2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* config.c: VM configuration management
|
|
|
|
*
|
2009-01-30 17:15:39 +00:00
|
|
|
* Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
|
2007-02-14 01:40:09 +00:00
|
|
|
* 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>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-11-26 11:50:16 +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>
|
2008-10-10 16:52:20 +00:00
|
|
|
#include <stdlib.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
#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
|
|
|
|
2008-11-04 22:30:33 +00:00
|
|
|
#include "virterror_internal.h"
|
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"
|
2008-05-22 15:29:50 +00:00
|
|
|
#include "memory.h"
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
#include "verify.h"
|
2008-12-20 13:09:45 +00:00
|
|
|
#include "datatypes.h"
|
|
|
|
#include "xml.h"
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#include "nodeinfo.h"
|
2008-07-11 19:34:11 +00:00
|
|
|
|
2009-01-23 16:22:20 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
VIR_ENUM_DECL(virDomainDiskQEMUBus)
|
|
|
|
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
|
|
|
|
"ide",
|
|
|
|
"floppy",
|
|
|
|
"scsi",
|
|
|
|
"virtio",
|
2008-08-08 15:03:00 +00:00
|
|
|
"xen",
|
2008-11-19 16:58:23 +00:00
|
|
|
"usb",
|
|
|
|
"uml")
|
2008-07-11 19:34:11 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
|
2009-01-30 17:15:39 +00:00
|
|
|
VIR_ENUM_DECL(qemuDiskCacheV1)
|
|
|
|
VIR_ENUM_DECL(qemuDiskCacheV2)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
|
|
|
|
"default",
|
|
|
|
"off",
|
|
|
|
"off", /* writethrough not supported, so for safety, disable */
|
|
|
|
"on"); /* Old 'on' was equivalent to 'writeback' */
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
|
|
|
|
"default",
|
|
|
|
"none",
|
|
|
|
"writethrough",
|
|
|
|
"writeback");
|
|
|
|
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
#define qemudLog(level, msg...) fprintf(stderr, msg)
|
|
|
|
|
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 */
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!(driver->vncListen = strdup("127.0.0.1"))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(NULL);
|
2008-07-11 19:34:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-10-12 16:05:44 +00:00
|
|
|
if (!(driver->vncTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-vnc"))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(NULL);
|
2007-10-12 16:05:44 +00:00
|
|
|
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) {
|
2008-05-29 19:20:22 +00:00
|
|
|
VIR_FREE(driver->vncTLSx509certdir);
|
2007-10-12 16:05:44 +00:00
|
|
|
if (!(driver->vncTLSx509certdir = strdup(p->str))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(NULL);
|
2007-10-12 16:05:44 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_listen");
|
|
|
|
CHECK_TYPE ("vnc_listen", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
2008-11-05 14:24:21 +00:00
|
|
|
VIR_FREE(driver->vncListen);
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!(driver->vncListen = strdup(p->str))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(NULL);
|
2008-07-11 19:34:11 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
|
|
|
|
2009-01-29 17:50:00 +00:00
|
|
|
p = virConfGetValue (conf, "vnc_password");
|
|
|
|
CHECK_TYPE ("vnc_password", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
|
|
|
VIR_FREE(driver->vncPassword);
|
|
|
|
if (!(driver->vncPassword = strdup(p->str))) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
virConfFree (conf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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 */
|
2008-02-27 04:35:08 +00:00
|
|
|
static const char *const arch_info_hvm_x86_machines[] = {
|
|
|
|
"pc", "isapc"
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
2008-02-27 04:35:08 +00:00
|
|
|
static const char *const arch_info_hvm_mips_machines[] = {
|
|
|
|
"mips"
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
2008-02-27 04:35:08 +00:00
|
|
|
static const char *const arch_info_hvm_sparc_machines[] = {
|
|
|
|
"sun4m"
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
2008-02-27 04:35:08 +00:00
|
|
|
static const char *const arch_info_hvm_ppc_machines[] = {
|
|
|
|
"g3bw", "mac99", "prep"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *const arch_info_xen_x86_machines[] = {
|
|
|
|
"xenner"
|
|
|
|
};
|
|
|
|
|
|
|
|
struct qemu_feature_flags {
|
|
|
|
const char *name;
|
|
|
|
const int default_on;
|
|
|
|
const int toggle;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct qemu_arch_info {
|
|
|
|
const char *arch;
|
|
|
|
int wordsize;
|
|
|
|
const char *const *machines;
|
|
|
|
int nmachines;
|
|
|
|
const char *binary;
|
|
|
|
const struct qemu_feature_flags *flags;
|
|
|
|
int nflags;
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
|
2007-07-30 09:59:05 +00:00
|
|
|
/* Feature flags for the architecture info */
|
2008-01-14 14:05:25 +00:00
|
|
|
static const struct qemu_feature_flags const arch_info_i686_flags [] = {
|
2008-02-27 04:35:08 +00:00
|
|
|
{ "pae", 1, 0 },
|
|
|
|
{ "nonpae", 1, 0 },
|
2007-07-30 09:59:05 +00:00
|
|
|
{ "acpi", 1, 1 },
|
|
|
|
{ "apic", 1, 0 },
|
|
|
|
};
|
|
|
|
|
2008-01-14 14:05:25 +00:00
|
|
|
static const struct qemu_feature_flags const arch_info_x86_64_flags [] = {
|
2007-07-30 09:59:05 +00:00
|
|
|
{ "acpi", 1, 1 },
|
|
|
|
{ "apic", 1, 0 },
|
|
|
|
};
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/* The archicture tables for supported QEMU archs */
|
2008-02-27 04:35:08 +00:00
|
|
|
static const struct qemu_arch_info const arch_info_hvm[] = {
|
|
|
|
{ "i686", 32, arch_info_hvm_x86_machines, 2,
|
|
|
|
"/usr/bin/qemu", arch_info_i686_flags, 4 },
|
|
|
|
{ "x86_64", 64, arch_info_hvm_x86_machines, 2,
|
|
|
|
"/usr/bin/qemu-system-x86_64", arch_info_x86_64_flags, 2 },
|
|
|
|
{ "mips", 32, arch_info_hvm_mips_machines, 1,
|
|
|
|
"/usr/bin/qemu-system-mips", NULL, 0 },
|
|
|
|
{ "mipsel", 32, arch_info_hvm_mips_machines, 1,
|
|
|
|
"/usr/bin/qemu-system-mipsel", NULL, 0 },
|
|
|
|
{ "sparc", 32, arch_info_hvm_sparc_machines, 1,
|
|
|
|
"/usr/bin/qemu-system-sparc", NULL, 0 },
|
|
|
|
{ "ppc", 32, arch_info_hvm_ppc_machines, 3,
|
|
|
|
"/usr/bin/qemu-system-ppc", NULL, 0 },
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
static const struct qemu_arch_info const arch_info_xen[] = {
|
|
|
|
{ "i686", 32, arch_info_xen_x86_machines, 1,
|
|
|
|
"/usr/bin/xenner", arch_info_i686_flags, 4 },
|
|
|
|
{ "x86_64", 64, arch_info_xen_x86_machines, 1,
|
|
|
|
"/usr/bin/xenner", arch_info_x86_64_flags, 2 },
|
|
|
|
};
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
static int
|
|
|
|
qemudCapsInitGuest(virCapsPtr caps,
|
|
|
|
const char *hostmachine,
|
|
|
|
const struct qemu_arch_info *info,
|
|
|
|
int hvm) {
|
|
|
|
virCapsGuestPtr guest;
|
2008-09-02 15:00:09 +00:00
|
|
|
int i, haskvm, hasbase, samearch;
|
|
|
|
const char *kvmbin = NULL;
|
|
|
|
|
|
|
|
/* Check for existance of base emulator */
|
|
|
|
hasbase = (access(info->binary, X_OK) == 0);
|
|
|
|
|
|
|
|
samearch = STREQ(info->arch, hostmachine);
|
|
|
|
if (samearch) {
|
|
|
|
const char *const kvmbins[] = { "/usr/bin/qemu-kvm", /* Fedora */
|
|
|
|
"/usr/bin/kvm" }; /* Upstream .spec */
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) {
|
|
|
|
if ((haskvm = (access(kvmbins[i], X_OK) == 0))) {
|
|
|
|
kvmbin = kvmbins[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
haskvm = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasbase && !haskvm)
|
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if ((guest = virCapabilitiesAddGuest(caps,
|
|
|
|
hvm ? "hvm" : "xen",
|
|
|
|
info->arch,
|
|
|
|
info->wordsize,
|
|
|
|
info->binary,
|
|
|
|
NULL,
|
|
|
|
info->nmachines,
|
|
|
|
info->machines)) == NULL)
|
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if (hvm) {
|
2008-09-02 15:00:09 +00:00
|
|
|
if (hasbase &&
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesAddGuestDomain(guest,
|
|
|
|
"qemu",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL) == NULL)
|
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
/* If guest & host match, then we can accelerate */
|
2008-09-02 15:00:09 +00:00
|
|
|
if (samearch) {
|
2008-02-27 04:35:08 +00:00
|
|
|
if (access("/dev/kqemu", F_OK) == 0 &&
|
|
|
|
virCapabilitiesAddGuestDomain(guest,
|
|
|
|
"kqemu",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL) == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (access("/dev/kvm", F_OK) == 0 &&
|
2008-09-02 15:00:09 +00:00
|
|
|
haskvm &&
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesAddGuestDomain(guest,
|
|
|
|
"kvm",
|
2008-09-02 15:00:09 +00:00
|
|
|
kvmbin,
|
2008-02-27 04:35:08 +00:00
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL) == NULL)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virCapabilitiesAddGuestDomain(guest,
|
|
|
|
"kvm",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL) == NULL)
|
|
|
|
return -1;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if (info->nflags) {
|
|
|
|
for (i = 0 ; i < info->nflags ; i++) {
|
|
|
|
if (virCapabilitiesAddGuestFeature(guest,
|
|
|
|
info->flags[i].name,
|
|
|
|
info->flags[i].default_on,
|
|
|
|
info->flags[i].toggle) == NULL)
|
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapsPtr qemudCapsInit(void) {
|
|
|
|
struct utsname utsname;
|
|
|
|
virCapsPtr caps;
|
|
|
|
int i;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
/* Really, this never fails - look at the man-page. */
|
|
|
|
uname (&utsname);
|
|
|
|
|
|
|
|
if ((caps = virCapabilitiesNew(utsname.machine,
|
|
|
|
0, 0)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
|
2008-10-24 11:20:08 +00:00
|
|
|
/* Using KVM's mac prefix for QEMU too */
|
|
|
|
virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });
|
|
|
|
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
if (virCapsInitNUMA(caps) < 0)
|
2008-05-22 15:29:50 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2008-10-28 17:43:24 +00:00
|
|
|
for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
|
2008-02-27 04:35:08 +00:00
|
|
|
if (qemudCapsInitGuest(caps,
|
|
|
|
utsname.machine,
|
|
|
|
&arch_info_hvm[i], 1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (access("/usr/bin/xenner", X_OK) == 0 &&
|
|
|
|
access("/dev/kvm", F_OK) == 0) {
|
2008-10-28 17:43:24 +00:00
|
|
|
for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_xen) ; i++)
|
2008-02-27 04:35:08 +00:00
|
|
|
/* Allow Xen 32-on-32, 32-on-64 and 64-on-64 */
|
|
|
|
if (STREQ(arch_info_xen[i].arch, utsname.machine) ||
|
|
|
|
(STREQ(utsname.machine, "x86_64") &&
|
|
|
|
STREQ(arch_info_xen[i].arch, "i686"))) {
|
|
|
|
if (qemudCapsInitGuest(caps,
|
|
|
|
utsname.machine,
|
|
|
|
&arch_info_xen[i], 0) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
return caps;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virCapabilitiesFree(caps);
|
|
|
|
return NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
int qemudExtractVersionInfo(const char *qemu,
|
|
|
|
unsigned int *retversion,
|
|
|
|
unsigned int *retflags) {
|
|
|
|
const char *const qemuarg[] = { qemu, "-help", NULL };
|
|
|
|
const char *const qemuenv[] = { "LC_ALL=C", NULL };
|
2007-02-23 17:15:18 +00:00
|
|
|
pid_t child;
|
2008-08-29 07:11:15 +00:00
|
|
|
int newstdout = -1;
|
2008-09-02 10:30:40 +00:00
|
|
|
int ret = -1, status;
|
2008-08-29 07:11:15 +00:00
|
|
|
unsigned int major, minor, micro;
|
2009-01-27 11:12:05 +00:00
|
|
|
unsigned int version, kvm_version;
|
2008-08-29 07:11:15 +00:00
|
|
|
unsigned int flags = 0;
|
|
|
|
|
|
|
|
if (retflags)
|
|
|
|
*retflags = 0;
|
|
|
|
if (retversion)
|
|
|
|
*retversion = 0;
|
|
|
|
|
|
|
|
if (virExec(NULL, qemuarg, qemuenv, NULL,
|
|
|
|
&child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
|
|
|
|
return -1;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-09-02 10:30:40 +00:00
|
|
|
char *help = NULL;
|
|
|
|
enum { MAX_HELP_OUTPUT_SIZE = 8192 };
|
|
|
|
int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help);
|
|
|
|
if (len < 0)
|
|
|
|
goto cleanup2;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2009-01-27 11:12:05 +00:00
|
|
|
if (sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u)",
|
|
|
|
&major, &minor, µ, &kvm_version) != 4)
|
|
|
|
kvm_version = 0;
|
|
|
|
|
|
|
|
if (!kvm_version && sscanf(help, "QEMU PC emulator version %u.%u.%u",
|
|
|
|
&major, &minor, µ) != 3)
|
2008-08-29 07:11:15 +00:00
|
|
|
goto cleanup2;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
version = (major * 1000 * 1000) + (minor * 1000) + micro;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
if (strstr(help, "-no-kqemu"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_KQEMU;
|
|
|
|
if (strstr(help, "-no-reboot"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_NO_REBOOT;
|
|
|
|
if (strstr(help, "-name"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_NAME;
|
2008-11-04 22:15:30 +00:00
|
|
|
if (strstr(help, "-uuid"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_UUID;
|
|
|
|
if (strstr(help, "-domid"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DOMID;
|
2009-01-30 17:15:39 +00:00
|
|
|
if (strstr(help, "-drive")) {
|
2008-08-29 07:11:15 +00:00
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE;
|
2009-01-30 17:15:39 +00:00
|
|
|
if (strstr(help, "cache=writethrough|writeback|none"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE_CACHE_V2;
|
|
|
|
}
|
2008-08-29 07:11:15 +00:00
|
|
|
if (strstr(help, "boot=on"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
|
|
|
|
if (version >= 9000)
|
|
|
|
flags |= QEMUD_CMD_FLAG_VNC_COLON;
|
2009-01-27 11:12:05 +00:00
|
|
|
if (kvm_version >= 74)
|
|
|
|
flags |= QEMUD_CMD_FLAG_VNET_HDR;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2009-01-29 17:27:54 +00:00
|
|
|
/*
|
|
|
|
* Handling of -incoming arg with varying features
|
|
|
|
* -incoming tcp (kvm >= 79)
|
|
|
|
* -incoming exec (kvm >= 80)
|
|
|
|
* -incoming stdio (all earlier kvm)
|
|
|
|
*
|
|
|
|
* NB, there was a pre-kvm-79 'tcp' support, but it
|
|
|
|
* was broken, because it blocked the monitor console
|
|
|
|
* while waiting for data, so pretend it doesn't exist
|
|
|
|
*
|
|
|
|
* XXX when next QEMU release after 0.9.1 arrives,
|
|
|
|
* we'll need to add MIGRATE_QEMU_TCP/EXEC here too
|
|
|
|
*/
|
|
|
|
if (kvm_version >= 79) {
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
|
|
|
|
if (kvm_version >= 80)
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
|
|
|
|
} else if (kvm_version > 0) {
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO;
|
|
|
|
}
|
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
if (retversion)
|
|
|
|
*retversion = version;
|
|
|
|
if (retflags)
|
|
|
|
*retflags = flags;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
ret = 0;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d",
|
|
|
|
major, minor, micro, version, flags);
|
2009-01-27 11:12:05 +00:00
|
|
|
if (kvm_version)
|
|
|
|
qemudDebug("KVM version %d detected", kvm_version);
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
cleanup2:
|
2008-09-02 10:30:40 +00:00
|
|
|
VIR_FREE(help);
|
2008-08-29 07:11:15 +00:00
|
|
|
if (close(newstdout) < 0)
|
|
|
|
ret = -1;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
rewait:
|
|
|
|
if (waitpid(child, &status, 0) != child) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto rewait;
|
|
|
|
|
|
|
|
qemudLog(QEMUD_ERR,
|
|
|
|
_("Unexpected exit status from qemu %d pid %lu"),
|
|
|
|
WEXITSTATUS(status), (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(status) != 0) {
|
|
|
|
qemudLog(QEMUD_WARN,
|
|
|
|
_("Unexpected exit status '%d', qemu probably failed"),
|
|
|
|
WEXITSTATUS(status));
|
2007-02-23 17:15:18 +00:00
|
|
|
}
|
2008-08-29 07:11:15 +00:00
|
|
|
|
|
|
|
return ret;
|
2007-02-23 17:15:18 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
int qemudExtractVersion(virConnectPtr conn,
|
2008-02-27 04:35:08 +00:00
|
|
|
struct qemud_driver *driver) {
|
|
|
|
const char *binary;
|
2007-04-16 13:14:28 +00:00
|
|
|
struct stat sb;
|
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;
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
|
|
|
|
"hvm",
|
2008-07-11 19:34:11 +00:00
|
|
|
"i686",
|
|
|
|
"qemu")) == NULL)
|
|
|
|
return -1;
|
2007-07-18 21:08:22 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (stat(binary, &sb) < 0) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot find QEMU binary %s: %s"), binary,
|
|
|
|
strerror(errno));
|
|
|
|
return -1;
|
2007-07-18 21:08:22 +00:00
|
|
|
}
|
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
|
2008-07-11 19:34:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
return 0;
|
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,
|
2008-07-11 19:34:11 +00:00
|
|
|
int **tapfds,
|
|
|
|
int *ntapfds,
|
|
|
|
virDomainNetDefPtr net,
|
2009-01-27 11:12:05 +00:00
|
|
|
int vlan,
|
|
|
|
int vnet_hdr)
|
2007-02-14 16:09:37 +00:00
|
|
|
{
|
2007-03-13 22:43:22 +00:00
|
|
|
char *brname;
|
2007-02-14 16:09:37 +00:00
|
|
|
char tapfdstr[4+3+32+7];
|
|
|
|
char *retval = NULL;
|
|
|
|
int err;
|
|
|
|
int tapfd = -1;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
2008-10-10 13:57:13 +00:00
|
|
|
virNetworkPtr network = virNetworkLookupByName(conn,
|
|
|
|
net->data.network.name);
|
|
|
|
if (!network) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError: mark for translation string args to this function
* Makefile.maint (msg_gen_function): Add qemudReportError.
* src/qemu_conf.c (qemudLoadDriverConfig)
(qemudExtractVersion, qemudParseDiskXML, qemudParseInterfaceXML)
(qemudParseInputXML, qemudParseXML, qemudNetworkIfaceConnect)
(qemudBuildCommandLine, qemudSaveConfig, qemudParseVMDeviceDef)
(qemudAssignVMDef, qemudSaveVMDef, qemudSaveNetworkConfig)
(qemudParseDhcpRangesXML, qemudParseNetworkXML)
(qemudAssignNetworkDef, qemudSaveNetworkDef, qemudGenerateXML)
(qemudGenerateNetworkXML, qemudDeleteConfig): Mark strings.
* src/qemu_driver.c (qemudBuildDnsmasqArgv, qemudAddIptablesRules)
(qemudGetCapabilities, qemudDomainGetOSType)
(qemudListDefinedDomains, qemudListNetworks)
(qemudListDefinedNetworks, qemudNetworkGetBridgeName): Mark strings.
2008-03-27 13:53:14 +00:00
|
|
|
_("Network '%s' not found"),
|
2008-07-11 19:34:11 +00:00
|
|
|
net->data.network.name);
|
2007-03-13 22:43:22 +00:00
|
|
|
goto error;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
brname = virNetworkGetBridgeName(network);
|
|
|
|
|
|
|
|
virNetworkFree(network);
|
|
|
|
|
|
|
|
if (brname == NULL) {
|
2007-03-13 22:43:22 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2008-07-11 19:34:11 +00:00
|
|
|
} else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
|
|
|
brname = net->data.bridge.brname;
|
2007-03-13 22:43:22 +00:00
|
|
|
} else {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError: mark for translation string args to this function
* Makefile.maint (msg_gen_function): Add qemudReportError.
* src/qemu_conf.c (qemudLoadDriverConfig)
(qemudExtractVersion, qemudParseDiskXML, qemudParseInterfaceXML)
(qemudParseInputXML, qemudParseXML, qemudNetworkIfaceConnect)
(qemudBuildCommandLine, qemudSaveConfig, qemudParseVMDeviceDef)
(qemudAssignVMDef, qemudSaveVMDef, qemudSaveNetworkConfig)
(qemudParseDhcpRangesXML, qemudParseNetworkXML)
(qemudAssignNetworkDef, qemudSaveNetworkDef, qemudGenerateXML)
(qemudGenerateNetworkXML, qemudDeleteConfig): Mark strings.
* src/qemu_driver.c (qemudBuildDnsmasqArgv, qemudAddIptablesRules)
(qemudGetCapabilities, qemudDomainGetOSType)
(qemudListDefinedDomains, qemudListNetworks)
(qemudListDefinedNetworks, qemudNetworkGetBridgeName): Mark strings.
2008-03-27 13:53:14 +00:00
|
|
|
_("Network type %d is not supported"), net->type);
|
2007-02-14 16:09:37 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!net->ifname ||
|
|
|
|
STRPREFIX(net->ifname, "vnet") ||
|
|
|
|
strchr(net->ifname, '%')) {
|
|
|
|
VIR_FREE(net->ifname);
|
|
|
|
if (!(net->ifname = strdup("vnet%d"))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 19:34:11 +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,
|
qemudReportError: mark for translation string args to this function
* Makefile.maint (msg_gen_function): Add qemudReportError.
* src/qemu_conf.c (qemudLoadDriverConfig)
(qemudExtractVersion, qemudParseDiskXML, qemudParseInterfaceXML)
(qemudParseInputXML, qemudParseXML, qemudNetworkIfaceConnect)
(qemudBuildCommandLine, qemudSaveConfig, qemudParseVMDeviceDef)
(qemudAssignVMDef, qemudSaveVMDef, qemudSaveNetworkConfig)
(qemudParseDhcpRangesXML, qemudParseNetworkXML)
(qemudAssignNetworkDef, qemudSaveNetworkDef, qemudGenerateXML)
(qemudGenerateNetworkXML, qemudDeleteConfig): Mark strings.
* src/qemu_driver.c (qemudBuildDnsmasqArgv, qemudAddIptablesRules)
(qemudGetCapabilities, qemudDomainGetOSType)
(qemudListDefinedDomains, qemudListNetworks)
(qemudListDefinedNetworks, qemudNetworkGetBridgeName): Mark strings.
2008-03-27 13:53:14 +00:00
|
|
|
_("cannot initialize bridge support: %s"),
|
|
|
|
strerror(err));
|
2007-05-14 15:41:57 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = brAddTap(driver->brctl, brname,
|
2009-01-27 11:12:05 +00:00
|
|
|
&net->ifname, vnet_hdr, &tapfd))) {
|
2008-07-09 05:24:08 +00:00
|
|
|
if (errno == ENOTSUP) {
|
|
|
|
/* In this particular case, give a better diagnostic. */
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to add tap interface to bridge. "
|
|
|
|
"%s is not a bridge device"), brname);
|
|
|
|
} else {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to add tap interface '%s' "
|
|
|
|
"to bridge '%s' : %s"),
|
2008-07-11 19:34:11 +00:00
|
|
|
net->ifname, brname, strerror(err));
|
2008-07-09 05:24:08 +00:00
|
|
|
}
|
2007-02-14 16:09:37 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-03-14 20:30:03 +00:00
|
|
|
snprintf(tapfdstr, sizeof(tapfdstr),
|
|
|
|
"tap,fd=%d,script=,vlan=%d,ifname=%s",
|
2008-07-11 19:34:11 +00:00
|
|
|
tapfd, vlan, net->ifname);
|
2007-02-14 16:09:37 +00:00
|
|
|
|
|
|
|
if (!(retval = strdup(tapfdstr)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0)
|
2007-02-14 16:09:37 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
(*tapfds)[(*ntapfds)++] = tapfd;
|
2007-02-14 16:09:37 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
no_memory:
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2007-02-14 16:09:37 +00:00
|
|
|
error:
|
2008-05-29 19:20:22 +00:00
|
|
|
VIR_FREE(retval);
|
2007-02-14 16:09:37 +00:00
|
|
|
if (tapfd != -1)
|
|
|
|
close(tapfd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-01-30 17:15:39 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
|
2008-04-25 20:46:13 +00:00
|
|
|
char *buf,
|
|
|
|
int buflen)
|
|
|
|
{
|
2008-07-11 19:34:11 +00:00
|
|
|
switch (dev->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_NULL:
|
2008-04-25 20:46:13 +00:00
|
|
|
strncpy(buf, "null", buflen);
|
|
|
|
buf[buflen-1] = '\0';
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_VC:
|
2008-04-25 20:46:13 +00:00
|
|
|
strncpy(buf, "vc", buflen);
|
|
|
|
buf[buflen-1] = '\0';
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
2008-04-25 20:46:13 +00:00
|
|
|
strncpy(buf, "pty", buflen);
|
|
|
|
buf[buflen-1] = '\0';
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_DEV:
|
2008-04-25 20:46:13 +00:00
|
|
|
if (snprintf(buf, buflen, "%s",
|
2008-07-11 19:34:11 +00:00
|
|
|
dev->data.file.path) >= buflen)
|
2008-04-25 20:46:13 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
2008-04-25 20:46:13 +00:00
|
|
|
if (snprintf(buf, buflen, "file:%s",
|
2008-07-11 19:34:11 +00:00
|
|
|
dev->data.file.path) >= buflen)
|
2008-04-25 20:46:13 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
2008-04-25 20:46:13 +00:00
|
|
|
if (snprintf(buf, buflen, "pipe:%s",
|
2008-07-11 19:34:11 +00:00
|
|
|
dev->data.file.path) >= buflen)
|
2008-04-25 20:46:13 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
2008-04-25 20:46:13 +00:00
|
|
|
strncpy(buf, "stdio", buflen);
|
|
|
|
buf[buflen-1] = '\0';
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
2008-04-25 20:46:13 +00:00
|
|
|
if (snprintf(buf, buflen, "udp:%s:%s@%s:%s",
|
2008-07-11 19:34:11 +00:00
|
|
|
dev->data.udp.connectHost,
|
|
|
|
dev->data.udp.connectService,
|
|
|
|
dev->data.udp.bindHost,
|
|
|
|
dev->data.udp.bindService) >= buflen)
|
2008-04-25 20:46:13 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
2008-08-15 10:02:33 +00:00
|
|
|
if (dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) {
|
|
|
|
if (snprintf(buf, buflen, "telnet:%s:%s%s",
|
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
2008-12-12 09:39:31 +00:00
|
|
|
dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
|
2008-08-15 10:02:33 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (snprintf(buf, buflen, "tcp:%s:%s%s",
|
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
2008-12-12 09:39:31 +00:00
|
|
|
dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
|
2008-08-15 10:02:33 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
2008-04-25 20:46:13 +00:00
|
|
|
if (snprintf(buf, buflen, "unix:%s%s",
|
2008-07-11 19:34:11 +00:00
|
|
|
dev->data.nix.path,
|
2008-12-12 09:39:31 +00:00
|
|
|
dev->data.nix.listen ? ",server,nowait" : "") >= buflen)
|
2008-04-25 20:46:13 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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,
|
2008-07-11 19:34:11 +00:00
|
|
|
virDomainObjPtr vm,
|
2008-08-29 07:11:15 +00:00
|
|
|
unsigned int qemuCmdFlags,
|
2008-08-08 15:43:38 +00:00
|
|
|
const char ***retargv,
|
2008-10-10 16:52:20 +00:00
|
|
|
const char ***retenv,
|
2008-07-11 19:34:11 +00:00
|
|
|
int **tapfds,
|
|
|
|
int *ntapfds,
|
|
|
|
const char *migrateFrom) {
|
2008-05-22 23:45:09 +00:00
|
|
|
int i;
|
2007-02-14 01:40:09 +00:00
|
|
|
char memory[50];
|
|
|
|
char vcpus[50];
|
2008-07-11 19:34:11 +00:00
|
|
|
char boot[VIR_DOMAIN_BOOT_LAST];
|
2007-04-16 13:14:28 +00:00
|
|
|
struct utsname ut;
|
|
|
|
int disableKQEMU = 0;
|
2008-05-22 23:45:09 +00:00
|
|
|
int qargc = 0, qarga = 0;
|
2008-08-08 15:43:38 +00:00
|
|
|
const char **qargv = NULL;
|
2008-10-10 16:52:20 +00:00
|
|
|
int qenvc = 0, qenva = 0;
|
|
|
|
const char **qenv = NULL;
|
2008-09-05 11:52:12 +00:00
|
|
|
const char *emulator;
|
2008-11-04 22:15:30 +00:00
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char domid[50];
|
2008-12-18 15:22:49 +00:00
|
|
|
char *pidfile;
|
2007-02-14 01:40:09 +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
|
|
|
|
2008-11-04 22:15:30 +00:00
|
|
|
virUUIDFormat(vm->def->uuid, uuid);
|
|
|
|
|
2009-01-29 17:27:54 +00:00
|
|
|
/* Migration is very annoying due to wildly varying syntax & capabilities
|
|
|
|
* over time of KVM / QEMU codebases
|
|
|
|
*/
|
|
|
|
if (migrateFrom) {
|
|
|
|
if (STRPREFIX(migrateFrom, "tcp")) {
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP)) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("TCP migration is not supported with this QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (STREQ(migrateFrom, "stdio")) {
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
|
|
|
|
migrateFrom = "exec:cat";
|
|
|
|
} else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO)) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("STDIO migration is not supported with this QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (STRPREFIX(migrateFrom, "exec")) {
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("STDIO migration is not supported with this QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
*/
|
2008-07-11 19:34:11 +00:00
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) &&
|
2008-05-14 19:51:24 +00:00
|
|
|
STREQ(ut.machine, vm->def->os.arch) &&
|
2008-07-11 19:34:11 +00:00
|
|
|
vm->def->virtType == VIR_DOMAIN_VIRT_QEMU)
|
2007-04-16 13:14:28 +00:00
|
|
|
disableKQEMU = 1;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
#define ADD_ARG_SPACE \
|
|
|
|
do { \
|
|
|
|
if (qargc == qarga) { \
|
|
|
|
qarga += 10; \
|
|
|
|
if (VIR_REALLOC_N(qargv, qarga) < 0) \
|
|
|
|
goto no_memory; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ARG(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ARG_SPACE; \
|
|
|
|
qargv[qargc++] = thisarg; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ARG_LIT(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ARG_SPACE; \
|
|
|
|
if ((qargv[qargc++] = strdup(thisarg)) == NULL) \
|
|
|
|
goto no_memory; \
|
|
|
|
} while (0)
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-08-08 15:03:00 +00:00
|
|
|
#define ADD_USBDISK(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ARG_LIT("-usbdevice"); \
|
|
|
|
ADD_ARG_SPACE; \
|
2008-12-23 13:03:29 +00:00
|
|
|
if ((virAsprintf((char **)&(qargv[qargc++]), \
|
|
|
|
"disk:%s", thisarg)) == -1) { \
|
2008-08-08 15:03:00 +00:00
|
|
|
goto no_memory; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2008-10-10 16:52:20 +00:00
|
|
|
#define ADD_ENV_SPACE \
|
|
|
|
do { \
|
|
|
|
if (qenvc == qenva) { \
|
|
|
|
qenva += 10; \
|
|
|
|
if (VIR_REALLOC_N(qenv, qenva) < 0) \
|
|
|
|
goto no_memory; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ENV(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ENV_SPACE; \
|
|
|
|
qenv[qenvc++] = thisarg; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ENV_LIT(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ENV_SPACE; \
|
|
|
|
if ((qenv[qenvc++] = strdup(thisarg)) == NULL) \
|
|
|
|
goto no_memory; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ENV_COPY(envname) \
|
|
|
|
do { \
|
|
|
|
char *val = getenv(envname); \
|
|
|
|
char *envval; \
|
|
|
|
ADD_ENV_SPACE; \
|
|
|
|
if (val != NULL) { \
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&envval, "%s=%s", envname, val) < 0) \
|
2008-10-10 16:52:20 +00:00
|
|
|
goto no_memory; \
|
|
|
|
qenv[qenvc++] = envval; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2008-03-19 14:32:50 +00:00
|
|
|
snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024);
|
2008-07-11 19:34:11 +00:00
|
|
|
snprintf(vcpus, sizeof(vcpus), "%lu", vm->def->vcpus);
|
2008-11-04 22:15:30 +00:00
|
|
|
snprintf(domid, sizeof(domid), "%d", vm->def->id);
|
2008-12-18 15:22:49 +00:00
|
|
|
pidfile = virFilePid(driver->stateDir, vm->def->name);
|
|
|
|
if (!pidfile)
|
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-10-10 16:52:20 +00:00
|
|
|
ADD_ENV_LIT("LC_ALL=C");
|
|
|
|
|
|
|
|
ADD_ENV_COPY("LD_PRELOAD");
|
|
|
|
ADD_ENV_COPY("LD_LIBRARY_PATH");
|
|
|
|
ADD_ENV_COPY("PATH");
|
|
|
|
ADD_ENV_COPY("HOME");
|
|
|
|
ADD_ENV_COPY("USER");
|
|
|
|
ADD_ENV_COPY("LOGNAME");
|
|
|
|
ADD_ENV_COPY("TMPDIR");
|
|
|
|
|
2008-09-05 11:52:12 +00:00
|
|
|
emulator = vm->def->emulator;
|
|
|
|
if (!emulator)
|
|
|
|
emulator = virDomainDefDefaultEmulator(conn, vm->def, driver->caps);
|
|
|
|
if (!emulator)
|
|
|
|
return -1;
|
2008-05-22 23:45:09 +00:00
|
|
|
|
2008-09-09 13:44:42 +00:00
|
|
|
ADD_ARG_LIT(emulator);
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-S");
|
2009-01-30 17:12:28 +00:00
|
|
|
|
|
|
|
/* This should *never* be NULL, since we always provide
|
|
|
|
* a machine in the capabilities data for QEMU. So this
|
|
|
|
* check is just here as a safety in case the unexpected
|
|
|
|
* happens */
|
|
|
|
if (vm->def->os.machine) {
|
|
|
|
ADD_ARG_LIT("-M");
|
|
|
|
ADD_ARG_LIT(vm->def->os.machine);
|
|
|
|
}
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
if (disableKQEMU)
|
|
|
|
ADD_ARG_LIT("-no-kqemu");
|
|
|
|
ADD_ARG_LIT("-m");
|
|
|
|
ADD_ARG_LIT(memory);
|
|
|
|
ADD_ARG_LIT("-smp");
|
|
|
|
ADD_ARG_LIT(vcpus);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-name");
|
|
|
|
ADD_ARG_LIT(vm->def->name);
|
2008-05-15 16:15:17 +00:00
|
|
|
}
|
2008-11-04 22:15:30 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_UUID) {
|
|
|
|
ADD_ARG_LIT("-uuid");
|
|
|
|
ADD_ARG_LIT(uuid);
|
|
|
|
}
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
|
|
|
|
ADD_ARG_LIT("-domid");
|
|
|
|
ADD_ARG_LIT(domid);
|
|
|
|
}
|
|
|
|
|
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...
|
|
|
|
*/
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!vm->def->graphics)
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-nographic");
|
2007-07-24 14:30:05 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-monitor");
|
|
|
|
ADD_ARG_LIT("pty");
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-12-18 15:22:49 +00:00
|
|
|
ADD_ARG_LIT("-pidfile");
|
|
|
|
ADD_ARG(pidfile);
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
if (vm->def->localtime)
|
|
|
|
ADD_ARG_LIT("-localtime");
|
2007-07-16 21:30:30 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
|
|
|
|
vm->def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-no-reboot");
|
2007-05-03 16:10:40 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!(vm->def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-no-acpi");
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!vm->def->os.bootloader) {
|
2008-05-15 16:21:11 +00:00
|
|
|
for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
|
|
|
|
switch (vm->def->os.bootDevs[i]) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_CDROM:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'd';
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_FLOPPY:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'a';
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_DISK:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_NET:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'n';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boot[vm->def->os.nBootDevs] = '\0';
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-boot");
|
|
|
|
ADD_ARG_LIT(boot);
|
2008-05-15 16:21:11 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (vm->def->os.kernel) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-kernel");
|
|
|
|
ADD_ARG_LIT(vm->def->os.kernel);
|
2008-05-15 16:21:11 +00:00
|
|
|
}
|
2008-07-11 19:34:11 +00:00
|
|
|
if (vm->def->os.initrd) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-initrd");
|
|
|
|
ADD_ARG_LIT(vm->def->os.initrd);
|
2008-05-15 16:21:11 +00:00
|
|
|
}
|
2008-07-11 19:34:11 +00:00
|
|
|
if (vm->def->os.cmdline) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-append");
|
|
|
|
ADD_ARG_LIT(vm->def->os.cmdline);
|
2008-05-15 16:21:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-bootloader");
|
|
|
|
ADD_ARG_LIT(vm->def->os.bootloader);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-01-23 16:22:20 +00:00
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
virDomainDiskDefPtr disk = vm->def->disks[i];
|
|
|
|
|
|
|
|
if (disk->driverName != NULL &&
|
|
|
|
!STREQ(disk->driverName, "qemu")) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported driver name '%s' for disk '%s'"),
|
|
|
|
disk->driverName, disk->src);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-09 16:41:19 +00:00
|
|
|
/* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
|
2008-05-09 16:41:19 +00:00
|
|
|
int bootCD = 0, bootFloppy = 0, bootDisk = 0;
|
|
|
|
|
|
|
|
/* If QEMU supports boot=on for -drive param... */
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) {
|
2008-05-09 16:41:19 +00:00
|
|
|
for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
|
|
|
|
switch (vm->def->os.bootDevs[i]) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_CDROM:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootCD = 1;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_FLOPPY:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootFloppy = 1;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_DISK:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootDisk = 1;
|
|
|
|
break;
|
|
|
|
}
|
2008-03-13 09:17:45 +00:00
|
|
|
}
|
2008-05-09 16:41:19 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
2009-01-23 16:22:20 +00:00
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *optstr;
|
2008-05-09 16:41:19 +00:00
|
|
|
int bootable = 0;
|
2008-10-10 16:08:01 +00:00
|
|
|
virDomainDiskDefPtr disk = vm->def->disks[i];
|
2008-05-09 16:41:19 +00:00
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
2008-07-11 19:34:11 +00:00
|
|
|
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-08-08 15:03:00 +00:00
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
ADD_USBDISK(disk->src);
|
|
|
|
} else {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported usb disk type for '%s'"), disk->src);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-05-09 16:41:19 +00:00
|
|
|
if (idx < 0) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (disk->device) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_DISK_DEVICE_CDROM:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootable = bootCD;
|
|
|
|
bootCD = 0;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootable = bootFloppy;
|
|
|
|
bootFloppy = 0;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_DISK_DEVICE_DISK:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootable = bootDisk;
|
|
|
|
bootDisk = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-01-23 16:22:20 +00:00
|
|
|
virBufferVSprintf(&opt, "file=%s", disk->src ? disk->src : "");
|
|
|
|
virBufferVSprintf(&opt, ",if=%s", bus);
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
virBufferAddLit(&opt, ",media=cdrom");
|
|
|
|
virBufferVSprintf(&opt, ",index=%d", idx);
|
|
|
|
if (bootable &&
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
|
|
|
|
virBufferAddLit(&opt, ",boot=on");
|
|
|
|
if (disk->driverType)
|
|
|
|
virBufferVSprintf(&opt, ",fmt=%s", disk->driverType);
|
|
|
|
|
2009-01-30 17:15:39 +00:00
|
|
|
if (disk->cachemode) {
|
|
|
|
const char *mode =
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_CACHE_V2) ?
|
|
|
|
qemuDiskCacheV2TypeToString(disk->cachemode) :
|
|
|
|
qemuDiskCacheV1TypeToString(disk->cachemode);
|
|
|
|
|
|
|
|
virBufferVSprintf(&opt, ",cache=%s", mode);
|
|
|
|
} else if (disk->shared && !disk->readonly) {
|
|
|
|
virBufferAddLit(&opt, ",cache=off");
|
|
|
|
}
|
|
|
|
|
2009-01-23 16:22:20 +00:00
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
optstr = virBufferContentAndReset(&opt);
|
2008-05-09 16:41:19 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-drive");
|
2009-01-23 16:22:20 +00:00
|
|
|
ADD_ARG(optstr);
|
2008-05-09 16:41:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
2008-05-09 16:41:19 +00:00
|
|
|
char dev[NAME_MAX];
|
|
|
|
char file[PATH_MAX];
|
2008-10-10 16:08:01 +00:00
|
|
|
virDomainDiskDefPtr disk = vm->def->disks[i];
|
2008-05-09 16:41:19 +00:00
|
|
|
|
2008-08-08 15:03:00 +00:00
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
ADD_USBDISK(disk->src);
|
|
|
|
} else {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported usb disk type for '%s'"), disk->src);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-05-09 16:41:19 +00:00
|
|
|
if (STREQ(disk->dst, "hdc") &&
|
2008-07-11 19:34:11 +00:00
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
|
|
|
|
if (disk->src) {
|
2008-05-09 16:41:19 +00:00
|
|
|
snprintf(dev, NAME_MAX, "-%s", "cdrom");
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (STRPREFIX(disk->dst, "hd") ||
|
|
|
|
STRPREFIX(disk->dst, "fd")) {
|
|
|
|
snprintf(dev, NAME_MAX, "-%s", disk->dst);
|
|
|
|
} else {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(file, PATH_MAX, "%s", disk->src);
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT(dev);
|
|
|
|
ADD_ARG_LIT(file);
|
2008-05-09 16:41:19 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
if (!vm->def->nnets) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-net");
|
|
|
|
ADD_ARG_LIT("none");
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
2007-03-13 22:43:22 +00:00
|
|
|
int vlan = 0;
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->nnets ; i++) {
|
2007-03-20 16:50:42 +00:00
|
|
|
char nic[100];
|
2008-10-10 16:08:01 +00:00
|
|
|
virDomainNetDefPtr net = vm->def->nets[i];
|
2007-02-14 15:51:53 +00:00
|
|
|
|
2008-04-30 12:30:55 +00:00
|
|
|
if (snprintf(nic, sizeof(nic),
|
|
|
|
"nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s",
|
2007-03-20 16:50:42 +00:00
|
|
|
net->mac[0], net->mac[1],
|
|
|
|
net->mac[2], net->mac[3],
|
|
|
|
net->mac[4], net->mac[5],
|
2008-04-30 12:30:55 +00:00
|
|
|
vlan,
|
2008-07-11 19:34:11 +00:00
|
|
|
(net->model ? ",model=" : ""),
|
|
|
|
(net->model ? net->model : "")) >= sizeof(nic))
|
2007-03-20 16:50:42 +00:00
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-net");
|
|
|
|
ADD_ARG_LIT(nic);
|
|
|
|
ADD_ARG_LIT("-net");
|
2007-02-14 16:09:37 +00:00
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
switch (net->type) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
2008-06-12 10:19:24 +00:00
|
|
|
{
|
2009-01-27 11:12:05 +00:00
|
|
|
char *tap;
|
|
|
|
int vnet_hdr = 0;
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
|
|
|
|
net->model && STREQ(net->model, "virtio"))
|
|
|
|
vnet_hdr = 1;
|
|
|
|
|
|
|
|
tap = qemudNetworkIfaceConnect(conn, driver,
|
|
|
|
tapfds, ntapfds,
|
|
|
|
net, vlan, vnet_hdr);
|
2008-06-12 10:19:24 +00:00
|
|
|
if (tap == NULL)
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(tap);
|
|
|
|
break;
|
|
|
|
}
|
2007-03-13 22:43:22 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
2007-03-13 22:43:22 +00:00
|
|
|
{
|
|
|
|
char arg[PATH_MAX];
|
|
|
|
if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d",
|
2008-07-11 19:34:11 +00:00
|
|
|
net->ifname,
|
|
|
|
net->data.ethernet.script,
|
2007-03-13 22:43:22 +00:00
|
|
|
vlan) >= (PATH_MAX-1))
|
|
|
|
goto error;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT(arg);
|
2007-03-13 22:43:22 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
2007-03-13 22:43:22 +00:00
|
|
|
{
|
|
|
|
char arg[PATH_MAX];
|
|
|
|
const char *mode = NULL;
|
|
|
|
switch (net->type) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
2007-03-13 22:43:22 +00:00
|
|
|
mode = "connect";
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
2007-03-13 22:43:22 +00:00
|
|
|
mode = "listen";
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
2007-03-13 22:43:22 +00:00
|
|
|
mode = "mcast";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (snprintf(arg, PATH_MAX-1, "socket,%s=%s:%d,vlan=%d",
|
|
|
|
mode,
|
2008-07-11 19:34:11 +00:00
|
|
|
net->data.socket.address,
|
|
|
|
net->data.socket.port,
|
2007-03-13 22:43:22 +00:00
|
|
|
vlan) >= (PATH_MAX-1))
|
|
|
|
goto error;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT(arg);
|
2007-03-13 22:43:22 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
2007-03-13 22:43:22 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
char arg[PATH_MAX];
|
|
|
|
if (snprintf(arg, PATH_MAX-1, "user,vlan=%d", vlan) >= (PATH_MAX-1))
|
|
|
|
goto error;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT(arg);
|
2007-03-13 22:43:22 +00:00
|
|
|
}
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
vlan++;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
if (!vm->def->nserials) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-serial");
|
|
|
|
ADD_ARG_LIT("none");
|
2008-04-25 20:46:13 +00:00
|
|
|
} else {
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->nserials ; i++) {
|
2008-04-25 20:46:13 +00:00
|
|
|
char buf[4096];
|
2008-10-10 16:08:01 +00:00
|
|
|
virDomainChrDefPtr serial = vm->def->serials[i];
|
2008-04-25 20:46:13 +00:00
|
|
|
|
|
|
|
if (qemudBuildCommandLineChrDevStr(serial, buf, sizeof(buf)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-serial");
|
|
|
|
ADD_ARG_LIT(buf);
|
2008-04-25 20:46:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
if (!vm->def->nparallels) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-parallel");
|
|
|
|
ADD_ARG_LIT("none");
|
2008-04-25 20:46:13 +00:00
|
|
|
} else {
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->nparallels ; i++) {
|
2008-04-25 20:46:13 +00:00
|
|
|
char buf[4096];
|
2008-10-10 16:08:01 +00:00
|
|
|
virDomainChrDefPtr parallel = vm->def->parallels[i];
|
2008-04-25 20:46:13 +00:00
|
|
|
|
|
|
|
if (qemudBuildCommandLineChrDevStr(parallel, buf, sizeof(buf)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-parallel");
|
|
|
|
ADD_ARG_LIT(buf);
|
2008-04-25 20:46:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-usb");
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->ninputs ; i++) {
|
|
|
|
virDomainInputDefPtr input = vm->def->inputs[i];
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-usbdevice");
|
2008-07-11 19:34:11 +00:00
|
|
|
ADD_ARG_LIT(input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet");
|
2007-07-18 21:08:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (vm->def->graphics &&
|
|
|
|
vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *optstr;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
|
2009-01-29 17:50:00 +00:00
|
|
|
if (vm->def->graphics->data.vnc.listenAddr)
|
|
|
|
virBufferAdd(&opt, vm->def->graphics->data.vnc.listenAddr, -1);
|
|
|
|
else if (driver->vncListen)
|
|
|
|
virBufferAdd(&opt, driver->vncListen, -1);
|
|
|
|
|
|
|
|
virBufferVSprintf(&opt, ":%d",
|
|
|
|
vm->def->graphics->data.vnc.port - 5900);
|
|
|
|
|
|
|
|
if (vm->def->graphics->data.vnc.passwd ||
|
|
|
|
driver->vncPassword)
|
|
|
|
virBufferAddLit(&opt, ",password");
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
if (driver->vncTLS) {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferAddLit(&opt, ",tls");
|
2007-10-12 16:05:44 +00:00
|
|
|
if (driver->vncTLSx509verify) {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferVSprintf(&opt, ",x509verify=%s",
|
|
|
|
driver->vncTLSx509certdir);
|
2007-10-12 16:05:44 +00:00
|
|
|
} else {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferVSprintf(&opt, ",x509=%s",
|
|
|
|
driver->vncTLSx509certdir);
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferVSprintf(&opt, "%d",
|
|
|
|
vm->def->graphics->data.vnc.port - 5900);
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
2009-01-29 17:50:00 +00:00
|
|
|
if (virBufferError(&opt))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
optstr = virBufferContentAndReset(&opt);
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-vnc");
|
2009-01-29 17:50:00 +00:00
|
|
|
ADD_ARG(optstr);
|
2008-07-11 19:34:11 +00:00
|
|
|
if (vm->def->graphics->data.vnc.keymap) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-k");
|
2008-07-11 19:34:11 +00:00
|
|
|
ADD_ARG_LIT(vm->def->graphics->data.vnc.keymap);
|
2008-01-15 15:18:33 +00:00
|
|
|
}
|
2008-07-11 19:34:11 +00:00
|
|
|
} else if (vm->def->graphics &&
|
|
|
|
vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
|
2008-10-10 16:52:20 +00:00
|
|
|
char *xauth = NULL;
|
|
|
|
char *display = NULL;
|
|
|
|
|
|
|
|
if (vm->def->graphics->data.sdl.xauth &&
|
2008-12-23 13:03:29 +00:00
|
|
|
virAsprintf(&xauth, "XAUTHORITY=%s",
|
|
|
|
vm->def->graphics->data.sdl.xauth) < 0)
|
2008-10-10 16:52:20 +00:00
|
|
|
goto no_memory;
|
|
|
|
if (vm->def->graphics->data.sdl.display &&
|
2008-12-23 13:03:29 +00:00
|
|
|
virAsprintf(&display, "DISPLAY=%s",
|
|
|
|
vm->def->graphics->data.sdl.display) < 0) {
|
2008-10-10 16:52:20 +00:00
|
|
|
VIR_FREE(xauth);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xauth)
|
|
|
|
ADD_ENV(xauth);
|
|
|
|
if (display)
|
|
|
|
ADD_ENV(display);
|
2008-12-11 11:44:30 +00:00
|
|
|
if (vm->def->graphics->data.sdl.fullscreen)
|
|
|
|
ADD_ARG_LIT("-full-screen");
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2008-05-07 14:04:40 +00:00
|
|
|
/* Add sound hardware */
|
2008-10-10 16:08:01 +00:00
|
|
|
if (vm->def->nsounds) {
|
2008-05-07 14:04:40 +00:00
|
|
|
int size = 100;
|
2008-05-29 19:20:22 +00:00
|
|
|
char *modstr;
|
|
|
|
if (VIR_ALLOC_N(modstr, size+1) < 0)
|
2008-05-07 14:04:40 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->nsounds && size > 0 ; i++) {
|
|
|
|
virDomainSoundDefPtr sound = vm->def->sounds[i];
|
2008-07-11 19:34:11 +00:00
|
|
|
const char *model = virDomainSoundModelTypeToString(sound->model);
|
2008-05-07 14:04:40 +00:00
|
|
|
if (!model) {
|
2008-05-29 19:20:22 +00:00
|
|
|
VIR_FREE(modstr);
|
2008-05-13 09:15:11 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid sound model"));
|
|
|
|
goto error;
|
2008-05-07 14:04:40 +00:00
|
|
|
}
|
|
|
|
strncat(modstr, model, size);
|
|
|
|
size -= strlen(model);
|
2008-10-10 16:08:01 +00:00
|
|
|
if (i < (vm->def->nsounds - 1))
|
2008-05-07 14:04:40 +00:00
|
|
|
strncat(modstr, ",", size--);
|
|
|
|
}
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-soundhw");
|
|
|
|
ADD_ARG(modstr);
|
2008-05-07 14:04:40 +00:00
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
/* Add host passthrough hardware */
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
2008-08-08 14:27:05 +00:00
|
|
|
int ret;
|
|
|
|
char* usbdev;
|
2009-01-07 12:56:13 +00:00
|
|
|
char* pcidev;
|
2008-10-10 16:08:01 +00:00
|
|
|
virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
|
2008-08-08 14:27:05 +00:00
|
|
|
|
2009-01-07 12:56:13 +00:00
|
|
|
/* USB */
|
2008-08-08 14:27:05 +00:00
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
2008-12-17 18:12:07 +00:00
|
|
|
if(hostdev->source.subsys.u.usb.vendor) {
|
2008-12-23 13:03:29 +00:00
|
|
|
ret = virAsprintf(&usbdev, "host:%.4x:%.4x",
|
2008-12-17 18:12:07 +00:00
|
|
|
hostdev->source.subsys.u.usb.vendor,
|
|
|
|
hostdev->source.subsys.u.usb.product);
|
2008-08-08 14:27:05 +00:00
|
|
|
|
|
|
|
} else {
|
2008-12-23 13:03:29 +00:00
|
|
|
ret = virAsprintf(&usbdev, "host:%.3d.%.3d",
|
2008-12-17 18:12:07 +00:00
|
|
|
hostdev->source.subsys.u.usb.bus,
|
|
|
|
hostdev->source.subsys.u.usb.device);
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
2008-12-23 13:03:29 +00:00
|
|
|
if (ret < 0)
|
2008-08-08 14:27:05 +00:00
|
|
|
goto error;
|
2008-12-23 13:03:29 +00:00
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
ADD_ARG_LIT("-usbdevice");
|
|
|
|
ADD_ARG_LIT(usbdev);
|
|
|
|
VIR_FREE(usbdev);
|
|
|
|
}
|
2009-01-07 12:56:13 +00:00
|
|
|
|
|
|
|
/* PCI */
|
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
|
|
|
ret = virAsprintf(&pcidev, "host=%.2x:%.2x.%.1x",
|
|
|
|
hostdev->source.subsys.u.pci.bus,
|
|
|
|
hostdev->source.subsys.u.pci.slot,
|
|
|
|
hostdev->source.subsys.u.pci.function);
|
|
|
|
if (ret < 0) {
|
|
|
|
pcidev = NULL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
ADD_ARG_LIT("-pcidevice");
|
|
|
|
ADD_ARG_LIT(pcidev);
|
|
|
|
VIR_FREE(pcidev);
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (migrateFrom) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-incoming");
|
2008-07-11 19:34:11 +00:00
|
|
|
ADD_ARG_LIT(migrateFrom);
|
2007-08-14 01:28:47 +00:00
|
|
|
}
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG(NULL);
|
2008-10-10 16:52:20 +00:00
|
|
|
ADD_ENV(NULL);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
*retargv = qargv;
|
2008-10-10 16:52:20 +00:00
|
|
|
*retenv = qenv;
|
2007-02-14 01:40:09 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2007-02-14 16:09:37 +00:00
|
|
|
error:
|
2008-07-11 19:34:11 +00:00
|
|
|
if (tapfds &&
|
|
|
|
*tapfds) {
|
2008-10-06 19:36:46 +00:00
|
|
|
for (i = 0; i < *ntapfds; i++)
|
2008-07-11 19:34:11 +00:00
|
|
|
close((*tapfds)[i]);
|
|
|
|
VIR_FREE(*tapfds);
|
|
|
|
*ntapfds = 0;
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
2008-05-22 23:45:09 +00:00
|
|
|
if (qargv) {
|
|
|
|
for (i = 0 ; i < qargc ; i++)
|
2008-05-29 19:20:22 +00:00
|
|
|
VIR_FREE((qargv)[i]);
|
|
|
|
VIR_FREE(qargv);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2008-10-10 16:52:20 +00:00
|
|
|
if (qenv) {
|
|
|
|
for (i = 0 ; i < qenvc ; i++)
|
|
|
|
VIR_FREE((qenv)[i]);
|
|
|
|
VIR_FREE(qenv);
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
2008-05-22 23:45:09 +00:00
|
|
|
|
|
|
|
#undef ADD_ARG
|
|
|
|
#undef ADD_ARG_LIT
|
|
|
|
#undef ADD_ARG_SPACE
|
2008-10-10 16:52:20 +00:00
|
|
|
#undef ADD_USBDISK
|
|
|
|
#undef ADD_ENV
|
|
|
|
#undef ADD_ENV_COPY
|
|
|
|
#undef ADD_ENV_LIT
|
|
|
|
#undef ADD_ENV_SPACE
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2008-12-20 13:09:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Called from SAX on parsing errors in the XML. */
|
|
|
|
static void
|
|
|
|
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
|
|
|
{
|
|
|
|
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
|
|
|
|
|
|
|
|
if (ctxt) {
|
|
|
|
virConnectPtr conn = ctxt->_private;
|
|
|
|
|
|
|
|
if (ctxt->lastError.level == XML_ERR_FATAL &&
|
|
|
|
ctxt->lastError.message != NULL) {
|
|
|
|
qemudReportError (conn, NULL, NULL, VIR_ERR_XML_DETAIL,
|
|
|
|
_("at line %d: %s"),
|
|
|
|
ctxt->lastError.line,
|
|
|
|
ctxt->lastError.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemudDomainStatusParseFile
|
|
|
|
*
|
|
|
|
* read the last known status of a domain
|
|
|
|
*
|
|
|
|
* Returns 0 on success
|
|
|
|
*/
|
|
|
|
qemudDomainStatusPtr
|
|
|
|
qemudDomainStatusParseFile(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
|
|
|
const char *filename, int flags)
|
|
|
|
{
|
|
|
|
xmlParserCtxtPtr pctxt = NULL;
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr root, config_root;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
char *tmp = NULL;
|
|
|
|
long val;
|
|
|
|
qemudDomainStatusPtr status = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(status) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-12-20 13:09:45 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up a parser context so we can catch the details of XML errors. */
|
|
|
|
pctxt = xmlNewParserCtxt ();
|
|
|
|
if (!pctxt || !pctxt->sax)
|
|
|
|
goto error;
|
|
|
|
pctxt->sax->error = catchXMLError;
|
|
|
|
pctxt->_private = conn;
|
|
|
|
|
|
|
|
if (conn) virResetError (&conn->err);
|
|
|
|
xml = xmlCtxtReadFile (pctxt, filename, NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOWARNING);
|
|
|
|
if (!xml) {
|
|
|
|
if (conn && conn->err.code == VIR_ERR_NONE)
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR,
|
|
|
|
"%s", _("failed to parse xml document"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((root = xmlDocGetRootElement(xml)) == NULL) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing root element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-12-20 13:09:45 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("incorrect root element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
2009-01-19 21:06:26 +00:00
|
|
|
if(!(tmp = virXPathString(conn, "string(./@state)", ctxt))) {
|
2008-12-20 13:09:45 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid domain state"));
|
|
|
|
goto error;
|
2009-01-19 21:06:26 +00:00
|
|
|
} else {
|
|
|
|
status->state = virDomainStateTypeFromString(tmp);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
2008-12-20 13:09:45 +00:00
|
|
|
|
|
|
|
if((virXPathLong(conn, "string(./@pid)", ctxt, &val)) < 0) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid pid"));
|
|
|
|
goto error;
|
|
|
|
} else
|
|
|
|
status->pid = (pid_t)val;
|
|
|
|
|
|
|
|
if(!(tmp = virXPathString(conn, "string(./monitor[1]/@path)", ctxt))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no monitor path"));
|
|
|
|
goto error;
|
|
|
|
} else
|
|
|
|
status->monitorpath = tmp;
|
|
|
|
|
|
|
|
if(!(config_root = virXPathNode(conn, "./domain", ctxt))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no domain config"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if(!(def = virDomainDefParseNode(conn, caps, xml, config_root, flags)))
|
|
|
|
goto error;
|
|
|
|
else
|
|
|
|
status->def = def;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
xmlFreeParserCtxt (pctxt);
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
xmlFreeDoc (xml);
|
|
|
|
return status;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
VIR_FREE(status);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemudDomainStatusFormat
|
|
|
|
*
|
|
|
|
* Get the state of a running domain as XML
|
|
|
|
*
|
|
|
|
* Returns xml on success
|
|
|
|
*/
|
|
|
|
static char*
|
|
|
|
qemudDomainStatusFormat(virConnectPtr conn,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
char *config_xml = NULL, *xml = NULL;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2009-01-19 21:06:26 +00:00
|
|
|
virBufferVSprintf(&buf, "<domstatus state='%s' pid='%d'>\n",
|
|
|
|
virDomainStateTypeToString(vm->state),
|
|
|
|
vm->pid);
|
2008-12-20 13:09:45 +00:00
|
|
|
virBufferEscapeString(&buf, " <monitor path='%s'/>\n", vm->monitorpath);
|
|
|
|
|
|
|
|
if (!(config_xml = virDomainDefFormat(conn,
|
|
|
|
vm->def,
|
|
|
|
VIR_DOMAIN_XML_SECURE)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virBufferAdd(&buf, config_xml, strlen(config_xml));
|
|
|
|
virBufferAddLit(&buf, "</domstatus>\n");
|
|
|
|
|
|
|
|
xml = virBufferContentAndReset(&buf);
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(config_xml);
|
|
|
|
return xml;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemudSaveDomainStatus
|
|
|
|
*
|
|
|
|
* Save the current status of a running domain
|
|
|
|
*
|
|
|
|
* Returns 0 on success
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qemudSaveDomainStatus(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *xml = NULL;
|
|
|
|
|
|
|
|
if (!(xml = qemudDomainStatusFormat(conn, vm)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((ret = virDomainSaveXML(conn, driver->stateDir, vm->def, xml)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
|
|
|
return ret;
|
|
|
|
}
|