1*f3de9d7dShelg /* $OpenBSD: fuse-opt-parse.c,v 1.4 2018/07/20 12:05:08 helg Exp $ */
20e9b8da4Shelg /*
30e9b8da4Shelg * Copyright (c) 2017 Helg Bredow <helg@openbsd.org>
40e9b8da4Shelg *
50e9b8da4Shelg * Permission to use, copy, modify, and distribute this software for any
60e9b8da4Shelg * purpose with or without fee is hereby granted, provided that the above
70e9b8da4Shelg * copyright notice and this permission notice appear in all copies.
80e9b8da4Shelg *
90e9b8da4Shelg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100e9b8da4Shelg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110e9b8da4Shelg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120e9b8da4Shelg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130e9b8da4Shelg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140e9b8da4Shelg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150e9b8da4Shelg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160e9b8da4Shelg */
170e9b8da4Shelg
18c32970f0Shelg #include <assert.h>
190e9b8da4Shelg #include <fuse_opt.h>
200e9b8da4Shelg #include <stddef.h>
210e9b8da4Shelg #include <stdlib.h>
220e9b8da4Shelg #include <string.h>
230e9b8da4Shelg
240e9b8da4Shelg struct data {
250e9b8da4Shelg int port;
260e9b8da4Shelg char *fsname;
270e9b8da4Shelg char *x;
280e9b8da4Shelg char *optstring;
290e9b8da4Shelg int debug;
30c32970f0Shelg int foreground;
310e9b8da4Shelg int noatime;
320e9b8da4Shelg int ssh_ver;
330e9b8da4Shelg int count;
340e9b8da4Shelg int cache;
35c32970f0Shelg int set_gid;
36c32970f0Shelg int gid;
37d997417fShelg int bad_opt;
38c32970f0Shelg };
39c32970f0Shelg
40c32970f0Shelg enum {
41c32970f0Shelg KEY_DEBUG,
42c32970f0Shelg KEY_NOATIME,
43c32970f0Shelg KEY_PORT
440e9b8da4Shelg };
450e9b8da4Shelg
460e9b8da4Shelg #define DATA_OPT(o,m,v) {o, offsetof(struct data, m), v}
470e9b8da4Shelg
480e9b8da4Shelg struct fuse_opt opts[] = {
49c32970f0Shelg FUSE_OPT_KEY("noatime", KEY_NOATIME ),
500e9b8da4Shelg
510e9b8da4Shelg DATA_OPT("optstring=%s", optstring, 0),
520e9b8da4Shelg DATA_OPT("-f=%s", fsname, 0),
530e9b8da4Shelg DATA_OPT("-x %s", x, 0),
540e9b8da4Shelg DATA_OPT("--count=%u", count, 0),
550e9b8da4Shelg DATA_OPT("-1", ssh_ver, 5),
56c32970f0Shelg DATA_OPT("cache=yes", cache, 1),
570e9b8da4Shelg DATA_OPT("cache=no", cache, 0),
58c32970f0Shelg DATA_OPT("debug", debug, 1),
59c32970f0Shelg DATA_OPT("debug", foreground, 1),
60c32970f0Shelg FUSE_OPT_KEY("debug", KEY_DEBUG ),
61c32970f0Shelg FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
62c32970f0Shelg DATA_OPT("-p", port, 25),
63c32970f0Shelg FUSE_OPT_KEY("-p ", KEY_PORT ),
64c32970f0Shelg DATA_OPT("gid=", set_gid, 1),
65c32970f0Shelg DATA_OPT("gid=%o", gid, 1),
660e9b8da4Shelg
670e9b8da4Shelg FUSE_OPT_END
680e9b8da4Shelg };
690e9b8da4Shelg
700e9b8da4Shelg int
proc(void * data,const char * arg,int key,struct fuse_args * args)710e9b8da4Shelg proc(void *data, const char *arg, int key, struct fuse_args *args)
720e9b8da4Shelg {
73c32970f0Shelg struct data *conf = data;
740e9b8da4Shelg
750e9b8da4Shelg if (conf == NULL)
760e9b8da4Shelg return (1);
770e9b8da4Shelg
780e9b8da4Shelg switch (key)
790e9b8da4Shelg {
80c32970f0Shelg case KEY_PORT:
810e9b8da4Shelg conf->port = atoi(&arg[2]);
820e9b8da4Shelg return (0);
83c32970f0Shelg case KEY_DEBUG:
84c32970f0Shelg conf->debug = 2;
85c32970f0Shelg return (0);
86c32970f0Shelg case KEY_NOATIME:
870e9b8da4Shelg conf->noatime = 1;
880e9b8da4Shelg return (1);
890e9b8da4Shelg }
900e9b8da4Shelg
91d997417fShelg if (strcmp("bad_opt", arg) == 0) {
92d997417fShelg conf->bad_opt = 1;
93d997417fShelg return (0);
94d997417fShelg }
95d997417fShelg
960e9b8da4Shelg return (1);
970e9b8da4Shelg }
980e9b8da4Shelg
990e9b8da4Shelg /*
1000e9b8da4Shelg * A NULL 'args' is equivalent to an empty argument vector.
1010e9b8da4Shelg */
1020e9b8da4Shelg void
test_null_args(void)1030e9b8da4Shelg test_null_args(void) {
1040e9b8da4Shelg struct data data;
1050e9b8da4Shelg struct fuse_args args;
1060e9b8da4Shelg
1070e9b8da4Shelg bzero(&data, sizeof(data));
1080e9b8da4Shelg
109c32970f0Shelg assert(fuse_opt_parse(NULL, &data, opts, proc) == 0);
1100e9b8da4Shelg
111c32970f0Shelg assert(data.port == 0);
112c32970f0Shelg assert(data.fsname == NULL);
113c32970f0Shelg assert(data.x == NULL);
114c32970f0Shelg assert(data.optstring == NULL);
115c32970f0Shelg assert(data.debug == 0);
116c32970f0Shelg assert(data.noatime == 0);
117c32970f0Shelg assert(data.ssh_ver == 0);
118c32970f0Shelg assert(data.count == 0);
119c32970f0Shelg assert(data.cache == 0);
120d997417fShelg assert(data.bad_opt == 0);
1210e9b8da4Shelg }
1220e9b8da4Shelg
1230e9b8da4Shelg /*
1240e9b8da4Shelg * A NULL 'opts' is equivalent to an 'opts' array containing a single
1250e9b8da4Shelg * end marker.
1260e9b8da4Shelg */
1270e9b8da4Shelg void
test_null_opts(void)1280e9b8da4Shelg test_null_opts(void)
1290e9b8da4Shelg {
1300e9b8da4Shelg struct data data;
1310e9b8da4Shelg struct fuse_args args;
1320e9b8da4Shelg
1330e9b8da4Shelg char *argv_null_opts[] = {
1340e9b8da4Shelg "progname",
135d997417fShelg "/mnt",
136d997417fShelg "bad_opt"
1370e9b8da4Shelg };
1380e9b8da4Shelg
1390e9b8da4Shelg args.argc = sizeof(argv_null_opts) / sizeof(argv_null_opts[0]);
1400e9b8da4Shelg args.argv = argv_null_opts;
1410e9b8da4Shelg args.allocated = 0;
1420e9b8da4Shelg
1430e9b8da4Shelg bzero(&data, sizeof(data));
1440e9b8da4Shelg
145c32970f0Shelg assert(fuse_opt_parse(&args, &data, NULL, proc) == 0);
1460e9b8da4Shelg
147c32970f0Shelg assert(data.port == 0);
148c32970f0Shelg assert(data.fsname == NULL);
149c32970f0Shelg assert(data.x == NULL);
150c32970f0Shelg assert(data.optstring == NULL);
151c32970f0Shelg assert(data.debug == 0);
152c32970f0Shelg assert(data.noatime == 0);
153c32970f0Shelg assert(data.ssh_ver == 0);
154c32970f0Shelg assert(data.count == 0);
155c32970f0Shelg assert(data.cache == 0);
156c32970f0Shelg assert(data.set_gid == 0);
157c32970f0Shelg assert(data.gid == 0);
158d997417fShelg assert(data.bad_opt == 1);
1590e9b8da4Shelg
160c32970f0Shelg assert(args.argc == 2);
161c32970f0Shelg assert(strcmp(args.argv[0], "progname") == 0);
162c32970f0Shelg assert(strcmp(args.argv[1], "/mnt") == 0);
163c32970f0Shelg assert(args.allocated);
1640e9b8da4Shelg
1650e9b8da4Shelg fuse_opt_free_args(&args);
1660e9b8da4Shelg }
1670e9b8da4Shelg
1680e9b8da4Shelg /*
1690e9b8da4Shelg * A NULL 'proc' is equivalent to a processing function always returning '1'.
1700e9b8da4Shelg */
1710e9b8da4Shelg void
test_null_proc(void)1720e9b8da4Shelg test_null_proc(void)
1730e9b8da4Shelg {
1740e9b8da4Shelg struct data data;
1750e9b8da4Shelg struct fuse_args args;
1760e9b8da4Shelg
1770e9b8da4Shelg char *argv_null_proc[] = {
1780e9b8da4Shelg "progname",
179c32970f0Shelg "-odebug,noatime,gid=077",
1800e9b8da4Shelg "-d",
1810e9b8da4Shelg "-p", "22",
1820e9b8da4Shelg "/mnt",
1830e9b8da4Shelg "-f=filename",
1840e9b8da4Shelg "-1",
1850e9b8da4Shelg "-x", "xanadu",
1860e9b8da4Shelg "-o", "optstring=",
1870e9b8da4Shelg "-o", "optstring=optstring",
188d997417fShelg "--count=10",
189d997417fShelg "bad_opt"
1900e9b8da4Shelg };
1910e9b8da4Shelg
1920e9b8da4Shelg args.argc = sizeof(argv_null_proc) / sizeof(argv_null_proc[0]);
1930e9b8da4Shelg args.argv = argv_null_proc;
1940e9b8da4Shelg args.allocated = 0;
1950e9b8da4Shelg
1960e9b8da4Shelg bzero(&data, sizeof(data));
1970e9b8da4Shelg
198c32970f0Shelg assert(fuse_opt_parse(&args, &data, opts, NULL) == 0);
1990e9b8da4Shelg
200c32970f0Shelg assert(data.port == 25);
201c32970f0Shelg assert(strcmp(data.fsname, "filename") == 0);
202c32970f0Shelg assert(strcmp(data.x, "xanadu") == 0);
203c32970f0Shelg assert(strcmp(data.optstring, "optstring") == 0);
204c32970f0Shelg assert(data.debug == 1);
205c32970f0Shelg assert(data.noatime == 0);
206c32970f0Shelg assert(data.ssh_ver == 5);
207c32970f0Shelg assert(data.count == 10);
208c32970f0Shelg assert(data.cache == 0);
209c32970f0Shelg assert(data.set_gid == 1);
210c32970f0Shelg assert(data.gid == 077);
211d997417fShelg assert(data.bad_opt == 0);
2120e9b8da4Shelg
213d997417fShelg assert(args.argc == 9);
214c32970f0Shelg assert(strcmp(args.argv[0], "progname") == 0);
215c32970f0Shelg assert(strcmp(args.argv[1], "-o") == 0);
216c32970f0Shelg assert(strcmp(args.argv[2], "debug") == 0);
217c32970f0Shelg assert(strcmp(args.argv[3], "-o") == 0);
218c32970f0Shelg assert(strcmp(args.argv[4], "noatime") == 0);
219c32970f0Shelg assert(strcmp(args.argv[5], "-d") == 0);
220c32970f0Shelg assert(strcmp(args.argv[6], "-p22") == 0);
221c32970f0Shelg assert(strcmp(args.argv[7], "/mnt") == 0);
222d997417fShelg assert(strcmp(args.argv[8], "bad_opt") == 0);
223c32970f0Shelg assert(args.allocated);
2240e9b8da4Shelg
2250e9b8da4Shelg fuse_opt_free_args(&args);
2260e9b8da4Shelg }
2270e9b8da4Shelg
2280e9b8da4Shelg /*
2290e9b8da4Shelg * Test with all args supplied to fuse_opt_parse.
2300e9b8da4Shelg */
2310e9b8da4Shelg void
test_all_args(void)2320e9b8da4Shelg test_all_args(void)
2330e9b8da4Shelg {
2340e9b8da4Shelg struct data data;
2350e9b8da4Shelg struct fuse_args args;
2360e9b8da4Shelg
2370e9b8da4Shelg char *argv[] = {
2380e9b8da4Shelg "progname",
239c32970f0Shelg "-odebug,noatime,gid=077",
2400e9b8da4Shelg "-d",
2410e9b8da4Shelg "-p", "22",
2420e9b8da4Shelg "/mnt",
2430e9b8da4Shelg "-f=filename",
2440e9b8da4Shelg "-1",
2450e9b8da4Shelg "-x", "xanadu",
2460e9b8da4Shelg "-o", "optstring=optstring,cache=no",
247d997417fShelg "--count=10",
248d997417fShelg "bad_opt"
2490e9b8da4Shelg };
2500e9b8da4Shelg
2510e9b8da4Shelg args.argc = sizeof(argv) / sizeof(argv[0]);
2520e9b8da4Shelg args.argv = argv;
2530e9b8da4Shelg args.allocated = 0;
2540e9b8da4Shelg
2550e9b8da4Shelg bzero(&data, sizeof(data));
2560e9b8da4Shelg
257c32970f0Shelg assert(fuse_opt_parse(&args, &data, opts, proc) == 0);
2580e9b8da4Shelg
259c32970f0Shelg assert(data.port == 22);
260c32970f0Shelg assert(strcmp(data.fsname, "filename") == 0);
261c32970f0Shelg assert(strcmp(data.x, "xanadu") == 0);
262c32970f0Shelg assert(strcmp(data.optstring, "optstring") == 0);
263c32970f0Shelg assert(data.debug == 2);
264c32970f0Shelg assert(data.noatime == 1);
265c32970f0Shelg assert(data.ssh_ver == 5);
266c32970f0Shelg assert(data.count == 10);
267c32970f0Shelg assert(data.cache == 0);
268c32970f0Shelg assert(data.set_gid == 1);
269c32970f0Shelg assert(data.gid == 077);
270d997417fShelg assert(data.bad_opt == 1);
2710e9b8da4Shelg
272c32970f0Shelg assert(args.argc == 7);
273c32970f0Shelg assert(strcmp(args.argv[0], "progname") == 0);
274c32970f0Shelg assert(strcmp(args.argv[1], "-o") == 0);
275c32970f0Shelg assert(strcmp(args.argv[2], "debug") == 0);
276c32970f0Shelg assert(strcmp(args.argv[3], "-o") == 0);
277c32970f0Shelg assert(strcmp(args.argv[4], "noatime") == 0);
278c32970f0Shelg assert(strcmp(args.argv[5], "-d") == 0);
279c32970f0Shelg assert(strcmp(args.argv[6], "/mnt") == 0);
280c32970f0Shelg assert(args.allocated);
2810e9b8da4Shelg
2820e9b8da4Shelg fuse_opt_free_args(&args);
2830e9b8da4Shelg }
2840e9b8da4Shelg
2850e9b8da4Shelg int
main(void)2860e9b8da4Shelg main(void)
2870e9b8da4Shelg {
2880e9b8da4Shelg test_null_opts();
2890e9b8da4Shelg test_null_args();
2900e9b8da4Shelg test_null_proc();
2910e9b8da4Shelg test_all_args();
2920e9b8da4Shelg
2930e9b8da4Shelg return (0);
2940e9b8da4Shelg }
295