]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: add private mnt_optstr_get_missing()
authorKarel Zak <kzak@redhat.com>
Wed, 29 Nov 2023 11:19:55 +0000 (12:19 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 29 Nov 2023 11:19:55 +0000 (12:19 +0100)
The function compares two options strings and returns options which
are missing.

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/mountP.h
libmount/src/optstr.c

index de44c064ab0d8d167c59ee4a7908defe9c724a7f..59921cf7405f4009668eb085fcb6a5fe216473fa 100644 (file)
@@ -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,
index 55888bde35bb2cbc38d8056ec126efc6f4b7cabf..7ebc29555b6e864f9a45d3a08a5c686f3e32ef4f 100644 (file)
@@ -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,"<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" },
                { "--match",  test_match,  "<optstr> <pattern>         compare optstr with pattern" },