2008-02-20 15:34:52 +00:00
|
|
|
/*
|
Mark many more strings for translation.
* Makefile.maint (err_func_re): Add to the list and make it readable.
* po/POTFILES.in: Add src/util.c and src/xm_internal.c, and sort.
* src/storage_backend.c: Fix comment.
* src/util.c (virFileLinkPointsTo): Mark a string.
* qemud/remote.c (remoteDispatchClientRequest): Mark strings.
(remoteDispatchOpen, CHECK_CONN, remoteDispatchGetType): Likewise.
(remoteDispatchDomainGetSchedulerType): Likewise.
(remoteDispatchDomainGetSchedulerParameters): Likewise.
(remoteDispatchDomainSetSchedulerParameters): Likewise.
(remoteDispatchDomainBlockStats): Likewise.
(remoteDispatchDomainInterfaceStats): Likewise.
(remoteDispatchDomainAttachDevice, remoteDispatchDomainCreate):
(remoteDispatchDomainDestroy, remoteDispatchDomainDetachDevice):
(remoteDispatchDomainDumpXml, remoteDispatchDomainGetAutostart):
(remoteDispatchDomainGetInfo, remoteDispatchDomainGetMaxMemory):
(remoteDispatchDomainGetMaxVcpus, remoteDispatchDomainGetOsType):
(remoteDispatchDomainGetVcpus): Likewise.
(remoteDispatchDomainMigratePerform): Likewise.
(remoteDispatchListDefinedDomains, remoteDispatchDomainPinVcpu):
(remoteDispatchDomainReboot, remoteDispatchDomainResume):
(remoteDispatchDomainSave, remoteDispatchDomainCoreDump):
(remoteDispatchDomainSetAutostart): Likewise.
(remoteDispatchDomainSetMaxMemory, remoteDispatchDomainSetMemory):
(remoteDispatchDomainSetVcpus, remoteDispatchDomainShutdown):
(remoteDispatchDomainSuspend, remoteDispatchDomainUndefine):
(remoteDispatchListDefinedNetworks, remoteDispatchListDomains):
(remoteDispatchListNetworks, remoteDispatchNetworkCreate):
(remoteDispatchNetworkDestroy, remoteDispatchNetworkDumpXml):
(remoteDispatchNetworkGetAutostart, remoteDispatchNetworkGetBridgeName):
(remoteDispatchNetworkSetAutostart, remoteDispatchNetworkUndefine):
(addrToString, remoteDispatchAuthSaslInit, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchListDefinedStoragePools):
(remoteDispatchListStoragePools, remoteDispatchStoragePoolCreate):
(remoteDispatchStoragePoolBuild, remoteDispatchStoragePoolDestroy):
(remoteDispatchStoragePoolDelete, remoteDispatchStoragePoolRefresh):
(remoteDispatchStoragePoolGetInfo, remoteDispatchStoragePoolDumpXml):
(remoteDispatchStoragePoolGetAutostart): Likewise.
(remoteDispatchStoragePoolSetAutostart):
(remoteDispatchStoragePoolListVolumes):
(remoteDispatchStoragePoolNumOfVolumes):
(remoteDispatchStoragePoolUndefine, remoteDispatchStorageVolCreateXml):
(remoteDispatchStorageVolDelete, remoteDispatchStorageVolGetInfo):
(remoteDispatchStorageVolDumpXml, remoteDispatchStorageVolGetPath):
(remoteDispatchStorageVolLookupByName): Likewise.
* src/qemu_driver.c (qemudOpenMonitor, qemudStartVMDaemon):
(dhcpStartDhcpDaemon, qemudStartNetworkDaemon):
(qemudDomainSuspend, qemudDomainResume, qemudDomainShutdown):
(qemudDomainGetOSType, qemudDomainSetMaxMemory):
(qemudDomainSetMemory, qemudDomainGetInfo, qemudDomainSave):
(qemudDomainRestore, qemudDomainDumpXML, qemudDomainStart):
(qemudDomainUndefine, qemudDomainChangeCDROM):
(qemudDomainAttachDevice, qemudDomainGetAutostart):
(qemudDomainSetAutostart, qemudDomainInterfaceStats):
(qemudNetworkLookupByUUID, qemudNetworkLookupByName):
(qemudNetworkUndefine, qemudNetworkStart, qemudNetworkDestroy):
(qemudNetworkDumpXML, qemudNetworkGetAutostart):
(qemudNetworkSetAutostart): Likewise.
* src/virsh.c (cmdVcpupin, cmdAttachDevice, cmdDetachDevice): Likewise.
* src/xm_internal.c (xenXMConfigCacheRefresh, xenXMDomainPinVcpu): Likewise.
2008-03-27 13:43:01 +00:00
|
|
|
* storage_backend.c: internal storage driver backend contract
|
2008-02-20 15:34:52 +00:00
|
|
|
*
|
2009-09-03 08:22:57 +00:00
|
|
|
* Copyright (C) 2007-2009 Red Hat, Inc.
|
2008-02-20 15:34:52 +00:00
|
|
|
* Copyright (C) 2007-2008 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
2008-11-17 11:19:33 +00:00
|
|
|
#include <stdio.h>
|
2008-09-05 12:03:45 +00:00
|
|
|
#if HAVE_REGEX_H
|
2008-02-20 15:34:52 +00:00
|
|
|
#include <regex.h>
|
2008-09-05 12:03:45 +00:00
|
|
|
#endif
|
2008-02-20 15:34:52 +00:00
|
|
|
#include <sys/types.h>
|
2008-09-05 12:03:45 +00:00
|
|
|
#if HAVE_SYS_WAIT_H
|
2008-02-20 15:34:52 +00:00
|
|
|
#include <sys/wait.h>
|
2008-09-05 12:03:45 +00:00
|
|
|
#endif
|
2008-02-20 15:34:52 +00:00
|
|
|
#include <unistd.h>
|
2008-02-20 15:38:29 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <sys/stat.h>
|
2009-04-03 14:13:02 +00:00
|
|
|
#include <sys/param.h>
|
2008-02-20 15:38:29 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
#if HAVE_SELINUX
|
|
|
|
#include <selinux/selinux.h>
|
|
|
|
#endif
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
|
2009-08-14 18:06:59 +00:00
|
|
|
#include "datatypes.h"
|
2008-11-04 22:30:33 +00:00
|
|
|
#include "virterror_internal.h"
|
2008-09-05 12:03:45 +00:00
|
|
|
#include "util.h"
|
|
|
|
#include "memory.h"
|
2009-09-03 08:22:57 +00:00
|
|
|
#include "internal.h"
|
2009-08-14 18:06:59 +00:00
|
|
|
#include "secret_conf.h"
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
#include "uuid.h"
|
2009-09-25 13:20:13 +00:00
|
|
|
#include "storage_file.h"
|
2008-09-05 12:03:45 +00:00
|
|
|
#include "storage_backend.h"
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
#include "logging.h"
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
|
2008-11-12 16:28:27 +00:00
|
|
|
#if WITH_STORAGE_LVM
|
|
|
|
#include "storage_backend_logical.h"
|
|
|
|
#endif
|
|
|
|
#if WITH_STORAGE_ISCSI
|
|
|
|
#include "storage_backend_iscsi.h"
|
|
|
|
#endif
|
2009-04-01 16:03:22 +00:00
|
|
|
#if WITH_STORAGE_SCSI
|
|
|
|
#include "storage_backend_scsi.h"
|
|
|
|
#endif
|
2009-09-08 13:47:45 +00:00
|
|
|
#if WITH_STORAGE_MPATH
|
|
|
|
#include "storage_backend_mpath.h"
|
|
|
|
#endif
|
2008-11-12 16:28:27 +00:00
|
|
|
#if WITH_STORAGE_DISK
|
|
|
|
#include "storage_backend_disk.h"
|
|
|
|
#endif
|
|
|
|
#if WITH_STORAGE_DIR
|
|
|
|
#include "storage_backend_fs.h"
|
|
|
|
#endif
|
|
|
|
|
2009-04-03 14:13:02 +00:00
|
|
|
#ifndef DEV_BSIZE
|
|
|
|
#define DEV_BSIZE 512
|
|
|
|
#endif
|
2008-10-16 15:06:03 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
|
|
2008-11-12 16:28:27 +00:00
|
|
|
static virStorageBackendPtr backends[] = {
|
|
|
|
#if WITH_STORAGE_DIR
|
|
|
|
&virStorageBackendDirectory,
|
|
|
|
#endif
|
|
|
|
#if WITH_STORAGE_FS
|
|
|
|
&virStorageBackendFileSystem,
|
|
|
|
&virStorageBackendNetFileSystem,
|
|
|
|
#endif
|
|
|
|
#if WITH_STORAGE_LVM
|
|
|
|
&virStorageBackendLogical,
|
|
|
|
#endif
|
|
|
|
#if WITH_STORAGE_ISCSI
|
|
|
|
&virStorageBackendISCSI,
|
|
|
|
#endif
|
2009-04-01 16:03:22 +00:00
|
|
|
#if WITH_STORAGE_SCSI
|
|
|
|
&virStorageBackendSCSI,
|
|
|
|
#endif
|
2009-09-08 13:47:45 +00:00
|
|
|
#if WITH_STORAGE_MPATH
|
|
|
|
&virStorageBackendMpath,
|
|
|
|
#endif
|
2008-11-12 16:28:27 +00:00
|
|
|
#if WITH_STORAGE_DISK
|
|
|
|
&virStorageBackendDisk,
|
|
|
|
#endif
|
|
|
|
NULL
|
|
|
|
};
|
2008-11-11 15:52:16 +00:00
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
static int track_allocation_progress = 0;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
TOOL_QEMU_IMG,
|
|
|
|
TOOL_KVM_IMG,
|
|
|
|
TOOL_QCOW_CREATE,
|
|
|
|
};
|
|
|
|
|
2009-09-03 08:22:57 +00:00
|
|
|
static int ATTRIBUTE_NONNULL (3)
|
2009-06-25 22:34:59 +00:00
|
|
|
virStorageBackendCopyToFD(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol,
|
|
|
|
virStorageVolDefPtr inputvol,
|
|
|
|
int fd,
|
2009-07-10 18:04:27 +00:00
|
|
|
unsigned long long *total,
|
|
|
|
int is_dest_file)
|
2009-06-25 22:34:59 +00:00
|
|
|
{
|
|
|
|
int inputfd = -1;
|
|
|
|
int amtread = -1;
|
|
|
|
int ret = -1;
|
|
|
|
unsigned long long remain;
|
|
|
|
size_t bytes = 1024 * 1024;
|
|
|
|
char zerobuf[512];
|
|
|
|
char *buf = NULL;
|
|
|
|
|
2009-09-03 08:22:57 +00:00
|
|
|
if ((inputfd = open(inputvol->target.path, O_RDONLY)) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("could not open input path '%s'"),
|
|
|
|
inputvol->target.path);
|
|
|
|
goto cleanup;
|
2009-06-25 22:34:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bzero(&zerobuf, sizeof(zerobuf));
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(buf, bytes) < 0) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
remain = *total;
|
|
|
|
|
|
|
|
while (amtread != 0) {
|
|
|
|
int amtleft;
|
|
|
|
|
|
|
|
if (remain < bytes)
|
|
|
|
bytes = remain;
|
|
|
|
|
|
|
|
if ((amtread = saferead(inputfd, buf, bytes)) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("failed reading from file '%s'"),
|
|
|
|
inputvol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
remain -= amtread;
|
|
|
|
|
|
|
|
/* Loop over amt read in 512 byte increments, looking for sparse
|
|
|
|
* blocks */
|
|
|
|
amtleft = amtread;
|
|
|
|
do {
|
|
|
|
int interval = ((512 > amtleft) ? amtleft : 512);
|
|
|
|
int offset = amtread - amtleft;
|
|
|
|
|
2009-07-10 18:04:27 +00:00
|
|
|
if (is_dest_file && memcmp(buf+offset, zerobuf, interval) == 0) {
|
2009-06-25 22:34:59 +00:00
|
|
|
if (lseek(fd, interval, SEEK_CUR) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot extend file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (safewrite(fd, buf+offset, interval) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("failed writing to file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
}
|
|
|
|
} while ((amtleft -= 512) > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inputfd != -1 && close(inputfd) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot close file '%s'"),
|
|
|
|
inputvol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
inputfd = -1;
|
|
|
|
|
|
|
|
*total -= remain;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (inputfd != -1)
|
|
|
|
close(inputfd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-07-09 23:14:51 +00:00
|
|
|
static int
|
|
|
|
virStorageBackendCreateBlockFrom(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol,
|
|
|
|
virStorageVolDefPtr inputvol,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
unsigned long long remain;
|
|
|
|
|
|
|
|
if ((fd = open(vol->target.path, O_RDWR)) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot create path '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
remain = vol->allocation;
|
|
|
|
|
|
|
|
if (inputvol) {
|
2009-07-10 18:04:27 +00:00
|
|
|
int res = virStorageBackendCopyToFD(conn, vol, inputvol,
|
|
|
|
fd, &remain, 0);
|
2009-07-09 23:14:51 +00:00
|
|
|
if (res < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot close file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
fd = -1;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (fd != -1)
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
int
|
|
|
|
virStorageBackendCreateRaw(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol,
|
2009-07-16 16:27:07 +00:00
|
|
|
virStorageVolDefPtr inputvol,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED)
|
2009-07-16 16:09:26 +00:00
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
unsigned long long remain;
|
|
|
|
char *buf = NULL;
|
|
|
|
|
2009-07-21 02:40:50 +00:00
|
|
|
if (vol->target.encryption != NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("storage pool does not support encrypted "
|
|
|
|
"volumes"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL,
|
|
|
|
vol->target.perms.mode)) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot create path '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Seek to the final size, so the capacity is available upfront
|
|
|
|
* for progress reporting */
|
|
|
|
if (ftruncate(fd, vol->capacity) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot extend file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
remain = vol->allocation;
|
|
|
|
|
2009-06-25 22:34:59 +00:00
|
|
|
if (inputvol) {
|
2009-07-10 18:04:27 +00:00
|
|
|
int res = virStorageBackendCopyToFD(conn, vol, inputvol,
|
|
|
|
fd, &remain, 1);
|
2009-06-25 22:34:59 +00:00
|
|
|
if (res < 0)
|
2009-07-16 16:09:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (remain) {
|
|
|
|
if (track_allocation_progress) {
|
|
|
|
|
|
|
|
while (remain) {
|
|
|
|
/* Allocate in chunks of 512MiB: big-enough chunk
|
|
|
|
* size and takes approx. 9s on ext3. A progress
|
|
|
|
* update every 9s is a fair-enough trade-off
|
|
|
|
*/
|
|
|
|
unsigned long long bytes = 512 * 1024 * 1024;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (bytes > remain)
|
|
|
|
bytes = remain;
|
|
|
|
if ((r = safezero(fd, 0, vol->allocation - remain,
|
|
|
|
bytes)) != 0) {
|
|
|
|
virReportSystemError(conn, r,
|
|
|
|
_("cannot fill file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
remain -= bytes;
|
|
|
|
}
|
|
|
|
} else { /* No progress bars to be shown */
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if ((r = safezero(fd, 0, 0, remain)) != 0) {
|
|
|
|
virReportSystemError(conn, r,
|
|
|
|
_("cannot fill file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot close file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
fd = -1;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (fd != -1)
|
|
|
|
close(fd);
|
|
|
|
VIR_FREE(buf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
static int
|
|
|
|
virStorageGenerateSecretUUID(virConnectPtr conn,
|
|
|
|
unsigned char *uuid)
|
|
|
|
{
|
|
|
|
unsigned attempt;
|
|
|
|
|
|
|
|
for (attempt = 0; attempt < 65536; attempt++) {
|
|
|
|
virSecretPtr tmp;
|
|
|
|
if (virUUIDGenerate(uuid) < 0) {
|
|
|
|
virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unable to generate uuid"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
tmp = conn->secretDriver->lookupByUUID(conn, uuid);
|
|
|
|
if (tmp == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virSecretFree(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("too many conflicts when generating an uuid"));
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-08-14 18:06:59 +00:00
|
|
|
static int
|
|
|
|
virStorageGenerateQcowEncryption(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol)
|
|
|
|
{
|
|
|
|
virSecretDefPtr def = NULL;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
virStorageEncryptionPtr enc;
|
|
|
|
virStorageEncryptionSecretPtr enc_secret = NULL;
|
|
|
|
virSecretPtr secret = NULL;
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
char *xml;
|
2009-08-14 18:06:59 +00:00
|
|
|
unsigned char value[VIR_STORAGE_QCOW_PASSPHRASE_SIZE];
|
|
|
|
int ret = -1;
|
|
|
|
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
if (conn->secretDriver == NULL ||
|
|
|
|
conn->secretDriver->lookupByUUID == NULL ||
|
|
|
|
conn->secretDriver->defineXML == NULL ||
|
2009-08-14 18:06:59 +00:00
|
|
|
conn->secretDriver->setValue == NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("secret storage not supported"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
enc = vol->target.encryption;
|
|
|
|
if (enc->nsecrets != 0) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("secrets already defined"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(enc_secret) < 0 || VIR_REALLOC_N(enc->secrets, 1) < 0 ||
|
|
|
|
VIR_ALLOC(def) < 0) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->ephemeral = 0;
|
|
|
|
def->private = 0;
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
if (virStorageGenerateSecretUUID(conn, def->uuid) < 0)
|
2009-08-14 18:06:59 +00:00
|
|
|
goto cleanup;
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
|
2009-08-14 18:06:59 +00:00
|
|
|
def->usage_type = VIR_SECRET_USAGE_TYPE_VOLUME;
|
|
|
|
def->usage.volume = strdup(vol->target.path);
|
|
|
|
if (def->usage.volume == NULL) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
xml = virSecretDefFormat(conn, def);
|
|
|
|
virSecretDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
if (xml == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
secret = conn->secretDriver->defineXML(conn, xml, 0);
|
|
|
|
if (secret == NULL) {
|
|
|
|
VIR_FREE(xml);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(xml);
|
|
|
|
|
|
|
|
if (virStorageGenerateQcowPassphrase(conn, value) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (conn->secretDriver->setValue(secret, value, sizeof(value), 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
enc_secret->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
memcpy(enc_secret->uuid, secret->uuid, VIR_UUID_BUFLEN);
|
2009-08-14 18:06:59 +00:00
|
|
|
enc->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
|
|
|
|
enc->secrets[0] = enc_secret; /* Space for secrets[0] allocated above */
|
|
|
|
enc_secret = NULL;
|
|
|
|
enc->nsecrets = 1;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (secret != NULL) {
|
Fix UUID handling in secrets/storage encryption APIs
Convert all the secret/storage encryption APIs / wire format to
handle UUIDs in raw format instead of non-canonical printable
format. Guarentees data format correctness.
* docs/schemas/storageencryption.rng: Make UUID mandatory for a secret
and validate fully
* docs/schemas/secret.rng: Fully validate UUID
* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add
virSecretLookupByUUID and virSecretGetUUID. Make
virSecretGetUUIDString follow normal API design pattern
* python/generator.py: Skip generation of virSecretGetUUID,
virSecretGetUUIDString and virSecretLookupByUUID
* python/libvir.c, python/libvirt-python-api.xml: Manual impl
of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID
* qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/
Fix get_nonnull_secret/make_nonnull_secret to use unsigned char
* qemud/remote_protocol.x: Fix remote_nonnull_secret to use a
remote_uuid instead of remote_nonnull_string for UUID field.
Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to
REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an
remote_uuid value
* qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h,
qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h,
qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate
* src/datatypes.h, src/datatypes.c: Store UUID in raw format instead
of printable. Change virGetSecret to use raw format UUID
* src/driver.h: Rename virDrvSecretLookupByUUIDString to
virDrvSecretLookupByUUID and use raw format UUID
* src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID
and re-implement virSecretLookupByUUIDString and
virSecretGetUUIDString in terms of those
* src/libvirt_public.syms: Add virSecretLookupByUUID and
virSecretGetUUID
* src/remote_internal.c: Rename remoteSecretLookupByUUIDString
to remoteSecretLookupByUUID. Fix typo in args for
remoteSecretDefineXML impl. Use raw UUID format for
get_nonnull_secret and make_nonnull_secret
* src/storage_encryption_conf.c, src/storage_encryption_conf.h:
Storage UUID in raw format, and require it to be present in
XML. Use UUID parser to validate.
* secret_conf.h, secret_conf.c: Generate a UUID if none is provided.
Storage UUID in raw format.
* src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets
in a filed with printable UUID, instead of base64 UUID.
* src/virsh.c: Adjust for changed public API contract of
virSecretGetUUIDString.
* src/storage_Backend.c: DOn't undefine secret we just generated
upon successful volume creation. Fix to handle raw UUIDs. Generate
a non-clashing UUID
* src/qemu_driver.c: Change to use lookupByUUID instead of
lookupByUUIDString
2009-09-10 16:44:12 +00:00
|
|
|
if (ret != 0 &&
|
|
|
|
conn->secretDriver->undefine != NULL)
|
2009-08-14 18:06:59 +00:00
|
|
|
conn->secretDriver->undefine(secret);
|
|
|
|
virSecretFree(secret);
|
|
|
|
}
|
|
|
|
xml = virBufferContentAndReset(&buf);
|
|
|
|
VIR_FREE(xml);
|
|
|
|
virSecretDefFree(def);
|
|
|
|
VIR_FREE(enc_secret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
static int
|
|
|
|
virStorageBackendCreateQemuImg(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol,
|
2009-07-16 16:27:07 +00:00
|
|
|
virStorageVolDefPtr inputvol,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED)
|
2009-07-16 16:09:26 +00:00
|
|
|
{
|
|
|
|
char size[100];
|
|
|
|
char *create_tool;
|
|
|
|
short use_kvmimg;
|
|
|
|
|
2009-09-25 13:20:13 +00:00
|
|
|
const char *type = virStorageFileFormatTypeToString(vol->target.format);
|
2009-07-16 16:09:26 +00:00
|
|
|
const char *backingType = vol->backingStore.path ?
|
2009-09-25 13:20:13 +00:00
|
|
|
virStorageFileFormatTypeToString(vol->backingStore.format) : NULL;
|
2009-07-16 16:09:26 +00:00
|
|
|
|
|
|
|
const char *inputBackingPath = (inputvol ? inputvol->backingStore.path
|
|
|
|
: NULL);
|
|
|
|
const char *inputPath = inputvol ? inputvol->target.path : NULL;
|
|
|
|
/* Treat input block devices as 'raw' format */
|
|
|
|
const char *inputType = inputPath ?
|
2009-09-25 13:20:13 +00:00
|
|
|
virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_FILE_RAW : inputvol->target.format) :
|
2009-07-16 16:09:26 +00:00
|
|
|
NULL;
|
|
|
|
|
|
|
|
const char **imgargv;
|
2009-07-21 02:40:50 +00:00
|
|
|
/* The extra NULL field is for indicating encryption (-e). */
|
2009-07-16 16:09:26 +00:00
|
|
|
const char *imgargvnormal[] = {
|
|
|
|
NULL, "create",
|
|
|
|
"-f", type,
|
|
|
|
vol->target.path,
|
|
|
|
size,
|
|
|
|
NULL,
|
2009-07-21 02:40:50 +00:00
|
|
|
NULL
|
2009-07-16 16:09:26 +00:00
|
|
|
};
|
|
|
|
/* Extra NULL fields are for including "backingType" when using
|
2009-07-21 02:40:50 +00:00
|
|
|
* kvm-img (-F backingType), and for indicating encryption (-e).
|
2009-07-16 16:09:26 +00:00
|
|
|
*/
|
|
|
|
const char *imgargvbacking[] = {
|
|
|
|
NULL, "create",
|
|
|
|
"-f", type,
|
|
|
|
"-b", vol->backingStore.path,
|
|
|
|
vol->target.path,
|
|
|
|
size,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
2009-07-21 02:40:50 +00:00
|
|
|
NULL,
|
2009-07-16 16:09:26 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
const char *convargv[] = {
|
|
|
|
NULL, "convert",
|
|
|
|
"-f", inputType,
|
|
|
|
"-O", type,
|
|
|
|
inputPath,
|
|
|
|
vol->target.path,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (type == NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown storage vol type %d"),
|
|
|
|
vol->target.format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (inputvol && inputType == NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown storage vol type %d"),
|
|
|
|
inputvol->target.format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vol->backingStore.path) {
|
|
|
|
|
|
|
|
/* XXX: Not strictly required: qemu-img has an option a different
|
|
|
|
* backing store, not really sure what use it serves though, and it
|
|
|
|
* may cause issues with lvm. Untested essentially.
|
|
|
|
*/
|
|
|
|
if (inputvol &&
|
|
|
|
(!inputBackingPath ||
|
|
|
|
STRNEQ(inputBackingPath, vol->backingStore.path))) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("a different backing store can not "
|
|
|
|
"be specified."));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (backingType == NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown storage vol backing store type %d"),
|
|
|
|
vol->backingStore.format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (access(vol->backingStore.path, R_OK) != 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("inaccessible backing store volume %s"),
|
|
|
|
vol->backingStore.path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-21 02:40:50 +00:00
|
|
|
if (vol->target.encryption != NULL) {
|
2009-08-14 18:06:59 +00:00
|
|
|
virStorageEncryptionPtr enc;
|
|
|
|
|
2009-09-25 13:20:13 +00:00
|
|
|
if (vol->target.format != VIR_STORAGE_FILE_QCOW &&
|
|
|
|
vol->target.format != VIR_STORAGE_FILE_QCOW2) {
|
2009-07-21 02:40:50 +00:00
|
|
|
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
|
|
|
|
_("qcow volume encryption unsupported with "
|
|
|
|
"volume format %s"), type);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-08-14 18:06:59 +00:00
|
|
|
enc = vol->target.encryption;
|
|
|
|
if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW &&
|
|
|
|
enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT) {
|
2009-07-21 02:40:50 +00:00
|
|
|
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
|
|
|
|
_("unsupported volume encryption format %d"),
|
|
|
|
vol->target.encryption->format);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-08-14 18:06:59 +00:00
|
|
|
if (enc->nsecrets > 1) {
|
2009-07-21 02:40:50 +00:00
|
|
|
virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
|
|
|
|
_("too many secrets for qcow encryption"));
|
|
|
|
return -1;
|
|
|
|
}
|
2009-08-14 18:06:59 +00:00
|
|
|
if (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT ||
|
|
|
|
enc->nsecrets == 0) {
|
|
|
|
if (virStorageGenerateQcowEncryption(conn, vol) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2009-07-21 02:40:50 +00:00
|
|
|
}
|
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
if ((create_tool = virFindFileInPath("kvm-img")) != NULL)
|
|
|
|
use_kvmimg = 1;
|
|
|
|
else if ((create_tool = virFindFileInPath("qemu-img")) != NULL)
|
|
|
|
use_kvmimg = 0;
|
|
|
|
else {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
2009-07-23 16:27:47 +00:00
|
|
|
"%s", _("unable to find kvm-img or qemu-img"));
|
2009-07-16 16:09:26 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inputvol) {
|
|
|
|
convargv[0] = create_tool;
|
|
|
|
imgargv = convargv;
|
|
|
|
} else if (vol->backingStore.path) {
|
|
|
|
imgargvbacking[0] = create_tool;
|
|
|
|
if (use_kvmimg) {
|
|
|
|
imgargvbacking[6] = "-F";
|
|
|
|
imgargvbacking[7] = backingType;
|
|
|
|
imgargvbacking[8] = vol->target.path;
|
|
|
|
imgargvbacking[9] = size;
|
2009-07-21 02:40:50 +00:00
|
|
|
if (vol->target.encryption != NULL)
|
|
|
|
imgargvbacking[10] = "-e";
|
|
|
|
} else if (vol->target.encryption != NULL)
|
|
|
|
imgargvbacking[8] = "-e";
|
2009-07-16 16:09:26 +00:00
|
|
|
imgargv = imgargvbacking;
|
|
|
|
} else {
|
|
|
|
imgargvnormal[0] = create_tool;
|
|
|
|
imgargv = imgargvnormal;
|
2009-07-21 02:40:50 +00:00
|
|
|
if (vol->target.encryption != NULL)
|
|
|
|
imgargv[6] = "-e";
|
2009-07-16 16:09:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Size in KB */
|
2009-08-05 12:35:17 +00:00
|
|
|
snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
|
2009-07-16 16:09:26 +00:00
|
|
|
|
|
|
|
if (virRun(conn, imgargv, NULL) < 0) {
|
|
|
|
VIR_FREE(imgargv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(imgargv[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Xen removed the fully-functional qemu-img, and replaced it
|
|
|
|
* with a partially functional qcow-create. Go figure ??!?
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virStorageBackendCreateQcowCreate(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol,
|
2009-07-16 16:27:07 +00:00
|
|
|
virStorageVolDefPtr inputvol,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED)
|
2009-07-16 16:09:26 +00:00
|
|
|
{
|
|
|
|
char size[100];
|
|
|
|
const char *imgargv[4];
|
|
|
|
|
|
|
|
if (inputvol) {
|
2009-07-23 16:27:47 +00:00
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-07-16 16:09:26 +00:00
|
|
|
_("cannot copy from volume with qcow-create"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-09-25 13:20:13 +00:00
|
|
|
if (vol->target.format != VIR_STORAGE_FILE_QCOW2) {
|
2009-07-16 16:09:26 +00:00
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported storage vol type %d"),
|
|
|
|
vol->target.format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (vol->backingStore.path != NULL) {
|
2009-07-23 16:27:47 +00:00
|
|
|
virStorageReportError(conn, VIR_ERR_NO_SUPPORT, "%s",
|
2009-07-16 16:09:26 +00:00
|
|
|
_("copy-on-write image not supported with "
|
2009-07-23 16:27:47 +00:00
|
|
|
"qcow-create"));
|
2009-07-16 16:09:26 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2009-07-21 02:40:50 +00:00
|
|
|
if (vol->target.encryption != NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("encrypted volumes not supported with "
|
|
|
|
"qcow-create"));
|
|
|
|
return -1;
|
|
|
|
}
|
2009-07-16 16:09:26 +00:00
|
|
|
|
|
|
|
/* Size in MB - yes different units to qemu-img :-( */
|
|
|
|
snprintf(size, sizeof(size), "%llu", vol->capacity/1024/1024);
|
|
|
|
|
|
|
|
imgargv[0] = virFindFileInPath("qcow-create");
|
|
|
|
imgargv[1] = size;
|
|
|
|
imgargv[2] = vol->target.path;
|
|
|
|
imgargv[3] = NULL;
|
|
|
|
|
|
|
|
if (virRun(conn, imgargv, NULL) < 0) {
|
|
|
|
VIR_FREE(imgargv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(imgargv[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-07-16 16:27:07 +00:00
|
|
|
virStorageBackendBuildVolFrom
|
2009-07-16 16:09:26 +00:00
|
|
|
virStorageBackendFSImageToolTypeToFunc(virConnectPtr conn, int tool_type)
|
|
|
|
{
|
|
|
|
switch (tool_type) {
|
|
|
|
case TOOL_KVM_IMG:
|
|
|
|
case TOOL_QEMU_IMG:
|
|
|
|
return virStorageBackendCreateQemuImg;
|
|
|
|
case TOOL_QCOW_CREATE:
|
|
|
|
return virStorageBackendCreateQcowCreate;
|
|
|
|
default:
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown file create tool type '%d'."),
|
|
|
|
tool_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virStorageBackendFindFSImageTool(char **tool)
|
|
|
|
{
|
|
|
|
int tool_type = -1;
|
|
|
|
char *tmp = NULL;
|
|
|
|
|
|
|
|
if ((tmp = virFindFileInPath("kvm-img")) != NULL) {
|
|
|
|
tool_type = TOOL_KVM_IMG;
|
|
|
|
} else if ((tmp = virFindFileInPath("qemu-img")) != NULL) {
|
|
|
|
tool_type = TOOL_QEMU_IMG;
|
|
|
|
} else if ((tmp = virFindFileInPath("qcow-create")) != NULL) {
|
|
|
|
tool_type = TOOL_QCOW_CREATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tool)
|
|
|
|
*tool = tmp;
|
|
|
|
else
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
|
|
|
return tool_type;
|
|
|
|
}
|
|
|
|
|
2009-07-16 16:27:07 +00:00
|
|
|
virStorageBackendBuildVolFrom
|
2009-07-16 16:09:26 +00:00
|
|
|
virStorageBackendGetBuildVolFromFunction(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol,
|
|
|
|
virStorageVolDefPtr inputvol)
|
|
|
|
{
|
|
|
|
int tool_type;
|
|
|
|
|
|
|
|
if (!inputvol)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* If either volume is a non-raw file vol, we need to use an external
|
|
|
|
* tool for converting
|
|
|
|
*/
|
|
|
|
if ((vol->type == VIR_STORAGE_VOL_FILE &&
|
2009-09-25 13:20:13 +00:00
|
|
|
vol->target.format != VIR_STORAGE_FILE_RAW) ||
|
2009-07-16 16:09:26 +00:00
|
|
|
(inputvol->type == VIR_STORAGE_VOL_FILE &&
|
2009-09-25 13:20:13 +00:00
|
|
|
inputvol->target.format != VIR_STORAGE_FILE_RAW)) {
|
2009-07-16 16:09:26 +00:00
|
|
|
|
2009-07-17 12:33:24 +00:00
|
|
|
if ((tool_type = virStorageBackendFindFSImageTool(NULL)) < 0) {
|
2009-07-16 16:09:26 +00:00
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("creation of non-raw file images is "
|
|
|
|
"not supported without qemu-img."));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virStorageBackendFSImageToolTypeToFunc(conn, tool_type);
|
|
|
|
}
|
|
|
|
|
2009-07-09 23:14:51 +00:00
|
|
|
if (vol->type == VIR_STORAGE_VOL_BLOCK)
|
|
|
|
return virStorageBackendCreateBlockFrom;
|
|
|
|
else
|
|
|
|
return virStorageBackendCreateRaw;
|
2009-07-16 16:09:26 +00:00
|
|
|
}
|
2008-11-11 15:52:16 +00:00
|
|
|
|
2009-06-17 08:38:17 +00:00
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
virStorageBackendPtr
|
|
|
|
virStorageBackendForType(int type) {
|
2008-02-20 15:42:30 +00:00
|
|
|
unsigned int i;
|
2008-11-12 16:28:27 +00:00
|
|
|
for (i = 0; backends[i]; i++)
|
2008-02-20 15:42:30 +00:00
|
|
|
if (backends[i]->type == type)
|
|
|
|
return backends[i];
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing backend for pool type %d"), type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-20 15:38:29 +00:00
|
|
|
int
|
2009-01-27 18:30:03 +00:00
|
|
|
virStorageBackendUpdateVolTargetInfo(virConnectPtr conn,
|
|
|
|
virStorageVolTargetPtr target,
|
|
|
|
unsigned long long *allocation,
|
|
|
|
unsigned long long *capacity)
|
2008-02-20 15:38:29 +00:00
|
|
|
{
|
|
|
|
int ret, fd;
|
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
if ((fd = open(target->path, O_RDONLY)) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot open volume '%s'"),
|
2009-01-27 18:30:03 +00:00
|
|
|
target->path);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
ret = virStorageBackendUpdateVolTargetInfoFD(conn,
|
|
|
|
target,
|
|
|
|
fd,
|
|
|
|
allocation,
|
|
|
|
capacity);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
int
|
|
|
|
virStorageBackendUpdateVolInfo(virConnectPtr conn,
|
|
|
|
virStorageVolDefPtr vol,
|
|
|
|
int withCapacity)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((ret = virStorageBackendUpdateVolTargetInfo(conn,
|
|
|
|
&vol->target,
|
|
|
|
&vol->allocation,
|
|
|
|
withCapacity ? &vol->capacity : NULL)) < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (vol->backingStore.path &&
|
|
|
|
(ret = virStorageBackendUpdateVolTargetInfo(conn,
|
|
|
|
&vol->backingStore,
|
|
|
|
NULL, NULL)) < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-12 19:59:46 +00:00
|
|
|
/*
|
|
|
|
* virStorageBackendUpdateVolTargetInfoFD:
|
|
|
|
* @conn: connection to report errors on
|
|
|
|
* @target: target definition ptr of volume to update
|
|
|
|
* @fd: fd of storage volume to update
|
|
|
|
* @allocation: If not NULL, updated allocation information will be stored
|
|
|
|
* @capacity: If not NULL, updated capacity info will be stored
|
|
|
|
*
|
|
|
|
* Returns 0 for success-1 on a legitimate error condition,
|
|
|
|
* -2 if passed FD isn't a regular, char, or block file.
|
|
|
|
*/
|
2008-02-20 15:38:29 +00:00
|
|
|
int
|
2009-01-27 18:30:03 +00:00
|
|
|
virStorageBackendUpdateVolTargetInfoFD(virConnectPtr conn,
|
|
|
|
virStorageVolTargetPtr target,
|
|
|
|
int fd,
|
|
|
|
unsigned long long *allocation,
|
|
|
|
unsigned long long *capacity)
|
2008-02-20 15:38:29 +00:00
|
|
|
{
|
|
|
|
struct stat sb;
|
|
|
|
#if HAVE_SELINUX
|
|
|
|
security_context_t filecon = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (fstat(fd, &sb) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot stat file '%s'"),
|
2009-01-27 18:30:03 +00:00
|
|
|
target->path);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISREG(sb.st_mode) &&
|
|
|
|
!S_ISCHR(sb.st_mode) &&
|
|
|
|
!S_ISBLK(sb.st_mode))
|
|
|
|
return -2;
|
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
if (allocation) {
|
|
|
|
if (S_ISREG(sb.st_mode)) {
|
2008-09-05 12:03:45 +00:00
|
|
|
#ifndef __MINGW32__
|
2009-01-27 18:30:03 +00:00
|
|
|
*allocation = (unsigned long long)sb.st_blocks *
|
2009-04-03 14:13:02 +00:00
|
|
|
(unsigned long long)DEV_BSIZE;
|
2008-09-05 12:03:45 +00:00
|
|
|
#else
|
2009-01-27 18:30:03 +00:00
|
|
|
*allocation = sb.st_size;
|
2008-09-05 12:03:45 +00:00
|
|
|
#endif
|
2009-01-27 18:30:03 +00:00
|
|
|
/* Regular files may be sparse, so logical size (capacity) is not same
|
|
|
|
* as actual allocation above
|
|
|
|
*/
|
|
|
|
if (capacity)
|
|
|
|
*capacity = sb.st_size;
|
|
|
|
} else {
|
|
|
|
off_t end;
|
|
|
|
/* XXX this is POSIX compliant, but doesn't work for for CHAR files,
|
|
|
|
* only BLOCK. There is a Linux specific ioctl() for getting
|
|
|
|
* size of both CHAR / BLOCK devices we should check for in
|
|
|
|
* configure
|
|
|
|
*/
|
|
|
|
end = lseek(fd, 0, SEEK_END);
|
|
|
|
if (end == (off_t)-1) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot seek to end of file '%s'"),
|
|
|
|
target->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*allocation = end;
|
|
|
|
if (capacity)
|
|
|
|
*capacity = end;
|
2008-02-20 15:38:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
target->perms.mode = sb.st_mode & S_IRWXUGO;
|
|
|
|
target->perms.uid = sb.st_uid;
|
|
|
|
target->perms.gid = sb.st_gid;
|
2008-02-20 15:38:29 +00:00
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
VIR_FREE(target->perms.label);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
#if HAVE_SELINUX
|
2009-03-03 09:44:41 +00:00
|
|
|
/* XXX: make this a security driver call */
|
2008-02-20 15:38:29 +00:00
|
|
|
if (fgetfilecon(fd, &filecon) == -1) {
|
2008-03-17 16:57:21 +00:00
|
|
|
if (errno != ENODATA && errno != ENOTSUP) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot get file context of '%s'"),
|
2009-01-27 18:30:03 +00:00
|
|
|
target->path);
|
2008-03-17 15:09:38 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
2009-01-27 18:30:03 +00:00
|
|
|
target->perms.label = NULL;
|
2008-03-17 15:09:38 +00:00
|
|
|
}
|
|
|
|
} else {
|
2009-01-27 18:30:03 +00:00
|
|
|
target->perms.label = strdup(filecon);
|
|
|
|
if (target->perms.label == NULL) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-03-17 15:09:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
freecon(filecon);
|
2008-02-20 15:38:29 +00:00
|
|
|
}
|
|
|
|
#else
|
2009-01-27 18:30:03 +00:00
|
|
|
target->perms.label = NULL;
|
2008-02-20 15:38:29 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-08 13:47:45 +00:00
|
|
|
|
|
|
|
struct diskType {
|
|
|
|
int part_table_type;
|
|
|
|
unsigned short offset;
|
|
|
|
unsigned short length;
|
|
|
|
unsigned long long magic;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static struct diskType const disk_types[] = {
|
|
|
|
{ VIR_STORAGE_POOL_DISK_LVM2, 0x218, 8, 0x31303020324D564CULL },
|
|
|
|
{ VIR_STORAGE_POOL_DISK_GPT, 0x200, 8, 0x5452415020494645ULL },
|
|
|
|
{ VIR_STORAGE_POOL_DISK_DVH, 0x0, 4, 0x41A9E50BULL },
|
|
|
|
{ VIR_STORAGE_POOL_DISK_MAC, 0x0, 2, 0x5245ULL },
|
|
|
|
{ VIR_STORAGE_POOL_DISK_BSD, 0x40, 4, 0x82564557ULL },
|
|
|
|
{ VIR_STORAGE_POOL_DISK_SUN, 0x1fc, 2, 0xBEDAULL },
|
|
|
|
/*
|
|
|
|
* NOTE: pc98 is funky; the actual signature is 0x55AA (just like dos), so
|
|
|
|
* we can't use that. At the moment I'm relying on the "dummy" IPL
|
|
|
|
* bootloader data that comes from parted. Luckily, the chances of running
|
|
|
|
* into a pc98 machine running libvirt are approximately nil.
|
|
|
|
*/
|
|
|
|
/*{ 0x1fe, 2, 0xAA55UL },*/
|
|
|
|
{ VIR_STORAGE_POOL_DISK_PC98, 0x0, 8, 0x314C5049000000CBULL },
|
|
|
|
/*
|
|
|
|
* NOTE: the order is important here; some other disk types (like GPT and
|
|
|
|
* and PC98) also have 0x55AA at this offset. For that reason, the DOS
|
|
|
|
* one must be the last one.
|
|
|
|
*/
|
|
|
|
{ VIR_STORAGE_POOL_DISK_DOS, 0x1fe, 2, 0xAA55ULL },
|
|
|
|
{ -1, 0x0, 0, 0x0ULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virStorageBackendUpdateVolTargetFormatFD(virConnectPtr conn,
|
|
|
|
virStorageVolTargetPtr target,
|
|
|
|
int fd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
off_t start;
|
|
|
|
unsigned char buffer[1024];
|
|
|
|
ssize_t bytes;
|
|
|
|
|
|
|
|
/* make sure to set the target format "unknown" to begin with */
|
|
|
|
target->format = VIR_STORAGE_POOL_DISK_UNKNOWN;
|
|
|
|
|
|
|
|
start = lseek(fd, 0, SEEK_SET);
|
|
|
|
if (start < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot seek to beginning of file '%s'"),
|
|
|
|
target->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
bytes = saferead(fd, buffer, sizeof(buffer));
|
|
|
|
if (bytes < 0) {
|
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot read beginning of file '%s'"),
|
|
|
|
target->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; disk_types[i].part_table_type != -1; i++) {
|
|
|
|
if (disk_types[i].offset + disk_types[i].length > bytes)
|
|
|
|
continue;
|
|
|
|
if (memcmp(buffer+disk_types[i].offset, &disk_types[i].magic,
|
|
|
|
disk_types[i].length) == 0) {
|
|
|
|
target->format = disk_types[i].part_table_type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-20 15:38:29 +00:00
|
|
|
/*
|
|
|
|
* Given a volume path directly in /dev/XXX, iterate over the
|
|
|
|
* entries in the directory pool->def->target.path and find the
|
|
|
|
* first symlink pointing to the volume path.
|
|
|
|
*
|
|
|
|
* If, the target.path is /dev/, then return the original volume
|
|
|
|
* path.
|
|
|
|
*
|
|
|
|
* If no symlink is found, then return the original volume path
|
|
|
|
*
|
|
|
|
* Typically target.path is one of the /dev/disk/by-XXX dirs
|
|
|
|
* with stable paths.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
virStorageBackendStablePath(virConnectPtr conn,
|
|
|
|
virStoragePoolObjPtr pool,
|
2008-11-03 11:37:11 +00:00
|
|
|
const char *devpath)
|
2008-02-20 15:38:29 +00:00
|
|
|
{
|
|
|
|
DIR *dh;
|
|
|
|
struct dirent *dent;
|
2008-11-03 11:37:11 +00:00
|
|
|
char *stablepath;
|
2008-11-28 07:42:21 +00:00
|
|
|
int opentries = 0;
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
/* Short circuit if pool has no target, or if its /dev */
|
|
|
|
if (pool->def->target.path == NULL ||
|
|
|
|
STREQ(pool->def->target.path, "/dev") ||
|
|
|
|
STREQ(pool->def->target.path, "/dev/"))
|
2008-11-03 11:37:11 +00:00
|
|
|
goto ret_strdup;
|
2008-02-20 15:38:29 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
/* Skip whole thing for a pool which isn't in /dev
|
|
|
|
* so we don't mess will filesystem/dir based pools
|
|
|
|
*/
|
|
|
|
if (!STRPREFIX(pool->def->target.path, "/dev"))
|
|
|
|
goto ret_strdup;
|
|
|
|
|
2008-11-28 07:42:21 +00:00
|
|
|
/* We loop here because /dev/disk/by-{id,path} may not have existed
|
|
|
|
* before we started this operation, so we have to give it some time to
|
|
|
|
* get created.
|
2008-02-20 15:38:29 +00:00
|
|
|
*/
|
2008-11-28 07:42:21 +00:00
|
|
|
reopen:
|
2008-02-20 15:38:29 +00:00
|
|
|
if ((dh = opendir(pool->def->target.path)) == NULL) {
|
2008-11-28 07:42:21 +00:00
|
|
|
opentries++;
|
|
|
|
if (errno == ENOENT && opentries < 50) {
|
|
|
|
usleep(100 * 1000);
|
|
|
|
goto reopen;
|
|
|
|
}
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot read dir '%s'"),
|
|
|
|
pool->def->target.path);
|
2008-02-20 15:38:29 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-11-28 07:42:21 +00:00
|
|
|
/* The pool is pointing somewhere like /dev/disk/by-path
|
|
|
|
* or /dev/disk/by-id, so we need to check all symlinks in
|
|
|
|
* the target directory and figure out which one points
|
|
|
|
* to this device node
|
|
|
|
*/
|
2008-02-20 15:38:29 +00:00
|
|
|
while ((dent = readdir(dh)) != NULL) {
|
|
|
|
if (dent->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2009-05-19 13:15:50 +00:00
|
|
|
if (virAsprintf(&stablepath, "%s/%s",
|
|
|
|
pool->def->target.path,
|
|
|
|
dent->d_name) == -1) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-02-20 15:38:29 +00:00
|
|
|
closedir(dh);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virFileLinkPointsTo(stablepath, devpath)) {
|
|
|
|
closedir(dh);
|
|
|
|
return stablepath;
|
|
|
|
}
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(stablepath);
|
2008-02-20 15:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dh);
|
|
|
|
|
2008-11-03 11:37:11 +00:00
|
|
|
ret_strdup:
|
2008-02-20 15:38:29 +00:00
|
|
|
/* Couldn't find any matching stable link so give back
|
|
|
|
* the original non-stable dev path
|
|
|
|
*/
|
2008-11-03 11:37:11 +00:00
|
|
|
|
|
|
|
stablepath = strdup(devpath);
|
|
|
|
|
|
|
|
if (stablepath == NULL)
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-11-03 11:37:11 +00:00
|
|
|
|
|
|
|
return stablepath;
|
2008-02-20 15:38:29 +00:00
|
|
|
}
|
|
|
|
|
2008-09-05 12:03:45 +00:00
|
|
|
|
|
|
|
#ifndef __MINGW32__
|
2008-02-20 15:38:29 +00:00
|
|
|
/*
|
|
|
|
* Run an external program.
|
|
|
|
*
|
|
|
|
* Read its output and apply a series of regexes to each line
|
2008-02-27 10:37:19 +00:00
|
|
|
* When the entire set of regexes has matched consecutively
|
2008-02-20 15:38:29 +00:00
|
|
|
* then run a callback passing in all the matches
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virStorageBackendRunProgRegex(virConnectPtr conn,
|
|
|
|
virStoragePoolObjPtr pool,
|
2008-06-24 14:30:25 +00:00
|
|
|
const char *const*prog,
|
2008-02-20 15:38:29 +00:00
|
|
|
int nregex,
|
|
|
|
const char **regex,
|
|
|
|
int *nvars,
|
|
|
|
virStorageBackendListVolRegexFunc func,
|
2008-06-17 12:45:24 +00:00
|
|
|
void *data,
|
|
|
|
int *outexit)
|
2008-02-20 15:38:29 +00:00
|
|
|
{
|
2008-12-18 11:58:28 +00:00
|
|
|
int fd = -1, exitstatus, err, failed = 1;
|
|
|
|
pid_t child = 0;
|
2008-02-20 15:38:29 +00:00
|
|
|
FILE *list = NULL;
|
|
|
|
regex_t *reg;
|
|
|
|
regmatch_t *vars = NULL;
|
|
|
|
char line[1024];
|
|
|
|
int maxReg = 0, i, j;
|
|
|
|
int totgroups = 0, ngroup = 0, maxvars = 0;
|
|
|
|
char **groups;
|
|
|
|
|
|
|
|
/* Compile all regular expressions */
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC_N(reg, nregex) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0 ; i < nregex ; i++) {
|
|
|
|
err = regcomp(®[i], regex[i], REG_EXTENDED);
|
|
|
|
if (err != 0) {
|
|
|
|
char error[100];
|
|
|
|
regerror(err, ®[i], error, sizeof(error));
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to compile regex %s"), error);
|
|
|
|
for (j = 0 ; j <= i ; j++)
|
|
|
|
regfree(®[j]);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(reg);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
totgroups += nvars[i];
|
|
|
|
if (nvars[i] > maxvars)
|
|
|
|
maxvars = nvars[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Storage for matched variables */
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC_N(groups, totgroups) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC_N(vars, maxvars+1) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Run the program and capture its output */
|
2008-08-27 11:42:52 +00:00
|
|
|
if (virExec(conn, prog, NULL, NULL,
|
|
|
|
&child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) {
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((list = fdopen(fd, "r")) == NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
2008-02-22 16:26:13 +00:00
|
|
|
"%s", _("cannot read fd"));
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), list) != NULL) {
|
|
|
|
/* Strip trailing newline */
|
|
|
|
int len = strlen(line);
|
|
|
|
if (len && line[len-1] == '\n')
|
|
|
|
line[len-1] = '\0';
|
|
|
|
|
|
|
|
for (i = 0 ; i <= maxReg && i < nregex ; i++) {
|
|
|
|
if (regexec(®[i], line, nvars[i]+1, vars, 0) == 0) {
|
|
|
|
maxReg++;
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
ngroup = 0;
|
|
|
|
|
|
|
|
/* NULL terminate each captured group in the line */
|
|
|
|
for (j = 0 ; j < nvars[i] ; j++) {
|
|
|
|
/* NB vars[0] is the full pattern, so we offset j by 1 */
|
|
|
|
line[vars[j+1].rm_eo] = '\0';
|
|
|
|
if ((groups[ngroup++] =
|
|
|
|
strdup(line + vars[j+1].rm_so)) == NULL) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We're matching on the last regex, so callback time */
|
|
|
|
if (i == (nregex-1)) {
|
|
|
|
if (((*func)(conn, pool, groups, data)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Release matches & restart to matching the first regex */
|
2008-07-19 07:42:34 +00:00
|
|
|
for (j = 0 ; j < totgroups ; j++)
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(groups[j]);
|
2008-02-20 15:38:29 +00:00
|
|
|
maxReg = 0;
|
|
|
|
ngroup = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
failed = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (groups) {
|
|
|
|
for (j = 0 ; j < totgroups ; j++)
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(groups[j]);
|
|
|
|
VIR_FREE(groups);
|
2008-02-20 15:38:29 +00:00
|
|
|
}
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(vars);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < nregex ; i++)
|
|
|
|
regfree(®[i]);
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(reg);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
if (list)
|
|
|
|
fclose(list);
|
|
|
|
else
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
while ((err = waitpid(child, &exitstatus, 0) == -1) && errno == EINTR);
|
|
|
|
|
|
|
|
/* Don't bother checking exit status if we already failed */
|
|
|
|
if (failed)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (err == -1) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("failed to wait for command '%s'"),
|
|
|
|
prog[0]);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (WIFEXITED(exitstatus)) {
|
2008-06-17 12:45:24 +00:00
|
|
|
if (outexit != NULL)
|
|
|
|
*outexit = WEXITSTATUS(exitstatus);
|
2008-02-20 15:38:29 +00:00
|
|
|
} else {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
2008-02-22 16:26:13 +00:00
|
|
|
"%s", _("command did not exit cleanly"));
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run an external program and read from its standard output
|
|
|
|
* a stream of tokens from IN_STREAM, applying FUNC to
|
|
|
|
* each successive sequence of N_COLUMNS tokens.
|
|
|
|
* If FUNC returns < 0, stop processing input and return -1.
|
|
|
|
* Return -1 if N_COLUMNS == 0.
|
|
|
|
* Return -1 upon memory allocation error.
|
|
|
|
* If the number of input tokens is not a multiple of N_COLUMNS,
|
|
|
|
* then the final FUNC call will specify a number smaller than N_COLUMNS.
|
|
|
|
* If there are no input tokens (empty input), call FUNC with N_COLUMNS == 0.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virStorageBackendRunProgNul(virConnectPtr conn,
|
|
|
|
virStoragePoolObjPtr pool,
|
|
|
|
const char **prog,
|
|
|
|
size_t n_columns,
|
|
|
|
virStorageBackendListVolNulFunc func,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
size_t n_tok = 0;
|
2008-12-18 11:58:28 +00:00
|
|
|
int fd = -1, exitstatus;
|
|
|
|
pid_t child = 0;
|
2008-02-20 15:38:29 +00:00
|
|
|
FILE *fp = NULL;
|
|
|
|
char **v;
|
|
|
|
int err = -1;
|
|
|
|
int w_err;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (n_columns == 0)
|
|
|
|
return -1;
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC_N(v, n_columns) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
|
|
v[i] = NULL;
|
|
|
|
|
|
|
|
/* Run the program and capture its output */
|
2008-08-27 11:42:52 +00:00
|
|
|
if (virExec(conn, prog, NULL, NULL,
|
|
|
|
&child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) {
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fp = fdopen(fd, "r")) == NULL) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
2008-02-22 16:26:13 +00:00
|
|
|
"%s", _("cannot read fd"));
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
char *buf = NULL;
|
|
|
|
size_t buf_len = 0;
|
|
|
|
/* Be careful: even when it returns -1,
|
|
|
|
this use of getdelim allocates memory. */
|
|
|
|
ssize_t tok_len = getdelim (&buf, &buf_len, 0, fp);
|
|
|
|
v[n_tok] = buf;
|
|
|
|
if (tok_len < 0) {
|
|
|
|
/* Maybe EOF, maybe an error.
|
|
|
|
If n_tok > 0, then we know it's an error. */
|
|
|
|
if (n_tok && func (conn, pool, n_tok, v, data) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++n_tok;
|
|
|
|
if (n_tok == n_columns) {
|
|
|
|
if (func (conn, pool, n_tok, v, data) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
n_tok = 0;
|
|
|
|
for (i = 0; i < n_columns; i++) {
|
|
|
|
free (v[i]);
|
|
|
|
v[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (feof (fp))
|
|
|
|
err = 0;
|
|
|
|
else
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("read error on pipe to '%s'"), prog[0]);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
|
|
free (v[i]);
|
|
|
|
free (v);
|
|
|
|
|
|
|
|
if (fp)
|
|
|
|
fclose (fp);
|
|
|
|
else
|
|
|
|
close (fd);
|
|
|
|
|
|
|
|
while ((w_err = waitpid (child, &exitstatus, 0) == -1) && errno == EINTR)
|
|
|
|
/* empty */ ;
|
|
|
|
|
|
|
|
/* Don't bother checking exit status if we already failed */
|
|
|
|
if (err < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (w_err == -1) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("failed to wait for command '%s'"),
|
|
|
|
prog[0]);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (WIFEXITED(exitstatus)) {
|
|
|
|
if (WEXITSTATUS(exitstatus) != 0) {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("non-zero exit status from command %d"),
|
|
|
|
WEXITSTATUS(exitstatus));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
2008-02-22 16:26:13 +00:00
|
|
|
"%s", _("command did not exit cleanly"));
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-09-05 12:03:45 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
int
|
|
|
|
virStorageBackendRunProgRegex(virConnectPtr conn,
|
|
|
|
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
|
|
|
const char *const*prog ATTRIBUTE_UNUSED,
|
|
|
|
int nregex ATTRIBUTE_UNUSED,
|
|
|
|
const char **regex ATTRIBUTE_UNUSED,
|
|
|
|
int *nvars ATTRIBUTE_UNUSED,
|
|
|
|
virStorageBackendListVolRegexFunc func ATTRIBUTE_UNUSED,
|
|
|
|
void *data ATTRIBUTE_UNUSED,
|
|
|
|
int *outexit ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("%s not implemented on Win32"), __FUNCTION__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virStorageBackendRunProgNul(virConnectPtr conn,
|
|
|
|
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
|
|
|
const char **prog ATTRIBUTE_UNUSED,
|
|
|
|
size_t n_columns ATTRIBUTE_UNUSED,
|
|
|
|
virStorageBackendListVolNulFunc func ATTRIBUTE_UNUSED,
|
|
|
|
void *data ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("%s not implemented on Win32"), __FUNCTION__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|