From c7abf1c87c44c54c16758e079dc3528a13d8e177 Mon Sep 17 00:00:00 2001 From: Karel Zak 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 --- 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," [] prepend value to optstr" }, { "--set", test_set, " [] (un)set value" }, { "--get", test_get, " search name in optstr" }, + { "--missing",test_missing," what from wanted is missing" }, { "--remove", test_remove, " remove name in optstr" }, { "--dedup", test_dedup, " deduplicate name in optstr" }, { "--split", test_split, " split into FS, VFS and userspace" }, -- 2.43.0