mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-27 02:51:16 +00:00
Core internal driver stub for sVirt support (Jams Morris & Dan Walsh)
This commit is contained in:
parent
a8cd24b346
commit
8bd1604cb7
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
||||
Tue Mar 3 09:40:13 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
Core internal driver stub for sVirt support (Jams Morris & Dan Walsh)
|
||||
* Makefile.maint: Add virSecurityReportError as a msggen
|
||||
function
|
||||
* docs/schemas/capability.rng: Add <secmodel> element
|
||||
* docs/schemas/domain.rng: Add <seclabel> element
|
||||
* include/libvirt/virterror.h, src/virterror.c: Add
|
||||
VIR_FROM_SECURITY and VIR_ERR_NO_SECURITY_MODEL
|
||||
* po/POTFILES.in: Add src/security.c
|
||||
* src/Makefile.am: Build security driver into libvirt.so
|
||||
* src/capabilities.c, src/capabilities.h: Handling of
|
||||
<secmodel> element / data
|
||||
* src/domain_conf.c, src/domain_conf.h: Handling of
|
||||
<seclabel> element / data
|
||||
* src/libvirt_private.syms: Add virXPathStringLimit and
|
||||
virSecurity* methods
|
||||
* src/security.c, src/security.h: Add internal driver
|
||||
stub impl
|
||||
* src/storage_backend.c: TODO item about seclabel
|
||||
* src/xml.c, src/xml.h: Add virXPathStringLimit
|
||||
|
||||
Tue Mar 3 09:25:13 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
Remote protocol / RPC API for sVirt support (James Morris & Dan Walsh)
|
||||
|
@ -343,6 +343,7 @@ msg_gen_function += umlLog
|
||||
msg_gen_function += umlReportError
|
||||
msg_gen_function += virConfError
|
||||
msg_gen_function += virDomainReportError
|
||||
msg_gen_function += virSecurityReportError
|
||||
msg_gen_function += virHashError
|
||||
msg_gen_function += virLibConnError
|
||||
msg_gen_function += virLibDomainError
|
||||
|
@ -33,9 +33,24 @@
|
||||
<optional>
|
||||
<ref name='topology'/>
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name='secmodel'/>
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name='secmodel'>
|
||||
<element name='secmodel'>
|
||||
<element name='model'>
|
||||
<text/>
|
||||
</element>
|
||||
<element name='doi'>
|
||||
<text/>
|
||||
</element>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
|
||||
<define name='cpufeatures'>
|
||||
<element name='features'>
|
||||
<optional>
|
||||
|
@ -22,10 +22,25 @@
|
||||
<optional>
|
||||
<ref name='devices'/>
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name='seclabel'/>
|
||||
</optional>
|
||||
</interleave>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name='seclabel'>
|
||||
<element name='seclabel'>
|
||||
<attribute name='model'>
|
||||
<text/>
|
||||
</attribute>
|
||||
<element name='label'>
|
||||
<text/>
|
||||
</element>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
|
||||
<define name='hvs'>
|
||||
<attribute name='type'>
|
||||
<choice>
|
||||
|
@ -61,6 +61,7 @@ typedef enum {
|
||||
VIR_FROM_UML, /* Error at the UML driver */
|
||||
VIR_FROM_NODEDEV, /* Error from node device monitor */
|
||||
VIR_FROM_XEN_INOTIFY, /* Error from xen inotify layer */
|
||||
VIR_FROM_SECURITY, /* Error from security framework */
|
||||
} virErrorDomain;
|
||||
|
||||
|
||||
@ -154,6 +155,7 @@ typedef enum {
|
||||
VIR_WAR_NO_NODE, /* failed to start node driver */
|
||||
VIR_ERR_INVALID_NODE_DEVICE,/* invalid node device object */
|
||||
VIR_ERR_NO_NODE_DEVICE,/* node device not found */
|
||||
VIR_ERR_NO_SECURITY_MODEL, /* security model not found */
|
||||
} virErrorNumber;
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@ src/proxy_internal.c
|
||||
src/qemu_conf.c
|
||||
src/qemu_driver.c
|
||||
src/remote_internal.c
|
||||
src/security.c
|
||||
src/storage_backend.c
|
||||
src/storage_backend_disk.c
|
||||
src/storage_backend_fs.c
|
||||
|
@ -140,7 +140,7 @@ UML_DRIVER_SOURCES = \
|
||||
NETWORK_DRIVER_SOURCES = \
|
||||
network_driver.h network_driver.c
|
||||
|
||||
# And finally storage backend specific impls
|
||||
# Storage backend specific impls
|
||||
STORAGE_DRIVER_SOURCES = \
|
||||
storage_driver.h storage_driver.c \
|
||||
storage_backend.h storage_backend.c
|
||||
@ -166,6 +166,11 @@ STORAGE_HELPER_DISK_SOURCES = \
|
||||
parthelper.c
|
||||
|
||||
|
||||
# Security framework and drivers for various models
|
||||
SECURITY_DRIVER_SOURCES = \
|
||||
security.h security.c
|
||||
|
||||
|
||||
NODE_DEVICE_DRIVER_SOURCES = \
|
||||
node_device.c node_device.h
|
||||
|
||||
@ -379,6 +384,10 @@ endif
|
||||
endif
|
||||
|
||||
|
||||
libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
|
||||
noinst_LTLIBRARIES += libvirt_driver_security.la
|
||||
libvirt_la_LIBADD += libvirt_driver_security.la
|
||||
|
||||
# Add all conditional sources just in case...
|
||||
EXTRA_DIST += \
|
||||
$(TEST_DRIVER_SOURCES) \
|
||||
|
@ -150,6 +150,8 @@ virCapabilitiesFree(virCapsPtr caps) {
|
||||
VIR_FREE(caps->host.migrateTrans);
|
||||
|
||||
VIR_FREE(caps->host.arch);
|
||||
VIR_FREE(caps->host.secModel.model);
|
||||
VIR_FREE(caps->host.secModel.doi);
|
||||
VIR_FREE(caps);
|
||||
}
|
||||
|
||||
@ -599,6 +601,14 @@ virCapabilitiesFormatXML(virCapsPtr caps)
|
||||
virBufferAddLit(&xml, " </cells>\n");
|
||||
virBufferAddLit(&xml, " </topology>\n");
|
||||
}
|
||||
|
||||
if (caps->host.secModel.model) {
|
||||
virBufferAddLit(&xml, " <secmodel>\n");
|
||||
virBufferVSprintf(&xml, " <model>%s</model>\n", caps->host.secModel.model);
|
||||
virBufferVSprintf(&xml, " <doi>%s</doi>\n", caps->host.secModel.doi);
|
||||
virBufferAddLit(&xml, " </secmodel>\n");
|
||||
}
|
||||
|
||||
virBufferAddLit(&xml, " </host>\n\n");
|
||||
|
||||
|
||||
|
@ -78,6 +78,12 @@ struct _virCapsHostNUMACell {
|
||||
int *cpus;
|
||||
};
|
||||
|
||||
typedef struct _virCapsHostSecModel virCapsHostSecModel;
|
||||
struct _virCapsHostSecModel {
|
||||
char *model;
|
||||
char *doi;
|
||||
};
|
||||
|
||||
typedef struct _virCapsHost virCapsHost;
|
||||
typedef virCapsHost *virCapsHostPtr;
|
||||
struct _virCapsHost {
|
||||
@ -90,6 +96,7 @@ struct _virCapsHost {
|
||||
char **migrateTrans;
|
||||
int nnumaCell;
|
||||
virCapsHostNUMACellPtr *numaCell;
|
||||
virCapsHostSecModel secModel;
|
||||
};
|
||||
|
||||
typedef struct _virCaps virCaps;
|
||||
|
@ -387,6 +387,15 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
|
||||
VIR_FREE(def);
|
||||
}
|
||||
|
||||
void virSecurityLabelDefFree(virDomainDefPtr def);
|
||||
|
||||
void virSecurityLabelDefFree(virDomainDefPtr def)
|
||||
{
|
||||
VIR_FREE(def->seclabel.model);
|
||||
VIR_FREE(def->seclabel.label);
|
||||
VIR_FREE(def->seclabel.imagelabel);
|
||||
}
|
||||
|
||||
void virDomainDefFree(virDomainDefPtr def)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -445,6 +454,8 @@ void virDomainDefFree(virDomainDefPtr def)
|
||||
VIR_FREE(def->cpumask);
|
||||
VIR_FREE(def->emulator);
|
||||
|
||||
virSecurityLabelDefFree(def);
|
||||
|
||||
VIR_FREE(def);
|
||||
}
|
||||
|
||||
@ -1833,6 +1844,34 @@ static int virDomainLifecycleParseXML(virConnectPtr conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virSecurityLabelDefParseXML(virConnectPtr conn,
|
||||
const virDomainDefPtr def,
|
||||
xmlXPathContextPtr ctxt)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (virXPathNode(conn, "./seclabel", ctxt) == NULL)
|
||||
return 0;
|
||||
|
||||
p = virXPathStringLimit(conn, "string(./seclabel/label[1])",
|
||||
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
|
||||
if (p == NULL)
|
||||
goto error;
|
||||
def->seclabel.label = p;
|
||||
|
||||
p = virXPathStringLimit(conn, "string(./seclabel/@model)",
|
||||
VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
|
||||
if (p == NULL)
|
||||
goto error;
|
||||
def->seclabel.model = p;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
virSecurityLabelDefFree(def);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
|
||||
virCapsPtr caps,
|
||||
@ -2418,6 +2457,10 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
|
||||
}
|
||||
VIR_FREE(nodes);
|
||||
|
||||
/* analysis of security label */
|
||||
if (virSecurityLabelDefParseXML(conn, def, ctxt) == -1)
|
||||
goto error;
|
||||
|
||||
return def;
|
||||
|
||||
no_memory:
|
||||
@ -3435,6 +3478,13 @@ char *virDomainDefFormat(virConnectPtr conn,
|
||||
goto cleanup;
|
||||
|
||||
virBufferAddLit(&buf, " </devices>\n");
|
||||
|
||||
if (def->seclabel.model) {
|
||||
virBufferEscapeString(&buf, " <seclabel model='%s'>\n", def->seclabel.model);
|
||||
virBufferEscapeString(&buf, " <label>%s</label>\n", def->seclabel.label);
|
||||
virBufferAddLit(&buf, " </seclabel>\n");
|
||||
}
|
||||
|
||||
virBufferAddLit(&buf, "</domain>\n");
|
||||
|
||||
if (virBufferError(&buf))
|
||||
|
@ -410,6 +410,15 @@ struct _virDomainOSDef {
|
||||
char *bootloaderArgs;
|
||||
};
|
||||
|
||||
/* Security configuration for domain */
|
||||
typedef struct _virSecurityLabelDef virSecurityLabelDef;
|
||||
typedef virSecurityLabelDef *virSecurityLabelDefPtr;
|
||||
struct _virSecurityLabelDef {
|
||||
char *model; /* name of security model */
|
||||
char *label; /* security label string */
|
||||
char *imagelabel; /* security image label string */
|
||||
};
|
||||
|
||||
#define VIR_DOMAIN_CPUMASK_LEN 1024
|
||||
|
||||
/* Guest VM main configuration */
|
||||
@ -467,6 +476,7 @@ struct _virDomainDef {
|
||||
|
||||
/* Only 1 */
|
||||
virDomainChrDefPtr console;
|
||||
virSecurityLabelDef seclabel;
|
||||
};
|
||||
|
||||
/* Guest VM runtime state */
|
||||
|
@ -247,6 +247,14 @@ qparam_query_parse;
|
||||
free_qparam_set;
|
||||
|
||||
|
||||
# security.h
|
||||
virSecurityDriverStartup;
|
||||
virSecurityDriverInit;
|
||||
virSecurityDriverSetDOI;
|
||||
virSecurityDriverGetDOI;
|
||||
virSecurityDriverGetModel;
|
||||
|
||||
|
||||
# storage_conf.h
|
||||
virStoragePoolDefFormat;
|
||||
virStoragePoolDefFree;
|
||||
@ -351,3 +359,4 @@ virXPathNode;
|
||||
virXPathNodeSet;
|
||||
virXPathString;
|
||||
virXMLPropString;
|
||||
virXPathStringLimit;
|
||||
|
113
src/security.c
Normal file
113
src/security.c
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Authors:
|
||||
* James Morris <jmorris@namei.org>
|
||||
*
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "virterror_internal.h"
|
||||
|
||||
#include "security.h"
|
||||
|
||||
static virSecurityDriverPtr security_drivers[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int
|
||||
virSecurityDriverStartup(virSecurityDriverPtr *drv,
|
||||
const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (name && STREQ(name, "none"))
|
||||
return -2;
|
||||
|
||||
for (i = 0; security_drivers[i] != NULL ; i++) {
|
||||
virSecurityDriverPtr tmp = security_drivers[i];
|
||||
|
||||
if (name && STRNEQ(tmp->name, name))
|
||||
continue;
|
||||
|
||||
switch (tmp->probe()) {
|
||||
case SECURITY_DRIVER_ENABLE:
|
||||
virSecurityDriverInit(tmp);
|
||||
if (tmp->open(NULL, tmp) == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
*drv = tmp;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SECURITY_DRIVER_DISABLE:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
void
|
||||
virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char errorMessage[1024];
|
||||
|
||||
if (fmt) {
|
||||
va_start(args, fmt);
|
||||
vsnprintf(errorMessage, sizeof(errorMessage) - 1, fmt, args);
|
||||
va_end(args);
|
||||
} else
|
||||
errorMessage[0] = '\0';
|
||||
|
||||
virRaiseError(conn, NULL, NULL, VIR_FROM_SECURITY, code,
|
||||
VIR_ERR_ERROR, NULL, NULL, NULL, -1, -1, "%s",
|
||||
errorMessage);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
void
|
||||
virSecurityDriverInit(virSecurityDriverPtr drv)
|
||||
{
|
||||
memset(&drv->_private, 0, sizeof drv->_private);
|
||||
}
|
||||
|
||||
int
|
||||
virSecurityDriverSetDOI(virConnectPtr conn,
|
||||
virSecurityDriverPtr drv,
|
||||
const char *doi)
|
||||
{
|
||||
if (strlen(doi) >= VIR_SECURITY_DOI_BUFLEN) {
|
||||
virSecurityReportError(conn, VIR_ERR_ERROR,
|
||||
_("%s: DOI \'%s\' is "
|
||||
"longer than the maximum allowed length of %d"),
|
||||
__func__, doi, VIR_SECURITY_DOI_BUFLEN - 1);
|
||||
return -1;
|
||||
}
|
||||
strcpy(drv->_private.doi, doi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
virSecurityDriverGetDOI(virSecurityDriverPtr drv)
|
||||
{
|
||||
return drv->_private.doi;
|
||||
}
|
||||
|
||||
const char *
|
||||
virSecurityDriverGetModel(virSecurityDriverPtr drv)
|
||||
{
|
||||
return drv->name;
|
||||
}
|
86
src/security.h
Normal file
86
src/security.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Authors:
|
||||
* James Morris <jmorris@namei.org>
|
||||
*
|
||||
*/
|
||||
#ifndef __VIR_SECURITY_H__
|
||||
#define __VIR_SECURITY_H__
|
||||
|
||||
#include "internal.h"
|
||||
#include "domain_conf.h"
|
||||
|
||||
/*
|
||||
* Return values for security driver probing: the driver will determine
|
||||
* whether it should be enabled or disabled.
|
||||
*/
|
||||
typedef enum {
|
||||
SECURITY_DRIVER_ENABLE = 0,
|
||||
SECURITY_DRIVER_ERROR = -1,
|
||||
SECURITY_DRIVER_DISABLE = -2,
|
||||
} virSecurityDriverStatus;
|
||||
|
||||
typedef struct _virSecurityDriver virSecurityDriver;
|
||||
typedef virSecurityDriver *virSecurityDriverPtr;
|
||||
typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
|
||||
typedef int (*virSecurityDriverOpen) (virConnectPtr conn,
|
||||
virSecurityDriverPtr drv);
|
||||
typedef int (*virSecurityDomainRestoreImageLabel) (virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
virDomainDeviceDefPtr dev);
|
||||
typedef int (*virSecurityDomainSetImageLabel) (virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
virDomainDeviceDefPtr dev);
|
||||
typedef int (*virSecurityDomainGenLabel) (virDomainObjPtr sec);
|
||||
typedef int (*virSecurityDomainGetLabel) (virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
virSecurityLabelPtr sec);
|
||||
typedef int (*virSecurityDomainRestoreLabel) (virConnectPtr conn,
|
||||
virDomainObjPtr vm);
|
||||
typedef int (*virSecurityDomainSetLabel) (virConnectPtr conn,
|
||||
virSecurityDriverPtr drv,
|
||||
virDomainObjPtr vm);
|
||||
|
||||
struct _virSecurityDriver {
|
||||
const char *name;
|
||||
virSecurityDriverProbe probe;
|
||||
virSecurityDriverOpen open;
|
||||
virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
|
||||
virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
|
||||
virSecurityDomainGenLabel domainGenSecurityLabel;
|
||||
virSecurityDomainGetLabel domainGetSecurityLabel;
|
||||
virSecurityDomainSetLabel domainSetSecurityLabel;
|
||||
virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
|
||||
|
||||
/*
|
||||
* This is internally managed driver state and should only be accessed
|
||||
* via helpers below.
|
||||
*/
|
||||
struct {
|
||||
char doi[VIR_SECURITY_DOI_BUFLEN];
|
||||
} _private;
|
||||
};
|
||||
|
||||
/* Global methods */
|
||||
int virSecurityDriverStartup(virSecurityDriverPtr *drv,
|
||||
const char *name);
|
||||
|
||||
void
|
||||
virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
|
||||
ATTRIBUTE_FORMAT(printf, 3, 4);
|
||||
|
||||
/* Helpers */
|
||||
void virSecurityDriverInit(virSecurityDriverPtr drv);
|
||||
int virSecurityDriverSetDOI(virConnectPtr conn,
|
||||
virSecurityDriverPtr drv,
|
||||
const char *doi);
|
||||
const char *virSecurityDriverGetDOI(virSecurityDriverPtr drv);
|
||||
const char *virSecurityDriverGetModel(virSecurityDriverPtr drv);
|
||||
|
||||
#endif /* __VIR_SECURITY_H__ */
|
@ -276,6 +276,7 @@ virStorageBackendUpdateVolTargetInfoFD(virConnectPtr conn,
|
||||
VIR_FREE(target->perms.label);
|
||||
|
||||
#if HAVE_SELINUX
|
||||
/* XXX: make this a security driver call */
|
||||
if (fgetfilecon(fd, &filecon) == -1) {
|
||||
if (errno != ENODATA && errno != ENOTSUP) {
|
||||
virReportSystemError(conn, errno,
|
||||
|
@ -151,6 +151,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
|
||||
case VIR_FROM_UML:
|
||||
dom = "UML ";
|
||||
break;
|
||||
case VIR_FROM_SECURITY:
|
||||
dom = "Security Labeling ";
|
||||
break;
|
||||
}
|
||||
return(dom);
|
||||
}
|
||||
@ -995,6 +998,12 @@ virErrorMsg(virErrorNumber error, const char *info)
|
||||
else
|
||||
errmsg = _("Node device not found: %s");
|
||||
break;
|
||||
case VIR_ERR_NO_SECURITY_MODEL:
|
||||
if (info == NULL)
|
||||
errmsg = _("Security model not found");
|
||||
else
|
||||
errmsg = _("Security model not found: %s");
|
||||
break;
|
||||
}
|
||||
return (errmsg);
|
||||
}
|
||||
|
30
src/xml.c
30
src/xml.c
@ -76,6 +76,36 @@ virXPathString(virConnectPtr conn,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* virXPathStringLimit:
|
||||
* @xpath: the XPath string to evaluate
|
||||
* @maxlen: maximum length permittred string
|
||||
* @ctxt: an XPath context
|
||||
*
|
||||
* Wrapper for virXPathString, which validates the length of the returned
|
||||
* string.
|
||||
*
|
||||
* Returns a new string which must be deallocated by the caller or NULL if
|
||||
* the evaluation failed.
|
||||
*/
|
||||
char *
|
||||
virXPathStringLimit(virConnectPtr conn,
|
||||
const char *xpath,
|
||||
size_t maxlen,
|
||||
xmlXPathContextPtr ctxt)
|
||||
{
|
||||
char *tmp = virXPathString(conn, xpath, ctxt);
|
||||
|
||||
if (tmp != NULL && strlen(tmp) >= maxlen) {
|
||||
virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("\'%s\' value longer than %Zd bytes in virXPathStringLimit()"),
|
||||
xpath, maxlen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* virXPathNumber:
|
||||
* @xpath: the XPath string to evaluate
|
||||
|
@ -17,6 +17,10 @@ int virXPathBoolean (virConnectPtr conn,
|
||||
char * virXPathString (virConnectPtr conn,
|
||||
const char *xpath,
|
||||
xmlXPathContextPtr ctxt);
|
||||
char * virXPathStringLimit(virConnectPtr conn,
|
||||
const char *xpath,
|
||||
size_t maxlen,
|
||||
xmlXPathContextPtr ctxt);
|
||||
int virXPathNumber (virConnectPtr conn,
|
||||
const char *xpath,
|
||||
xmlXPathContextPtr ctxt,
|
||||
|
Loading…
Reference in New Issue
Block a user