mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
Added storage backend helper APIs
This commit is contained in:
parent
20878720c0
commit
4a4e272f9d
@ -1,3 +1,11 @@
|
||||
Wed Feb 20 10:32:27 EST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* configure.in: Add check for selinux library
|
||||
* libvirt.spec.in: Add BuildRequires on libselinux-devel
|
||||
* src/Makefile.am, tests/Makefile.am: Add selinux build flags
|
||||
* src/storage_backend.c, src/storage_backend.h: Add some
|
||||
helper routines for storage backend impls
|
||||
|
||||
Wed Feb 20 10:26:27 EST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* Makefile.maint: Add virStorageReportError to locale check rule
|
||||
|
39
configure.in
39
configure.in
@ -473,6 +473,40 @@ AM_CONDITIONAL(HAVE_AVAHI, [test "x$with_avahi" = "xyes"])
|
||||
AC_SUBST(AVAHI_CFLAGS)
|
||||
AC_SUBST(AVAHI_LIBS)
|
||||
|
||||
dnl SELinux
|
||||
AC_ARG_WITH(selinux,
|
||||
[ --with-selinux use SELinux to manage security],
|
||||
[],
|
||||
[with_selinux=check])
|
||||
|
||||
SELINUX_CFLAGS=
|
||||
SELINUX_LIBS=
|
||||
if test "$with_selinux" != "no"; then
|
||||
old_cflags="$CFLAGS"
|
||||
old_libs="$LIBS"
|
||||
if test "$with_selinux" = "check"; then
|
||||
AC_CHECK_HEADER([selinux/selinux.h],[],[with_selinux=no])
|
||||
AC_CHECK_LIB(selinux, fgetfilecon,[],[with_selinux=no])
|
||||
if test "$with_selinux" != "no"; then
|
||||
with_selinux="yes"
|
||||
fi
|
||||
else
|
||||
AC_CHECK_HEADER([selinux/selinux.h],[],
|
||||
[AC_MSG_ERROR([You must install the SELinux development package in order to compile libvirt])])
|
||||
AC_CHECK_LIB(selinux, fgetfilecon,[],
|
||||
[AC_MSG_ERROR([You must install the SELinux development package in order to compile and run libvirt])])
|
||||
fi
|
||||
CFLAGS="$old_cflags"
|
||||
LIBS="$old_libs"
|
||||
fi
|
||||
if test "$with_selinux" = "yes"; then
|
||||
SELINUX_LIBS="-lselinux"
|
||||
AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1, [whether SELinux is available for security])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_SELINUX, [test "$with_selinux" != "no"])
|
||||
AC_SUBST(SELINUX_CFLAGS)
|
||||
AC_SUBST(SELINUX_LIBS)
|
||||
|
||||
dnl virsh libraries
|
||||
AC_CHECK_HEADERS([readline/readline.h])
|
||||
|
||||
@ -745,6 +779,11 @@ AC_MSG_NOTICE([ polkit: $POLKIT_CFLAGS $POLKIT_LIBS])
|
||||
else
|
||||
AC_MSG_NOTICE([ polkit: no])
|
||||
fi
|
||||
if test "$with_selinux" = "yes" ; then
|
||||
AC_MSG_NOTICE([ selinux: $SELINUX_CFLAGS $SELINUX_LIBS])
|
||||
else
|
||||
AC_MSG_NOTICE([ selinux: no])
|
||||
fi
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([Miscellaneous])
|
||||
AC_MSG_NOTICE([])
|
||||
|
@ -41,6 +41,7 @@ BuildRequires: ncurses-devel
|
||||
BuildRequires: gettext
|
||||
BuildRequires: gnutls-devel
|
||||
BuildRequires: avahi-devel
|
||||
BuildRequires: libselinux-devel
|
||||
BuildRequires: dnsmasq
|
||||
BuildRequires: bridge-utils
|
||||
BuildRequires: qemu
|
||||
|
@ -8,6 +8,7 @@ INCLUDES = \
|
||||
$(LIBXML_CFLAGS) \
|
||||
$(GNUTLS_CFLAGS) \
|
||||
$(SASL_CFLAGS) \
|
||||
$(SELINUX_CFLAGS) \
|
||||
-DBINDIR=\""$(libexecdir)"\" \
|
||||
-DSBINDIR=\""$(sbindir)"\" \
|
||||
-DSYSCONF_DIR="\"$(sysconfdir)\"" \
|
||||
@ -67,7 +68,7 @@ SERVER_SOURCES = \
|
||||
../qemud/remote_protocol.c ../qemud/remote_protocol.h
|
||||
|
||||
libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES)
|
||||
libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) \
|
||||
libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) $(SELINUX_LIBS) \
|
||||
@CYGWIN_EXTRA_LIBADD@ ../gnulib/lib/libgnu.la
|
||||
libvirt_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvirt_sym.version \
|
||||
-version-info @LIBVIRT_VERSION_INFO@ \
|
||||
|
@ -28,6 +28,14 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#if HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
@ -73,6 +81,468 @@ virStorageBackendToString(int type) {
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
virStorageBackendUpdateVolInfo(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
int withCapacity)
|
||||
{
|
||||
int ret, fd;
|
||||
|
||||
if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot open volume '%s': %s"),
|
||||
vol->target.path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = virStorageBackendUpdateVolInfoFD(conn,
|
||||
vol,
|
||||
fd,
|
||||
withCapacity);
|
||||
|
||||
close(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
virStorageBackendUpdateVolInfoFD(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
int fd,
|
||||
int withCapacity)
|
||||
{
|
||||
struct stat sb;
|
||||
#if HAVE_SELINUX
|
||||
security_context_t filecon = NULL;
|
||||
#endif
|
||||
|
||||
if (fstat(fd, &sb) < 0) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot stat file '%s': %s"),
|
||||
vol->target.path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sb.st_mode) &&
|
||||
!S_ISCHR(sb.st_mode) &&
|
||||
!S_ISBLK(sb.st_mode))
|
||||
return -2;
|
||||
|
||||
if (S_ISREG(sb.st_mode)) {
|
||||
vol->allocation = (unsigned long long)sb.st_blocks *
|
||||
(unsigned long long)sb.st_blksize;
|
||||
/* Regular files may be sparse, so logical size (capacity) is not same
|
||||
* as actual allocation above
|
||||
*/
|
||||
if (withCapacity)
|
||||
vol->capacity = sb.st_size;
|
||||
} else {
|
||||
off_t end;
|
||||
/* XXX this is POSIX compliant, but doesn't work for for CHAR files,
|
||||
* only BLOCK. There is a Linux specific ioctl() for getting
|
||||
* size of both CHAR / BLOCK devices we should check for in
|
||||
* configure
|
||||
*/
|
||||
end = lseek(fd, 0, SEEK_END);
|
||||
if (end == (off_t)-1) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot seek to end of file '%s':%s"),
|
||||
vol->target.path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
vol->allocation = end;
|
||||
if (withCapacity) vol->capacity = end;
|
||||
}
|
||||
|
||||
vol->target.perms.mode = sb.st_mode;
|
||||
vol->target.perms.uid = sb.st_uid;
|
||||
vol->target.perms.gid = sb.st_gid;
|
||||
|
||||
free(vol->target.perms.label);
|
||||
vol->target.perms.label = NULL;
|
||||
|
||||
#if HAVE_SELINUX
|
||||
if (fgetfilecon(fd, &filecon) == -1) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot get file context of %s: %s"),
|
||||
vol->target.path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
vol->target.perms.label = strdup(filecon);
|
||||
if (vol->target.perms.label == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("context"));
|
||||
return -1;
|
||||
}
|
||||
freecon(filecon);
|
||||
#else
|
||||
vol->target.perms.label = NULL;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a volume path directly in /dev/XXX, iterate over the
|
||||
* entries in the directory pool->def->target.path and find the
|
||||
* first symlink pointing to the volume path.
|
||||
*
|
||||
* If, the target.path is /dev/, then return the original volume
|
||||
* path.
|
||||
*
|
||||
* If no symlink is found, then return the original volume path
|
||||
*
|
||||
* Typically target.path is one of the /dev/disk/by-XXX dirs
|
||||
* with stable paths.
|
||||
*/
|
||||
char *
|
||||
virStorageBackendStablePath(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
char *devpath)
|
||||
{
|
||||
DIR *dh;
|
||||
struct dirent *dent;
|
||||
|
||||
/* Short circuit if pool has no target, or if its /dev */
|
||||
if (pool->def->target.path == NULL ||
|
||||
STREQ(pool->def->target.path, "/dev") ||
|
||||
STREQ(pool->def->target.path, "/dev/"))
|
||||
return devpath;
|
||||
|
||||
/* The pool is pointing somewhere like /dev/disk/by-path
|
||||
* or /dev/disk/by-id, so we need to check all symlinks in
|
||||
* the target directory and figure out which one points
|
||||
* to this device node
|
||||
*/
|
||||
if ((dh = opendir(pool->def->target.path)) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot read dir %s: %s"),
|
||||
pool->def->target.path,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((dent = readdir(dh)) != NULL) {
|
||||
char *stablepath;
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
stablepath = malloc(strlen(pool->def->target.path) +
|
||||
1 + strlen(dent->d_name) + 1);
|
||||
if (stablepath == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("path"));
|
||||
closedir(dh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(stablepath, pool->def->target.path);
|
||||
strcat(stablepath, "/");
|
||||
strcat(stablepath, dent->d_name);
|
||||
|
||||
if (virFileLinkPointsTo(stablepath, devpath)) {
|
||||
closedir(dh);
|
||||
return stablepath;
|
||||
}
|
||||
|
||||
free(stablepath);
|
||||
}
|
||||
|
||||
closedir(dh);
|
||||
|
||||
/* Couldn't find any matching stable link so give back
|
||||
* the original non-stable dev path
|
||||
*/
|
||||
return devpath;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run an external program.
|
||||
*
|
||||
* Read its output and apply a series of regexes to each line
|
||||
* When the entire set of regexes has matched consequetively
|
||||
* then run a callback passing in all the matches
|
||||
*/
|
||||
int
|
||||
virStorageBackendRunProgRegex(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
const char **prog,
|
||||
int nregex,
|
||||
const char **regex,
|
||||
int *nvars,
|
||||
virStorageBackendListVolRegexFunc func,
|
||||
void *data)
|
||||
{
|
||||
int child = 0, fd = -1, exitstatus, err, failed = 1;
|
||||
FILE *list = NULL;
|
||||
regex_t *reg;
|
||||
regmatch_t *vars = NULL;
|
||||
char line[1024];
|
||||
int maxReg = 0, i, j;
|
||||
int totgroups = 0, ngroup = 0, maxvars = 0;
|
||||
char **groups;
|
||||
|
||||
/* Compile all regular expressions */
|
||||
if ((reg = calloc(nregex, sizeof(*reg))) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("regex"));
|
||||
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));
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("Failed to compile regex %s"), error);
|
||||
for (j = 0 ; j <= i ; j++)
|
||||
regfree(®[j]);
|
||||
free(reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
totgroups += nvars[i];
|
||||
if (nvars[i] > maxvars)
|
||||
maxvars = nvars[i];
|
||||
|
||||
}
|
||||
|
||||
/* Storage for matched variables */
|
||||
if ((groups = calloc(totgroups, sizeof(*groups))) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("regex groups"));
|
||||
goto cleanup;
|
||||
}
|
||||
if ((vars = calloc(maxvars+1, sizeof(*vars))) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("regex groups"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* Run the program and capture its output */
|
||||
if (virExec(conn, (char**)prog, &child, -1, &fd, NULL) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((list = fdopen(fd, "r")) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot read fd"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), list) != NULL) {
|
||||
/* Strip trailing newline */
|
||||
int len = strlen(line);
|
||||
if (len && line[len-1] == '\n')
|
||||
line[len-1] = '\0';
|
||||
|
||||
for (i = 0 ; i <= maxReg && i < nregex ; i++) {
|
||||
if (regexec(®[i], line, 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 */
|
||||
line[vars[j+1].rm_eo] = '\0';
|
||||
if ((groups[ngroup++] =
|
||||
strdup(line + vars[j+1].rm_so)) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("regex groups"));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* We're matching on the last regex, so callback time */
|
||||
if (i == (nregex-1)) {
|
||||
if (((*func)(conn, pool, groups, data)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Release matches & restart to matching the first regex */
|
||||
for (j = 0 ; j < totgroups ; j++) {
|
||||
free(groups[j]);
|
||||
groups[j] = NULL;
|
||||
}
|
||||
maxReg = 0;
|
||||
ngroup = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
failed = 0;
|
||||
|
||||
cleanup:
|
||||
if (groups) {
|
||||
for (j = 0 ; j < totgroups ; j++)
|
||||
free(groups[j]);
|
||||
free(groups);
|
||||
}
|
||||
free(vars);
|
||||
|
||||
for (i = 0 ; i < nregex ; i++)
|
||||
regfree(®[i]);
|
||||
|
||||
free(reg);
|
||||
|
||||
if (list)
|
||||
fclose(list);
|
||||
else
|
||||
close(fd);
|
||||
|
||||
while ((err = waitpid(child, &exitstatus, 0) == -1) && errno == EINTR);
|
||||
|
||||
/* Don't bother checking exit status if we already failed */
|
||||
if (failed)
|
||||
return -1;
|
||||
|
||||
if (err == -1) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("failed to wait for command: %s"),
|
||||
strerror(errno));
|
||||
return -1;
|
||||
} else {
|
||||
if (WIFEXITED(exitstatus)) {
|
||||
if (WEXITSTATUS(exitstatus) != 0) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("non-zero exit status from command %d"),
|
||||
WEXITSTATUS(exitstatus));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("command did not exit cleanly"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
const char **prog,
|
||||
size_t n_columns,
|
||||
virStorageBackendListVolNulFunc func,
|
||||
void *data)
|
||||
{
|
||||
size_t n_tok = 0;
|
||||
int child = 0, fd = -1, exitstatus;
|
||||
FILE *fp = NULL;
|
||||
char **v;
|
||||
int err = -1;
|
||||
int w_err;
|
||||
int i;
|
||||
|
||||
if (n_columns == 0)
|
||||
return -1;
|
||||
|
||||
if (n_columns > SIZE_MAX / sizeof *v
|
||||
|| (v = malloc (n_columns * sizeof *v)) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("n_columns too large"));
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < n_columns; i++)
|
||||
v[i] = NULL;
|
||||
|
||||
/* Run the program and capture its output */
|
||||
if (virExec(conn, (char**)prog, &child, -1, &fd, NULL) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((fp = fdopen(fd, "r")) == NULL) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot read 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 (conn, pool, n_tok, v, data) < 0)
|
||||
goto cleanup;
|
||||
break;
|
||||
}
|
||||
++n_tok;
|
||||
if (n_tok == n_columns) {
|
||||
if (func (conn, pool, n_tok, v, data) < 0)
|
||||
goto cleanup;
|
||||
n_tok = 0;
|
||||
for (i = 0; i < n_columns; i++) {
|
||||
free (v[i]);
|
||||
v[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (feof (fp))
|
||||
err = 0;
|
||||
else
|
||||
virStorageReportError (conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("read error: %s"), strerror (errno));
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < n_columns; i++)
|
||||
free (v[i]);
|
||||
free (v);
|
||||
|
||||
if (fp)
|
||||
fclose (fp);
|
||||
else
|
||||
close (fd);
|
||||
|
||||
while ((w_err = waitpid (child, &exitstatus, 0) == -1) && errno == EINTR)
|
||||
/* empty */ ;
|
||||
|
||||
/* Don't bother checking exit status if we already failed */
|
||||
if (err < 0)
|
||||
return -1;
|
||||
|
||||
if (w_err == -1) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("failed to wait for command: %s"),
|
||||
strerror(errno));
|
||||
return -1;
|
||||
} else {
|
||||
if (WIFEXITED(exitstatus)) {
|
||||
if (WEXITSTATUS(exitstatus) != 0) {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("non-zero exit status from command %d"),
|
||||
WEXITSTATUS(exitstatus));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("command did not exit cleanly"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vim: set tabstop=4:
|
||||
* vim: set shiftwidth=4:
|
||||
|
@ -103,6 +103,44 @@ virStorageBackendVolOptionsPtr virStorageBackendVolOptionsForType(int type);
|
||||
int virStorageBackendFromString(const char *type);
|
||||
const char *virStorageBackendToString(int type);
|
||||
|
||||
int virStorageBackendUpdateVolInfo(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
int withCapacity);
|
||||
|
||||
int virStorageBackendUpdateVolInfoFD(virConnectPtr conn,
|
||||
virStorageVolDefPtr vol,
|
||||
int fd,
|
||||
int withCapacity);
|
||||
|
||||
char *virStorageBackendStablePath(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
char *devpath);
|
||||
|
||||
typedef int (*virStorageBackendListVolRegexFunc)(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
char **const groups,
|
||||
void *data);
|
||||
typedef int (*virStorageBackendListVolNulFunc)(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
size_t n_tokens,
|
||||
char **const groups,
|
||||
void *data);
|
||||
|
||||
int virStorageBackendRunProgRegex(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
const char **prog,
|
||||
int nregex,
|
||||
const char **regex,
|
||||
int *nvars,
|
||||
virStorageBackendListVolRegexFunc func,
|
||||
void *data);
|
||||
|
||||
int virStorageBackendRunProgNul(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
const char **prog,
|
||||
size_t n_columns,
|
||||
virStorageBackendListVolNulFunc func,
|
||||
void *data);
|
||||
|
||||
#endif /* __VIR_STORAGE_BACKEND_H__ */
|
||||
|
||||
|
@ -20,6 +20,7 @@ INCLUDES = \
|
||||
$(LIBXML_CFLAGS) \
|
||||
$(GNUTLS_CFLAGS) \
|
||||
$(SASL_CFLAGS) \
|
||||
$(SELINUX_CFLAGS) \
|
||||
-D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=199506L \
|
||||
-DGETTEXT_PACKAGE=\"$(PACKAGE)\" \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
@ -31,6 +32,7 @@ LDADDS = \
|
||||
$(LIBXML_LIBS) \
|
||||
$(GNUTLS_LIBS) \
|
||||
$(SASL_LIBS) \
|
||||
$(SELINUX_LIBS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(LIBVIRT) \
|
||||
../gnulib/lib/libgnu.la \
|
||||
|
Loading…
Reference in New Issue
Block a user