]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
util: typedparam: Introduce 'virTypedParamsValidateTemplate'
authorPeter Krempa <pkrempa@redhat.com>
Wed, 22 Apr 2026 08:11:31 +0000 (10:11 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 14 May 2026 10:13:10 +0000 (12:13 +0200)
While 'virTypedParamsValidate', which uses varargs to pass the template
to validate parameters against, is convenient for single uses we have
multiple occasions where we want to validate the same list of parameters
in muliple places. We use either a macro which expands to the parameter
list in place or a function which encapsulates the validation.

For introspection of input typed parameters we'll need to have the list
of supported typed parameters in each function which uses them as input
and either of the approaches is inconvenient for generating the
introspection parts.

Refactor 'virTypedParamsValidate', to split the actual validation
internals into ''virTypedParamsValidateInternal' and create two
wrappers:
 - 'virTypedParamsValidate' which uses varargs
 - 'virTypedParamsValidateTemplate' which uses an array of structs
    containing the template.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/libvirt_private.syms
src/util/virtypedparam.c
src/util/virtypedparam.h

index 2d7b6222323e580b2a4ee654f89f17e44bf1b0d5..b1dc6788197cc3fd8ee04b1bb7c926b908830682 100644 (file)
@@ -3681,6 +3681,7 @@ virTypedParamsRemoteFree;
 virTypedParamsReplaceString;
 virTypedParamsSerialize;
 virTypedParamsValidate;
+virTypedParamsValidateTemplate;
 
 
 # util/viruri.h
index ec8046b9987d350612d6a90a69e0540e016e9c46..92f25cea3968a008080538e83b0662ee489a7189 100644 (file)
@@ -94,75 +94,55 @@ virTypedParamsSortName(const void *left,
     return strcmp(param_left->field, param_right->field);
 }
 
+static int
+virTypedParamsSortTemplate(const void *left,
+                           const void *right,
+                           void *opaque G_GNUC_UNUSED)
+{
+    const virTypedParamValidationTemplate *param_left = left;
+    const virTypedParamValidationTemplate *param_right = right;
+    return strcmp(param_left->name, param_right->name);
+}
+
 /* Validate that PARAMS contains only recognized parameter names with
  * correct types, and with no duplicates except for parameters
  * specified with VIR_TYPED_PARAM_MULTIPLE flag in type.
  * Pass in as many name/type pairs as appropriate, and pass NULL to end
  * the list of accepted parameters.  Return 0 on success, -1 on failure
  * with error message already issued.  */
-int
-virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...)
+static int
+virTypedParamsValidateInternal(virTypedParameterPtr params,
+                               size_t nparams,
+                               virTypedParamValidationTemplate *templates,
+                               size_t ntemplates)
 {
-    va_list ap;
     size_t i;
     size_t j;
-    const char *name;
     const char *last_name = NULL;
-    size_t nkeys = 0;
-    size_t nkeysalloc = 0;
-    g_autofree virTypedParameterPtr sorted = NULL;
-    g_autofree virTypedParameterPtr keys = NULL;
+    g_autofree virTypedParameterPtr sorted = g_new0(virTypedParameter, nparams);
 
-    if (!nparams) {
-        return 0;
-    }
-
-    va_start(ap, nparams);
-
-    sorted = g_new0(virTypedParameter, nparams);
-
-    /* Here we intentionally don't copy values */
     memcpy(sorted, params, sizeof(*params) * nparams);
     g_qsort_with_data(sorted, nparams,
                       sizeof(*sorted), virTypedParamsSortName, NULL);
 
-    name = va_arg(ap, const char *);
-    while (name) {
-        int type = va_arg(ap, int);
-        VIR_RESIZE_N(keys, nkeysalloc, nkeys, 1);
-
-        if (virStrcpyStatic(keys[nkeys].field, name) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Field name '%1$s' too long"), name);
-            va_end(ap);
-            return -1;
-        }
-
-        keys[nkeys].type = type & ~VIR_TYPED_PARAM_MULTIPLE;
-        /* Value is not used anyway */
-        keys[nkeys].value.i = type & VIR_TYPED_PARAM_MULTIPLE;
-
-        nkeys++;
-        name = va_arg(ap, const char *);
-    }
-
-    va_end(ap);
-
-    g_qsort_with_data(keys, nkeys, sizeof(*keys), virTypedParamsSortName, NULL);
+    g_qsort_with_data(templates, ntemplates,
+                      sizeof(*templates), virTypedParamsSortTemplate, NULL);
 
-    for (i = 0, j = 0; i < nparams && j < nkeys;) {
-        if (STRNEQ(sorted[i].field, keys[j].field)) {
+    for (i = 0, j = 0; i < nparams && j < ntemplates;) {
+        if (STRNEQ(sorted[i].field, templates[j].name)) {
             j++;
         } else {
-            if (STREQ_NULLABLE(last_name, sorted[i].field) &&
-                !(keys[j].value.i & VIR_TYPED_PARAM_MULTIPLE)) {
+            unsigned int expected_type = templates[j].typeflags & ~VIR_TYPED_PARAM_MULTIPLE;
+            bool multiple = templates[j].typeflags & VIR_TYPED_PARAM_MULTIPLE;
+
+            if (STREQ_NULLABLE(last_name, sorted[i].field) && !multiple) {
                 virReportError(VIR_ERR_INVALID_ARG,
                                _("parameter '%1$s' occurs multiple times"),
                                sorted[i].field);
                 return -1;
             }
 
-            if (virTypedParamValidateType(sorted + i, keys[j].type) < 0)
+            if (virTypedParamValidateType(sorted + i, expected_type) < 0)
                 return -1;
 
             last_name = sorted[i].field;
@@ -170,7 +150,7 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...)
         }
     }
 
-    if (j == nkeys && i != nparams) {
+    if (j == ntemplates && i != nparams) {
         virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                        _("parameter '%1$s' not supported"),
                        sorted[i].field);
@@ -181,6 +161,68 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...)
 }
 
 
+/* Validate that PARAMS contains only recognized parameter names with
+ * correct types, and with no duplicates except for parameters
+ * specified with VIR_TYPED_PARAM_MULTIPLE flag in type.
+ * Pass in as many name/type pairs as appropriate, and pass NULL to end
+ * the list of accepted parameters.  Return 0 on success, -1 on failure
+ * with error message already issued.  */
+int
+virTypedParamsValidate(virTypedParameterPtr params,
+                       int nparams,
+                       ...)
+{
+    va_list ap;
+    const char *name;
+    g_autofree virTypedParamValidationTemplate *templates = NULL;
+    size_t ntemplates = 0;
+    size_t ntemplatesalloc = 0;
+
+    if (nparams == 0)
+        return 0;
+
+    va_start(ap, nparams);
+
+    for (name = va_arg(ap, const char *); name; name = va_arg(ap, const char *)) {
+        VIR_RESIZE_N(templates, ntemplatesalloc, ntemplates, 1);
+
+        if (virStrcpy((char *)templates[ntemplates].name, name, VIR_TYPED_PARAM_FIELD_LENGTH) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Field name '%1$s' too long"), name);
+            va_end(ap);
+            return -1;
+        }
+
+        templates[ntemplates].typeflags = va_arg(ap, unsigned int);
+        ntemplates++;
+    }
+
+    va_end(ap);
+
+    return virTypedParamsValidateInternal(params, nparams, templates, ntemplates);
+}
+
+
+int
+virTypedParamsValidateTemplate(virTypedParameterPtr params,
+                               int nparams,
+                               const virTypedParamValidationTemplate *templates)
+{
+    size_t ntemplates = 0;
+    g_autofree virTypedParamValidationTemplate *templ_copy = NULL;
+
+    /* we need to copy the list of templates because
+     * 'virTypedParamsValidateInternal' will need to sort it */
+    while (*templates[ntemplates++].name == '\0')
+        ;
+
+    templ_copy = g_new0(virTypedParamValidationTemplate, ntemplates);
+    memcpy(templ_copy, templates, sizeof(*templates) * ntemplates);
+
+    return virTypedParamsValidateInternal(params, nparams, templ_copy, ntemplates);
+}
+
+
 /* Check if params contains only specified parameter names. Return true if
  * only specified names are present in params, false if params contains any
  * unspecified parameter name. */
index 819166ff1bb93d6656b64a71f2a1b9af68896266..bee3ecc14d4d5aab0971a7a6f795601eac7cc6a3 100644 (file)
@@ -68,6 +68,17 @@ virTypedParamValidateType(virTypedParameterPtr param,
                           unsigned int expected_type)
     G_GNUC_WARN_UNUSED_RESULT;
 
+struct _virTypedParamValidationTemplate {
+    const char name[VIR_TYPED_PARAM_FIELD_LENGTH];  /* parameter name */
+    unsigned int typeflags;
+};
+typedef struct _virTypedParamValidationTemplate virTypedParamValidationTemplate;
+
+int
+virTypedParamsValidateTemplate(virTypedParameterPtr params,
+                               int nparams,
+                               const virTypedParamValidationTemplate *templates)
+    G_GNUC_WARN_UNUSED_RESULT;
 int
 virTypedParamsValidate(virTypedParameterPtr params,
                        int nparams,