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(®[i], regex[i], REG_EXTENDED);
- if (err != 0) {
- char error[100];
- regerror(err, ®[i], error, sizeof(error));
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Failed to compile regex %s"), error);
- for (j = 0; j < i; j++)
- regfree(®[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(®[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(®[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(®[i], regex[i], REG_EXTENDED);
+ if (err != 0) {
+ char error[100];
+ regerror(err, ®[i], error, sizeof(error));
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to compile regex %s"), error);
+ for (j = 0; j < i; j++)
+ regfree(®[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(®[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(®[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