2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* config.c: VM configuration management
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006, 2007 Red Hat, Inc.
|
|
|
|
* Copyright (C) 2006 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@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2007-11-26 11:50:16 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#ifdef WITH_QEMU
|
2007-02-14 15:42:55 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2007-02-23 17:15:18 +00:00
|
|
|
#include <sys/wait.h>
|
2007-04-10 23:17:46 +00:00
|
|
|
#include <arpa/inet.h>
|
2007-04-16 13:14:28 +00:00
|
|
|
#include <sys/utsname.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
#include <libxml/parser.h>
|
|
|
|
#include <libxml/tree.h>
|
|
|
|
#include <libxml/xpath.h>
|
|
|
|
#include <libxml/uri.h>
|
|
|
|
|
Wed Dec 5 13:48:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
* python/libvir.c, python/libvirt_wrap.h, qemud/qemud.c,
qemud/remote.c, src/internal.h, src/openvz_conf.c,
src/openvz_driver.c, src/proxy_internal.h, src/qemu_conf.c,
src/qemu_driver.c, src/remote_internal.h, src/test.h, src/util.c,
src/xen_unified.c, src/xen_unified.h, tests/nodeinfotest.c,
tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c, tests/reconnect.c,
tests/sexpr2xmltest.c, tests/virshtest.c, tests/xencapstest.c,
tests/xmconfigtest.c, tests/xml2sexprtest.c:
Change #include <> to #include "" for local includes.
Removed many includes from src/internal.h and put them in
the C files which actually use them.
Removed <ansidecl.h> - unused.
Added a comment around __func__.
Removed a clashing redefinition of VERSION symbol.
All limits (PATH_MAX etc) now done in src/internal.h, so we
don't need to include those headers in other files.
2007-12-05 13:56:22 +00:00
|
|
|
#include "libvirt/virterror.h"
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-06-27 00:12:29 +00:00
|
|
|
#include "qemu_conf.h"
|
2007-02-26 15:32:27 +00:00
|
|
|
#include "uuid.h"
|
2007-06-27 00:12:29 +00:00
|
|
|
#include "buf.h"
|
2007-10-12 16:05:44 +00:00
|
|
|
#include "conf.h"
|
2007-12-03 14:30:46 +00:00
|
|
|
#include "util.h"
|
2007-06-26 22:13:21 +00:00
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
#define qemudLog(level, msg...) fprintf(stderr, msg)
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
void qemudReportError(virConnectPtr conn,
|
|
|
|
virDomainPtr dom,
|
|
|
|
virNetworkPtr net,
|
|
|
|
int code, const char *fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
char errorMessage[QEMUD_MAX_ERROR_LEN];
|
|
|
|
|
|
|
|
if (fmt) {
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(errorMessage, QEMUD_MAX_ERROR_LEN-1, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
} else {
|
|
|
|
errorMessage[0] = '\0';
|
|
|
|
}
|
|
|
|
__virRaiseError(conn, dom, net, VIR_FROM_QEMU, code, VIR_ERR_ERROR,
|
2007-11-07 12:29:37 +00:00
|
|
|
NULL, NULL, NULL, -1, -1, "%s", errorMessage);
|
2007-06-26 22:13:21 +00:00
|
|
|
}
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
int qemudLoadDriverConfig(struct qemud_driver *driver,
|
|
|
|
const char *filename) {
|
|
|
|
virConfPtr conf;
|
|
|
|
virConfValuePtr p;
|
|
|
|
|
|
|
|
/* Setup 2 critical defaults */
|
|
|
|
strcpy(driver->vncListen, "127.0.0.1");
|
|
|
|
if (!(driver->vncTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-vnc"))) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
|
|
|
|
"vncTLSx509certdir");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Just check the file is readable before opening it, otherwise
|
|
|
|
* libvirt emits an error.
|
|
|
|
*/
|
|
|
|
if (access (filename, R_OK) == -1) return 0;
|
|
|
|
|
|
|
|
conf = virConfReadFile (filename);
|
|
|
|
if (!conf) return 0;
|
|
|
|
|
|
|
|
|
|
|
|
#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) { \
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
"remoteReadConfigFile: %s: %s: expected type " #typ "\n", \
|
|
|
|
filename, (name)); \
|
|
|
|
virConfFree(conf); \
|
|
|
|
return -1; \
|
|
|
|
}
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_tls");
|
|
|
|
CHECK_TYPE ("vnc_tls", VIR_CONF_LONG);
|
|
|
|
if (p) driver->vncTLS = p->l;
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_tls_x509_verify");
|
|
|
|
CHECK_TYPE ("vnc_tls_x509_verify", VIR_CONF_LONG);
|
|
|
|
if (p) driver->vncTLSx509verify = p->l;
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_tls_x509_cert_dir");
|
|
|
|
CHECK_TYPE ("vnc_tls_x509_cert_dir", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
|
|
|
free(driver->vncTLSx509certdir);
|
|
|
|
if (!(driver->vncTLSx509certdir = strdup(p->str))) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
|
|
|
|
"vncTLSx509certdir");
|
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_listen");
|
|
|
|
CHECK_TYPE ("vnc_listen", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
|
|
|
strncpy(driver->vncListen, p->str, sizeof(driver->vncListen));
|
|
|
|
driver->vncListen[sizeof(driver->vncListen)-1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
virConfFree (conf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-26 22:42:47 +00:00
|
|
|
struct qemud_vm *qemudFindVMByID(const struct qemud_driver *driver, int id) {
|
|
|
|
struct qemud_vm *vm = driver->vms;
|
|
|
|
|
|
|
|
while (vm) {
|
|
|
|
if (qemudIsActiveVM(vm) && vm->id == id)
|
|
|
|
return vm;
|
|
|
|
vm = vm->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qemud_vm *qemudFindVMByUUID(const struct qemud_driver *driver,
|
|
|
|
const unsigned char *uuid) {
|
|
|
|
struct qemud_vm *vm = driver->vms;
|
|
|
|
|
|
|
|
while (vm) {
|
2007-08-09 20:19:12 +00:00
|
|
|
if (!memcmp(vm->def->uuid, uuid, VIR_UUID_BUFLEN))
|
2007-06-26 22:42:47 +00:00
|
|
|
return vm;
|
|
|
|
vm = vm->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qemud_vm *qemudFindVMByName(const struct qemud_driver *driver,
|
|
|
|
const char *name) {
|
|
|
|
struct qemud_vm *vm = driver->vms;
|
|
|
|
|
|
|
|
while (vm) {
|
|
|
|
if (!strcmp(vm->def->name, name))
|
|
|
|
return vm;
|
|
|
|
vm = vm->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qemud_network *qemudFindNetworkByUUID(const struct qemud_driver *driver,
|
|
|
|
const unsigned char *uuid) {
|
|
|
|
struct qemud_network *network = driver->networks;
|
|
|
|
|
|
|
|
while (network) {
|
2007-08-09 20:19:12 +00:00
|
|
|
if (!memcmp(network->def->uuid, uuid, VIR_UUID_BUFLEN))
|
2007-06-26 22:42:47 +00:00
|
|
|
return network;
|
|
|
|
network = network->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qemud_network *qemudFindNetworkByName(const struct qemud_driver *driver,
|
|
|
|
const char *name) {
|
|
|
|
struct qemud_network *network = driver->networks;
|
|
|
|
|
|
|
|
while (network) {
|
|
|
|
if (!strcmp(network->def->name, name))
|
|
|
|
return network;
|
|
|
|
network = network->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
/* Free all memory associated with a struct qemud_vm object */
|
|
|
|
void qemudFreeVMDef(struct qemud_vm_def *def) {
|
|
|
|
struct qemud_vm_disk_def *disk = def->disks;
|
|
|
|
struct qemud_vm_net_def *net = def->nets;
|
2007-07-31 14:27:12 +00:00
|
|
|
struct qemud_vm_input_def *input = def->inputs;
|
2007-02-14 17:05:55 +00:00
|
|
|
|
|
|
|
while (disk) {
|
|
|
|
struct qemud_vm_disk_def *prev = disk;
|
|
|
|
disk = disk->next;
|
|
|
|
free(prev);
|
|
|
|
}
|
|
|
|
while (net) {
|
|
|
|
struct qemud_vm_net_def *prev = net;
|
|
|
|
net = net->next;
|
|
|
|
free(prev);
|
|
|
|
}
|
2007-07-31 14:27:12 +00:00
|
|
|
while (input) {
|
|
|
|
struct qemud_vm_input_def *prev = input;
|
|
|
|
input = input->next;
|
|
|
|
free(prev);
|
|
|
|
}
|
2007-02-15 15:52:28 +00:00
|
|
|
free(def);
|
2007-02-14 17:05:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemudFreeVM(struct qemud_vm *vm) {
|
|
|
|
qemudFreeVMDef(vm->def);
|
|
|
|
if (vm->newDef)
|
|
|
|
qemudFreeVMDef(vm->newDef);
|
|
|
|
free(vm);
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-02-14 15:53:14 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/* The list of possible machine types for various architectures,
|
|
|
|
as supported by QEMU - taken from 'qemu -M ?' for each arch */
|
|
|
|
static const char *arch_info_x86_machines[] = {
|
2007-03-15 17:24:56 +00:00
|
|
|
"pc", "isapc", NULL
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
static const char *arch_info_mips_machines[] = {
|
2007-03-15 17:24:56 +00:00
|
|
|
"mips", NULL
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
static const char *arch_info_sparc_machines[] = {
|
2007-03-15 17:24:56 +00:00
|
|
|
"sun4m", NULL
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
static const char *arch_info_ppc_machines[] = {
|
2007-03-15 17:24:56 +00:00
|
|
|
"g3bw", "mac99", "prep", NULL
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
|
2007-07-30 09:59:05 +00:00
|
|
|
/* Feature flags for the architecture info */
|
|
|
|
struct qemu_feature_flags arch_info_i686_flags [] = {
|
|
|
|
{ "pae", 1, 1 },
|
|
|
|
{ "acpi", 1, 1 },
|
|
|
|
{ "apic", 1, 0 },
|
|
|
|
{ NULL, -1, -1 }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct qemu_feature_flags arch_info_x86_64_flags [] = {
|
|
|
|
{ "acpi", 1, 1 },
|
|
|
|
{ "apic", 1, 0 },
|
|
|
|
{ NULL, -1, -1 }
|
|
|
|
};
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/* The archicture tables for supported QEMU archs */
|
2007-03-15 17:24:56 +00:00
|
|
|
struct qemu_arch_info qemudArchs[] = {
|
|
|
|
/* i686 must be in position 0 */
|
2007-07-30 09:59:05 +00:00
|
|
|
{ "i686", 32, arch_info_x86_machines, "qemu", arch_info_i686_flags },
|
2007-03-15 17:24:56 +00:00
|
|
|
/* x86_64 must be in position 1 */
|
2007-07-30 09:59:05 +00:00
|
|
|
{ "x86_64", 64, arch_info_x86_machines, "qemu-system-x86_64", arch_info_x86_64_flags },
|
|
|
|
{ "mips", 32, arch_info_mips_machines, "qemu-system-mips", NULL },
|
|
|
|
{ "mipsel", 32, arch_info_mips_machines, "qemu-system-mipsel", NULL },
|
|
|
|
{ "sparc", 32, arch_info_sparc_machines, "qemu-system-sparc", NULL },
|
|
|
|
{ "ppc", 32, arch_info_ppc_machines, "qemu-system-ppc", NULL },
|
|
|
|
{ NULL, -1, NULL, NULL, NULL }
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Return the default architecture if none is explicitly requested*/
|
|
|
|
static const char *qemudDefaultArch(void) {
|
2007-03-15 17:24:56 +00:00
|
|
|
return qemudArchs[0].arch;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the default machine type for a given architecture */
|
|
|
|
static const char *qemudDefaultMachineForArch(const char *arch) {
|
|
|
|
int i;
|
|
|
|
|
2007-03-15 17:24:56 +00:00
|
|
|
for (i = 0; qemudArchs[i].arch; i++) {
|
|
|
|
if (!strcmp(qemudArchs[i].arch, arch)) {
|
|
|
|
return qemudArchs[i].machines[0];
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the default binary name for a particular architecture */
|
|
|
|
static const char *qemudDefaultBinaryForArch(const char *arch) {
|
|
|
|
int i;
|
|
|
|
|
2007-03-15 17:24:56 +00:00
|
|
|
for (i = 0 ; qemudArchs[i].arch; i++) {
|
|
|
|
if (!strcmp(qemudArchs[i].arch, arch)) {
|
|
|
|
return qemudArchs[i].binary;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the fully qualified path to the binary for an architecture */
|
2007-07-12 15:09:01 +00:00
|
|
|
static char *qemudLocateBinaryForArch(virConnectPtr conn,
|
2007-02-14 01:40:09 +00:00
|
|
|
int virtType, const char *arch) {
|
|
|
|
const char *name;
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
if (virtType == QEMUD_VIRT_KVM)
|
|
|
|
name = "qemu-kvm";
|
|
|
|
else
|
|
|
|
name = qemudDefaultBinaryForArch(arch);
|
|
|
|
|
|
|
|
if (!name) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot determin binary for architecture %s", arch);
|
2007-02-14 01:40:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX lame. should actually use $PATH ... */
|
|
|
|
path = malloc(strlen(name) + strlen("/usr/bin/") + 1);
|
|
|
|
if (!path) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "path");
|
2007-02-14 01:40:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
strcpy(path, "/usr/bin/");
|
|
|
|
strcat(path, name);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2007-02-23 17:15:18 +00:00
|
|
|
|
|
|
|
static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) {
|
|
|
|
pid_t child;
|
|
|
|
int newstdout[2];
|
|
|
|
|
|
|
|
*flags = 0;
|
|
|
|
*version = 0;
|
|
|
|
|
|
|
|
if (pipe(newstdout) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((child = fork()) < 0) {
|
|
|
|
close(newstdout[0]);
|
|
|
|
close(newstdout[1]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (child == 0) { /* Kid */
|
|
|
|
if (close(STDIN_FILENO) < 0)
|
|
|
|
goto cleanup1;
|
|
|
|
if (close(STDERR_FILENO) < 0)
|
|
|
|
goto cleanup1;
|
|
|
|
if (close(newstdout[0]) < 0)
|
|
|
|
goto cleanup1;
|
|
|
|
if (dup2(newstdout[1], STDOUT_FILENO) < 0)
|
|
|
|
goto cleanup1;
|
|
|
|
|
|
|
|
/* Just in case QEMU is translated someday.. */
|
|
|
|
setenv("LANG", "C", 1);
|
|
|
|
execl(qemu, qemu, (char*)NULL);
|
|
|
|
|
|
|
|
cleanup1:
|
|
|
|
_exit(-1); /* Just in case */
|
|
|
|
} else { /* Parent */
|
2007-05-03 16:10:40 +00:00
|
|
|
char help[8192]; /* Ought to be enough to hold QEMU help screen */
|
2007-05-14 15:41:57 +00:00
|
|
|
int got = 0, ret = -1;
|
2007-02-23 17:15:18 +00:00
|
|
|
int major, minor, micro;
|
|
|
|
|
|
|
|
if (close(newstdout[1]) < 0)
|
|
|
|
goto cleanup2;
|
|
|
|
|
2007-05-03 16:10:40 +00:00
|
|
|
while (got < (sizeof(help)-1)) {
|
|
|
|
int len;
|
|
|
|
if ((len = read(newstdout[0], help+got, sizeof(help)-got-1)) <= 0) {
|
|
|
|
if (!len)
|
|
|
|
break;
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
goto cleanup2;
|
|
|
|
}
|
|
|
|
got += len;
|
2007-02-23 17:15:18 +00:00
|
|
|
}
|
|
|
|
help[got] = '\0';
|
|
|
|
|
|
|
|
if (sscanf(help, "QEMU PC emulator version %d.%d.%d", &major,&minor, µ) != 3) {
|
|
|
|
goto cleanup2;
|
|
|
|
}
|
|
|
|
|
|
|
|
*version = (major * 1000 * 1000) + (minor * 1000) + micro;
|
|
|
|
if (strstr(help, "-no-kqemu"))
|
|
|
|
*flags |= QEMUD_CMD_FLAG_KQEMU;
|
2007-05-03 16:10:40 +00:00
|
|
|
if (strstr(help, "-no-reboot"))
|
|
|
|
*flags |= QEMUD_CMD_FLAG_NO_REBOOT;
|
2007-02-23 17:15:18 +00:00
|
|
|
if (*version >= 9000)
|
|
|
|
*flags |= QEMUD_CMD_FLAG_VNC_COLON;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d",
|
|
|
|
major, minor, micro, *version, *flags);
|
|
|
|
|
|
|
|
cleanup2:
|
|
|
|
if (close(newstdout[0]) < 0)
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
rewait:
|
|
|
|
if (waitpid(child, &got, 0) != child) {
|
|
|
|
if (errno == EINTR) {
|
|
|
|
goto rewait;
|
|
|
|
}
|
|
|
|
qemudLog(QEMUD_ERR, "Unexpected exit status from qemu %d pid %lu", got, (unsigned long)child);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
/* Check & log unexpected exit status, but don't fail,
|
|
|
|
* as there's really no need to throw an error if we did
|
|
|
|
* actually read a valid version number above */
|
|
|
|
if (WEXITSTATUS(got) != 1) {
|
|
|
|
qemudLog(QEMUD_WARN, "Unexpected exit status '%d', qemu probably failed", got);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
int qemudExtractVersion(virConnectPtr conn,
|
2007-09-21 21:20:32 +00:00
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED) {
|
2007-02-23 17:15:18 +00:00
|
|
|
char *binary = NULL;
|
2007-04-16 13:14:28 +00:00
|
|
|
struct stat sb;
|
2007-09-21 21:20:32 +00:00
|
|
|
int ignored;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if (driver->qemuVersion > 0)
|
2007-02-23 17:15:18 +00:00
|
|
|
return 0;
|
|
|
|
|
2007-09-21 21:20:32 +00:00
|
|
|
if (!(binary = qemudLocateBinaryForArch(conn, QEMUD_VIRT_QEMU, "i686")))
|
2007-02-23 17:15:18 +00:00
|
|
|
return -1;
|
|
|
|
|
2007-04-16 13:14:28 +00:00
|
|
|
if (stat(binary, &sb) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-04-16 13:14:28 +00:00
|
|
|
"Cannot find QEMU binary %s: %s", binary,
|
|
|
|
strerror(errno));
|
|
|
|
free(binary);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-09-21 21:20:32 +00:00
|
|
|
if (qemudExtractVersionInfo(binary, &driver->qemuVersion, &ignored) < 0) {
|
2007-02-23 17:15:18 +00:00
|
|
|
free(binary);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(binary);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-27 01:18:38 +00:00
|
|
|
/* Parse the XML definition for a disk
|
|
|
|
* @param disk pre-allocated & zero'd disk record
|
|
|
|
* @param node XML nodeset to parse for disk definition
|
|
|
|
* @return 0 on success, -1 on failure
|
|
|
|
*/
|
|
|
|
static int qemudParseDiskXML(virConnectPtr conn,
|
|
|
|
struct qemud_vm_disk_def *disk,
|
|
|
|
xmlNodePtr node) {
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
xmlChar *device = NULL;
|
|
|
|
xmlChar *source = NULL;
|
|
|
|
xmlChar *target = NULL;
|
|
|
|
xmlChar *type = NULL;
|
|
|
|
int typ = 0;
|
|
|
|
|
|
|
|
type = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
if (type != NULL) {
|
|
|
|
if (xmlStrEqual(type, BAD_CAST "file"))
|
|
|
|
typ = QEMUD_DISK_FILE;
|
|
|
|
else if (xmlStrEqual(type, BAD_CAST "block"))
|
|
|
|
typ = QEMUD_DISK_BLOCK;
|
|
|
|
else {
|
|
|
|
typ = QEMUD_DISK_FILE;
|
|
|
|
}
|
|
|
|
xmlFree(type);
|
|
|
|
type = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
device = xmlGetProp(node, BAD_CAST "device");
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((source == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
|
|
|
|
if (typ == QEMUD_DISK_FILE)
|
|
|
|
source = xmlGetProp(cur, BAD_CAST "file");
|
|
|
|
else
|
|
|
|
source = xmlGetProp(cur, BAD_CAST "dev");
|
|
|
|
} else if ((target == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "target"))) {
|
|
|
|
target = xmlGetProp(cur, BAD_CAST "dev");
|
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
|
|
|
|
disk->readonly = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source == NULL) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SOURCE, target ? "%s" : NULL, target);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (target == NULL) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_TARGET, source ? "%s" : NULL, source);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (device &&
|
|
|
|
!strcmp((const char *)device, "floppy") &&
|
|
|
|
strcmp((const char *)target, "fda") &&
|
|
|
|
strcmp((const char *)target, "fdb")) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "Invalid floppy device name: %s", target);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (device &&
|
|
|
|
!strcmp((const char *)device, "cdrom") &&
|
|
|
|
strcmp((const char *)target, "hdc")) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "Invalid cdrom device name: %s", target);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (device &&
|
|
|
|
!strcmp((const char *)device, "cdrom"))
|
|
|
|
disk->readonly = 1;
|
|
|
|
|
|
|
|
if ((!device || !strcmp((const char *)device, "disk")) &&
|
|
|
|
strcmp((const char *)target, "hda") &&
|
|
|
|
strcmp((const char *)target, "hdb") &&
|
|
|
|
strcmp((const char *)target, "hdc") &&
|
|
|
|
strcmp((const char *)target, "hdd")) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "Invalid harddisk device name: %s", target);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy(disk->src, (const char *)source, NAME_MAX-1);
|
|
|
|
disk->src[NAME_MAX-1] = '\0';
|
|
|
|
|
|
|
|
strncpy(disk->dst, (const char *)target, NAME_MAX-1);
|
|
|
|
disk->dst[NAME_MAX-1] = '\0';
|
|
|
|
disk->type = typ;
|
|
|
|
|
|
|
|
if (!device)
|
|
|
|
disk->device = QEMUD_DISK_DISK;
|
|
|
|
else if (!strcmp((const char *)device, "disk"))
|
|
|
|
disk->device = QEMUD_DISK_DISK;
|
|
|
|
else if (!strcmp((const char *)device, "cdrom"))
|
|
|
|
disk->device = QEMUD_DISK_CDROM;
|
|
|
|
else if (!strcmp((const char *)device, "floppy"))
|
|
|
|
disk->device = QEMUD_DISK_FLOPPY;
|
|
|
|
else {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "Invalid device type: %s", device);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlFree(device);
|
|
|
|
xmlFree(target);
|
|
|
|
xmlFree(source);
|
|
|
|
|
2007-10-27 01:18:38 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
if (type)
|
|
|
|
xmlFree(type);
|
|
|
|
if (target)
|
|
|
|
xmlFree(target);
|
|
|
|
if (source)
|
|
|
|
xmlFree(source);
|
|
|
|
if (device)
|
|
|
|
xmlFree(device);
|
2007-10-27 01:18:38 +00:00
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
static void qemudRandomMAC(struct qemud_vm_net_def *net) {
|
|
|
|
net->mac[0] = 0x52;
|
|
|
|
net->mac[1] = 0x54;
|
|
|
|
net->mac[2] = 0x00;
|
|
|
|
net->mac[3] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
|
|
|
|
net->mac[4] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
|
|
|
|
net->mac[5] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-10-27 01:18:38 +00:00
|
|
|
/* Parse the XML definition for a network interface
|
|
|
|
* @param net pre-allocated & zero'd net record
|
|
|
|
* @param node XML nodeset to parse for net definition
|
|
|
|
* @return 0 on success, -1 on failure
|
|
|
|
*/
|
|
|
|
static int qemudParseInterfaceXML(virConnectPtr conn,
|
|
|
|
struct qemud_vm_net_def *net,
|
|
|
|
xmlNodePtr node) {
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
xmlChar *macaddr = NULL;
|
|
|
|
xmlChar *type = NULL;
|
2007-02-14 16:09:37 +00:00
|
|
|
xmlChar *network = NULL;
|
2007-03-13 22:43:22 +00:00
|
|
|
xmlChar *bridge = NULL;
|
|
|
|
xmlChar *ifname = NULL;
|
|
|
|
xmlChar *script = NULL;
|
|
|
|
xmlChar *address = NULL;
|
|
|
|
xmlChar *port = NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
net->type = QEMUD_NET_USER;
|
|
|
|
|
|
|
|
type = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
if (type != NULL) {
|
|
|
|
if (xmlStrEqual(type, BAD_CAST "user"))
|
|
|
|
net->type = QEMUD_NET_USER;
|
2007-03-13 22:43:22 +00:00
|
|
|
else if (xmlStrEqual(type, BAD_CAST "ethernet"))
|
|
|
|
net->type = QEMUD_NET_ETHERNET;
|
2007-02-14 01:40:09 +00:00
|
|
|
else if (xmlStrEqual(type, BAD_CAST "server"))
|
|
|
|
net->type = QEMUD_NET_SERVER;
|
|
|
|
else if (xmlStrEqual(type, BAD_CAST "client"))
|
|
|
|
net->type = QEMUD_NET_CLIENT;
|
|
|
|
else if (xmlStrEqual(type, BAD_CAST "mcast"))
|
|
|
|
net->type = QEMUD_NET_MCAST;
|
2007-02-14 16:09:37 +00:00
|
|
|
else if (xmlStrEqual(type, BAD_CAST "network"))
|
|
|
|
net->type = QEMUD_NET_NETWORK;
|
2007-03-13 22:43:22 +00:00
|
|
|
else if (xmlStrEqual(type, BAD_CAST "bridge"))
|
|
|
|
net->type = QEMUD_NET_BRIDGE;
|
2007-02-14 01:40:09 +00:00
|
|
|
else
|
|
|
|
net->type = QEMUD_NET_USER;
|
|
|
|
xmlFree(type);
|
|
|
|
type = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((macaddr == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "mac"))) {
|
|
|
|
macaddr = xmlGetProp(cur, BAD_CAST "address");
|
2007-02-14 16:09:37 +00:00
|
|
|
} else if ((network == NULL) &&
|
|
|
|
(net->type == QEMUD_NET_NETWORK) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
network = xmlGetProp(cur, BAD_CAST "network");
|
2007-03-13 22:43:22 +00:00
|
|
|
} else if ((network == NULL) &&
|
|
|
|
(net->type == QEMUD_NET_BRIDGE) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
2007-03-27 14:46:45 +00:00
|
|
|
bridge = xmlGetProp(cur, BAD_CAST "bridge");
|
2007-03-13 22:43:22 +00:00
|
|
|
} else if ((network == NULL) &&
|
|
|
|
((net->type == QEMUD_NET_SERVER) ||
|
|
|
|
(net->type == QEMUD_NET_CLIENT) ||
|
|
|
|
(net->type == QEMUD_NET_MCAST)) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
address = xmlGetProp(cur, BAD_CAST "address");
|
|
|
|
port = xmlGetProp(cur, BAD_CAST "port");
|
|
|
|
} else if ((ifname == NULL) &&
|
|
|
|
((net->type == QEMUD_NET_NETWORK) ||
|
|
|
|
(net->type == QEMUD_NET_ETHERNET) ||
|
|
|
|
(net->type == QEMUD_NET_BRIDGE)) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "target")) {
|
|
|
|
ifname = xmlGetProp(cur, BAD_CAST "dev");
|
2007-12-05 15:08:23 +00:00
|
|
|
if (STREQLEN("vnet", (const char*)ifname, 4)) {
|
|
|
|
/* An auto-generated target name, blank it out */
|
|
|
|
xmlFree(ifname);
|
|
|
|
ifname = NULL;
|
|
|
|
}
|
2007-03-13 22:43:22 +00:00
|
|
|
} else if ((script == NULL) &&
|
|
|
|
(net->type == QEMUD_NET_ETHERNET) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "script")) {
|
|
|
|
script = xmlGetProp(cur, BAD_CAST "path");
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (macaddr) {
|
2007-02-19 15:01:20 +00:00
|
|
|
unsigned int mac[6];
|
2007-02-14 01:40:09 +00:00
|
|
|
sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
|
2007-02-19 15:01:20 +00:00
|
|
|
(unsigned int*)&mac[0],
|
|
|
|
(unsigned int*)&mac[1],
|
|
|
|
(unsigned int*)&mac[2],
|
|
|
|
(unsigned int*)&mac[3],
|
|
|
|
(unsigned int*)&mac[4],
|
|
|
|
(unsigned int*)&mac[5]);
|
|
|
|
net->mac[0] = mac[0];
|
|
|
|
net->mac[1] = mac[1];
|
|
|
|
net->mac[2] = mac[2];
|
|
|
|
net->mac[3] = mac[3];
|
|
|
|
net->mac[4] = mac[4];
|
|
|
|
net->mac[5] = mac[5];
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
xmlFree(macaddr);
|
2007-03-13 22:43:22 +00:00
|
|
|
macaddr = NULL;
|
|
|
|
} else {
|
|
|
|
qemudRandomMAC(net);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-02-14 16:09:37 +00:00
|
|
|
if (net->type == QEMUD_NET_NETWORK) {
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (network == NULL) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-14 16:09:37 +00:00
|
|
|
"No <source> 'network' attribute specified with <interface type='network'/>");
|
|
|
|
goto error;
|
2007-03-13 22:43:22 +00:00
|
|
|
} else if ((len = xmlStrlen(network)) >= (QEMUD_MAX_NAME_LEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-14 16:09:37 +00:00
|
|
|
"Network name '%s' too long", network);
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
strncpy(net->dst.network.name, (char *)network, len);
|
|
|
|
net->dst.network.name[len] = '\0';
|
|
|
|
}
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
if (network) {
|
2007-02-14 16:09:37 +00:00
|
|
|
xmlFree(network);
|
2007-03-13 22:43:22 +00:00
|
|
|
network = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifname != NULL) {
|
|
|
|
if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"TAP interface name '%s' is too long", ifname);
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
strncpy(net->dst.network.ifname, (char *)ifname, len);
|
|
|
|
net->dst.network.ifname[len] = '\0';
|
|
|
|
}
|
|
|
|
xmlFree(ifname);
|
|
|
|
ifname = NULL;
|
|
|
|
}
|
|
|
|
} else if (net->type == QEMUD_NET_ETHERNET) {
|
|
|
|
int len;
|
2007-02-14 16:09:37 +00:00
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
if (script != NULL) {
|
|
|
|
if ((len = xmlStrlen(script)) >= (PATH_MAX-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"TAP script path '%s' is too long", script);
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
strncpy(net->dst.ethernet.script, (char *)script, len);
|
|
|
|
net->dst.ethernet.script[len] = '\0';
|
|
|
|
}
|
|
|
|
xmlFree(script);
|
|
|
|
script = NULL;
|
|
|
|
}
|
|
|
|
if (ifname != NULL) {
|
|
|
|
if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"TAP interface name '%s' is too long", ifname);
|
2007-02-14 16:09:37 +00:00
|
|
|
goto error;
|
|
|
|
} else {
|
2007-03-13 22:43:22 +00:00
|
|
|
strncpy(net->dst.ethernet.ifname, (char *)ifname, len);
|
|
|
|
net->dst.ethernet.ifname[len] = '\0';
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
2007-03-13 22:43:22 +00:00
|
|
|
xmlFree(ifname);
|
|
|
|
}
|
|
|
|
} else if (net->type == QEMUD_NET_BRIDGE) {
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (bridge == NULL) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"No <source> 'dev' attribute specified with <interface type='bridge'/>");
|
|
|
|
goto error;
|
|
|
|
} else if ((len = xmlStrlen(bridge)) >= (BR_IFNAME_MAXLEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"TAP bridge path '%s' is too long", bridge);
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
strncpy(net->dst.bridge.brname, (char *)bridge, len);
|
|
|
|
net->dst.bridge.brname[len] = '\0';
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
2007-03-13 22:43:22 +00:00
|
|
|
|
|
|
|
xmlFree(bridge);
|
|
|
|
bridge = NULL;
|
|
|
|
|
|
|
|
if (ifname != NULL) {
|
|
|
|
if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"TAP interface name '%s' is too long", ifname);
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
strncpy(net->dst.bridge.ifname, (char *)ifname, len);
|
|
|
|
net->dst.bridge.ifname[len] = '\0';
|
|
|
|
}
|
|
|
|
xmlFree(ifname);
|
|
|
|
}
|
|
|
|
} else if (net->type == QEMUD_NET_CLIENT ||
|
|
|
|
net->type == QEMUD_NET_SERVER ||
|
|
|
|
net->type == QEMUD_NET_MCAST) {
|
2007-08-07 13:02:35 +00:00
|
|
|
int len = 0;
|
2007-03-13 22:43:22 +00:00
|
|
|
char *ret;
|
|
|
|
|
|
|
|
if (port == NULL) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"No <source> 'port' attribute specified with socket interface");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!(net->dst.socket.port = strtol((char*)port, &ret, 10)) &&
|
|
|
|
ret == (char*)port) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"Cannot parse <source> 'port' attribute with socket interface");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
xmlFree(port);
|
|
|
|
port = NULL;
|
|
|
|
|
|
|
|
if (address == NULL) {
|
|
|
|
if (net->type == QEMUD_NET_CLIENT ||
|
|
|
|
net->type == QEMUD_NET_MCAST) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"No <source> 'address' attribute specified with socket interface");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else if ((len = xmlStrlen(address)) >= (BR_INET_ADDR_MAXLEN)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"IP address '%s' is too long", address);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (address == NULL) {
|
|
|
|
net->dst.socket.address[0] = '\0';
|
|
|
|
} else {
|
|
|
|
strncpy(net->dst.socket.address, (char*)address,len);
|
|
|
|
net->dst.socket.address[len] = '\0';
|
|
|
|
}
|
|
|
|
xmlFree(address);
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
|
|
|
|
2007-10-27 01:18:38 +00:00
|
|
|
return 0;
|
2007-02-14 16:09:37 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
if (network)
|
|
|
|
xmlFree(network);
|
2007-03-13 22:43:22 +00:00
|
|
|
if (address)
|
|
|
|
xmlFree(address);
|
|
|
|
if (port)
|
|
|
|
xmlFree(port);
|
|
|
|
if (ifname)
|
|
|
|
xmlFree(ifname);
|
|
|
|
if (script)
|
|
|
|
xmlFree(script);
|
|
|
|
if (bridge)
|
|
|
|
xmlFree(bridge);
|
2007-10-27 01:18:38 +00:00
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-18 21:08:22 +00:00
|
|
|
/* Parse the XML definition for a network interface */
|
2007-10-27 01:18:38 +00:00
|
|
|
static int qemudParseInputXML(virConnectPtr conn,
|
|
|
|
struct qemud_vm_input_def *input,
|
|
|
|
xmlNodePtr node) {
|
2007-07-18 21:08:22 +00:00
|
|
|
xmlChar *type = NULL;
|
|
|
|
xmlChar *bus = NULL;
|
|
|
|
|
|
|
|
type = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
bus = xmlGetProp(node, BAD_CAST "bus");
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "no type provide for input device");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp((const char *)type, "mouse")) {
|
|
|
|
input->type = QEMU_INPUT_TYPE_MOUSE;
|
|
|
|
} else if (!strcmp((const char *)type, "tablet")) {
|
|
|
|
input->type = QEMU_INPUT_TYPE_TABLET;
|
|
|
|
} else {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "unsupported input device type %s", (const char*)type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus) {
|
|
|
|
if (!strcmp((const char*)bus, "ps2")) { /* Only allow mouse */
|
|
|
|
if (input->type == QEMU_INPUT_TYPE_TABLET) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "ps2 bus does not support %s input device", (const char*)type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
input->bus = QEMU_INPUT_BUS_PS2;
|
|
|
|
} else if (!strcmp((const char *)bus, "usb")) { /* Allow mouse & keyboard */
|
|
|
|
input->bus = QEMU_INPUT_BUS_USB;
|
|
|
|
} else {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "unsupported input bus %s", (const char*)bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (input->type == QEMU_INPUT_TYPE_MOUSE)
|
|
|
|
input->bus = QEMU_INPUT_BUS_PS2;
|
|
|
|
else
|
|
|
|
input->bus = QEMU_INPUT_BUS_USB;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type)
|
|
|
|
xmlFree(type);
|
|
|
|
if (bus)
|
|
|
|
xmlFree(bus);
|
|
|
|
|
2007-10-27 01:18:38 +00:00
|
|
|
return 0;
|
2007-07-18 21:08:22 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
if (type)
|
|
|
|
xmlFree(type);
|
|
|
|
if (bus)
|
|
|
|
xmlFree(bus);
|
|
|
|
|
2007-10-27 01:18:38 +00:00
|
|
|
return -1;
|
2007-07-18 21:08:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* Parses a libvirt XML definition of a guest, and populates the
|
|
|
|
* the qemud_vm struct with matching data about the guests config
|
|
|
|
*/
|
2007-07-12 15:09:01 +00:00
|
|
|
static struct qemud_vm_def *qemudParseXML(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-14 17:05:55 +00:00
|
|
|
xmlDocPtr xml) {
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlNodePtr root = NULL;
|
|
|
|
xmlChar *prop = NULL;
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
xmlXPathObjectPtr obj = NULL;
|
|
|
|
char *conv = NULL;
|
|
|
|
int i;
|
2007-02-14 17:05:55 +00:00
|
|
|
struct qemud_vm_def *def;
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(def = calloc(1, sizeof(*def)))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "xmlXPathContext");
|
2007-02-14 17:05:55 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
/* Prepare parser / xpath context */
|
|
|
|
root = xmlDocGetRootElement(xml);
|
|
|
|
if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "incorrect root element");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "xmlXPathContext");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Find out what type of QEMU virtualization to use */
|
|
|
|
if (!(prop = xmlGetProp(root, BAD_CAST "type"))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "missing domain type attribute");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp((char *)prop, "qemu"))
|
2007-02-14 17:05:55 +00:00
|
|
|
def->virtType = QEMUD_VIRT_QEMU;
|
2007-02-14 01:40:09 +00:00
|
|
|
else if (!strcmp((char *)prop, "kqemu"))
|
2007-02-14 17:05:55 +00:00
|
|
|
def->virtType = QEMUD_VIRT_KQEMU;
|
2007-02-14 01:40:09 +00:00
|
|
|
else if (!strcmp((char *)prop, "kvm"))
|
2007-02-14 17:05:55 +00:00
|
|
|
def->virtType = QEMUD_VIRT_KVM;
|
2007-02-14 01:40:09 +00:00
|
|
|
else {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "invalid domain type attribute");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
free(prop);
|
|
|
|
prop = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/* Extract domain name */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_NAME, NULL);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (strlen((const char *)obj->stringval) >= (QEMUD_MAX_NAME_LEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "domain name length too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->name, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
/* Extract domain uuid */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-02-26 15:32:27 +00:00
|
|
|
int err;
|
2007-06-26 22:19:38 +00:00
|
|
|
if ((err = virUUIDGenerate(def->uuid))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-26 15:32:27 +00:00
|
|
|
"Failed to generate UUID: %s", strerror(err));
|
|
|
|
goto error;
|
|
|
|
}
|
2007-06-26 22:19:38 +00:00
|
|
|
} else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "malformed uuid element");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
/* Extract domain memory */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/memory[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "missing memory element");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
conv = NULL;
|
2007-02-14 17:05:55 +00:00
|
|
|
def->maxmem = strtoll((const char*)obj->stringval, &conv, 10);
|
2007-02-14 01:40:09 +00:00
|
|
|
if (conv == (const char*)obj->stringval) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "malformed memory information");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
/* Extract domain memory */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/currentMemory[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->memory = def->maxmem;
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
|
|
|
conv = NULL;
|
2007-02-14 17:05:55 +00:00
|
|
|
def->memory = strtoll((const char*)obj->stringval, &conv, 10);
|
|
|
|
if (def->memory > def->maxmem)
|
|
|
|
def->memory = def->maxmem;
|
2007-02-14 01:40:09 +00:00
|
|
|
if (conv == (const char*)obj->stringval) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "malformed memory information");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
/* Extract domain vcpu info */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/vcpu[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->vcpus = 1;
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
|
|
|
conv = NULL;
|
2007-02-14 17:05:55 +00:00
|
|
|
def->vcpus = strtoll((const char*)obj->stringval, &conv, 10);
|
2007-02-14 01:40:09 +00:00
|
|
|
if (conv == (const char*)obj->stringval) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "malformed vcpu information");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
/* See if ACPI feature is requested */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/features/acpi", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->features |= QEMUD_FEATURE_ACPI;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-02-20 17:51:41 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-05-03 16:10:40 +00:00
|
|
|
|
|
|
|
/* See if we disable reboots */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/on_reboot)", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
|
|
|
def->noReboot = 0;
|
|
|
|
} else {
|
|
|
|
if (!strcmp((char*)obj->stringval, "destroy"))
|
|
|
|
def->noReboot = 1;
|
|
|
|
else
|
|
|
|
def->noReboot = 0;
|
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
2007-07-16 21:30:30 +00:00
|
|
|
/* See if we set clock to localtime */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/clock/@offset)", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
|
|
|
def->localtime = 0;
|
|
|
|
} else {
|
|
|
|
if (!strcmp((char*)obj->stringval, "localtime"))
|
|
|
|
def->localtime = 1;
|
|
|
|
else
|
|
|
|
def->localtime = 0;
|
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
2007-05-03 16:10:40 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/* Extract OS type info */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, NULL);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (strcmp((const char *)obj->stringval, "hvm")) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, "%s", obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.type, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1]/@arch)", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
|
|
|
const char *defaultArch = qemudDefaultArch();
|
|
|
|
if (strlen(defaultArch) >= (QEMUD_OS_TYPE_MAX_LEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "architecture type too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.arch, defaultArch);
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
|
|
|
if (strlen((const char *)obj->stringval) >= (QEMUD_OS_TYPE_MAX_LEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "architecture type too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.arch, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1]/@machine)", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-02-14 17:05:55 +00:00
|
|
|
const char *defaultMachine = qemudDefaultMachineForArch(def->os.arch);
|
2007-07-30 18:50:07 +00:00
|
|
|
if (!defaultMachine) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "unsupported arch %s", def->os.arch);
|
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
if (strlen(defaultMachine) >= (QEMUD_OS_MACHINE_MAX_LEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "machine type too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.machine, defaultMachine);
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
|
|
|
if (strlen((const char *)obj->stringval) >= (QEMUD_OS_MACHINE_MAX_LEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "architecture type too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.machine, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/os/kernel[1])", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "kernel path too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.kernel, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/os/initrd[1])", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "initrd path too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.initrd, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/os/cmdline[1])", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "cmdline arguments too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.cmdline, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
/* analysis of the disk devices */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/os/boot", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
|
|
|
|
for (i = 0; i < obj->nodesetval->nodeNr && i < QEMUD_MAX_BOOT_DEVS ; i++) {
|
2007-02-22 10:39:38 +00:00
|
|
|
if (!(prop = xmlGetProp(obj->nodesetval->nodeTab[i], BAD_CAST "dev")))
|
|
|
|
continue;
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!strcmp((char *)prop, "hd")) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_DISK;
|
2007-02-14 01:40:09 +00:00
|
|
|
} else if (!strcmp((char *)prop, "fd")) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_FLOPPY;
|
2007-02-14 01:40:09 +00:00
|
|
|
} else if (!strcmp((char *)prop, "cdrom")) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_CDROM;
|
2007-09-13 22:06:54 +00:00
|
|
|
} else if (!strcmp((char *)prop, "network")) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_NET;
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
|
|
|
goto error;
|
|
|
|
}
|
2007-02-22 10:39:38 +00:00
|
|
|
xmlFree(prop);
|
2007-03-09 03:08:34 +00:00
|
|
|
prop = NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
2007-02-14 17:05:55 +00:00
|
|
|
if (def->os.nBootDevs == 0) {
|
|
|
|
def->os.nBootDevs = 1;
|
|
|
|
def->os.bootDevs[0] = QEMUD_BOOT_DISK;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-09-21 21:20:32 +00:00
|
|
|
char *tmp = qemudLocateBinaryForArch(conn, def->virtType, def->os.arch);
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!tmp) {
|
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.binary, tmp);
|
2007-02-14 01:40:09 +00:00
|
|
|
free(tmp);
|
|
|
|
} else {
|
|
|
|
if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "emulator path too long");
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
strcpy(def->os.binary, (const char *)obj->stringval);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
|
|
|
|
(obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->graphicsType = QEMUD_GRAPHICS_NONE;
|
2007-02-20 17:51:41 +00:00
|
|
|
} else if ((prop = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "type"))) {
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!strcmp((char *)prop, "vnc")) {
|
2007-07-24 14:30:05 +00:00
|
|
|
xmlChar *vncport, *vnclisten;
|
2007-02-14 17:05:55 +00:00
|
|
|
def->graphicsType = QEMUD_GRAPHICS_VNC;
|
2007-07-24 14:30:05 +00:00
|
|
|
vncport = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "port");
|
|
|
|
if (vncport) {
|
2007-02-14 01:40:09 +00:00
|
|
|
conv = NULL;
|
2007-07-24 14:30:05 +00:00
|
|
|
def->vncPort = strtoll((const char*)vncport, &conv, 10);
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->vncPort = -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-07-24 14:30:05 +00:00
|
|
|
vnclisten = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "listen");
|
|
|
|
if (vnclisten && *vnclisten)
|
|
|
|
strncpy(def->vncListen, (char *)vnclisten, BR_INET_ADDR_MAXLEN-1);
|
|
|
|
else
|
2007-10-12 16:05:44 +00:00
|
|
|
strcpy(def->vncListen, driver->vncListen);
|
2007-07-24 14:30:05 +00:00
|
|
|
def->vncListen[BR_INET_ADDR_MAXLEN-1] = '\0';
|
|
|
|
xmlFree(vncport);
|
|
|
|
xmlFree(vnclisten);
|
2007-02-14 01:40:09 +00:00
|
|
|
} else if (!strcmp((char *)prop, "sdl")) {
|
2007-02-14 17:05:55 +00:00
|
|
|
def->graphicsType = QEMUD_GRAPHICS_SDL;
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "Unsupported graphics type %s", prop);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-20 17:51:41 +00:00
|
|
|
xmlFree(prop);
|
2007-03-09 03:08:34 +00:00
|
|
|
prop = NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-02-20 17:51:41 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
/* analysis of the disk devices */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
|
2007-03-13 22:43:22 +00:00
|
|
|
struct qemud_vm_disk_def *prev = NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
|
2007-12-11 21:57:29 +00:00
|
|
|
struct qemud_vm_disk_def *disk = calloc(1, sizeof(*disk));
|
2007-10-27 01:18:38 +00:00
|
|
|
if (!disk) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "disk");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (qemudParseDiskXML(conn, disk, obj->nodesetval->nodeTab[i]) < 0) {
|
|
|
|
free(disk);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
def->ndisks++;
|
2007-03-13 22:43:22 +00:00
|
|
|
disk->next = NULL;
|
|
|
|
if (i == 0) {
|
|
|
|
def->disks = disk;
|
|
|
|
} else {
|
|
|
|
prev->next = disk;
|
|
|
|
}
|
|
|
|
prev = disk;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
/* analysis of the network devices */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
|
2007-03-13 22:43:22 +00:00
|
|
|
struct qemud_vm_net_def *prev = NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
|
2007-12-11 21:57:29 +00:00
|
|
|
struct qemud_vm_net_def *net = calloc(1, sizeof(*net));
|
2007-10-27 01:18:38 +00:00
|
|
|
if (!net) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "net");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (qemudParseInterfaceXML(conn, net, obj->nodesetval->nodeTab[i]) < 0) {
|
|
|
|
free(net);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
def->nnets++;
|
2007-03-13 22:43:22 +00:00
|
|
|
net->next = NULL;
|
|
|
|
if (i == 0) {
|
|
|
|
def->nets = net;
|
|
|
|
} else {
|
|
|
|
prev->next = net;
|
|
|
|
}
|
|
|
|
prev = net;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
2007-07-18 21:08:22 +00:00
|
|
|
|
|
|
|
/* analysis of the input devices */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/devices/input", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
|
|
|
|
struct qemud_vm_input_def *prev = NULL;
|
|
|
|
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
|
2007-12-11 21:57:29 +00:00
|
|
|
struct qemud_vm_input_def *input = calloc(1, sizeof(*input));
|
2007-10-27 01:18:38 +00:00
|
|
|
if (!input) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "input");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (qemudParseInputXML(conn, input, obj->nodesetval->nodeTab[i]) < 0) {
|
|
|
|
free(input);
|
2007-07-18 21:08:22 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* Mouse + PS/2 is implicit with graphics, so don't store it */
|
|
|
|
if (input->bus == QEMU_INPUT_BUS_PS2 &&
|
|
|
|
input->type == QEMU_INPUT_TYPE_MOUSE) {
|
|
|
|
free(input);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
def->ninputs++;
|
|
|
|
input->next = NULL;
|
2007-09-28 20:47:58 +00:00
|
|
|
if (def->inputs == NULL) {
|
2007-07-18 21:08:22 +00:00
|
|
|
def->inputs = input;
|
|
|
|
} else {
|
|
|
|
prev->next = input;
|
|
|
|
}
|
|
|
|
prev = input;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
obj = NULL;
|
|
|
|
|
|
|
|
/* If graphics are enabled, there's an implicit PS2 mouse */
|
|
|
|
if (def->graphicsType != QEMUD_GRAPHICS_NONE) {
|
|
|
|
int hasPS2mouse = 0;
|
|
|
|
struct qemud_vm_input_def *input = def->inputs;
|
|
|
|
while (input) {
|
|
|
|
if (input->type == QEMU_INPUT_TYPE_MOUSE &&
|
|
|
|
input->bus == QEMU_INPUT_BUS_PS2)
|
|
|
|
hasPS2mouse = 1;
|
|
|
|
input = input->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasPS2mouse) {
|
2007-12-11 21:57:29 +00:00
|
|
|
input = calloc(1, sizeof(*input));
|
2007-07-18 21:08:22 +00:00
|
|
|
if (!input) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "input");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
input->type = QEMU_INPUT_TYPE_MOUSE;
|
|
|
|
input->bus = QEMU_INPUT_BUS_PS2;
|
|
|
|
input->next = def->inputs;
|
|
|
|
def->inputs = input;
|
|
|
|
def->ninputs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
return def;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
if (prop)
|
|
|
|
free(prop);
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
if (ctxt)
|
|
|
|
xmlXPathFreeContext(ctxt);
|
2007-02-14 17:05:55 +00:00
|
|
|
qemudFreeVMDef(def);
|
|
|
|
return NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-14 16:09:37 +00:00
|
|
|
static char *
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudNetworkIfaceConnect(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-14 16:09:37 +00:00
|
|
|
struct qemud_vm *vm,
|
2007-03-13 22:43:22 +00:00
|
|
|
struct qemud_vm_net_def *net,
|
|
|
|
int vlan)
|
2007-02-14 16:09:37 +00:00
|
|
|
{
|
2007-03-13 22:43:22 +00:00
|
|
|
struct qemud_network *network = NULL;
|
|
|
|
char *brname;
|
|
|
|
char *ifname;
|
2007-02-14 16:09:37 +00:00
|
|
|
char tapfdstr[4+3+32+7];
|
|
|
|
char *retval = NULL;
|
|
|
|
int err;
|
|
|
|
int tapfd = -1;
|
|
|
|
int *tapfds;
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
if (net->type == QEMUD_NET_NETWORK) {
|
2007-06-26 22:13:21 +00:00
|
|
|
if (!(network = qemudFindNetworkByName(driver, net->dst.network.name))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"Network '%s' not found", net->dst.network.name);
|
|
|
|
goto error;
|
|
|
|
} else if (network->bridge[0] == '\0') {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"Network '%s' not active", net->dst.network.name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
brname = network->bridge;
|
|
|
|
if (net->dst.network.ifname[0] == '\0' ||
|
2007-12-05 15:08:23 +00:00
|
|
|
STREQLEN(net->dst.network.ifname, "vnet", 4) ||
|
2007-03-13 22:43:22 +00:00
|
|
|
strchr(net->dst.network.ifname, '%')) {
|
|
|
|
strcpy(net->dst.network.ifname, "vnet%d");
|
|
|
|
}
|
|
|
|
ifname = net->dst.network.ifname;
|
|
|
|
} else if (net->type == QEMUD_NET_BRIDGE) {
|
|
|
|
brname = net->dst.bridge.brname;
|
|
|
|
if (net->dst.bridge.ifname[0] == '\0' ||
|
2007-12-05 15:08:23 +00:00
|
|
|
STREQLEN(net->dst.bridge.ifname, "vnet", 4) ||
|
2007-03-13 22:43:22 +00:00
|
|
|
strchr(net->dst.bridge.ifname, '%')) {
|
|
|
|
strcpy(net->dst.bridge.ifname, "vnet%d");
|
|
|
|
}
|
|
|
|
ifname = net->dst.bridge.ifname;
|
|
|
|
} else {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"Network type %d is not supported", net->type);
|
2007-02-14 16:09:37 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if (!driver->brctl && (err = brInit(&driver->brctl))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-05-14 15:41:57 +00:00
|
|
|
"cannot initialize bridge support: %s", strerror(err));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = brAddTap(driver->brctl, brname,
|
2007-03-13 22:43:22 +00:00
|
|
|
ifname, BR_IFNAME_MAXLEN, &tapfd))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-14 16:09:37 +00:00
|
|
|
"Failed to add tap interface '%s' to bridge '%s' : %s",
|
2007-03-13 22:43:22 +00:00
|
|
|
ifname, brname, strerror(err));
|
2007-02-14 16:09:37 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=,vlan=%d", tapfd, vlan);
|
2007-02-14 16:09:37 +00:00
|
|
|
|
|
|
|
if (!(retval = strdup(tapfdstr)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(tapfds = realloc(vm->tapfds, sizeof(*tapfds) * (vm->ntapfds+2))))
|
2007-02-14 16:09:37 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
vm->tapfds = tapfds;
|
|
|
|
vm->tapfds[vm->ntapfds++] = tapfd;
|
|
|
|
vm->tapfds[vm->ntapfds] = -1;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
no_memory:
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "tapfds");
|
2007-02-14 16:09:37 +00:00
|
|
|
error:
|
|
|
|
if (retval)
|
|
|
|
free(retval);
|
|
|
|
if (tapfd != -1)
|
|
|
|
close(tapfd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* Constructs a argv suitable for launching qemu with config defined
|
|
|
|
* for a given virtual machine.
|
|
|
|
*/
|
2007-07-12 15:09:01 +00:00
|
|
|
int qemudBuildCommandLine(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-14 01:40:09 +00:00
|
|
|
struct qemud_vm *vm,
|
2007-02-14 15:54:47 +00:00
|
|
|
char ***argv) {
|
|
|
|
int len, n = -1, i;
|
2007-02-14 01:40:09 +00:00
|
|
|
char memory[50];
|
|
|
|
char vcpus[50];
|
|
|
|
char boot[QEMUD_MAX_BOOT_DEVS+1];
|
2007-04-16 13:14:28 +00:00
|
|
|
struct stat sb;
|
2007-02-14 17:05:55 +00:00
|
|
|
struct qemud_vm_disk_def *disk = vm->def->disks;
|
|
|
|
struct qemud_vm_net_def *net = vm->def->nets;
|
2007-07-18 21:08:22 +00:00
|
|
|
struct qemud_vm_input_def *input = vm->def->inputs;
|
2007-04-16 13:14:28 +00:00
|
|
|
struct utsname ut;
|
|
|
|
int disableKQEMU = 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-09-21 21:20:32 +00:00
|
|
|
/* Make sure the binary we are about to try exec'ing exists.
|
|
|
|
* Technically we could catch the exec() failure, but that's
|
|
|
|
* in a sub-process so its hard to feed back a useful error
|
|
|
|
*/
|
|
|
|
if (stat(vm->def->os.binary, &sb) < 0) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Cannot find QEMU binary %s: %s", vm->def->os.binary,
|
|
|
|
strerror(errno));
|
2007-02-23 17:15:18 +00:00
|
|
|
return -1;
|
2007-09-21 21:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vm->qemuVersion == 0) {
|
|
|
|
if (qemudExtractVersionInfo(vm->def->os.binary,
|
|
|
|
&(vm->qemuVersion),
|
|
|
|
&(vm->qemuCmdFlags)) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2007-04-16 13:14:28 +00:00
|
|
|
uname(&ut);
|
|
|
|
|
2007-05-18 18:36:24 +00:00
|
|
|
/* Nasty hack make i?86 look like i686 to simplify next comparison */
|
2007-04-16 13:14:28 +00:00
|
|
|
if (ut.machine[0] == 'i' &&
|
|
|
|
ut.machine[2] == '8' &&
|
|
|
|
ut.machine[3] == '6' &&
|
|
|
|
!ut.machine[4])
|
2007-05-18 18:36:24 +00:00
|
|
|
ut.machine[1] = '6';
|
2007-04-16 13:14:28 +00:00
|
|
|
|
|
|
|
/* Need to explicitly disable KQEMU if
|
|
|
|
* 1. Arch matches host arch
|
|
|
|
* 2. Guest is 'qemu'
|
|
|
|
* 3. The qemu binary has the -no-kqemu flag
|
|
|
|
*/
|
2007-09-21 21:20:32 +00:00
|
|
|
if ((vm->qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) &&
|
2007-04-16 13:14:28 +00:00
|
|
|
!strcmp(ut.machine, vm->def->os.arch) &&
|
|
|
|
vm->def->virtType == QEMUD_VIRT_QEMU)
|
|
|
|
disableKQEMU = 1;
|
|
|
|
|
2007-02-14 15:54:47 +00:00
|
|
|
len = 1 + /* qemu */
|
2007-02-14 01:40:09 +00:00
|
|
|
2 + /* machine type */
|
2007-04-16 13:14:28 +00:00
|
|
|
disableKQEMU + /* Disable kqemu */
|
2007-02-14 17:05:55 +00:00
|
|
|
2 * vm->def->ndisks + /* disks*/
|
|
|
|
(vm->def->nnets > 0 ? (4 * vm->def->nnets) : 2) + /* networks */
|
2007-07-18 21:08:22 +00:00
|
|
|
1 + /* usb */
|
|
|
|
2 * vm->def->ninputs + /* input devices */
|
2007-02-14 01:40:09 +00:00
|
|
|
2 + /* memory*/
|
|
|
|
2 + /* cpus */
|
|
|
|
2 + /* boot device */
|
|
|
|
2 + /* monitor */
|
2007-07-16 21:30:30 +00:00
|
|
|
(vm->def->localtime ? 1 : 0) + /* localtime */
|
2007-09-21 21:20:32 +00:00
|
|
|
(vm->qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT &&
|
2007-05-03 16:10:40 +00:00
|
|
|
vm->def->noReboot ? 1 : 0) + /* no-reboot */
|
2007-02-14 17:05:55 +00:00
|
|
|
(vm->def->features & QEMUD_FEATURE_ACPI ? 0 : 1) + /* acpi */
|
|
|
|
(vm->def->os.kernel[0] ? 2 : 0) + /* kernel */
|
|
|
|
(vm->def->os.initrd[0] ? 2 : 0) + /* initrd */
|
|
|
|
(vm->def->os.cmdline[0] ? 2 : 0) + /* cmdline */
|
|
|
|
(vm->def->graphicsType == QEMUD_GRAPHICS_VNC ? 2 :
|
2007-08-14 01:28:47 +00:00
|
|
|
(vm->def->graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)) + /* graphics */
|
|
|
|
(vm->migrateFrom[0] ? 3 : 0); /* migrateFrom */
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-03-23 16:15:07 +00:00
|
|
|
snprintf(memory, sizeof(memory), "%d", vm->def->memory/1024);
|
|
|
|
snprintf(vcpus, sizeof(vcpus), "%d", vm->def->vcpus);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(*argv = malloc(sizeof(**argv) * (len+1))))
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
if (!((*argv)[++n] = strdup(vm->def->os.binary)))
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup("-M")))
|
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
if (!((*argv)[++n] = strdup(vm->def->os.machine)))
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-04-16 13:14:28 +00:00
|
|
|
if (disableKQEMU) {
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-no-kqemu")))
|
2007-02-23 17:15:18 +00:00
|
|
|
goto no_memory;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
if (!((*argv)[++n] = strdup("-m")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup(memory)))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup("-smp")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup(vcpus)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-07-24 14:30:05 +00:00
|
|
|
/*
|
|
|
|
* NB, -nographic *MUST* come before any serial, or monitor
|
|
|
|
* or parallel port flags due to QEMU craziness, where it
|
|
|
|
* decides to change the serial port & monitor to be on stdout
|
|
|
|
* if you ask for nographic. So we have to make sure we override
|
|
|
|
* these defaults ourselves...
|
|
|
|
*/
|
|
|
|
if (vm->def->graphicsType == QEMUD_GRAPHICS_NONE) {
|
|
|
|
if (!((*argv)[++n] = strdup("-nographic")))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-monitor")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup("pty")))
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-07-16 21:30:30 +00:00
|
|
|
if (vm->def->localtime) {
|
|
|
|
if (!((*argv)[++n] = strdup("-localtime")))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-09-21 21:20:32 +00:00
|
|
|
if (vm->qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT &&
|
2007-05-03 16:10:40 +00:00
|
|
|
vm->def->noReboot) {
|
|
|
|
if (!((*argv)[++n] = strdup("-no-reboot")))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
if (!(vm->def->features & QEMUD_FEATURE_ACPI)) {
|
2007-02-23 17:15:18 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-no-acpi")))
|
|
|
|
goto no_memory;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
|
|
|
|
switch (vm->def->os.bootDevs[i]) {
|
2007-02-14 01:40:09 +00:00
|
|
|
case QEMUD_BOOT_CDROM:
|
|
|
|
boot[i] = 'd';
|
|
|
|
break;
|
|
|
|
case QEMUD_BOOT_FLOPPY:
|
|
|
|
boot[i] = 'a';
|
|
|
|
break;
|
|
|
|
case QEMUD_BOOT_DISK:
|
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
|
|
|
case QEMUD_BOOT_NET:
|
|
|
|
boot[i] = 'n';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
boot[vm->def->os.nBootDevs] = '\0';
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-boot")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup(boot)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
if (vm->def->os.kernel[0]) {
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-kernel")))
|
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
if (!((*argv)[++n] = strdup(vm->def->os.kernel)))
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
if (vm->def->os.initrd[0]) {
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-initrd")))
|
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
if (!((*argv)[++n] = strdup(vm->def->os.initrd)))
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-02-14 17:05:55 +00:00
|
|
|
if (vm->def->os.cmdline[0]) {
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-append")))
|
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
if (!((*argv)[++n] = strdup(vm->def->os.cmdline)))
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (disk) {
|
|
|
|
char dev[NAME_MAX];
|
|
|
|
char file[PATH_MAX];
|
|
|
|
if (!strcmp(disk->dst, "hdc") &&
|
|
|
|
disk->device == QEMUD_DISK_CDROM)
|
|
|
|
snprintf(dev, NAME_MAX, "-%s", "cdrom");
|
|
|
|
else
|
|
|
|
snprintf(dev, NAME_MAX, "-%s", disk->dst);
|
|
|
|
snprintf(file, PATH_MAX, "%s", disk->src);
|
|
|
|
|
|
|
|
if (!((*argv)[++n] = strdup(dev)))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup(file)))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
disk = disk->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net) {
|
|
|
|
if (!((*argv)[++n] = strdup("-net")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup("none")))
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
2007-03-13 22:43:22 +00:00
|
|
|
int vlan = 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
while (net) {
|
2007-03-20 16:50:42 +00:00
|
|
|
char nic[100];
|
2007-02-14 15:51:53 +00:00
|
|
|
|
2007-03-20 16:50:42 +00:00
|
|
|
if (snprintf(nic, sizeof(nic), "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d",
|
|
|
|
net->mac[0], net->mac[1],
|
|
|
|
net->mac[2], net->mac[3],
|
|
|
|
net->mac[4], net->mac[5],
|
|
|
|
vlan) >= sizeof(nic))
|
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
if (!((*argv)[++n] = strdup("-net")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup(nic)))
|
|
|
|
goto no_memory;
|
2007-03-13 22:43:22 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-net")))
|
|
|
|
goto no_memory;
|
2007-02-14 16:09:37 +00:00
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
switch (net->type) {
|
|
|
|
case QEMUD_NET_NETWORK:
|
|
|
|
case QEMUD_NET_BRIDGE:
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!((*argv)[++n] = qemudNetworkIfaceConnect(conn, driver, vm, net, vlan)))
|
2007-02-14 16:09:37 +00:00
|
|
|
goto error;
|
2007-03-13 22:43:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMUD_NET_ETHERNET:
|
|
|
|
{
|
|
|
|
char arg[PATH_MAX];
|
|
|
|
if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d",
|
|
|
|
net->dst.ethernet.ifname,
|
|
|
|
net->dst.ethernet.script,
|
|
|
|
vlan) >= (PATH_MAX-1))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!((*argv)[++n] = strdup(arg)))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMUD_NET_CLIENT:
|
|
|
|
case QEMUD_NET_SERVER:
|
|
|
|
case QEMUD_NET_MCAST:
|
|
|
|
{
|
|
|
|
char arg[PATH_MAX];
|
|
|
|
const char *mode = NULL;
|
|
|
|
switch (net->type) {
|
|
|
|
case QEMUD_NET_CLIENT:
|
|
|
|
mode = "connect";
|
|
|
|
break;
|
|
|
|
case QEMUD_NET_SERVER:
|
|
|
|
mode = "listen";
|
|
|
|
break;
|
|
|
|
case QEMUD_NET_MCAST:
|
|
|
|
mode = "mcast";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (snprintf(arg, PATH_MAX-1, "socket,%s=%s:%d,vlan=%d",
|
|
|
|
mode,
|
|
|
|
net->dst.socket.address,
|
|
|
|
net->dst.socket.port,
|
|
|
|
vlan) >= (PATH_MAX-1))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!((*argv)[++n] = strdup(arg)))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMUD_NET_USER:
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
char arg[PATH_MAX];
|
|
|
|
if (snprintf(arg, PATH_MAX-1, "user,vlan=%d", vlan) >= (PATH_MAX-1))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!((*argv)[++n] = strdup(arg)))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
net = net->next;
|
2007-03-13 22:43:22 +00:00
|
|
|
vlan++;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-18 21:08:22 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-usb")))
|
|
|
|
goto no_memory;
|
|
|
|
while (input) {
|
|
|
|
if (input->bus == QEMU_INPUT_BUS_USB) {
|
|
|
|
if (!((*argv)[++n] = strdup("-usbdevice")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup(input->type == QEMU_INPUT_TYPE_MOUSE ? "mouse" : "tablet")))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
input = input->next;
|
|
|
|
}
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
if (vm->def->graphicsType == QEMUD_GRAPHICS_VNC) {
|
2007-10-12 16:05:44 +00:00
|
|
|
char vncdisplay[PATH_MAX];
|
2007-02-23 17:15:18 +00:00
|
|
|
int ret;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
|
|
|
if (vm->qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
|
|
|
|
char options[PATH_MAX] = "";
|
|
|
|
if (driver->vncTLS) {
|
|
|
|
strcat(options, ",tls");
|
|
|
|
if (driver->vncTLSx509verify) {
|
|
|
|
strcat(options, ",x509verify=");
|
|
|
|
} else {
|
|
|
|
strcat(options, ",x509=");
|
|
|
|
}
|
|
|
|
strncat(options, driver->vncTLSx509certdir,
|
|
|
|
sizeof(options) - (strlen(driver->vncTLSx509certdir)-1));
|
|
|
|
options[sizeof(options)-1] = '\0';
|
|
|
|
}
|
|
|
|
ret = snprintf(vncdisplay, sizeof(vncdisplay), "%s:%d%s",
|
2007-07-24 14:30:05 +00:00
|
|
|
vm->def->vncListen,
|
2007-10-12 16:05:44 +00:00
|
|
|
vm->def->vncActivePort - 5900,
|
|
|
|
options);
|
|
|
|
} else {
|
2007-07-24 14:30:05 +00:00
|
|
|
ret = snprintf(vncdisplay, sizeof(vncdisplay), "%d",
|
|
|
|
vm->def->vncActivePort - 5900);
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
2007-07-24 14:30:05 +00:00
|
|
|
if (ret < 0 || ret >= (int)sizeof(vncdisplay))
|
2007-02-23 17:15:18 +00:00
|
|
|
goto error;
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!((*argv)[++n] = strdup("-vnc")))
|
|
|
|
goto no_memory;
|
2007-07-24 14:30:05 +00:00
|
|
|
if (!((*argv)[++n] = strdup(vncdisplay)))
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
} else if (vm->def->graphicsType == QEMUD_GRAPHICS_NONE) {
|
2007-07-24 14:30:05 +00:00
|
|
|
/* Nada - we added -nographic earlier in this function */
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
|
|
|
/* SDL is the default. no args needed */
|
|
|
|
}
|
|
|
|
|
2007-08-14 01:28:47 +00:00
|
|
|
if (vm->migrateFrom[0]) {
|
|
|
|
if (!((*argv)[++n] = strdup("-S")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup("-incoming")))
|
|
|
|
goto no_memory;
|
|
|
|
if (!((*argv)[++n] = strdup(vm->migrateFrom)))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
(*argv)[++n] = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "argv");
|
2007-02-14 16:09:37 +00:00
|
|
|
error:
|
|
|
|
if (vm->tapfds) {
|
|
|
|
for (i = 0; vm->tapfds[i] != -1; i++)
|
|
|
|
close(vm->tapfds[i]);
|
|
|
|
free(vm->tapfds);
|
|
|
|
vm->tapfds = NULL;
|
|
|
|
vm->ntapfds = 0;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
if (argv) {
|
|
|
|
for (i = 0 ; i < n ; i++)
|
2007-02-14 15:51:53 +00:00
|
|
|
free((*argv)[i]);
|
|
|
|
free(*argv);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Save a guest's config data into a persistent file */
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudSaveConfig(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm *vm,
|
|
|
|
struct qemud_vm_def *def) {
|
2007-02-14 01:40:09 +00:00
|
|
|
char *xml;
|
|
|
|
int fd = -1, ret = -1;
|
|
|
|
int towrite;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(xml = qemudGenerateXML(conn, driver, vm, def, 0)))
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ((fd = open(vm->configFile,
|
|
|
|
O_WRONLY | O_CREAT | O_TRUNC,
|
|
|
|
S_IRUSR | S_IWUSR )) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-20 19:09:44 +00:00
|
|
|
"cannot create config file %s: %s",
|
|
|
|
vm->configFile, strerror(errno));
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
towrite = strlen(xml);
|
|
|
|
if (write(fd, xml, towrite) != towrite) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-20 19:09:44 +00:00
|
|
|
"cannot write config file %s: %s",
|
|
|
|
vm->configFile, strerror(errno));
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-20 19:09:44 +00:00
|
|
|
"cannot save config file %s: %s",
|
|
|
|
vm->configFile, strerror(errno));
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (fd != -1)
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
free(xml);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-10-27 01:18:38 +00:00
|
|
|
struct qemud_vm_device_def *
|
|
|
|
qemudParseVMDeviceDef(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
|
|
|
const char *xmlStr)
|
|
|
|
{
|
|
|
|
xmlDocPtr xml;
|
|
|
|
xmlNodePtr node;
|
2007-12-11 21:57:29 +00:00
|
|
|
struct qemud_vm_device_def *dev = calloc(1, sizeof(*dev));
|
2007-10-27 01:18:38 +00:00
|
|
|
|
|
|
|
if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "device.xml", NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, NULL);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
node = xmlDocGetRootElement(xml);
|
|
|
|
if (node == NULL) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, "missing root element");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
|
|
|
|
dev->type = QEMUD_DEVICE_DISK;
|
|
|
|
qemudParseDiskXML(conn, &(dev->data.disk), node);
|
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "net")) {
|
|
|
|
dev->type = QEMUD_DEVICE_NET;
|
|
|
|
qemudParseInterfaceXML(conn, &(dev->data.net), node);
|
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "input")) {
|
|
|
|
dev->type = QEMUD_DEVICE_DISK;
|
|
|
|
qemudParseInputXML(conn, &(dev->data.input), node);
|
|
|
|
} else {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, "unknown device type");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (xml) xmlFreeDoc(xml);
|
|
|
|
if (dev) free(dev);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm_def *
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudParseVMDef(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
const char *xmlStr,
|
|
|
|
const char *displayName) {
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlDocPtr xml;
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm_def *def = NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
if (!(xml = xmlReadDoc(BAD_CAST xmlStr, displayName ? displayName : "domain.xml", NULL,
|
2007-02-14 01:40:09 +00:00
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, NULL);
|
2007-02-14 01:40:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
def = qemudParseXML(conn, driver, xml);
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
xmlFreeDoc(xml);
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qemud_vm *
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudAssignVMDef(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm_def *def)
|
|
|
|
{
|
|
|
|
struct qemud_vm *vm = NULL;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((vm = qemudFindVMByName(driver, def->name))) {
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveVM(vm)) {
|
2007-02-14 17:05:55 +00:00
|
|
|
qemudFreeVMDef(vm->def);
|
|
|
|
vm->def = def;
|
|
|
|
} else {
|
|
|
|
if (vm->newDef)
|
|
|
|
qemudFreeVMDef(vm->newDef);
|
|
|
|
vm->newDef = def;
|
|
|
|
}
|
2007-09-21 21:20:32 +00:00
|
|
|
/* Reset version, because the emulator path might have changed */
|
|
|
|
vm->qemuVersion = 0;
|
|
|
|
vm->qemuCmdFlags = 0;
|
2007-02-23 08:48:02 +00:00
|
|
|
return vm;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(vm = calloc(1, sizeof(*vm)))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "vm");
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-08-14 01:28:47 +00:00
|
|
|
vm->stdin = -1;
|
2007-02-23 08:48:02 +00:00
|
|
|
vm->stdout = -1;
|
|
|
|
vm->stderr = -1;
|
|
|
|
vm->monitor = -1;
|
|
|
|
vm->pid = -1;
|
|
|
|
vm->id = -1;
|
2007-06-26 22:39:53 +00:00
|
|
|
vm->state = VIR_DOMAIN_SHUTOFF;
|
2007-02-23 08:48:02 +00:00
|
|
|
vm->def = def;
|
2007-06-26 22:13:21 +00:00
|
|
|
vm->next = driver->vms;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->vms = vm;
|
|
|
|
driver->ninactivevms++;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveVM(struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm *vm)
|
|
|
|
{
|
|
|
|
struct qemud_vm *prev = NULL, *curr;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
curr = driver->vms;
|
2007-02-23 08:48:02 +00:00
|
|
|
while (curr != vm) {
|
|
|
|
prev = curr;
|
|
|
|
curr = curr->next;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
if (curr) {
|
|
|
|
if (prev)
|
|
|
|
prev->next = curr->next;
|
|
|
|
else
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->vms = curr->next;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->ninactivevms--;
|
2007-02-14 17:05:55 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudFreeVM(vm);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudSaveVMDef(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm *vm,
|
|
|
|
struct qemud_vm_def *def) {
|
|
|
|
if (vm->configFile[0] == '\0') {
|
|
|
|
int err;
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if ((err = virFileMakePath(driver->configDir))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-23 08:48:02 +00:00
|
|
|
"cannot create config directory %s: %s",
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->configDir, strerror(err));
|
2007-02-23 08:48:02 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (virFileBuildPath(driver->configDir, def->name, ".xml",
|
|
|
|
vm->configFile, PATH_MAX) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-23 08:48:02 +00:00
|
|
|
"cannot construct config file path");
|
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 09:07:41 +00:00
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (virFileBuildPath(driver->autostartDir, def->name, ".xml",
|
|
|
|
vm->autostartLink, PATH_MAX) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-23 09:07:41 +00:00
|
|
|
"cannot construct autostart link path");
|
|
|
|
vm->configFile[0] = '\0';
|
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 08:48:02 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
return qemudSaveConfig(conn, driver, vm, def);
|
2007-02-23 08:48:02 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudSaveNetworkConfig(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network *network,
|
|
|
|
struct qemud_network_def *def) {
|
2007-02-14 16:02:40 +00:00
|
|
|
char *xml;
|
|
|
|
int fd, ret = -1;
|
|
|
|
int towrite;
|
2007-02-20 16:55:56 +00:00
|
|
|
int err;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(xml = qemudGenerateNetworkXML(conn, driver, network, def))) {
|
2007-02-14 16:02:40 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if ((err = virFileMakePath(driver->networkConfigDir))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-20 16:55:56 +00:00
|
|
|
"cannot create config directory %s: %s",
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->networkConfigDir, strerror(err));
|
2007-02-14 16:02:40 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = open(network->configFile,
|
|
|
|
O_WRONLY | O_CREAT | O_TRUNC,
|
|
|
|
S_IRUSR | S_IWUSR )) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-20 19:09:44 +00:00
|
|
|
"cannot create config file %s: %s",
|
|
|
|
network->configFile, strerror(errno));
|
2007-02-14 16:02:40 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
towrite = strlen(xml);
|
|
|
|
if (write(fd, xml, towrite) != towrite) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-16 15:03:21 +00:00
|
|
|
"cannot write config file %s: %s",
|
2007-02-20 19:09:44 +00:00
|
|
|
network->configFile, strerror(errno));
|
2007-02-14 16:02:40 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-16 15:03:21 +00:00
|
|
|
"cannot save config file %s: %s",
|
2007-02-20 19:09:44 +00:00
|
|
|
network->configFile, strerror(errno));
|
2007-02-14 16:02:40 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
|
|
|
free(xml);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
void qemudFreeNetworkDef(struct qemud_network_def *def) {
|
|
|
|
struct qemud_dhcp_range_def *range = def->ranges;
|
|
|
|
while (range) {
|
|
|
|
struct qemud_dhcp_range_def *next = range->next;
|
|
|
|
free(range);
|
|
|
|
range = next;
|
|
|
|
}
|
|
|
|
free(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemudFreeNetwork(struct qemud_network *network) {
|
|
|
|
qemudFreeNetworkDef(network->def);
|
|
|
|
if (network->newDef)
|
|
|
|
qemudFreeNetworkDef(network->newDef);
|
|
|
|
free(network);
|
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
static int qemudParseBridgeXML(struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-02-15 16:00:16 +00:00
|
|
|
struct qemud_network_def *def,
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlNodePtr node) {
|
|
|
|
xmlChar *name, *stp, *delay;
|
|
|
|
|
|
|
|
name = xmlGetProp(node, BAD_CAST "name");
|
|
|
|
if (name != NULL) {
|
2007-02-15 16:00:16 +00:00
|
|
|
strncpy(def->bridge, (const char *)name, IF_NAMESIZE-1);
|
|
|
|
def->bridge[IF_NAMESIZE-1] = '\0';
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlFree(name);
|
|
|
|
name = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
stp = xmlGetProp(node, BAD_CAST "stp");
|
|
|
|
if (stp != NULL) {
|
|
|
|
if (xmlStrEqual(stp, BAD_CAST "off")) {
|
2007-02-15 16:00:16 +00:00
|
|
|
def->disableSTP = 1;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
xmlFree(stp);
|
|
|
|
stp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
delay = xmlGetProp(node, BAD_CAST "delay");
|
|
|
|
if (delay != NULL) {
|
2007-02-15 16:00:16 +00:00
|
|
|
def->forwardDelay = strtol((const char *)delay, NULL, 10);
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlFree(delay);
|
|
|
|
delay = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudParseDhcpRangesXML(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-02-15 16:00:16 +00:00
|
|
|
struct qemud_network_def *def,
|
2007-02-14 16:05:29 +00:00
|
|
|
xmlNodePtr node) {
|
|
|
|
|
|
|
|
xmlNodePtr cur;
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
struct qemud_dhcp_range_def *range;
|
|
|
|
xmlChar *start, *end;
|
|
|
|
|
|
|
|
if (cur->type != XML_ELEMENT_NODE ||
|
|
|
|
!xmlStrEqual(cur->name, BAD_CAST "range")) {
|
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(range = calloc(1, sizeof(*range)))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "range");
|
2007-02-14 16:05:29 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = xmlGetProp(cur, BAD_CAST "start");
|
|
|
|
end = xmlGetProp(cur, BAD_CAST "end");
|
|
|
|
|
|
|
|
if (start && start[0] && end && end[0]) {
|
|
|
|
strncpy(range->start, (const char *)start, BR_INET_ADDR_MAXLEN-1);
|
|
|
|
range->start[BR_INET_ADDR_MAXLEN-1] = '\0';
|
|
|
|
|
|
|
|
strncpy(range->end, (const char *)end, BR_INET_ADDR_MAXLEN-1);
|
|
|
|
range->end[BR_INET_ADDR_MAXLEN-1] = '\0';
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
range->next = def->ranges;
|
|
|
|
def->ranges = range;
|
|
|
|
def->nranges++;
|
2007-02-14 16:05:29 +00:00
|
|
|
} else {
|
|
|
|
free(range);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (start)
|
|
|
|
xmlFree(start);
|
|
|
|
if (end)
|
|
|
|
xmlFree(end);
|
|
|
|
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudParseInetXML(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-02-15 16:00:16 +00:00
|
|
|
struct qemud_network_def *def,
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlNodePtr node) {
|
|
|
|
xmlChar *address, *netmask;
|
2007-02-14 16:05:29 +00:00
|
|
|
xmlNodePtr cur;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
address = xmlGetProp(node, BAD_CAST "address");
|
|
|
|
if (address != NULL) {
|
2007-02-15 16:00:16 +00:00
|
|
|
strncpy(def->ipAddress, (const char *)address, BR_INET_ADDR_MAXLEN-1);
|
|
|
|
def->ipAddress[BR_INET_ADDR_MAXLEN-1] = '\0';
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlFree(address);
|
|
|
|
address = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
netmask = xmlGetProp(node, BAD_CAST "netmask");
|
|
|
|
if (netmask != NULL) {
|
2007-02-15 16:00:16 +00:00
|
|
|
strncpy(def->netmask, (const char *)netmask, BR_INET_ADDR_MAXLEN-1);
|
|
|
|
def->netmask[BR_INET_ADDR_MAXLEN-1] = '\0';
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlFree(netmask);
|
|
|
|
netmask = NULL;
|
|
|
|
}
|
|
|
|
|
2007-04-10 23:17:46 +00:00
|
|
|
if (def->ipAddress[0] && def->netmask[0]) {
|
|
|
|
struct in_addr inaddress, innetmask;
|
|
|
|
char *netaddr;
|
|
|
|
|
|
|
|
inet_aton((const char*)def->ipAddress, &inaddress);
|
|
|
|
inet_aton((const char*)def->netmask, &innetmask);
|
|
|
|
|
|
|
|
inaddress.s_addr &= innetmask.s_addr;
|
|
|
|
|
|
|
|
netaddr = inet_ntoa(inaddress);
|
|
|
|
|
|
|
|
snprintf(def->network,sizeof(def->network)-1,
|
|
|
|
"%s/%s", netaddr, (const char *)def->netmask);
|
|
|
|
}
|
|
|
|
|
2007-02-14 16:05:29 +00:00
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "dhcp") &&
|
2007-07-12 15:09:01 +00:00
|
|
|
!qemudParseDhcpRangesXML(conn, driver, def, cur))
|
2007-02-14 16:05:29 +00:00
|
|
|
return 0;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static struct qemud_network_def *qemudParseNetworkXML(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-15 16:00:16 +00:00
|
|
|
xmlDocPtr xml) {
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlNodePtr root = NULL;
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
2007-03-13 22:43:22 +00:00
|
|
|
xmlXPathObjectPtr obj = NULL, tmp = NULL;
|
2007-02-15 16:00:16 +00:00
|
|
|
struct qemud_network_def *def;
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(def = calloc(1, sizeof(*def)))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "network_def");
|
2007-02-15 16:00:16 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
/* Prepare parser / xpath context */
|
|
|
|
root = xmlDocGetRootElement(xml);
|
|
|
|
if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "network"))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "incorrect root element");
|
2007-02-14 16:02:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "xmlXPathContext");
|
2007-02-14 16:02:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Extract network name */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/network/name[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_NAME, NULL);
|
2007-02-14 16:02:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (strlen((const char *)obj->stringval) >= (QEMUD_MAX_NAME_LEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "network name length too long");
|
2007-02-14 16:02:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-15 16:00:16 +00:00
|
|
|
strcpy(def->name, (const char *)obj->stringval);
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
|
|
|
/* Extract network uuid */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/network/uuid[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2007-02-26 15:32:27 +00:00
|
|
|
int err;
|
2007-06-26 22:19:38 +00:00
|
|
|
if ((err = virUUIDGenerate(def->uuid))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-26 15:32:27 +00:00
|
|
|
"Failed to generate UUID: %s", strerror(err));
|
|
|
|
goto error;
|
|
|
|
}
|
2007-06-26 22:19:38 +00:00
|
|
|
} else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "malformed uuid element");
|
2007-02-14 16:02:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
2007-04-10 23:17:46 +00:00
|
|
|
/* Parse bridge information */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/network/bridge[1]", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr > 0)) {
|
2007-06-26 22:13:21 +00:00
|
|
|
if (!qemudParseBridgeXML(driver, def, obj->nodesetval->nodeTab[0])) {
|
2007-04-10 23:17:46 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
/* Parse IP information */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/network/ip[1]", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr > 0)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!qemudParseInetXML(conn, driver, def, obj->nodesetval->nodeTab[0])) {
|
2007-04-10 23:17:46 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
/* IPv4 forwarding setup */
|
2007-03-13 22:43:22 +00:00
|
|
|
obj = xmlXPathEval(BAD_CAST "count(/network/forward) > 0", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_BOOLEAN) &&
|
|
|
|
obj->boolval) {
|
2007-04-10 23:17:46 +00:00
|
|
|
if (!def->ipAddress[0] ||
|
|
|
|
!def->netmask[0]) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-04-10 23:17:46 +00:00
|
|
|
"Forwarding requested, but no IPv4 address/netmask provided");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
def->forward = 1;
|
|
|
|
tmp = xmlXPathEval(BAD_CAST "string(/network/forward[1]/@dev)", ctxt);
|
|
|
|
if ((tmp != NULL) && (tmp->type == XPATH_STRING) &&
|
|
|
|
(tmp->stringval != NULL) && (tmp->stringval[0] != 0)) {
|
|
|
|
int len;
|
|
|
|
if ((len = xmlStrlen(tmp->stringval)) >= (BR_IFNAME_MAXLEN-1)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-03-13 22:43:22 +00:00
|
|
|
"forward device name '%s' is too long",
|
|
|
|
(char*)tmp->stringval);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
strcpy(def->forwardDev, (char*)tmp->stringval);
|
|
|
|
} else {
|
|
|
|
def->forwardDev[0] = '\0';
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(tmp);
|
|
|
|
tmp = NULL;
|
|
|
|
} else {
|
|
|
|
def->forward = 0;
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
return def;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
/* XXX free all the stuff in the qemud_network struct, or leave it upto
|
|
|
|
the caller ? */
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
2007-03-13 22:43:22 +00:00
|
|
|
if (tmp)
|
|
|
|
xmlXPathFreeObject(tmp);
|
2007-02-14 16:02:40 +00:00
|
|
|
if (ctxt)
|
|
|
|
xmlXPathFreeContext(ctxt);
|
2007-02-15 16:00:16 +00:00
|
|
|
qemudFreeNetworkDef(def);
|
|
|
|
return NULL;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network_def *
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudParseNetworkDef(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
const char *xmlStr,
|
|
|
|
const char *displayName) {
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlDocPtr xml;
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network_def *def;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
if (!(xml = xmlReadDoc(BAD_CAST xmlStr, displayName ? displayName : "network.xml", NULL,
|
2007-02-14 16:02:40 +00:00
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, NULL);
|
2007-02-14 16:02:40 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
def = qemudParseNetworkXML(conn, driver, xml);
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
xmlFreeDoc(xml);
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qemud_network *
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudAssignNetworkDef(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network_def *def) {
|
|
|
|
struct qemud_network *network;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((network = qemudFindNetworkByName(driver, def->name))) {
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveNetwork(network)) {
|
2007-02-15 16:00:16 +00:00
|
|
|
qemudFreeNetworkDef(network->def);
|
|
|
|
network->def = def;
|
|
|
|
} else {
|
|
|
|
if (network->newDef)
|
|
|
|
qemudFreeNetworkDef(network->newDef);
|
|
|
|
network->newDef = def;
|
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
return network;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(network = calloc(1, sizeof(*network)))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "network");
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
network->def = def;
|
2007-06-26 22:13:21 +00:00
|
|
|
network->next = driver->networks;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->networks = network;
|
|
|
|
driver->ninactivenetworks++;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
|
|
|
return network;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveNetwork(struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network *network)
|
|
|
|
{
|
|
|
|
struct qemud_network *prev = NULL, *curr;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
curr = driver->networks;
|
2007-02-23 08:48:02 +00:00
|
|
|
while (curr != network) {
|
|
|
|
prev = curr;
|
|
|
|
curr = curr->next;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
if (curr) {
|
|
|
|
if (prev)
|
|
|
|
prev->next = curr->next;
|
|
|
|
else
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->networks = curr->next;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->ninactivenetworks--;
|
2007-02-15 16:00:16 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudFreeNetwork(network);
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudSaveNetworkDef(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network *network,
|
|
|
|
struct qemud_network_def *def) {
|
|
|
|
|
|
|
|
if (network->configFile[0] == '\0') {
|
|
|
|
int err;
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if ((err = virFileMakePath(driver->networkConfigDir))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-23 08:48:02 +00:00
|
|
|
"cannot create config directory %s: %s",
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->networkConfigDir, strerror(err));
|
2007-02-23 08:48:02 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (virFileBuildPath(driver->networkConfigDir, def->name, ".xml",
|
|
|
|
network->configFile, PATH_MAX) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-23 08:48:02 +00:00
|
|
|
"cannot construct config file path");
|
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 09:07:41 +00:00
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (virFileBuildPath(driver->networkAutostartDir, def->name, ".xml",
|
|
|
|
network->autostartLink, PATH_MAX) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2007-02-23 09:07:41 +00:00
|
|
|
"cannot construct autostart link path");
|
|
|
|
network->configFile[0] = '\0';
|
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 08:48:02 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
return qemudSaveNetworkConfig(conn, driver, network, def);
|
2007-02-23 08:48:02 +00:00
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-02-23 09:07:41 +00:00
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
static struct qemud_vm *
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudLoadConfig(struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
const char *file,
|
|
|
|
const char *path,
|
2007-02-23 09:07:41 +00:00
|
|
|
const char *xml,
|
|
|
|
const char *autostartLink) {
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm_def *def;
|
|
|
|
struct qemud_vm *vm;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(def = qemudParseVMDef(NULL, driver, xml, file))) {
|
2007-06-26 20:51:00 +00:00
|
|
|
virErrorPtr err = virGetLastError();
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudLog(QEMUD_WARN, "Error parsing QEMU guest config '%s' : %s",
|
2007-06-26 20:51:00 +00:00
|
|
|
path, err->message);
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudLog(QEMUD_WARN, "QEMU guest config filename '%s' does not match guest name '%s'",
|
|
|
|
path, def->name);
|
|
|
|
qemudFreeVMDef(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(vm = qemudAssignVMDef(NULL, driver, def))) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudLog(QEMUD_WARN, "Failed to load QEMU guest config '%s': out of memory", path);
|
|
|
|
qemudFreeVMDef(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy(vm->configFile, path, PATH_MAX);
|
|
|
|
vm->configFile[PATH_MAX-1] = '\0';
|
|
|
|
|
2007-02-23 09:07:41 +00:00
|
|
|
strncpy(vm->autostartLink, autostartLink, PATH_MAX);
|
|
|
|
vm->autostartLink[PATH_MAX-1] = '\0';
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
vm->autostart = virFileLinkPointsTo(vm->autostartLink, vm->configFile);
|
2007-02-23 09:07:41 +00:00
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct qemud_network *
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudLoadNetworkConfig(struct qemud_driver *driver,
|
2007-02-23 08:48:02 +00:00
|
|
|
const char *file,
|
|
|
|
const char *path,
|
2007-02-23 09:07:41 +00:00
|
|
|
const char *xml,
|
|
|
|
const char *autostartLink) {
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network_def *def;
|
|
|
|
struct qemud_network *network;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(def = qemudParseNetworkDef(NULL, driver, xml, file))) {
|
2007-06-26 20:51:00 +00:00
|
|
|
virErrorPtr err = virGetLastError();
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudLog(QEMUD_WARN, "Error parsing network config '%s' : %s",
|
2007-06-26 20:51:00 +00:00
|
|
|
path, err->message);
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudLog(QEMUD_WARN, "Network config filename '%s' does not match network name '%s'",
|
|
|
|
path, def->name);
|
|
|
|
qemudFreeNetworkDef(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(network = qemudAssignNetworkDef(NULL, driver, def))) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudLog(QEMUD_WARN, "Failed to load network config '%s': out of memory", path);
|
|
|
|
qemudFreeNetworkDef(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy(network->configFile, path, PATH_MAX);
|
|
|
|
network->configFile[PATH_MAX-1] = '\0';
|
|
|
|
|
2007-02-23 09:07:41 +00:00
|
|
|
strncpy(network->autostartLink, autostartLink, PATH_MAX);
|
|
|
|
network->autostartLink[PATH_MAX-1] = '\0';
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
network->autostart = virFileLinkPointsTo(network->autostartLink, network->configFile);
|
2007-02-23 09:07:41 +00:00
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
return network;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-02-14 15:53:14 +00:00
|
|
|
static
|
2007-06-26 22:13:21 +00:00
|
|
|
int qemudScanConfigDir(struct qemud_driver *driver,
|
2007-02-14 16:02:40 +00:00
|
|
|
const char *configDir,
|
2007-02-23 09:07:41 +00:00
|
|
|
const char *autostartDir,
|
2007-02-14 16:02:40 +00:00
|
|
|
int isGuest) {
|
2007-02-14 01:40:09 +00:00
|
|
|
DIR *dir;
|
|
|
|
struct dirent *entry;
|
|
|
|
|
2007-02-14 15:53:14 +00:00
|
|
|
if (!(dir = opendir(configDir))) {
|
2007-02-14 01:40:09 +00:00
|
|
|
if (errno == ENOENT)
|
|
|
|
return 0;
|
2007-02-16 18:30:55 +00:00
|
|
|
qemudLog(QEMUD_ERR, "Failed to open dir '%s': %s",
|
|
|
|
configDir, strerror(errno));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((entry = readdir(dir))) {
|
2008-01-07 15:21:33 +00:00
|
|
|
char *xml;
|
2007-02-23 08:48:02 +00:00
|
|
|
char path[PATH_MAX];
|
2007-02-23 09:07:41 +00:00
|
|
|
char autostartLink[PATH_MAX];
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
if (entry->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (!virFileHasSuffix(entry->d_name, ".xml"))
|
2007-02-23 14:33:37 +00:00
|
|
|
continue;
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (virFileBuildPath(configDir, entry->d_name, NULL, path, PATH_MAX) < 0) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudLog(QEMUD_WARN, "Config filename '%s/%s' is too long",
|
|
|
|
configDir, entry->d_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (virFileBuildPath(autostartDir, entry->d_name, NULL, autostartLink, PATH_MAX) < 0) {
|
2007-02-23 09:07:41 +00:00
|
|
|
qemudLog(QEMUD_WARN, "Autostart link path '%s/%s' is too long",
|
|
|
|
autostartDir, entry->d_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-01-07 15:21:33 +00:00
|
|
|
if (virFileReadAll(path, QEMUD_MAX_XML_LEN, &xml) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
continue;
|
|
|
|
|
2007-02-23 08:48:02 +00:00
|
|
|
if (isGuest)
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudLoadConfig(driver, entry->d_name, path, xml, autostartLink);
|
2007-02-23 08:48:02 +00:00
|
|
|
else
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudLoadNetworkConfig(driver, entry->d_name, path, xml, autostartLink);
|
2008-01-07 15:21:33 +00:00
|
|
|
|
|
|
|
free(xml);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-14 15:53:14 +00:00
|
|
|
/* Scan for all guest and network config files */
|
2007-06-26 22:13:21 +00:00
|
|
|
int qemudScanConfigs(struct qemud_driver *driver) {
|
|
|
|
if (qemudScanConfigDir(driver, driver->configDir, driver->autostartDir, 1) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
return -1;
|
2007-02-23 09:11:52 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if (qemudScanConfigDir(driver, driver->networkConfigDir, driver->networkAutostartDir, 0) < 0)
|
2007-02-23 09:11:52 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2007-02-14 15:53:14 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
/* Generate an XML document describing the guest's configuration */
|
2007-07-12 15:09:01 +00:00
|
|
|
char *qemudGenerateXML(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm *vm,
|
|
|
|
struct qemud_vm_def *def,
|
|
|
|
int live) {
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferPtr buf = 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
unsigned char *uuid;
|
2007-08-09 20:19:12 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2007-02-14 01:40:09 +00:00
|
|
|
struct qemud_vm_disk_def *disk;
|
|
|
|
struct qemud_vm_net_def *net;
|
2007-07-18 21:08:22 +00:00
|
|
|
struct qemud_vm_input_def *input;
|
2007-02-14 01:40:09 +00:00
|
|
|
const char *type = NULL;
|
|
|
|
int n;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
buf = virBufferNew (QEMUD_MAX_XML_LEN);
|
2007-03-15 17:24:56 +00:00
|
|
|
if (!buf)
|
2007-02-26 14:21:21 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
switch (def->virtType) {
|
2007-02-14 01:40:09 +00:00
|
|
|
case QEMUD_VIRT_QEMU:
|
|
|
|
type = "qemu";
|
|
|
|
break;
|
|
|
|
case QEMUD_VIRT_KQEMU:
|
|
|
|
type = "kqemu";
|
|
|
|
break;
|
|
|
|
case QEMUD_VIRT_KVM:
|
|
|
|
type = "kvm";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!type) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "unexpected domain type %d", def->virtType);
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2007-02-23 08:39:49 +00:00
|
|
|
if (qemudIsActiveVM(vm) && live) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, "<domain type='%s' id='%d'>\n", type, vm->id) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, "<domain type='%s'>\n", type) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <name>%s</name>\n", def->name) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
uuid = def->uuid;
|
2007-08-09 20:19:12 +00:00
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
if (virBufferVSprintf(buf, " <uuid>%s</uuid>\n", uuidstr) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <memory>%d</memory>\n", def->maxmem) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <currentMemory>%d</currentMemory>\n", def->memory) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <vcpu>%d</vcpu>\n", def->vcpus) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <os>\n", -1) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
if (def->virtType == QEMUD_VIRT_QEMU) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <type arch='%s' machine='%s'>%s</type>\n",
|
2007-02-14 17:05:55 +00:00
|
|
|
def->os.arch, def->os.machine, def->os.type) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <type>%s</type>\n", def->os.type) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
if (def->os.kernel[0])
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <kernel>%s</kernel>\n", def->os.kernel) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
if (def->os.initrd[0])
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <initrd>%s</initrd>\n", def->os.initrd) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
2007-02-14 17:05:55 +00:00
|
|
|
if (def->os.cmdline[0])
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <cmdline>%s</cmdline>\n", def->os.cmdline) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
for (n = 0 ; n < def->os.nBootDevs ; n++) {
|
2007-02-14 01:40:09 +00:00
|
|
|
const char *boottype = "hd";
|
2007-02-14 17:05:55 +00:00
|
|
|
switch (def->os.bootDevs[n]) {
|
2007-02-14 01:40:09 +00:00
|
|
|
case QEMUD_BOOT_FLOPPY:
|
|
|
|
boottype = "fd";
|
|
|
|
break;
|
|
|
|
case QEMUD_BOOT_DISK:
|
|
|
|
boottype = "hd";
|
|
|
|
break;
|
|
|
|
case QEMUD_BOOT_CDROM:
|
|
|
|
boottype = "cdrom";
|
|
|
|
break;
|
|
|
|
case QEMUD_BOOT_NET:
|
2007-09-13 22:06:54 +00:00
|
|
|
boottype = "network";
|
2007-02-14 01:40:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <boot dev='%s'/>\n", boottype) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " </os>\n", -1) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 21:47:59 +00:00
|
|
|
if (def->features & QEMUD_FEATURE_ACPI) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <features>\n", -1) < 0)
|
2007-02-14 21:47:59 +00:00
|
|
|
goto no_memory;
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <acpi/>\n", -1) < 0)
|
2007-02-14 21:47:59 +00:00
|
|
|
goto no_memory;
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " </features>\n", -1) < 0)
|
2007-02-14 21:47:59 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-07-16 21:30:30 +00:00
|
|
|
virBufferVSprintf(buf, " <clock offset='%s'/>\n", def->localtime ? "localtime" : "utc");
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <on_poweroff>destroy</on_poweroff>\n", -1) < 0)
|
2007-05-03 16:10:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
if (def->noReboot) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <on_reboot>destroy</on_reboot>\n", -1) < 0)
|
2007-05-03 16:10:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <on_reboot>restart</on_reboot>\n", -1) < 0)
|
2007-05-03 16:10:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <on_crash>destroy</on_crash>\n", -1) < 0)
|
2007-05-03 16:10:40 +00:00
|
|
|
goto no_memory;
|
2007-02-14 21:47:59 +00:00
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <devices>\n", -1) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <emulator>%s</emulator>\n", def->os.binary) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
disk = def->disks;
|
2007-02-14 01:40:09 +00:00
|
|
|
while (disk) {
|
|
|
|
const char *types[] = {
|
|
|
|
"block",
|
|
|
|
"file",
|
|
|
|
};
|
|
|
|
const char *typeAttrs[] = {
|
|
|
|
"dev",
|
|
|
|
"file",
|
|
|
|
};
|
|
|
|
const char *devices[] = {
|
|
|
|
"disk",
|
|
|
|
"cdrom",
|
|
|
|
"floppy",
|
|
|
|
};
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <disk type='%s' device='%s'>\n",
|
2007-02-14 01:40:09 +00:00
|
|
|
types[disk->type], devices[disk->device]) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <source %s='%s'/>\n", typeAttrs[disk->type], disk->src) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <target dev='%s'/>\n", disk->dst) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (disk->readonly)
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <readonly/>\n", -1) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " </disk>\n") < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
disk = disk->next;
|
|
|
|
}
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
net = def->nets;
|
2007-02-14 15:51:53 +00:00
|
|
|
while (net) {
|
2007-02-14 01:40:09 +00:00
|
|
|
const char *types[] = {
|
|
|
|
"user",
|
2007-03-13 22:43:22 +00:00
|
|
|
"ethernet",
|
2007-02-14 01:40:09 +00:00
|
|
|
"server",
|
|
|
|
"client",
|
|
|
|
"mcast",
|
2007-02-15 19:08:08 +00:00
|
|
|
"network",
|
2007-03-13 22:43:22 +00:00
|
|
|
"bridge",
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <interface type='%s'>\n",
|
2007-02-14 01:40:09 +00:00
|
|
|
types[net->type]) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
|
2007-02-14 01:40:09 +00:00
|
|
|
net->mac[0], net->mac[1], net->mac[2],
|
|
|
|
net->mac[3], net->mac[4], net->mac[5]) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
switch (net->type) {
|
|
|
|
case QEMUD_NET_NETWORK:
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <source network='%s'/>\n", net->dst.network.name) < 0)
|
2007-02-14 16:09:37 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
if (net->dst.network.ifname[0] != '\0') {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <target dev='%s'/>\n", net->dst.network.ifname) < 0)
|
2007-03-13 22:43:22 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
break;
|
2007-02-14 16:09:37 +00:00
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
case QEMUD_NET_ETHERNET:
|
|
|
|
if (net->dst.ethernet.ifname[0] != '\0') {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <target dev='%s'/>\n", net->dst.ethernet.ifname) < 0)
|
2007-03-13 22:43:22 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
if (net->dst.ethernet.script[0] != '\0') {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <script path='%s'/>\n", net->dst.ethernet.script) < 0)
|
2007-03-13 22:43:22 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMUD_NET_BRIDGE:
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <source bridge='%s'/>\n", net->dst.bridge.brname) < 0)
|
2007-02-14 16:09:37 +00:00
|
|
|
goto no_memory;
|
2007-03-13 22:43:22 +00:00
|
|
|
if (net->dst.bridge.ifname[0] != '\0') {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <target dev='%s'/>\n", net->dst.bridge.ifname) < 0)
|
2007-03-13 22:43:22 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMUD_NET_SERVER:
|
|
|
|
case QEMUD_NET_CLIENT:
|
|
|
|
case QEMUD_NET_MCAST:
|
|
|
|
if (net->dst.socket.address[0] != '\0') {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <source address='%s' port='%d'/>\n",
|
2007-03-13 22:43:22 +00:00
|
|
|
net->dst.socket.address, net->dst.socket.port) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <source port='%d'/>\n",
|
2007-03-13 22:43:22 +00:00
|
|
|
net->dst.socket.port) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " </interface>\n") < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-14 15:51:53 +00:00
|
|
|
net = net->next;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-07-18 21:08:22 +00:00
|
|
|
input = def->inputs;
|
|
|
|
while (input) {
|
|
|
|
if (input->bus != QEMU_INPUT_BUS_PS2 &&
|
|
|
|
virBufferVSprintf(buf, " <input type='%s' bus='usb'/>\n",
|
|
|
|
input->type == QEMU_INPUT_TYPE_MOUSE ? "mouse" : "tablet") < 0)
|
|
|
|
goto no_memory;
|
|
|
|
input = input->next;
|
|
|
|
}
|
|
|
|
/* If graphics is enable, add implicit mouse */
|
|
|
|
if (def->graphicsType != QEMUD_GRAPHICS_NONE)
|
|
|
|
if (virBufferAdd(buf, " <input type='mouse' bus='ps2'/>\n", -1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-15 19:07:06 +00:00
|
|
|
switch (def->graphicsType) {
|
|
|
|
case QEMUD_GRAPHICS_VNC:
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <graphics type='vnc'", -1) < 0)
|
2007-02-15 19:07:06 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (def->vncPort &&
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferVSprintf(buf, " port='%d'",
|
2007-02-23 08:39:49 +00:00
|
|
|
qemudIsActiveVM(vm) && live ? def->vncActivePort : def->vncPort) < 0)
|
2007-02-15 19:07:06 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-07-24 14:30:05 +00:00
|
|
|
if (def->vncListen[0] &&
|
|
|
|
virBufferVSprintf(buf, " listen='%s'",
|
|
|
|
def->vncListen) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, "/>\n", -1) < 0)
|
2007-02-15 19:07:06 +00:00
|
|
|
goto no_memory;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMUD_GRAPHICS_SDL:
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <graphics type='sdl'/>\n", -1) < 0)
|
2007-02-15 19:07:06 +00:00
|
|
|
goto no_memory;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMUD_GRAPHICS_NONE:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-02-14 17:05:55 +00:00
|
|
|
if (def->graphicsType == QEMUD_GRAPHICS_VNC) {
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " </devices>\n", -1) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, "</domain>\n", -1) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
return virBufferContentAndFree (buf);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
no_memory:
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "xml");
|
2007-02-14 01:40:09 +00:00
|
|
|
cleanup:
|
2007-06-26 22:21:22 +00:00
|
|
|
if (buf) virBufferFree (buf);
|
2007-02-14 01:40:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
char *qemudGenerateNetworkXML(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-04-10 23:17:46 +00:00
|
|
|
struct qemud_network *network,
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network_def *def) {
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferPtr buf = 0;
|
2007-02-14 16:02:40 +00:00
|
|
|
unsigned char *uuid;
|
2007-08-09 20:19:12 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
buf = virBufferNew (QEMUD_MAX_XML_LEN);
|
2007-03-15 17:24:56 +00:00
|
|
|
if (!buf)
|
2007-02-26 14:21:21 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, "<network>\n") < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <name>%s</name>\n", def->name) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
uuid = def->uuid;
|
2007-08-09 20:19:12 +00:00
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
if (virBufferVSprintf(buf, " <uuid>%s</uuid>\n", uuidstr) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
if (def->forward) {
|
|
|
|
if (def->forwardDev[0]) {
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferVSprintf(buf, " <forward dev='%s'/>\n",
|
2007-03-13 22:43:22 +00:00
|
|
|
def->forwardDev);
|
|
|
|
} else {
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferAdd(buf, " <forward/>\n", -1);
|
2007-03-13 22:43:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferAdd(buf, " <bridge", -1);
|
2007-04-10 23:17:46 +00:00
|
|
|
if (qemudIsActiveNetwork(network)) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " name='%s'", network->bridge) < 0)
|
2007-04-10 23:17:46 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else if (def->bridge[0]) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " name='%s'", def->bridge) < 0)
|
2007-04-10 23:17:46 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " stp='%s' forwardDelay='%d' />\n",
|
2007-04-10 23:17:46 +00:00
|
|
|
def->disableSTP ? "off" : "on",
|
|
|
|
def->forwardDelay) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
if (def->ipAddress[0] || def->netmask[0]) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <ip", -1) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
if (def->ipAddress[0] &&
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferVSprintf(buf, " address='%s'", def->ipAddress) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
if (def->netmask[0] &&
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferVSprintf(buf, " netmask='%s'", def->netmask) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, ">\n", -1) < 0)
|
2007-02-14 16:05:29 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-02-15 16:00:16 +00:00
|
|
|
if (def->ranges) {
|
|
|
|
struct qemud_dhcp_range_def *range = def->ranges;
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " <dhcp>\n", -1) < 0)
|
2007-02-14 16:05:29 +00:00
|
|
|
goto no_memory;
|
|
|
|
while (range) {
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferVSprintf(buf, " <range start='%s' end='%s' />\n",
|
2007-02-14 16:05:29 +00:00
|
|
|
range->start, range->end) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
range = range->next;
|
|
|
|
}
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " </dhcp>\n", -1) < 0)
|
2007-02-14 16:05:29 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, " </ip>\n", -1) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
if (virBufferAdd(buf, "</network>\n", -1) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2007-06-26 22:21:22 +00:00
|
|
|
return virBufferContentAndFree (buf);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
no_memory:
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "xml");
|
2007-06-26 22:21:22 +00:00
|
|
|
if (buf) virBufferFree (buf);
|
2007-02-14 16:02:40 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
int qemudDeleteConfig(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-02-14 16:02:40 +00:00
|
|
|
const char *configFile,
|
|
|
|
const char *name) {
|
|
|
|
if (!configFile[0]) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "no config file for %s", name);
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
if (unlink(configFile) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot remove config for %s", name);
|
2007-02-14 16:02:40 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-14 15:58:21 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-26 11:50:16 +00:00
|
|
|
#endif /* WITH_QEMU */
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* c-indent-level: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 4
|
|
|
|
* End:
|
|
|
|
*/
|