2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* config.c: VM configuration management
|
|
|
|
*
|
2008-02-07 16:49:29 +00:00
|
|
|
* Copyright (C) 2006, 2007, 2008 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-05-22 15:29:50 +00:00
|
|
|
#if HAVE_NUMACTL
|
|
|
|
#include <numa.h>
|
|
|
|
#endif
|
|
|
|
|
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-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",
|
|
|
|
"usb")
|
2008-07-11 19:34:11 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
|
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"))) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
|
|
|
|
"%s", _("failed to allocate vncListen"));
|
|
|
|
return -1;
|
|
|
|
}
|
2007-10-12 16:05:44 +00:00
|
|
|
if (!(driver->vncTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-vnc"))) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
|
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
|
|
|
"%s", _("failed to allocate vncTLSx509certdir"));
|
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))) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
|
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
|
|
|
"%s", _("failed to allocate vncTLSx509certdir"));
|
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-07-11 19:34:11 +00:00
|
|
|
if (!(driver->vncListen = strdup(p->str))) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
|
|
|
|
"%s", _("failed to allocate vncTLSx509certdir"));
|
|
|
|
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-05-22 15:29:50 +00:00
|
|
|
#if HAVE_NUMACTL
|
|
|
|
#define MAX_CPUS 4096
|
|
|
|
#define MAX_CPUS_MASK_SIZE (sizeof(unsigned long))
|
|
|
|
#define MAX_CPUS_MASK_LEN (MAX_CPUS / MAX_CPUS_MASK_SIZE)
|
|
|
|
#define MAX_CPUS_MASK_BYTES (MAX_CPUS / 8)
|
|
|
|
|
|
|
|
#define MASK_CPU_ISSET(mask, cpu) \
|
|
|
|
(((mask)[((cpu) / MAX_CPUS_MASK_SIZE)] >> ((cpu) % MAX_CPUS_MASK_SIZE)) & 1)
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemudCapsInitNUMA(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
int n, i;
|
|
|
|
unsigned long *mask = NULL;
|
|
|
|
int ncpus;
|
|
|
|
int *cpus = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (numa_available() < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(mask, MAX_CPUS_MASK_LEN) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (n = 0 ; n <= numa_max_node() ; n++) {
|
|
|
|
if (numa_node_to_cpus(n, mask, MAX_CPUS_MASK_BYTES) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (ncpus = 0, i = 0 ; i < MAX_CPUS ; i++)
|
|
|
|
if (MASK_CPU_ISSET(mask, i))
|
|
|
|
ncpus++;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(cpus, ncpus) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (ncpus = 0, i = 0 ; i < MAX_CPUS ; i++)
|
|
|
|
if (MASK_CPU_ISSET(mask, i))
|
|
|
|
cpus[ncpus++] = i;
|
|
|
|
|
|
|
|
if (virCapabilitiesAddHostNUMACell(caps,
|
|
|
|
n,
|
|
|
|
ncpus,
|
|
|
|
cpus) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
VIR_FREE(mask);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int qemudCapsInitNUMA(virCapsPtr caps ATTRIBUTE_UNUSED) { return 0; }
|
|
|
|
#endif
|
|
|
|
|
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 });
|
|
|
|
|
2008-05-22 15:29:50 +00:00
|
|
|
if (qemudCapsInitNUMA(caps) < 0)
|
|
|
|
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;
|
|
|
|
unsigned int version;
|
|
|
|
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
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
if (sscanf(help, "QEMU PC emulator version %u.%u.%u",
|
|
|
|
&major, &minor, µ) != 3) {
|
|
|
|
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;
|
2008-08-29 07:11:15 +00:00
|
|
|
if (strstr(help, "-drive"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE;
|
|
|
|
if (strstr(help, "boot=on"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
|
|
|
|
if (version >= 9000)
|
|
|
|
flags |= QEMUD_CMD_FLAG_VNC_COLON;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
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);
|
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,
|
2007-03-13 22:43:22 +00:00
|
|
|
int vlan)
|
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-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-10-10 13:57:13 +00:00
|
|
|
_("Network '%s' is not active"),
|
2008-07-11 19:34:11 +00:00
|
|
|
net->data.network.name);
|
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"))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
|
|
|
|
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,
|
2008-07-11 19:34:11 +00:00
|
|
|
&net->ifname, &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:
|
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
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
|
|
|
|
"%s", _("failed to allocate space for tapfds string"));
|
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;
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
dev->data.tcp.listen ? ",server" : "") >= buflen)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (snprintf(buf, buflen, "tcp:%s:%s%s",
|
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
|
|
|
dev->data.tcp.listen ? ",listen" : "") >= buflen)
|
|
|
|
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,
|
|
|
|
dev->data.nix.listen ? ",listen" : "") >= 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];
|
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);
|
|
|
|
|
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-10-10 16:52:20 +00:00
|
|
|
if ((asprintf((char **)&(qargv[qargc++]), \
|
|
|
|
"disk:%s", thisarg)) == -1) { \
|
2008-08-08 15:03:00 +00:00
|
|
|
qargv[qargc-1] = NULL; \
|
|
|
|
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) { \
|
|
|
|
if (asprintf(&envval, "%s=%s", envname, val) < 0) \
|
|
|
|
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);
|
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");
|
|
|
|
ADD_ARG_LIT("-M");
|
|
|
|
ADD_ARG_LIT(vm->def->os.machine);
|
|
|
|
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-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
|
|
|
}
|
|
|
|
|
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++) {
|
2008-05-09 16:41:19 +00:00
|
|
|
char opt[PATH_MAX];
|
|
|
|
const char *media = NULL;
|
|
|
|
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;
|
2008-07-29 12:09:21 +00:00
|
|
|
media = "media=cdrom,";
|
2008-05-09 16:41:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-11-03 15:58:02 +00:00
|
|
|
snprintf(opt, PATH_MAX, "file=%s,if=%s,%sindex=%d%s%s",
|
2008-07-29 12:09:21 +00:00
|
|
|
disk->src ? disk->src : "", bus,
|
2008-05-09 16:41:19 +00:00
|
|
|
media ? media : "",
|
|
|
|
idx,
|
2008-07-11 19:34:11 +00:00
|
|
|
bootable &&
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_DISK
|
2008-11-03 15:58:02 +00:00
|
|
|
? ",boot=on" : "",
|
|
|
|
disk->shared && ! disk->readonly
|
|
|
|
? ",cache=off" : "");
|
2008-05-09 16:41:19 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-drive");
|
|
|
|
ADD_ARG_LIT(opt);
|
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
|
|
|
{
|
2008-07-11 19:34:11 +00:00
|
|
|
char *tap = qemudNetworkIfaceConnect(conn, driver,
|
|
|
|
tapfds, ntapfds,
|
|
|
|
net, vlan);
|
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) {
|
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
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
|
2007-10-12 16:05:44 +00:00
|
|
|
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",
|
2008-07-25 09:31:24 +00:00
|
|
|
(vm->def->graphics->data.vnc.listenAddr ?
|
|
|
|
vm->def->graphics->data.vnc.listenAddr :
|
|
|
|
(driver->vncListen ? driver->vncListen : "")),
|
2008-07-11 19:34:11 +00:00
|
|
|
vm->def->graphics->data.vnc.port - 5900,
|
2007-10-12 16:05:44 +00:00
|
|
|
options);
|
|
|
|
} else {
|
2007-07-24 14:30:05 +00:00
|
|
|
ret = snprintf(vncdisplay, sizeof(vncdisplay), "%d",
|
2008-07-11 19:34:11 +00:00
|
|
|
vm->def->graphics->data.vnc.port - 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;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-vnc");
|
|
|
|
ADD_ARG_LIT(vncdisplay);
|
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 &&
|
|
|
|
asprintf(&xauth, "XAUTHORITY=%s",
|
|
|
|
vm->def->graphics->data.sdl.xauth) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (vm->def->graphics->data.sdl.display &&
|
|
|
|
asprintf(&display, "DISPLAY=%s",
|
|
|
|
vm->def->graphics->data.sdl.display) < 0) {
|
|
|
|
VIR_FREE(xauth);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xauth)
|
|
|
|
ADD_ENV(xauth);
|
|
|
|
if (display)
|
|
|
|
ADD_ENV(display);
|
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;
|
2008-10-10 16:08:01 +00:00
|
|
|
virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
|
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) {
|
|
|
|
if(hostdev->source.subsys.usb.vendor) {
|
|
|
|
ret = asprintf(&usbdev, "host:%.4x:%.4x",
|
|
|
|
hostdev->source.subsys.usb.vendor,
|
|
|
|
hostdev->source.subsys.usb.product);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
ret = asprintf(&usbdev, "host:%.3d.%.3d",
|
|
|
|
hostdev->source.subsys.usb.bus,
|
|
|
|
hostdev->source.subsys.usb.device);
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
usbdev = NULL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
ADD_ARG_LIT("-usbdevice");
|
|
|
|
ADD_ARG_LIT(usbdev);
|
|
|
|
VIR_FREE(usbdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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:
|
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
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
|
|
|
|
"%s", _("failed to allocate space for argv string"));
|
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
|
|
|
}
|