From: Karel Zak Date: Wed, 29 Nov 2023 11:19:55 +0000 (+0100) Subject: libmount: add private mnt_optstr_get_missing() X-Git-Tag: v2.40-rc1~136^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=722e4d47a9a21f09a6a719a0f510f29f12497ce5;p=thirdparty%2Futil-linux.git libmount: add private mnt_optstr_get_missing() The function compares two options strings and returns options which are missing. Signed-off-by: Karel Zak --- diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index de44c064ab..59921cf740 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -508,6 +508,7 @@ extern const struct libmnt_optmap *mnt_optmap_get_entry( /* optstr.c */ 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_buffer_append_option(struct ul_buffer *buf, const char *name, size_t namesz, diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c index 55888bde35..7ebc29555b 100644 --- a/libmount/src/optstr.c +++ b/libmount/src/optstr.c @@ -43,13 +43,16 @@ struct libmnt_optloc { * 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) @@ -57,27 +60,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 = ul_optstr_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 @@ -223,7 +229,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; @@ -255,7 +261,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 */ @@ -368,7 +374,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) @@ -411,7 +417,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; @@ -571,6 +577,51 @@ 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 = mnt_buffer_append_option(&buf, name, namesz, val, valsz, 0); + } + if (rc < 0) + break; + rc = 0; + } + + if (!rc && missing) { + if (ul_buffer_is_empty(&buf)) + rc = 1; + else + *missing = ul_buffer_get_data(&buf, NULL, NULL); + } else + ul_buffer_free_data(&buf); + + return rc; +} /** * mnt_optstr_get_flags: @@ -1101,6 +1152,30 @@ static int test_get(struct libmnt_test *ts __attribute__((unused)), return rc; } +static int test_missing(struct libmnt_test *ts __attribute__((unused)), + 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 __attribute__((unused)), int argc, char *argv[]) { @@ -1166,6 +1241,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" }, { "--match", test_match, " compare optstr with pattern" },