xref: /openbsd-src/regress/lib/libfuse/fuse-opt-parse.c (revision f3de9d7dd81d004e964f4bd559c4dd6d7cb610e1)
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