Devel
Threads by month
- ----- 2026 -----
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- 38 participants
- 40039 discussions
This patch contains:
-random bugfixes
-gcc -Wall "fixes"
-a few new constants for 4.x
-Implementation of virConnectAuth
-javah build fixes (One .class file can generate many .h files.)
It is NOT a full update for 4.x, the only major new feature is
authentication support.
I've attached the patch, and the new files. (Is there some way to
generate patches with new files?)
Please remove the
/src/jni/org_libvirt_VirDomain_CreateFlags.h
/src/jni/org_libvirt_VirDomain_MigrateFlags.h
files from the CVS, as these are auto-generated.
regards
István
? .project
? src/jni/VirConnectAuthCallbackBridge.c
? src/jni/VirConnectAuthCallbackBridge.h
? src/org/libvirt/VirConnectAuth.java
? src/org/libvirt/VirConnectAuthDefault.java
? src/org/libvirt/VirConnectCredential.java
Index: src/Makefile.am
===================================================================
RCS file: /data/cvs/libvirt-java/src/Makefile.am,v
retrieving revision 1.2
diff -u -p -r1.2 Makefile.am
--- src/Makefile.am 25 Jun 2008 13:02:30 -0000 1.2
+++ src/Makefile.am 29 Jun 2008 17:22:35 -0000
@@ -4,6 +4,9 @@ SUBDIRS=. jni
java_libvirt_source_files = \
org/libvirt/LibvirtException.java \
org/libvirt/VirConnect.java \
+ org/libvirt/VirConnectAuthDefault.java \
+ org/libvirt/VirConnectAuth.java \
+ org/libvirt/VirConnectCredential.java \
org/libvirt/VirDomainBlockStats.java \
org/libvirt/VirDomainInfo.java \
org/libvirt/VirDomainInterfaceStats.java \
Index: src/test.java
===================================================================
RCS file: /data/cvs/libvirt-java/src/test.java,v
retrieving revision 1.1
diff -u -p -r1.1 test.java
--- src/test.java 24 Jun 2008 16:32:24 -0000 1.1
+++ src/test.java 29 Jun 2008 17:22:35 -0000
@@ -16,6 +16,19 @@ public class test {
Integer.decode("0xc3"), Integer.decode("0x0f"),
Integer.decode("0x5a"), Integer.decode("0xa5"),
Integer.decode("0xf0"), Integer.decode("0x3c"), Integer.decode("0x87"), Integer.decode("0xd2"), Integer.decode("0x1e"), Integer.decode("0x69")} ;
+
+ //For testing the authentication
+ VirConnectAuth defaultAuth = new VirConnectAuthDefault();
+
+ //You need to configure your libvirtd for remote/authenticated connections, and adjust the URL below
+ //for this to work. Otherwise, you'll get an error
+ try{
+ conn = new VirConnect("test+tcp://localhost/default", defaultAuth, 0);
+ System.out.println("Encrypted connection successful!");
+ } catch (LibvirtException e){
+ System.out.println("exception caught:"+e);
+ System.out.println(e.getVirError());
+ }
try{
conn = new VirConnect("test:///default", false);
Index: src/jni/Makefile.am
===================================================================
RCS file: /data/cvs/libvirt-java/src/jni/Makefile.am,v
retrieving revision 1.2
diff -u -p -r1.2 Makefile.am
--- src/jni/Makefile.am 25 Jun 2008 13:02:30 -0000 1.2
+++ src/jni/Makefile.am 29 Jun 2008 17:22:35 -0000
@@ -5,12 +5,17 @@ SOURCES = \
org_libvirt_VirConnect.c \
org_libvirt_VirDomain.c \
VirErrorHandler.c \
- VirErrorHandler.h
+ VirErrorHandler.h \
+ VirConnectAuthCallbackBridge.c \
+ VirConnectAuthCallbackBridge.h
GENERATED = \
org_libvirt_VirConnect.h \
org_libvirt_VirNetwork.h \
- org_libvirt_VirDomain.h
+ org_libvirt_VirDomain.h \
+ org_libvirt_VirDomain_CreateFlags.h \
+ org_libvirt_VirDomain_MigrateFlags.h \
+ org_libvirt_VirDomain_XMLFlags.h
BUILT_SOURCES = $(GENERATED)
@@ -20,7 +25,7 @@ org_libvirt_VirConnect.h : $(JAVA_CLASS_
org_libvirt_VirNetwork.h: $(JAVA_CLASS_ROOT)/org/libvirt/VirNetwork.class
$(JAVAH) -classpath $(JAVA_CLASS_ROOT) org.libvirt.VirNetwork
-org_libvirt_VirDomain.h: $(JAVA_CLASS_ROOT)/org/libvirt/VirDomain.class
+org_libvirt_VirDomain.h org_libvirt_VirDomain_CreateFlags.h org_libvirt_VirDomain_MigrateFlags.h org_libvirt_VirDomain_XMLFlags.h : $(JAVA_CLASS_ROOT)/org/libvirt/VirDomain.class
$(JAVAH) -classpath $(JAVA_CLASS_ROOT) org.libvirt.VirDomain
lib_LTLIBRARIES = libvirt_jni.la
@@ -31,4 +36,4 @@ libvirt_jni_la_LDFLAGS = -version-info
CLEANFILES = \
- $(GENERATED)
+ $(GENERATED) $(GENERATED_SUB_1)
Index: src/jni/org_libvirt_VirConnect.c
===================================================================
RCS file: /data/cvs/libvirt-java/src/jni/org_libvirt_VirConnect.c,v
retrieving revision 1.1
diff -u -p -r1.1 org_libvirt_VirConnect.c
--- src/jni/org_libvirt_VirConnect.c 24 Jun 2008 16:32:24 -0000 1.1
+++ src/jni/org_libvirt_VirConnect.c 29 Jun 2008 17:22:35 -0000
@@ -2,14 +2,20 @@
#include <libvirt/libvirt.h>
#include <stdlib.h>
#include "VirErrorHandler.h"
+#include "VirConnectAuthCallbackBridge.h"
+
+#include <assert.h>
+
+//TODO We are leaking UTFChars all over the place. We need to strcpy, then release every string we get from JAVA, and not use them directly!
JNIEXPORT jint JNICALL Java_org_libvirt_VirConnect__1virInitialize
(JNIEnv *env, jclass cls){
int result;
result=virInitialize();
- //The connection-less errors go to the initializing thread as an aexception.
+ //The connection-less errors go to the initializing thread as an exception.
//Not ideal, but better than just dropping the errors.
virSetErrorFunc(env, virErrorHandler);
+ return result;
}
JNIEXPORT void JNICALL Java_org_libvirt_VirConnect__1close
@@ -22,7 +28,7 @@ JNIEXPORT jstring JNICALL Java_org_libvi
//All this gymnastics is so that we can free() the hostname string
jstring j_hostname=NULL;
char *hostname;
- if(hostname = virConnectGetHostname((virConnectPtr)VCP)){
+ if((hostname = virConnectGetHostname((virConnectPtr)VCP))){
j_hostname = (*env)->NewStringUTF(env, hostname);
free(hostname);
}
@@ -33,7 +39,7 @@ JNIEXPORT jstring JNICALL Java_org_libvi
(JNIEnv *env, jobject obj, jlong VCP){
jstring j_capabilities=NULL;
char *capabilities;
- if(capabilities = virConnectGetCapabilities((virConnectPtr)VCP)){
+ if((capabilities = virConnectGetCapabilities((virConnectPtr)VCP))){
j_capabilities = (*env)->NewStringUTF(env, capabilities);
free(capabilities);
}
@@ -49,7 +55,7 @@ JNIEXPORT jstring JNICALL Java_org_libvi
(JNIEnv *env, jobject obj, jlong VCP){
const char *type;
//Here we get a static string, no need to free()
- if(type=virConnectGetType((virConnectPtr)VCP)){
+ if((type=virConnectGetType((virConnectPtr)VCP))){
return (*env)->NewStringUTF(env, type);
} else {
return NULL;
@@ -60,7 +66,7 @@ JNIEXPORT jstring JNICALL Java_org_libvi
(JNIEnv *env, jobject obj, jlong VCP){
jstring j_uri=NULL;
char *uri;
- if(uri = virConnectGetURI((virConnectPtr)VCP)){
+ if((uri = virConnectGetURI((virConnectPtr)VCP))){
j_uri = (*env)->NewStringUTF(env, uri);
free(uri);
}
@@ -150,7 +156,7 @@ JNIEXPORT jlong JNICALL Java_org_libvirt
if(vc==NULL){
virCopyLastError(&error);
virErrorHandler(env, &error);
- return (long)NULL;
+ return (jlong)NULL;
}
//Initialized the error handler for this connection
@@ -170,7 +176,7 @@ JNIEXPORT jlong JNICALL Java_org_libvirt
if(vc==NULL){
virCopyLastError(&error);
virErrorHandler(env, &error);
- return (long)NULL;
+ return (jlong)NULL;
}
//Initialized the error handler for this connection
@@ -179,14 +185,67 @@ JNIEXPORT jlong JNICALL Java_org_libvirt
return (jlong)vc;
};
+JNIEXPORT jlong JNICALL Java_org_libvirt_VirConnect__1openAuth
+ (JNIEnv *env, jobject obj, jstring uri, jobject j_auth, jint flags){
+
+ virConnectPtr vc;
+ virError error;
+
+ virConnectAuth *auth = malloc(sizeof(virConnectAuth));
+
+ jobject j_credTypeElement;
+ int c;
+
+ //Prepare by computing the class and field IDs
+ jfieldID credTypeArray_id = (*env)->GetFieldID(env,
+ (*env)->FindClass(env, "org/libvirt/VirConnectAuth"),
+ "credType",
+ "[Lorg/libvirt/VirConnectCredential$VirConnectCredentialType;");
+ jmethodID credTypeMapToInt_id = (*env)->GetMethodID(env,
+ (*env)->FindClass(env, "org/libvirt/VirConnectCredential$VirConnectCredentialType"),
+ "mapToInt",
+ "()I");
+
+ //Copy the array of credtypes with the helper function
+ jarray j_credTypeArray=(*env)->GetObjectField(env, j_auth, credTypeArray_id);
+ auth->ncredtype = (*env)->GetArrayLength(env, j_credTypeArray);
+
+ auth->credtype = calloc(auth->ncredtype, sizeof(int));
+ for(c=0; c< auth->ncredtype; c++){
+ j_credTypeElement = (*env)->GetObjectArrayElement(env, j_credTypeArray, c);
+ auth->credtype[c]=(*env)->CallIntMethod(env, j_credTypeElement, credTypeMapToInt_id);
+ }
+
+ //The callback function is always VirConnectAuthCallbackBridge
+ auth->cb = &VirConnectAuthCallbackBridge;
+ //We pass the VirConnectAuth object and the JNI env in cdbata
+ CallBackStructType* cb_wrapper;
+ cb_wrapper = malloc(sizeof(CallBackStructType));
+ cb_wrapper->env = env;
+ cb_wrapper->auth = j_auth;
+ auth->cbdata=cb_wrapper;
+
+ vc=virConnectOpenAuth((*env)->GetStringUTFChars(env, uri, NULL), auth, flags);
+ if(vc==NULL){
+ virCopyLastError(&error);
+ virErrorHandler(env, &error);
+ return (jlong)NULL;
+ }
+
+ //Initialize the error handler for this connection
+ virConnSetErrorFunc(vc, env, virErrorHandler);
+
+ return (jlong)vc;
+}
+
JNIEXPORT jlong JNICALL Java_org_libvirt_VirConnect__1virNetworkCreateXML
(JNIEnv *env, jobject obj, jlong VCP, jstring xmlDesc){
- return(jlong)virNetworkCreateXML((virConnectPtr)VCP, (*env)->GetStringUTFChars(env, xmlDesc, NULL));
+ return (jlong)virNetworkCreateXML((virConnectPtr)VCP, (*env)->GetStringUTFChars(env, xmlDesc, NULL));
}
JNIEXPORT jlong JNICALL Java_org_libvirt_VirConnect__1virNetworkDefineXML
(JNIEnv *env, jobject obj, jlong VCP, jstring xmlDesc){
- return(jlong)virNetworkDefineXML((virConnectPtr)VCP, (*env)->GetStringUTFChars(env, xmlDesc, NULL));
+ return (jlong)virNetworkDefineXML((virConnectPtr)VCP, (*env)->GetStringUTFChars(env, xmlDesc, NULL));
}
JNIEXPORT jlong JNICALL Java_org_libvirt_VirConnect__1virNetworkLookupByName
@@ -202,7 +261,6 @@ JNIEXPORT jlong JNICALL Java_org_libvirt
//compact to bytes
for(c=0; c < VIR_UUID_BUFLEN; c++)
UUID[c]=UUID_int[c];
- (*env)->ExceptionDescribe(env);
return (jlong)virNetworkLookupByUUID((virConnectPtr)VCP, UUID);
}
@@ -266,8 +324,8 @@ JNIEXPORT jintArray JNICALL Java_org_lib
(JNIEnv *env, jobject obj, jlong VCP){
int maxids;
int *ids;
- int c;
jintArray j_ids=NULL;
+
if((maxids = virConnectNumOfDomains((virConnectPtr)VCP))<0)
return NULL;
ids= (int*)calloc(maxids, sizeof(int));
@@ -313,7 +371,7 @@ JNIEXPORT jlong JNICALL Java_org_libvirt
JNIEXPORT jlong JNICALL Java_org_libvirt_VirConnect__1virGetHypervisorVersion
(JNIEnv *env, jobject obj, jstring j_type){
- long libVer;
+ unsigned long libVer;
const char *type;
unsigned long typeVer;
Index: src/jni/org_libvirt_VirDomain.c
===================================================================
RCS file: /data/cvs/libvirt-java/src/jni/org_libvirt_VirDomain.c,v
retrieving revision 1.1
diff -u -p -r1.1 org_libvirt_VirDomain.c
--- src/jni/org_libvirt_VirDomain.c 24 Jun 2008 16:32:24 -0000 1.1
+++ src/jni/org_libvirt_VirDomain.c 29 Jun 2008 17:22:36 -0000
@@ -7,7 +7,7 @@ JNIEXPORT jstring JNICALL Java_org_libvi
(JNIEnv *env, jobject obj, jlong VDP, jint flags){
jstring j_xmlDesc;
char* xmlDesc = NULL;
- if(xmlDesc = virDomainGetXMLDesc((virDomainPtr)VDP, flags)){
+ if((xmlDesc = virDomainGetXMLDesc((virDomainPtr)VDP, flags))){
j_xmlDesc = (*env)->NewStringUTF(env, xmlDesc);
free(xmlDesc);
}
@@ -56,7 +56,7 @@ JNIEXPORT jstring JNICALL Java_org_libvi
jstring j_OSType;
char *OSType;
- if(OSType = virDomainGetOSType((virDomainPtr)VDP)){
+ if((OSType = virDomainGetOSType((virDomainPtr)VDP))){
j_OSType = (*env)->NewStringUTF(env, OSType);
free(OSType);
}
@@ -70,7 +70,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_
int nparams;
//We don't return nparams
- if(schedulerType = virDomainGetSchedulerType((virDomainPtr)VDP, &nparams)){
+ if((schedulerType = virDomainGetSchedulerType((virDomainPtr)VDP, &nparams))){
j_schedulerType = (*env)->NewStringUTF(env, schedulerType);
free(schedulerType);
}
@@ -264,7 +264,6 @@ JNIEXPORT jobjectArray JNICALL Java_org_
jobject j_info;
jobjectArray j_infoArray=NULL;
- jobjectArray j_statusArray;
jfieldID number_id;
jfieldID state_id;
@@ -332,7 +331,7 @@ JNIEXPORT jintArray JNICALL Java_org_lib
int *i_cpumaps;
jintArray j_cpumaps;
int c;
- virNodeInfo nodeinfo;
+ virNodeInfoPtr nodeinfo;
virVcpuInfoPtr info;
//Check number of vcpus;
@@ -340,9 +339,9 @@ JNIEXPORT jintArray JNICALL Java_org_lib
return NULL;
//Get maplen
- if(VirNodeGetInfo( virDomainGetConnect( (virDomainPtr)VDP), nodeinfo )<0)
+ if(virNodeGetInfo( virDomainGetConnect( (virDomainPtr)VDP), nodeinfo )<0)
return NULL;
- maplen=VIR_CPU_MAPLEN( VIR_NODEINFO_MAXCPUS( nodeinfo ) );
+ maplen=VIR_CPU_MAPLEN( VIR_NODEINFO_MAXCPUS( *nodeinfo ) );
info=(virVcpuInfoPtr)calloc(maxinfo, sizeof(virVcpuInfo));
cpumaps=malloc(sizeof(int)*maxinfo*maplen);
@@ -368,6 +367,7 @@ JNIEXPORT jint JNICALL Java_org_libvirt_
unsigned char *cpumap;
jint *i_cpumap;
int c;
+ int retval;
//Get maplen
maplen=(*env)->GetArrayLength(env, j_cpumap);
@@ -382,10 +382,11 @@ JNIEXPORT jint JNICALL Java_org_libvirt_
cpumap[c]=i_cpumap[c];
//Call libvirt
- virDomainPinVcpu((virDomainPtr)VDP, vcpu, cpumap, maplen);
+ retval = virDomainPinVcpu((virDomainPtr)VDP, vcpu, cpumap, maplen);
free(cpumap);
free(i_cpumap);
+ return retval;
}
JNIEXPORT jint JNICALL Java_org_libvirt_VirDomain__1setVcpus
Index: src/jni/org_libvirt_VirNetwork.c
===================================================================
RCS file: /data/cvs/libvirt-java/src/jni/org_libvirt_VirNetwork.c,v
retrieving revision 1.1
diff -u -p -r1.1 org_libvirt_VirNetwork.c
--- src/jni/org_libvirt_VirNetwork.c 24 Jun 2008 16:32:24 -0000 1.1
+++ src/jni/org_libvirt_VirNetwork.c 29 Jun 2008 17:22:36 -0000
@@ -1,11 +1,12 @@
#include "org_libvirt_VirNetwork.h"
#include <libvirt/libvirt.h>
+#include <stdlib.h>
JNIEXPORT jstring JNICALL Java_org_libvirt_VirNetwork__1getXMLDesc
(JNIEnv *env, jobject obj, jlong VNP, jint flags){
jstring j_xmlDesc;
char* xmlDesc;
- if(xmlDesc = virNetworkGetXMLDesc((virNetworkPtr)VNP, flags)){
+ if((xmlDesc = virNetworkGetXMLDesc((virNetworkPtr)VNP, flags))){
j_xmlDesc = (*env)->NewStringUTF(env, xmlDesc);
free(xmlDesc);
}
@@ -36,15 +37,15 @@ JNIEXPORT jboolean JNICALL Java_org_libv
JNIEXPORT jint JNICALL Java_org_libvirt_VirNetwork__1setAutostart
(JNIEnv *env, jobject obj, jlong VNP, jboolean autostart){
- virNetworkSetAutostart((virNetworkPtr)VNP, autostart);
+ return virNetworkSetAutostart((virNetworkPtr)VNP, autostart);
}
JNIEXPORT jstring JNICALL Java_org_libvirt_VirNetwork__1getBridgeName
(JNIEnv *env, jobject obj, jlong VNP){
jstring j_bridgeName;
- char *bridgeName;
+ char *bridgeName=NULL;
- if(bridgeName = virNetworkGetBridgeName((virNetworkPtr)VNP)){
+ if((bridgeName = virNetworkGetBridgeName((virNetworkPtr)VNP))){
j_bridgeName = (*env)->NewStringUTF(env, bridgeName);
free(bridgeName);
}
Index: src/org/libvirt/VirConnect.java
===================================================================
RCS file: /data/cvs/libvirt-java/src/org/libvirt/VirConnect.java,v
retrieving revision 1.1
diff -u -p -r1.1 VirConnect.java
--- src/org/libvirt/VirConnect.java 24 Jun 2008 16:32:24 -0000 1.1
+++ src/org/libvirt/VirConnect.java 29 Jun 2008 17:22:36 -0000
@@ -49,16 +49,30 @@ public class VirConnect {
}
/**
+ * Constructs a VirConnect object from the supplied URI,
+ * using the supplied authentication callback
+ *
+ * @param uri The connection URI
+ * @param auth a VirConnectAuth object
+ * @param flags
+ * @throws LibvirtException
+ * @see <a href="http://libvirt.org/uri.html">The URI documentation</a>
+ */
+ public VirConnect(String uri, VirConnectAuth auth, int flags) throws LibvirtException {
+ VCP = _openAuth(uri, auth, flags);
+ }
+
+ /**
* Constructs a read-write VirConnect object from the supplied URI.
*
- * @param uri
+ * @param uri The connection URI
* @throws LibvirtException
* @see <a href="http://libvirt.org/uri.html">The URI documentation</a>
*/
public VirConnect(String uri) throws LibvirtException {
VCP = _open(uri);
}
-
+
public void finalize() throws LibvirtException {
close();
}
@@ -307,6 +321,9 @@ public class VirConnect {
// openReadOnly
private native long _openReadOnly(String uri) throws LibvirtException;
+ // openAuth
+ private native long _openAuth(String uri, VirConnectAuth auth, int flags) throws LibvirtException;
+
// virNetwork stuff
/**
Index: src/org/libvirt/VirDomain.java
===================================================================
RCS file: /data/cvs/libvirt-java/src/org/libvirt/VirDomain.java,v
retrieving revision 1.1
diff -u -p -r1.1 VirDomain.java
--- src/org/libvirt/VirDomain.java 24 Jun 2008 16:32:24 -0000 1.1
+++ src/org/libvirt/VirDomain.java 29 Jun 2008 17:22:36 -0000
@@ -7,9 +7,23 @@ public class VirDomain {
}
static final class MigrateFlags{
+ /**
+ * live migration
+ */
static final int VIR_MIGRATE_LIVE = 1;
}
+ static final class XMLFlags{
+ /**
+ * dump security sensitive information too
+ */
+ static final int VIR_DOMAIN_XML_SECURE = 1;
+ /**
+ * dump inactive domain information
+ */
+ static final int VIR_DOMAIN_XML_INACTIVE = 2;
+ }
+
/**
* the native virDomainPtr.
*/
Index: src/org/libvirt/VirError.java
===================================================================
RCS file: /data/cvs/libvirt-java/src/org/libvirt/VirError.java,v
retrieving revision 1.1
diff -u -p -r1.1 VirError.java
--- src/org/libvirt/VirError.java 24 Jun 2008 16:32:24 -0000 1.1
+++ src/org/libvirt/VirError.java 29 Jun 2008 17:22:37 -0000
@@ -59,7 +59,23 @@ public class VirError {
/**
* Error from OpenVZ driver
*/
- VIR_FROM_OPENVZ
+ VIR_FROM_OPENVZ,
+ /**
+ * Error at Xen XM layer
+ */
+ VIR_FROM_XENXM,
+ /**
+ * Error in the Linux Stats code
+ */
+ VIR_FROM_STATS_LINUX,
+ /**
+ * Error from Linux Container driver
+ */
+ VIR_FROM_LXC,
+ /**
+ * Error from storage driver
+ */
+ VIR_FROM_STORAGE
}
public static enum VirErrorLevel {
@@ -251,7 +267,31 @@ public class VirError {
/**
* invalid MAC adress
*/
- VIR_ERR_INVALID_MAC
+ VIR_ERR_INVALID_MAC,
+ /**
+ * authentication failed
+ */
+ VIR_ERR_AUTH_FAILED,
+ /**
+ * invalid storage pool object
+ */
+ VIR_ERR_INVALID_STORAGE_POOL,
+ /**
+ * invalid storage vol object
+ */
+ VIR_ERR_INVALID_STORAGE_VOL,
+ /**
+ * failed to start storage
+ */
+ VIR_WAR_NO_STORAGE,
+ /**
+ * storage pool not found
+ */
+ VIR_ERR_NO_STORAGE_POOL,
+ /**
+ * storage pool not found
+ */
+ VIR_ERR_NO_STORAGE_VOL
}
VirErrorNumber code;
@@ -328,7 +368,7 @@ public class VirError {
}
/**
- * Does this error has a valid Connection object atteched?
+ * Does this error has a valid Connection object attached?
* @return
*/
public boolean hasConn(){
@@ -416,7 +456,6 @@ public class VirError {
output.append("int1:" + int1 + "\n");
output.append("int2:" + int2 + "\n");
return output.toString();
-
}
}
Index: src/org/libvirt/VirSchedParameter.java
===================================================================
RCS file: /data/cvs/libvirt-java/src/org/libvirt/VirSchedParameter.java,v
retrieving revision 1.1
diff -u -p -r1.1 VirSchedParameter.java
--- src/org/libvirt/VirSchedParameter.java 24 Jun 2008 16:32:24 -0000 1.1
+++ src/org/libvirt/VirSchedParameter.java 29 Jun 2008 17:22:37 -0000
@@ -20,7 +20,7 @@ public abstract class VirSchedParameter
*/
public abstract String getValueAsString();
/**
- * Utility function for displayinf the type
+ * Utility function for displaying the type
*
* @return the Type of the parameter as string
*/
#include <jni.h>
#include <libvirt/libvirt.h>
#include <string.h>
#include "VirConnectAuthCallbackBridge.h"
#include <assert.h>
int VirConnectAuthCallbackBridge(virConnectCredentialPtr cred, unsigned int ncred, void * cbdata){
//cbdata contains the java object that contains tha callback, as well as the JNI environment
JNIEnv *env = ((CallBackStructType*)cbdata)->env;
jobject j_auth = ((CallBackStructType*)cbdata)->auth;
jclass j_auth_cls = (*env)->GetObjectClass(env, j_auth);
jmethodID j_auth_cb_id=(*env)->GetMethodID(env, (*env)->GetObjectClass(env, j_auth), "callback", "([Lorg/libvirt/VirConnectCredential;)I");
jclass j_cred_cls = (*env)->FindClass(env, "org/libvirt/VirConnectCredential");
jmethodID j_cred_constructor = (*env)->GetMethodID(env, j_cred_cls, "<init>", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
jfieldID j_cred_result_id = (*env)->GetFieldID(env, j_cred_cls, "result", "Ljava/lang/String;");
jobjectArray j_credArray = (*env)->NewObjectArray(env, ncred, j_cred_cls, NULL);
//copy the credentials array to the Java object.
int c;
jobject j_cred;
for(c=0; c<ncred; c++){
j_cred=(*env)->NewObject(env,
j_cred_cls,
j_cred_constructor,
cred[c].type,
(*env)->NewStringUTF(env, cred[c].prompt),
(*env)->NewStringUTF(env, cred[c].challenge),
(*env)->NewStringUTF(env, cred[c].defresult));
(*env)->SetObjectArrayElement(env, j_credArray, c, j_cred);
}
//Time to call the actual java callback function
int retval = (*env)->CallNonvirtualIntMethod(env,
j_auth,
j_auth_cls,
j_auth_cb_id,
j_credArray);
if(retval){
//The java callback function has failed, so we fail as well.
return -1;
}
//If we are still here, the java callback returned sucessfully, so copy the results back.
jstring j_cred_result;
const char* result;
for(c=0; c<ncred; c++){
j_cred = (*env)->GetObjectArrayElement(env, j_credArray, c);
j_cred_result = (*env)->GetObjectField(env, j_cred, j_cred_result_id);
//If this assert triggers, then the user-supplied VirConnectAuth.callback function is broken
assert(j_cred_result);
result = (*env)->GetStringUTFChars(env,
j_cred_result,
NULL);
cred[c].result = strdup(result);
cred[c].resultlen = strlen(result);
(*env)->ReleaseStringUTFChars(env, j_cred_result, result);
}
//All done, back to libvirt
return 0;
}
#include <jni.h>
#include <libvirt/libvirt.h>
typedef struct {
JNIEnv *env;
jobject auth;
} CallBackStructType;
int VirConnectAuthCallbackBridge(virConnectCredentialPtr cred, unsigned int ncred, void * cbdata);
package org.libvirt;
/**
* We diverge from the C implementation
* There is no explicit cbdata field, you should just add any extra data to the child class's instance.
*
* @author stoty
*
*/
public abstract class VirConnectAuth {
/**
* List of supported VirConnectCredential.VirConnectCredentialType values
*/
public VirConnectCredential.VirConnectCredentialType credType[];
/**
* The callback function that fills the credentials in
* @param cred the array of credentials passed by libvirt
* @return 0 if the defresult field contains a vailde response, -1 otherwise
*/
public abstract int callback(VirConnectCredential[] cred);
}
package org.libvirt;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* @author stoty
* Implements virConnectAuthPtrDefault functionality from libvirt.c without the external method support
* It's not officially a part of the libvirt API, but provided here for completeness, testing, and as an example
*/
public final class VirConnectAuthDefault extends VirConnectAuth {
{
credType= new VirConnectCredential.VirConnectCredentialType[] {
VirConnectCredential.VirConnectCredentialType.VIR_CRED_AUTHNAME,
VirConnectCredential.VirConnectCredentialType.VIR_CRED_ECHOPROMPT,
VirConnectCredential.VirConnectCredentialType.VIR_CRED_REALM,
VirConnectCredential.VirConnectCredentialType.VIR_CRED_PASSPHRASE,
VirConnectCredential.VirConnectCredentialType.VIR_CRED_NOECHOPROMPT
};
}
@Override
public int callback(VirConnectCredential[] cred) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try{
for(VirConnectCredential c: cred){
String response="";
switch(c.type){
case VIR_CRED_USERNAME:
case VIR_CRED_AUTHNAME:
case VIR_CRED_ECHOPROMPT:
case VIR_CRED_REALM:
System.out.println(c.prompt);
response= in.readLine();
break;
case VIR_CRED_PASSPHRASE:
case VIR_CRED_NOECHOPROMPT:
System.out.println(c.prompt);
System.out.println("WARNING: THE ENTERED PASSWORD WILL NOT BE MASKED!");
response= in.readLine();
break;
}
if(response.equals("") && !c.defresult.equals("")){
c.result=c.defresult;
} else {
c.result=response;
}
if(c.result.equals("")){
return -1;
}
}
} catch (Exception e) {
return -1;
}
return 0;
}
}
package org.libvirt;
/**
* @author stoty
*
*/
public class VirConnectCredential {
public static enum VirConnectCredentialType {
//This is off by one, but we don't care, because we can't convert java Enum to C enum in a sane way anyway
/**
* Identity to act as
*/
VIR_CRED_USERNAME,
/**
* Identify to authorize as
*/
VIR_CRED_AUTHNAME,
/**
* RFC 1766 languages, comma separated
*/
VIR_CRED_LANGUAGE,
/**
* client supplies a nonce
*/
VIR_CRED_CNONCE,
/**
* Passphrase secret
*/
VIR_CRED_PASSPHRASE,
/**
* Challenge response
*/
VIR_CRED_ECHOPROMPT,
/**
* Challenge response
*/
VIR_CRED_NOECHOPROMPT,
/**
* Authentication realm
*/
VIR_CRED_REALM,
/**
* Externally managed credential More may be added - expect the unexpected
*/
VIR_CRED_EXTERNAL;
/**
* Maps the java VirConnectCredentialType Enum to libvirt's integer constant
*
* @return The integer equivalent
*/
private int mapToInt(){
switch(this){
case VIR_CRED_USERNAME: return 1;
case VIR_CRED_AUTHNAME: return 2;
case VIR_CRED_LANGUAGE: return 3;
case VIR_CRED_CNONCE: return 4;
case VIR_CRED_PASSPHRASE: return 5;
case VIR_CRED_ECHOPROMPT: return 6;
case VIR_CRED_NOECHOPROMPT: return 7;
case VIR_CRED_REALM: return 8;
case VIR_CRED_EXTERNAL: return 9;
}
//We may never reach this point
assert(false);
return 0;
}
}
/**
* One of virConnectCredentialType constants
*/
public VirConnectCredentialType type;
/**
* Prompt to show to user
*/
public String prompt;
/**
* Additional challenge to show
*/
public String challenge;
/**
* Optional default result
*/
public String defresult;
/**
* Result to be filled with user response (or defresult)
*/
public String result;
/**
* Convenience constructor to be called from the JNI side
*
* @param type
* @param prompt
* @param challenge
* @param defresult
*/
VirConnectCredential(int type, String prompt, String challenge, String defresult){
switch(type){
case 1: this.type=VirConnectCredentialType.VIR_CRED_USERNAME; break;
case 2: this.type=VirConnectCredentialType.VIR_CRED_AUTHNAME; break;
case 3: this.type=VirConnectCredentialType.VIR_CRED_LANGUAGE; break;
case 4: this.type=VirConnectCredentialType.VIR_CRED_CNONCE; break;
case 5: this.type=VirConnectCredentialType.VIR_CRED_PASSPHRASE; break;
case 6: this.type=VirConnectCredentialType.VIR_CRED_ECHOPROMPT; break;
case 7: this.type=VirConnectCredentialType.VIR_CRED_NOECHOPROMPT; break;
case 8: this.type=VirConnectCredentialType.VIR_CRED_REALM; break;
case 9: this.type=VirConnectCredentialType.VIR_CRED_EXTERNAL; break;
default: assert(false);
}
this.prompt = prompt;
this.challenge = challenge;
this.defresult = defresult;
}
}
2
1
[libvirt] [PATCH] [LXC] Remove unused variable and fix uninitialized variable
by Dan Smith 27 Jun '08
by Dan Smith 27 Jun '08
27 Jun '08
Also remove a stale comment in the area. This makes libvirt compile when
passed --with-lxc and --enable-compiler-warnings=error
diff -r bd08a3f22fb2 -r fa048279476d src/veth.c
--- a/src/veth.c Thu Jun 26 16:09:48 2008 +0000
+++ b/src/veth.c Fri Jun 27 06:48:10 2008 -0700
@@ -192,14 +192,12 @@
*/
int moveInterfaceToNetNs(const char* interface, int pidInNs)
{
- int rc;
- /* offset of the pid field in the following args */
+ int rc = -1;
char *pid = NULL;
const char *argv[] = {
"ip", "link", "set", interface, "netns", NULL, NULL
};
int cmdResult;
- int len;
if (NULL == interface) {
goto error_out;
2
1
New thread.
> Honnestly I'm still lost trying to understand what you wanted to do.
I have implemented a webserver plugin that allows (by mDNS) to access
all 'VMs' on the network.
http://xen.bot.nu/virt/ <- demo
> I didn't understand the point, I just noted you wanted to put things
> in libvirtd, something about event API while to me i don't see the even side
> of the proposal.
Using mDNS, mDNS events can be used on the network to subscribe to
certain VM changes. Reboot/Shutdown/etc.
> Now suggesting to convey this as part of Java *bindings* sounds even more
> confusing, how does that relate at all ?
You proposed (new) bindings for Java. I have written new bindings using
the HTTP protocol. I wonder what should be done to get it adapted into
libvirt, or standardize the format (like any other API).
Stefan
2
4
Hello, Dan Smith
Please check your moveInterfaceToNetNs on veth.c
**rc** and **len** have warning problem.
http://builder.virt-manager.org/logs/modules/libvirt--devel-build-output.log
P.S.
Many Dan stay in this mailing list.
Also My previous patch save this problem for general users
but not for LXC users :-)
Thanks
Atsushi SAKAI
1
0
I am running Fedora 8 with Xen 3.1.2 and libvirt 0.4.3 on two machines
(machine #1 and #2). I am using virDomainMigrate() to migrate a VM
from machine #2 (where it originally resides) to machine #1. I am
unable to migrate the VM back to machine #2 using virDomainMigrate(),
even if I first migrate the VM from #2 to #1 by hand, using "xm
migrate -l <vmname> <ipaddress1>".
When I make the call to virDomainMigrate(domain_to_migrate,
connection_to_machine_2, VIR_MIGRATE_LIVE, NULL, NULL, 0), I get the
following message:
libvir: Xen Daemon error : POST operation failed: xend_post: error
from xen daemon: (xend.err "can't connect: Name or service not known")
I have tried running my program on both machine #2 (connecting to
machine #1 with ssh, and machine #2 with local (NULL) or ssh), and on
a separate 3rd machine (connecting to machine #1 and #2 with ssh), but
I get the same error message in both cases. I've tried connecting
with both virConnectOpen() and virConnectOpenReadOnly().
I don't see any obvious error messages when running libvirtd --
verbose, other than the one above, which shows up on machine #1.
There are no obvious error messages in libvirtd --verbose on machine #2.
I checked /var/log/xen/xend.log and xend-debug.log, but didn't see any
error message there either. My /etc/xen/xend-config.sxp is set with
default loglevel of DEBUG.
Any clues as to why I cannot migrate the VM back to the original
machine with libvirt? I am able to migrate it back from #1 to #2 by
hand using "xm migrate -l <vmname> <ipaddress2>".
Thanks,
Elaine
1
0
Hi,
Most of the changes in the attached patch are trivial #ifdef
corrections for Solaris compilation.
The biggest part of the change gets 'virsh capabilities' running
correctly under Xen on Solaris.
Signed-off-by: Mark Johnson <Mark.Johnson(a)Sun.COM>
--- a/src/xs_internal.c
+++ b/src/xs_internal.c
@@ -35,7 +35,7 @@
#ifdef __linux__
#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"
-#elif define(__sun__)
+#elif defined(__sun)
#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd"
#else
#error "unsupported platform"
--- a/src/xen_internal.c
+++ b/src/xen_internal.c
@@ -75,7 +75,7 @@ typedef struct v1_hypercall_struct
#define XEN_V1_IOCTL_HYPERCALL_CMD \
_IOC(_IOC_NONE, 'P', 0, sizeof(v1_hypercall_t))
typedef v1_hypercall_t hypercall_t;
-#elif define(__sun__)
+#elif defined(__sun)
typedef privcmd_hypercall_t hypercall_t;
#else
#error "unsupported platform"
@@ -340,8 +340,10 @@ lock_pages(void *addr, size_t len)
{
#ifdef __linux__
return (mlock(addr, len));
-#elif define(__sun)
+#elif defined(__sun)
return (0);
+#else
+#error "unsupported platform"
#endif
}
@@ -350,8 +352,10 @@ unlock_pages(void *addr, size_t len)
{
#ifdef __linux__
return (munlock(addr, len));
-#elif define(__sun)
+#elif defined(__sun)
return (0);
+#else
+#error "unsupported platform"
#endif
}
@@ -666,7 +670,7 @@ typedef struct xen_op_v2_dom xen_op_v2_d
#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"
#define HYPERVISOR_CAPABILITIES "/sys/hypervisor/properties/capabilities"
#define CPUINFO "/proc/cpuinfo"
-#elif define(__sun__)
+#elif defined(__sun)
#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd"
#define HYPERVISOR_CAPABILITIES ""
#define CPUINFO "/dev/cpu/self/cpuid"
@@ -1948,7 +1952,7 @@ xenHypervisorInit(void)
goto detect_v2;
}
-#ifndef __sun__
+#ifndef __sun
/*
* check if the old hypercall are actually working
*/
@@ -2265,6 +2269,92 @@ xenHypervisorBuildCapabilities(virConnec
return NULL;
}
+#ifdef __linux__
+void
+loadCapabilities(FILE *cpuinfo, FILE *capabilities, char *hvm_type,
+ int *host_pae, char *line, int LINE_SIZE)
+{
+ regmatch_t subs[4];
+
+ /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
+ * It's not clear if this will work on IA64, let alone other
+ * architectures and non-Linux. (XXX)
+ */
+ if (cpuinfo) {
+ while (fgets (line, LINE_SIZE, cpuinfo)) {
+ if (regexec (&flags_hvm_rec, line,
+ sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
+ && subs[0].rm_so != -1) {
+ strncpy (hvm_type,
+ &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1);
+ hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0';
+ } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0)
+ *host_pae = 1;
+ }
+ }
+
+ /* Expecting one line in this file - ignore any more. */
+ (void) fgets(line, LINE_SIZE, capabilities);
+}
+
+#else
+void
+loadCapabilities(FILE *cpuinfo, FILE *capabilities, char *hvm_type,
+ int *host_pae, char *line, int LINE_SIZE)
+{
+ struct {
+ uint32_t r_eax, r_ebx, r_ecx, r_edx;
+ } _r, *rp = &_r;
+ int d, cmd;
+ char *s;
+ hypercall_t hc;
+
+
+ if ((d = open(CPUINFO, O_RDONLY)) == -1) {
+ goto cpuinfo_open_fail;
+ }
+
+ if (pread(d, rp, sizeof (*rp), 0) != sizeof (*rp)) {
+ goto cpuinfo_pread_fail;
+ }
+
+ s = (char *)&rp->r_ebx;
+ if (strncmp(s, "Auth" "cAMD" "enti", 12) == 0) {
+ if (pread(d, rp, sizeof (*rp), 0x80000001) == sizeof (*rp)) {
+ /* Read secure virtual machine bit (bit 2 of ECX feature ID) */
+ if ((rp->r_ecx >> 2) & 1) {
+ strcpy(hvm_type, "svm");
+ }
+ if ((rp->r_edx >> 6) & 1) {
+ *host_pae = 1;
+ }
+ }
+ } else if (strncmp(s, "Genu" "ntel" "ineI", 12) == 0) {
+ if (pread(d, rp, sizeof (*rp), 0x00000001) == sizeof (*rp)) {
+ /* Read VMXE feature bit (bit 5 of ECX feature ID) */
+ if ((rp->r_ecx >> 5) & 1) {
+ strcpy(hvm_type, "vmx");
+ }
+ if ((rp->r_edx >> 6) & 1) {
+ *host_pae = 1;
+ }
+ }
+ }
+cpuinfo_pread_fail:
+ (void) close(d);
+cpuinfo_open_fail:
+
+ d = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
+ hc.op = __HYPERVISOR_xen_version;
+ hc.arg[0] = (unsigned long) XENVER_capabilities;
+ hc.arg[1] = (unsigned long) line;
+ cmd = IOCTL_PRIVCMD_HYPERCALL;
+ (void) ioctl(d, cmd, (unsigned long) &hc);
+ close(d);
+}
+
+#endif
+
/**
* xenHypervisorGetCapabilities:
* @conn: pointer to the connection block
@@ -2278,7 +2368,8 @@ xenHypervisorMakeCapabilitiesXML(virConn
const char *hostmachine,
FILE *cpuinfo, FILE *capabilities)
{
- char line[1024], *str, *token;
+ const int LINE_SIZE = 1024;
+ char line[LINE_SIZE], *str, *token;
regmatch_t subs[4];
char *saveptr = NULL;
int i;
@@ -2295,24 +2386,12 @@ xenHypervisorMakeCapabilitiesXML(virConn
memset(guest_archs, 0, sizeof(guest_archs));
- /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
- * It's not clear if this will work on IA64, let alone other
- * architectures and non-Linux. (XXX)
- */
- if (cpuinfo) {
- while (fgets (line, sizeof line, cpuinfo)) {
- if (regexec (&flags_hvm_rec, line, sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
- && subs[0].rm_so != -1) {
- strncpy (hvm_type,
- &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1);
- hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0';
- } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0)
- host_pae = 1;
- }
- }
+ memset(line, 0, sizeof(line));
+ loadCapabilities(cpuinfo, capabilities, hvm_type, &host_pae, line,
+ LINE_SIZE);
- /* Most of the useful info is in /sys/hypervisor/properties/capabilities
- * which is documented in the code in xen-unstable.hg/xen/arch/.../setup.c.
+ /* The capabilities line is documented in the code in
+ * xen-unstable.hg/xen/arch/.../setup.c.
*
* It is a space-separated list of supported guest architectures.
*
@@ -2335,80 +2414,77 @@ xenHypervisorMakeCapabilitiesXML(virConn
* +--------------- "xen" or "hvm" for para or full virt respectively
*/
- /* Expecting one line in this file - ignore any more. */
- if ((capabilities) && (fgets (line, sizeof line, capabilities))) {
- /* Split the line into tokens. strtok_r is OK here because we "own"
- * this buffer. Parse out the features from each token.
- */
- for (str = line, nr_guest_archs = 0;
- nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0]
- && (token = strtok_r (str, " ", &saveptr)) != NULL;
- str = NULL) {
-
- if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0],
- subs, 0) == 0) {
- int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
- const char *model;
- int bits, pae = 0, nonpae = 0, ia64_be = 0;
-
- if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
- model = "i686";
- bits = 32;
- if (subs[3].rm_so != -1 &&
- STRPREFIX(&token[subs[3].rm_so], "p"))
- pae = 1;
- else
- nonpae = 1;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
- model = "x86_64";
- bits = 64;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
- model = "ia64";
- bits = 64;
- if (subs[3].rm_so != -1 &&
- STRPREFIX(&token[subs[3].rm_so], "be"))
- ia64_be = 1;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
- model = "ppc64";
- bits = 64;
- } else {
- /* XXX surely no other Xen archs exist */
- continue;
- }
+ /* Split the line into tokens. strtok_r is OK here because we "own"
+ * this buffer. Parse out the features from each token.
+ */
+ for (str = line, nr_guest_archs = 0;
+ nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0]
+ && (token = strtok_r (str, " ", &saveptr)) != NULL;
+ str = NULL) {
+
+ if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0],
+ subs, 0) == 0) {
+ int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
+ const char *model;
+ int bits, pae = 0, nonpae = 0, ia64_be = 0;
+
+ if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
+ model = "i686";
+ bits = 32;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "p"))
+ pae = 1;
+ else
+ nonpae = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
+ model = "x86_64";
+ bits = 64;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
+ model = "ia64";
+ bits = 64;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "be"))
+ ia64_be = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
+ model = "ppc64";
+ bits = 64;
+ } else {
+ /* XXX surely no other Xen archs exist */
+ continue;
+ }
- /* Search for existing matching (model,hvm) tuple */
- for (i = 0 ; i < nr_guest_archs ; i++) {
- if (STREQ(guest_archs[i].model, model) &&
- guest_archs[i].hvm == hvm) {
- break;
- }
+ /* Search for existing matching (model,hvm) tuple */
+ for (i = 0 ; i < nr_guest_archs ; i++) {
+ if (STREQ(guest_archs[i].model, model) &&
+ guest_archs[i].hvm == hvm) {
+ break;
}
-
- /* Too many arch flavours - highly unlikely ! */
- if (i >= sizeof(guest_archs)/sizeof(guest_archs[0]))
- continue;
- /* Didn't find a match, so create a new one */
- if (i == nr_guest_archs)
- nr_guest_archs++;
-
- guest_archs[i].model = model;
- guest_archs[i].bits = bits;
- guest_archs[i].hvm = hvm;
-
- /* Careful not to overwrite a previous positive
- setting with a negative one here - some archs
- can do both pae & non-pae, but Xen reports
- separately capabilities so we're merging archs */
- if (pae)
- guest_archs[i].pae = pae;
- if (nonpae)
- guest_archs[i].nonpae = nonpae;
- if (ia64_be)
- guest_archs[i].ia64_be = ia64_be;
}
+
+ /* Too many arch flavours - highly unlikely ! */
+ if (i >= sizeof(guest_archs)/sizeof(guest_archs[0]))
+ continue;
+ /* Didn't find a match, so create a new one */
+ if (i == nr_guest_archs)
+ nr_guest_archs++;
+
+ guest_archs[i].model = model;
+ guest_archs[i].bits = bits;
+ guest_archs[i].hvm = hvm;
+
+ /* Careful not to overwrite a previous positive
+ setting with a negative one here - some archs
+ can do both pae & non-pae, but Xen reports
+ separately capabilities so we're merging archs */
+ if (pae)
+ guest_archs[i].pae = pae;
+ if (nonpae)
+ guest_archs[i].nonpae = nonpae;
+ if (ia64_be)
+ guest_archs[i].ia64_be = ia64_be;
}
}
@@ -2447,29 +2523,33 @@ xenHypervisorGetCapabilities (virConnect
/* Really, this never fails - look at the man-page. */
uname (&utsname);
- cpuinfo = fopen ("/proc/cpuinfo", "r");
+#ifdef __linux__
+ cpuinfo = fopen (CPUINFO, "r");
if (cpuinfo == NULL) {
if (errno != ENOENT) {
- virXenPerror (conn, "/proc/cpuinfo");
+ virXenPerror (conn, CPUINFO);
return NULL;
}
}
- capabilities = fopen ("/sys/hypervisor/properties/capabilities", "r");
+ capabilities = fopen (HYPERVISOR_CAPABILITIES, "r");
if (capabilities == NULL) {
if (errno != ENOENT) {
fclose(cpuinfo);
- virXenPerror (conn, "/sys/hypervisor/properties/capabilities");
+ virXenPerror (conn, HYPERVISOR_CAPABILITIES);
return NULL;
}
}
+#endif
xml = xenHypervisorMakeCapabilitiesXML(conn, utsname.machine, cpuinfo, capabilities);
+#ifdef __linux__
if (cpuinfo)
fclose(cpuinfo);
if (capabilities)
fclose(capabilities);
+#endif
return xml;
}
2
1
At the popular request of pretty much everyone in Sun who uses virsh...
Change virsh list to list all domains, and add an "--active" flag to
list only the active domains.
Signed-off-by: Ryan Scott <ryan.scott(a)sun.com>
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -551,6 +551,7 @@ static vshCmdInfo info_list[] = {
static vshCmdOptDef opts_list[] = {
{"inactive", VSH_OT_BOOL, 0, gettext_noop("list inactive domains")},
+ {"active", VSH_OT_BOOL, 0, gettext_noop("list only active domains")},
{"all", VSH_OT_BOOL, 0, gettext_noop("list inactive & active domains")},
{NULL, 0, 0, NULL}
};
@@ -559,13 +560,17 @@ static vshCmdOptDef opts_list[] = {
static int
cmdList(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
- int inactive = vshCommandOptBool(cmd, "inactive");
+ int inactiveOpt = vshCommandOptBool(cmd, "inactive");
+ int activeOpt = vshCommandOptBool(cmd, "active");
int all = vshCommandOptBool(cmd, "all");
- int active = !inactive || all ? 1 : 0;
+ int active, inactive;
int *ids = NULL, maxid = 0, i;
char **names = NULL;
int maxname = 0;
- inactive |= all;
+
+ /* If no options are specified, default to both active and inactive */
+ active = activeOpt || all || !inactiveOpt;
+ inactive = inactiveOpt || all || !activeOpt;
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
4
3
I think I have addressed all of the comments. Changes detailed per patch.
I converted to using a dynamic detection routine for determining NETNS
support, which I think is much better. That is pulled out into a separate
patch for easier distinction.
Thanks!
3
21
[libvirt] PATCH: Generic internal API for domain XML parser/formatter
by Daniel P. Berrange 26 Jun '08
by Daniel P. Berrange 26 Jun '08
26 Jun '08
We currently have five drivers which handle the domain XML containing
duplicated parsers and formatters for the XML with varying degrees of
buginess, and often very similar structs. This patch introduces a new
general purpose internal API for parsing and formatting network XML,
and representing it as a series of structs.
This code is derived from the current equivalent code in the QEMU driver
for domains, but with alot of extra config parsing added for stuff needed
by the Xen drivers. I have not yet added the extra bits needed by the
container based drivers, LXC and OpenVZ, but don't anticipate any problems
in this regard.
Again the naming conventions I'm adopting in this patch follow those in
the storage and network drivers:
- virDomainPtr - the public opaque object in libvirt.h
- virDomainObjPtr - the primary internal object for domain state
- virDomainDefPtr - the configuration data for a domain
A virDomainObjPtr contains a reference to one or two virDomainDefPtr
objects - the current live config, and potentially a secondary inactive
config which will become live at the next restart.
The structs are defined in domain_conf.h, along with a bunch of APIs for
dealing with them. These APIs are the same as similarly named ones from
the current qemu driver, but I'll go over them again for a reminder:
virDomainObjPtr virDomainFindByUUID(const virDomainObjPtr doms,
const unsigned char *uuid);
virDomainObjPtr virDomainFindByName(const virDomainObjPtr doms,
const char *name);
virDomainObjPtr virDomainFindByID(const virDomainObjPtr doms,
const char *id);
Allow lookup of a virDomainObjPtr object based on its name, ID or UUID,
as typically obtained from the public virDomainPtr object.
The 'doms' parameter to both of thse is a linked list of domains which
are currently known to the driver using this API. Not all drivers will
use these APIs - the Xen driver will just query XenD - these are only
for drivers which maintain state internally with the libvirt daemon.
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
void virDomainInputDefFree(virDomainInputDefPtr def);
void virDomainDiskDefFree(virDomainDiskDefPtr def);
void virDomainNetDefFree(virDomainNetDefPtr def);
void virDomainChrDefFree(virDomainChrDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
void virDomainDefFree(virDomainDefPtr def);
void virDomainObjFree(virDomainObjPtr net);
Convenience APIs to totally free the memory associated with these
objects.
virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
virDomainObjPtr *doms,
const virDomainDefPtr def);
Given a virDomainDefPtr object, it'll search for a pre-existing
virDomainObjPtr object with matching config. If one is found, its
config will be updated, otherwise a new object will be allocated.
void virDomainRemoveInactive(virDomainObjPtr *doms,
const virDomainObjPtr dom);
Convenience for removing and free'ing a virDomainObjPtr object in
the current list of active domains.
virDomainDefPtr virDomainDefParse(virConnectPtr conn,
virCapsPtr caps,
const char *xmlStr,
const char *displayName);
Given an XML document describing a network, parses the doc and generates
a virDomainDefPtr to represent it in memory. This is a little more
advanced than the network parser because the various hypervisor drivers
have slightly varying capabilities. So we pass a virCapsPtr object in
so the parser can validate against the actual driver's capabilities.
I'd like to extend the capabilities format to cover things like the
boot parameters supported - eg PXE vs kernel+initrd vs bootloader vs
BIOS, so we can further validate at time of parsing, instead of time
of use.
char *virDomainDefFormat(virConnectPtr conn,
const virDomainDefPtr def,
int secure);
Given a virDomainDefPtr object, generate a XML document describing the
domain. The secure flag controls whether passwords are included in the
XML output.
int virDomainCpuSetParse(virConnectPtr conn,
const char **str,
char sep,
char *cpuset,
int maxcpu);
char *virDomainCpuSetFormat(virConnectPtr conn,
char *cpuset,
int maxcpu);
These are just the APIs for dealing with CPU ranges moved from the xml.c
file so they are in the expected place. A future patch will remove them
from xml.c when the Xen driver is ported to this API.
VIR_ENUM_DECL(virDomainVirt)
VIR_ENUM_DECL(virDomainBoot)
VIR_ENUM_DECL(virDomainFeature)
VIR_ENUM_DECL(virDomainLifecycle)
VIR_ENUM_DECL(virDomainDisk)
VIR_ENUM_DECL(virDomainDiskDevice)
VIR_ENUM_DECL(virDomainDiskBus)
VIR_ENUM_DECL(virDomainNet)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainSoundModel)
VIR_ENUM_DECL(virDomainInput)
VIR_ENUM_DECL(virDomainInputBus)
VIR_ENUM_DECL(virDomainGraphics)
This provides prototypes for all the enumerations useful to drivers using
this API and struct definitions.
As a mentioned earlier, the impl of these APIs is just copied from the QEMU
driver, but instead of using pre-declared char[PATH_MAX] fields, we allocate
memory for strings as required. This dramatically reduces the memory needs
of the QEMU driver (when ported to this API). It also switches to use the
xml.c convenience routines instead of the regular libxml2 APIs, and in doing
so I added a couple more convenience routines.
There is no test suite explicitly against these parsers because when the
QEMU and Xen drivers are ported to this API their existing test suites
exercise nearly all the code.
Regards,
Daniel.
diff -r f47fdc49c62f src/Makefile.am
--- a/src/Makefile.am Sun Jun 22 17:58:48 2008 -0400
+++ b/src/Makefile.am Sun Jun 22 18:31:20 2008 -0400
@@ -39,6 +39,7 @@
test.c test.h \
buf.c buf.h \
qparams.c qparams.h \
+ domain_conf.c domain_conf.h \
capabilities.c capabilities.h \
xml.c xml.h \
event.c event.h \
diff -r f47fdc49c62f src/domain_conf.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/domain_conf.c Sun Jun 22 18:31:20 2008 -0400
@@ -0,0 +1,2621 @@
+/*
+ * domain_conf.c: domain XML processing
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * 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.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include "internal.h"
+
+#include "domain_conf.h"
+#include "memory.h"
+#include "verify.h"
+#include "xml.h"
+#include "uuid.h"
+#include "util.h"
+#include "buf.h"
+#include "c-ctype.h"
+
+VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
+ "qemu",
+ "kqemu",
+ "kvm",
+ "xen",
+ "lxc",
+ "uml",
+ "openvz",
+ "vserver",
+ "ldom",
+ "test",
+ "vmware",
+ "hyperv")
+
+VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST,
+ "fd",
+ "cdrom",
+ "hd",
+ "network")
+
+VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST,
+ "acpi",
+ "apic",
+ "pae")
+
+VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
+ "destroy",
+ "restart",
+ "rename-restart",
+ "preserve")
+
+VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
+ "block",
+ "file")
+
+VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
+ "disk",
+ "cdrom",
+ "floppy")
+
+VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
+ "ide",
+ "fdc",
+ "scsi",
+ "virtio",
+ "xen")
+
+VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
+ "user",
+ "ethernet",
+ "server",
+ "client",
+ "mcast",
+ "network",
+ "bridge")
+
+VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
+ "null",
+ "vc",
+ "pty",
+ "dev",
+ "file",
+ "pipe",
+ "stdio",
+ "udp",
+ "tcp",
+ "unix")
+
+VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
+ "sb16",
+ "es1370",
+ "pcspk");
+
+VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
+ "mouse",
+ "tablet")
+
+VIR_ENUM_IMPL(virDomainInputBus, VIR_DOMAIN_INPUT_BUS_LAST,
+ "ps2",
+ "usb",
+ "xen")
+
+VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
+ "sdl",
+ "vnc")
+
+
+static void virDomainReportError(virConnectPtr conn,
+ int code, const char *fmt, ...)
+{
+ va_list args;
+ char errorMessage[1024];
+ const char *virerr;
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args);
+ va_end(args);
+ } else {
+ errorMessage[0] = '\0';
+ }
+
+ virerr = __virErrorMsg(code, (errorMessage[0] ? errorMessage : NULL));
+ __virRaiseError(conn, NULL, NULL, VIR_FROM_QEMU, code, VIR_ERR_ERROR,
+ virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
+}
+
+
+virDomainObjPtr virDomainFindByID(const virDomainObjPtr doms,
+ int id)
+{
+ virDomainObjPtr dom = doms;
+ while (dom) {
+ if (virDomainIsActive(dom) && dom->def->id == id)
+ return dom;
+ dom = dom->next;
+ }
+
+ return NULL;
+}
+
+
+virDomainObjPtr virDomainFindByUUID(const virDomainObjPtr doms,
+ const unsigned char *uuid)
+{
+ virDomainObjPtr dom = doms;
+
+ while (dom) {
+ if (!memcmp(dom->def->uuid, uuid, VIR_UUID_BUFLEN))
+ return dom;
+ dom = dom->next;
+ }
+
+ return NULL;
+}
+
+virDomainObjPtr virDomainFindByName(const virDomainObjPtr doms,
+ const char *name)
+{
+ virDomainObjPtr dom = doms;
+
+ while (dom) {
+ if (STREQ(dom->def->name, name))
+ return dom;
+ dom = dom->next;
+ }
+
+ return NULL;
+}
+
+void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
+{
+ if (!def)
+ return;
+
+ switch (def->type) {
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ VIR_FREE(def->data.vnc.listenAddr);
+ VIR_FREE(def->data.vnc.keymap);
+ VIR_FREE(def->data.vnc.passwd);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ VIR_FREE(def->data.sdl.display);
+ VIR_FREE(def->data.sdl.xauth);
+ break;
+ }
+
+ VIR_FREE(def);
+}
+
+void virDomainInputDefFree(virDomainInputDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainInputDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainDiskDefFree(virDomainDiskDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->src);
+ VIR_FREE(def->dst);
+ VIR_FREE(def->driverName);
+ VIR_FREE(def->driverType);
+
+ virDomainDiskDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainNetDefFree(virDomainNetDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->model);
+
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ VIR_FREE(def->dst.ethernet.ifname);
+ VIR_FREE(def->dst.ethernet.script);
+ VIR_FREE(def->dst.ethernet.ipaddr);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ VIR_FREE(def->dst.socket.address);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ VIR_FREE(def->dst.network.name);
+ VIR_FREE(def->dst.network.ifname);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ VIR_FREE(def->dst.bridge.brname);
+ VIR_FREE(def->dst.bridge.ifname);
+ break;
+ }
+
+ virDomainNetDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainChrDefFree(virDomainChrDefPtr def)
+{
+ if (!def)
+ return;
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ VIR_FREE(def->data.file.path);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ VIR_FREE(def->data.udp.bindHost);
+ VIR_FREE(def->data.udp.bindService);
+ VIR_FREE(def->data.udp.connectHost);
+ VIR_FREE(def->data.udp.connectService);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ VIR_FREE(def->data.tcp.host);
+ VIR_FREE(def->data.tcp.service);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ VIR_FREE(def->data.nix.path);
+ break;
+ }
+
+ virDomainChrDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainSoundDefFree(virDomainSoundDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainSoundDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainDefFree(virDomainDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainGraphicsDefFree(def->graphics);
+ virDomainInputDefFree(def->inputs);
+ virDomainDiskDefFree(def->disks);
+ virDomainNetDefFree(def->nets);
+ virDomainChrDefFree(def->serials);
+ virDomainChrDefFree(def->parallels);
+ virDomainChrDefFree(def->console);
+ virDomainSoundDefFree(def->sounds);
+
+
+ VIR_FREE(def->os.type);
+ VIR_FREE(def->os.arch);
+ VIR_FREE(def->os.machine);
+ VIR_FREE(def->os.kernel);
+ VIR_FREE(def->os.initrd);
+ VIR_FREE(def->os.cmdline);
+ VIR_FREE(def->os.root);
+ VIR_FREE(def->os.loader);
+ VIR_FREE(def->os.bootloader);
+ VIR_FREE(def->os.bootloaderArgs);
+
+ VIR_FREE(def->name);
+ VIR_FREE(def->cpumask);
+ VIR_FREE(def->emulator);
+
+ VIR_FREE(def);
+}
+
+void virDomainObjFree(virDomainObjPtr dom)
+{
+ if (!dom)
+ return;
+
+ virDomainDefFree(dom->def);
+ virDomainDefFree(dom->newDef);
+
+ VIR_FREE(dom->vcpupids);
+ VIR_FREE(dom->configFile);
+ VIR_FREE(dom->autostartLink);
+
+ VIR_FREE(dom);
+}
+
+virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
+ virDomainObjPtr *doms,
+ const virDomainDefPtr def)
+{
+ virDomainObjPtr domain;
+
+ if ((domain = virDomainFindByName(*doms, def->name))) {
+ if (!virDomainIsActive(domain)) {
+ virDomainDefFree(domain->def);
+ domain->def = def;
+ } else {
+ if (domain->newDef)
+ virDomainDefFree(domain->newDef);
+ domain->newDef = def;
+ }
+
+ return domain;
+ }
+
+ if (VIR_ALLOC(domain) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ domain->def = def;
+ domain->next = *doms;
+
+ *doms = domain;
+
+ return domain;
+}
+
+void virDomainRemoveInactive(virDomainObjPtr *doms,
+ virDomainObjPtr dom)
+{
+ virDomainObjPtr prev = NULL;
+ virDomainObjPtr curr = *doms;
+
+ while (curr &&
+ curr != dom) {
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (curr) {
+ if (prev)
+ prev->next = curr->next;
+ else
+ *doms = curr->next;
+ }
+
+ virDomainObjFree(dom);
+}
+
+static int virDomainDiskCompare(virDomainDiskDefPtr a,
+ virDomainDiskDefPtr b) {
+ if (a->bus == b->bus)
+ return virDiskNameToIndex(a->dst) - virDiskNameToIndex(b->dst);
+ else
+ return a->bus - b->bus;
+}
+
+
+/* Parse the XML definition for a disk
+ * @param node XML nodeset to parse for disk definition
+ */
+static virDomainDiskDefPtr
+virDomainDiskDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ virDomainDiskDefPtr def;
+ xmlNodePtr cur;
+ char *type = NULL;
+ char *device = NULL;
+ char *driverName = NULL;
+ char *driverType = NULL;
+ char *source = NULL;
+ char *target = NULL;
+ char *bus = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ if (type) {
+ if ((def->type = virDomainDiskTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk type '%s'"), type);
+ goto error;
+ }
+ } else {
+ def->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((source == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+
+ if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
+ source = virXMLPropString(cur, "file");
+ else
+ source = virXMLPropString(cur, "dev");
+ } else if ((target == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "target"))) {
+ target = virXMLPropString(cur, "dev");
+ bus = virXMLPropString(cur, "bus");
+ } else if ((driverName == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "driver"))) {
+ driverName = virXMLPropString(cur, "name");
+ driverType = virXMLPropString(cur, "type");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
+ def->readonly = 1;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
+ def->shared = 1;
+ }
+ }
+ cur = cur->next;
+ }
+
+ device = virXMLPropString(node, "device");
+ if (device) {
+ if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk device '%s'"), device);
+ goto error;
+ }
+ } else {
+ def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+ }
+
+ /* Only CDROM and Floppy devices are allowed missing source path
+ * to indicate no media present */
+ if (source == NULL &&
+ def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
+ def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+ virDomainReportError(conn, VIR_ERR_NO_SOURCE,
+ target ? "%s" : NULL, target);
+ goto error;
+ }
+
+ if (target == NULL) {
+ virDomainReportError(conn, VIR_ERR_NO_TARGET,
+ source ? "%s" : NULL, source);
+ goto error;
+ }
+
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
+ !STRPREFIX(target, "fd")) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid floppy device name: %s"), target);
+ goto error;
+ }
+
+ /* Force CDROM to be listed as read only */
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+ def->readonly = 1;
+
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+ !STRPREFIX((const char *)target, "hd") &&
+ !STRPREFIX((const char *)target, "sd") &&
+ !STRPREFIX((const char *)target, "vd") &&
+ !STRPREFIX((const char *)target, "xvd")) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid harddisk device name: %s"), target);
+ goto error;
+ }
+
+ if (bus) {
+ if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk bus type '%s'"), bus);
+ goto error;
+ }
+ } else {
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+ def->bus = VIR_DOMAIN_DISK_BUS_FDC;
+ } else {
+ if (STRPREFIX(target, "hd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ else if (STRPREFIX(target, "sd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
+ else if (STRPREFIX(target, "vd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
+ else if (STRPREFIX(target, "xvd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_XEN;
+ else
+ def->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ }
+ }
+
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
+ def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid bus type '%s' for floppy disk"), bus);
+ goto error;
+ }
+ if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
+ def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid bus type '%s' for disk"), bus);
+ goto error;
+ }
+
+ def->src = source;
+ source = NULL;
+ def->dst = target;
+ target = NULL;
+ def->driverName = driverName;
+ driverName = NULL;
+ def->driverType = driverType;
+ driverType = NULL;
+
+cleanup:
+ VIR_FREE(bus);
+ VIR_FREE(type);
+ VIR_FREE(target);
+ VIR_FREE(source);
+ VIR_FREE(device);
+ VIR_FREE(driverType);
+ VIR_FREE(driverName);
+
+ return def;
+
+ error:
+ virDomainDiskDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+static void virDomainNetRandomMAC(virDomainNetDefPtr def) {
+ /* XXX there different vendor prefixes per hypervisor */
+ def->mac[0] = 0x52;
+ def->mac[1] = 0x54;
+ def->mac[2] = 0x00;
+ def->mac[3] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+ def->mac[4] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+ def->mac[5] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+}
+
+
+/* Parse the XML definition for a network interface
+ * @param node XML nodeset to parse for net definition
+ * @return 0 on success, -1 on failure
+ */
+static virDomainNetDefPtr
+virDomainNetDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ virDomainNetDefPtr def;
+ xmlNodePtr cur;
+ char *macaddr = NULL;
+ char *type = NULL;
+ char *network = NULL;
+ char *bridge = NULL;
+ char *ifname = NULL;
+ char *script = NULL;
+ char *address = NULL;
+ char *port = NULL;
+ char *model = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ if (type != NULL) {
+ if ((def->type = virDomainNetTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown interface type '%s'"), type);
+ goto error;
+ }
+ } else {
+ def->type = VIR_DOMAIN_NET_TYPE_USER;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((macaddr == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "mac"))) {
+ macaddr = virXMLPropString(cur, "address");
+ } else if ((network == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ network = virXMLPropString(cur, "network");
+ } else if ((network == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ bridge = virXMLPropString(cur, "bridge");
+ } else if ((network == NULL) &&
+ ((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_MCAST)) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ address = virXMLPropString(cur, "address");
+ port = virXMLPropString(cur, "port");
+ } else if ((address == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET) &&
+ (xmlStrEqual(cur->name, BAD_CAST "ip"))) {
+ address = virXMLPropString(cur, "address");
+ } else if ((ifname == NULL) &&
+ ((def->type == VIR_DOMAIN_NET_TYPE_NETWORK) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE)) &&
+ xmlStrEqual(cur->name, BAD_CAST "target")) {
+ ifname = virXMLPropString(cur, "dev");
+ if (STRPREFIX((const char*)ifname, "vnet")) {
+ /* An auto-generated target name, blank it out */
+ VIR_FREE(ifname);
+ ifname = NULL;
+ }
+ } else if ((script == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET) &&
+ xmlStrEqual(cur->name, BAD_CAST "script")) {
+ script = virXMLPropString(cur, "path");
+ } else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
+ model = virXMLPropString(cur, "type");
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (macaddr) {
+ unsigned int mac[6];
+ sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned int*)&mac[0],
+ (unsigned int*)&mac[1],
+ (unsigned int*)&mac[2],
+ (unsigned int*)&mac[3],
+ (unsigned int*)&mac[4],
+ (unsigned int*)&mac[5]);
+ def->mac[0] = mac[0];
+ def->mac[1] = mac[1];
+ def->mac[2] = mac[2];
+ def->mac[3] = mac[3];
+ def->mac[4] = mac[4];
+ def->mac[5] = mac[5];
+ } else {
+ virDomainNetRandomMAC(def);
+ }
+
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ if (network == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'network' attribute specified with <interface type='network'/>"));
+ goto error;
+ }
+ def->dst.network.name = network;
+ network = NULL;
+
+ if (ifname != NULL) {
+ def->dst.network.ifname = ifname;
+ ifname = NULL;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+
+ if (script != NULL) {
+ def->dst.ethernet.script = script;
+ script = NULL;
+ }
+ if (ifname != NULL) {
+ def->dst.ethernet.ifname = ifname;
+ ifname = NULL;
+ }
+ if (address != NULL) {
+ def->dst.ethernet.ipaddr = address;
+ address = NULL;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ if (bridge == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'dev' attribute specified with <interface type='bridge'/>"));
+ goto error;
+ }
+ def->dst.bridge.brname = bridge;
+ bridge = NULL;
+
+ if (ifname != NULL) {
+ def->dst.bridge.ifname = ifname;
+ ifname = NULL;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ if (port == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'port' attribute specified with socket interface"));
+ goto error;
+ }
+ if (virStrToLong_i(port, NULL, 10, &def->dst.socket.port) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Cannot parse <source> 'port' attribute with socket interface"));
+ goto error;
+ }
+
+ if (address == NULL) {
+ if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
+ def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'address' attribute specified with socket interface"));
+ goto error;
+ }
+ } else {
+ def->dst.socket.address = address;
+ address = NULL;
+ }
+ }
+
+ /* NIC model (see -net nic,model=?). We only check that it looks
+ * reasonable, not that it is a supported NIC type. FWIW kvm
+ * supports these types as of April 2008:
+ * i82551 i82557b i82559er ne2k_pci pcnet rtl8139 e1000 virtio
+ */
+ if (model != NULL) {
+ int i;
+ for (i = 0 ; i < strlen(model) ; i++) {
+ int char_ok = c_isalnum(model[i]) || model[i] == '_';
+ if (!char_ok) {
+ virDomainReportError (conn, VIR_ERR_INVALID_ARG, "%s",
+ _("Model name contains invalid characters"));
+ goto error;
+ }
+ }
+ def->model = model;
+ model = NULL;
+ }
+
+cleanup:
+ VIR_FREE(macaddr);
+ VIR_FREE(network);
+ VIR_FREE(address);
+ VIR_FREE(port);
+ VIR_FREE(ifname);
+ VIR_FREE(script);
+ VIR_FREE(bridge);
+ VIR_FREE(model);
+ VIR_FREE(type);
+
+ return def;
+
+error:
+ virDomainNetDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+/* Parse the XML definition for a character device
+ * @param node XML nodeset to parse for net definition
+ *
+ * The XML we're dealing with looks like
+ *
+ * <serial type="pty">
+ * <source path="/dev/pts/3"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="dev">
+ * <source path="/dev/ttyS0"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="tcp">
+ * <source mode="connect" host="0.0.0.0" service="2445"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="tcp">
+ * <source mode="bind" host="0.0.0.0" service="2445"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="udp">
+ * <source mode="bind" host="0.0.0.0" service="2445"/>
+ * <source mode="connect" host="0.0.0.0" service="2445"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="unix">
+ * <source mode="bind" path="/tmp/foo"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ */
+static virDomainChrDefPtr
+virDomainChrDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ xmlNodePtr cur;
+ char *type = NULL;
+ char *bindHost = NULL;
+ char *bindService = NULL;
+ char *connectHost = NULL;
+ char *connectService = NULL;
+ char *path = NULL;
+ char *mode = NULL;
+ char *protocol = NULL;
+ virDomainChrDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ def->type = VIR_DOMAIN_CHR_TYPE_PTY;
+ type = virXMLPropString(node, "type");
+ if (type != NULL) {
+ if (STREQ(type, "null"))
+ def->type = VIR_DOMAIN_CHR_TYPE_NULL;
+ else if (STREQ(type, "vc"))
+ def->type = VIR_DOMAIN_CHR_TYPE_VC;
+ else if (STREQ(type, "pty"))
+ def->type = VIR_DOMAIN_CHR_TYPE_PTY;
+ else if (STREQ(type, "dev"))
+ def->type = VIR_DOMAIN_CHR_TYPE_DEV;
+ else if (STREQ(type, "file"))
+ def->type = VIR_DOMAIN_CHR_TYPE_FILE;
+ else if (STREQ(type, "pipe"))
+ def->type = VIR_DOMAIN_CHR_TYPE_PIPE;
+ else if (STREQ(type, "stdio"))
+ def->type = VIR_DOMAIN_CHR_TYPE_STDIO;
+ else if (STREQ(type, "udp"))
+ def->type = VIR_DOMAIN_CHR_TYPE_UDP;
+ else if (STREQ(type, "tcp"))
+ def->type = VIR_DOMAIN_CHR_TYPE_TCP;
+ else if (STREQ(type, "unix"))
+ def->type = VIR_DOMAIN_CHR_TYPE_UNIX;
+ else
+ def->type = VIR_DOMAIN_CHR_TYPE_NULL;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "source")) {
+ if (mode == NULL)
+ mode = virXMLPropString(cur, "mode");
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ if (path == NULL)
+ path = virXMLPropString(cur, "path");
+
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ if (mode == NULL ||
+ STREQ((const char *)mode, "connect")) {
+
+ if (connectHost == NULL)
+ connectHost = virXMLPropString(cur, "host");
+ if (connectService == NULL)
+ connectService = virXMLPropString(cur, "service");
+ } else {
+ if (bindHost == NULL)
+ bindHost = virXMLPropString(cur, "host");
+ if (bindService == NULL)
+ bindService = virXMLPropString(cur, "service");
+ }
+
+ if (def->type == VIR_DOMAIN_CHR_TYPE_UDP) {
+ VIR_FREE(mode);
+ mode = NULL;
+ }
+ }
+ } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
+ if (protocol == NULL)
+ protocol = virXMLPropString(cur, "type");
+ }
+ }
+ cur = cur->next;
+ }
+
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_NULL:
+ /* Nada */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_VC:
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ /* @path attribute is an output only property - pty is auto-allocted */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ if (path == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source path attribute for char device"));
+ goto error;
+ }
+
+ def->data.file.path = path;
+ path = NULL;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
+ /* Nada */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ if (mode == NULL ||
+ STREQ(mode, "connect")) {
+ if (connectHost == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source host attribute for char device"));
+ goto error;
+ }
+ if (connectService == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source service attribute for char device"));
+ goto error;
+ }
+
+ def->data.tcp.host = connectHost;
+ connectHost = NULL;
+ def->data.tcp.service = connectService;
+ connectService = NULL;
+ def->data.tcp.listen = 0;
+ } else {
+ if (bindHost == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source host attribute for char device"));
+ goto error;
+ }
+ if (bindService == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source service attribute for char device"));
+ goto error;
+ }
+
+ def->data.tcp.host = bindHost;
+ bindHost = NULL;
+ def->data.tcp.service = bindService;
+ bindService = NULL;
+ def->data.tcp.listen = 1;
+ }
+ if (protocol != NULL &&
+ STREQ(protocol, "telnet"))
+ def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
+ else
+ def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ if (connectService == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source service attribute for char device"));
+ goto error;
+ }
+
+ def->data.udp.connectHost = connectHost;
+ connectHost = NULL;
+ def->data.udp.connectService = connectService;
+ connectService = NULL;
+
+ def->data.udp.bindHost = bindHost;
+ bindHost = NULL;
+ def->data.udp.bindService = bindService;
+ bindService = NULL;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ if (path == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source path attribute for char device"));
+ goto error;
+ }
+
+ if (mode != NULL &&
+ STRNEQ(mode, "connect"))
+ def->data.nix.listen = 1;
+ else
+ def->data.nix.listen = 0;
+
+ def->data.nix.path = path;
+ path = NULL;
+ break;
+ }
+
+cleanup:
+ VIR_FREE(mode);
+ VIR_FREE(protocol);
+ VIR_FREE(type);
+ VIR_FREE(bindHost);
+ VIR_FREE(bindService);
+ VIR_FREE(connectHost);
+ VIR_FREE(connectService);
+ VIR_FREE(path);
+
+ return def;
+
+error:
+ virDomainChrDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+/* Parse the XML definition for a network interface */
+static virDomainInputDefPtr
+virDomainInputDefParseXML(virConnectPtr conn,
+ const char *ostype,
+ xmlNodePtr node) {
+ virDomainInputDefPtr def;
+ char *type = NULL;
+ char *bus = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ bus = virXMLPropString(node, "bus");
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing input device type"));
+ goto error;
+ }
+
+ if ((def->type = virDomainInputTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown input device type '%s'"), type);
+ goto error;
+ }
+
+ if (bus) {
+ if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown input bus type '%s'"), bus);
+ goto error;
+ }
+
+ if (STREQ(ostype, "hvm")) {
+ if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 && /* Only allow mouse for ps2 */
+ def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("ps2 bus does not support %s input device"),
+ type);
+ goto error;
+ }
+ if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported input bus %s"),
+ bus);
+ goto error;
+ }
+ } else {
+ if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported input bus %s"),
+ bus);
+ }
+ if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("xen bus does not support %s input device"),
+ type);
+ goto error;
+ }
+ }
+ } else {
+ if (STREQ(ostype, "hvm")) {
+ if (def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)
+ def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
+ else
+ def->bus = VIR_DOMAIN_INPUT_BUS_USB;
+ } else {
+ def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
+ }
+ }
+
+cleanup:
+ VIR_FREE(type);
+ VIR_FREE(bus);
+
+ return def;
+
+error:
+ virDomainInputDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+/* Parse the XML definition for a graphics device */
+static virDomainGraphicsDefPtr
+virDomainGraphicsDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ virDomainGraphicsDefPtr def;
+ char *type = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing graphics device type"));
+ goto error;
+ }
+
+ if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown graphics device type '%s'"), type);
+ goto error;
+ }
+
+ if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ char *port = virXMLPropString(node, "port");
+ char *autoport;
+
+ if (port) {
+ if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse vnc port %s"), port);
+ VIR_FREE(port);
+ goto error;
+ }
+ VIR_FREE(port);
+ /* Legacy compat syntax, used -1 for auto-port */
+ if (def->data.vnc.port == -1) {
+ def->data.vnc.port = 0;
+ def->data.vnc.autoport = 1;
+ }
+ } else {
+ def->data.vnc.port = 0;
+ def->data.vnc.autoport = 1;
+ }
+
+ if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
+ if (STREQ(autoport, "yes")) {
+ def->data.vnc.port = 0;
+ def->data.vnc.autoport = 1;
+ }
+ VIR_FREE(autoport);
+ }
+
+ def->data.vnc.listenAddr = virXMLPropString(node, "listen");
+ def->data.vnc.passwd = virXMLPropString(node, "passwd");
+ def->data.vnc.keymap = virXMLPropString(node, "keymap");
+ } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+ def->data.sdl.xauth = virXMLPropString(node, "xauth");
+ def->data.sdl.display = virXMLPropString(node, "display");
+ }
+
+cleanup:
+ VIR_FREE(type);
+
+ return def;
+
+error:
+ virDomainGraphicsDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+static virDomainSoundDefPtr
+virDomainSoundDefParseXML(virConnectPtr conn,
+ const xmlNodePtr node) {
+
+ char *model;
+ virDomainSoundDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ model = virXMLPropString(node, "model");
+ if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown sound model '%s'"), model);
+ goto error;
+ }
+
+cleanup:
+ VIR_FREE(model);
+
+ return def;
+
+error:
+ virDomainSoundDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+static int virDomainLifecycleParseXML(virConnectPtr conn,
+ xmlXPathContextPtr ctxt,
+ const char *xpath,
+ int *val,
+ int defaultVal)
+{
+ char *tmp = virXPathString(xpath, ctxt);
+ if (tmp == NULL) {
+ *val = defaultVal;
+ } else {
+ *val = virDomainLifecycleTypeFromString(tmp);
+ if (*val < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown lifecycle action %s"), tmp);
+ VIR_FREE(tmp);
+ return -1;
+ }
+ VIR_FREE(tmp);
+ }
+ return 0;
+}
+
+
+virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
+ const virDomainDefPtr def,
+ const char *xmlStr)
+{
+ xmlDocPtr xml;
+ xmlNodePtr node;
+ virDomainDeviceDefPtr dev = NULL;
+
+ if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "device.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);
+ goto error;
+ }
+
+ node = xmlDocGetRootElement(xml);
+ if (node == NULL) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("missing root element"));
+ goto error;
+ }
+
+ if (VIR_ALLOC(dev) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+
+ if (xmlStrEqual(node->name, BAD_CAST "disk")) {
+ dev->type = VIR_DOMAIN_DEVICE_DISK;
+ if (!(dev->data.disk = virDomainDiskDefParseXML(conn, node)))
+ goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
+ dev->type = VIR_DOMAIN_DEVICE_NET;
+ if (!(dev->data.net = virDomainNetDefParseXML(conn, node)))
+ goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "input")) {
+ dev->type = VIR_DOMAIN_DEVICE_DISK;
+ if (!(dev->data.input = virDomainInputDefParseXML(conn, def->os.type, node)))
+ goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "sound")) {
+ dev->type = VIR_DOMAIN_DEVICE_SOUND;
+ if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node)))
+ goto error;
+ } else {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("unknown device type"));
+ goto error;
+ }
+
+ xmlFreeDoc(xml);
+
+ return dev;
+
+ error:
+ xmlFreeDoc(xml);
+ VIR_FREE(dev);
+ return NULL;
+}
+
+
+static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
+ virCapsPtr caps,
+ xmlDocPtr xml)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ xmlNodePtr *nodes = NULL, node = NULL;
+ char *tmp = NULL;
+ int i, n;
+ virDomainDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY,
+ "%s", _("failed to allocate space for xmlXPathContext"));
+ return NULL;
+ }
+ def->id = -1;
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY,
+ "%s", _("failed to allocate space for xmlXPathContext"));
+ goto error;
+ }
+
+
+ /* Find out what type of QEMU virtualization to use */
+ if (!(tmp = virXPathString("string(/domain/@type)", ctxt))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing domain type attribute"));
+ goto error;
+ }
+
+ if ((def->virtType = virDomainVirtTypeFromString(tmp)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("invalid domain type %s"), tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+
+ /* Extract domain name */
+ if (!(def->name = virXPathString("string(/domain/name[1])", ctxt))) {
+ virDomainReportError(conn, VIR_ERR_NO_NAME, NULL);
+ goto error;
+ }
+
+ /* Extract domain uuid */
+ tmp = virXPathString("string(/domain/uuid[1])", ctxt);
+ if (!tmp) {
+ int err;
+ if ((err = virUUIDGenerate(def->uuid))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to generate UUID: %s"),
+ strerror(err));
+ goto error;
+ }
+ } else {
+ if (virUUIDParse(tmp, def->uuid) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed uuid element"));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ }
+
+ /* Extract domain memory */
+ if (virXPathULong("string(/domain/memory[1])", ctxt, &def->maxmem) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing memory element"));
+ goto error;
+ }
+
+ if (virXPathULong("string(/domain/currentMemory[1])", ctxt, &def->memory) < 0)
+ def->memory = def->maxmem;
+
+ if (virXPathULong("string(/domain/vcpu[1])", ctxt, &def->vcpus) < 0)
+ def->vcpus = 1;
+
+ tmp = virXPathString("string(/domain/vcpu[1]/@cpuset)", ctxt);
+ if (tmp) {
+ char *set = tmp;
+ def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+ if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ if (virDomainCpuSetParse(conn, (const char **)&set,
+ 0, def->cpumask,
+ def->cpumasklen) < 0)
+ goto error;
+ VIR_FREE(tmp);
+ }
+
+ if ((n = virXPathNodeSet("/domain/features/*", ctxt, &nodes)) > 0) {
+ for (i = 0 ; i < n ; i++) {
+ int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
+ if (val < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected feature %s"),
+ nodes[i]->name);
+ goto error;
+ }
+ def->features |= (1 << val);
+ }
+ }
+ VIR_FREE(nodes);
+
+ if (virDomainLifecycleParseXML(conn, ctxt, "string(/domain/on_reboot[1])",
+ &def->onReboot, VIR_DOMAIN_LIFECYCLE_RESTART) < 0)
+ goto error;
+
+ if (virDomainLifecycleParseXML(conn, ctxt, "string(/domain/on_poweroff[1])",
+ &def->onPoweroff, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
+ goto error;
+
+ if (virDomainLifecycleParseXML(conn, ctxt, "string(/domain/on_crash[1])",
+ &def->onCrash, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
+ goto error;
+
+
+ tmp = virXPathString("string(/domain/clock/@offset)", ctxt);
+ if (tmp && STREQ(tmp, "localtime"))
+ def->localtime = 1;
+ VIR_FREE(tmp);
+
+ def->os.bootloader = virXPathString("string(/domain/bootloader)", ctxt);
+ def->os.bootloaderArgs = virXPathString("string(/domain/bootloader_args)", ctxt);
+
+ def->os.type = virXPathString("string(/domain/os/type[1])", ctxt);
+ if (!def->os.type) {
+ if (def->os.bootloader) {
+ def->os.type = strdup("xen");
+ if (!def->os.type) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ } else {
+ virDomainReportError(conn, VIR_ERR_OS_TYPE,
+ "%s", _("no OS type"));
+ goto error;
+ }
+ }
+ /*
+ * HACK: For xen driver we previously used bogus 'linux' as the
+ * os type for paravirt, whereas capabilities declare it to
+ * be 'xen'. So we accept the former and convert
+ */
+ if (STREQ(def->os.type, "linux") &&
+ def->virtType == VIR_DOMAIN_VIRT_XEN) {
+ VIR_FREE(def->os.type);
+ if (!(def->os.type = strdup("xen"))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+
+ if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
+ virDomainReportError(conn, VIR_ERR_OS_TYPE,
+ "%s", def->os.type);
+ goto error;
+ }
+
+ def->os.arch = virXPathString("string(/domain/os/type[1]/@arch)", ctxt);
+ if (!def->os.arch) {
+ const char *defaultArch = virCapabilitiesDefaultGuestArch(caps, def->os.type);
+ if (defaultArch == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no supported architecture for os type '%s'"),
+ def->os.type);
+ goto error;
+ }
+ if (!(def->os.arch = strdup(defaultArch))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+
+ def->os.machine = virXPathString("string(/domain/os/type[1]/@machine)", ctxt);
+ if (!def->os.machine) {
+ const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
+ def->os.type,
+ def->os.arch);
+ if (defaultMachine != NULL) {
+ if (!(def->os.machine = strdup(defaultMachine))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+ }
+
+ if (!def->os.bootloader) {
+ def->os.kernel = virXPathString("string(/domain/os/kernel[1])", ctxt);
+ def->os.initrd = virXPathString("string(/domain/os/initrd[1])", ctxt);
+ def->os.cmdline = virXPathString("string(/domain/os/cmdline[1])", ctxt);
+ def->os.root = virXPathString("string(/domain/os/root[1])", ctxt);
+ def->os.loader = virXPathString("string(/domain/os/loader[1])", ctxt);
+
+ /* analysis of the boot devices */
+ if ((n = virXPathNodeSet("/domain/os/boot", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract boot device"));
+ goto error;
+ }
+ for (i = 0 ; i < n && i < VIR_DOMAIN_BOOT_LAST ; i++) {
+ int val;
+ char *dev = virXMLPropString(nodes[i], "dev");
+ if (!dev) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing boot device"));
+ goto error;
+ }
+ if ((val = virDomainBootTypeFromString(dev)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown boot device '%s'"),
+ dev);
+ VIR_FREE(dev);
+ goto error;
+ }
+ VIR_FREE(dev);
+ def->os.bootDevs[def->os.nBootDevs++] = val;
+ }
+ if (def->os.nBootDevs == 0) {
+ def->os.nBootDevs = 1;
+ def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
+ }
+ VIR_FREE(nodes);
+ }
+
+ def->emulator = virXPathString("string(/domain/devices/emulator[1])", ctxt);
+ if (!def->emulator) {
+ const char *type = virDomainVirtTypeToString(def->virtType);
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unknown virt type"));
+ goto error;
+ }
+ const char *emulator = virCapabilitiesDefaultGuestEmulator(caps,
+ def->os.type,
+ def->os.arch,
+ type);
+ if (!emulator) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unsupported guest type"));
+ goto error;
+ }
+ if (!(def->emulator = strdup(emulator))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+
+ /* analysis of the disk devices */
+ if ((n = virXPathNodeSet("/domain/devices/disk", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract disk devices"));
+ goto error;
+ }
+ for (i = 0 ; i < n ; i++) {
+ virDomainDiskDefPtr disk = virDomainDiskDefParseXML(conn,
+ nodes[i]);
+ if (!disk)
+ goto error;
+
+ /* Maintain list in sorted order according to target device name */
+ if (def->disks == NULL) {
+ disk->next = def->disks;
+ def->disks = disk;
+ } else {
+ virDomainDiskDefPtr ptr = def->disks;
+ while (ptr) {
+ if (!ptr->next || virDomainDiskCompare(disk, ptr->next) < 0) {
+ disk->next = ptr->next;
+ ptr->next = disk;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ }
+ }
+ VIR_FREE(nodes);
+
+ /* analysis of the network devices */
+ if ((n = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract network devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainNetDefPtr net = virDomainNetDefParseXML(conn,
+ nodes[i]);
+ if (!net)
+ goto error;
+
+ net->next = def->nets;
+ def->nets = net;
+ }
+ VIR_FREE(nodes);
+
+
+ /* analysis of the character devices */
+ if ((n = virXPathNodeSet("/domain/devices/parallel", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract parallel devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
+ nodes[i]);
+ if (!chr)
+ goto error;
+
+ chr->dstPort = i;
+ chr->next = def->parallels;
+ def->parallels = chr;
+ }
+ VIR_FREE(nodes);
+
+ if ((n = virXPathNodeSet("/domain/devices/serial", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract serial devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
+ nodes[i]);
+ if (!chr)
+ goto error;
+
+ chr->dstPort = i;
+ chr->next = def->serials;
+ def->serials = chr;
+ }
+ VIR_FREE(nodes);
+
+ /*
+ * If no serial devices were listed, then look for console
+ * devices which is the legacy syntax for the same thing
+ */
+ if (def->serials == NULL) {
+ if ((node = virXPathNode("/domain/devices/console[1]", ctxt)) != NULL) {
+ virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
+ node);
+ if (!chr)
+ goto error;
+
+ chr->dstPort = 0;
+ /*
+ * For HVM console actually created a serial device
+ * while for non-HVM it was a parvirt console
+ */
+ if (STREQ(def->os.type, "hvm")) {
+ chr->next = def->serials;
+ def->serials = chr;
+ } else {
+ def->console = chr;
+ }
+ }
+ }
+
+
+ /* analysis of the input devices */
+ if ((n = virXPathNodeSet("/domain/devices/input", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract input devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainInputDefPtr input = virDomainInputDefParseXML(conn,
+ def->os.type,
+ nodes[i]);
+ if (!input)
+ goto error;
+
+
+ /* With QEMU / KVM / Xen graphics, mouse + PS/2 is implicit
+ * with graphics, so don't store it.
+ * XXX will this be true for other virt types ? */
+ if ((STREQ(def->os.type, "hvm") &&
+ input->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
+ input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE) ||
+ (STRNEQ(def->os.type, "hvm") &&
+ input->bus == VIR_DOMAIN_INPUT_BUS_XEN &&
+ input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)) {
+ virDomainInputDefFree(input);
+ continue;
+ }
+
+ input->next = def->inputs;
+ def->inputs = input;
+ }
+ VIR_FREE(nodes);
+
+ /* analysis of the input devices */
+ if ((n = virXPathNodeSet("/domain/devices/graphics", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract graphics devices"));
+ goto error;
+ }
+ if (n > 0) {
+ virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(conn,
+ nodes[0]);
+ if (!graphics)
+ goto error;
+
+ def->graphics = graphics;
+ }
+ VIR_FREE(nodes);
+
+ /* If graphics are enabled, there's an implicit PS2 mouse */
+ if (def->graphics != NULL) {
+ virDomainInputDefPtr input;
+
+ if (VIR_ALLOC(input) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ if (STREQ(def->os.type, "hvm")) {
+ input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
+ input->bus = VIR_DOMAIN_INPUT_BUS_PS2;
+ } else {
+ input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
+ input->bus = VIR_DOMAIN_INPUT_BUS_XEN;
+ }
+ input->next = def->inputs;
+ def->inputs = input;
+ }
+
+
+ /* analysis of the sound devices */
+ if ((n = virXPathNodeSet("/domain/devices/sound", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract sound devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ int collision = 0;
+ virDomainSoundDefPtr check;
+ virDomainSoundDefPtr sound = virDomainSoundDefParseXML(conn,
+ nodes[i]);
+ if (!sound)
+ goto error;
+
+ /* Verify there's no duplicated sound card */
+ check = def->sounds;
+ while (check) {
+ if (check->model == sound->model)
+ collision = 1;
+ check = check->next;
+ }
+ if (collision) {
+ virDomainSoundDefFree(sound);
+ continue;
+ }
+
+ sound->next = def->sounds;
+ def->sounds = sound;
+ }
+ VIR_FREE(nodes);
+
+ xmlXPathFreeContext(ctxt);
+
+ return def;
+
+ error:
+ VIR_FREE(tmp);
+ VIR_FREE(nodes);
+ xmlXPathFreeContext(ctxt);
+ virDomainDefFree(def);
+ return NULL;
+}
+
+
+virDomainDefPtr virDomainDefParse(virConnectPtr conn,
+ virCapsPtr caps,
+ const char *xmlStr,
+ const char *displayName)
+{
+ xmlDocPtr xml;
+ virDomainDefPtr def;
+
+ if (!(xml = xmlReadDoc(BAD_CAST xmlStr,
+ displayName ? displayName : "domain.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);
+ return NULL;
+ }
+
+ def = virDomainDefParseXML(conn, caps, xml);
+
+ xmlFreeDoc(xml);
+
+ return def;
+}
+
+/************************************************************************
+ * *
+ * Parser and converter for the CPUset strings used in libvirt *
+ * *
+ ************************************************************************/
+/**
+ * virDomainCpuNumberParse
+ * @str: pointer to the char pointer used
+ * @maxcpu: maximum CPU number allowed
+ *
+ * Parse a CPU number
+ *
+ * Returns the CPU number or -1 in case of error. @str will be
+ * updated to skip the number.
+ */
+static int
+virDomainCpuNumberParse(const char **str, int maxcpu)
+{
+ int ret = 0;
+ const char *cur = *str;
+
+ if (!c_isdigit(*cur))
+ return (-1);
+
+ while (c_isdigit(*cur)) {
+ ret = ret * 10 + (*cur - '0');
+ if (ret >= maxcpu)
+ return (-1);
+ cur++;
+ }
+ *str = cur;
+ return (ret);
+}
+
+/**
+ * virDomainCpuSetFormat:
+ * @conn: connection
+ * @cpuset: pointer to a char array for the CPU set
+ * @maxcpu: number of elements available in @cpuset
+ *
+ * Serialize the cpuset to a string
+ *
+ * Returns the new string NULL in case of error. The string need to be
+ * freed by the caller.
+ */
+char *
+virDomainCpuSetFormat(virConnectPtr conn, char *cpuset, int maxcpu)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int start, cur;
+ int first = 1;
+
+ if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
+ return (NULL);
+
+ cur = 0;
+ start = -1;
+ while (cur < maxcpu) {
+ if (cpuset[cur]) {
+ if (start == -1)
+ start = cur;
+ } else if (start != -1) {
+ if (!first)
+ virBufferAddLit(&buf, ",");
+ else
+ first = 0;
+ if (cur == start + 1)
+ virBufferVSprintf(&buf, "%d", start);
+ else
+ virBufferVSprintf(&buf, "%d-%d", start, cur - 1);
+ start = -1;
+ }
+ cur++;
+ }
+ if (start != -1) {
+ if (!first)
+ virBufferAddLit(&buf, ",");
+ if (maxcpu == start + 1)
+ virBufferVSprintf(&buf, "%d", start);
+ else
+ virBufferVSprintf(&buf, "%d-%d", start, maxcpu - 1);
+ }
+
+ if (virBufferError(&buf)) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+/**
+ * virDomainCpuSetParse:
+ * @conn: connection
+ * @str: pointer to a CPU set string pointer
+ * @sep: potential character used to mark the end of string if not 0
+ * @cpuset: pointer to a char array for the CPU set
+ * @maxcpu: number of elements available in @cpuset
+ *
+ * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
+ * to 1, and 0 otherwise. The syntax allows coma separated entries each
+ * can be either a CPU number, ^N to unset that CPU or N-M for ranges.
+ *
+ * Returns the number of CPU found in that set, or -1 in case of error.
+ * @cpuset is modified accordingly to the value parsed.
+ * @str is updated to the end of the part parsed
+ */
+int
+virDomainCpuSetParse(virConnectPtr conn, const char **str, char sep,
+ char *cpuset, int maxcpu)
+{
+ const char *cur;
+ int ret = 0;
+ int i, start, last;
+ int neg = 0;
+
+ if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) ||
+ (maxcpu > 100000))
+ return (-1);
+
+ cur = *str;
+ virSkipSpaces(&cur);
+ if (*cur == 0)
+ goto parse_error;
+
+ /* initialize cpumap to all 0s */
+ for (i = 0; i < maxcpu; i++)
+ cpuset[i] = 0;
+ ret = 0;
+
+ while ((*cur != 0) && (*cur != sep)) {
+ /*
+ * 3 constructs are allowed:
+ * - N : a single CPU number
+ * - N-M : a range of CPU numbers with N < M
+ * - ^N : remove a single CPU number from the current set
+ */
+ if (*cur == '^') {
+ cur++;
+ neg = 1;
+ }
+
+ if (!c_isdigit(*cur))
+ goto parse_error;
+ start = virDomainCpuNumberParse(&cur, maxcpu);
+ if (start < 0)
+ goto parse_error;
+ virSkipSpaces(&cur);
+ if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
+ if (neg) {
+ if (cpuset[start] == 1) {
+ cpuset[start] = 0;
+ ret--;
+ }
+ } else {
+ if (cpuset[start] == 0) {
+ cpuset[start] = 1;
+ ret++;
+ }
+ }
+ } else if (*cur == '-') {
+ if (neg)
+ goto parse_error;
+ cur++;
+ virSkipSpaces(&cur);
+ last = virDomainCpuNumberParse(&cur, maxcpu);
+ if (last < start)
+ goto parse_error;
+ for (i = start; i <= last; i++) {
+ if (cpuset[i] == 0) {
+ cpuset[i] = 1;
+ ret++;
+ }
+ }
+ virSkipSpaces(&cur);
+ }
+ if (*cur == ',') {
+ cur++;
+ virSkipSpaces(&cur);
+ neg = 0;
+ } else if ((*cur == 0) || (*cur == sep)) {
+ break;
+ } else
+ goto parse_error;
+ }
+ *str = cur;
+ return (ret);
+
+ parse_error:
+ virDomainReportError(conn, VIR_ERR_XEN_CALL,
+ "%s", _("topology cpuset syntax error"));
+ return (-1);
+}
+
+
+static int
+virDomainLifecycleDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ int type,
+ const char *name)
+{
+ const char *typeStr = virDomainLifecycleTypeToString(type);
+ if (!typeStr) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle type %d"), type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <%s>%s</%s>\n", name, typeStr, name);
+
+ return 0;
+}
+
+
+static int
+virDomainDiskDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainDiskDefPtr def)
+{
+ const char *type = virDomainDiskTypeToString(def->type);
+ const char *device = virDomainDiskDeviceTypeToString(def->device);
+ const char *bus = virDomainDiskBusTypeToString(def->bus);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected disk type %d"), def->type);
+ return -1;
+ }
+ if (!device) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected disk device %d"), def->device);
+ return -1;
+ }
+ if (!bus) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected disk bus %d"), def->bus);
+ return -1;
+ }
+
+ virBufferVSprintf(buf,
+ " <disk type='%s' device='%s'>\n",
+ type, device);
+
+ if (def->driverName) {
+ if (def->driverType)
+ virBufferVSprintf(buf,
+ " <driver name='%s' type='%s'/>\n",
+ def->driverName, def->driverType);
+ else
+ virBufferVSprintf(buf,
+ " <driver name='%s'/>\n",
+ def->driverName);
+ }
+
+ if (def->src) {
+ if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
+ virBufferVSprintf(buf, " <source file='%s'/>\n",
+ def->src);
+ else
+ virBufferVSprintf(buf, " <source dev='%s'/>\n",
+ def->src);
+ }
+
+ virBufferVSprintf(buf, " <target dev='%s' bus='%s'/>\n",
+ def->dst, bus);
+
+ if (def->readonly)
+ virBufferAddLit(buf, " <readonly/>\n");
+ if (def->shared)
+ virBufferAddLit(buf, " <shareable/>\n");
+
+ virBufferAddLit(buf, " </disk>\n");
+
+ return 0;
+}
+
+static int
+virDomainNetDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainNetDefPtr def)
+{
+ const char *type = virDomainNetTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected net type %d"), def->type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <interface type='%s'>\n", type);
+
+ virBufferVSprintf(buf,
+ " <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
+ def->mac[0], def->mac[1], def->mac[2],
+ def->mac[3], def->mac[4], def->mac[5]);
+
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ virBufferVSprintf(buf, " <source network='%s'/>\n",
+ def->dst.network.name);
+
+ if (def->dst.network.ifname)
+ virBufferVSprintf(buf, " <target dev='%s'/>\n",
+ def->dst.network.ifname);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (def->dst.ethernet.ifname)
+ virBufferVSprintf(buf, " <target dev='%s'/>\n",
+ def->dst.ethernet.ifname);
+ if (def->dst.ethernet.ipaddr)
+ virBufferVSprintf(buf, " <ip address='%s'/>\n",
+ def->dst.ethernet.ipaddr);
+ if (def->dst.ethernet.script)
+ virBufferVSprintf(buf, " <script path='%s'/>\n",
+ def->dst.ethernet.script);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ virBufferVSprintf(buf, " <source bridge='%s'/>\n",
+ def->dst.bridge.brname);
+ if (def->dst.bridge.ifname)
+ virBufferVSprintf(buf, " <target dev='%s'/>\n",
+ def->dst.bridge.ifname);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ if (def->dst.socket.address)
+ virBufferVSprintf(buf, " <source address='%s' port='%d'/>\n",
+ def->dst.socket.address, def->dst.socket.port);
+ else
+ virBufferVSprintf(buf, " <source port='%d'/>\n",
+ def->dst.socket.port);
+ }
+
+ if (def->model)
+ virBufferVSprintf(buf, " <model type='%s'/>\n",
+ def->model);
+
+ virBufferAddLit(buf, " </interface>\n");
+
+ return 0;
+}
+
+
+static int
+virDomainChrDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainChrDefPtr def,
+ const char *name)
+{
+ const char *type = virDomainChrTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected char type %d"), def->type);
+ return -1;
+ }
+
+ /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
+ if (STREQ(name, "console") &&
+ def->type == VIR_DOMAIN_CHR_TYPE_PTY &&
+ def->data.file.path) {
+ virBufferVSprintf(buf, " <%s type='%s' tty='%s'>\n",
+ name, type,
+ def->data.file.path);
+ } else {
+ virBufferVSprintf(buf, " <%s type='%s'>\n",
+ name, type);
+ }
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_NULL:
+ case VIR_DOMAIN_CHR_TYPE_VC:
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
+ /* nada */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
+ def->data.file.path) {
+ virBufferVSprintf(buf, " <source path='%s'/>\n",
+ def->data.file.path);
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ if (def->data.udp.bindService &&
+ def->data.udp.bindHost) {
+ virBufferVSprintf(buf, " <source mode='bind' host='%s' service='%s'/>\n",
+ def->data.udp.bindHost,
+ def->data.udp.bindService);
+ } else if (def->data.udp.bindHost) {
+ virBufferVSprintf(buf, " <source mode='bind' host='%s'/>\n",
+ def->data.udp.bindHost);
+ } else if (def->data.udp.bindService) {
+ virBufferVSprintf(buf, " <source mode='bind' service='%s'/>\n",
+ def->data.udp.bindService);
+ }
+
+ if (def->data.udp.connectService &&
+ def->data.udp.connectHost) {
+ virBufferVSprintf(buf, " <source mode='connect' host='%s' service='%s'/>\n",
+ def->data.udp.connectHost,
+ def->data.udp.connectService);
+ } else if (def->data.udp.connectHost) {
+ virBufferVSprintf(buf, " <source mode='connect' host='%s'/>\n",
+ def->data.udp.connectHost);
+ } else if (def->data.udp.connectService) {
+ virBufferVSprintf(buf, " <source mode='connect' service='%s'/>\n",
+ def->data.udp.connectService);
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ virBufferVSprintf(buf, " <source mode='%s' host='%s' service='%s'/>\n",
+ def->data.tcp.listen ? "bind" : "connect",
+ def->data.tcp.host,
+ def->data.tcp.service);
+ virBufferVSprintf(buf, " <protocol type='%s'/>\n",
+ def->data.tcp.protocol ==
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET
+ ? "telnet" : "raw");
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ virBufferVSprintf(buf, " <source mode='%s' path='%s'/>\n",
+ def->data.nix.listen ? "bind" : "connect",
+ def->data.nix.path);
+ break;
+ }
+
+ virBufferVSprintf(buf, " <target port='%d'/>\n",
+ def->dstPort);
+
+ virBufferVSprintf(buf, " </%s>\n",
+ name);
+
+ return 0;
+}
+
+static int
+virDomainSoundDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainSoundDefPtr def)
+{
+ const char *model = virDomainSoundModelTypeToString(def->model);
+
+ if (!model) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected sound model %d"), def->model);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <sound model='%s'/>\n",
+ model);
+
+ return 0;
+}
+
+static int
+virDomainInputDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainInputDefPtr def)
+{
+ const char *type = virDomainInputTypeToString(def->type);
+ const char *bus = virDomainInputBusTypeToString(def->bus);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected input type %d"), def->type);
+ return -1;
+ }
+ if (!bus) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected input bus type %d"), def->bus);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <input type='%s' bus='%s'/>\n",
+ type, bus);
+
+ return 0;
+}
+
+
+static int
+virDomainGraphicsDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainGraphicsDefPtr def,
+ int secure)
+{
+ const char *type = virDomainGraphicsTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected net type %d"), def->type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <graphics type='%s'", type);
+
+ switch (def->type) {
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ if (def->data.vnc.autoport)
+ virBufferAddLit(buf, " port='-1'");
+ else if (def->data.vnc.port)
+ virBufferVSprintf(buf, " port='%d'",
+ def->data.vnc.port);
+
+ virBufferVSprintf(buf, " autoport='%s'",
+ def->data.vnc.autoport ? "yes" : "no");
+
+ if (def->data.vnc.listenAddr)
+ virBufferVSprintf(buf, " listen='%s'",
+ def->data.vnc.listenAddr);
+
+ if (def->data.vnc.keymap)
+ virBufferVSprintf(buf, " keymap='%s'",
+ def->data.vnc.keymap);
+
+ if (def->data.vnc.passwd && secure)
+ virBufferVSprintf(buf, " passwd='%s'",
+ def->data.vnc.passwd);
+
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ if (def->data.sdl.display)
+ virBufferVSprintf(buf, " display='%s'",
+ def->data.sdl.display);
+
+ if (def->data.sdl.xauth)
+ virBufferVSprintf(buf, " xauth='%s'",
+ def->data.sdl.xauth);
+ break;
+ }
+
+ virBufferAddLit(buf, "/>\n");
+
+ return 0;
+}
+
+char *virDomainDefFormat(virConnectPtr conn,
+ virDomainDefPtr def,
+ int secure)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ unsigned char *uuid;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDomainDiskDefPtr disk;
+ virDomainNetDefPtr net;
+ virDomainSoundDefPtr sound;
+ virDomainInputDefPtr input;
+ virDomainChrDefPtr chr;
+ const char *type = NULL, *tmp;
+ int n, allones = 1;
+
+ if (!(type = virDomainVirtTypeToString(def->virtType))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected domain type %d"), def->virtType);
+ goto cleanup;
+ }
+
+ if (def->id >= 0)
+ virBufferVSprintf(&buf, "<domain type='%s' id='%d'>\n", type, def->id);
+ else
+ virBufferVSprintf(&buf, "<domain type='%s'>\n", type);
+
+ virBufferVSprintf(&buf, " <name>%s</name>\n", def->name);
+
+ uuid = def->uuid;
+ virUUIDFormat(uuid, uuidstr);
+ virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", uuidstr);
+
+ virBufferVSprintf(&buf, " <memory>%lu</memory>\n", def->maxmem);
+ virBufferVSprintf(&buf, " <currentMemory>%lu</currentMemory>\n",
+ def->memory);
+
+ for (n = 0 ; n < def->cpumasklen ; n++)
+ if (def->cpumask[n] != 1)
+ allones = 0;
+
+ if (allones) {
+ virBufferVSprintf(&buf, " <vcpu>%lu</vcpu>\n", def->vcpus);
+ } else {
+ char *cpumask = NULL;
+ if ((cpumask =
+ virDomainCpuSetFormat(conn, def->cpumask, def->cpumasklen)) == NULL)
+ goto cleanup;
+ virBufferVSprintf(&buf, " <vcpu cpuset='%s'>%lu</vcpu>\n",
+ cpumask, def->vcpus);
+ VIR_FREE(cpumask);
+ }
+
+ if (def->os.bootloader) {
+ virBufferVSprintf(&buf, " <bootloader>%s</bootloader>\n",
+ def->os.bootloader);
+ if (def->os.bootloaderArgs)
+ virBufferVSprintf(&buf, " <bootloader_args>%s</bootloader_args>\n",
+ def->os.bootloaderArgs);
+ }
+ virBufferAddLit(&buf, " <os>\n");
+
+ virBufferAddLit(&buf, " <type");
+ if (def->os.arch)
+ virBufferVSprintf(&buf, " arch='%s'", def->os.arch);
+ if (def->os.machine)
+ virBufferVSprintf(&buf, " machine='%s'", def->os.machine);
+ /*
+ * HACK: For xen driver we previously used bogus 'linux' as the
+ * os type for paravirt, whereas capabilities declare it to
+ * be 'xen'. So we convert to the former for backcompat
+ */
+ if (def->virtType == VIR_DOMAIN_VIRT_XEN &&
+ STREQ(def->os.type, "xen"))
+ virBufferVSprintf(&buf, ">%s</type>\n", "linux");
+ else
+ virBufferVSprintf(&buf, ">%s</type>\n", def->os.type);
+
+ if (def->os.loader)
+ virBufferVSprintf(&buf, " <loader>%s</loader>\n",
+ def->os.loader);
+ if (def->os.kernel)
+ virBufferVSprintf(&buf, " <kernel>%s</kernel>\n",
+ def->os.kernel);
+ if (def->os.initrd)
+ virBufferVSprintf(&buf, " <initrd>%s</initrd>\n",
+ def->os.initrd);
+ if (def->os.cmdline)
+ virBufferVSprintf(&buf, " <cmdline>%s</cmdline>\n",
+ def->os.cmdline);
+ if (def->os.root)
+ virBufferVSprintf(&buf, " <root>%s</root>\n",
+ def->os.root);
+
+ if (!def->os.bootloader) {
+ for (n = 0 ; n < def->os.nBootDevs ; n++) {
+ const char *boottype =
+ virDomainBootTypeToString(def->os.bootDevs[n]);
+ if (!boottype) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected boot device type %d"),
+ def->os.bootDevs[n]);
+ goto cleanup;
+ }
+ virBufferVSprintf(&buf, " <boot dev='%s'/>\n", boottype);
+ }
+ }
+
+ virBufferAddLit(&buf, " </os>\n");
+
+ if (def->features) {
+ int i;
+ virBufferAddLit(&buf, " <features>\n");
+ for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) {
+ if (def->features & (1 << i)) {
+ const char *name = virDomainFeatureTypeToString(i);
+ if (!name) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected feature %d"), i);
+ goto cleanup;
+ }
+ virBufferVSprintf(&buf, " <%s/>\n", name);
+ }
+ }
+ virBufferAddLit(&buf, " </features>\n");
+ }
+
+ virBufferVSprintf(&buf, " <clock offset='%s'/>\n",
+ def->localtime ? "localtime" : "utc");
+
+ if (virDomainLifecycleDefFormat(conn, &buf, def->onPoweroff,
+ "on_poweroff") < 0)
+ goto cleanup;
+ if (virDomainLifecycleDefFormat(conn, &buf, def->onReboot,
+ "on_reboot") < 0)
+ goto cleanup;
+ if (virDomainLifecycleDefFormat(conn, &buf, def->onCrash,
+ "on_crash") < 0)
+ goto cleanup;
+
+ virBufferAddLit(&buf, " <devices>\n");
+
+ if (def->emulator)
+ virBufferVSprintf(&buf, " <emulator>%s</emulator>\n",
+ def->emulator);
+
+ disk = def->disks;
+ while (disk) {
+ if (virDomainDiskDefFormat(conn, &buf, disk) < 0)
+ goto cleanup;
+ disk = disk->next;
+ }
+
+ net = def->nets;
+ while (net) {
+ if (virDomainNetDefFormat(conn, &buf, net) < 0)
+ goto cleanup;
+ net = net->next;
+ }
+
+
+ chr = def->serials;
+ while (chr) {
+ if (virDomainChrDefFormat(conn, &buf, chr, "serial") < 0)
+ goto cleanup;
+ chr = chr->next;
+ }
+
+ chr = def->parallels;
+ while (chr) {
+ if (virDomainChrDefFormat(conn, &buf, chr, "parallel") < 0)
+ goto cleanup;
+ chr = chr->next;
+ }
+
+ /* If there's a PV console that's preferred.. */
+ if (def->console) {
+ if (virDomainChrDefFormat(conn, &buf, def->console, "console") < 0)
+ goto cleanup;
+ } else if (def->serials != NULL) {
+ /* ..else for legacy compat duplicate the serial device as a console */
+ if (virDomainChrDefFormat(conn, &buf, def->serials, "console") < 0)
+ goto cleanup;
+ }
+
+ input = def->inputs;
+ while (input) {
+ if (input->bus == VIR_DOMAIN_INPUT_BUS_USB &&
+ virDomainInputDefFormat(conn, &buf, input) < 0)
+ goto cleanup;
+ input = input->next;
+ }
+
+ if (def->graphics) {
+ /* If graphics is enabled, add the implicit mouse */
+ virDomainInputDef autoInput = {
+ VIR_DOMAIN_INPUT_TYPE_MOUSE,
+ STREQ(def->os.type, "hvm") ?
+ VIR_DOMAIN_INPUT_BUS_PS2 : VIR_DOMAIN_INPUT_BUS_XEN,
+ NULL };
+
+ if (virDomainInputDefFormat(conn, &buf, &autoInput) < 0)
+ goto cleanup;
+
+ if (virDomainGraphicsDefFormat(conn, &buf, def->graphics, secure) < 0)
+ goto cleanup;
+ }
+
+ sound = def->sounds;
+ while(sound) {
+ if (virDomainSoundDefFormat(conn, &buf, sound) < 0)
+ goto cleanup;
+ sound = sound->next;
+ }
+
+ virBufferAddLit(&buf, " </devices>\n");
+ virBufferAddLit(&buf, "</domain>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+ no_memory:
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ cleanup:
+ tmp = virBufferContentAndReset(&buf);
+ VIR_FREE(tmp);
+ return NULL;
+}
+
diff -r f47fdc49c62f src/domain_conf.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/domain_conf.h Sun Jun 22 18:31:20 2008 -0400
@@ -0,0 +1,461 @@
+/*
+ * domain_conf.h: domain XML processing
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * 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.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#ifndef __DOMAIN_CONF_H
+#define __DOMAIN_CONF_H
+
+#include <config.h>
+
+#include "internal.h"
+#include "capabilities.h"
+#include "util.h"
+
+/* Different types of hypervisor */
+/* NB: Keep in sync with virDomainVirtTypeToString impl */
+enum virDomainVirtType {
+ VIR_DOMAIN_VIRT_QEMU,
+ VIR_DOMAIN_VIRT_KQEMU,
+ VIR_DOMAIN_VIRT_KVM,
+ VIR_DOMAIN_VIRT_XEN,
+ VIR_DOMAIN_VIRT_LXC,
+ VIR_DOMAIN_VIRT_UML,
+ VIR_DOMAIN_VIRT_OPENVZ,
+ VIR_DOMAIN_VIRT_VSERVER,
+ VIR_DOMAIN_VIRT_LDOM,
+ VIR_DOMAIN_VIRT_TEST,
+ VIR_DOMAIN_VIRT_VMWARE,
+ VIR_DOMAIN_VIRT_HYPERV,
+
+ VIR_DOMAIN_VIRT_LAST,
+};
+
+/* Two types of disk backends */
+enum virDomainDiskType {
+ VIR_DOMAIN_DISK_TYPE_BLOCK,
+ VIR_DOMAIN_DISK_TYPE_FILE,
+
+ VIR_DOMAIN_DISK_TYPE_LAST
+};
+
+/* Three types of disk frontend */
+enum virDomainDiskDevice {
+ VIR_DOMAIN_DISK_DEVICE_DISK,
+ VIR_DOMAIN_DISK_DEVICE_CDROM,
+ VIR_DOMAIN_DISK_DEVICE_FLOPPY,
+
+ VIR_DOMAIN_DISK_DEVICE_LAST
+};
+
+enum virDomainDiskBus {
+ VIR_DOMAIN_DISK_BUS_IDE,
+ VIR_DOMAIN_DISK_BUS_FDC,
+ VIR_DOMAIN_DISK_BUS_SCSI,
+ VIR_DOMAIN_DISK_BUS_VIRTIO,
+ VIR_DOMAIN_DISK_BUS_XEN,
+
+ VIR_DOMAIN_DISK_BUS_LAST
+};
+
+/* Stores the virtual disk configuration */
+typedef struct _virDomainDiskDef virDomainDiskDef;
+typedef virDomainDiskDef *virDomainDiskDefPtr;
+struct _virDomainDiskDef {
+ int type;
+ int device;
+ int bus;
+ char *src;
+ char *dst;
+ char *driverName;
+ char *driverType;
+ unsigned int readonly : 1;
+ unsigned int shared : 1;
+
+ virDomainDiskDefPtr next;
+};
+
+
+/* 5 different types of networking config */
+enum virDomainNetType {
+ VIR_DOMAIN_NET_TYPE_USER,
+ VIR_DOMAIN_NET_TYPE_ETHERNET,
+ VIR_DOMAIN_NET_TYPE_SERVER,
+ VIR_DOMAIN_NET_TYPE_CLIENT,
+ VIR_DOMAIN_NET_TYPE_MCAST,
+ VIR_DOMAIN_NET_TYPE_NETWORK,
+ VIR_DOMAIN_NET_TYPE_BRIDGE,
+
+ VIR_DOMAIN_NET_TYPE_LAST,
+};
+
+
+#define VIR_DOMAIN_NET_MAC_SIZE 6
+
+/* Stores the virtual network interface configuration */
+typedef struct _virDomainNetDef virDomainNetDef;
+typedef virDomainNetDef *virDomainNetDefPtr;
+struct _virDomainNetDef {
+ int type;
+ unsigned char mac[VIR_DOMAIN_NET_MAC_SIZE];
+ char *model;
+ union {
+ struct {
+ char *ifname;
+ char *script;
+ char *ipaddr;
+ } ethernet;
+ struct {
+ char *address;
+ int port;
+ } socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */
+ struct {
+ char *name;
+ char *ifname;
+ } network;
+ struct {
+ char *brname;
+ char *ifname;
+ } bridge;
+ } dst;
+
+ virDomainNetDefPtr next;
+};
+
+enum virDomainChrSrcType {
+ VIR_DOMAIN_CHR_TYPE_NULL,
+ VIR_DOMAIN_CHR_TYPE_VC,
+ VIR_DOMAIN_CHR_TYPE_PTY,
+ VIR_DOMAIN_CHR_TYPE_DEV,
+ VIR_DOMAIN_CHR_TYPE_FILE,
+ VIR_DOMAIN_CHR_TYPE_PIPE,
+ VIR_DOMAIN_CHR_TYPE_STDIO,
+ VIR_DOMAIN_CHR_TYPE_UDP,
+ VIR_DOMAIN_CHR_TYPE_TCP,
+ VIR_DOMAIN_CHR_TYPE_UNIX,
+
+ VIR_DOMAIN_CHR_TYPE_LAST,
+};
+
+enum virDomainChrTcpProtocol {
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW,
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET,
+
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
+};
+
+typedef struct _virDomainChrDef virDomainChrDef;
+typedef virDomainChrDef *virDomainChrDefPtr;
+struct _virDomainChrDef {
+ int dstPort;
+
+ int type;
+ union {
+ struct {
+ char *path;
+ } file; /* pty, file, pipe, or device */
+ struct {
+ char *host;
+ char *service;
+ int listen;
+ int protocol;
+ } tcp;
+ struct {
+ char *bindHost;
+ char *bindService;
+ char *connectHost;
+ char *connectService;
+ } udp;
+ struct {
+ char *path;
+ int listen;
+ } nix;
+ } data;
+
+ virDomainChrDefPtr next;
+};
+
+enum virDomainInputType {
+ VIR_DOMAIN_INPUT_TYPE_MOUSE,
+ VIR_DOMAIN_INPUT_TYPE_TABLET,
+
+ VIR_DOMAIN_INPUT_TYPE_LAST,
+};
+
+enum virDomainInputBus {
+ VIR_DOMAIN_INPUT_BUS_PS2,
+ VIR_DOMAIN_INPUT_BUS_USB,
+ VIR_DOMAIN_INPUT_BUS_XEN,
+
+ VIR_DOMAIN_INPUT_BUS_LAST
+};
+
+typedef struct _virDomainInputDef virDomainInputDef;
+typedef virDomainInputDef *virDomainInputDefPtr;
+struct _virDomainInputDef {
+ int type;
+ int bus;
+ virDomainInputDefPtr next;
+};
+
+enum virDomainSoundModel {
+ VIR_DOMAIN_SOUND_MODEL_SB16,
+ VIR_DOMAIN_SOUND_MODEL_ES1370,
+ VIR_DOMAIN_SOUND_MODEL_PCSPK,
+
+ VIR_DOMAIN_SOUND_MODEL_LAST
+};
+
+typedef struct _virDomainSoundDef virDomainSoundDef;
+typedef virDomainSoundDef *virDomainSoundDefPtr;
+struct _virDomainSoundDef {
+ int model;
+ virDomainSoundDefPtr next;
+};
+
+/* 3 possible graphics console modes */
+enum virDomainGraphicsType {
+ VIR_DOMAIN_GRAPHICS_TYPE_SDL,
+ VIR_DOMAIN_GRAPHICS_TYPE_VNC,
+
+ VIR_DOMAIN_GRAPHICS_TYPE_LAST,
+};
+
+typedef struct _virDomainGraphicsDef virDomainGraphicsDef;
+typedef virDomainGraphicsDef *virDomainGraphicsDefPtr;
+struct _virDomainGraphicsDef {
+ int type;
+ union {
+ struct {
+ int port;
+ int autoport : 1;
+ char *listenAddr;
+ char *keymap;
+ char *passwd;
+ } vnc;
+ struct {
+ char *display;
+ char *xauth;
+ } sdl;
+ } data;
+};
+
+
+
+/* Flags for the 'type' field in next struct */
+enum virDomainDeviceType {
+ VIR_DOMAIN_DEVICE_DISK,
+ VIR_DOMAIN_DEVICE_NET,
+ VIR_DOMAIN_DEVICE_INPUT,
+ VIR_DOMAIN_DEVICE_SOUND,
+};
+
+typedef struct _virDomainDeviceDef virDomainDeviceDef;
+typedef virDomainDeviceDef *virDomainDeviceDefPtr;
+struct _virDomainDeviceDef {
+ int type;
+ union {
+ virDomainDiskDefPtr disk;
+ virDomainNetDefPtr net;
+ virDomainInputDefPtr input;
+ virDomainSoundDefPtr sound;
+ } data;
+};
+
+
+#define VIR_DOMAIN_MAX_BOOT_DEVS 4
+
+/* 3 possible boot devices */
+enum virDomainBootOrder {
+ VIR_DOMAIN_BOOT_FLOPPY,
+ VIR_DOMAIN_BOOT_CDROM,
+ VIR_DOMAIN_BOOT_DISK,
+ VIR_DOMAIN_BOOT_NET,
+
+ VIR_DOMAIN_BOOT_LAST,
+};
+
+enum virDomainFeature {
+ VIR_DOMAIN_FEATURE_ACPI,
+ VIR_DOMAIN_FEATURE_APIC,
+ VIR_DOMAIN_FEATURE_PAE,
+
+ VIR_DOMAIN_FEATURE_LAST
+};
+
+enum virDomainLifecycleAction {
+ VIR_DOMAIN_LIFECYCLE_DESTROY,
+ VIR_DOMAIN_LIFECYCLE_RESTART,
+ VIR_DOMAIN_LIFECYCLE_RESTART_RENAME,
+ VIR_DOMAIN_LIFECYCLE_PRESERVE,
+
+ VIR_DOMAIN_LIFECYCLE_LAST
+};
+
+/* Operating system configuration data & machine / arch */
+typedef struct _virDomainOSDef virDomainOSDef;
+typedef virDomainOSDef *virDomainOSDefPtr;
+struct _virDomainOSDef {
+ char *type;
+ char *arch;
+ char *machine;
+ int nBootDevs;
+ int bootDevs[VIR_DOMAIN_BOOT_LAST];
+ char *kernel;
+ char *initrd;
+ char *cmdline;
+ char *root;
+ char *loader;
+ char *bootloader;
+ char *bootloaderArgs;
+};
+
+#define VIR_DOMAIN_CPUMASK_LEN 1024
+
+/* Guest VM main configuration */
+typedef struct _virDomainDef virDomainDef;
+typedef virDomainDef *virDomainDefPtr;
+struct _virDomainDef {
+ int virtType;
+ int id;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ char *name;
+
+ unsigned long memory;
+ unsigned long maxmem;
+ unsigned long vcpus;
+ int cpumasklen;
+ char *cpumask;
+
+ /* These 3 are based on virDomainLifeCycleAction enum flags */
+ int onReboot;
+ int onPoweroff;
+ int onCrash;
+
+ virDomainOSDef os;
+ char *emulator;
+ int features;
+
+ int localtime;
+
+ virDomainGraphicsDefPtr graphics;
+ virDomainDiskDefPtr disks;
+ virDomainNetDefPtr nets;
+ virDomainInputDefPtr inputs;
+ virDomainSoundDefPtr sounds;
+ virDomainChrDefPtr serials;
+ virDomainChrDefPtr parallels;
+ virDomainChrDefPtr console;
+};
+
+/* Guest VM runtime state */
+typedef struct _virDomainObj virDomainObj;
+typedef virDomainObj *virDomainObjPtr;
+struct _virDomainObj {
+ int stdin;
+ int stdout;
+ int stderr;
+ int monitor;
+ int logfile;
+ int pid;
+ int state;
+
+ int nvcpupids;
+ int *vcpupids;
+
+ unsigned int autostart : 1;
+ unsigned int persistent : 1;
+
+ char *configFile;
+ char *autostartLink;
+
+ virDomainDefPtr def; /* The current definition */
+ virDomainDefPtr newDef; /* New definition to activate at shutdown */
+
+ virDomainObjPtr next;
+};
+
+
+static inline int
+virDomainIsActive(virDomainObjPtr dom)
+{
+ return dom->def->id != -1;
+}
+
+
+virDomainObjPtr virDomainFindByID(const virDomainObjPtr doms,
+ int id);
+virDomainObjPtr virDomainFindByUUID(const virDomainObjPtr doms,
+ const unsigned char *uuid);
+virDomainObjPtr virDomainFindByName(const virDomainObjPtr doms,
+ const char *name);
+
+
+void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
+void virDomainInputDefFree(virDomainInputDefPtr def);
+void virDomainDiskDefFree(virDomainDiskDefPtr def);
+void virDomainNetDefFree(virDomainNetDefPtr def);
+void virDomainChrDefFree(virDomainChrDefPtr def);
+void virDomainSoundDefFree(virDomainSoundDefPtr def);
+void virDomainDefFree(virDomainDefPtr vm);
+void virDomainObjFree(virDomainObjPtr vm);
+
+virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
+ virDomainObjPtr *doms,
+ const virDomainDefPtr def);
+void virDomainRemoveInactive(virDomainObjPtr *doms,
+ virDomainObjPtr dom);
+
+virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
+ const virDomainDefPtr def,
+ const char *xmlStr);
+virDomainDefPtr virDomainDefParse(virConnectPtr conn,
+ virCapsPtr caps,
+ const char *xmlStr,
+ const char *displayName);
+char *virDomainDefFormat(virConnectPtr conn,
+ virDomainDefPtr def,
+ int secure);
+
+int virDomainCpuSetParse(virConnectPtr conn,
+ const char **str,
+ char sep,
+ char *cpuset,
+ int maxcpu);
+char *virDomainCpuSetFormat(virConnectPtr conn,
+ char *cpuset,
+ int maxcpu);
+
+VIR_ENUM_DECL(virDomainVirt)
+VIR_ENUM_DECL(virDomainBoot)
+VIR_ENUM_DECL(virDomainFeature)
+VIR_ENUM_DECL(virDomainLifecycle)
+VIR_ENUM_DECL(virDomainDisk)
+VIR_ENUM_DECL(virDomainDiskDevice)
+VIR_ENUM_DECL(virDomainDiskBus)
+VIR_ENUM_DECL(virDomainNet)
+VIR_ENUM_DECL(virDomainChr)
+VIR_ENUM_DECL(virDomainSoundModel)
+VIR_ENUM_DECL(virDomainInput)
+VIR_ENUM_DECL(virDomainInputBus)
+VIR_ENUM_DECL(virDomainGraphics)
+
+#endif /* __DOMAIN_CONF_H */
diff -r f47fdc49c62f src/util.h
--- a/src/util.h Sun Jun 22 17:58:48 2008 -0400
+++ b/src/util.h Sun Jun 22 18:31:20 2008 -0400
@@ -100,7 +100,7 @@
#define VIR_ENUM_IMPL(name, lastVal, ...) \
static const char const *name ## TypeList[] = { __VA_ARGS__ }; \
- verify(ARRAY_CARDINALITY(name ## TypeList) == lastVal); \
+ extern int (* name ## Verify (void)) [verify_true (ARRAY_CARDINALITY(name ## TypeList) == lastVal)]; \
const char *name ## TypeToString(int type) { \
return virEnumToString(name ## TypeList, \
ARRAY_CARDINALITY(name ## TypeList), \
diff -r f47fdc49c62f src/xml.c
--- a/src/xml.c Sun Jun 22 17:58:48 2008 -0400
+++ b/src/xml.c Sun Jun 22 18:31:20 2008 -0400
@@ -490,6 +490,59 @@
}
/**
+ * virXPathULong:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathULong(const char *xpath, xmlXPathContextPtr ctxt, unsigned long *value)
+{
+ xmlXPathObjectPtr obj;
+ int ret = 0;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid parameter to virXPathNumber()"), 0);
+ return (-1);
+ }
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+ (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+ char *conv = NULL;
+ long val;
+
+ val = strtoul((const char *) obj->stringval, &conv, 10);
+ if (conv == (const char *) obj->stringval) {
+ ret = -2;
+ } else {
+ *value = val;
+ }
+ } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
+ (!(isnan(obj->floatval)))) {
+ if (obj->floatval < 0) {
+ ret = -2;
+ } else {
+ *value = (unsigned long) obj->floatval;
+ if (*value != obj->floatval) {
+ ret = -2;
+ }
+ }
+ } else {
+ ret = -1;
+ }
+
+ xmlXPathFreeObject(obj);
+ return (ret);
+}
+
+/**
* virXPathBoolean:
* @xpath: the XPath string to evaluate
* @ctxt: an XPath context
@@ -578,18 +631,18 @@
_("Invalid parameter to virXPathNodeSet()"), 0);
return (-1);
}
+ if (list != NULL)
+ *list = NULL;
+
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
- (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
- (obj->nodesetval->nodeTab == NULL)) {
+ (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) {
xmlXPathFreeObject(obj);
- if (list != NULL)
- *list = NULL;
return (-1);
}
ret = obj->nodesetval->nodeNr;
- if (list != NULL) {
+ if (list != NULL && ret) {
if (VIR_ALLOC_N(*list, ret) < 0) {
virXMLError(NULL, VIR_ERR_NO_MEMORY,
_("allocate string array"),
@@ -602,6 +655,13 @@
}
xmlXPathFreeObject(obj);
return (ret);
+}
+
+char *
+virXMLPropString(xmlNodePtr node,
+ const char *name)
+{
+ return (char *)xmlGetProp(node, BAD_CAST name);
}
/************************************************************************
diff -r f47fdc49c62f src/xml.h
--- a/src/xml.h Sun Jun 22 17:58:48 2008 -0400
+++ b/src/xml.h Sun Jun 22 18:31:20 2008 -0400
@@ -23,14 +23,27 @@
int virXPathNumber (const char *xpath,
xmlXPathContextPtr ctxt,
double *value);
+int virXPathInt (const char *xpath,
+ xmlXPathContextPtr ctxt,
+ int *value);
+int virXPathUInt (const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned int *value);
int virXPathLong (const char *xpath,
xmlXPathContextPtr ctxt,
long *value);
+int virXPathULong (const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long *value);
xmlNodePtr virXPathNode (const char *xpath,
xmlXPathContextPtr ctxt);
int virXPathNodeSet (const char *xpath,
xmlXPathContextPtr ctxt,
xmlNodePtr **list);
+
+char * virXMLPropString(xmlNodePtr node,
+ const char *name);
+
#if WITH_XEN || WITH_QEMU
int virParseCpuSet (virConnectPtr conn,
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
5
9
Hi, Daniel
I accidentally met the following error.
Just changes tabs to spaces.
xm_internal.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Thanks
Atsushi SAKAI
2
1