summaryrefslogtreecommitdiffstats
path: root/src/shared/fstab-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/fstab-util.c')
-rw-r--r--src/shared/fstab-util.c138
1 files changed, 77 insertions, 61 deletions
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index 55e76b6..60ceff5 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -74,8 +74,8 @@ bool fstab_is_extrinsic(const char *mount, const char *opts) {
"/run/initramfs", /* This should stay around from before we boot until after we shutdown */
"/run/nextroot", /* Similar (though might be updated from the host) */
"/proc", /* All of this is API VFS */
- "/sys", /* … dito … */
- "/dev")) /* … dito … */
+ "/sys", /* … ditto … */
+ "/dev")) /* … ditto … */
return true;
/* If this is an initrd mount, and we are not in the initrd, then leave
@@ -105,6 +105,34 @@ static int fstab_is_same_node(const char *what_fstab, const char *path) {
return false;
}
+int fstab_has_mount_point_prefix_strv(char **prefixes) {
+ _cleanup_endmntent_ FILE *f = NULL;
+
+ assert(prefixes);
+
+ /* This function returns true if at least one entry in fstab has a mount point that starts with one
+ * of the passed prefixes. */
+
+ if (!fstab_enabled())
+ return false;
+
+ f = setmntent(fstab_path(), "re");
+ if (!f)
+ return errno == ENOENT ? false : -errno;
+
+ for (;;) {
+ struct mntent *me;
+
+ errno = 0;
+ me = getmntent(f);
+ if (!me)
+ return errno != 0 ? -errno : false;
+
+ if (path_startswith_strv(me->mnt_dir, prefixes))
+ return true;
+ }
+}
+
int fstab_is_mount_point_full(const char *where, const char *path) {
_cleanup_endmntent_ FILE *f = NULL;
int r;
@@ -136,8 +164,6 @@ int fstab_is_mount_point_full(const char *where, const char *path) {
if (r > 0 || (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r)))
return r;
}
-
- return false;
}
int fstab_filter_options(
@@ -148,16 +174,16 @@ int fstab_filter_options(
char ***ret_values,
char **ret_filtered) {
- const char *namefound = NULL, *x;
- _cleanup_strv_free_ char **stor = NULL, **values = NULL;
- _cleanup_free_ char *value = NULL, **filtered = NULL;
+ _cleanup_strv_free_ char **values = NULL;
+ _cleanup_free_ char *value = NULL, *filtered = NULL;
+ const char *namefound = NULL;
int r;
- assert(names && *names);
+ assert(!isempty(names));
assert(!(ret_value && ret_values));
if (!opts)
- goto answer;
+ goto finish;
/* Finds any options matching 'names', and returns:
* - the last matching option name in ret_namefound,
@@ -169,50 +195,49 @@ int fstab_filter_options(
*
* Returns negative on error, true if any matching options were found, false otherwise. */
- if (ret_filtered || ret_value || ret_values) {
+ if (ret_value || ret_values || ret_filtered) {
+ _cleanup_strv_free_ char **opts_split = NULL;
+ _cleanup_free_ char **filtered_strv = NULL; /* strings are owned by 'opts_split' */
+
/* For backwards compatibility, we need to pass-through escape characters.
* The only ones we "consume" are the ones used as "\," or "\\". */
- r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX);
+ r = strv_split_full(&opts_split, opts, ",", EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX);
if (r < 0)
return r;
- filtered = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
- if (!filtered)
- return -ENOMEM;
+ STRV_FOREACH(opt, opts_split) {
+ bool found = false;
+ const char *x;
- char **t = filtered;
- for (char **s = t; *s; s++) {
NULSTR_FOREACH(name, names) {
- x = startswith(*s, name);
+ x = startswith(*opt, name);
if (!x)
continue;
- /* Match name, but when ret_values, only when followed by assignment. */
+
+ /* If ret_values, only accept settings followed by assignment. */
if (*x == '=' || (!ret_values && *x == '\0')) {
- /* Keep the last occurrence found */
namefound = name;
- goto found;
+ found = true;
+ break;
}
}
- *t = *s;
- t++;
- continue;
- found:
- if (ret_value || ret_values) {
- assert(IN_SET(*x, '=', '\0'));
-
- if (ret_value) {
+ if (found) {
+ if (ret_value)
r = free_and_strdup(&value, *x == '=' ? x + 1 : NULL);
- if (r < 0)
- return r;
- } else if (*x) {
+ else if (ret_values)
r = strv_extend(&values, x + 1);
- if (r < 0)
- return r;
- }
- }
+ else
+ r = 0;
+ } else
+ r = strv_push(&filtered_strv, *opt);
+ if (r < 0)
+ return r;
}
- *t = NULL;
+
+ filtered = strv_join_full(filtered_strv, ",", NULL, /* escape_separator = */ true);
+ if (!filtered)
+ return -ENOMEM;
} else
for (const char *word = opts;;) {
const char *end = word;
@@ -226,64 +251,55 @@ int fstab_filter_options(
if (IN_SET(*end, ',', '\0'))
break;
assert(*end == '\\');
- end ++; /* Skip the backslash */
+ end++; /* Skip the backslash */
if (*end != '\0')
- end ++; /* Skip the escaped char, but watch out for a trailing comma */
+ end++; /* Skip the escaped char, but watch out for a trailing comma */
}
NULSTR_FOREACH(name, names) {
- if (end < word + strlen(name))
- continue;
- if (!strneq(word, name, strlen(name)))
+ const char *x = startswith(word, name);
+ if (!x || x > end)
continue;
/* We know that the string is NUL terminated, so *x is valid */
- x = word + strlen(name);
if (IN_SET(*x, '\0', '=', ',')) {
namefound = name;
break;
}
}
- if (*end)
- word = end + 1;
- else
+ if (*end == '\0')
break;
+
+ word = end + 1;
}
-answer:
+finish:
if (ret_namefound)
- *ret_namefound = namefound;
- if (ret_filtered) {
- char *f;
-
- f = strv_join_full(filtered, ",", NULL, true);
- if (!f)
- return -ENOMEM;
-
- *ret_filtered = f;
- }
+ *ret_namefound = namefound; /* owned by 'names' (passed-in) */
if (ret_value)
*ret_value = TAKE_PTR(value);
if (ret_values)
*ret_values = TAKE_PTR(values);
+ if (ret_filtered)
+ *ret_filtered = TAKE_PTR(filtered);
return !!namefound;
}
-int fstab_find_pri(const char *options, int *ret) {
- _cleanup_free_ char *opt = NULL;
+int fstab_find_pri(const char *opts, int *ret) {
+ _cleanup_free_ char *v = NULL;
int r, pri;
assert(ret);
- r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL, NULL);
+ r = fstab_filter_options(opts, "pri\0", NULL, &v, NULL, NULL);
if (r < 0)
return r;
- if (r == 0 || !opt)
+ if (r == 0 || !v)
return 0;
- r = safe_atoi(opt, &pri);
+ r = safe_atoi(v, &pri);
if (r < 0)
return r;