]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/optstr.c
2 * Copyright (C) 2008,2009,2012 Karel Zak <kzak@redhat.com>
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
10 * @title: Options string
11 * @short_description: low-level API for working with mount options
13 * This is a simple and low-level API to working with mount options that are stored
18 #ifdef HAVE_LIBSELINUX
19 #include <selinux/selinux.h>
20 #include <selinux/context.h>
28 struct libmnt_optloc
{
36 #define mnt_init_optloc(_ol) (memset((_ol), 0, sizeof(struct libmnt_optloc)))
38 #define mnt_optmap_entry_novalue(e) \
39 (e && (e)->name && !strchr((e)->name, '=') && !((e)->mask & MNT_PREFIX))
42 * Parses the first option from @optstr. The @optstr pointer is set to the beginning
45 * Returns -EINVAL on parse error, 1 at the end of optstr and 0 on success.
47 static int mnt_optstr_parse_next(char **optstr
, char **name
, size_t *namesz
,
48 char **value
, size_t *valsz
)
51 char *start
= NULL
, *stop
= NULL
, *p
, *sep
= NULL
;
68 /* trim leading commas as to not invalidate option
69 * strings with multiple consecutive commas */
70 while (optstr0
&& *optstr0
== ',')
73 for (p
= optstr0
; p
&& *p
; p
++) {
75 start
= p
; /* beginning of the option item */
77 open_quote
^= 1; /* reverse the status */
79 continue; /* still in quoted block */
80 if (!sep
&& p
> start
&& *p
== '=')
81 sep
= p
; /* name and value separator */
83 stop
= p
; /* terminate the option item */
84 else if (*(p
+ 1) == '\0')
85 stop
= p
+ 1; /* end of optstr */
94 *namesz
= sep
? sep
- start
: stop
- start
;
95 *optstr
= *stop
? stop
+ 1 : stop
;
101 *valsz
= stop
- sep
- 1;
106 return 1; /* end of optstr */
109 DBG(OPTIONS
, ul_debug("parse error: \"%s\"", optstr0
));
114 * Locates the first option that matches @name. The @end is set to the
115 * char behind the option (it means ',' or \0).
117 * Returns negative number on parse error, 1 when not found and 0 on success.
119 static int mnt_optstr_locate_option(char *optstr
, const char *name
,
120 struct libmnt_optloc
*ol
)
132 namesz
= strlen(name
);
135 rc
= mnt_optstr_parse_next(&optstr
, &n
, &nsz
,
136 &ol
->value
, &ol
->valsz
);
140 if (namesz
== nsz
&& strncmp(n
, name
, nsz
) == 0) {
142 ol
->end
= *(optstr
- 1) == ',' ? optstr
- 1 : optstr
;
152 * mnt_optstr_next_option:
153 * @optstr: option string, returns the position of the next option
154 * @name: returns the option name
155 * @namesz: returns the option name length
156 * @value: returns the option value or NULL
157 * @valuesz: returns the option value length or zero
159 * Parses the first option in @optstr.
161 * Returns: 0 on success, 1 at the end of @optstr or negative number in case of
164 int mnt_optstr_next_option(char **optstr
, char **name
, size_t *namesz
,
165 char **value
, size_t *valuesz
)
167 if (!optstr
|| !*optstr
)
169 return mnt_optstr_parse_next(optstr
, name
, namesz
, value
, valuesz
);
172 static int __mnt_optstr_append_option(char **optstr
,
173 const char *name
, size_t nsz
,
174 const char *value
, size_t vsz
)
184 osz
= *optstr
? strlen(*optstr
) : 0;
186 sz
= osz
+ nsz
+ 1; /* 1: '\0' */
188 sz
++; /* ',' options separator */
190 sz
+= vsz
+ 1; /* 1: '=' */
192 p
= realloc(*optstr
, sz
);
202 memcpy(p
, name
, nsz
);
207 memcpy(p
, value
, vsz
);
216 * mnt_optstr_append_option:
217 * @optstr: option string or NULL, returns a reallocated string
221 * Returns: 0 on success or -1 in case of error. After an error the @optstr should
224 int mnt_optstr_append_option(char **optstr
, const char *name
, const char *value
)
234 vsz
= value
? strlen(value
) : 0;
236 return __mnt_optstr_append_option(optstr
, name
, nsz
, value
, vsz
);
240 * mnt_optstr_prepend_option:
241 * @optstr: option string or NULL, returns a reallocated string
245 * Returns: 0 on success or -1 in case of error. After an error the @optstr should
248 int mnt_optstr_prepend_option(char **optstr
, const char *name
, const char *value
)
260 rc
= mnt_optstr_append_option(optstr
, name
, value
);
261 if (!rc
&& tmp
&& *tmp
)
262 rc
= mnt_optstr_append_option(optstr
, tmp
, NULL
);
271 DBG(OPTIONS
, ul_debug("failed to prepend '%s[=%s]' to '%s'",
272 name
, value
, *optstr
));
277 * mnt_optstr_get_option:
278 * @optstr: string with a comma separated list of options
279 * @name: requested option name
280 * @value: returns a pointer to the beginning of the value (e.g. name=VALUE) or NULL
281 * @valsz: returns size of the value or 0
283 * Returns: 0 on success, 1 when not found the @name or negative number in case
286 int mnt_optstr_get_option(const char *optstr
, const char *name
,
287 char **value
, size_t *valsz
)
289 struct libmnt_optloc ol
;
295 mnt_init_optloc(&ol
);
297 rc
= mnt_optstr_locate_option((char *) optstr
, name
, &ol
);
308 * mnt_optstr_deduplicate_option:
309 * @optstr: string with a comma separated list of options
310 * @name: requested option name
312 * Removes all instances of @name except the last one.
314 * Returns: 0 on success, 1 when not found the @name or negative number in case
317 int mnt_optstr_deduplicate_option(char **optstr
, const char *name
)
320 char *begin
= NULL
, *end
= NULL
, *opt
;
327 struct libmnt_optloc ol
;
329 mnt_init_optloc(&ol
);
331 rc
= mnt_optstr_locate_option(opt
, name
, &ol
);
334 /* remove the previous instance */
335 size_t shift
= strlen(*optstr
);
337 mnt_optstr_remove_option_at(optstr
, begin
, end
);
339 /* now all the offsets are not valid anymore - recount */
340 shift
-= strlen(*optstr
);
346 opt
= end
&& *end
? end
+ 1 : NULL
;
348 } while (rc
== 0 && opt
&& *opt
);
350 return rc
< 0 ? rc
: begin
? 0 : 1;
354 * The result never starts or ends with a comma or contains two commas
355 * (e.g. ",aaa,bbb" or "aaa,,bbb" or "aaa,")
357 int mnt_optstr_remove_option_at(char **optstr
, char *begin
, char *end
)
361 if (!optstr
|| !begin
|| !end
)
364 if ((begin
== *optstr
|| *(begin
- 1) == ',') && *end
== ',')
369 memmove(begin
, end
, sz
+ 1);
370 if (!*begin
&& (begin
> *optstr
) && *(begin
- 1) == ',')
376 /* insert 'substr' or '=substr' to @str on position @pos */
377 static int __attribute__((nonnull(1,2,3)))
378 insert_value(char **str
, char *pos
, const char *substr
, char **next
)
380 size_t subsz
= strlen(substr
); /* substring size */
381 size_t strsz
= strlen(*str
);
382 size_t possz
= strlen(pos
);
387 /* is it necessary to prepend '=' before the substring ? */
388 sep
= !(pos
> *str
&& *(pos
- 1) == '=');
390 /* save an offset of the place where we need to add substr */
393 p
= realloc(*str
, strsz
+ sep
+ subsz
+ 1);
397 /* zeroize the newly allocated memory -- valgrind loves us... */
398 memset(p
+ strsz
, 0, sep
+ subsz
+ 1);
400 /* set pointers to the reallocated string */
405 /* create a room for the new substring */
406 memmove(pos
+ subsz
+ sep
, pos
, possz
+ 1);
410 memcpy(pos
, substr
, subsz
);
413 /* set pointer to the next option */
422 * mnt_optstr_set_option:
423 * @optstr: string with a comma separated list of options
424 * @name: requested option
425 * @value: new value or NULL
427 * Set or unset the option @value.
429 * Returns: 0 on success, 1 when not found the @name or negative number in case
432 int mnt_optstr_set_option(char **optstr
, const char *name
, const char *value
)
434 struct libmnt_optloc ol
;
444 mnt_init_optloc(&ol
);
447 rc
= mnt_optstr_locate_option(*optstr
, name
, &ol
);
449 return rc
; /* parse error */
451 return mnt_optstr_append_option(optstr
, name
, value
); /* not found */
453 nameend
= ol
.begin
+ ol
.namesz
;
455 if (value
== NULL
&& ol
.value
&& ol
.valsz
)
456 /* remove unwanted "=value" */
457 mnt_optstr_remove_option_at(optstr
, nameend
, ol
.end
);
459 else if (value
&& ol
.value
== NULL
)
460 /* insert "=value" */
461 rc
= insert_value(optstr
, nameend
, value
, NULL
);
463 else if (value
&& ol
.value
&& strlen(value
) == ol
.valsz
)
464 /* simply replace =value */
465 memcpy(ol
.value
, value
, ol
.valsz
);
467 else if (value
&& ol
.value
) {
468 mnt_optstr_remove_option_at(optstr
, nameend
, ol
.end
);
469 rc
= insert_value(optstr
, nameend
, value
, NULL
);
475 * mnt_optstr_remove_option:
476 * @optstr: string with a comma separated list of options
477 * @name: requested option name
479 * Returns: 0 on success, 1 when not found the @name or negative number in case
482 int mnt_optstr_remove_option(char **optstr
, const char *name
)
484 struct libmnt_optloc ol
;
490 mnt_init_optloc(&ol
);
492 rc
= mnt_optstr_locate_option(*optstr
, name
, &ol
);
496 mnt_optstr_remove_option_at(optstr
, ol
.begin
, ol
.end
);
502 * @optstr: string with comma separated list of options
503 * @user: returns newly allocated string with userspace options
504 * @vfs: returns newly allocated string with VFS options
505 * @fs: returns newly allocated string with FS options
506 * @ignore_user: option mask for options that should be ignored
507 * @ignore_vfs: option mask for options that should be ignored
511 * mnt_split_optstr(optstr, &u, NULL, NULL, MNT_NOMTAB, 0);
513 * returns all userspace options, the options that do not belong to
516 * Note that FS options are all options that are undefined in MNT_USERSPACE_MAP
519 * Returns: 0 on success, or a negative number in case of error.
521 int mnt_split_optstr(const char *optstr
, char **user
, char **vfs
,
522 char **fs
, int ignore_user
, int ignore_vfs
)
524 char *name
, *val
, *str
= (char *) optstr
;
525 size_t namesz
, valsz
;
526 struct libmnt_optmap
const *maps
[2];
533 maps
[0] = mnt_get_builtin_optmap(MNT_LINUX_MAP
);
534 maps
[1] = mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
543 while (!mnt_optstr_next_option(&str
, &name
, &namesz
, &val
, &valsz
)) {
545 const struct libmnt_optmap
*ent
= NULL
;
546 const struct libmnt_optmap
*m
=
547 mnt_optmap_get_entry(maps
, 2, name
, namesz
, &ent
);
550 continue; /* ignore undefined options (comments) */
552 /* ignore name=<value> if options map expects <name> only */
553 if (valsz
&& mnt_optmap_entry_novalue(ent
))
556 if (ent
&& m
&& m
== maps
[0] && vfs
) {
557 if (ignore_vfs
&& (ent
->mask
& ignore_vfs
))
559 rc
= __mnt_optstr_append_option(vfs
, name
, namesz
,
561 } else if (ent
&& m
&& m
== maps
[1] && user
) {
562 if (ignore_user
&& (ent
->mask
& ignore_user
))
564 rc
= __mnt_optstr_append_option(user
, name
, namesz
,
567 rc
= __mnt_optstr_append_option(fs
, name
, namesz
,
590 * mnt_optstr_get_options
591 * @optstr: string with a comma separated list of options
592 * @subset: returns newly allocated string with options
594 * @ignore: mask of the options that should be ignored
596 * Extracts options from @optstr that belong to the @map, for example:
598 * mnt_optstr_get_options(optstr, &p,
599 * mnt_get_builtin_optmap(MNT_LINUX_MAP),
602 * the 'p' returns all VFS options, the options that do not belong to mtab
605 * Returns: 0 on success, or a negative number in case of error.
607 int mnt_optstr_get_options(const char *optstr
, char **subset
,
608 const struct libmnt_optmap
*map
, int ignore
)
610 struct libmnt_optmap
const *maps
[1];
611 char *name
, *val
, *str
= (char *) optstr
;
612 size_t namesz
, valsz
;
614 if (!optstr
|| !subset
)
620 while(!mnt_optstr_next_option(&str
, &name
, &namesz
, &val
, &valsz
)) {
622 const struct libmnt_optmap
*ent
;
624 mnt_optmap_get_entry(maps
, 1, name
, namesz
, &ent
);
626 if (!ent
|| !ent
->id
)
627 continue; /* ignore undefined options (comments) */
629 if (ignore
&& (ent
->mask
& ignore
))
632 /* ignore name=<value> if options map expects <name> only */
633 if (valsz
&& mnt_optmap_entry_novalue(ent
))
636 rc
= __mnt_optstr_append_option(subset
, name
, namesz
, val
, valsz
);
648 * mnt_optstr_get_flags:
649 * @optstr: string with comma separated list of options
650 * @flags: returns mount flags
653 * Returns in @flags IDs of options from @optstr as defined in the @map.
657 * "bind,exec,foo,bar" --returns-> MS_BIND
659 * "bind,noexec,foo,bar" --returns-> MS_BIND|MS_NOEXEC
661 * Note that @flags are not zeroized by this function! This function sets/unsets
662 * bits in the @flags only.
664 * Returns: 0 on success or negative number in case of error
666 int mnt_optstr_get_flags(const char *optstr
, unsigned long *flags
,
667 const struct libmnt_optmap
*map
)
669 struct libmnt_optmap
const *maps
[2];
670 char *name
, *str
= (char *) optstr
;
671 size_t namesz
= 0, valsz
= 0;
676 if (!optstr
|| !flags
|| !map
)
681 if (map
== mnt_get_builtin_optmap(MNT_LINUX_MAP
))
683 * Add userspace map -- the "user" is interpreted as
684 * MS_NO{EXEC,SUID,DEV}.
686 maps
[nmaps
++] = mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
688 while(!mnt_optstr_next_option(&str
, &name
, &namesz
, NULL
, &valsz
)) {
689 const struct libmnt_optmap
*ent
;
690 const struct libmnt_optmap
*m
;
692 m
= mnt_optmap_get_entry(maps
, nmaps
, name
, namesz
, &ent
);
693 if (!m
|| !ent
|| !ent
->id
)
696 /* ignore name=<value> if options map expects <name> only */
697 if (valsz
&& mnt_optmap_entry_novalue(ent
))
700 if (m
== map
) { /* requested map */
701 if (ent
->mask
& MNT_INVERT
)
706 } else if (nmaps
== 2 && m
== maps
[1] && valsz
== 0) {
708 * Special case -- translate "user" (but no user=) to
711 if (ent
->mask
& MNT_INVERT
)
713 if (ent
->id
& (MNT_MS_OWNER
| MNT_MS_GROUP
))
714 *flags
|= MS_OWNERSECURE
;
715 else if (ent
->id
& (MNT_MS_USER
| MNT_MS_USERS
))
724 * mnt_optstr_apply_flags:
725 * @optstr: string with comma separated list of options
726 * @flags: returns mount flags
729 * Removes/adds options to the @optstr according to flags. For example:
731 * MS_NOATIME and "foo,bar,noexec" --returns-> "foo,bar,noatime"
733 * Returns: 0 on success or negative number in case of error.
735 int mnt_optstr_apply_flags(char **optstr
, unsigned long flags
,
736 const struct libmnt_optmap
*map
)
738 struct libmnt_optmap
const *maps
[1];
739 char *name
, *next
, *val
;
740 size_t namesz
= 0, valsz
= 0;
749 DBG(CXT
, ul_debug("applying 0x%08lu flags to '%s'", flags
, *optstr
));
756 * There is a convention that 'rw/ro' flags are always at the beginning of
757 * the string (although the 'rw' is unnecessary).
759 if (map
== mnt_get_builtin_optmap(MNT_LINUX_MAP
)) {
760 const char *o
= (fl
& MS_RDONLY
) ? "ro" : "rw";
763 (!strncmp(next
, "rw", 2) || !strncmp(next
, "ro", 2)) &&
764 (*(next
+ 2) == '\0' || *(next
+ 2) == ',')) {
766 /* already set, be paranoid and fix it */
769 rc
= mnt_optstr_prepend_option(optstr
, o
, NULL
);
772 next
= *optstr
; /* because realloc() */
782 * scan @optstr and remove options that are missing in
785 while(!mnt_optstr_next_option(&next
, &name
, &namesz
,
787 const struct libmnt_optmap
*ent
;
789 if (mnt_optmap_get_entry(maps
, 1, name
, namesz
, &ent
)) {
791 * remove unwanted option (rw/ro is already set)
793 if (!ent
|| !ent
->id
)
795 /* ignore name=<value> if options map expects <name> only */
796 if (valsz
&& mnt_optmap_entry_novalue(ent
))
799 if (ent
->id
== MS_RDONLY
||
800 (ent
->mask
& MNT_INVERT
) ||
801 (fl
& ent
->id
) != (unsigned long) ent
->id
) {
803 char *end
= val
? val
+ valsz
:
806 rc
= mnt_optstr_remove_option_at(
811 if (!(ent
->mask
& MNT_INVERT
))
817 /* add missing options */
819 const struct libmnt_optmap
*ent
;
822 for (ent
= map
; ent
&& ent
->name
; ent
++) {
823 if ((ent
->mask
& MNT_INVERT
)
825 || (fl
& ent
->id
) != (unsigned long) ent
->id
)
828 /* don't add options which require values (e.g. offset=%d) */
829 p
= strchr(ent
->name
, '=');
831 if (p
> ent
->name
&& *(p
- 1) == '[')
834 continue; /* name= */
836 p
= strndup(ent
->name
, p
- ent
->name
);
841 mnt_optstr_append_option(optstr
, p
, NULL
);
844 mnt_optstr_append_option(optstr
, ent
->name
, NULL
);
848 DBG(CXT
, ul_debug("new optstr '%s'", *optstr
));
851 DBG(CXT
, ul_debug("failed to apply flags [rc=%d]", rc
));
856 * @optstr: string with comma separated list of options
857 * @value: pointer to the begin of the context value
858 * @valsz: size of the value
859 * @next: returns pointer to the next option (optional argument)
861 * Translates SELinux context from human to raw format. The function does not
862 * modify @optstr and returns zero if libmount is compiled without SELinux
865 * Returns: 0 on success, a negative number in case of error.
867 #ifndef HAVE_LIBSELINUX
868 int mnt_optstr_fix_secontext(char **optstr
__attribute__ ((__unused__
)),
869 char *value
__attribute__ ((__unused__
)),
870 size_t valsz
__attribute__ ((__unused__
)),
871 char **next
__attribute__ ((__unused__
)))
876 int mnt_optstr_fix_secontext(char **optstr
,
883 security_context_t raw
= NULL
;
884 char *p
, *val
, *begin
, *end
;
887 if (!optstr
|| !*optstr
|| !value
|| !valsz
)
890 DBG(CXT
, ul_debug("fixing SELinux context"));
895 /* the selinux contexts are quoted */
897 if (valsz
<= 2 || *(value
+ valsz
- 1) != '"')
898 return -EINVAL
; /* improperly quoted option string */
903 p
= strndup(value
, valsz
);
908 /* translate the context */
909 rc
= selinux_trans_to_raw_context((security_context_t
) p
, &raw
);
911 DBG(CXT
, ul_debug("SELinux context '%s' translated to '%s'",
912 p
, rc
== -1 ? "FAILED" : (char *) raw
));
915 if (rc
== -1 || !raw
)
919 /* create a quoted string from the raw context */
920 sz
= strlen((char *) raw
);
924 p
= val
= malloc(valsz
+ 3);
936 /* set new context */
937 mnt_optstr_remove_option_at(optstr
, begin
, end
);
938 rc
= insert_value(optstr
, begin
, val
, next
);
945 static int set_uint_value(char **optstr
, unsigned int num
,
946 char *begin
, char *end
, char **next
)
949 snprintf(buf
, sizeof(buf
), "%u", num
);
951 mnt_optstr_remove_option_at(optstr
, begin
, end
);
952 return insert_value(optstr
, begin
, buf
, next
);
956 * @optstr: string with a comma separated list of options
957 * @value: pointer to the beginning of the uid value
958 * @valsz: size of the value
959 * @next: returns pointer to the next option (optional argument)
961 * Translates "username" or "useruid" to the real UID.
964 * if (!mnt_optstr_get_option(optstr, "uid", &val, &valsz))
965 * mnt_optstr_fix_uid(&optstr, val, valsz, NULL);
967 * Returns: 0 on success, a negative number in case of error.
969 int mnt_optstr_fix_uid(char **optstr
, char *value
, size_t valsz
, char **next
)
974 if (!optstr
|| !*optstr
|| !value
|| !valsz
)
977 DBG(CXT
, ul_debug("fixing uid"));
981 if (valsz
== 7 && !strncmp(value
, "useruid", 7) &&
982 (*(value
+ 7) == ',' || !*(value
+ 7)))
983 rc
= set_uint_value(optstr
, getuid(), value
, end
, next
);
985 else if (!isdigit(*value
)) {
987 char *p
= strndup(value
, valsz
);
990 rc
= mnt_get_uid(p
, &id
);
994 rc
= set_uint_value(optstr
, id
, value
, end
, next
);
998 *next
= value
+ valsz
;
1007 * @optstr: string with a comma separated list of options
1008 * @value: pointer to the beginning of the uid value
1009 * @valsz: size of the value
1010 * @next: returns pointer to the next option (optional argument)
1012 * Translates "groupname" or "usergid" to the real GID.
1014 * Returns: 0 on success, a negative number in case of error.
1016 int mnt_optstr_fix_gid(char **optstr
, char *value
, size_t valsz
, char **next
)
1021 if (!optstr
|| !*optstr
|| !value
|| !valsz
)
1024 DBG(CXT
, ul_debug("fixing gid"));
1026 end
= value
+ valsz
;
1028 if (valsz
== 7 && !strncmp(value
, "usergid", 7) &&
1029 (*(value
+ 7) == ',' || !*(value
+ 7)))
1030 rc
= set_uint_value(optstr
, getgid(), value
, end
, next
);
1032 else if (!isdigit(*value
)) {
1034 char *p
= strndup(value
, valsz
);
1037 rc
= mnt_get_gid(p
, &id
);
1041 rc
= set_uint_value(optstr
, id
, value
, end
, next
);
1045 *next
= value
+ valsz
;
1053 * Converts "user" to "user=<username>".
1055 * Returns: 0 on success, negative number in case of error.
1057 int mnt_optstr_fix_user(char **optstr
)
1060 struct libmnt_optloc ol
;
1063 DBG(CXT
, ul_debug("fixing user"));
1065 mnt_init_optloc(&ol
);
1067 rc
= mnt_optstr_locate_option(*optstr
, "user", &ol
);
1069 return rc
== 1 ? 0 : rc
; /* 1: user= not found */
1071 username
= mnt_get_username(getuid());
1075 if (!ol
.valsz
|| (ol
.value
&& strncmp(ol
.value
, username
, ol
.valsz
))) {
1077 /* remove old value */
1078 mnt_optstr_remove_option_at(optstr
, ol
.value
, ol
.end
);
1080 rc
= insert_value(optstr
, ol
.value
? ol
.value
: ol
.end
,
1090 int test_append(struct libmnt_test
*ts
, int argc
, char *argv
[])
1092 const char *value
= NULL
, *name
;
1098 optstr
= strdup(argv
[1]);
1104 rc
= mnt_optstr_append_option(&optstr
, name
, value
);
1106 printf("result: >%s<\n", optstr
);
1111 int test_prepend(struct libmnt_test
*ts
, int argc
, char *argv
[])
1113 const char *value
= NULL
, *name
;
1119 optstr
= strdup(argv
[1]);
1125 rc
= mnt_optstr_prepend_option(&optstr
, name
, value
);
1127 printf("result: >%s<\n", optstr
);
1132 int test_split(struct libmnt_test
*ts
, int argc
, char *argv
[])
1134 char *optstr
, *user
= NULL
, *fs
= NULL
, *vfs
= NULL
;
1140 optstr
= strdup(argv
[1]);
1142 rc
= mnt_split_optstr(optstr
, &user
, &vfs
, &fs
, 0, 0);
1144 printf("user : %s\n", user
);
1145 printf("vfs : %s\n", vfs
);
1146 printf("fs : %s\n", fs
);
1156 int test_flags(struct libmnt_test
*ts
, int argc
, char *argv
[])
1160 unsigned long fl
= 0;
1165 optstr
= strdup(argv
[1]);
1167 rc
= mnt_optstr_get_flags(optstr
, &fl
, mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1170 printf("mountflags: 0x%08lx\n", fl
);
1173 rc
= mnt_optstr_get_flags(optstr
, &fl
, mnt_get_builtin_optmap(MNT_USERSPACE_MAP
));
1176 printf("userspace-mountflags: 0x%08lx\n", fl
);
1182 int test_apply(struct libmnt_test
*ts
, int argc
, char *argv
[])
1186 unsigned long flags
;
1191 if (!strcmp(argv
[1], "--user"))
1192 map
= MNT_USERSPACE_MAP
;
1193 else if (!strcmp(argv
[1], "--linux"))
1194 map
= MNT_LINUX_MAP
;
1196 fprintf(stderr
, "unknown option '%s'\n", argv
[1]);
1200 optstr
= strdup(argv
[2]);
1201 flags
= strtoul(argv
[3], NULL
, 16);
1203 printf("flags: 0x%08lx\n", flags
);
1205 rc
= mnt_optstr_apply_flags(&optstr
, flags
, mnt_get_builtin_optmap(map
));
1206 printf("optstr: %s\n", optstr
);
1212 int test_set(struct libmnt_test
*ts
, int argc
, char *argv
[])
1214 const char *value
= NULL
, *name
;
1220 optstr
= strdup(argv
[1]);
1226 rc
= mnt_optstr_set_option(&optstr
, name
, value
);
1228 printf("result: >%s<\n", optstr
);
1233 int test_get(struct libmnt_test
*ts
, int argc
, char *argv
[])
1246 rc
= mnt_optstr_get_option(optstr
, name
, &val
, &sz
);
1248 printf("found; name: %s", name
);
1250 printf(", argument: size=%zd data=", sz
);
1251 if (fwrite(val
, 1, sz
, stdout
) != sz
)
1256 printf("%s: not found\n", name
);
1258 printf("parse error: %s\n", optstr
);
1262 int test_remove(struct libmnt_test
*ts
, int argc
, char *argv
[])
1270 optstr
= strdup(argv
[1]);
1273 rc
= mnt_optstr_remove_option(&optstr
, name
);
1275 printf("result: >%s<\n", optstr
);
1280 int test_dedup(struct libmnt_test
*ts
, int argc
, char *argv
[])
1288 optstr
= strdup(argv
[1]);
1291 rc
= mnt_optstr_deduplicate_option(&optstr
, name
);
1293 printf("result: >%s<\n", optstr
);
1298 int test_fix(struct libmnt_test
*ts
, int argc
, char *argv
[])
1302 char *name
, *val
, *next
;
1303 size_t valsz
, namesz
;
1308 next
= optstr
= strdup(argv
[1]);
1310 printf("optstr: %s\n", optstr
);
1312 while (!mnt_optstr_next_option(&next
, &name
, &namesz
, &val
, &valsz
)) {
1314 if (!strncmp(name
, "uid", 3))
1315 rc
= mnt_optstr_fix_uid(&optstr
, val
, valsz
, &next
);
1316 else if (!strncmp(name
, "gid", 3))
1317 rc
= mnt_optstr_fix_gid(&optstr
, val
, valsz
, &next
);
1318 else if (!strncmp(name
, "context", 7))
1319 rc
= mnt_optstr_fix_secontext(&optstr
, val
, valsz
, &next
);
1324 rc
= mnt_optstr_fix_user(&optstr
);
1326 printf("fixed: %s\n", optstr
);
1333 int main(int argc
, char *argv
[])
1335 struct libmnt_test tss
[] = {
1336 { "--append", test_append
, "<optstr> <name> [<value>] append value to optstr" },
1337 { "--prepend",test_prepend
,"<optstr> <name> [<value>] prepend value to optstr" },
1338 { "--set", test_set
, "<optstr> <name> [<value>] (un)set value" },
1339 { "--get", test_get
, "<optstr> <name> search name in optstr" },
1340 { "--remove", test_remove
, "<optstr> <name> remove name in optstr" },
1341 { "--dedup", test_dedup
, "<optstr> <name> deduplicate name in optstr" },
1342 { "--split", test_split
, "<optstr> split into FS, VFS and userspace" },
1343 { "--flags", test_flags
, "<optstr> convert options to MS_* flags" },
1344 { "--apply", test_apply
, "--{linux,user} <optstr> <mask> apply mask to optstr" },
1345 { "--fix", test_fix
, "<optstr> fix uid=, gid=, user, and context=" },
1349 return mnt_run_test(tss
, argc
, argv
);
1351 #endif /* TEST_PROGRAM */