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;
|
virCommandRequireHandshake;
|
||||||
virCommandRun;
|
virCommandRun;
|
||||||
virCommandRunAsync;
|
virCommandRunAsync;
|
||||||
|
virCommandRunNul;
|
||||||
|
virCommandRunRegex;
|
||||||
virCommandSetAppArmorProfile;
|
virCommandSetAppArmorProfile;
|
||||||
virCommandSetDryRun;
|
virCommandSetDryRun;
|
||||||
virCommandSetErrorBuffer;
|
virCommandSetErrorBuffer;
|
||||||
|
@ -1632,252 +1632,3 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool,
|
|||||||
|
|
||||||
return stablepath;
|
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,
|
const char *devpath,
|
||||||
bool loop);
|
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
|
virCommandPtr
|
||||||
virStorageBackendCreateQemuImgCmd(virConnectPtr conn,
|
virStorageBackendCreateQemuImgCmd(virConnectPtr conn,
|
||||||
virStoragePoolObjPtr pool,
|
virStoragePoolObjPtr pool,
|
||||||
|
@ -188,12 +188,18 @@ virStorageBackendDiskMakeFreeExtent(virStoragePoolObjPtr pool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct virStorageBackendDiskPoolVolData {
|
||||||
|
virStoragePoolObjPtr pool;
|
||||||
|
virStorageVolDefPtr vol;
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendDiskMakeVol(virStoragePoolObjPtr pool,
|
virStorageBackendDiskMakeVol(size_t ntok ATTRIBUTE_UNUSED,
|
||||||
size_t ntok ATTRIBUTE_UNUSED,
|
|
||||||
char **const groups,
|
char **const groups,
|
||||||
void *data)
|
void *opaque)
|
||||||
{
|
{
|
||||||
|
struct virStorageBackendDiskPoolVolData *data = opaque;
|
||||||
|
virStoragePoolObjPtr pool = data->pool;
|
||||||
/*
|
/*
|
||||||
* Ignore normal+metadata, and logical+metadata partitions
|
* Ignore normal+metadata, and logical+metadata partitions
|
||||||
* since they're basically internal book-keeping regions
|
* since they're basically internal book-keeping regions
|
||||||
@ -209,7 +215,7 @@ virStorageBackendDiskMakeVol(virStoragePoolObjPtr pool,
|
|||||||
/* Remaining data / metadata parts get turn into volumes... */
|
/* Remaining data / metadata parts get turn into volumes... */
|
||||||
if (STREQ(groups[2], "metadata") ||
|
if (STREQ(groups[2], "metadata") ||
|
||||||
STREQ(groups[2], "data")) {
|
STREQ(groups[2], "data")) {
|
||||||
virStorageVolDefPtr vol = data;
|
virStorageVolDefPtr vol = data->vol;
|
||||||
|
|
||||||
if (vol) {
|
if (vol) {
|
||||||
/* We're searching for a specific vol only */
|
/* 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
|
/* To get a list of partitions we run an external helper
|
||||||
* tool which then uses parted APIs. This is because
|
* tool which then uses parted APIs. This is because
|
||||||
* parted's API is not compatible with libvirt's license
|
* parted's API is not compatible with libvirt's license
|
||||||
@ -259,25 +264,28 @@ virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
|
|||||||
virCommandPtr cmd = virCommandNewArgList(PARTHELPER,
|
virCommandPtr cmd = virCommandNewArgList(PARTHELPER,
|
||||||
pool->def->source.devices[0].path,
|
pool->def->source.devices[0].path,
|
||||||
NULL);
|
NULL);
|
||||||
|
struct virStorageBackendDiskPoolVolData cbdata = {
|
||||||
|
.pool = pool,
|
||||||
|
.vol = vol,
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pool->def->allocation = pool->def->capacity = pool->def->available = 0;
|
pool->def->allocation = pool->def->capacity = pool->def->available = 0;
|
||||||
|
|
||||||
ret = virStorageBackendRunProgNul(pool,
|
ret = virCommandRunNul(cmd,
|
||||||
cmd,
|
6,
|
||||||
6,
|
virStorageBackendDiskMakeVol,
|
||||||
virStorageBackendDiskMakeVol,
|
&cbdata);
|
||||||
vol);
|
|
||||||
virCommandFree(cmd);
|
virCommandFree(cmd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendDiskMakePoolGeometry(virStoragePoolObjPtr pool,
|
virStorageBackendDiskMakePoolGeometry(size_t ntok ATTRIBUTE_UNUSED,
|
||||||
size_t ntok ATTRIBUTE_UNUSED,
|
|
||||||
char **const groups,
|
char **const groups,
|
||||||
void *data ATTRIBUTE_UNUSED)
|
void *data)
|
||||||
{
|
{
|
||||||
|
virStoragePoolObjPtr pool = data;
|
||||||
virStoragePoolSourceDevicePtr device = &(pool->def->source.devices[0]);
|
virStoragePoolSourceDevicePtr device = &(pool->def->source.devices[0]);
|
||||||
if (virStrToLong_i(groups[0], NULL, 0, &device->geometry.cylinders) < 0 ||
|
if (virStrToLong_i(groups[0], NULL, 0, &device->geometry.cylinders) < 0 ||
|
||||||
virStrToLong_i(groups[1], NULL, 0, &device->geometry.heads) < 0 ||
|
virStrToLong_i(groups[1], NULL, 0, &device->geometry.heads) < 0 ||
|
||||||
@ -299,11 +307,10 @@ virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
|
|||||||
NULL);
|
NULL);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = virStorageBackendRunProgNul(pool,
|
ret = virCommandRunNul(cmd,
|
||||||
cmd,
|
3,
|
||||||
3,
|
virStorageBackendDiskMakePoolGeometry,
|
||||||
virStorageBackendDiskMakePoolGeometry,
|
pool);
|
||||||
NULL);
|
|
||||||
virCommandFree(cmd);
|
virCommandFree(cmd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -202,8 +202,7 @@ struct _virNetfsDiscoverState {
|
|||||||
typedef struct _virNetfsDiscoverState virNetfsDiscoverState;
|
typedef struct _virNetfsDiscoverState virNetfsDiscoverState;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendFileSystemNetFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
virStorageBackendFileSystemNetFindPoolSourcesFunc(char **const groups,
|
||||||
char **const groups,
|
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
virNetfsDiscoverState *state = data;
|
virNetfsDiscoverState *state = data;
|
||||||
@ -301,9 +300,9 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
|
|||||||
source->hosts[0].name,
|
source->hosts[0].name,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (virStorageBackendRunProgRegex(NULL, cmd, 1, regexes, vars,
|
if (virCommandRunRegex(cmd, 1, regexes, vars,
|
||||||
virStorageBackendFileSystemNetFindPoolSourcesFunc,
|
virStorageBackendFileSystemNetFindPoolSourcesFunc,
|
||||||
&state, NULL) < 0)
|
&state, NULL) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
retval = virStoragePoolSourceListFormat(&state.list);
|
retval = virStoragePoolSourceListFormat(&state.list);
|
||||||
|
@ -79,16 +79,19 @@ virStorageBackendISCSIPortal(virStoragePoolSourcePtr source)
|
|||||||
return portal;
|
return portal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct virStorageBackendISCSISessionData {
|
||||||
|
char *session;
|
||||||
|
const char *devpath;
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendISCSIExtractSession(virStoragePoolObjPtr pool,
|
virStorageBackendISCSIExtractSession(char **const groups,
|
||||||
char **const groups,
|
void *opaque)
|
||||||
void *data)
|
|
||||||
{
|
{
|
||||||
char **session = data;
|
struct virStorageBackendISCSISessionData *data = opaque;
|
||||||
|
|
||||||
if (STREQ(groups[1], pool->def->source.devices[0].path))
|
if (STREQ(groups[1], data->devpath))
|
||||||
return VIR_STRDUP(*session, groups[0]);
|
return VIR_STRDUP(data->session, groups[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,21 +112,22 @@ virStorageBackendISCSISession(virStoragePoolObjPtr pool,
|
|||||||
int vars[] = {
|
int vars[] = {
|
||||||
2,
|
2,
|
||||||
};
|
};
|
||||||
char *session = NULL;
|
struct virStorageBackendISCSISessionData cbdata = {
|
||||||
|
.session = NULL,
|
||||||
|
.devpath = pool->def->source.devices[0].path
|
||||||
|
};
|
||||||
|
|
||||||
virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL);
|
virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL);
|
||||||
|
|
||||||
if (virStorageBackendRunProgRegex(pool,
|
if (virCommandRunRegex(cmd,
|
||||||
cmd,
|
1,
|
||||||
1,
|
regexes,
|
||||||
regexes,
|
vars,
|
||||||
vars,
|
virStorageBackendISCSIExtractSession,
|
||||||
virStorageBackendISCSIExtractSession,
|
&cbdata, NULL) < 0)
|
||||||
&session, NULL) < 0)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (session == NULL &&
|
if (cbdata.session == NULL && !probe) {
|
||||||
!probe) {
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
"%s", _("cannot find session"));
|
"%s", _("cannot find session"));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -131,7 +135,7 @@ virStorageBackendISCSISession(virStoragePoolObjPtr pool,
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virCommandFree(cmd);
|
virCommandFree(cmd);
|
||||||
return session;
|
return cbdata.session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -439,8 +443,7 @@ struct virStorageBackendISCSITargetList {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendISCSIGetTargets(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
virStorageBackendISCSIGetTargets(char **const groups,
|
||||||
char **const groups,
|
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct virStorageBackendISCSITargetList *list = data;
|
struct virStorageBackendISCSITargetList *list = data;
|
||||||
@ -503,13 +506,12 @@ virStorageBackendISCSIScanTargets(const char *portal,
|
|||||||
|
|
||||||
memset(&list, 0, sizeof(list));
|
memset(&list, 0, sizeof(list));
|
||||||
|
|
||||||
if (virStorageBackendRunProgRegex(NULL, /* No pool for callback */
|
if (virCommandRunRegex(cmd,
|
||||||
cmd,
|
1,
|
||||||
1,
|
regexes,
|
||||||
regexes,
|
vars,
|
||||||
vars,
|
virStorageBackendISCSIGetTargets,
|
||||||
virStorageBackendISCSIGetTargets,
|
&list, NULL) < 0)
|
||||||
&list, NULL) < 0)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
for (i = 0; i < list.ntargets; i++) {
|
for (i = 0; i < list.ntargets; i++) {
|
||||||
|
@ -66,11 +66,17 @@ virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool,
|
|||||||
|
|
||||||
#define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped"
|
#define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped"
|
||||||
|
|
||||||
|
struct virStorageBackendLogicalPoolVolData {
|
||||||
|
virStoragePoolObjPtr pool;
|
||||||
|
virStorageVolDefPtr vol;
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
|
virStorageBackendLogicalMakeVol(char **const groups,
|
||||||
char **const groups,
|
void *opaque)
|
||||||
void *data)
|
|
||||||
{
|
{
|
||||||
|
struct virStorageBackendLogicalPoolVolData *data = opaque;
|
||||||
|
virStoragePoolObjPtr pool = data->pool;
|
||||||
virStorageVolDefPtr vol = NULL;
|
virStorageVolDefPtr vol = NULL;
|
||||||
bool is_new_vol = false;
|
bool is_new_vol = false;
|
||||||
unsigned long long offset, size, length;
|
unsigned long long offset, size, length;
|
||||||
@ -96,8 +102,8 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* See if we're only looking for a specific volume */
|
/* See if we're only looking for a specific volume */
|
||||||
if (data != NULL) {
|
if (data->vol != NULL) {
|
||||||
vol = data;
|
vol = data->vol;
|
||||||
if (STRNEQ(vol->name, groups[0]))
|
if (STRNEQ(vol->name, groups[0]))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -299,6 +305,10 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
|
|||||||
};
|
};
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
virCommandPtr cmd;
|
virCommandPtr cmd;
|
||||||
|
struct virStorageBackendLogicalPoolVolData cbdata = {
|
||||||
|
.pool = pool,
|
||||||
|
.vol = vol,
|
||||||
|
};
|
||||||
|
|
||||||
cmd = virCommandNewArgList(LVS,
|
cmd = virCommandNewArgList(LVS,
|
||||||
"--separator", "#",
|
"--separator", "#",
|
||||||
@ -310,13 +320,13 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
|
|||||||
"lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size,size,lv_attr",
|
"lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size,size,lv_attr",
|
||||||
pool->def->source.name,
|
pool->def->source.name,
|
||||||
NULL);
|
NULL);
|
||||||
if (virStorageBackendRunProgRegex(pool,
|
if (virCommandRunRegex(cmd,
|
||||||
cmd,
|
1,
|
||||||
1,
|
regexes,
|
||||||
regexes,
|
vars,
|
||||||
vars,
|
virStorageBackendLogicalMakeVol,
|
||||||
virStorageBackendLogicalMakeVol,
|
&cbdata,
|
||||||
vol, "lvs") < 0)
|
"lvs") < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -326,10 +336,10 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
virStorageBackendLogicalRefreshPoolFunc(char **const groups,
|
||||||
char **const groups,
|
void *data)
|
||||||
void *data ATTRIBUTE_UNUSED)
|
|
||||||
{
|
{
|
||||||
|
virStoragePoolObjPtr pool = data;
|
||||||
if (virStrToLong_ull(groups[0], NULL, 10, &pool->def->capacity) < 0)
|
if (virStrToLong_ull(groups[0], NULL, 10, &pool->def->capacity) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (virStrToLong_ull(groups[1], NULL, 10, &pool->def->available) < 0)
|
if (virStrToLong_ull(groups[1], NULL, 10, &pool->def->available) < 0)
|
||||||
@ -341,8 +351,7 @@ virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUS
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virStorageBackendLogicalFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
virStorageBackendLogicalFindPoolSourcesFunc(char **const groups,
|
||||||
char **const groups,
|
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
virStoragePoolSourceListPtr sourceList = data;
|
virStoragePoolSourceListPtr sourceList = data;
|
||||||
@ -432,9 +441,9 @@ virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
"--noheadings",
|
"--noheadings",
|
||||||
"-o", "pv_name,vg_name",
|
"-o", "pv_name,vg_name",
|
||||||
NULL);
|
NULL);
|
||||||
if (virStorageBackendRunProgRegex(NULL, cmd, 1, regexes, vars,
|
if (virCommandRunRegex(cmd, 1, regexes, vars,
|
||||||
virStorageBackendLogicalFindPoolSourcesFunc,
|
virStorageBackendLogicalFindPoolSourcesFunc,
|
||||||
&sourceList, "pvs") < 0) {
|
&sourceList, "pvs") < 0) {
|
||||||
virCommandFree(cmd);
|
virCommandFree(cmd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -593,13 +602,13 @@ virStorageBackendLogicalRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
/* Now get basic volgrp metadata */
|
/* Now get basic volgrp metadata */
|
||||||
if (virStorageBackendRunProgRegex(pool,
|
if (virCommandRunRegex(cmd,
|
||||||
cmd,
|
1,
|
||||||
1,
|
regexes,
|
||||||
regexes,
|
vars,
|
||||||
vars,
|
virStorageBackendLogicalRefreshPoolFunc,
|
||||||
virStorageBackendLogicalRefreshPoolFunc,
|
pool,
|
||||||
NULL, "vgs") < 0)
|
"vgs") < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -2760,3 +2761,247 @@ virCommandSetDryRun(virBufferPtr buf,
|
|||||||
dryRunCallback = cb;
|
dryRunCallback = cb;
|
||||||
dryRunOpaque = opaque;
|
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);
|
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__ */
|
#endif /* __VIR_COMMAND_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user