2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* driver.c: core driver methods for managing qemu guests
|
|
|
|
*
|
Eliminate all uses of virBufferAdd with string literals.
* Makefile.maint (sc_prohibit_virBufferAdd_with_string_literal):
New rule.
* src/buf.h (virBufferAddLit): Define.
* src/conf.c (virConfSaveValue): Use virBufferAddLit, in place
of virBufferAdd everywhere possible.
(virConfSaveEntry): Likewise.
* src/qemu_conf.c (qemudGenerateXML, qemudGenerateNetworkXML): Likewise.
* src/qemu_driver.c (qemudGetFeatures, qemudGetCapabilities): Likewise.
* src/test.c (testDomainDumpXML, testNetworkDumpXML): Likewise.
* src/xen_internal.c (xenHypervisorMakeCapabilitiesXML): Likewise.
* src/xend_internal.c (xend_parse_sexp_desc_os): Likewise.
(xend_parse_sexp_desc, sexpr_to_xend_topology_xml): Likewise.
* src/xm_internal.c (xenXMDomainFormatXML, xenXMDomainPinVcpu): Likewise.
* src/xml.c (virSaveCpuSet, virParseXenCpuTopology): Likewise.
(virDomainParseXMLGraphicsDescImage): Likewise.
(virDomainParseXMLGraphicsDescVFB, virDomainParseXMLOSDescHVM): Likewise.
(virDomainParseXMLOSDescPV, virDomainParseXMLDiskDesc): Likewise.
(virDomainParseXMLIfDesc, virDomainParseXMLDesc): Likewise.
2008-02-05 14:22:28 +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
|
|
|
|
|
|
|
#ifdef WITH_QEMU
|
2007-02-14 15:42:55 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <strings.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2007-06-26 19:49:50 +00:00
|
|
|
#include <sys/utsname.h>
|
2007-06-26 20:41:25 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <paths.h>
|
|
|
|
#include <ctype.h>
|
2007-06-26 22:13:21 +00:00
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdio.h>
|
2007-06-26 20:41:25 +00:00
|
|
|
#include <sys/wait.h>
|
2007-09-21 19:32:02 +00:00
|
|
|
#include <libxml/uri.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
|
Wed Dec 5 13:48:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
* python/libvir.c, python/libvirt_wrap.h, qemud/qemud.c,
qemud/remote.c, src/internal.h, src/openvz_conf.c,
src/openvz_driver.c, src/proxy_internal.h, src/qemu_conf.c,
src/qemu_driver.c, src/remote_internal.h, src/test.h, src/util.c,
src/xen_unified.c, src/xen_unified.h, tests/nodeinfotest.c,
tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c, tests/reconnect.c,
tests/sexpr2xmltest.c, tests/virshtest.c, tests/xencapstest.c,
tests/xmconfigtest.c, tests/xml2sexprtest.c:
Change #include <> to #include "" for local includes.
Removed many includes from src/internal.h and put them in
the C files which actually use them.
Removed <ansidecl.h> - unused.
Added a comment around __func__.
Removed a clashing redefinition of VERSION symbol.
All limits (PATH_MAX etc) now done in src/internal.h, so we
don't need to include those headers in other files.
2007-12-05 13:56:22 +00:00
|
|
|
#include "libvirt/virterror.h"
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
#include "event.h"
|
2007-06-27 00:12:29 +00:00
|
|
|
#include "buf.h"
|
2007-07-19 16:22:40 +00:00
|
|
|
#include "util.h"
|
2007-06-27 00:12:29 +00:00
|
|
|
#include "qemu_driver.h"
|
|
|
|
#include "qemu_conf.h"
|
2007-07-25 23:16:30 +00:00
|
|
|
#include "nodeinfo.h"
|
2007-11-15 17:45:44 +00:00
|
|
|
#include "stats_linux.h"
|
2008-02-27 04:35:08 +00:00
|
|
|
#include "capabilities.h"
|
2007-06-26 20:41:25 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudShutdown(void);
|
|
|
|
|
2008-02-26 18:41:43 +00:00
|
|
|
/* qemudDebug statements should be changed to use this macro instead. */
|
|
|
|
#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
|
|
|
|
#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
|
2007-06-29 13:23:13 +00:00
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
#define qemudLog(level, msg...) fprintf(stderr, msg)
|
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
static int qemudSetCloseExec(int fd) {
|
|
|
|
int flags;
|
|
|
|
if ((flags = fcntl(fd, F_GETFD)) < 0)
|
|
|
|
goto error;
|
|
|
|
flags |= FD_CLOEXEC;
|
|
|
|
if ((fcntl(fd, F_SETFD, flags)) < 0)
|
|
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
2008-02-22 16:26:13 +00:00
|
|
|
qemudLog(QEMUD_ERR,
|
|
|
|
"%s", _("Failed to set close-on-exec file descriptor flag"));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int qemudSetNonBlock(int fd) {
|
|
|
|
int flags;
|
|
|
|
if ((flags = fcntl(fd, F_GETFL)) < 0)
|
|
|
|
goto error;
|
|
|
|
flags |= O_NONBLOCK;
|
|
|
|
if ((fcntl(fd, F_SETFL, flags)) < 0)
|
|
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
2008-02-22 16:26:13 +00:00
|
|
|
qemudLog(QEMUD_ERR,
|
|
|
|
"%s", _("Failed to set non-blocking file descriptor flag"));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
static void qemudDispatchVMEvent(int fd, int events, void *opaque);
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudStartVMDaemon(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_vm *vm);
|
2007-06-26 22:42:47 +00:00
|
|
|
|
2007-07-24 14:24:52 +00:00
|
|
|
static void qemudShutdownVMDaemon(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_vm *vm);
|
2007-06-26 22:42:47 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudStartNetworkDaemon(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_network *network);
|
2007-06-26 22:42:47 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudShutdownNetworkDaemon(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_network *network);
|
2007-06-26 22:42:47 +00:00
|
|
|
|
2008-01-14 14:05:25 +00:00
|
|
|
static struct qemud_driver *qemu_driver = NULL;
|
2007-06-26 22:13:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
void qemudAutostartConfigs(struct qemud_driver *driver) {
|
|
|
|
struct qemud_network *network;
|
|
|
|
struct qemud_vm *vm;
|
|
|
|
|
|
|
|
network = driver->networks;
|
|
|
|
while (network != NULL) {
|
|
|
|
struct qemud_network *next = network->next;
|
|
|
|
|
|
|
|
if (network->autostart &&
|
|
|
|
!qemudIsActiveNetwork(network) &&
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudStartNetworkDaemon(NULL, driver, network) < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
virErrorPtr err = virGetLastError();
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_ERR, _("Failed to autostart network '%s': %s"),
|
2007-06-26 22:13:21 +00:00
|
|
|
network->def->name, err->message);
|
|
|
|
}
|
|
|
|
|
|
|
|
network = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
vm = driver->vms;
|
|
|
|
while (vm != NULL) {
|
|
|
|
struct qemud_vm *next = vm->next;
|
|
|
|
|
|
|
|
if (vm->autostart &&
|
|
|
|
!qemudIsActiveVM(vm) &&
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudStartVMDaemon(NULL, driver, vm) < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
virErrorPtr err = virGetLastError();
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_ERR, _("Failed to autostart VM '%s': %s"),
|
2007-06-26 22:13:21 +00:00
|
|
|
vm->def->name, err->message);
|
|
|
|
}
|
|
|
|
|
|
|
|
vm = next;
|
|
|
|
}
|
2007-06-26 20:45:21 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* qemudStartup:
|
|
|
|
*
|
|
|
|
* Initialization function for the QEmu daemon
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudStartup(void) {
|
2007-06-26 22:13:21 +00:00
|
|
|
uid_t uid = geteuid();
|
|
|
|
struct passwd *pw;
|
|
|
|
char *base = NULL;
|
2007-10-12 16:05:44 +00:00
|
|
|
char driverConf[PATH_MAX];
|
2007-06-26 22:13:21 +00:00
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(qemu_driver = calloc(1, sizeof(*qemu_driver)))) {
|
2007-06-26 22:13:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't have a dom0 so start from 1 */
|
|
|
|
qemu_driver->nextvmid = 1;
|
|
|
|
|
|
|
|
if (!uid) {
|
|
|
|
if (snprintf(qemu_driver->logDir, PATH_MAX, "%s/log/libvirt/qemu", LOCAL_STATE_DIR) >= PATH_MAX)
|
|
|
|
goto snprintf_error;
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
|
2007-06-26 22:13:21 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
} else {
|
|
|
|
if (!(pw = getpwuid(uid))) {
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_ERR, _("Failed to find user record for uid '%d': %s"),
|
2007-06-26 22:13:21 +00:00
|
|
|
uid, strerror(errno));
|
|
|
|
goto out_of_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (snprintf(qemu_driver->logDir, PATH_MAX, "%s/.libvirt/qemu/log", pw->pw_dir) >= PATH_MAX)
|
|
|
|
goto snprintf_error;
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
if (asprintf (&base, "%s/.libvirt", pw->pw_dir) == -1) {
|
2008-02-22 16:26:13 +00:00
|
|
|
qemudLog (QEMUD_ERR,
|
|
|
|
"%s", _("out of memory in asprintf"));
|
2007-06-26 22:13:21 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Configuration paths are either ~/.libvirt/qemu/... (session) or
|
|
|
|
* /etc/libvirt/qemu/... (system).
|
|
|
|
*/
|
2007-10-12 16:05:44 +00:00
|
|
|
if (snprintf (driverConf, sizeof(driverConf), "%s/qemu.conf", base) == -1)
|
2007-06-26 22:13:21 +00:00
|
|
|
goto out_of_memory;
|
2007-10-12 16:05:44 +00:00
|
|
|
driverConf[sizeof(driverConf)-1] = '\0';
|
2007-06-26 22:13:21 +00:00
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
if (asprintf (&qemu_driver->configDir, "%s/qemu", base) == -1)
|
2007-06-26 22:13:21 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
if (asprintf (&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
|
2007-06-26 22:13:21 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
if (asprintf (&qemu_driver->networkConfigDir, "%s/qemu/networks", base) == -1)
|
|
|
|
goto out_of_memory;
|
|
|
|
|
|
|
|
if (asprintf (&qemu_driver->networkAutostartDir, "%s/qemu/networks/autostart",
|
2007-06-26 22:13:21 +00:00
|
|
|
base) == -1)
|
|
|
|
goto out_of_memory;
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
free(base);
|
2008-02-27 04:35:08 +00:00
|
|
|
base = NULL;
|
|
|
|
|
|
|
|
if ((qemu_driver->caps = qemudCapsInit()) == NULL)
|
|
|
|
goto out_of_memory;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
|
|
|
if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudShutdown();
|
2007-10-12 16:05:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemudScanConfigs(qemu_driver) < 0) {
|
|
|
|
qemudShutdown();
|
|
|
|
return -1;
|
|
|
|
}
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudAutostartConfigs(qemu_driver);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
snprintf_error:
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_ERR,
|
2008-02-22 16:26:13 +00:00
|
|
|
"%s", _("Resulting path to long for buffer in qemudInitPaths()"));
|
2007-06-26 22:13:21 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
out_of_memory:
|
2008-02-22 16:26:13 +00:00
|
|
|
qemudLog (QEMUD_ERR,
|
|
|
|
"%s", _("qemudStartup: out of memory"));
|
2008-01-29 17:41:07 +00:00
|
|
|
free (base);
|
2007-06-26 22:13:21 +00:00
|
|
|
free(qemu_driver);
|
|
|
|
qemu_driver = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* qemudReload:
|
|
|
|
*
|
|
|
|
* Function to restart the QEmu daemon, it will recheck the configuration
|
|
|
|
* files and update its state and the networking
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudReload(void) {
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudScanConfigs(qemu_driver);
|
|
|
|
|
|
|
|
if (qemu_driver->iptables) {
|
2008-02-22 16:26:13 +00:00
|
|
|
qemudLog(QEMUD_INFO,
|
|
|
|
"%s", _("Reloading iptables rules"));
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesReloadRules(qemu_driver->iptables);
|
2007-06-26 20:45:21 +00:00
|
|
|
}
|
2007-06-26 22:13:21 +00:00
|
|
|
|
|
|
|
qemudAutostartConfigs(qemu_driver);
|
2007-06-26 22:56:14 +00:00
|
|
|
|
|
|
|
return 0;
|
2007-06-26 20:45:21 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* qemudActive:
|
|
|
|
*
|
|
|
|
* Checks if the QEmu daemon is active, i.e. has an active domain or
|
|
|
|
* an active network
|
|
|
|
*
|
|
|
|
* Returns 1 if active, 0 otherwise
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudActive(void) {
|
2007-06-26 22:56:14 +00:00
|
|
|
/* If we've any active networks or guests, then we
|
|
|
|
* mark this driver as active
|
|
|
|
*/
|
|
|
|
if (qemu_driver->nactivenetworks &&
|
|
|
|
qemu_driver->nactivevms)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Otherwise we're happy to deal with a shutdown */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* qemudShutdown:
|
|
|
|
*
|
|
|
|
* Shutdown the QEmu daemon, it will stop all active domains and networks
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudShutdown(void) {
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_vm *vm;
|
|
|
|
struct qemud_network *network;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if (!qemu_driver)
|
2007-06-26 22:56:14 +00:00
|
|
|
return -1;
|
2007-06-26 22:13:21 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesFree(qemu_driver->caps);
|
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
/* shutdown active VMs */
|
2007-06-26 22:13:21 +00:00
|
|
|
vm = qemu_driver->vms;
|
2007-06-26 20:41:25 +00:00
|
|
|
while (vm) {
|
|
|
|
struct qemud_vm *next = vm->next;
|
|
|
|
if (qemudIsActiveVM(vm))
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudShutdownVMDaemon(NULL, qemu_driver, vm);
|
2007-07-24 14:24:52 +00:00
|
|
|
if (!vm->configFile[0])
|
|
|
|
qemudRemoveInactiveVM(qemu_driver, vm);
|
2007-06-26 20:41:25 +00:00
|
|
|
vm = next;
|
|
|
|
}
|
2008-02-05 19:27:37 +00:00
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
/* free inactive VMs */
|
2007-06-26 22:13:21 +00:00
|
|
|
vm = qemu_driver->vms;
|
2007-06-26 20:41:25 +00:00
|
|
|
while (vm) {
|
|
|
|
struct qemud_vm *next = vm->next;
|
|
|
|
qemudFreeVM(vm);
|
|
|
|
vm = next;
|
|
|
|
}
|
2007-06-26 22:13:21 +00:00
|
|
|
qemu_driver->vms = NULL;
|
|
|
|
qemu_driver->nactivevms = 0;
|
|
|
|
qemu_driver->ninactivevms = 0;
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
/* shutdown active networks */
|
2007-06-26 22:13:21 +00:00
|
|
|
network = qemu_driver->networks;
|
2007-06-26 20:41:25 +00:00
|
|
|
while (network) {
|
|
|
|
struct qemud_network *next = network->next;
|
|
|
|
if (qemudIsActiveNetwork(network))
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudShutdownNetworkDaemon(NULL, qemu_driver, network);
|
2007-06-26 20:41:25 +00:00
|
|
|
network = next;
|
|
|
|
}
|
2008-02-05 19:27:37 +00:00
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
/* free inactive networks */
|
2007-06-26 22:13:21 +00:00
|
|
|
network = qemu_driver->networks;
|
2007-06-26 20:41:25 +00:00
|
|
|
while (network) {
|
|
|
|
struct qemud_network *next = network->next;
|
|
|
|
qemudFreeNetwork(network);
|
|
|
|
network = next;
|
|
|
|
}
|
2007-06-26 22:13:21 +00:00
|
|
|
qemu_driver->networks = NULL;
|
|
|
|
qemu_driver->nactivenetworks = 0;
|
|
|
|
qemu_driver->ninactivenetworks = 0;
|
|
|
|
|
2008-01-29 17:41:07 +00:00
|
|
|
free(qemu_driver->configDir);
|
|
|
|
free(qemu_driver->autostartDir);
|
|
|
|
free(qemu_driver->networkConfigDir);
|
|
|
|
free(qemu_driver->networkAutostartDir);
|
|
|
|
free(qemu_driver->vncTLSx509certdir);
|
2007-12-01 15:45:25 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if (qemu_driver->brctl)
|
|
|
|
brShutdown(qemu_driver->brctl);
|
|
|
|
if (qemu_driver->iptables)
|
|
|
|
iptablesContextFree(qemu_driver->iptables);
|
|
|
|
|
|
|
|
free(qemu_driver);
|
|
|
|
qemu_driver = NULL;
|
2007-06-26 22:56:14 +00:00
|
|
|
|
|
|
|
return 0;
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return -1 for error, 1 to continue reading and 0 for success */
|
2007-07-12 15:09:01 +00:00
|
|
|
typedef int qemudHandlerMonitorOutput(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_vm *vm,
|
|
|
|
const char *output,
|
|
|
|
int fd);
|
|
|
|
|
|
|
|
static int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReadMonitorOutput(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_vm *vm,
|
|
|
|
int fd,
|
|
|
|
char *buf,
|
|
|
|
int buflen,
|
|
|
|
qemudHandlerMonitorOutput func,
|
|
|
|
const char *what)
|
|
|
|
{
|
|
|
|
#define MONITOR_TIMEOUT 3000
|
|
|
|
|
|
|
|
int got = 0;
|
|
|
|
buf[0] = '\0';
|
|
|
|
|
|
|
|
/* Consume & discard the initial greeting */
|
|
|
|
while (got < (buflen-1)) {
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(fd, buf+got, buflen-got-1);
|
|
|
|
if (ret == 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("QEMU quit during %s startup\n%s"), what, buf);
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (errno != EAGAIN) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Failure while reading %s startup output: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
what, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = poll(&pfd, 1, MONITOR_TIMEOUT);
|
|
|
|
if (ret == 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Timed out while reading %s startup output"), what);
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
} else if (ret == -1) {
|
|
|
|
if (errno != EINTR) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Failure while reading %s startup output: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
what, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Make sure we continue loop & read any further data
|
|
|
|
available before dealing with EOF */
|
|
|
|
if (pfd.revents & (POLLIN | POLLHUP))
|
|
|
|
continue;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Failure while reading %s startup output"), what);
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
got += ret;
|
|
|
|
buf[got] = '\0';
|
2007-07-12 15:09:01 +00:00
|
|
|
if ((ret = func(conn, driver, vm, buf, fd)) != 1)
|
2007-06-26 20:41:25 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Out of space while reading %s startup output"), what);
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
#undef MONITOR_TIMEOUT
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudCheckMonitorPrompt(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_vm *vm,
|
|
|
|
const char *output,
|
|
|
|
int fd)
|
|
|
|
{
|
|
|
|
if (strstr(output, "(qemu) ") == NULL)
|
|
|
|
return 1; /* keep reading */
|
|
|
|
|
|
|
|
vm->monitor = fd;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudOpenMonitor(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_vm *vm,
|
|
|
|
const char *monitor) {
|
2007-06-26 20:41:25 +00:00
|
|
|
int monfd;
|
|
|
|
char buf[1024];
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!(monfd = open(monitor, O_RDWR))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Unable to open monitor path %s"), monitor);
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (qemudSetCloseExec(monfd) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Unable to set monitor close-on-exec flag"));
|
2007-06-26 20:41:25 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (qemudSetNonBlock(monfd) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Unable to put monitor into non-blocking mode"));
|
2007-06-26 20:41:25 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
ret = qemudReadMonitorOutput(conn,
|
|
|
|
driver, vm, monfd,
|
2007-06-26 20:41:25 +00:00
|
|
|
buf, sizeof(buf),
|
|
|
|
qemudCheckMonitorPrompt,
|
|
|
|
"monitor");
|
2007-07-23 18:00:33 +00:00
|
|
|
|
|
|
|
/* Keep monitor open upon success */
|
|
|
|
if (ret == 0)
|
|
|
|
return ret;
|
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
error:
|
|
|
|
close(monfd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudExtractMonitorPath(const char *haystack, char *path, int pathmax) {
|
|
|
|
static const char needle[] = "char device redirected to";
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
if (!(tmp = strstr(haystack, needle)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
strncpy(path, tmp+sizeof(needle), pathmax-1);
|
|
|
|
path[pathmax-1] = '\0';
|
|
|
|
|
|
|
|
while (*path) {
|
|
|
|
/*
|
|
|
|
* The monitor path ends at first whitespace char
|
|
|
|
* so lets search for it & NULL terminate it there
|
|
|
|
*/
|
|
|
|
if (isspace(*path)) {
|
|
|
|
*path = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
path++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We found a path, but didn't find any whitespace,
|
|
|
|
* so it must be still incomplete - we should at
|
|
|
|
* least see a \n
|
|
|
|
*/
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudOpenMonitorPath(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_vm *vm,
|
|
|
|
const char *output,
|
|
|
|
int fd ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
char monitor[PATH_MAX];
|
|
|
|
|
|
|
|
if (qemudExtractMonitorPath(output, monitor, sizeof(monitor)) < 0)
|
|
|
|
return 1; /* keep reading */
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
return qemudOpenMonitor(conn, driver, vm, monitor);
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudWaitForMonitor(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_vm *vm) {
|
2007-06-26 20:41:25 +00:00
|
|
|
char buf[1024]; /* Plenty of space to get startup greeting */
|
2007-07-12 15:09:01 +00:00
|
|
|
int ret = qemudReadMonitorOutput(conn,
|
|
|
|
driver, vm, vm->stderr,
|
2007-06-26 20:41:25 +00:00
|
|
|
buf, sizeof(buf),
|
|
|
|
qemudOpenMonitorPath,
|
|
|
|
"console");
|
|
|
|
|
|
|
|
buf[sizeof(buf)-1] = '\0';
|
Use safewrite in place of write, in many cases.
Also add "make syntax-check" rules to ensure no new uses sneak in.
There are many uses of write like this:
if (write (fd, xml, towrite) != towrite)
return -1;
The problem is that the syscall can succeed, yet write less than
the requested number of bytes, so the caller should retry
rather than simply failing.
This patch changes most of them to use util.c's safewrite wrapper,
which encapsulates the process. Also, there were a few cases in
which the retry loop was open-coded, and I replaced those, too.
* Makefile.maint (sc_avoid_write): New rule, to avoid recurrence.
* .x-sc_avoid_write: New file. Record two legitimate exemptions.
* qemud/qemud.c (sig_handler, qemudClientWriteBuf): Use safewrite, not write.
* src/conf.c (__virConfWriteFile): Likewise.
* src/qemu_conf.c (qemudSaveConfig, qemudSaveNetworkConfig): Likewise.
* src/qemu_driver.c (qemudWaitForMonitor, qemudStartVMDaemon)
(qemudVMData, PROC_IP_FORWARD): Likewise.
* proxy/libvirt_proxy.c: Include "util.h".
(proxyWriteClientSocket): Use safewrite.
* src/test.c (testDomainSave, testDomainCoreDump): Likewise.
* src/proxy_internal.c (virProxyWriteClientSocket): Likewise.
* src/virsh.c: Include "util-lib.h".
(vshOutputLogFile): Use safewrite.
* src/console.c: Include "util-lib.h".
(vshRunConsole): Use safewrite.
2008-02-22 15:55:04 +00:00
|
|
|
|
|
|
|
if (safewrite(vm->logfile, buf, strlen(buf)) < 0) {
|
2007-06-26 20:41:25 +00:00
|
|
|
/* Log, but ignore failures to write logfile for VM */
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to log VM console data: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
|
2007-06-26 20:41:25 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 5900 ; i < 6000 ; i++) {
|
|
|
|
int fd;
|
|
|
|
int reuse = 1;
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
addr.sin_port = htons(i);
|
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
fd = socket(PF_INET, SOCK_STREAM, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse)) < 0) {
|
|
|
|
close(fd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
|
|
|
|
/* Not in use, lets grab it */
|
|
|
|
close(fd);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (errno == EADDRINUSE) {
|
|
|
|
/* In use, try next */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Some other bad failure, get out.. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudStartVMDaemon(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_vm *vm) {
|
2007-06-26 20:41:25 +00:00
|
|
|
char **argv = NULL, **tmp;
|
2007-06-26 20:45:21 +00:00
|
|
|
int i;
|
2007-06-26 20:41:25 +00:00
|
|
|
char logfile[PATH_MAX];
|
|
|
|
|
|
|
|
if (qemudIsActiveVM(vm)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("VM is already active"));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm->def->vncPort < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
int port = qemudNextFreeVNCPort(driver);
|
2007-06-26 20:41:25 +00:00
|
|
|
if (port < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Unable to find an unused VNC port"));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
vm->def->vncActivePort = port;
|
|
|
|
} else
|
|
|
|
vm->def->vncActivePort = vm->def->vncPort;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((strlen(driver->logDir) + /* path */
|
2007-06-26 20:41:25 +00:00
|
|
|
1 + /* Separator */
|
|
|
|
strlen(vm->def->name) + /* basename */
|
|
|
|
4 + /* suffix .log */
|
|
|
|
1 /* NULL */) > PATH_MAX) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("config file path too long: %s/%s.log"),
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->logDir, vm->def->name);
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-26 22:13:21 +00:00
|
|
|
strcpy(logfile, driver->logDir);
|
2007-06-26 20:41:25 +00:00
|
|
|
strcat(logfile, "/");
|
|
|
|
strcat(logfile, vm->def->name);
|
|
|
|
strcat(logfile, ".log");
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if (virFileMakePath(driver->logDir) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("cannot create log directory %s: %s"),
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->logDir, strerror(errno));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((vm->logfile = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
|
|
|
|
S_IRUSR | S_IWUSR)) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to create logfile %s: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
logfile, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2007-07-23 18:00:33 +00:00
|
|
|
if (qemudSetCloseExec(vm->logfile) < 0) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Unable to set VM logfile close-on-exec flag %s"),
|
2007-07-23 18:00:33 +00:00
|
|
|
strerror(errno));
|
|
|
|
close(vm->logfile);
|
|
|
|
vm->logfile = -1;
|
|
|
|
return -1;
|
|
|
|
}
|
2007-06-26 20:41:25 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudBuildCommandLine(conn, driver, vm, &argv) < 0) {
|
2007-06-26 20:41:25 +00:00
|
|
|
close(vm->logfile);
|
|
|
|
vm->logfile = -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = argv;
|
|
|
|
while (*tmp) {
|
Use safewrite in place of write, in many cases.
Also add "make syntax-check" rules to ensure no new uses sneak in.
There are many uses of write like this:
if (write (fd, xml, towrite) != towrite)
return -1;
The problem is that the syscall can succeed, yet write less than
the requested number of bytes, so the caller should retry
rather than simply failing.
This patch changes most of them to use util.c's safewrite wrapper,
which encapsulates the process. Also, there were a few cases in
which the retry loop was open-coded, and I replaced those, too.
* Makefile.maint (sc_avoid_write): New rule, to avoid recurrence.
* .x-sc_avoid_write: New file. Record two legitimate exemptions.
* qemud/qemud.c (sig_handler, qemudClientWriteBuf): Use safewrite, not write.
* src/conf.c (__virConfWriteFile): Likewise.
* src/qemu_conf.c (qemudSaveConfig, qemudSaveNetworkConfig): Likewise.
* src/qemu_driver.c (qemudWaitForMonitor, qemudStartVMDaemon)
(qemudVMData, PROC_IP_FORWARD): Likewise.
* proxy/libvirt_proxy.c: Include "util.h".
(proxyWriteClientSocket): Use safewrite.
* src/test.c (testDomainSave, testDomainCoreDump): Likewise.
* src/proxy_internal.c (virProxyWriteClientSocket): Likewise.
* src/virsh.c: Include "util-lib.h".
(vshOutputLogFile): Use safewrite.
* src/console.c: Include "util-lib.h".
(vshRunConsole): Use safewrite.
2008-02-22 15:55:04 +00:00
|
|
|
if (safewrite(vm->logfile, *tmp, strlen(*tmp)) < 0)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to write argv to logfile %d: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
errno, strerror(errno));
|
Use safewrite in place of write, in many cases.
Also add "make syntax-check" rules to ensure no new uses sneak in.
There are many uses of write like this:
if (write (fd, xml, towrite) != towrite)
return -1;
The problem is that the syscall can succeed, yet write less than
the requested number of bytes, so the caller should retry
rather than simply failing.
This patch changes most of them to use util.c's safewrite wrapper,
which encapsulates the process. Also, there were a few cases in
which the retry loop was open-coded, and I replaced those, too.
* Makefile.maint (sc_avoid_write): New rule, to avoid recurrence.
* .x-sc_avoid_write: New file. Record two legitimate exemptions.
* qemud/qemud.c (sig_handler, qemudClientWriteBuf): Use safewrite, not write.
* src/conf.c (__virConfWriteFile): Likewise.
* src/qemu_conf.c (qemudSaveConfig, qemudSaveNetworkConfig): Likewise.
* src/qemu_driver.c (qemudWaitForMonitor, qemudStartVMDaemon)
(qemudVMData, PROC_IP_FORWARD): Likewise.
* proxy/libvirt_proxy.c: Include "util.h".
(proxyWriteClientSocket): Use safewrite.
* src/test.c (testDomainSave, testDomainCoreDump): Likewise.
* src/proxy_internal.c (virProxyWriteClientSocket): Likewise.
* src/virsh.c: Include "util-lib.h".
(vshOutputLogFile): Use safewrite.
* src/console.c: Include "util-lib.h".
(vshRunConsole): Use safewrite.
2008-02-22 15:55:04 +00:00
|
|
|
if (safewrite(vm->logfile, " ", 1) < 0)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to write argv to logfile %d: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
errno, strerror(errno));
|
|
|
|
tmp++;
|
|
|
|
}
|
Use safewrite in place of write, in many cases.
Also add "make syntax-check" rules to ensure no new uses sneak in.
There are many uses of write like this:
if (write (fd, xml, towrite) != towrite)
return -1;
The problem is that the syscall can succeed, yet write less than
the requested number of bytes, so the caller should retry
rather than simply failing.
This patch changes most of them to use util.c's safewrite wrapper,
which encapsulates the process. Also, there were a few cases in
which the retry loop was open-coded, and I replaced those, too.
* Makefile.maint (sc_avoid_write): New rule, to avoid recurrence.
* .x-sc_avoid_write: New file. Record two legitimate exemptions.
* qemud/qemud.c (sig_handler, qemudClientWriteBuf): Use safewrite, not write.
* src/conf.c (__virConfWriteFile): Likewise.
* src/qemu_conf.c (qemudSaveConfig, qemudSaveNetworkConfig): Likewise.
* src/qemu_driver.c (qemudWaitForMonitor, qemudStartVMDaemon)
(qemudVMData, PROC_IP_FORWARD): Likewise.
* proxy/libvirt_proxy.c: Include "util.h".
(proxyWriteClientSocket): Use safewrite.
* src/test.c (testDomainSave, testDomainCoreDump): Likewise.
* src/proxy_internal.c (virProxyWriteClientSocket): Likewise.
* src/virsh.c: Include "util-lib.h".
(vshOutputLogFile): Use safewrite.
* src/console.c: Include "util-lib.h".
(vshRunConsole): Use safewrite.
2008-02-22 15:55:04 +00:00
|
|
|
if (safewrite(vm->logfile, "\n", 1) < 0)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to write argv to logfile %d: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
errno, strerror(errno));
|
|
|
|
|
2007-08-14 01:23:59 +00:00
|
|
|
if (virExecNonBlock(conn, argv, &vm->pid,
|
2007-08-14 01:28:47 +00:00
|
|
|
vm->stdin, &vm->stdout, &vm->stderr) == 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
vm->id = driver->nextvmid++;
|
2007-08-14 01:28:47 +00:00
|
|
|
vm->state = vm->migrateFrom[0] ? VIR_DOMAIN_PAUSED : VIR_DOMAIN_RUNNING;
|
2007-06-26 20:41:25 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->ninactivevms--;
|
|
|
|
driver->nactivevms++;
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 20:45:21 +00:00
|
|
|
for (i = 0 ; argv[i] ; i++)
|
|
|
|
free(argv[i]);
|
|
|
|
free(argv);
|
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
if (vm->tapfds) {
|
|
|
|
for (i = 0; vm->tapfds[i] != -1; i++) {
|
|
|
|
close(vm->tapfds[i]);
|
|
|
|
vm->tapfds[i] = -1;
|
|
|
|
}
|
|
|
|
free(vm->tapfds);
|
|
|
|
vm->tapfds = NULL;
|
|
|
|
vm->ntapfds = 0;
|
|
|
|
}
|
|
|
|
|
2007-06-26 20:45:21 +00:00
|
|
|
if (virEventAddHandle(vm->stdout,
|
|
|
|
POLLIN | POLLERR | POLLHUP,
|
|
|
|
qemudDispatchVMEvent,
|
2007-06-26 22:13:21 +00:00
|
|
|
driver) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudShutdownVMDaemon(conn, driver, vm);
|
2007-06-26 20:45:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virEventAddHandle(vm->stderr,
|
|
|
|
POLLIN | POLLERR | POLLHUP,
|
|
|
|
qemudDispatchVMEvent,
|
2007-06-26 22:13:21 +00:00
|
|
|
driver) < 0) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudShutdownVMDaemon(conn, driver, vm);
|
2007-06-26 20:45:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudWaitForMonitor(conn, driver, vm) < 0) {
|
|
|
|
qemudShutdownVMDaemon(conn, driver, vm);
|
2007-06-26 20:45:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
static int qemudVMData(struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_vm *vm, int fd) {
|
|
|
|
char buf[4096];
|
|
|
|
if (vm->pid < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
int ret = read(fd, buf, sizeof(buf)-1);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
return 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (ret == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
buf[ret] = '\0';
|
|
|
|
|
Use safewrite in place of write, in many cases.
Also add "make syntax-check" rules to ensure no new uses sneak in.
There are many uses of write like this:
if (write (fd, xml, towrite) != towrite)
return -1;
The problem is that the syscall can succeed, yet write less than
the requested number of bytes, so the caller should retry
rather than simply failing.
This patch changes most of them to use util.c's safewrite wrapper,
which encapsulates the process. Also, there were a few cases in
which the retry loop was open-coded, and I replaced those, too.
* Makefile.maint (sc_avoid_write): New rule, to avoid recurrence.
* .x-sc_avoid_write: New file. Record two legitimate exemptions.
* qemud/qemud.c (sig_handler, qemudClientWriteBuf): Use safewrite, not write.
* src/conf.c (__virConfWriteFile): Likewise.
* src/qemu_conf.c (qemudSaveConfig, qemudSaveNetworkConfig): Likewise.
* src/qemu_driver.c (qemudWaitForMonitor, qemudStartVMDaemon)
(qemudVMData, PROC_IP_FORWARD): Likewise.
* proxy/libvirt_proxy.c: Include "util.h".
(proxyWriteClientSocket): Use safewrite.
* src/test.c (testDomainSave, testDomainCoreDump): Likewise.
* src/proxy_internal.c (virProxyWriteClientSocket): Likewise.
* src/virsh.c: Include "util-lib.h".
(vshOutputLogFile): Use safewrite.
* src/console.c: Include "util-lib.h".
(vshRunConsole): Use safewrite.
2008-02-22 15:55:04 +00:00
|
|
|
if (safewrite(vm->logfile, buf, ret) < 0) {
|
2007-06-26 20:41:25 +00:00
|
|
|
/* Log, but ignore failures to write logfile for VM */
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to log VM console data: %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
2007-06-26 22:42:47 +00:00
|
|
|
|
|
|
|
qemudAutostartConfigs(qemu_driver);
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-24 14:24:52 +00:00
|
|
|
static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
struct qemud_driver *driver, struct qemud_vm *vm) {
|
2007-06-26 20:41:25 +00:00
|
|
|
if (!qemudIsActiveVM(vm))
|
2007-07-24 14:24:52 +00:00
|
|
|
return;
|
2007-06-26 20:41:25 +00:00
|
|
|
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_INFO, _("Shutting down VM '%s'"), vm->def->name);
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
kill(vm->pid, SIGTERM);
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudVMData(driver, vm, vm->stdout);
|
|
|
|
qemudVMData(driver, vm, vm->stderr);
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
virEventRemoveHandle(vm->stdout);
|
|
|
|
virEventRemoveHandle(vm->stderr);
|
|
|
|
|
|
|
|
if (close(vm->logfile) < 0)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to close logfile %d: %s"),
|
|
|
|
errno, strerror(errno));
|
2007-06-26 20:41:25 +00:00
|
|
|
close(vm->stdout);
|
|
|
|
close(vm->stderr);
|
|
|
|
if (vm->monitor != -1)
|
|
|
|
close(vm->monitor);
|
|
|
|
vm->logfile = -1;
|
|
|
|
vm->stdout = -1;
|
|
|
|
vm->stderr = -1;
|
|
|
|
vm->monitor = -1;
|
|
|
|
|
|
|
|
if (waitpid(vm->pid, NULL, WNOHANG) != vm->pid) {
|
|
|
|
kill(vm->pid, SIGKILL);
|
|
|
|
if (waitpid(vm->pid, NULL, 0) != vm->pid) {
|
2008-02-22 16:26:13 +00:00
|
|
|
qemudLog(QEMUD_WARN,
|
|
|
|
"%s", _("Got unexpected pid, damn"));
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->pid = -1;
|
|
|
|
vm->id = -1;
|
2007-06-26 22:39:53 +00:00
|
|
|
vm->state = VIR_DOMAIN_SHUTOFF;
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
if (vm->newDef) {
|
|
|
|
qemudFreeVMDef(vm->def);
|
|
|
|
vm->def = vm->newDef;
|
|
|
|
vm->newDef = NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->nactivevms--;
|
|
|
|
driver->ninactivevms++;
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
static int qemudDispatchVMLog(struct qemud_driver *driver, struct qemud_vm *vm, int fd) {
|
2007-07-24 14:24:52 +00:00
|
|
|
if (qemudVMData(driver, vm, fd) < 0) {
|
|
|
|
qemudShutdownVMDaemon(NULL, driver, vm);
|
|
|
|
if (!vm->configFile[0])
|
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
|
|
|
}
|
2007-06-26 20:41:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
static int qemudDispatchVMFailure(struct qemud_driver *driver, struct qemud_vm *vm,
|
2007-06-26 20:41:25 +00:00
|
|
|
int fd ATTRIBUTE_UNUSED) {
|
2007-07-24 14:24:52 +00:00
|
|
|
qemudShutdownVMDaemon(NULL, driver, vm);
|
|
|
|
if (!vm->configFile[0])
|
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
2007-06-26 20:41:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudBuildDnsmasqArgv(virConnectPtr conn,
|
|
|
|
struct qemud_network *network,
|
2007-06-26 20:41:25 +00:00
|
|
|
char ***argv) {
|
|
|
|
int i, len;
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
struct qemud_dhcp_range_def *range;
|
|
|
|
|
|
|
|
len =
|
|
|
|
1 + /* dnsmasq */
|
|
|
|
1 + /* --keep-in-foreground */
|
|
|
|
1 + /* --strict-order */
|
|
|
|
1 + /* --bind-interfaces */
|
|
|
|
2 + /* --pid-file "" */
|
|
|
|
2 + /* --conf-file "" */
|
|
|
|
/*2 + *//* --interface virbr0 */
|
|
|
|
2 + /* --except-interface lo */
|
|
|
|
2 + /* --listen-address 10.0.0.1 */
|
|
|
|
1 + /* --dhcp-leasefile=path */
|
|
|
|
(2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
|
|
|
|
1; /* NULL */
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
if (!(*argv = calloc(len, sizeof(**argv))))
|
2007-06-26 20:41:25 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
#define APPEND_ARG(v, n, s) do { \
|
|
|
|
if (!((v)[(n)] = strdup(s))) \
|
|
|
|
goto no_memory; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
2007-09-20 18:40:36 +00:00
|
|
|
APPEND_ARG(*argv, i++, DNSMASQ);
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
APPEND_ARG(*argv, i++, "--keep-in-foreground");
|
|
|
|
/*
|
|
|
|
* Needed to ensure dnsmasq uses same algorithm for processing
|
2007-06-26 22:13:21 +00:00
|
|
|
* multiple namedriver entries in /etc/resolv.conf as GLibC.
|
2007-06-26 20:41:25 +00:00
|
|
|
*/
|
|
|
|
APPEND_ARG(*argv, i++, "--strict-order");
|
|
|
|
APPEND_ARG(*argv, i++, "--bind-interfaces");
|
|
|
|
|
|
|
|
APPEND_ARG(*argv, i++, "--pid-file");
|
|
|
|
APPEND_ARG(*argv, i++, "");
|
|
|
|
|
|
|
|
APPEND_ARG(*argv, i++, "--conf-file");
|
|
|
|
APPEND_ARG(*argv, i++, "");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX does not actually work, due to some kind of
|
|
|
|
* race condition setting up ipv6 addresses on the
|
|
|
|
* interface. A sleep(10) makes it work, but that's
|
|
|
|
* clearly not practical
|
|
|
|
*
|
|
|
|
* APPEND_ARG(*argv, i++, "--interface");
|
|
|
|
* APPEND_ARG(*argv, i++, network->def->bridge);
|
|
|
|
*/
|
|
|
|
APPEND_ARG(*argv, i++, "--listen-address");
|
|
|
|
APPEND_ARG(*argv, i++, network->def->ipAddress);
|
|
|
|
|
|
|
|
APPEND_ARG(*argv, i++, "--except-interface");
|
|
|
|
APPEND_ARG(*argv, i++, "lo");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NB, dnsmasq command line arg bug means we need to
|
|
|
|
* use a single arg '--dhcp-leasefile=path' rather than
|
|
|
|
* two separate args in '--dhcp-leasefile path' style
|
|
|
|
*/
|
|
|
|
snprintf(buf, sizeof(buf), "--dhcp-leasefile=%s/lib/libvirt/dhcp-%s.leases",
|
|
|
|
LOCAL_STATE_DIR, network->def->name);
|
|
|
|
APPEND_ARG(*argv, i++, buf);
|
|
|
|
|
|
|
|
range = network->def->ranges;
|
|
|
|
while (range) {
|
|
|
|
snprintf(buf, sizeof(buf), "%s,%s",
|
|
|
|
range->start, range->end);
|
|
|
|
|
|
|
|
APPEND_ARG(*argv, i++, "--dhcp-range");
|
|
|
|
APPEND_ARG(*argv, i++, buf);
|
|
|
|
|
|
|
|
range = range->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef APPEND_ARG
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
if (argv) {
|
|
|
|
for (i = 0; (*argv)[i]; i++)
|
|
|
|
free((*argv)[i]);
|
|
|
|
free(*argv);
|
|
|
|
}
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "dnsmasq argv");
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2007-07-12 15:09:01 +00:00
|
|
|
dhcpStartDhcpDaemon(virConnectPtr conn,
|
|
|
|
struct qemud_network *network)
|
2007-06-26 20:41:25 +00:00
|
|
|
{
|
|
|
|
char **argv;
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
if (network->def->ipAddress[0] == '\0') {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("cannot start dhcp daemon without IP address for server"));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
argv = NULL;
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudBuildDnsmasqArgv(conn, network, &argv) < 0)
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
|
2007-08-14 01:23:59 +00:00
|
|
|
ret = virExecNonBlock(conn, argv, &network->dnsmasqPid, -1, NULL, NULL);
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
for (i = 0; argv[i]; i++)
|
|
|
|
free(argv[i]);
|
|
|
|
free(argv);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudAddIptablesRules(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_network *network) {
|
|
|
|
int err;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if (!driver->iptables && !(driver->iptables = iptablesContextNew())) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "iptables support");
|
2007-06-26 20:41:25 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* allow DHCP requests through to dnsmasq */
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddTcpInput(driver->iptables, network->bridge, 67))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to allow DHCP requests from '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddUdpInput(driver->iptables, network->bridge, 67))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to allow DHCP requests from '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allow DNS requests through to dnsmasq */
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddTcpInput(driver->iptables, network->bridge, 53))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to allow DNS requests from '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err3;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddUdpInput(driver->iptables, network->bridge, 53))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to allow DNS requests from '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err4;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Catch all rules to block forwarding to/from bridges */
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddForwardRejectOut(driver->iptables, network->bridge))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to block outbound traffic from '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err5;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddForwardRejectIn(driver->iptables, network->bridge))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to block inbound traffic to '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err6;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allow traffic between guests on the same bridge */
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddForwardAllowCross(driver->iptables, network->bridge))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to allow cross bridge traffic on '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err7;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The remaining rules are only needed for IP forwarding */
|
2008-01-10 14:01:00 +00:00
|
|
|
if (!network->def->forward) {
|
|
|
|
iptablesSaveRules(driver->iptables);
|
2007-06-26 20:41:25 +00:00
|
|
|
return 1;
|
2008-01-10 14:01:00 +00:00
|
|
|
}
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
/* allow forwarding packets from the bridge interface */
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddForwardAllowOut(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->bridge,
|
|
|
|
network->def->forwardDev))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to allow forwarding from '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err8;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allow forwarding packets to the bridge interface if they are part of an existing connection */
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddForwardAllowIn(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->bridge,
|
|
|
|
network->def->forwardDev))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to allow forwarding to '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err9;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enable masquerading */
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = iptablesAddForwardMasquerade(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->def->forwardDev))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to add iptables rule to enable masquerading : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
strerror(err));
|
|
|
|
goto err10;
|
|
|
|
}
|
|
|
|
|
2008-01-10 14:01:00 +00:00
|
|
|
iptablesSaveRules(driver->iptables);
|
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
err10:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardAllowIn(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->bridge,
|
|
|
|
network->def->forwardDev);
|
|
|
|
err9:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardAllowOut(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->bridge,
|
|
|
|
network->def->forwardDev);
|
|
|
|
err8:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardAllowCross(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge);
|
|
|
|
err7:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardRejectIn(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge);
|
|
|
|
err6:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardRejectOut(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge);
|
|
|
|
err5:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, network->bridge, 53);
|
2007-06-26 20:41:25 +00:00
|
|
|
err4:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveTcpInput(driver->iptables, network->bridge, 53);
|
2007-06-26 20:41:25 +00:00
|
|
|
err3:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, network->bridge, 67);
|
2007-06-26 20:41:25 +00:00
|
|
|
err2:
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveTcpInput(driver->iptables, network->bridge, 67);
|
2007-06-26 20:41:25 +00:00
|
|
|
err1:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveIptablesRules(struct qemud_driver *driver,
|
2007-06-26 20:41:25 +00:00
|
|
|
struct qemud_network *network) {
|
|
|
|
if (network->def->forward) {
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardMasquerade(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->def->forwardDev);
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardAllowIn(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->bridge,
|
|
|
|
network->def->forwardDev);
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardAllowOut(driver->iptables,
|
2007-06-26 20:41:25 +00:00
|
|
|
network->def->network,
|
|
|
|
network->bridge,
|
|
|
|
network->def->forwardDev);
|
|
|
|
}
|
2007-06-26 22:13:21 +00:00
|
|
|
iptablesRemoveForwardAllowCross(driver->iptables, network->bridge);
|
|
|
|
iptablesRemoveForwardRejectIn(driver->iptables, network->bridge);
|
|
|
|
iptablesRemoveForwardRejectOut(driver->iptables, network->bridge);
|
|
|
|
iptablesRemoveUdpInput(driver->iptables, network->bridge, 53);
|
|
|
|
iptablesRemoveTcpInput(driver->iptables, network->bridge, 53);
|
|
|
|
iptablesRemoveUdpInput(driver->iptables, network->bridge, 67);
|
|
|
|
iptablesRemoveTcpInput(driver->iptables, network->bridge, 67);
|
2008-01-10 14:01:00 +00:00
|
|
|
iptablesSaveRules(driver->iptables);
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemudEnableIpForwarding(void)
|
|
|
|
{
|
|
|
|
#define PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward"
|
|
|
|
|
|
|
|
int fd, ret;
|
|
|
|
|
|
|
|
if ((fd = open(PROC_IP_FORWARD, O_WRONLY|O_TRUNC)) == -1)
|
|
|
|
return 0;
|
|
|
|
|
Use safewrite in place of write, in many cases.
Also add "make syntax-check" rules to ensure no new uses sneak in.
There are many uses of write like this:
if (write (fd, xml, towrite) != towrite)
return -1;
The problem is that the syscall can succeed, yet write less than
the requested number of bytes, so the caller should retry
rather than simply failing.
This patch changes most of them to use util.c's safewrite wrapper,
which encapsulates the process. Also, there were a few cases in
which the retry loop was open-coded, and I replaced those, too.
* Makefile.maint (sc_avoid_write): New rule, to avoid recurrence.
* .x-sc_avoid_write: New file. Record two legitimate exemptions.
* qemud/qemud.c (sig_handler, qemudClientWriteBuf): Use safewrite, not write.
* src/conf.c (__virConfWriteFile): Likewise.
* src/qemu_conf.c (qemudSaveConfig, qemudSaveNetworkConfig): Likewise.
* src/qemu_driver.c (qemudWaitForMonitor, qemudStartVMDaemon)
(qemudVMData, PROC_IP_FORWARD): Likewise.
* proxy/libvirt_proxy.c: Include "util.h".
(proxyWriteClientSocket): Use safewrite.
* src/test.c (testDomainSave, testDomainCoreDump): Likewise.
* src/proxy_internal.c (virProxyWriteClientSocket): Likewise.
* src/virsh.c: Include "util-lib.h".
(vshOutputLogFile): Use safewrite.
* src/console.c: Include "util-lib.h".
(vshRunConsole): Use safewrite.
2008-02-22 15:55:04 +00:00
|
|
|
if (safewrite(fd, "1\n", 2) < 0)
|
2007-06-26 20:41:25 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
close (fd);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
#undef PROC_IP_FORWARD
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudStartNetworkDaemon(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_network *network) {
|
2007-06-26 20:41:25 +00:00
|
|
|
const char *name;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (qemudIsActiveNetwork(network)) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("network is already active"));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
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,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("cannot initialize bridge support: %s"), strerror(err));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network->def->bridge[0] == '\0' ||
|
|
|
|
strchr(network->def->bridge, '%')) {
|
|
|
|
name = "vnet%d";
|
|
|
|
} else {
|
|
|
|
name = network->def->bridge;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = brAddBridge(driver->brctl, name, network->bridge, sizeof(network->bridge)))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("cannot create bridge '%s' : %s"), name, strerror(err));
|
2007-06-26 20:41:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
|
|
|
|
if (network->def->forwardDelay &&
|
|
|
|
(err = brSetForwardDelay(driver->brctl, network->bridge, network->def->forwardDelay))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to set bridge forward delay to %d"),
|
2007-06-26 23:01:54 +00:00
|
|
|
network->def->forwardDelay);
|
|
|
|
goto err_delbr;
|
|
|
|
}
|
|
|
|
|
2007-11-21 11:46:05 +00:00
|
|
|
if ((err = brSetEnableSTP(driver->brctl, network->bridge, network->def->disableSTP ? 0 : 1))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to set bridge STP to %s"),
|
2007-06-26 23:01:54 +00:00
|
|
|
network->def->disableSTP ? "off" : "on");
|
|
|
|
goto err_delbr;
|
|
|
|
}
|
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
if (network->def->ipAddress[0] &&
|
2007-06-26 22:13:21 +00:00
|
|
|
(err = brSetInetAddress(driver->brctl, network->bridge, network->def->ipAddress))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("cannot set IP address on bridge '%s' to '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, network->def->ipAddress, strerror(err));
|
|
|
|
goto err_delbr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network->def->netmask[0] &&
|
2007-06-26 22:13:21 +00:00
|
|
|
(err = brSetInetNetmask(driver->brctl, network->bridge, network->def->netmask))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("cannot set netmask on bridge '%s' to '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, network->def->netmask, strerror(err));
|
|
|
|
goto err_delbr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network->def->ipAddress[0] &&
|
2007-06-26 22:13:21 +00:00
|
|
|
(err = brSetInterfaceUp(driver->brctl, network->bridge, 1))) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to bring the bridge '%s' up : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
goto err_delbr;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!qemudAddIptablesRules(conn, driver, network))
|
2007-06-26 20:41:25 +00:00
|
|
|
goto err_delbr1;
|
|
|
|
|
|
|
|
if (network->def->forward &&
|
|
|
|
!qemudEnableIpForwarding()) {
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:58:21 +00:00
|
|
|
_("failed to enable IP forwarding : %s"), strerror(err));
|
2007-06-26 20:41:25 +00:00
|
|
|
goto err_delbr2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network->def->ranges &&
|
2007-07-12 15:09:01 +00:00
|
|
|
dhcpStartDhcpDaemon(conn, network) < 0)
|
2007-06-26 20:41:25 +00:00
|
|
|
goto err_delbr2;
|
|
|
|
|
|
|
|
network->active = 1;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->ninactivenetworks--;
|
|
|
|
driver->nactivenetworks++;
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_delbr2:
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveIptablesRules(driver, network);
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
err_delbr1:
|
|
|
|
if (network->def->ipAddress[0] &&
|
2007-06-26 22:13:21 +00:00
|
|
|
(err = brSetInterfaceUp(driver->brctl, network->bridge, 0))) {
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Failed to bring down bridge '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
}
|
|
|
|
|
|
|
|
err_delbr:
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = brDeleteBridge(driver->brctl, network->bridge))) {
|
2008-03-24 10:58:21 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Failed to delete bridge '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
static int qemudShutdownNetworkDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
struct qemud_network *network) {
|
2007-06-26 20:41:25 +00:00
|
|
|
int err;
|
|
|
|
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_INFO, _("Shutting down network '%s'"), network->def->name);
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
if (!qemudIsActiveNetwork(network))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (network->dnsmasqPid > 0)
|
|
|
|
kill(network->dnsmasqPid, SIGTERM);
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveIptablesRules(driver, network);
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
if (network->def->ipAddress[0] &&
|
2007-06-26 22:13:21 +00:00
|
|
|
(err = brSetInterfaceUp(driver->brctl, network->bridge, 0))) {
|
2008-03-24 10:58:21 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Failed to bring down bridge '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = brDeleteBridge(driver->brctl, network->bridge))) {
|
2008-03-24 10:58:21 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Failed to delete bridge '%s' : %s"),
|
2007-06-26 20:41:25 +00:00
|
|
|
network->bridge, strerror(err));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network->dnsmasqPid > 0 &&
|
|
|
|
waitpid(network->dnsmasqPid, NULL, WNOHANG) != network->dnsmasqPid) {
|
|
|
|
kill(network->dnsmasqPid, SIGKILL);
|
|
|
|
if (waitpid(network->dnsmasqPid, NULL, 0) != network->dnsmasqPid)
|
2008-02-22 16:26:13 +00:00
|
|
|
qemudLog(QEMUD_WARN,
|
2008-03-24 10:58:21 +00:00
|
|
|
"%s", _("Got unexpected pid for dnsmasq"));
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
network->bridge[0] = '\0';
|
|
|
|
network->dnsmasqPid = -1;
|
|
|
|
network->active = 0;
|
|
|
|
|
|
|
|
if (network->newDef) {
|
|
|
|
qemudFreeNetworkDef(network->def);
|
|
|
|
network->def = network->newDef;
|
|
|
|
network->newDef = NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->nactivenetworks--;
|
|
|
|
driver->ninactivenetworks++;
|
2007-06-26 20:41:25 +00:00
|
|
|
|
2007-06-26 20:45:21 +00:00
|
|
|
if (!network->configFile[0])
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveNetwork(driver, network);
|
2007-06-26 20:45:21 +00:00
|
|
|
|
2007-06-26 20:41:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void qemudDispatchVMEvent(int fd, int events, void *opaque) {
|
2007-06-26 22:13:21 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)opaque;
|
|
|
|
struct qemud_vm *vm = driver->vms;
|
2007-06-26 20:41:25 +00:00
|
|
|
|
|
|
|
while (vm) {
|
|
|
|
if (qemudIsActiveVM(vm) &&
|
|
|
|
(vm->stdout == fd ||
|
|
|
|
vm->stderr == fd))
|
|
|
|
break;
|
|
|
|
|
|
|
|
vm = vm->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!vm)
|
|
|
|
return;
|
|
|
|
|
2007-06-26 20:45:21 +00:00
|
|
|
if (events == POLLIN)
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudDispatchVMLog(driver, vm, fd);
|
2007-06-26 20:45:21 +00:00
|
|
|
else
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudDispatchVMFailure(driver, vm, fd);
|
2007-06-26 20:41:25 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 18:41:43 +00:00
|
|
|
static int
|
|
|
|
qemudMonitorCommand (const struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
|
|
|
const struct qemud_vm *vm,
|
|
|
|
const char *cmd,
|
|
|
|
char **reply) {
|
2007-02-14 01:40:09 +00:00
|
|
|
int size = 0;
|
|
|
|
char *buf = NULL;
|
2007-10-27 01:16:53 +00:00
|
|
|
size_t cmdlen = strlen(cmd);
|
2007-03-05 17:15:20 +00:00
|
|
|
|
2007-10-27 01:16:53 +00:00
|
|
|
if (safewrite(vm->monitor, cmd, cmdlen) != cmdlen)
|
|
|
|
return -1;
|
|
|
|
if (safewrite(vm->monitor, "\r", 1) != 1)
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
*reply = NULL;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
struct pollfd fd = { vm->monitor, POLLIN | POLLERR | POLLHUP, 0 };
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
/* Read all the data QEMU has sent thus far */
|
|
|
|
for (;;) {
|
|
|
|
char data[1024];
|
|
|
|
int got = read(vm->monitor, data, sizeof(data));
|
2007-06-22 10:14:48 +00:00
|
|
|
char *b;
|
2007-03-05 17:15:20 +00:00
|
|
|
|
2007-10-27 01:16:53 +00:00
|
|
|
if (got == 0)
|
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
if (got < 0) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
break;
|
2007-10-27 01:16:53 +00:00
|
|
|
goto error;
|
2007-06-22 10:14:48 +00:00
|
|
|
}
|
2007-10-27 01:16:53 +00:00
|
|
|
if (!(b = realloc(buf, size+got+1)))
|
|
|
|
goto error;
|
|
|
|
|
2007-06-22 10:14:48 +00:00
|
|
|
buf = b;
|
2007-02-14 01:40:09 +00:00
|
|
|
memmove(buf+size, data, got);
|
|
|
|
buf[size+got] = '\0';
|
|
|
|
size += got;
|
|
|
|
}
|
2007-10-27 01:16:53 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/* Look for QEMU prompt to indicate completion */
|
2007-03-05 17:15:20 +00:00
|
|
|
if (buf && ((tmp = strstr(buf, "\n(qemu) ")) != NULL)) {
|
2007-02-14 01:40:09 +00:00
|
|
|
tmp[0] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pollagain:
|
|
|
|
/* Need to wait for more data */
|
|
|
|
if (poll(&fd, 1, -1) < 0) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto pollagain;
|
2007-10-27 01:16:53 +00:00
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-27 01:16:53 +00:00
|
|
|
/* Log, but ignore failures to write logfile for VM */
|
|
|
|
if (safewrite(vm->logfile, buf, strlen(buf)) < 0)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to log VM console data: %s"),
|
2007-10-27 01:16:53 +00:00
|
|
|
strerror(errno));
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
*reply = buf;
|
|
|
|
return 0;
|
2007-10-27 01:16:53 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
if (buf) {
|
|
|
|
/* Log, but ignore failures to write logfile for VM */
|
|
|
|
if (safewrite(vm->logfile, buf, strlen(buf)) < 0)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Unable to log VM console data: %s"),
|
2007-10-27 01:16:53 +00:00
|
|
|
strerror(errno));
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 07:05:18 +00:00
|
|
|
/**
|
|
|
|
* qemudProbe:
|
|
|
|
*
|
|
|
|
* Probe for the availability of the qemu driver, assume the
|
|
|
|
* presence of QEmu emulation if the binaries are installed
|
|
|
|
*/
|
|
|
|
static const char *qemudProbe(void)
|
|
|
|
{
|
|
|
|
if ((virFileExists("/usr/bin/qemu")) ||
|
|
|
|
(virFileExists("/usr/bin/qemu-kvm")) ||
|
|
|
|
(virFileExists("/usr/bin/xenner"))) {
|
|
|
|
if (getuid() == 0) {
|
|
|
|
return("qemu:///system");
|
|
|
|
} else {
|
|
|
|
return("qemu:///session");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
}
|
2007-06-26 19:49:50 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
|
2007-11-14 11:40:57 +00:00
|
|
|
xmlURIPtr uri,
|
2007-12-05 18:28:05 +00:00
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
2007-09-21 19:32:02 +00:00
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
2007-06-26 22:39:53 +00:00
|
|
|
uid_t uid = getuid();
|
|
|
|
|
|
|
|
if (qemu_driver == NULL)
|
2007-11-14 11:40:57 +00:00
|
|
|
goto decline;
|
2007-06-26 22:39:53 +00:00
|
|
|
|
2007-09-21 19:32:02 +00:00
|
|
|
if (uri == NULL || uri->scheme == NULL || uri->path == NULL)
|
|
|
|
goto decline;
|
|
|
|
|
|
|
|
if (STRNEQ (uri->scheme, "qemu"))
|
|
|
|
goto decline;
|
|
|
|
|
2007-09-20 17:13:39 +00:00
|
|
|
if (uid != 0) {
|
2007-09-21 19:32:02 +00:00
|
|
|
if (STRNEQ (uri->path, "/session"))
|
|
|
|
goto decline;
|
2007-09-20 17:13:39 +00:00
|
|
|
} else { /* root */
|
2007-09-21 19:32:02 +00:00
|
|
|
if (STRNEQ (uri->path, "/system") &&
|
|
|
|
STRNEQ (uri->path, "/session"))
|
2008-02-05 19:27:37 +00:00
|
|
|
goto decline;
|
2007-06-26 22:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
conn->privateData = qemu_driver;
|
|
|
|
|
|
|
|
return VIR_DRV_OPEN_SUCCESS;
|
2007-09-21 19:32:02 +00:00
|
|
|
|
|
|
|
decline:
|
2008-02-05 19:27:37 +00:00
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
2007-06-26 22:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudClose(virConnectPtr conn) {
|
|
|
|
/*struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;*/
|
|
|
|
|
|
|
|
conn->privateData = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
|
2007-07-04 03:59:13 +00:00
|
|
|
return "QEMU";
|
2007-06-26 22:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
const char *type) {
|
|
|
|
if (!type)
|
|
|
|
return 16;
|
|
|
|
|
|
|
|
if (!strcmp(type, "qemu"))
|
|
|
|
return 16;
|
|
|
|
|
|
|
|
/* XXX future KVM will support SMP. Need to probe
|
|
|
|
kernel to figure out KVM module version i guess */
|
|
|
|
if (!strcmp(type, "kvm"))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!strcmp(type, "kqemu"))
|
|
|
|
return 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:16:30 +00:00
|
|
|
static int qemudGetNodeInfo(virConnectPtr conn,
|
|
|
|
virNodeInfoPtr nodeinfo) {
|
|
|
|
return virNodeInfoPopulate(conn, nodeinfo);
|
2007-06-26 19:49:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
static char *qemudGetCapabilities(virConnectPtr conn) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
|
|
|
char *xml;
|
2007-06-26 19:49:50 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "capabilities");
|
2007-06-26 19:49:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
return xml;
|
2007-06-26 19:49:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
static int qemudGetProcessInfo(unsigned long long *cpuTime, int pid) {
|
|
|
|
char proc[PATH_MAX];
|
|
|
|
FILE *pidinfo;
|
2007-04-15 19:58:44 +00:00
|
|
|
unsigned long long usertime, systime;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(pidinfo = fopen(proc, "r"))) {
|
|
|
|
/*printf("cannnot read pid info");*/
|
|
|
|
/* VM probably shut down, so fake 0 */
|
|
|
|
*cpuTime = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-15 19:58:44 +00:00
|
|
|
if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
|
2007-02-16 18:30:55 +00:00
|
|
|
qemudDebug("not enough arg");
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We got jiffies
|
|
|
|
* We want nanoseconds
|
|
|
|
* _SC_CLK_TCK is jiffies per second
|
|
|
|
* So calulate thus....
|
|
|
|
*/
|
2007-04-15 19:58:44 +00:00
|
|
|
*cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-04-15 19:58:44 +00:00
|
|
|
qemudDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
fclose(pidinfo);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
|
2007-06-26 22:39:53 +00:00
|
|
|
int id) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByID(driver, id);
|
|
|
|
virDomainPtr dom;
|
|
|
|
|
|
|
|
if (!vm) {
|
2007-07-06 14:56:15 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2007-07-06 15:02:09 +00:00
|
|
|
if (dom) dom->id = vm->id;
|
2007-06-26 22:39:53 +00:00
|
|
|
return dom;
|
|
|
|
}
|
2007-06-29 13:23:13 +00:00
|
|
|
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
|
2007-06-26 22:39:53 +00:00
|
|
|
const unsigned char *uuid) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, uuid);
|
|
|
|
virDomainPtr dom;
|
|
|
|
|
|
|
|
if (!vm) {
|
2007-07-06 14:56:15 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2007-07-06 15:02:09 +00:00
|
|
|
if (dom) dom->id = vm->id;
|
2007-06-26 22:39:53 +00:00
|
|
|
return dom;
|
|
|
|
}
|
2007-06-29 13:23:13 +00:00
|
|
|
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
|
2007-06-26 22:39:53 +00:00
|
|
|
const char *name) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByName(driver, name);
|
|
|
|
virDomainPtr dom;
|
|
|
|
|
|
|
|
if (!vm) {
|
2007-07-06 14:56:15 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2007-07-06 15:02:09 +00:00
|
|
|
if (dom) dom->id = vm->id;
|
2007-06-26 22:39:53 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudExtractVersion(conn, driver) < 0)
|
2007-02-23 17:15:18 +00:00
|
|
|
return -1;
|
|
|
|
|
2007-06-26 22:39:53 +00:00
|
|
|
*version = qemu_driver->qemuVersion;
|
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-09-20 17:13:39 +00:00
|
|
|
static char *
|
|
|
|
qemudGetHostname (virConnectPtr conn)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
char hostname[HOST_NAME_MAX+1], *str;
|
|
|
|
|
|
|
|
r = gethostname (hostname, HOST_NAME_MAX+1);
|
|
|
|
if (r == -1) {
|
|
|
|
qemudReportError (conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR,
|
|
|
|
"%s", strerror (errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Caller frees this string. */
|
|
|
|
str = strdup (hostname);
|
|
|
|
if (str == NULL) {
|
|
|
|
qemudReportError (conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR,
|
|
|
|
"%s", strerror (errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
struct qemud_vm *vm = driver->vms;
|
2007-02-14 01:40:09 +00:00
|
|
|
int got = 0;
|
|
|
|
while (vm && got < nids) {
|
2007-02-23 08:39:49 +00:00
|
|
|
if (qemudIsActiveVM(vm)) {
|
|
|
|
ids[got] = vm->id;
|
|
|
|
got++;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
vm = vm->next;
|
|
|
|
}
|
|
|
|
return got;
|
|
|
|
}
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNumDomains(virConnectPtr conn) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
return driver->nactivevms;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-06-29 13:23:13 +00:00
|
|
|
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
|
2007-07-12 15:09:01 +00:00
|
|
|
unsigned int flags ATTRIBUTE_UNUSED) {
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm_def *def;
|
2007-02-14 01:40:09 +00:00
|
|
|
struct qemud_vm *vm;
|
2007-06-26 22:39:53 +00:00
|
|
|
virDomainPtr dom;
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(def = qemudParseVMDef(conn, driver, xml, NULL)))
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(vm = qemudAssignVMDef(conn, driver, def))) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudFreeVMDef(def);
|
2007-02-14 01:40:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudStartVMDaemon(conn, driver, vm) < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
2007-02-14 01:40:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2007-07-06 15:02:09 +00:00
|
|
|
if (dom) dom->id = vm->id;
|
2007-06-26 22:39:53 +00:00
|
|
|
return dom;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainSuspend(virDomainPtr dom) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
2007-02-14 01:40:09 +00:00
|
|
|
char *info;
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_vm *vm = qemudFindVMByID(driver, dom->id);
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching id %d"), dom->id);
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveVM(vm)) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, _("domain is not running"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-26 22:39:53 +00:00
|
|
|
if (vm->state == VIR_DOMAIN_PAUSED)
|
2007-03-05 17:15:20 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-10-27 01:16:53 +00:00
|
|
|
if (qemudMonitorCommand(driver, vm, "stop", &info) < 0) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, _("suspend operation failed"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-26 22:39:53 +00:00
|
|
|
vm->state = VIR_DOMAIN_PAUSED;
|
2007-02-16 18:30:55 +00:00
|
|
|
qemudDebug("Reply %s", info);
|
2007-02-14 01:40:09 +00:00
|
|
|
free(info);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainResume(virDomainPtr dom) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
2007-02-14 01:40:09 +00:00
|
|
|
char *info;
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_vm *vm = qemudFindVMByID(driver, dom->id);
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching id %d"), dom->id);
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveVM(vm)) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, _("domain is not running"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-26 22:39:53 +00:00
|
|
|
if (vm->state == VIR_DOMAIN_RUNNING)
|
2007-03-05 17:15:20 +00:00
|
|
|
return 0;
|
2007-10-27 01:16:53 +00:00
|
|
|
if (qemudMonitorCommand(driver, vm, "cont", &info) < 0) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, _("resume operation failed"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-06-26 22:39:53 +00:00
|
|
|
vm->state = VIR_DOMAIN_RUNNING;
|
2007-02-16 18:30:55 +00:00
|
|
|
qemudDebug("Reply %s", info);
|
2007-02-14 01:40:09 +00:00
|
|
|
free(info);
|
2007-03-05 17:15:20 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-09 16:05:21 +00:00
|
|
|
static int qemudDomainShutdown(virDomainPtr dom) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByID(driver, dom->id);
|
|
|
|
char* info;
|
|
|
|
|
|
|
|
if (!vm) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no domain with matching id %d"), dom->id);
|
2008-01-09 16:05:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemudMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("shutdown operation failed"));
|
2008-01-09 16:05:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainDestroy(virDomainPtr dom) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByID(driver, dom->id);
|
2007-02-23 08:41:23 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!vm) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no domain with matching id %d"), dom->id);
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-23 08:41:23 +00:00
|
|
|
|
2007-07-24 14:24:52 +00:00
|
|
|
qemudShutdownVMDaemon(dom->conn, driver, vm);
|
|
|
|
if (!vm->configFile[0])
|
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
2008-01-21 16:29:10 +00:00
|
|
|
|
2007-07-24 14:24:52 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-26 22:39:53 +00:00
|
|
|
static char *qemudDomainGetOSType(virDomainPtr dom) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
|
|
|
char *type;
|
|
|
|
|
|
|
|
if (!vm) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no domain with matching uuid"));
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(type = strdup(vm->def->os.type))) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_MEMORY, "ostype");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2008-03-19 14:32:50 +00:00
|
|
|
/* Returns max memory in kb, 0 if error */
|
|
|
|
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
|
|
|
|
|
|
|
if (!vm) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching uuid '%s'"), dom->uuid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return vm->def->maxmem;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
|
|
|
|
|
|
|
if (!vm) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching uuid '%s'"), dom->uuid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newmax < vm->def->memory) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
|
|
|
_("cannot set max memory lower than current memory"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->def->maxmem = newmax;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
|
|
|
|
|
|
|
if (!vm) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching uuid '%s'"), dom->uuid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemudIsActiveVM(vm)) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot set memory of an active domain"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newmem > vm->def->maxmem) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
|
|
|
_("cannot set memory higher than max memory"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->def->memory = newmem;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainGetInfo(virDomainPtr dom,
|
2007-06-26 22:39:53 +00:00
|
|
|
virDomainInfoPtr info) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:39:53 +00:00
|
|
|
info->state = vm->state;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveVM(vm)) {
|
2007-06-26 22:39:53 +00:00
|
|
|
info->cpuTime = 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
2007-06-26 22:39:53 +00:00
|
|
|
if (qemudGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:39:53 +00:00
|
|
|
info->maxMem = vm->def->maxmem;
|
|
|
|
info->memory = vm->def->memory;
|
|
|
|
info->nrVirtCpu = vm->def->vcpus;
|
2007-02-14 01:40:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-27 01:19:51 +00:00
|
|
|
static char *qemudEscape(const char *in, int shell)
|
2007-08-14 01:33:38 +00:00
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
int i, j;
|
|
|
|
char *out;
|
|
|
|
|
|
|
|
/* To pass through the QEMU monitor, we need to use escape
|
|
|
|
sequences: \r, \n, \", \\
|
|
|
|
|
|
|
|
To pass through both QEMU + the shell, we need to escape
|
|
|
|
the single character ' as the five characters '\\''
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (i = 0; in[i] != '\0'; i++) {
|
|
|
|
switch(in[i]) {
|
|
|
|
case '\r':
|
|
|
|
case '\n':
|
|
|
|
case '"':
|
|
|
|
case '\\':
|
|
|
|
len += 2;
|
|
|
|
break;
|
|
|
|
case '\'':
|
2007-10-27 01:19:51 +00:00
|
|
|
if (shell)
|
|
|
|
len += 5;
|
|
|
|
else
|
|
|
|
len += 1;
|
2007-08-14 01:33:38 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
len += 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((out = (char *)malloc(len + 1)) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = j = 0; in[i] != '\0'; i++) {
|
|
|
|
switch(in[i]) {
|
|
|
|
case '\r':
|
|
|
|
out[j++] = '\\';
|
|
|
|
out[j++] = 'r';
|
|
|
|
break;
|
|
|
|
case '\n':
|
|
|
|
out[j++] = '\\';
|
|
|
|
out[j++] = 'n';
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
case '\\':
|
|
|
|
out[j++] = '\\';
|
|
|
|
out[j++] = in[i];
|
|
|
|
break;
|
|
|
|
case '\'':
|
2007-10-27 01:19:51 +00:00
|
|
|
if (shell) {
|
|
|
|
out[j++] = '\'';
|
|
|
|
out[j++] = '\\';
|
|
|
|
out[j++] = '\\';
|
|
|
|
out[j++] = '\'';
|
|
|
|
out[j++] = '\'';
|
|
|
|
} else {
|
|
|
|
out[j++] = in[i];
|
|
|
|
}
|
2007-08-14 01:33:38 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
out[j++] = in[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out[j] = '\0';
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2007-10-27 01:21:09 +00:00
|
|
|
static char *qemudEscapeMonitorArg(const char *in)
|
|
|
|
{
|
|
|
|
return qemudEscape(in, 0);
|
|
|
|
}
|
|
|
|
|
2007-10-27 01:19:51 +00:00
|
|
|
static char *qemudEscapeShellArg(const char *in)
|
|
|
|
{
|
|
|
|
return qemudEscape(in, 1);
|
|
|
|
}
|
2007-08-14 01:33:38 +00:00
|
|
|
|
2007-08-14 01:47:24 +00:00
|
|
|
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
|
|
|
|
#define QEMUD_SAVE_VERSION 1
|
|
|
|
|
|
|
|
struct qemud_save_header {
|
|
|
|
char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
|
|
|
|
int version;
|
|
|
|
int xml_len;
|
|
|
|
int was_running;
|
|
|
|
int unused[16];
|
|
|
|
};
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainSave(virDomainPtr dom,
|
2007-08-14 01:47:24 +00:00
|
|
|
const char *path) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByID(driver, dom->id);
|
2007-08-14 01:47:24 +00:00
|
|
|
char *command, *info;
|
|
|
|
int fd;
|
|
|
|
char *safe_path;
|
|
|
|
char *xml;
|
|
|
|
struct qemud_save_header header;
|
|
|
|
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
|
|
|
|
header.version = QEMUD_SAVE_VERSION;
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!vm) {
|
2007-08-14 01:47:24 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no domain with matching id %d"), dom->id);
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-08-14 01:47:24 +00:00
|
|
|
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveVM(vm)) {
|
2007-08-14 01:47:24 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("domain is not running"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-08-14 01:47:24 +00:00
|
|
|
|
|
|
|
/* Pause */
|
|
|
|
if (vm->state == VIR_DOMAIN_RUNNING) {
|
|
|
|
header.was_running = 1;
|
|
|
|
if (qemudDomainSuspend(dom) != 0) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to pause domain"));
|
2007-08-14 01:47:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get XML for the domain */
|
|
|
|
xml = qemudGenerateXML(dom->conn, driver, vm, vm->def, 0);
|
|
|
|
if (!xml) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to get domain xml"));
|
2007-08-14 01:47:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
header.xml_len = strlen(xml) + 1;
|
|
|
|
|
|
|
|
/* Write header to file, followed by XML */
|
|
|
|
if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to create '%s'"), path);
|
2007-08-14 01:47:24 +00:00
|
|
|
free(xml);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to write save header"));
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
free(xml);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (safewrite(fd, xml, header.xml_len) != header.xml_len) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to write xml"));
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
free(xml);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
free(xml);
|
|
|
|
|
|
|
|
/* Migrate to file */
|
|
|
|
safe_path = qemudEscapeShellArg(path);
|
|
|
|
if (!safe_path) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("out of memory"));
|
2007-08-14 01:47:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (asprintf (&command, "migrate \"exec:"
|
|
|
|
"dd of='%s' oflag=append conv=notrunc 2>/dev/null"
|
2007-10-27 01:16:53 +00:00
|
|
|
"\"", safe_path) == -1) {
|
2007-08-14 01:47:24 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("out of memory"));
|
2007-08-14 01:47:24 +00:00
|
|
|
free(safe_path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(safe_path);
|
|
|
|
|
|
|
|
if (qemudMonitorCommand(driver, vm, command, &info) < 0) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("migrate operation failed"));
|
2007-08-14 01:47:24 +00:00
|
|
|
free(command);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(info);
|
|
|
|
free(command);
|
|
|
|
|
|
|
|
/* Shut it down */
|
|
|
|
qemudShutdownVMDaemon(dom->conn, driver, vm);
|
|
|
|
if (!vm->configFile[0])
|
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
|
|
|
|
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainRestore(virConnectPtr conn,
|
2007-08-14 01:47:24 +00:00
|
|
|
const char *path) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
|
|
|
struct qemud_vm_def *def;
|
|
|
|
struct qemud_vm *vm;
|
|
|
|
int fd;
|
2007-10-10 19:46:17 +00:00
|
|
|
int ret;
|
2007-08-14 01:47:24 +00:00
|
|
|
char *xml;
|
|
|
|
struct qemud_save_header header;
|
|
|
|
|
|
|
|
/* Verify the header and read the XML */
|
|
|
|
if ((fd = open(path, O_RDONLY)) < 0) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("cannot read domain image"));
|
2007-08-14 01:47:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to read qemu header"));
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("image magic is incorrect"));
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (header.version > QEMUD_SAVE_VERSION) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("image version is not supported (%d > %d)"),
|
2007-08-14 01:47:24 +00:00
|
|
|
header.version, QEMUD_SAVE_VERSION);
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((xml = (char *)malloc(header.xml_len)) == NULL) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("out of memory"));
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (saferead(fd, xml, header.xml_len) != header.xml_len) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to read XML"));
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
free(xml);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a domain from this XML */
|
|
|
|
if (!(def = qemudParseVMDef(conn, driver, xml, NULL))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to parse XML"));
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
free(xml);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(xml);
|
|
|
|
|
|
|
|
/* Ensure the name and UUID don't already exist in an active VM */
|
|
|
|
vm = qemudFindVMByUUID(driver, def->uuid);
|
|
|
|
if (!vm) vm = qemudFindVMByName(driver, def->name);
|
|
|
|
if (vm && qemudIsActiveVM(vm)) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("domain is already active as '%s'"), vm->def->name);
|
2007-08-14 01:47:24 +00:00
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(vm = qemudAssignVMDef(conn, driver, def))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to assign new VM"));
|
2007-08-14 01:47:24 +00:00
|
|
|
qemudFreeVMDef(def);
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the migration source and start it up. */
|
|
|
|
snprintf(vm->migrateFrom, sizeof(vm->migrateFrom), "stdio");
|
|
|
|
vm->stdin = fd;
|
2007-10-10 19:46:17 +00:00
|
|
|
ret = qemudStartVMDaemon(conn, driver, vm);
|
|
|
|
close(fd);
|
|
|
|
vm->migrateFrom[0] = '\0';
|
|
|
|
vm->stdin = -1;
|
|
|
|
if (ret < 0) {
|
2007-08-14 01:47:24 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to start VM"));
|
2007-08-14 01:47:24 +00:00
|
|
|
if (!vm->configFile[0])
|
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If it was running before, resume it now. */
|
|
|
|
if (header.was_running) {
|
|
|
|
char *info;
|
2007-10-27 01:16:53 +00:00
|
|
|
if (qemudMonitorCommand(driver, vm, "cont", &info) < 0) {
|
2007-08-14 01:47:24 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("failed to resume domain"));
|
2007-08-14 01:47:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(info);
|
|
|
|
vm->state = VIR_DOMAIN_RUNNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static char *qemudDomainDumpXML(virDomainPtr dom,
|
2007-06-26 22:39:53 +00:00
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
2007-02-14 01:40:09 +00:00
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
return qemudGenerateXML(dom->conn, driver, vm, vm->def, 1);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudListDefinedDomains(virConnectPtr conn,
|
2007-06-26 22:39:53 +00:00
|
|
|
char **const names, int nnames) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
struct qemud_vm *vm = driver->vms;
|
2007-06-26 22:39:53 +00:00
|
|
|
int got = 0, i;
|
2007-02-14 01:40:09 +00:00
|
|
|
while (vm && got < nnames) {
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveVM(vm)) {
|
2007-06-26 22:39:53 +00:00
|
|
|
if (!(names[got] = strdup(vm->def->name))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-02-23 08:39:49 +00:00
|
|
|
got++;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
vm = vm->next;
|
|
|
|
}
|
|
|
|
return got;
|
2007-06-26 22:39:53 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < got ; i++)
|
|
|
|
free(names[i]);
|
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNumDefinedDomains(virConnectPtr conn) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
return driver->ninactivevms;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainStart(virDomainPtr dom) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
2007-02-23 08:41:23 +00:00
|
|
|
|
|
|
|
if (!vm) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no domain with matching uuid"));
|
2007-06-26 22:39:53 +00:00
|
|
|
return -1;
|
2007-02-23 08:41:23 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
return qemudStartVMDaemon(dom->conn, driver, vm);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_vm_def *def;
|
|
|
|
struct qemud_vm *vm;
|
2007-06-26 22:39:53 +00:00
|
|
|
virDomainPtr dom;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(def = qemudParseVMDef(conn, driver, xml, NULL)))
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(vm = qemudAssignVMDef(conn, driver, def))) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudFreeVMDef(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudSaveVMDef(conn, driver, vm, def) < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2007-07-06 15:02:09 +00:00
|
|
|
if (dom) dom->id = vm->id;
|
2007-06-26 22:39:53 +00:00
|
|
|
return dom;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainUndefine(virDomainPtr dom) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-02-23 08:39:49 +00:00
|
|
|
if (qemudIsActiveVM(vm)) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, _("cannot delete active domain"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudDeleteConfig(dom->conn, driver, vm->configFile, vm->def->name) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
|
2007-02-23 09:07:41 +00:00
|
|
|
if (unlink(vm->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Failed to delete autostart link '%s': %s"),
|
2007-02-23 09:07:41 +00:00
|
|
|
vm->autostartLink, strerror(errno));
|
|
|
|
|
2007-02-14 15:58:06 +00:00
|
|
|
vm->configFile[0] = '\0';
|
2007-02-23 09:07:41 +00:00
|
|
|
vm->autostartLink[0] = '\0';
|
2007-02-14 15:58:06 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveVM(driver, vm);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-27 01:21:09 +00:00
|
|
|
static int qemudDomainChangeCDROM(virDomainPtr dom,
|
|
|
|
struct qemud_vm *vm,
|
|
|
|
struct qemud_vm_disk_def *olddisk,
|
|
|
|
struct qemud_vm_disk_def *newdisk) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
char *cmd, *reply, *safe_path;
|
|
|
|
|
2008-03-13 09:17:45 +00:00
|
|
|
if (newdisk->src[0]) {
|
|
|
|
safe_path = qemudEscapeMonitorArg(newdisk->src);
|
|
|
|
if (!safe_path) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("out of memory"));
|
2008-03-13 09:17:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (asprintf (&cmd, "change %s \"%s\"",
|
|
|
|
/* XXX qemu may support multiple CDROM in future */
|
|
|
|
/* olddisk->dst */ "cdrom",
|
|
|
|
safe_path) == -1) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("out of memory"));
|
2008-03-13 09:17:45 +00:00
|
|
|
free(safe_path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(safe_path);
|
|
|
|
|
|
|
|
} else if (asprintf(&cmd, "eject cdrom") == -1) {
|
2007-10-27 01:21:09 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("out of memory"));
|
2007-10-27 01:21:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, _("cannot change cdrom media"));
|
2007-10-27 01:21:09 +00:00
|
|
|
free(cmd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(reply);
|
|
|
|
free(cmd);
|
2008-03-13 09:17:45 +00:00
|
|
|
strcpy(olddisk->src, newdisk->src);
|
2007-10-27 01:21:09 +00:00
|
|
|
olddisk->type = newdisk->type;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudDomainAttachDevice(virDomainPtr dom,
|
|
|
|
const char *xml) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
|
|
|
struct qemud_vm_device_def *dev;
|
|
|
|
struct qemud_vm_disk_def *disk;
|
|
|
|
|
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
|
2007-10-27 01:21:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!qemudIsActiveVM(vm)) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, _("cannot attach device on inactive domain"));
|
2007-10-27 01:21:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = qemudParseVMDeviceDef(dom->conn, driver, xml);
|
|
|
|
if (dev == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->type != QEMUD_DEVICE_DISK || dev->data.disk.device != QEMUD_DISK_CDROM) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, _("only CDROM disk devices can be attached"));
|
2007-10-27 01:21:09 +00:00
|
|
|
free(dev);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
disk = vm->def->disks;
|
|
|
|
while (disk) {
|
|
|
|
if (disk->device == QEMUD_DISK_CDROM &&
|
|
|
|
STREQ(disk->dst, dev->data.disk.dst))
|
|
|
|
break;
|
|
|
|
disk = disk->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!disk) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, _("CDROM not attached, cannot change media"));
|
2007-10-27 01:21:09 +00:00
|
|
|
free(dev);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemudDomainChangeCDROM(dom, vm, disk, &dev->data.disk) < 0) {
|
|
|
|
free(dev);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainGetAutostart(virDomainPtr dom,
|
2007-06-26 22:39:53 +00:00
|
|
|
int *autostart) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
2007-02-23 09:03:25 +00:00
|
|
|
|
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
|
2007-02-23 09:03:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*autostart = vm->autostart;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudDomainSetAutostart(virDomainPtr dom,
|
2007-06-26 22:39:53 +00:00
|
|
|
int autostart) {
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
|
2007-02-23 09:03:25 +00:00
|
|
|
|
|
|
|
if (!vm) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
|
2007-02-23 09:03:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
autostart = (autostart != 0);
|
|
|
|
|
|
|
|
if (vm->autostart == autostart)
|
|
|
|
return 0;
|
|
|
|
|
2007-02-23 09:07:41 +00:00
|
|
|
if (autostart) {
|
|
|
|
int err;
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if ((err = virFileMakePath(driver->autostartDir))) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("cannot create autostart directory %s: %s"),
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->autostartDir, strerror(err));
|
2007-02-23 09:07:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (symlink(vm->configFile, vm->autostartLink) < 0) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Failed to create symlink '%s' to '%s': %s"),
|
2007-02-23 09:07:41 +00:00
|
|
|
vm->autostartLink, vm->configFile, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (unlink(vm->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Failed to delete symlink '%s': %s"),
|
2007-02-23 09:07:41 +00:00
|
|
|
vm->autostartLink, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-23 09:03:25 +00:00
|
|
|
vm->autostart = autostart;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-26 18:41:43 +00:00
|
|
|
/* This uses the 'info blockstats' monitor command which was
|
|
|
|
* integrated into both qemu & kvm in late 2007. If the command is
|
|
|
|
* not supported we detect this and return the appropriate error.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudDomainBlockStats (virDomainPtr dom,
|
|
|
|
const char *path,
|
|
|
|
struct _virDomainBlockStats *stats)
|
|
|
|
{
|
|
|
|
const struct qemud_driver *driver =
|
|
|
|
(struct qemud_driver *)dom->conn->privateData;
|
|
|
|
char *dummy, *info;
|
|
|
|
const char *p, *eol;
|
|
|
|
char qemu_dev_name[32];
|
|
|
|
size_t len;
|
|
|
|
const struct qemud_vm *vm = qemudFindVMByID(driver, dom->id);
|
|
|
|
|
|
|
|
if (!vm) {
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching id %d"), dom->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!qemudIsActiveVM (vm)) {
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("domain is not running"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* QEMU internal block device names are different from the device
|
|
|
|
* names we use in libvirt, so we need to map between them:
|
|
|
|
*
|
|
|
|
* hd[a-] to ide0-hd[0-]
|
|
|
|
* cdrom to ide1-cd0
|
|
|
|
* fd[a-] to floppy[0-]
|
|
|
|
*/
|
|
|
|
if (STREQLEN (path, "hd", 2) && path[2] >= 'a' && path[2] <= 'z')
|
|
|
|
snprintf (qemu_dev_name, sizeof (qemu_dev_name),
|
|
|
|
"ide0-hd%d", path[2] - 'a');
|
|
|
|
else if (STREQ (path, "cdrom"))
|
|
|
|
strcpy (qemu_dev_name, "ide1-cd0");
|
|
|
|
else if (STREQLEN (path, "fd", 2) && path[2] >= 'a' && path[2] <= 'z')
|
|
|
|
snprintf (qemu_dev_name, sizeof (qemu_dev_name),
|
|
|
|
"floppy%d", path[2] - 'a');
|
|
|
|
else {
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
|
|
|
_("invalid path: %s"), path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen (qemu_dev_name);
|
|
|
|
|
|
|
|
if (qemudMonitorCommand (driver, vm, "info blockstats", &info) < 0) {
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("'info blockstats' command failed"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG ("info blockstats reply: %s", info);
|
|
|
|
|
|
|
|
/* If the command isn't supported then qemu prints the supported
|
|
|
|
* info commands, so the output starts "info ". Since this is
|
|
|
|
* unlikely to be the name of a block device, we can use this
|
|
|
|
* to detect if qemu supports the command.
|
|
|
|
*/
|
|
|
|
if (STREQLEN (info, "info ", 5)) {
|
|
|
|
free (info);
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s",
|
|
|
|
_("'info blockstats' not supported by this qemu"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
stats->rd_req = -1;
|
|
|
|
stats->rd_bytes = -1;
|
|
|
|
stats->wr_req = -1;
|
|
|
|
stats->wr_bytes = -1;
|
|
|
|
stats->errs = -1;
|
|
|
|
|
|
|
|
/* The output format for both qemu & KVM is:
|
|
|
|
* blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=%
|
|
|
|
* (repeated for each block device)
|
|
|
|
* where '%' is a 64 bit number.
|
|
|
|
*/
|
|
|
|
p = info;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (STREQLEN (p, qemu_dev_name, len)
|
|
|
|
&& p[len] == ':' && p[len+1] == ' ') {
|
|
|
|
|
|
|
|
eol = strchr (p, '\n');
|
|
|
|
if (!eol)
|
|
|
|
eol = p + strlen (p);
|
|
|
|
|
|
|
|
p += len+2; /* Skip to first label. */
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (STREQLEN (p, "rd_bytes=", 9)) {
|
|
|
|
p += 9;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, &stats->rd_bytes) == -1)
|
|
|
|
DEBUG ("error reading rd_bytes: %s", p);
|
|
|
|
} else if (STREQLEN (p, "wr_bytes=", 9)) {
|
|
|
|
p += 9;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, &stats->wr_bytes) == -1)
|
|
|
|
DEBUG ("error reading wr_bytes: %s", p);
|
|
|
|
} else if (STREQLEN (p, "rd_operations=", 14)) {
|
|
|
|
p += 14;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, &stats->rd_req) == -1)
|
|
|
|
DEBUG ("error reading rd_req: %s", p);
|
|
|
|
} else if (STREQLEN (p, "wr_operations=", 14)) {
|
|
|
|
p += 14;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, &stats->wr_req) == -1)
|
|
|
|
DEBUG ("error reading wr_req: %s", p);
|
|
|
|
} else
|
|
|
|
DEBUG ("unknown block stat near %s", p);
|
|
|
|
|
|
|
|
/* Skip to next label. */
|
|
|
|
p = strchr (p, ' ');
|
|
|
|
if (!p || p >= eol) break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip to next line. */
|
|
|
|
p = strchr (p, '\n');
|
|
|
|
if (!p) break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we reach here then the device was not found. */
|
|
|
|
free (info);
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
|
|
|
_("device not found: %s (%s)"), path, qemu_dev_name);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
done:
|
|
|
|
free (info);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-15 17:45:44 +00:00
|
|
|
static int
|
|
|
|
qemudDomainInterfaceStats (virDomainPtr dom,
|
|
|
|
const char *path,
|
|
|
|
struct _virDomainInterfaceStats *stats)
|
|
|
|
{
|
|
|
|
#ifdef __linux__
|
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
|
|
|
|
struct qemud_vm *vm = qemudFindVMByID (driver, dom->id);
|
|
|
|
struct qemud_vm_net_def *net;
|
|
|
|
|
|
|
|
if (!vm) {
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no domain with matching id %d"), dom->id);
|
2007-11-15 17:45:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!qemudIsActiveVM(vm)) {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("domain is not running"));
|
2007-11-15 17:45:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!path || path[0] == '\0') {
|
|
|
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("NULL or empty path"));
|
2007-11-15 17:45:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the path is one of the domain's network interfaces. */
|
|
|
|
for (net = vm->def->nets; net; net = net->next) {
|
|
|
|
switch (net->type) {
|
|
|
|
case QEMUD_NET_NETWORK:
|
|
|
|
if (STREQ (net->dst.network.ifname, path))
|
|
|
|
goto ok;
|
|
|
|
break;
|
|
|
|
case QEMUD_NET_ETHERNET:
|
|
|
|
if (STREQ (net->dst.ethernet.ifname, path))
|
|
|
|
goto ok;
|
|
|
|
break;
|
|
|
|
case QEMUD_NET_BRIDGE:
|
|
|
|
if (STREQ (net->dst.bridge.ifname, path))
|
|
|
|
goto ok;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("invalid path, '%s' is not a known interface"), path);
|
2007-11-15 17:45:44 +00:00
|
|
|
return -1;
|
|
|
|
ok:
|
|
|
|
|
|
|
|
return linuxDomainInterfaceStats (dom->conn, path, stats);
|
|
|
|
#else
|
|
|
|
qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", __FUNCTION__);
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2007-06-26 22:39:53 +00:00
|
|
|
const unsigned char *uuid) {
|
2007-07-04 03:59:13 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, uuid);
|
|
|
|
virNetworkPtr net;
|
|
|
|
|
|
|
|
if (!network) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK, _("no network with matching uuid"));
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
net = virGetNetwork(conn, network->def->name, network->def->uuid);
|
2007-06-26 22:39:53 +00:00
|
|
|
return net;
|
|
|
|
}
|
2007-06-29 13:23:13 +00:00
|
|
|
static virNetworkPtr qemudNetworkLookupByName(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2007-06-26 22:39:53 +00:00
|
|
|
const char *name) {
|
2007-07-04 03:59:13 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_network *network = qemudFindNetworkByName(driver, name);
|
|
|
|
virNetworkPtr net;
|
|
|
|
|
|
|
|
if (!network) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK, _("no network with matching name"));
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
net = virGetNetwork(conn, network->def->name, network->def->uuid);
|
2007-06-26 22:39:53 +00:00
|
|
|
return net;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virDrvOpenStatus qemudOpenNetwork(virConnectPtr conn,
|
2007-11-14 11:40:57 +00:00
|
|
|
xmlURIPtr uri ATTRIBUTE_UNUSED,
|
2007-12-05 18:28:05 +00:00
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
2007-06-26 22:39:53 +00:00
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
|
|
|
if (!qemu_driver)
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
|
|
|
|
|
|
|
conn->networkPrivateData = qemu_driver;
|
|
|
|
return VIR_DRV_OPEN_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudCloseNetwork(virConnectPtr conn) {
|
|
|
|
conn->networkPrivateData = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNumNetworks(virConnectPtr conn) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
return driver->nactivenetworks;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudListNetworks(virConnectPtr conn, char **const names, int nnames) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
struct qemud_network *network = driver->networks;
|
2007-06-26 22:39:53 +00:00
|
|
|
int got = 0, i;
|
2007-02-14 15:58:06 +00:00
|
|
|
while (network && got < nnames) {
|
2007-02-23 08:39:49 +00:00
|
|
|
if (qemudIsActiveNetwork(network)) {
|
2007-06-26 22:39:53 +00:00
|
|
|
if (!(names[got] = strdup(network->def->name))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-02-23 08:39:49 +00:00
|
|
|
got++;
|
|
|
|
}
|
2007-02-14 15:58:06 +00:00
|
|
|
network = network->next;
|
|
|
|
}
|
|
|
|
return got;
|
2007-06-26 22:39:53 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < got ; i++)
|
|
|
|
free(names[i]);
|
|
|
|
return -1;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNumDefinedNetworks(virConnectPtr conn) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
return driver->ninactivenetworks;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-06-26 22:13:21 +00:00
|
|
|
struct qemud_network *network = driver->networks;
|
2007-06-26 22:39:53 +00:00
|
|
|
int got = 0, i;
|
2007-02-14 15:58:06 +00:00
|
|
|
while (network && got < nnames) {
|
2007-02-23 08:39:49 +00:00
|
|
|
if (!qemudIsActiveNetwork(network)) {
|
2007-06-26 22:39:53 +00:00
|
|
|
if (!(names[got] = strdup(network->def->name))) {
|
|
|
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-02-23 08:39:49 +00:00
|
|
|
got++;
|
|
|
|
}
|
2007-02-14 15:58:06 +00:00
|
|
|
network = network->next;
|
|
|
|
}
|
|
|
|
return got;
|
2007-06-26 22:39:53 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < got ; i++)
|
|
|
|
free(names[i]);
|
|
|
|
return -1;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static virNetworkPtr qemudNetworkCreate(virConnectPtr conn, const char *xml) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network_def *def;
|
2007-02-14 15:58:06 +00:00
|
|
|
struct qemud_network *network;
|
2007-06-26 22:39:53 +00:00
|
|
|
virNetworkPtr net;
|
2007-02-14 15:58:06 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(def = qemudParseNetworkDef(conn, driver, xml, NULL)))
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(network = qemudAssignNetworkDef(conn, driver, def))) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudFreeNetworkDef(def);
|
2007-02-14 15:58:06 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudStartNetworkDaemon(conn, driver, network) < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveNetwork(driver, network);
|
2007-02-14 15:58:06 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
net = virGetNetwork(conn, network->def->name, network->def->uuid);
|
2007-06-26 22:39:53 +00:00
|
|
|
return net;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static virNetworkPtr qemudNetworkDefine(virConnectPtr conn, const char *xml) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
|
2007-02-23 08:48:02 +00:00
|
|
|
struct qemud_network_def *def;
|
|
|
|
struct qemud_network *network;
|
2007-06-26 22:39:53 +00:00
|
|
|
virNetworkPtr net;
|
2007-02-23 08:48:02 +00:00
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(def = qemudParseNetworkDef(conn, driver, xml, NULL)))
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (!(network = qemudAssignNetworkDef(conn, driver, def))) {
|
2007-02-23 08:48:02 +00:00
|
|
|
qemudFreeNetworkDef(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudSaveNetworkDef(conn, driver, network, def) < 0) {
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveNetwork(driver, network);
|
2007-02-23 08:48:02 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
net = virGetNetwork(conn, network->def->name, network->def->uuid);
|
2007-06-26 22:39:53 +00:00
|
|
|
return net;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNetworkUndefine(virNetworkPtr net) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData;
|
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, net->uuid);
|
2007-02-14 15:58:06 +00:00
|
|
|
|
|
|
|
if (!network) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_DOMAIN, _("no network with matching uuid"));
|
2007-02-14 15:58:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
if (qemudDeleteConfig(net->conn, driver, network->configFile, network->def->name) < 0)
|
2007-02-14 15:58:06 +00:00
|
|
|
return -1;
|
|
|
|
|
2007-02-23 09:07:41 +00:00
|
|
|
if (unlink(network->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR)
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
qemudLog(QEMUD_WARN, _("Failed to delete autostart link '%s': %s"),
|
2007-02-23 09:07:41 +00:00
|
|
|
network->autostartLink, strerror(errno));
|
|
|
|
|
2007-02-14 15:58:06 +00:00
|
|
|
network->configFile[0] = '\0';
|
2007-02-23 09:07:41 +00:00
|
|
|
network->autostartLink[0] = '\0';
|
2007-02-14 15:58:06 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
qemudRemoveInactiveNetwork(driver, network);
|
2007-02-14 15:58:06 +00:00
|
|
|
|
|
|
|
return 0;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNetworkStart(virNetworkPtr net) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData;
|
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, net->uuid);
|
2007-02-23 08:41:23 +00:00
|
|
|
|
|
|
|
if (!network) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no network with matching uuid"));
|
2007-06-26 22:39:53 +00:00
|
|
|
return -1;
|
2007-02-23 08:41:23 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
return qemudStartNetworkDaemon(net->conn, driver, network);
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNetworkDestroy(virNetworkPtr net) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData;
|
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, net->uuid);
|
2007-07-06 21:52:42 +00:00
|
|
|
int ret;
|
2007-02-23 08:41:23 +00:00
|
|
|
|
2007-02-14 15:58:06 +00:00
|
|
|
if (!network) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no network with matching uuid"));
|
2007-02-14 15:58:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
ret = qemudShutdownNetworkDaemon(net->conn, driver, network);
|
2007-07-06 21:52:42 +00:00
|
|
|
|
|
|
|
return ret;
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static char *qemudNetworkDumpXML(virNetworkPtr net, int flags ATTRIBUTE_UNUSED) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData;
|
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, net->uuid);
|
|
|
|
|
2007-02-14 15:58:06 +00:00
|
|
|
if (!network) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("no network with matching uuid"));
|
2007-06-26 22:39:53 +00:00
|
|
|
return NULL;
|
2007-02-14 15:58:06 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:09:01 +00:00
|
|
|
return qemudGenerateNetworkXML(net->conn, driver, network, network->def);
|
2007-02-14 15:54:10 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static char *qemudNetworkGetBridgeName(virNetworkPtr net) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData;
|
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, net->uuid);
|
|
|
|
char *bridge;
|
2007-02-14 16:20:38 +00:00
|
|
|
if (!network) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, "no network with matching id");
|
|
|
|
return NULL;
|
2007-02-14 16:20:38 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 22:39:53 +00:00
|
|
|
bridge = strdup(network->bridge);
|
|
|
|
if (!bridge) {
|
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_NO_MEMORY, "bridge");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return bridge;
|
2007-02-14 16:20:38 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNetworkGetAutostart(virNetworkPtr net,
|
2007-02-23 09:03:25 +00:00
|
|
|
int *autostart) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData;
|
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, net->uuid);
|
2007-02-23 09:03:25 +00:00
|
|
|
|
|
|
|
if (!network) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, _("no network with matching uuid"));
|
2007-02-23 09:03:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*autostart = network->autostart;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
static int qemudNetworkSetAutostart(virNetworkPtr net,
|
2007-02-23 09:03:25 +00:00
|
|
|
int autostart) {
|
2007-06-26 22:39:53 +00:00
|
|
|
struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData;
|
|
|
|
struct qemud_network *network = qemudFindNetworkByUUID(driver, net->uuid);
|
2007-02-23 09:03:25 +00:00
|
|
|
|
|
|
|
if (!network) {
|
2008-03-24 10:51:47 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, _("no network with matching uuid"));
|
2007-02-23 09:03:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
autostart = (autostart != 0);
|
|
|
|
|
|
|
|
if (network->autostart == autostart)
|
|
|
|
return 0;
|
|
|
|
|
2007-02-23 09:07:41 +00:00
|
|
|
if (autostart) {
|
|
|
|
int err;
|
|
|
|
|
2007-12-03 14:30:46 +00:00
|
|
|
if ((err = virFileMakePath(driver->networkAutostartDir))) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("cannot create autostart directory %s: %s"),
|
2007-06-26 22:13:21 +00:00
|
|
|
driver->networkAutostartDir, strerror(err));
|
2007-02-23 09:07:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (symlink(network->configFile, network->autostartLink) < 0) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Failed to create symlink '%s' to '%s': %s"),
|
2007-02-23 09:07:41 +00:00
|
|
|
network->autostartLink, network->configFile, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (unlink(network->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
|
2008-03-24 10:51:47 +00:00
|
|
|
_("Failed to delete symlink '%s': %s"),
|
2007-02-23 09:07:41 +00:00
|
|
|
network->autostartLink, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-23 09:03:25 +00:00
|
|
|
network->autostart = autostart;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:39:53 +00:00
|
|
|
static virDriver qemuDriver = {
|
|
|
|
VIR_DRV_QEMU,
|
|
|
|
"QEMU",
|
|
|
|
LIBVIR_VERSION_NUMBER,
|
2008-02-26 07:05:18 +00:00
|
|
|
qemudProbe, /* probe */
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudOpen, /* open */
|
|
|
|
qemudClose, /* close */
|
2007-08-21 09:03:55 +00:00
|
|
|
NULL, /* supports_feature */
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudGetType, /* type */
|
|
|
|
qemudGetVersion, /* version */
|
2007-09-20 17:13:39 +00:00
|
|
|
qemudGetHostname, /* hostname */
|
2007-11-14 11:40:57 +00:00
|
|
|
NULL, /* URI */
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudGetMaxVCPUs, /* getMaxVcpus */
|
|
|
|
qemudGetNodeInfo, /* nodeGetInfo */
|
|
|
|
qemudGetCapabilities, /* getCapabilities */
|
|
|
|
qemudListDomains, /* listDomains */
|
|
|
|
qemudNumDomains, /* numOfDomains */
|
|
|
|
qemudDomainCreate, /* domainCreateLinux */
|
|
|
|
qemudDomainLookupByID, /* domainLookupByID */
|
|
|
|
qemudDomainLookupByUUID, /* domainLookupByUUID */
|
|
|
|
qemudDomainLookupByName, /* domainLookupByName */
|
|
|
|
qemudDomainSuspend, /* domainSuspend */
|
|
|
|
qemudDomainResume, /* domainResume */
|
2008-01-09 16:05:21 +00:00
|
|
|
qemudDomainShutdown, /* domainShutdown */
|
2007-06-26 22:39:53 +00:00
|
|
|
NULL, /* domainReboot */
|
|
|
|
qemudDomainDestroy, /* domainDestroy */
|
|
|
|
qemudDomainGetOSType, /* domainGetOSType */
|
2008-03-19 14:32:50 +00:00
|
|
|
qemudDomainGetMaxMemory, /* domainGetMaxMemory */
|
|
|
|
qemudDomainSetMaxMemory, /* domainSetMaxMemory */
|
|
|
|
qemudDomainSetMemory, /* domainSetMemory */
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudDomainGetInfo, /* domainGetInfo */
|
|
|
|
qemudDomainSave, /* domainSave */
|
|
|
|
qemudDomainRestore, /* domainRestore */
|
|
|
|
NULL, /* domainCoreDump */
|
|
|
|
NULL, /* domainSetVcpus */
|
|
|
|
NULL, /* domainPinVcpu */
|
|
|
|
NULL, /* domainGetVcpus */
|
|
|
|
NULL, /* domainGetMaxVcpus */
|
|
|
|
qemudDomainDumpXML, /* domainDumpXML */
|
|
|
|
qemudListDefinedDomains, /* listDomains */
|
|
|
|
qemudNumDefinedDomains, /* numOfDomains */
|
|
|
|
qemudDomainStart, /* domainCreate */
|
|
|
|
qemudDomainDefine, /* domainDefineXML */
|
|
|
|
qemudDomainUndefine, /* domainUndefine */
|
2007-10-27 01:21:09 +00:00
|
|
|
qemudDomainAttachDevice, /* domainAttachDevice */
|
2007-06-26 22:39:53 +00:00
|
|
|
NULL, /* domainDetachDevice */
|
|
|
|
qemudDomainGetAutostart, /* domainGetAutostart */
|
|
|
|
qemudDomainSetAutostart, /* domainSetAutostart */
|
|
|
|
NULL, /* domainGetSchedulerType */
|
|
|
|
NULL, /* domainGetSchedulerParameters */
|
|
|
|
NULL, /* domainSetSchedulerParameters */
|
2007-08-21 09:31:12 +00:00
|
|
|
NULL, /* domainMigratePrepare */
|
|
|
|
NULL, /* domainMigratePerform */
|
|
|
|
NULL, /* domainMigrateFinish */
|
2008-02-26 18:41:43 +00:00
|
|
|
qemudDomainBlockStats, /* domainBlockStats */
|
2007-11-15 17:45:44 +00:00
|
|
|
qemudDomainInterfaceStats, /* domainInterfaceStats */
|
2007-09-28 14:28:12 +00:00
|
|
|
NULL, /* nodeGetCellsFreeMemory */
|
2007-09-30 13:09:07 +00:00
|
|
|
NULL, /* getFreeMemory */
|
2007-06-26 22:39:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static virNetworkDriver qemuNetworkDriver = {
|
2007-07-27 23:23:00 +00:00
|
|
|
"QEMU",
|
2007-06-26 22:39:53 +00:00
|
|
|
qemudOpenNetwork, /* open */
|
|
|
|
qemudCloseNetwork, /* close */
|
|
|
|
qemudNumNetworks, /* numOfNetworks */
|
|
|
|
qemudListNetworks, /* listNetworks */
|
|
|
|
qemudNumDefinedNetworks, /* numOfDefinedNetworks */
|
|
|
|
qemudListDefinedNetworks, /* listDefinedNetworks */
|
|
|
|
qemudNetworkLookupByUUID, /* networkLookupByUUID */
|
|
|
|
qemudNetworkLookupByName, /* networkLookupByName */
|
|
|
|
qemudNetworkCreate, /* networkCreateXML */
|
|
|
|
qemudNetworkDefine, /* networkDefineXML */
|
|
|
|
qemudNetworkUndefine, /* networkUndefine */
|
|
|
|
qemudNetworkStart, /* networkCreate */
|
|
|
|
qemudNetworkDestroy, /* networkDestroy */
|
|
|
|
qemudNetworkDumpXML, /* networkDumpXML */
|
|
|
|
qemudNetworkGetBridgeName, /* networkGetBridgeName */
|
|
|
|
qemudNetworkGetAutostart, /* networkGetAutostart */
|
|
|
|
qemudNetworkSetAutostart, /* networkSetAutostart */
|
|
|
|
};
|
|
|
|
|
2007-06-26 22:56:14 +00:00
|
|
|
static virStateDriver qemuStateDriver = {
|
|
|
|
qemudStartup,
|
|
|
|
qemudShutdown,
|
|
|
|
qemudReload,
|
|
|
|
qemudActive,
|
|
|
|
};
|
2007-06-26 22:39:53 +00:00
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
int qemudRegister(void) {
|
|
|
|
virRegisterDriver(&qemuDriver);
|
|
|
|
virRegisterNetworkDriver(&qemuNetworkDriver);
|
|
|
|
virRegisterStateDriver(&qemuStateDriver);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-26 11:50:16 +00:00
|
|
|
#endif /* WITH_QEMU */
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* c-indent-level: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 4
|
|
|
|
* End:
|
|
|
|
*/
|