1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
8 #include "device-nodes.h"
9 #include "fstab-util.h"
11 #include "mount-util.h"
12 #include "nulstr-util.h"
13 #include "parse-util.h"
14 #include "path-util.h"
15 #include "string-util.h"
18 int fstab_has_fstype(const char *fstype
) {
19 _cleanup_endmntent_
FILE *f
= NULL
;
22 f
= setmntent(fstab_path(), "re");
24 return errno
== ENOENT
? false : -errno
;
30 return errno
!= 0 ? -errno
: false;
32 if (streq(m
->mnt_type
, fstype
))
38 bool fstab_is_extrinsic(const char *mount
, const char *opts
) {
40 /* Don't bother with the OS data itself */
41 if (PATH_IN_SET(mount
,
47 if (PATH_STARTSWITH_SET(mount
,
48 "/run/initramfs", /* This should stay around from before we boot until after we shutdown */
49 "/proc", /* All of this is API VFS */
50 "/sys", /* … dito … */
51 "/dev")) /* … dito … */
54 /* If this is an initrd mount, and we are not in the initrd, then leave
55 * this around forever, too. */
56 if (opts
&& fstab_test_option(opts
, "x-initrd.mount\0") && !in_initrd())
62 int fstab_is_mount_point(const char *mount
) {
63 _cleanup_endmntent_
FILE *f
= NULL
;
66 f
= setmntent(fstab_path(), "re");
68 return errno
== ENOENT
? false : -errno
;
74 return errno
!= 0 ? -errno
: false;
76 if (path_equal(m
->mnt_dir
, mount
))
82 int fstab_filter_options(const char *opts
, const char *names
,
83 const char **ret_namefound
, char **ret_value
, char **ret_filtered
) {
84 const char *name
, *namefound
= NULL
, *x
;
85 _cleanup_strv_free_
char **stor
= NULL
;
86 _cleanup_free_
char *v
= NULL
, **strv
= NULL
;
89 assert(names
&& *names
);
94 /* If !ret_value and !ret_filtered, this function is not allowed to fail. */
97 for (const char *word
= opts
;;) {
98 const char *end
= word
;
100 /* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is
101 * the only valid escape sequence, so we can do a very simple test here. */
103 size_t n
= strcspn(end
, ",");
106 if (n
> 0 && end
[-1] == '\\')
112 NULSTR_FOREACH(name
, names
) {
113 if (end
< word
+ strlen(name
))
115 if (!strneq(word
, name
, strlen(name
)))
118 /* We know that the string is NUL terminated, so *x is valid */
119 x
= word
+ strlen(name
);
120 if (IN_SET(*x
, '\0', '=', ',')) {
124 assert(eq
|| IN_SET(*x
, ',', '\0'));
126 r
= free_and_strndup(&v
,
128 eq
? end
- x
- 1 : 0);
143 r
= strv_split_full(&stor
, opts
, ",", EXTRACT_DONT_COALESCE_SEPARATORS
| EXTRACT_UNESCAPE_SEPARATORS
);
147 strv
= memdup(stor
, sizeof(char*) * (strv_length(stor
) + 1));
152 for (char **s
= strv
; *s
; s
++) {
153 NULSTR_FOREACH(name
, names
) {
154 x
= startswith(*s
, name
);
155 if (x
&& IN_SET(*x
, '\0', '='))
163 /* Keep the last occurrence found */
166 assert(IN_SET(*x
, '=', '\0'));
167 r
= free_and_strdup(&v
, *x
== '=' ? x
+ 1 : NULL
);
177 *ret_namefound
= namefound
;
181 f
= strv_join_full(strv
, ",", NULL
, true);
188 *ret_value
= TAKE_PTR(v
);
193 int fstab_extract_values(const char *opts
, const char *name
, char ***values
) {
194 _cleanup_strv_free_
char **optsv
= NULL
, **res
= NULL
;
201 optsv
= strv_split(opts
, ",");
205 STRV_FOREACH(s
, optsv
) {
209 arg
= startswith(*s
, name
);
210 if (!arg
|| *arg
!= '=')
212 r
= strv_extend(&res
, arg
+ 1);
217 *values
= TAKE_PTR(res
);
222 int fstab_find_pri(const char *options
, int *ret
) {
223 _cleanup_free_
char *opt
= NULL
;
228 r
= fstab_filter_options(options
, "pri\0", NULL
, &opt
, NULL
);
234 r
= safe_atoi(opt
, &pri
);
242 static char *unquote(const char *s
, const char* quotes
) {
246 /* This is rather stupid, simply removes the heading and
247 * trailing quotes if there is one. Doesn't care about
248 * escaping or anything.
250 * DON'T USE THIS FOR NEW CODE ANYMORE! */
256 if (strchr(quotes
, s
[0]) && s
[l
-1] == s
[0])
257 return strndup(s
+1, l
-2);
262 static char *tag_to_udev_node(const char *tagvalue
, const char *by
) {
263 _cleanup_free_
char *t
= NULL
, *u
= NULL
;
266 u
= unquote(tagvalue
, QUOTES
);
270 enc_len
= strlen(u
) * 4 + 1;
271 t
= new(char, enc_len
);
275 if (encode_devnode_name(u
, t
, enc_len
) < 0)
278 return strjoin("/dev/disk/by-", by
, "/", t
);
281 char *fstab_node_to_udev_node(const char *p
) {
284 if (startswith(p
, "LABEL="))
285 return tag_to_udev_node(p
+6, "label");
287 if (startswith(p
, "UUID="))
288 return tag_to_udev_node(p
+5, "uuid");
290 if (startswith(p
, "PARTUUID="))
291 return tag_to_udev_node(p
+9, "partuuid");
293 if (startswith(p
, "PARTLABEL="))
294 return tag_to_udev_node(p
+10, "partlabel");