228 lines
6.9 KiB
Diff
228 lines
6.9 KiB
Diff
|
From c7abf1c87c44c54c16758e079dc3528a13d8e177 Mon Sep 17 00:00:00 2001
|
||
|
From: Karel Zak <kzak@redhat.com>
|
||
|
Date: Wed, 29 Nov 2023 12:19:55 +0100
|
||
|
Subject: libmount: add private mnt_optstr_get_missing()
|
||
|
|
||
|
The function compares two options strings and returns options which
|
||
|
are missing.
|
||
|
|
||
|
Addresses: https://issues.redhat.com/browse/RHEL-14612
|
||
|
Upstream: http://github.com/util-linux/util-linux/commit/722e4d47a9a21f09a6a719a0f510f29f12497ce5
|
||
|
Signed-off-by: Karel Zak <kzak@redhat.com>
|
||
|
---
|
||
|
libmount/src/mountP.h | 1 +
|
||
|
libmount/src/optstr.c | 104 ++++++++++++++++++++++++++++++++++++------
|
||
|
2 files changed, 92 insertions(+), 13 deletions(-)
|
||
|
|
||
|
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
|
||
|
index 22442ec55..30fac593a 100644
|
||
|
--- a/libmount/src/mountP.h
|
||
|
+++ b/libmount/src/mountP.h
|
||
|
@@ -401,6 +401,7 @@ extern const struct libmnt_optmap *mnt_optmap_get_entry(
|
||
|
/* optstr.c */
|
||
|
extern int mnt_optstr_get_uid(const char *optstr, const char *name, uid_t *uid);
|
||
|
extern int mnt_optstr_remove_option_at(char **optstr, char *begin, char *end);
|
||
|
+extern int mnt_optstr_get_missing(const char *optstr, const char *wanted, char **missing);
|
||
|
extern int mnt_optstr_fix_gid(char **optstr, char *value, size_t valsz, char **next);
|
||
|
extern int mnt_optstr_fix_uid(char **optstr, char *value, size_t valsz, char **next);
|
||
|
extern int mnt_optstr_fix_secontext(char **optstr, char *value, size_t valsz, char **next);
|
||
|
diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c
|
||
|
index 16800f571..a274e39b3 100644
|
||
|
--- a/libmount/src/optstr.c
|
||
|
+++ b/libmount/src/optstr.c
|
||
|
@@ -121,13 +121,16 @@ error:
|
||
|
* Locates the first option that matches @name. The @end is set to the
|
||
|
* char behind the option (it means ',' or \0).
|
||
|
*
|
||
|
+ * @ol is optional.
|
||
|
+ *
|
||
|
* Returns negative number on parse error, 1 when not found and 0 on success.
|
||
|
*/
|
||
|
-static int mnt_optstr_locate_option(char *optstr, const char *name,
|
||
|
+static int mnt_optstr_locate_option(char *optstr,
|
||
|
+ const char *name, size_t namesz,
|
||
|
struct libmnt_optloc *ol)
|
||
|
{
|
||
|
char *n;
|
||
|
- size_t namesz, nsz;
|
||
|
+ size_t nsz;
|
||
|
int rc;
|
||
|
|
||
|
if (!optstr)
|
||
|
@@ -135,25 +138,30 @@ static int mnt_optstr_locate_option(char *optstr, const char *name,
|
||
|
|
||
|
assert(name);
|
||
|
|
||
|
- namesz = strlen(name);
|
||
|
+ if (!namesz)
|
||
|
+ namesz = strlen(name);
|
||
|
+ if (!namesz)
|
||
|
+ return 1;
|
||
|
|
||
|
do {
|
||
|
rc = mnt_optstr_parse_next(&optstr, &n, &nsz,
|
||
|
- &ol->value, &ol->valsz);
|
||
|
+ ol ? &ol->value : NULL,
|
||
|
+ ol ? &ol->valsz : NULL);
|
||
|
if (rc)
|
||
|
break;
|
||
|
|
||
|
if (namesz == nsz && strncmp(n, name, nsz) == 0) {
|
||
|
- ol->begin = n;
|
||
|
- ol->end = *(optstr - 1) == ',' ? optstr - 1 : optstr;
|
||
|
- ol->namesz = nsz;
|
||
|
+ if (ol) {
|
||
|
+ ol->begin = n;
|
||
|
+ ol->end = *(optstr - 1) == ',' ? optstr - 1 : optstr;
|
||
|
+ ol->namesz = nsz;
|
||
|
+ }
|
||
|
return 0;
|
||
|
}
|
||
|
} while(1);
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
-
|
||
|
/**
|
||
|
* mnt_optstr_next_option:
|
||
|
* @optstr: option string, returns the position of the next option
|
||
|
@@ -284,7 +292,7 @@ int mnt_optstr_get_option(const char *optstr, const char *name,
|
||
|
if (!optstr || !name)
|
||
|
return -EINVAL;
|
||
|
|
||
|
- rc = mnt_optstr_locate_option((char *) optstr, name, &ol);
|
||
|
+ rc = mnt_optstr_locate_option((char *) optstr, name, 0, &ol);
|
||
|
if (!rc) {
|
||
|
if (value)
|
||
|
*value = ol.value;
|
||
|
@@ -316,7 +324,7 @@ int mnt_optstr_deduplicate_option(char **optstr, const char *name)
|
||
|
do {
|
||
|
struct libmnt_optloc ol = MNT_INIT_OPTLOC;
|
||
|
|
||
|
- rc = mnt_optstr_locate_option(opt, name, &ol);
|
||
|
+ rc = mnt_optstr_locate_option(opt, name, 0, &ol);
|
||
|
if (!rc) {
|
||
|
if (begin) {
|
||
|
/* remove the previous instance */
|
||
|
@@ -429,7 +437,7 @@ int mnt_optstr_set_option(char **optstr, const char *name, const char *value)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (*optstr)
|
||
|
- rc = mnt_optstr_locate_option(*optstr, name, &ol);
|
||
|
+ rc = mnt_optstr_locate_option(*optstr, name, 0, &ol);
|
||
|
if (rc < 0)
|
||
|
return rc; /* parse error */
|
||
|
if (rc == 1)
|
||
|
@@ -472,7 +480,7 @@ int mnt_optstr_remove_option(char **optstr, const char *name)
|
||
|
if (!optstr || !name)
|
||
|
return -EINVAL;
|
||
|
|
||
|
- rc = mnt_optstr_locate_option(*optstr, name, &ol);
|
||
|
+ rc = mnt_optstr_locate_option(*optstr, name, 0, &ol);
|
||
|
if (rc != 0)
|
||
|
return rc;
|
||
|
|
||
|
@@ -632,6 +640,52 @@ int mnt_optstr_get_options(const char *optstr, char **subset,
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * @optstr: string with comma separated list of options
|
||
|
+ * @wanted: options expected in @optstr
|
||
|
+ * @missing: returns options from @wanted which missing in @optstr (optional)
|
||
|
+ *
|
||
|
+ * Retursn: <0 on error, 0 on missing options, 1 if nothing is missing
|
||
|
+ */
|
||
|
+int mnt_optstr_get_missing(const char *optstr, const char *wanted, char **missing)
|
||
|
+{
|
||
|
+ char *name, *val, *str = (char *) wanted;
|
||
|
+ size_t namesz = 0, valsz = 0;
|
||
|
+ struct ul_buffer buf = UL_INIT_BUFFER;
|
||
|
+ int rc = 0;
|
||
|
+
|
||
|
+ if (!wanted)
|
||
|
+ return 1;
|
||
|
+ if (missing) {
|
||
|
+ /* caller wants data, prepare buffer */
|
||
|
+ ul_buffer_set_chunksize(&buf, strlen(wanted) + 3); /* to call realloc() only once */
|
||
|
+ *missing = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ while (!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
|
||
|
+
|
||
|
+ rc = mnt_optstr_locate_option((char *) optstr, name, namesz, NULL);
|
||
|
+ if (rc == 1) { /* not found */
|
||
|
+ if (!missing)
|
||
|
+ return 0;
|
||
|
+ rc = __buffer_append_option(&buf, name, namesz, val, valsz);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (rc < 0)
|
||
|
+ break;
|
||
|
+ rc = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!rc && missing) {
|
||
|
+ if (ul_buffer_is_empty(&buf))
|
||
|
+ rc = 1;
|
||
|
+ else
|
||
|
+ *missing = ul_buffer_get_data(&buf);
|
||
|
+ } else
|
||
|
+ ul_buffer_free_data(&buf);
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
|
||
|
/**
|
||
|
* mnt_optstr_get_flags:
|
||
|
@@ -1055,7 +1109,7 @@ int mnt_optstr_fix_user(char **optstr)
|
||
|
|
||
|
DBG(CXT, ul_debug("fixing user"));
|
||
|
|
||
|
- rc = mnt_optstr_locate_option(*optstr, "user", &ol);
|
||
|
+ rc = mnt_optstr_locate_option(*optstr, "user", 0, &ol);
|
||
|
if (rc)
|
||
|
return rc == 1 ? 0 : rc; /* 1: user= not found */
|
||
|
|
||
|
@@ -1378,6 +1432,29 @@ static int test_get(struct libmnt_test *ts, int argc, char *argv[])
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
+static int test_missing(struct libmnt_test *ts, int argc, char *argv[])
|
||
|
+{
|
||
|
+ const char *optstr;
|
||
|
+ const char *wanted;
|
||
|
+ char *missing = NULL;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ if (argc < 2)
|
||
|
+ return -EINVAL;
|
||
|
+ optstr = argv[1];
|
||
|
+ wanted = argv[2];
|
||
|
+
|
||
|
+ rc = mnt_optstr_get_missing(optstr, wanted, &missing);
|
||
|
+ if (rc == 0)
|
||
|
+ printf("missing: %s\n", missing);
|
||
|
+ else if (rc == 1) {
|
||
|
+ printf("nothing\n");
|
||
|
+ rc = 0;
|
||
|
+ } else
|
||
|
+ printf("parse error: %s\n", optstr);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
static int test_remove(struct libmnt_test *ts, int argc, char *argv[])
|
||
|
{
|
||
|
const char *name;
|
||
|
@@ -1456,6 +1533,7 @@ int main(int argc, char *argv[])
|
||
|
{ "--prepend",test_prepend,"<optstr> <name> [<value>] prepend value to optstr" },
|
||
|
{ "--set", test_set, "<optstr> <name> [<value>] (un)set value" },
|
||
|
{ "--get", test_get, "<optstr> <name> search name in optstr" },
|
||
|
+ { "--missing",test_missing,"<optstr> <wanted> what from wanted is missing" },
|
||
|
{ "--remove", test_remove, "<optstr> <name> remove name in optstr" },
|
||
|
{ "--dedup", test_dedup, "<optstr> <name> deduplicate name in optstr" },
|
||
|
{ "--split", test_split, "<optstr> split into FS, VFS and userspace" },
|
||
|
--
|
||
|
2.43.0
|
||
|
|