From fc53809803cd2bc2434e312b19a18fa36776da12 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 05:50:40 +0200 Subject: Adding upstream version 256. Signed-off-by: Daniel Baumann --- src/shared/fstab-util.c | 138 +++++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 61 deletions(-) (limited to 'src/shared/fstab-util.c') 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; -- cgit v1.2.3