1 /* $NetBSD: t_refuse_opt.c,v 1.8 2017/01/13 21:30:41 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2016 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: t_refuse_opt.c,v 1.8 2017/01/13 21:30:41 christos Exp $");
30
31 #define _KERNTYPES
32 #include <sys/types.h>
33
34 #include <atf-c.h>
35
36 #include <fuse.h>
37
38 #include "h_macros.h"
39
40 ATF_TC(t_fuse_opt_add_arg);
ATF_TC_HEAD(t_fuse_opt_add_arg,tc)41 ATF_TC_HEAD(t_fuse_opt_add_arg, tc)
42 {
43 atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_add_arg(3) works");
44 }
45
ATF_TC_BODY(t_fuse_opt_add_arg,tc)46 ATF_TC_BODY(t_fuse_opt_add_arg, tc)
47 {
48 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
49
50 RZ(fuse_opt_add_arg(&args, "foo"));
51 RZ(fuse_opt_add_arg(&args, "bar"));
52
53 ATF_REQUIRE_EQ(args.argc, 2);
54 ATF_CHECK_STREQ(args.argv[0], "foo");
55 ATF_CHECK_STREQ(args.argv[1], "bar");
56 ATF_CHECK(args.allocated != 0);
57 }
58
59 ATF_TC(t_fuse_opt_insert_arg);
ATF_TC_HEAD(t_fuse_opt_insert_arg,tc)60 ATF_TC_HEAD(t_fuse_opt_insert_arg, tc)
61 {
62 atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_insert_arg(3) works");
63 }
64
ATF_TC_BODY(t_fuse_opt_insert_arg,tc)65 ATF_TC_BODY(t_fuse_opt_insert_arg, tc)
66 {
67 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
68
69 RZ(fuse_opt_insert_arg(&args, 0, "foo"));
70 RZ(fuse_opt_insert_arg(&args, 0, "bar"));
71
72 ATF_REQUIRE_EQ(args.argc, 2);
73 ATF_CHECK_STREQ(args.argv[0], "bar");
74 ATF_CHECK_STREQ(args.argv[1], "foo");
75 ATF_CHECK(args.allocated != 0);
76 }
77
78 ATF_TC(t_fuse_opt_add_opt);
ATF_TC_HEAD(t_fuse_opt_add_opt,tc)79 ATF_TC_HEAD(t_fuse_opt_add_opt, tc)
80 {
81 atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_add_opt(3) works");
82 }
83
ATF_TC_BODY(t_fuse_opt_add_opt,tc)84 ATF_TC_BODY(t_fuse_opt_add_opt, tc)
85 {
86 char* opt = NULL;
87
88 RZ(fuse_opt_add_opt(&opt, "fo\\o"));
89 ATF_CHECK_STREQ(opt, "fo\\o");
90
91 RZ(fuse_opt_add_opt(&opt, "ba,r"));
92 ATF_CHECK_STREQ(opt, "fo\\o,ba,r");
93 }
94
95 ATF_TC(t_fuse_opt_add_opt_escaped);
ATF_TC_HEAD(t_fuse_opt_add_opt_escaped,tc)96 ATF_TC_HEAD(t_fuse_opt_add_opt_escaped, tc)
97 {
98 atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_add_opt_escaped(3) works");
99 }
100
ATF_TC_BODY(t_fuse_opt_add_opt_escaped,tc)101 ATF_TC_BODY(t_fuse_opt_add_opt_escaped, tc)
102 {
103 char* opt = NULL;
104
105 RZ(fuse_opt_add_opt_escaped(&opt, "fo\\o"));
106 ATF_CHECK_STREQ(opt, "fo\\\\o");
107
108 RZ(fuse_opt_add_opt_escaped(&opt, "ba,r"));
109 ATF_CHECK_STREQ(opt, "fo\\\\o,ba\\,r");
110 }
111
112 ATF_TC(t_fuse_opt_match);
ATF_TC_HEAD(t_fuse_opt_match,tc)113 ATF_TC_HEAD(t_fuse_opt_match, tc)
114 {
115 atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_match(3) works"
116 " for every form of templates");
117 }
118
ATF_TC_BODY(t_fuse_opt_match,tc)119 ATF_TC_BODY(t_fuse_opt_match, tc)
120 {
121 struct fuse_opt o1[] = { FUSE_OPT_KEY("-x" , 0), FUSE_OPT_END };
122 struct fuse_opt o2[] = { FUSE_OPT_KEY("foo" , 0), FUSE_OPT_END };
123 struct fuse_opt o3[] = { FUSE_OPT_KEY("foo=" , 0), FUSE_OPT_END };
124 struct fuse_opt o4[] = { FUSE_OPT_KEY("foo=%s", 0), FUSE_OPT_END };
125 struct fuse_opt o5[] = { FUSE_OPT_KEY("-x " , 0), FUSE_OPT_END };
126 struct fuse_opt o6[] = { FUSE_OPT_KEY("-x %s" , 0), FUSE_OPT_END };
127
128 ATF_CHECK(fuse_opt_match(o1, "-x") == 1);
129 ATF_CHECK(fuse_opt_match(o1, "x") == 0);
130
131 ATF_CHECK(fuse_opt_match(o2, "foo") == 1);
132 ATF_CHECK(fuse_opt_match(o2, "-foo") == 0);
133
134 ATF_CHECK(fuse_opt_match(o3, "foo=bar") == 1);
135 ATF_CHECK(fuse_opt_match(o3, "foo" ) == 0);
136
137 ATF_CHECK(fuse_opt_match(o4, "foo=bar") == 1);
138 ATF_CHECK(fuse_opt_match(o4, "foo" ) == 0);
139
140 ATF_CHECK(fuse_opt_match(o5, "-xbar" ) == 1);
141 ATF_CHECK(fuse_opt_match(o5, "-x" ) == 1);
142 ATF_CHECK(fuse_opt_match(o5, "-x=bar") == 1);
143 ATF_CHECK(fuse_opt_match(o5, "bar" ) == 0);
144
145 ATF_CHECK(fuse_opt_match(o6, "-xbar" ) == 1);
146 ATF_CHECK(fuse_opt_match(o6, "-x" ) == 1);
147 ATF_CHECK(fuse_opt_match(o6, "-x=bar") == 1);
148 ATF_CHECK(fuse_opt_match(o6, "bar" ) == 0);
149 }
150
151 struct foofs_config {
152 int number;
153 char *string;
154 char* nonopt;
155 };
156
157 #define FOOFS_OPT(t, p, v) { t, offsetof(struct foofs_config, p), v }
158
159 static struct fuse_opt foofs_opts[] = {
160 FOOFS_OPT("number=%i" , number, 0),
161 FOOFS_OPT("-n %i" , number, 0),
162 FOOFS_OPT("string=%s" , string, 0),
163 FOOFS_OPT("number1" , number, 1),
164 FOOFS_OPT("number2" , number, 2),
165 FOOFS_OPT("--number=three", number, 3),
166 FOOFS_OPT("--number=four" , number, 4),
167 FUSE_OPT_END
168 };
169
foo_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)170 static int foo_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) {
171 struct foofs_config *config = data;
172
173 if (key == FUSE_OPT_KEY_NONOPT && config->nonopt == NULL) {
174 config->nonopt = strdup(arg);
175 return 0;
176 }
177 else {
178 return 1;
179 }
180 }
181
182 ATF_TC(t_fuse_opt_parse_null_args);
ATF_TC_HEAD(t_fuse_opt_parse_null_args,tc)183 ATF_TC_HEAD(t_fuse_opt_parse_null_args, tc)
184 {
185 atf_tc_set_md_var(tc, "descr", "NULL args means an empty arguments vector");
186 }
187
ATF_TC_BODY(t_fuse_opt_parse_null_args,tc)188 ATF_TC_BODY(t_fuse_opt_parse_null_args, tc)
189 {
190 struct foofs_config config;
191
192 memset(&config, 0, sizeof(config));
193 ATF_CHECK(fuse_opt_parse(NULL, &config, NULL, NULL) == 0);
194 ATF_CHECK_EQ(config.number, 0);
195 ATF_CHECK_EQ(config.string, NULL);
196 ATF_CHECK_EQ(config.nonopt, NULL);
197 }
198
199 ATF_TC(t_fuse_opt_parse_null_opts);
ATF_TC_HEAD(t_fuse_opt_parse_null_opts,tc)200 ATF_TC_HEAD(t_fuse_opt_parse_null_opts, tc)
201 {
202 atf_tc_set_md_var(tc, "descr", "NULL opts means an opts array which only has FUSE_OPT_END");
203 }
204
ATF_TC_BODY(t_fuse_opt_parse_null_opts,tc)205 ATF_TC_BODY(t_fuse_opt_parse_null_opts, tc)
206 {
207 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
208 struct foofs_config config;
209
210 RZ(fuse_opt_add_arg(&args, "foofs"));
211 RZ(fuse_opt_add_arg(&args, "-o"));
212 RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
213 RZ(fuse_opt_add_arg(&args, "bar"));
214
215 memset(&config, 0, sizeof(config));
216 ATF_CHECK(fuse_opt_parse(&args, &config, NULL, NULL) == 0);
217 ATF_CHECK_EQ(config.number, 0);
218 ATF_CHECK_EQ(config.string, NULL);
219 ATF_CHECK_EQ(config.nonopt, NULL);
220 ATF_CHECK_EQ(args.argc, 4);
221 ATF_CHECK_STREQ(args.argv[0], "foofs");
222 ATF_CHECK_STREQ(args.argv[1], "-o");
223 ATF_CHECK_STREQ(args.argv[2], "number=1,string=foo");
224 ATF_CHECK_STREQ(args.argv[3], "bar");
225 }
226
227 ATF_TC(t_fuse_opt_parse_null_proc);
ATF_TC_HEAD(t_fuse_opt_parse_null_proc,tc)228 ATF_TC_HEAD(t_fuse_opt_parse_null_proc, tc)
229 {
230 atf_tc_set_md_var(tc, "descr", "NULL proc means a processor function always returning 1,"
231 " i.e. keep the argument");
232 }
233
ATF_TC_BODY(t_fuse_opt_parse_null_proc,tc)234 ATF_TC_BODY(t_fuse_opt_parse_null_proc, tc)
235 {
236 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
237 struct foofs_config config;
238
239 RZ(fuse_opt_add_arg(&args, "foofs"));
240 RZ(fuse_opt_add_arg(&args, "-o"));
241 RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
242 RZ(fuse_opt_add_arg(&args, "bar"));
243
244 memset(&config, 0, sizeof(config));
245 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, NULL) == 0);
246 ATF_CHECK_EQ(config.number, 1);
247 ATF_CHECK_STREQ(config.string, "foo");
248 ATF_CHECK_EQ(config.nonopt, NULL);
249 ATF_CHECK_EQ(args.argc, 2);
250 ATF_CHECK_STREQ(args.argv[0], "foofs");
251 ATF_CHECK_STREQ(args.argv[1], "bar");
252 }
253
254 ATF_TC(t_fuse_opt_parse);
ATF_TC_HEAD(t_fuse_opt_parse,tc)255 ATF_TC_HEAD(t_fuse_opt_parse, tc)
256 {
257 atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_parse(3) fully works");
258 }
259
ATF_TC_BODY(t_fuse_opt_parse,tc)260 ATF_TC_BODY(t_fuse_opt_parse, tc)
261 {
262 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
263 struct foofs_config config;
264
265 /* Standard form */
266 fuse_opt_free_args(&args);
267 RZ(fuse_opt_add_arg(&args, "foofs"));
268 RZ(fuse_opt_add_arg(&args, "-o"));
269 RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
270 RZ(fuse_opt_add_arg(&args, "bar"));
271
272 memset(&config, 0, sizeof(config));
273 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
274 ATF_CHECK_EQ(config.number, 1);
275 ATF_CHECK_STREQ(config.string, "foo");
276 ATF_CHECK_STREQ(config.nonopt, "bar");
277 ATF_CHECK_EQ(args.argc, 1);
278 ATF_CHECK_STREQ(args.argv[0], "foofs");
279
280 /* Concatenated -o */
281 fuse_opt_free_args(&args);
282 RZ(fuse_opt_add_arg(&args, "foofs"));
283 RZ(fuse_opt_add_arg(&args, "-onumber=1,unknown,string=foo"));
284 RZ(fuse_opt_add_arg(&args, "bar"));
285
286 memset(&config, 0, sizeof(config));
287 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
288 ATF_CHECK_EQ(config.number, 1);
289 ATF_CHECK_STREQ(config.string, "foo");
290 ATF_CHECK_STREQ(config.nonopt, "bar");
291 ATF_CHECK_EQ(args.argc, 3);
292 ATF_CHECK_STREQ(args.argv[0], "foofs");
293 ATF_CHECK_STREQ(args.argv[1], "-o");
294 ATF_CHECK_STREQ(args.argv[2], "unknown");
295
296 /* Sparse -o */
297 fuse_opt_free_args(&args);
298 RZ(fuse_opt_add_arg(&args, "foofs"));
299 RZ(fuse_opt_add_arg(&args, "bar"));
300 RZ(fuse_opt_add_arg(&args, "baz"));
301 RZ(fuse_opt_add_arg(&args, "-o"));
302 RZ(fuse_opt_add_arg(&args, "number=1"));
303 RZ(fuse_opt_add_arg(&args, "-o"));
304 RZ(fuse_opt_add_arg(&args, "unknown"));
305 RZ(fuse_opt_add_arg(&args, "-o"));
306 RZ(fuse_opt_add_arg(&args, "string=foo"));
307
308 memset(&config, 0, sizeof(config));
309 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
310 ATF_CHECK_EQ(config.number, 1);
311 ATF_CHECK_STREQ(config.string, "foo");
312 ATF_CHECK_STREQ(config.nonopt, "bar");
313 ATF_CHECK_EQ(args.argc, 4);
314 ATF_CHECK_STREQ(args.argv[0], "foofs");
315 ATF_CHECK_STREQ(args.argv[1], "-o");
316 ATF_CHECK_STREQ(args.argv[2], "unknown");
317 ATF_CHECK_STREQ(args.argv[3], "baz");
318
319 /* Separate -n %i */
320 fuse_opt_free_args(&args);
321 RZ(fuse_opt_add_arg(&args, "foofs"));
322 RZ(fuse_opt_add_arg(&args, "-n"));
323 RZ(fuse_opt_add_arg(&args, "3"));
324
325 memset(&config, 0, sizeof(config));
326 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
327 ATF_CHECK_EQ(config.number, 3);
328 ATF_CHECK_EQ(config.string, NULL);
329 ATF_CHECK_EQ(config.nonopt, NULL);
330 ATF_CHECK_EQ(args.argc, 1);
331 ATF_CHECK_STREQ(args.argv[0], "foofs");
332
333 /* Concatenated -n %i */
334 fuse_opt_free_args(&args);
335 RZ(fuse_opt_add_arg(&args, "foofs"));
336 RZ(fuse_opt_add_arg(&args, "-n3"));
337
338 memset(&config, 0, sizeof(config));
339 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
340 ATF_CHECK_EQ(config.number, 3);
341 ATF_CHECK_EQ(config.string, NULL);
342 ATF_CHECK_EQ(config.nonopt, NULL);
343 ATF_CHECK_EQ(args.argc, 1);
344 ATF_CHECK_STREQ(args.argv[0], "foofs");
345
346 /* -o constant */
347 fuse_opt_free_args(&args);
348 RZ(fuse_opt_add_arg(&args, "foofs"));
349 RZ(fuse_opt_add_arg(&args, "-o"));
350 RZ(fuse_opt_add_arg(&args, "number2"));
351
352 memset(&config, 0, sizeof(config));
353 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
354 ATF_CHECK_EQ(config.number, 2);
355 ATF_CHECK_EQ(config.string, NULL);
356 ATF_CHECK_EQ(config.nonopt, NULL);
357 ATF_CHECK_EQ(args.argc, 1);
358 ATF_CHECK_STREQ(args.argv[0], "foofs");
359
360 /* -x constant */
361 fuse_opt_free_args(&args);
362 RZ(fuse_opt_add_arg(&args, "foofs"));
363 RZ(fuse_opt_add_arg(&args, "--number=four"));
364
365 memset(&config, 0, sizeof(config));
366 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
367 ATF_CHECK_EQ(config.number, 4);
368 ATF_CHECK_EQ(config.string, NULL);
369 ATF_CHECK_EQ(config.nonopt, NULL);
370 ATF_CHECK_EQ(args.argc, 1);
371 ATF_CHECK_STREQ(args.argv[0], "foofs");
372
373 /* end-of-options "--" marker */
374 fuse_opt_free_args(&args);
375 RZ(fuse_opt_add_arg(&args, "foofs"));
376 RZ(fuse_opt_add_arg(&args, "--"));
377 RZ(fuse_opt_add_arg(&args, "-onumber=1"));
378 RZ(fuse_opt_add_arg(&args, "-ostring=foo"));
379
380 memset(&config, 0, sizeof(config));
381 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
382 ATF_CHECK_EQ(config.number, 0);
383 ATF_CHECK_EQ(config.string, NULL);
384 ATF_CHECK_STREQ(config.nonopt, "-onumber=1");
385 ATF_CHECK_EQ(args.argc, 3);
386 ATF_CHECK_STREQ(args.argv[0], "foofs");
387 ATF_CHECK_STREQ(args.argv[1], "--");
388 ATF_CHECK_STREQ(args.argv[2], "-ostring=foo");
389
390 /* The "--" marker at the last of outargs should be removed */
391 fuse_opt_free_args(&args);
392 RZ(fuse_opt_add_arg(&args, "foofs"));
393 RZ(fuse_opt_add_arg(&args, "--"));
394 RZ(fuse_opt_add_arg(&args, "-onumber=1"));
395
396 memset(&config, 0, sizeof(config));
397 ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
398 ATF_CHECK_EQ(config.number, 0);
399 ATF_CHECK_EQ(config.string, NULL);
400 ATF_CHECK_STREQ(config.nonopt, "-onumber=1");
401 ATF_CHECK_EQ(args.argc, 1);
402 ATF_CHECK_STREQ(args.argv[0], "foofs");
403 }
404
ATF_TP_ADD_TCS(tp)405 ATF_TP_ADD_TCS(tp)
406 {
407 ATF_TP_ADD_TC(tp, t_fuse_opt_add_arg);
408 ATF_TP_ADD_TC(tp, t_fuse_opt_insert_arg);
409 ATF_TP_ADD_TC(tp, t_fuse_opt_add_opt);
410 ATF_TP_ADD_TC(tp, t_fuse_opt_add_opt_escaped);
411 ATF_TP_ADD_TC(tp, t_fuse_opt_match);
412 ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_args);
413 ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_opts);
414 ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_proc);
415 ATF_TP_ADD_TC(tp, t_fuse_opt_parse);
416
417 return atf_no_error();
418 }
419