mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 19:41:16 +00:00
Move virStorageBackendRun to vircommand
The only storage-specific parameter is the pool object, which is only used for passing to the callback function.
This commit is contained in:
parent
845255a430
commit
f2cc42868e
@ -1113,6 +1113,8 @@ virCommandRawStatus;
|
||||
virCommandRequireHandshake;
|
||||
virCommandRun;
|
||||
virCommandRunAsync;
|
||||
virCommandRunNul;
|
||||
virCommandRunRegex;
|
||||
virCommandSetAppArmorProfile;
|
||||
virCommandSetDryRun;
|
||||
virCommandSetErrorBuffer;
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user