]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/optstr.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 * This file is part of libmount from util-linux project.
5 * Copyright (C) 2009-2018 Karel Zak <kzak@redhat.com>
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
15 * @title: Options string
16 * @short_description: low-level API for working with mount options
18 * This is a simple and low-level API to working with mount options that are stored
29 struct libmnt_optloc
{
37 #define MNT_INIT_OPTLOC { .begin = NULL }
39 #define mnt_optmap_entry_novalue(e) \
40 (e && (e)->name && !strchr((e)->name, '=') && !((e)->mask & MNT_PREFIX))
43 * Locates the first option that matches @name. The @end is set to the
44 * char behind the option (it means ',' or \0).
48 * Returns negative number on parse error, 1 when not found and 0 on success.
50 static int mnt_optstr_locate_option(char *optstr
,
51 const char *name
, size_t namesz
,
52 struct libmnt_optloc
*ol
)
64 namesz
= strlen(name
);
69 rc
= ul_optstr_next(&optstr
, &n
, &nsz
,
70 ol
? &ol
->value
: NULL
,
71 ol
? &ol
->valsz
: NULL
);
75 if (namesz
== nsz
&& strncmp(n
, name
, nsz
) == 0) {
78 ol
->end
= *(optstr
- 1) == ',' ? optstr
- 1 : optstr
;
88 * mnt_optstr_next_option:
89 * @optstr: option string, returns the position of the next option
90 * @name: returns the option name
91 * @namesz: returns the option name length
92 * @value: returns the option value or NULL
93 * @valuesz: returns the option value length or zero
95 * Parses the first option in @optstr.
97 * Returns: 0 on success, 1 at the end of @optstr or negative number in case of
100 int mnt_optstr_next_option(char **optstr
, char **name
, size_t *namesz
,
101 char **value
, size_t *valuesz
)
103 if (!optstr
|| !*optstr
)
106 return ul_optstr_next(optstr
, name
, namesz
, value
, valuesz
);
109 int mnt_buffer_append_option(struct ul_buffer
*buf
,
110 const char *name
, size_t namesz
,
111 const char *val
, size_t valsz
,
116 if (!ul_buffer_is_empty(buf
))
117 rc
= ul_buffer_append_data(buf
, ",", 1);
119 rc
= ul_buffer_append_data(buf
, name
, namesz
);
121 /* we need to append '=' is value is empty string, see
122 * 727c689908c5e68c92aa1dd65e0d3bdb6d91c1e5 */
123 rc
= ul_buffer_append_data(buf
, "=", 1);
126 rc
= ul_buffer_append_data(buf
, "\"", 1);
128 rc
= ul_buffer_append_data(buf
, val
, valsz
);
130 rc
= ul_buffer_append_data(buf
, "\"", 1);
137 * mnt_optstr_append_option:
138 * @optstr: option string or NULL, returns a reallocated string
142 * Returns: 0 on success or <0 in case of error. After an error the @optstr should
145 int mnt_optstr_append_option(char **optstr
, const char *name
, const char *value
)
147 struct ul_buffer buf
= UL_INIT_BUFFER
;
149 size_t nsz
, vsz
, osz
;
157 osz
= *optstr
? strlen(*optstr
) : 0;
158 vsz
= value
? strlen(value
) : 0;
160 ul_buffer_refer_string(&buf
, *optstr
);
161 ul_buffer_set_chunksize(&buf
, osz
+ nsz
+ vsz
+ 3); /* to call realloc() only once */
163 rc
= mnt_buffer_append_option(&buf
, name
, nsz
, value
, vsz
, 0);
165 *optstr
= ul_buffer_get_data(&buf
, NULL
, NULL
);
167 ul_buffer_free_data(&buf
);
172 * mnt_optstr_prepend_option:
173 * @optstr: option string or NULL, returns a reallocated string
177 * Returns: 0 on success or <0 in case of error. After an error the @optstr should
180 int mnt_optstr_prepend_option(char **optstr
, const char *name
, const char *value
)
182 struct ul_buffer buf
= UL_INIT_BUFFER
;
183 size_t nsz
, vsz
, osz
;
192 osz
= *optstr
? strlen(*optstr
) : 0;
193 vsz
= value
? strlen(value
) : 0;
195 ul_buffer_set_chunksize(&buf
, osz
+ nsz
+ vsz
+ 3); /* to call realloc() only once */
197 rc
= mnt_buffer_append_option(&buf
, name
, nsz
, value
, vsz
, 0);
198 if (*optstr
&& !rc
) {
199 rc
= ul_buffer_append_data(&buf
, ",", 1);
201 rc
= ul_buffer_append_data(&buf
, *optstr
, osz
);
206 *optstr
= ul_buffer_get_data(&buf
, NULL
, NULL
);
208 ul_buffer_free_data(&buf
);
214 * mnt_optstr_get_option:
215 * @optstr: string with a comma separated list of options
216 * @name: requested option name
217 * @value: returns a pointer to the beginning of the value (e.g. name=VALUE) or NULL
218 * @valsz: returns size of the value or 0
220 * Returns: 0 on success, 1 when not found the @name or negative number in case
223 int mnt_optstr_get_option(const char *optstr
, const char *name
,
224 char **value
, size_t *valsz
)
226 struct libmnt_optloc ol
= MNT_INIT_OPTLOC
;
229 if (!optstr
|| !name
)
232 rc
= mnt_optstr_locate_option((char *) optstr
, name
, 0, &ol
);
243 * mnt_optstr_deduplicate_option:
244 * @optstr: string with a comma separated list of options
245 * @name: requested option name
247 * Removes all instances of @name except the last one.
249 * Returns: 0 on success, 1 when not found the @name or negative number in case
252 int mnt_optstr_deduplicate_option(char **optstr
, const char *name
)
255 char *begin
= NULL
, *end
= NULL
, *opt
;
257 if (!optstr
|| !name
)
262 struct libmnt_optloc ol
= MNT_INIT_OPTLOC
;
264 rc
= mnt_optstr_locate_option(opt
, name
, 0, &ol
);
267 /* remove the previous instance */
268 size_t shift
= strlen(*optstr
);
270 mnt_optstr_remove_option_at(optstr
, begin
, end
);
272 /* now all the offsets are not valid anymore - recount */
273 shift
-= strlen(*optstr
);
279 opt
= end
&& *end
? end
+ 1 : NULL
;
283 } while (rc
== 0 && *opt
);
285 return rc
< 0 ? rc
: begin
? 0 : 1;
289 * The result never starts or ends with a comma or contains two commas
290 * (e.g. ",aaa,bbb" or "aaa,,bbb" or "aaa,")
292 int mnt_optstr_remove_option_at(char **optstr
, char *begin
, char *end
)
296 if (!optstr
|| !begin
|| !end
)
299 if ((begin
== *optstr
|| *(begin
- 1) == ',') && *end
== ',')
304 memmove(begin
, end
, sz
+ 1);
305 if (!*begin
&& (begin
> *optstr
) && *(begin
- 1) == ',')
311 /* insert 'substr' or '=substr' to @str on position @pos */
312 static int __attribute__((nonnull(1,2,3)))
313 insert_value(char **str
, char *pos
, const char *substr
, char **next
)
315 size_t subsz
= strlen(substr
); /* substring size */
316 size_t strsz
= strlen(*str
);
317 size_t possz
= strlen(pos
);
322 /* is it necessary to prepend '=' before the substring ? */
323 sep
= !(pos
> *str
&& *(pos
- 1) == '=');
325 /* save an offset of the place where we need to add substr */
328 p
= realloc(*str
, strsz
+ sep
+ subsz
+ 1);
332 /* zeroize the newly allocated memory -- valgrind loves us... */
333 memset(p
+ strsz
, 0, sep
+ subsz
+ 1);
335 /* set pointers to the reallocated string */
340 /* create a room for the new substring */
341 memmove(pos
+ subsz
+ sep
, pos
, possz
+ 1);
345 memcpy(pos
, substr
, subsz
);
348 /* set pointer to the next option */
357 * mnt_optstr_set_option:
358 * @optstr: string with a comma separated list of options
359 * @name: requested option
360 * @value: new value or NULL
362 * Set or unset the option @value.
364 * Returns: 0 on success, 1 when not found the @name or negative number in case
367 int mnt_optstr_set_option(char **optstr
, const char *name
, const char *value
)
369 struct libmnt_optloc ol
= MNT_INIT_OPTLOC
;
373 if (!optstr
|| !name
)
377 rc
= mnt_optstr_locate_option(*optstr
, name
, 0, &ol
);
379 return rc
; /* parse error */
381 return mnt_optstr_append_option(optstr
, name
, value
); /* not found */
383 nameend
= ol
.begin
+ ol
.namesz
;
385 if (value
== NULL
&& ol
.value
&& ol
.valsz
)
386 /* remove unwanted "=value" */
387 mnt_optstr_remove_option_at(optstr
, nameend
, ol
.end
);
389 else if (value
&& ol
.value
== NULL
)
390 /* insert "=value" */
391 rc
= insert_value(optstr
, nameend
, value
, NULL
);
393 else if (value
&& ol
.value
&& strlen(value
) == ol
.valsz
)
394 /* simply replace =value */
395 memcpy(ol
.value
, value
, ol
.valsz
);
397 else if (value
&& ol
.value
) {
398 mnt_optstr_remove_option_at(optstr
, nameend
, ol
.end
);
399 rc
= insert_value(optstr
, nameend
, value
, NULL
);
405 * mnt_optstr_remove_option:
406 * @optstr: string with a comma separated list of options
407 * @name: requested option name
409 * Returns: 0 on success, 1 when not found the @name or negative number in case
412 int mnt_optstr_remove_option(char **optstr
, const char *name
)
414 struct libmnt_optloc ol
= MNT_INIT_OPTLOC
;
417 if (!optstr
|| !name
)
420 rc
= mnt_optstr_locate_option(*optstr
, name
, 0, &ol
);
424 mnt_optstr_remove_option_at(optstr
, ol
.begin
, ol
.end
);
430 * @optstr: string with comma separated list of options
431 * @user: returns newly allocated string with userspace options
432 * @vfs: returns newly allocated string with VFS options
433 * @fs: returns newly allocated string with FS options
434 * @ignore_user: option mask for options that should be ignored
435 * @ignore_vfs: option mask for options that should be ignored
439 * mnt_split_optstr(optstr, &u, NULL, NULL, MNT_NOMTAB, 0);
441 * returns all userspace options, the options that do not belong to
444 * Note that FS options are all options that are undefined in MNT_USERSPACE_MAP
447 * Returns: 0 on success, or a negative number in case of error.
449 int mnt_split_optstr(const char *optstr
, char **user
, char **vfs
,
450 char **fs
, int ignore_user
, int ignore_vfs
)
453 char *name
, *val
, *str
= (char *) optstr
;
454 size_t namesz
, valsz
, chunsz
;
455 struct libmnt_optmap
const *maps
[2];
456 struct ul_buffer xvfs
= UL_INIT_BUFFER
,
457 xfs
= UL_INIT_BUFFER
,
458 xuser
= UL_INIT_BUFFER
;
463 maps
[0] = mnt_get_builtin_optmap(MNT_LINUX_MAP
);
464 maps
[1] = mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
466 chunsz
= strlen(optstr
) / 2;
468 while (!mnt_optstr_next_option(&str
, &name
, &namesz
, &val
, &valsz
)) {
469 struct ul_buffer
*buf
= NULL
;
470 const struct libmnt_optmap
*ent
= NULL
;
471 const struct libmnt_optmap
*m
=
472 mnt_optmap_get_entry(maps
, 2, name
, namesz
, &ent
);
475 continue; /* ignore undefined options (comments) */
477 /* ignore name=<value> if options map expects <name> only */
478 if (valsz
&& mnt_optmap_entry_novalue(ent
))
481 if (ent
&& m
&& m
== maps
[0] && vfs
) {
482 if (ignore_vfs
&& (ent
->mask
& ignore_vfs
))
486 } else if (ent
&& m
&& m
== maps
[1] && user
) {
487 if (ignore_user
&& (ent
->mask
& ignore_user
))
491 } else if (!m
&& fs
) {
497 if (ul_buffer_is_empty(buf
))
498 ul_buffer_set_chunksize(buf
, chunsz
);
499 rc
= mnt_buffer_append_option(buf
, name
, namesz
, val
, valsz
, 0);
506 *vfs
= rc
? NULL
: ul_buffer_get_data(&xvfs
, NULL
, NULL
);
508 *fs
= rc
? NULL
: ul_buffer_get_data(&xfs
, NULL
, NULL
);
510 *user
= rc
? NULL
: ul_buffer_get_data(&xuser
, NULL
, NULL
);
512 ul_buffer_free_data(&xvfs
);
513 ul_buffer_free_data(&xfs
);
514 ul_buffer_free_data(&xuser
);
521 * mnt_optstr_get_options
522 * @optstr: string with a comma separated list of options
523 * @subset: returns newly allocated string with options
525 * @ignore: mask of the options that should be ignored
527 * Extracts options from @optstr that belong to the @map, for example:
529 * mnt_optstr_get_options(optstr, &p,
530 * mnt_get_builtin_optmap(MNT_LINUX_MAP),
533 * the 'p' returns all VFS options, the options that do not belong to mtab
536 * Returns: 0 on success, or a negative number in case of error.
538 int mnt_optstr_get_options(const char *optstr
, char **subset
,
539 const struct libmnt_optmap
*map
, int ignore
)
541 struct libmnt_optmap
const *maps
[1];
542 struct ul_buffer buf
= UL_INIT_BUFFER
;
543 char *name
, *val
, *str
= (char *) optstr
;
544 size_t namesz
, valsz
;
547 if (!optstr
|| !subset
)
552 ul_buffer_set_chunksize(&buf
, strlen(optstr
)/2);
554 while (!mnt_optstr_next_option(&str
, &name
, &namesz
, &val
, &valsz
)) {
555 const struct libmnt_optmap
*ent
;
557 mnt_optmap_get_entry(maps
, 1, name
, namesz
, &ent
);
559 if (!ent
|| !ent
->id
)
560 continue; /* ignore undefined options (comments) */
562 if (ignore
&& (ent
->mask
& ignore
))
565 /* ignore name=<value> if options map expects <name> only */
566 if (valsz
&& mnt_optmap_entry_novalue(ent
))
569 rc
= mnt_buffer_append_option(&buf
, name
, namesz
, val
, valsz
, 0);
574 *subset
= rc
? NULL
: ul_buffer_get_data(&buf
, NULL
, NULL
);
576 ul_buffer_free_data(&buf
);
581 * @optstr: string with comma separated list of options
582 * @wanted: options expected in @optstr
583 * @missing: returns options from @wanted which missing in @optstr (optional)
585 * Retursn: <0 on error, 0 on missing options, 1 if nothing is missing
587 int mnt_optstr_get_missing(const char *optstr
, const char *wanted
, char **missing
)
589 char *name
, *val
, *str
= (char *) wanted
;
590 size_t namesz
= 0, valsz
= 0;
591 struct ul_buffer buf
= UL_INIT_BUFFER
;
597 /* caller wants data, prepare buffer */
598 ul_buffer_set_chunksize(&buf
, strlen(wanted
) + 3); /* to call realloc() only once */
602 while (!mnt_optstr_next_option(&str
, &name
, &namesz
, &val
, &valsz
)) {
604 rc
= mnt_optstr_locate_option((char *) optstr
, name
, namesz
, NULL
);
605 if (rc
== 1) { /* not found */
608 rc
= mnt_buffer_append_option(&buf
, name
, namesz
, val
, valsz
, 0);
615 if (!rc
&& missing
) {
616 if (ul_buffer_is_empty(&buf
))
619 *missing
= ul_buffer_get_data(&buf
, NULL
, NULL
);
621 ul_buffer_free_data(&buf
);
627 * mnt_optstr_get_flags:
628 * @optstr: string with comma separated list of options
629 * @flags: returns mount flags
632 * Returns in @flags IDs of options from @optstr as defined in the @map.
636 * "bind,exec,foo,bar" --returns-> MS_BIND
638 * "bind,noexec,foo,bar" --returns-> MS_BIND|MS_NOEXEC
640 * Note that @flags are not zeroized by this function! This function sets/unsets
641 * bits in the @flags only.
643 * Returns: 0 on success or negative number in case of error
645 int mnt_optstr_get_flags(const char *optstr
, unsigned long *flags
,
646 const struct libmnt_optmap
*map
)
648 struct libmnt_optmap
const *maps
[2];
649 char *name
, *str
= (char *) optstr
;
650 size_t namesz
= 0, valsz
= 0;
653 if (!optstr
|| !flags
|| !map
)
658 if (map
== mnt_get_builtin_optmap(MNT_LINUX_MAP
))
660 * Add userspace map -- the "user" is interpreted as
661 * MS_NO{EXEC,SUID,DEV}.
663 maps
[nmaps
++] = mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
665 while(!mnt_optstr_next_option(&str
, &name
, &namesz
, NULL
, &valsz
)) {
666 const struct libmnt_optmap
*ent
;
667 const struct libmnt_optmap
*m
;
669 m
= mnt_optmap_get_entry(maps
, nmaps
, name
, namesz
, &ent
);
670 if (!m
|| !ent
|| !ent
->id
)
673 /* ignore name=<value> if options map expects <name> only */
674 if (valsz
&& mnt_optmap_entry_novalue(ent
))
677 if (m
== map
) { /* requested map */
678 if (ent
->mask
& MNT_INVERT
)
683 } else if (nmaps
== 2 && m
== maps
[1] && valsz
== 0) {
685 * Special case -- translate "user" (but no user=) to
688 if (ent
->mask
& MNT_INVERT
)
690 if (ent
->id
& (MNT_MS_OWNER
| MNT_MS_GROUP
))
691 *flags
|= MS_OWNERSECURE
;
692 else if (ent
->id
& (MNT_MS_USER
| MNT_MS_USERS
))
701 * mnt_optstr_apply_flags:
702 * @optstr: string with comma separated list of options
703 * @flags: returns mount flags
706 * Removes/adds options to the @optstr according to flags. For example:
708 * MS_NOATIME and "foo,bar,noexec" --returns-> "foo,bar,noatime"
710 * Returns: 0 on success or negative number in case of error.
712 * Deprecated: since v2.39.
714 int mnt_optstr_apply_flags(char **optstr
, unsigned long flags
,
715 const struct libmnt_optmap
*map
)
717 struct libmnt_optmap
const *maps
[1];
718 char *name
, *next
, *val
;
719 size_t namesz
= 0, valsz
= 0, multi
= 0;
726 DBG(CXT
, ul_debug("applying 0x%08lx flags to '%s'", flags
, *optstr
));
733 * There is a convention that 'rw/ro' flags are always at the beginning of
734 * the string (although the 'rw' is unnecessary).
736 if (map
== mnt_get_builtin_optmap(MNT_LINUX_MAP
)) {
737 const char *o
= (fl
& MS_RDONLY
) ? "ro" : "rw";
740 (!strncmp(next
, "rw", 2) || !strncmp(next
, "ro", 2)) &&
741 (*(next
+ 2) == '\0' || *(next
+ 2) == ',')) {
743 /* already set, be paranoid and fix it */
746 rc
= mnt_optstr_prepend_option(optstr
, o
, NULL
);
749 next
= *optstr
; /* because realloc() */
759 * scan @optstr and remove options that are missing in
762 while(!mnt_optstr_next_option(&next
, &name
, &namesz
,
764 const struct libmnt_optmap
*ent
;
766 if (mnt_optmap_get_entry(maps
, 1, name
, namesz
, &ent
)) {
768 * remove unwanted option (rw/ro is already set)
770 if (!ent
|| !ent
->id
)
772 /* ignore name=<value> if options map expects <name> only */
773 if (valsz
&& mnt_optmap_entry_novalue(ent
))
776 if (ent
->id
== MS_RDONLY
||
777 (ent
->mask
& MNT_INVERT
) ||
778 (fl
& ent
->id
) != (unsigned long) ent
->id
) {
780 char *end
= val
? val
+ valsz
:
783 rc
= mnt_optstr_remove_option_at(
788 if (!(ent
->mask
& MNT_INVERT
)) {
789 /* allow options with prefix (X-mount.foo,X-mount.bar) more than once */
790 if (ent
->mask
& MNT_PREFIX
)
794 if (ent
->id
& MS_REC
)
801 /* remove from flags options which are allowed more than once */
804 /* add missing options (but ignore fl if contains MS_REC only) */
805 if (fl
&& fl
!= MS_REC
) {
807 const struct libmnt_optmap
*ent
;
808 struct ul_buffer buf
= UL_INIT_BUFFER
;
812 ul_buffer_refer_string(&buf
, *optstr
);
814 for (ent
= map
; ent
&& ent
->name
; ent
++) {
815 if ((ent
->mask
& MNT_INVERT
)
817 || (fl
& ent
->id
) != (unsigned long) ent
->id
)
820 /* don't add options which require values (e.g. offset=%d) */
821 p
= strchr(ent
->name
, '=');
823 if (p
> ent
->name
&& *(p
- 1) == '[')
826 continue; /* name= */
829 sz
= strlen(ent
->name
);
831 rc
= mnt_buffer_append_option(&buf
, ent
->name
, sz
, NULL
, 0, 0);
837 ul_buffer_free_data(&buf
);
840 *optstr
= ul_buffer_get_data(&buf
, NULL
, NULL
);
843 DBG(CXT
, ul_debug("new optstr '%s'", *optstr
));
846 DBG(CXT
, ul_debug("failed to apply flags [rc=%d]", rc
));
852 * @optstr: options string
853 * @pattern: comma delimited list of options
855 * The "no" could be used for individual items in the @options list. The "no"
856 * prefix does not have a global meaning.
858 * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
859 * DIFFERENT meanings; each option is matched explicitly as specified.
861 * The "no" prefix interpretation could be disabled by the "+" prefix, for example
862 * "+noauto" matches if @optstr literally contains the "noauto" string.
864 * The alone "no" is error and all matching ends with False.
866 * "xxx,yyy,zzz" : "nozzz" -> False
868 * "xxx,yyy,zzz" : "xxx,noeee" -> True
870 * "bar,zzz" : "nofoo" -> True (does not contain "foo")
872 * "nofoo,bar" : "nofoo" -> True (does not contain "foo")
874 * "nofoo,bar" : "+nofoo" -> True (contains "nofoo")
876 * "bar,zzz" : "+nofoo" -> False (does not contain "nofoo")
878 * "bar,zzz" : "" or "+" -> True (empty pattern is matching)
882 * "" : "foo" -> False
884 * "" : "nofoo" -> True
886 * "" : "no,foo" -> False (alone "no" is error)
888 * "no" : "+no" -> True ("no" is an option due to "+")
890 * Returns: 1 if pattern is matching, else 0. This function also returns 0
891 * if @pattern is NULL and @optstr is non-NULL.
893 int mnt_match_options(const char *optstr
, const char *pattern
)
895 char *name
, *pat
= (char *) pattern
;
896 char *buf
= NULL
, *patval
;
897 size_t namesz
= 0, patvalsz
= 0;
900 if (!pattern
&& !optstr
)
902 if (pattern
&& optstr
&& !*pattern
&& !*optstr
)
907 /* walk on pattern string
909 while (match
&& !mnt_optstr_next_option(&pat
, &name
, &namesz
,
910 &patval
, &patvalsz
)) {
917 else if ((no
= (startswith(name
, "no") != NULL
))) {
918 name
+= 2, namesz
-= 2;
919 if (!*name
|| *name
== ',') {
921 break; /* alone "no" keyword is error */
925 if (optstr
&& *optstr
&& *name
) {
927 buf
= malloc(strlen(pattern
) + 1);
932 xstrncpy(buf
, name
, namesz
+ 1);
933 rc
= mnt_optstr_get_option(optstr
, buf
, &val
, &sz
);
936 rc
= 0; /* empty pattern matches */
938 rc
= 1; /* not found in empty string */
941 /* check also value (if the pattern is "foo=value") */
942 if (rc
== 0 && patvalsz
> 0 &&
943 (patvalsz
!= sz
|| strncmp(patval
, val
, sz
) != 0))
948 match
= no
== 0 ? 1 : 0;
950 case 1: /* not found */
951 match
= no
== 1 ? 1 : 0;
953 default: /* parse error */
964 static int test_append(struct libmnt_test
*ts
__attribute__((unused
)),
965 int argc
, char *argv
[])
967 const char *value
= NULL
, *name
;
973 optstr
= strdup(argv
[1]);
981 rc
= mnt_optstr_append_option(&optstr
, name
, value
);
983 printf("result: >%s<\n", optstr
);
988 static int test_prepend(struct libmnt_test
*ts
__attribute__((unused
)),
989 int argc
, char *argv
[])
991 const char *value
= NULL
, *name
;
997 optstr
= strdup(argv
[1]);
1005 rc
= mnt_optstr_prepend_option(&optstr
, name
, value
);
1007 printf("result: >%s<\n", optstr
);
1012 static int test_split(struct libmnt_test
*ts
__attribute__((unused
)),
1013 int argc
, char *argv
[])
1015 char *optstr
, *user
= NULL
, *fs
= NULL
, *vfs
= NULL
;
1021 optstr
= strdup(argv
[1]);
1025 rc
= mnt_split_optstr(optstr
, &user
, &vfs
, &fs
, 0, 0);
1027 printf("user : %s\n", user
);
1028 printf("vfs : %s\n", vfs
);
1029 printf("fs : %s\n", fs
);
1039 static int test_flags(struct libmnt_test
*ts
__attribute__((unused
)),
1040 int argc
, char *argv
[])
1044 unsigned long fl
= 0;
1049 optstr
= strdup(argv
[1]);
1053 rc
= mnt_optstr_get_flags(optstr
, &fl
, mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1056 printf("mountflags: 0x%08lx\n", fl
);
1059 rc
= mnt_optstr_get_flags(optstr
, &fl
, mnt_get_builtin_optmap(MNT_USERSPACE_MAP
));
1062 printf("userspace-mountflags: 0x%08lx\n", fl
);
1068 static int test_apply(struct libmnt_test
*ts
__attribute__((unused
)),
1069 int argc
, char *argv
[])
1073 unsigned long flags
;
1078 if (!strcmp(argv
[1], "--user"))
1079 map
= MNT_USERSPACE_MAP
;
1080 else if (!strcmp(argv
[1], "--linux"))
1081 map
= MNT_LINUX_MAP
;
1083 fprintf(stderr
, "unknown option '%s'\n", argv
[1]);
1087 optstr
= strdup(argv
[2]);
1090 flags
= strtoul(argv
[3], NULL
, 16);
1092 printf("flags: 0x%08lx\n", flags
);
1094 rc
= mnt_optstr_apply_flags(&optstr
, flags
, mnt_get_builtin_optmap(map
));
1095 printf("optstr: %s\n", optstr
);
1101 static int test_set(struct libmnt_test
*ts
__attribute__((unused
)),
1102 int argc
, char *argv
[])
1104 const char *value
= NULL
, *name
;
1110 optstr
= strdup(argv
[1]);
1118 rc
= mnt_optstr_set_option(&optstr
, name
, value
);
1120 printf("result: >%s<\n", optstr
);
1125 static int test_get(struct libmnt_test
*ts
__attribute__((unused
)),
1126 int argc
, char *argv
[])
1139 rc
= mnt_optstr_get_option(optstr
, name
, &val
, &sz
);
1141 printf("found; name: %s", name
);
1143 printf(", argument: size=%zd data=", sz
);
1144 if (fwrite(val
, 1, sz
, stdout
) != sz
)
1149 printf("%s: not found\n", name
);
1151 printf("parse error: %s\n", optstr
);
1155 static int test_missing(struct libmnt_test
*ts
__attribute__((unused
)),
1156 int argc
, char *argv
[])
1160 char *missing
= NULL
;
1168 rc
= mnt_optstr_get_missing(optstr
, wanted
, &missing
);
1170 printf("missing: %s\n", missing
);
1172 printf("nothing\n");
1175 printf("parse error: %s\n", optstr
);
1179 static int test_remove(struct libmnt_test
*ts
__attribute__((unused
)),
1180 int argc
, char *argv
[])
1188 optstr
= strdup(argv
[1]);
1193 rc
= mnt_optstr_remove_option(&optstr
, name
);
1195 printf("result: >%s<\n", optstr
);
1200 static int test_dedup(struct libmnt_test
*ts
__attribute__((unused
)),
1201 int argc
, char *argv
[])
1209 optstr
= strdup(argv
[1]);
1214 rc
= mnt_optstr_deduplicate_option(&optstr
, name
);
1216 printf("result: >%s<\n", optstr
);
1221 static int test_match(struct libmnt_test
*ts
__attribute__((unused
)),
1222 int argc
, char *argv
[])
1224 char *optstr
, *pattern
;
1231 printf("%-6s: \"%s\"\t:\t\"%s\"\n",
1232 mnt_match_options(optstr
, pattern
) == 1 ? "true" : "false",
1237 int main(int argc
, char *argv
[])
1239 struct libmnt_test tss
[] = {
1240 { "--append", test_append
, "<optstr> <name> [<value>] append value to optstr" },
1241 { "--prepend",test_prepend
,"<optstr> <name> [<value>] prepend value to optstr" },
1242 { "--set", test_set
, "<optstr> <name> [<value>] (un)set value" },
1243 { "--get", test_get
, "<optstr> <name> search name in optstr" },
1244 { "--missing",test_missing
,"<optstr> <wanted> what from wanted is missing" },
1245 { "--remove", test_remove
, "<optstr> <name> remove name in optstr" },
1246 { "--dedup", test_dedup
, "<optstr> <name> deduplicate name in optstr" },
1247 { "--match", test_match
, "<optstr> <pattern> compare optstr with pattern" },
1248 { "--split", test_split
, "<optstr> split into FS, VFS and userspace" },
1249 { "--flags", test_flags
, "<optstr> convert options to MS_* flags" },
1250 { "--apply", test_apply
, "--{linux,user} <optstr> <mask> apply mask to optstr" },
1254 return mnt_run_test(tss
, argc
, argv
);
1256 #endif /* TEST_PROGRAM */