[libvirt] [PATCHv2 2/8] Move virStorageBackendRun to vircommand

Ján Tomko jtomko at redhat.com
Wed Mar 19 15:52:27 UTC 2014


The only storage-specific parameter is the pool object, which
is only used for passing to the callback function.
---
 src/libvirt_private.syms              |   2 +
 src/storage/storage_backend.c         | 249 ----------------------------------
 src/storage/storage_backend.h         |  22 ---
 src/storage/storage_backend_disk.c    |  43 +++---
 src/storage/storage_backend_fs.c      |   9 +-
 src/storage/storage_backend_iscsi.c   |  54 ++++----
 src/storage/storage_backend_logical.c |  63 +++++----
 src/util/vircommand.c                 | 245 +++++++++++++++++++++++++++++++++
 src/util/vircommand.h                 |  20 +++
 9 files changed, 360 insertions(+), 347 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3baf766..c7e024d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1113,6 +1113,8 @@ virCommandRawStatus;
 virCommandRequireHandshake;
 virCommandRun;
 virCommandRunAsync;
+virCommandRunNul;
+virCommandRunRegex;
 virCommandSetAppArmorProfile;
 virCommandSetDryRun;
 virCommandSetErrorBuffer;
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index d14e633..b1421ec 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -1632,252 +1632,3 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool,
 
     return stablepath;
 }
-
-
-#ifndef WIN32
-/*
- * Run an external program.
- *
- * Read its output and apply a series of regexes to each line
- * When the entire set of regexes has matched consecutively
- * then run a callback passing in all the matches
- */
-int
-virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
-                              virCommandPtr cmd,
-                              int nregex,
-                              const char **regex,
-                              int *nvars,
-                              virStorageBackendListVolRegexFunc func,
-                              void *data, const char *prefix)
-{
-    int fd = -1, err, ret = -1;
-    FILE *list = NULL;
-    regex_t *reg;
-    regmatch_t *vars = NULL;
-    char line[1024];
-    int maxReg = 0;
-    size_t i, j;
-    int totgroups = 0, ngroup = 0, maxvars = 0;
-    char **groups;
-
-    /* Compile all regular expressions */
-    if (VIR_ALLOC_N(reg, nregex) < 0)
-        return -1;
-
-    for (i = 0; i < nregex; i++) {
-        err = regcomp(&reg[i], regex[i], REG_EXTENDED);
-        if (err != 0) {
-            char error[100];
-            regerror(err, &reg[i], error, sizeof(error));
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Failed to compile regex %s"), error);
-            for (j = 0; j < i; j++)
-                regfree(&reg[j]);
-            VIR_FREE(reg);
-            return -1;
-        }
-
-        totgroups += nvars[i];
-        if (nvars[i] > maxvars)
-            maxvars = nvars[i];
-
-    }
-
-    /* Storage for matched variables */
-    if (VIR_ALLOC_N(groups, totgroups) < 0)
-        goto cleanup;
-    if (VIR_ALLOC_N(vars, maxvars+1) < 0)
-        goto cleanup;
-
-    virCommandSetOutputFD(cmd, &fd);
-    if (virCommandRunAsync(cmd, NULL) < 0) {
-        goto cleanup;
-    }
-
-    if ((list = VIR_FDOPEN(fd, "r")) == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("cannot read fd"));
-        goto cleanup;
-    }
-
-    while (fgets(line, sizeof(line), list) != NULL) {
-        char *p = NULL;
-        /* Strip trailing newline */
-        int len = strlen(line);
-        if (len && line[len-1] == '\n')
-            line[len-1] = '\0';
-
-        /* ignore any command prefix */
-        if (prefix)
-            p = STRSKIP(line, prefix);
-        if (!p)
-            p = line;
-
-        for (i = 0; i <= maxReg && i < nregex; i++) {
-            if (regexec(&reg[i], p, nvars[i]+1, vars, 0) == 0) {
-                maxReg++;
-
-                if (i == 0)
-                    ngroup = 0;
-
-                /* NULL terminate each captured group in the line */
-                for (j = 0; j < nvars[i]; j++) {
-                    /* NB vars[0] is the full pattern, so we offset j by 1 */
-                    p[vars[j+1].rm_eo] = '\0';
-                    if (VIR_STRDUP(groups[ngroup++], p + vars[j+1].rm_so) < 0)
-                        goto cleanup;
-                }
-
-                /* We're matching on the last regex, so callback time */
-                if (i == (nregex-1)) {
-                    if (((*func)(pool, groups, data)) < 0)
-                        goto cleanup;
-
-                    /* Release matches & restart to matching the first regex */
-                    for (j = 0; j < totgroups; j++)
-                        VIR_FREE(groups[j]);
-                    maxReg = 0;
-                    ngroup = 0;
-                }
-            }
-        }
-    }
-
-    ret = virCommandWait(cmd, NULL);
-cleanup:
-    if (groups) {
-        for (j = 0; j < totgroups; j++)
-            VIR_FREE(groups[j]);
-        VIR_FREE(groups);
-    }
-    VIR_FREE(vars);
-
-    for (i = 0; i < nregex; i++)
-        regfree(&reg[i]);
-
-    VIR_FREE(reg);
-
-    VIR_FORCE_FCLOSE(list);
-    VIR_FORCE_CLOSE(fd);
-
-    return ret;
-}
-
-/*
- * Run an external program and read from its standard output
- * a stream of tokens from IN_STREAM, applying FUNC to
- * each successive sequence of N_COLUMNS tokens.
- * If FUNC returns < 0, stop processing input and return -1.
- * Return -1 if N_COLUMNS == 0.
- * Return -1 upon memory allocation error.
- * If the number of input tokens is not a multiple of N_COLUMNS,
- * then the final FUNC call will specify a number smaller than N_COLUMNS.
- * If there are no input tokens (empty input), call FUNC with N_COLUMNS == 0.
- */
-int
-virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
-                            virCommandPtr cmd,
-                            size_t n_columns,
-                            virStorageBackendListVolNulFunc func,
-                            void *data)
-{
-    size_t n_tok = 0;
-    int fd = -1;
-    FILE *fp = NULL;
-    char **v;
-    int ret = -1;
-    size_t i;
-
-    if (n_columns == 0)
-        return -1;
-
-    if (VIR_ALLOC_N(v, n_columns) < 0)
-        return -1;
-    for (i = 0; i < n_columns; i++)
-        v[i] = NULL;
-
-    virCommandSetOutputFD(cmd, &fd);
-    if (virCommandRunAsync(cmd, NULL) < 0) {
-        goto cleanup;
-    }
-
-    if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("cannot open file using fd"));
-        goto cleanup;
-    }
-
-    while (1) {
-        char *buf = NULL;
-        size_t buf_len = 0;
-        /* Be careful: even when it returns -1,
-           this use of getdelim allocates memory.  */
-        ssize_t tok_len = getdelim(&buf, &buf_len, 0, fp);
-        v[n_tok] = buf;
-        if (tok_len < 0) {
-            /* Maybe EOF, maybe an error.
-               If n_tok > 0, then we know it's an error.  */
-            if (n_tok && func(pool, n_tok, v, data) < 0)
-                goto cleanup;
-            break;
-        }
-        ++n_tok;
-        if (n_tok == n_columns) {
-            if (func(pool, n_tok, v, data) < 0)
-                goto cleanup;
-            n_tok = 0;
-            for (i = 0; i < n_columns; i++) {
-                VIR_FREE(v[i]);
-            }
-        }
-    }
-
-    if (feof(fp) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("read error on pipe"));
-        goto cleanup;
-    }
-
-    ret = virCommandWait(cmd, NULL);
- cleanup:
-    for (i = 0; i < n_columns; i++)
-        VIR_FREE(v[i]);
-    VIR_FREE(v);
-
-    VIR_FORCE_FCLOSE(fp);
-    VIR_FORCE_CLOSE(fd);
-
-    return ret;
-}
-
-#else /* WIN32 */
-
-int
-virStorageBackendRunProgRegex(virConnectPtr conn,
-                              virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
-                              const char *const*prog ATTRIBUTE_UNUSED,
-                              int nregex ATTRIBUTE_UNUSED,
-                              const char **regex ATTRIBUTE_UNUSED,
-                              int *nvars ATTRIBUTE_UNUSED,
-                              virStorageBackendListVolRegexFunc func ATTRIBUTE_UNUSED,
-                              void *data ATTRIBUTE_UNUSED)
-{
-    virReportError(VIR_ERR_INTERNAL_ERROR,
-                   _("%s not implemented on Win32"), __FUNCTION__);
-    return -1;
-}
-
-int
-virStorageBackendRunProgNul(virConnectPtr conn,
-                            virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
-                            const char **prog ATTRIBUTE_UNUSED,
-                            size_t n_columns ATTRIBUTE_UNUSED,
-                            virStorageBackendListVolNulFunc func ATTRIBUTE_UNUSED,
-                            void *data ATTRIBUTE_UNUSED)
-{
-    virReportError(VIR_ERR_INTERNAL_ERROR,
-                   _("%s not implemented on Win32"), __FUNCTION__);
-    return -1;
-}
-#endif /* WIN32 */
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index 5314411..aaa17a0 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -159,28 +159,6 @@ char *virStorageBackendStablePath(virStoragePoolObjPtr pool,
                                   const char *devpath,
                                   bool loop);
 
-typedef int (*virStorageBackendListVolRegexFunc)(virStoragePoolObjPtr pool,
-                                                 char **const groups,
-                                                 void *data);
-typedef int (*virStorageBackendListVolNulFunc)(virStoragePoolObjPtr pool,
-                                               size_t n_tokens,
-                                               char **const groups,
-                                               void *data);
-
-int virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
-                                  virCommandPtr cmd,
-                                  int nregex,
-                                  const char **regex,
-                                  int *nvars,
-                                  virStorageBackendListVolRegexFunc func,
-                                  void *data, const char *cmd_to_ignore);
-
-int virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
-                                virCommandPtr cmd,
-                                size_t n_columns,
-                                virStorageBackendListVolNulFunc func,
-                                void *data);
-
 virCommandPtr
 virStorageBackendCreateQemuImgCmd(virConnectPtr conn,
                                   virStoragePoolObjPtr pool,
diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c
index 05799a3..81201fd 100644
--- a/src/storage/storage_backend_disk.c
+++ b/src/storage/storage_backend_disk.c
@@ -188,12 +188,18 @@ virStorageBackendDiskMakeFreeExtent(virStoragePoolObjPtr pool,
 }
 
 
+struct virStorageBackendDiskPoolVolData {
+    virStoragePoolObjPtr pool;
+    virStorageVolDefPtr vol;
+};
+
 static int
-virStorageBackendDiskMakeVol(virStoragePoolObjPtr pool,
-                             size_t ntok ATTRIBUTE_UNUSED,
+virStorageBackendDiskMakeVol(size_t ntok ATTRIBUTE_UNUSED,
                              char **const groups,
-                             void *data)
+                             void *opaque)
 {
+    struct virStorageBackendDiskPoolVolData *data = opaque;
+    virStoragePoolObjPtr pool = data->pool;
     /*
      * Ignore normal+metadata, and logical+metadata partitions
      * since they're basically internal book-keeping regions
@@ -209,7 +215,7 @@ virStorageBackendDiskMakeVol(virStoragePoolObjPtr pool,
     /* Remaining data / metadata parts get turn into volumes... */
     if (STREQ(groups[2], "metadata") ||
         STREQ(groups[2], "data")) {
-        virStorageVolDefPtr vol = data;
+        virStorageVolDefPtr vol = data->vol;
 
         if (vol) {
             /* We're searching for a specific vol only */
@@ -234,7 +240,6 @@ virStorageBackendDiskMakeVol(virStoragePoolObjPtr pool,
     }
 }
 
-
 /* To get a list of partitions we run an external helper
  * tool which then uses parted APIs. This is because
  * parted's API is not compatible with libvirt's license
@@ -259,25 +264,28 @@ virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
     virCommandPtr cmd = virCommandNewArgList(PARTHELPER,
                                              pool->def->source.devices[0].path,
                                              NULL);
+    struct virStorageBackendDiskPoolVolData cbdata = {
+        .pool = pool,
+        .vol = vol,
+    };
     int ret;
 
     pool->def->allocation = pool->def->capacity = pool->def->available = 0;
 
-    ret = virStorageBackendRunProgNul(pool,
-                                      cmd,
-                                      6,
-                                      virStorageBackendDiskMakeVol,
-                                      vol);
+    ret = virCommandRunNul(cmd,
+                           6,
+                           virStorageBackendDiskMakeVol,
+                           &cbdata);
     virCommandFree(cmd);
     return ret;
 }
 
 static int
-virStorageBackendDiskMakePoolGeometry(virStoragePoolObjPtr pool,
-                                      size_t ntok ATTRIBUTE_UNUSED,
+virStorageBackendDiskMakePoolGeometry(size_t ntok ATTRIBUTE_UNUSED,
                                       char **const groups,
-                                      void *data ATTRIBUTE_UNUSED)
+                                      void *data)
 {
+    virStoragePoolObjPtr pool = data;
     virStoragePoolSourceDevicePtr device = &(pool->def->source.devices[0]);
     if (virStrToLong_i(groups[0], NULL, 0, &device->geometry.cylinders) < 0 ||
         virStrToLong_i(groups[1], NULL, 0, &device->geometry.heads) < 0 ||
@@ -299,11 +307,10 @@ virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
                                              NULL);
     int ret;
 
-    ret = virStorageBackendRunProgNul(pool,
-                                      cmd,
-                                      3,
-                                      virStorageBackendDiskMakePoolGeometry,
-                                      NULL);
+    ret = virCommandRunNul(cmd,
+                           3,
+                           virStorageBackendDiskMakePoolGeometry,
+                           pool);
     virCommandFree(cmd);
     return ret;
 }
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index edb7cd0..b6fed01 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -202,8 +202,7 @@ struct _virNetfsDiscoverState {
 typedef struct _virNetfsDiscoverState virNetfsDiscoverState;
 
 static int
-virStorageBackendFileSystemNetFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
-                                                  char **const groups,
+virStorageBackendFileSystemNetFindPoolSourcesFunc(char **const groups,
                                                   void *data)
 {
     virNetfsDiscoverState *state = data;
@@ -301,9 +300,9 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
                                source->hosts[0].name,
                                NULL);
 
-    if (virStorageBackendRunProgRegex(NULL, cmd, 1, regexes, vars,
-                            virStorageBackendFileSystemNetFindPoolSourcesFunc,
-                            &state, NULL) < 0)
+    if (virCommandRunRegex(cmd, 1, regexes, vars,
+                           virStorageBackendFileSystemNetFindPoolSourcesFunc,
+                           &state, NULL) < 0)
         goto cleanup;
 
     retval = virStoragePoolSourceListFormat(&state.list);
diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index 0feeb5f..20fc0e6 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -79,16 +79,19 @@ virStorageBackendISCSIPortal(virStoragePoolSourcePtr source)
     return portal;
 }
 
+struct virStorageBackendISCSISessionData {
+    char *session;
+    const char *devpath;
+};
 
 static int
-virStorageBackendISCSIExtractSession(virStoragePoolObjPtr pool,
-                                     char **const groups,
-                                     void *data)
+virStorageBackendISCSIExtractSession(char **const groups,
+                                     void *opaque)
 {
-    char **session = data;
+    struct virStorageBackendISCSISessionData *data = opaque;
 
-    if (STREQ(groups[1], pool->def->source.devices[0].path))
-        return VIR_STRDUP(*session, groups[0]);
+    if (STREQ(groups[1], data->devpath))
+        return VIR_STRDUP(data->session, groups[0]);
     return 0;
 }
 
@@ -109,21 +112,22 @@ virStorageBackendISCSISession(virStoragePoolObjPtr pool,
     int vars[] = {
         2,
     };
-    char *session = NULL;
+    struct virStorageBackendISCSISessionData cbdata = {
+        .session = NULL,
+        .devpath = pool->def->source.devices[0].path
+    };
 
     virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL);
 
-    if (virStorageBackendRunProgRegex(pool,
-                                      cmd,
-                                      1,
-                                      regexes,
-                                      vars,
-                                      virStorageBackendISCSIExtractSession,
-                                      &session, NULL) < 0)
+    if (virCommandRunRegex(cmd,
+                           1,
+                           regexes,
+                           vars,
+                           virStorageBackendISCSIExtractSession,
+                           &cbdata, NULL) < 0)
         goto cleanup;
 
-    if (session == NULL &&
-        !probe) {
+    if (cbdata.session == NULL && !probe) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot find session"));
         goto cleanup;
@@ -131,7 +135,7 @@ virStorageBackendISCSISession(virStoragePoolObjPtr pool,
 
 cleanup:
     virCommandFree(cmd);
-    return session;
+    return cbdata.session;
 }
 
 
@@ -439,8 +443,7 @@ struct virStorageBackendISCSITargetList {
 };
 
 static int
-virStorageBackendISCSIGetTargets(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
-                                 char **const groups,
+virStorageBackendISCSIGetTargets(char **const groups,
                                  void *data)
 {
     struct virStorageBackendISCSITargetList *list = data;
@@ -503,13 +506,12 @@ virStorageBackendISCSIScanTargets(const char *portal,
 
     memset(&list, 0, sizeof(list));
 
-    if (virStorageBackendRunProgRegex(NULL, /* No pool for callback */
-                                      cmd,
-                                      1,
-                                      regexes,
-                                      vars,
-                                      virStorageBackendISCSIGetTargets,
-                                      &list, NULL) < 0)
+    if (virCommandRunRegex(cmd,
+                           1,
+                           regexes,
+                           vars,
+                           virStorageBackendISCSIGetTargets,
+                           &list, NULL) < 0)
         goto cleanup;
 
     for (i = 0; i < list.ntargets; i++) {
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index 667fb06..907b9b0 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -66,11 +66,17 @@ virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool,
 
 #define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped"
 
+struct virStorageBackendLogicalPoolVolData {
+    virStoragePoolObjPtr pool;
+    virStorageVolDefPtr vol;
+};
+
 static int
-virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
-                                char **const groups,
-                                void *data)
+virStorageBackendLogicalMakeVol(char **const groups,
+                                void *opaque)
 {
+    struct virStorageBackendLogicalPoolVolData *data = opaque;
+    virStoragePoolObjPtr pool = data->pool;
     virStorageVolDefPtr vol = NULL;
     bool is_new_vol = false;
     unsigned long long offset, size, length;
@@ -96,8 +102,8 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
         return 0;
 
     /* See if we're only looking for a specific volume */
-    if (data != NULL) {
-        vol = data;
+    if (data->vol != NULL) {
+        vol = data->vol;
         if (STRNEQ(vol->name, groups[0]))
             return 0;
     }
@@ -299,6 +305,10 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
     };
     int ret = -1;
     virCommandPtr cmd;
+    struct virStorageBackendLogicalPoolVolData cbdata = {
+        .pool = pool,
+        .vol = vol,
+    };
 
     cmd = virCommandNewArgList(LVS,
                                "--separator", "#",
@@ -310,13 +320,13 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
                                "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size,size,lv_attr",
                                pool->def->source.name,
                                NULL);
-    if (virStorageBackendRunProgRegex(pool,
-                                      cmd,
-                                      1,
-                                      regexes,
-                                      vars,
-                                      virStorageBackendLogicalMakeVol,
-                                      vol, "lvs") < 0)
+    if (virCommandRunRegex(cmd,
+                           1,
+                           regexes,
+                           vars,
+                           virStorageBackendLogicalMakeVol,
+                           &cbdata,
+                           "lvs") < 0)
         goto cleanup;
 
     ret = 0;
@@ -326,10 +336,10 @@ cleanup:
 }
 
 static int
-virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
-                                        char **const groups,
-                                        void *data ATTRIBUTE_UNUSED)
+virStorageBackendLogicalRefreshPoolFunc(char **const groups,
+                                        void *data)
 {
+    virStoragePoolObjPtr pool = data;
     if (virStrToLong_ull(groups[0], NULL, 10, &pool->def->capacity) < 0)
         return -1;
     if (virStrToLong_ull(groups[1], NULL, 10, &pool->def->available) < 0)
@@ -341,8 +351,7 @@ virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUS
 
 
 static int
-virStorageBackendLogicalFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
-                                            char **const groups,
+virStorageBackendLogicalFindPoolSourcesFunc(char **const groups,
                                             void *data)
 {
     virStoragePoolSourceListPtr sourceList = data;
@@ -432,9 +441,9 @@ virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
                                "--noheadings",
                                "-o", "pv_name,vg_name",
                                NULL);
-    if (virStorageBackendRunProgRegex(NULL, cmd, 1, regexes, vars,
-                                      virStorageBackendLogicalFindPoolSourcesFunc,
-                                      &sourceList, "pvs") < 0) {
+    if (virCommandRunRegex(cmd, 1, regexes, vars,
+                           virStorageBackendLogicalFindPoolSourcesFunc,
+                           &sourceList, "pvs") < 0) {
         virCommandFree(cmd);
         return NULL;
     }
@@ -593,13 +602,13 @@ virStorageBackendLogicalRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                NULL);
 
     /* Now get basic volgrp metadata */
-    if (virStorageBackendRunProgRegex(pool,
-                                      cmd,
-                                      1,
-                                      regexes,
-                                      vars,
-                                      virStorageBackendLogicalRefreshPoolFunc,
-                                      NULL, "vgs") < 0)
+    if (virCommandRunRegex(cmd,
+                           1,
+                           regexes,
+                           vars,
+                           virStorageBackendLogicalRefreshPoolFunc,
+                           pool,
+                           "vgs") < 0)
         goto cleanup;
 
     ret = 0;
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 79bb20c..3f98eb8 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -22,6 +22,7 @@
 #include <config.h>
 
 #include <poll.h>
+#include <regex.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -2760,3 +2761,247 @@ virCommandSetDryRun(virBufferPtr buf,
     dryRunCallback = cb;
     dryRunOpaque = opaque;
 }
+
+#ifndef WIN32
+/*
+ * Run an external program.
+ *
+ * Read its output and apply a series of regexes to each line
+ * When the entire set of regexes has matched consecutively
+ * then run a callback passing in all the matches
+ */
+int
+virCommandRunRegex(virCommandPtr cmd,
+                   int nregex,
+                   const char **regex,
+                   int *nvars,
+                   virCommandRunRegexFunc func,
+                   void *data,
+                   const char *prefix)
+{
+    int fd = -1, err, ret = -1;
+    FILE *list = NULL;
+    regex_t *reg;
+    regmatch_t *vars = NULL;
+    char line[1024];
+    int maxReg = 0;
+    size_t i, j;
+    int totgroups = 0, ngroup = 0, maxvars = 0;
+    char **groups;
+
+    /* Compile all regular expressions */
+    if (VIR_ALLOC_N(reg, nregex) < 0)
+        return -1;
+
+    for (i = 0; i < nregex; i++) {
+        err = regcomp(&reg[i], regex[i], REG_EXTENDED);
+        if (err != 0) {
+            char error[100];
+            regerror(err, &reg[i], error, sizeof(error));
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Failed to compile regex %s"), error);
+            for (j = 0; j < i; j++)
+                regfree(&reg[j]);
+            VIR_FREE(reg);
+            return -1;
+        }
+
+        totgroups += nvars[i];
+        if (nvars[i] > maxvars)
+            maxvars = nvars[i];
+
+    }
+
+    /* Storage for matched variables */
+    if (VIR_ALLOC_N(groups, totgroups) < 0)
+        goto cleanup;
+    if (VIR_ALLOC_N(vars, maxvars+1) < 0)
+        goto cleanup;
+
+    virCommandSetOutputFD(cmd, &fd);
+    if (virCommandRunAsync(cmd, NULL) < 0) {
+        goto cleanup;
+    }
+
+    if ((list = VIR_FDOPEN(fd, "r")) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("cannot read fd"));
+        goto cleanup;
+    }
+
+    while (fgets(line, sizeof(line), list) != NULL) {
+        char *p = NULL;
+        /* Strip trailing newline */
+        int len = strlen(line);
+        if (len && line[len-1] == '\n')
+            line[len-1] = '\0';
+
+        /* ignore any command prefix */
+        if (prefix)
+            p = STRSKIP(line, prefix);
+        if (!p)
+            p = line;
+
+        for (i = 0; i <= maxReg && i < nregex; i++) {
+            if (regexec(&reg[i], p, nvars[i]+1, vars, 0) == 0) {
+                maxReg++;
+
+                if (i == 0)
+                    ngroup = 0;
+
+                /* NULL terminate each captured group in the line */
+                for (j = 0; j < nvars[i]; j++) {
+                    /* NB vars[0] is the full pattern, so we offset j by 1 */
+                    p[vars[j+1].rm_eo] = '\0';
+                    if (VIR_STRDUP(groups[ngroup++], p + vars[j+1].rm_so) < 0)
+                        goto cleanup;
+                }
+
+                /* We're matching on the last regex, so callback time */
+                if (i == (nregex-1)) {
+                    if (((*func)(groups, data)) < 0)
+                        goto cleanup;
+
+                    /* Release matches & restart to matching the first regex */
+                    for (j = 0; j < totgroups; j++)
+                        VIR_FREE(groups[j]);
+                    maxReg = 0;
+                    ngroup = 0;
+                }
+            }
+        }
+    }
+
+    ret = virCommandWait(cmd, NULL);
+cleanup:
+    if (groups) {
+        for (j = 0; j < totgroups; j++)
+            VIR_FREE(groups[j]);
+        VIR_FREE(groups);
+    }
+    VIR_FREE(vars);
+
+    for (i = 0; i < nregex; i++)
+        regfree(&reg[i]);
+
+    VIR_FREE(reg);
+
+    VIR_FORCE_FCLOSE(list);
+    VIR_FORCE_CLOSE(fd);
+
+    return ret;
+}
+
+/*
+ * Run an external program and read from its standard output
+ * a stream of tokens from IN_STREAM, applying FUNC to
+ * each successive sequence of N_COLUMNS tokens.
+ * If FUNC returns < 0, stop processing input and return -1.
+ * Return -1 if N_COLUMNS == 0.
+ * Return -1 upon memory allocation error.
+ * If the number of input tokens is not a multiple of N_COLUMNS,
+ * then the final FUNC call will specify a number smaller than N_COLUMNS.
+ * If there are no input tokens (empty input), call FUNC with N_COLUMNS == 0.
+ */
+int
+virCommandRunNul(virCommandPtr cmd,
+                 size_t n_columns,
+                 virCommandRunNulFunc func,
+                 void *data)
+{
+    size_t n_tok = 0;
+    int fd = -1;
+    FILE *fp = NULL;
+    char **v;
+    int ret = -1;
+    size_t i;
+
+    if (n_columns == 0)
+        return -1;
+
+    if (VIR_ALLOC_N(v, n_columns) < 0)
+        return -1;
+    for (i = 0; i < n_columns; i++)
+        v[i] = NULL;
+
+    virCommandSetOutputFD(cmd, &fd);
+    if (virCommandRunAsync(cmd, NULL) < 0) {
+        goto cleanup;
+    }
+
+    if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("cannot open file using fd"));
+        goto cleanup;
+    }
+
+    while (1) {
+        char *buf = NULL;
+        size_t buf_len = 0;
+        /* Be careful: even when it returns -1,
+           this use of getdelim allocates memory.  */
+        ssize_t tok_len = getdelim(&buf, &buf_len, 0, fp);
+        v[n_tok] = buf;
+        if (tok_len < 0) {
+            /* Maybe EOF, maybe an error.
+               If n_tok > 0, then we know it's an error.  */
+            if (n_tok && func(n_tok, v, data) < 0)
+                goto cleanup;
+            break;
+        }
+        ++n_tok;
+        if (n_tok == n_columns) {
+            if (func(n_tok, v, data) < 0)
+                goto cleanup;
+            n_tok = 0;
+            for (i = 0; i < n_columns; i++) {
+                VIR_FREE(v[i]);
+            }
+        }
+    }
+
+    if (feof(fp) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("read error on pipe"));
+        goto cleanup;
+    }
+
+    ret = virCommandWait(cmd, NULL);
+ cleanup:
+    for (i = 0; i < n_columns; i++)
+        VIR_FREE(v[i]);
+    VIR_FREE(v);
+
+    VIR_FORCE_FCLOSE(fp);
+    VIR_FORCE_CLOSE(fd);
+
+    return ret;
+}
+
+#else /* WIN32 */
+
+int
+virCommandRunRegex(virCommandPtr cmd ATTRIBUTE_UNUSED,
+                   int nregex ATTRIBUTE_UNUSED,
+                   const char **regex ATTRIBUTE_UNUSED,
+                   int *nvars ATTRIBUTE_UNUSED,
+                   virCommandRunRegexFunc func ATTRIBUTE_UNUSED,
+                   void *data ATTRIBUTE_UNUSED,
+                   const char *prefix ATTRIBUTE_UNUSED)
+{
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("%s not implemented on Win32"), __FUNCTION__);
+    return -1;
+}
+
+int
+virCommandRunNul(virCommandPtr cmd ATTRIBUTE_UNUSED,
+                 size_t n_columns ATTRIBUTE_UNUSED,
+                 virCommandRunNulFunc func ATTRIBUTE_UNUSED,
+                 void *data ATTRIBUTE_UNUSED)
+{
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("%s not implemented on Win32"), __FUNCTION__);
+    return -1;
+}
+#endif /* WIN32 */
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index 929375b..8cdb31c 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -187,4 +187,24 @@ void virCommandFree(virCommandPtr cmd);
 
 void virCommandDoAsyncIO(virCommandPtr cmd);
 
+typedef int (*virCommandRunRegexFunc)(char **const groups,
+                                      void *data);
+typedef int (*virCommandRunNulFunc)(size_t n_tokens,
+                                    char **const groups,
+                                    void *data);
+
+int virCommandRunRegex(virCommandPtr cmd,
+                       int nregex,
+                       const char **regex,
+                       int *nvars,
+                       virCommandRunRegexFunc func,
+                       void *data,
+                       const char *cmd_to_ignore);
+
+int virCommandRunNul(virCommandPtr cmd,
+                     size_t n_columns,
+                     virCommandRunNulFunc func,
+                     void *data);
+
+
 #endif /* __VIR_COMMAND_H__ */
-- 
1.8.3.2




More information about the libvir-list mailing list