Home | History | Annotate | Line # | Download | only in librefuse
      1 /*	$NetBSD: t_refuse_opt.c,v 1.10 2023/11/24 17:31:03 riastradh 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.10 2023/11/24 17:31:03 riastradh Exp $");
     30 
     31 #include <sys/types.h>
     32 
     33 #include <atf-c.h>
     34 
     35 #define FUSE_USE_VERSION FUSE_MAKE_VERSION(2, 6)
     36 #include <fuse.h>
     37 
     38 #include "h_macros.h"
     39 
     40 ATF_TC(t_fuse_opt_add_arg);
     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 
     46 ATF_TC_BODY(t_fuse_opt_add_arg, tc)
     47 {
     48 	struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
     49 
     50 	RL(fuse_opt_add_arg(&args, "foo"));
     51 	RL(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);
     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 
     65 ATF_TC_BODY(t_fuse_opt_insert_arg, tc)
     66 {
     67 	struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
     68 
     69 	RL(fuse_opt_insert_arg(&args, 0, "foo"));
     70 	RL(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);
     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 
     84 ATF_TC_BODY(t_fuse_opt_add_opt, tc)
     85 {
     86 	char* opt = NULL;
     87 
     88 	RL(fuse_opt_add_opt(&opt, "fo\\o"));
     89 	ATF_CHECK_STREQ(opt, "fo\\o");
     90 
     91 	RL(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);
     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 
    101 ATF_TC_BODY(t_fuse_opt_add_opt_escaped, tc)
    102 {
    103 	char* opt = NULL;
    104 
    105 	RL(fuse_opt_add_opt_escaped(&opt, "fo\\o"));
    106 	ATF_CHECK_STREQ(opt, "fo\\\\o");
    107 
    108 	RL(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);
    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 
    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 
    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);
    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 
    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);
    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 
    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 	RL(fuse_opt_add_arg(&args, "foofs"));
    211 	RL(fuse_opt_add_arg(&args, "-o"));
    212 	RL(fuse_opt_add_arg(&args, "number=1,string=foo"));
    213 	RL(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);
    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 
    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 	RL(fuse_opt_add_arg(&args, "foofs"));
    240 	RL(fuse_opt_add_arg(&args, "-o"));
    241 	RL(fuse_opt_add_arg(&args, "number=1,string=foo"));
    242 	RL(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);
    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 
    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 	RL(fuse_opt_add_arg(&args, "foofs"));
    268 	RL(fuse_opt_add_arg(&args, "-o"));
    269 	RL(fuse_opt_add_arg(&args, "number=1,string=foo"));
    270 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    283 	RL(fuse_opt_add_arg(&args, "-onumber=1,unknown,string=foo"));
    284 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    299 	RL(fuse_opt_add_arg(&args, "bar"));
    300 	RL(fuse_opt_add_arg(&args, "baz"));
    301 	RL(fuse_opt_add_arg(&args, "-o"));
    302 	RL(fuse_opt_add_arg(&args, "number=1"));
    303 	RL(fuse_opt_add_arg(&args, "-o"));
    304 	RL(fuse_opt_add_arg(&args, "unknown"));
    305 	RL(fuse_opt_add_arg(&args, "-o"));
    306 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    322 	RL(fuse_opt_add_arg(&args, "-n"));
    323 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    336 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    349 	RL(fuse_opt_add_arg(&args, "-o"));
    350 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    363 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    376     RL(fuse_opt_add_arg(&args, "--"));
    377 	RL(fuse_opt_add_arg(&args, "-onumber=1"));
    378 	RL(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 	RL(fuse_opt_add_arg(&args, "foofs"));
    393     RL(fuse_opt_add_arg(&args, "--"));
    394 	RL(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 
    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