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
|
|
|
*
|
2011-03-08 11:06:51 +00:00
|
|
|
* Copyright (C) 2007-2011 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
|
2010-03-09 18:22:22 +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>
|
2010-04-29 03:31:16 +00:00
|
|
|
#include <sys/wait.h>
|
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>
|
2011-03-08 11:06:51 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
# include <linux/fs.h>
|
|
|
|
#endif
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
#if HAVE_SELINUX
|
2010-03-09 18:22:22 +00:00
|
|
|
# include <selinux/selinux.h>
|
2008-02-20 15:38:29 +00:00
|
|
|
#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"
|
2010-11-09 20:48:48 +00:00
|
|
|
#include "files.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
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "storage_backend_logical.h"
|
2008-11-12 16:28:27 +00:00
|
|
|
#endif
|
|
|
|
#if WITH_STORAGE_ISCSI
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "storage_backend_iscsi.h"
|
2008-11-12 16:28:27 +00:00
|
|
|
#endif
|
2009-04-01 16:03:22 +00:00
|
|
|
#if WITH_STORAGE_SCSI
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "storage_backend_scsi.h"
|
2009-04-01 16:03:22 +00:00
|
|
|
#endif
|
2009-09-08 13:47:45 +00:00
|
|
|
#if WITH_STORAGE_MPATH
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "storage_backend_mpath.h"
|
2009-09-08 13:47:45 +00:00
|
|
|
#endif
|
2008-11-12 16:28:27 +00:00
|
|
|
#if WITH_STORAGE_DISK
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "storage_backend_disk.h"
|
2008-11-12 16:28:27 +00:00
|
|
|
#endif
|
|
|
|
#if WITH_STORAGE_DIR
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "storage_backend_fs.h"
|
2008-11-12 16:28:27 +00:00
|
|
|
#endif
|
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2011-03-08 11:06:51 +00:00
|
|
|
#define READ_BLOCK_SIZE_DEFAULT (1024 * 1024)
|
|
|
|
#define WRITE_BLOCK_SIZE_DEFAULT (4 * 1024)
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
static int ATTRIBUTE_NONNULL (2)
|
|
|
|
virStorageBackendCopyToFD(virStorageVolDefPtr vol,
|
2009-06-25 22:34:59 +00:00
|
|
|
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;
|
2010-07-19 23:35:30 +00:00
|
|
|
int ret = 0;
|
2009-06-25 22:34:59 +00:00
|
|
|
unsigned long long remain;
|
2011-03-08 11:06:51 +00:00
|
|
|
size_t rbytes = READ_BLOCK_SIZE_DEFAULT;
|
|
|
|
size_t wbytes = 0;
|
|
|
|
int interval;
|
|
|
|
char *zerobuf;
|
2009-06-25 22:34:59 +00:00
|
|
|
char *buf = NULL;
|
2011-03-08 11:06:51 +00:00
|
|
|
struct stat st;
|
2009-06-25 22:34:59 +00:00
|
|
|
|
2009-09-03 08:22:57 +00:00
|
|
|
if ((inputfd = open(inputvol->target.path, O_RDONLY)) < 0) {
|
2010-07-19 23:35:30 +00:00
|
|
|
ret = -errno;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-09-03 08:22:57 +00:00
|
|
|
_("could not open input path '%s'"),
|
|
|
|
inputvol->target.path);
|
|
|
|
goto cleanup;
|
2009-06-25 22:34:59 +00:00
|
|
|
}
|
|
|
|
|
2011-03-08 11:06:51 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
if (ioctl(fd, BLKBSZGET, &wbytes) < 0) {
|
|
|
|
wbytes = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if ((wbytes == 0) && fstat(fd, &st) == 0)
|
|
|
|
wbytes = st.st_blksize;
|
|
|
|
if (wbytes < WRITE_BLOCK_SIZE_DEFAULT)
|
|
|
|
wbytes = WRITE_BLOCK_SIZE_DEFAULT;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(zerobuf, wbytes) < 0) {
|
|
|
|
ret = -errno;
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-06-25 22:34:59 +00:00
|
|
|
|
2011-03-08 11:06:51 +00:00
|
|
|
if (VIR_ALLOC_N(buf, rbytes) < 0) {
|
2010-07-19 23:35:30 +00:00
|
|
|
ret = -errno;
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-06-25 22:34:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
remain = *total;
|
|
|
|
|
|
|
|
while (amtread != 0) {
|
|
|
|
int amtleft;
|
|
|
|
|
2011-03-08 11:06:51 +00:00
|
|
|
if (remain < rbytes)
|
|
|
|
rbytes = remain;
|
2009-06-25 22:34:59 +00:00
|
|
|
|
2011-03-08 11:06:51 +00:00
|
|
|
if ((amtread = saferead(inputfd, buf, rbytes)) < 0) {
|
2010-07-19 23:35:30 +00:00
|
|
|
ret = -errno;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-06-25 22:34:59 +00:00
|
|
|
_("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 {
|
2011-03-08 11:06:51 +00:00
|
|
|
interval = ((wbytes > amtleft) ? amtleft : wbytes);
|
2009-06-25 22:34:59 +00:00
|
|
|
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) {
|
2010-07-19 23:35:30 +00:00
|
|
|
ret = -errno;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-06-25 22:34:59 +00:00
|
|
|
_("cannot extend file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (safewrite(fd, buf+offset, interval) < 0) {
|
2010-07-19 23:35:30 +00:00
|
|
|
ret = -errno;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-06-25 22:34:59 +00:00
|
|
|
_("failed writing to file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
}
|
2011-03-08 11:06:51 +00:00
|
|
|
} while ((amtleft -= interval) > 0);
|
2009-06-25 22:34:59 +00:00
|
|
|
}
|
|
|
|
|
2010-11-09 20:48:48 +00:00
|
|
|
if (VIR_CLOSE(inputfd) < 0) {
|
2010-07-19 23:35:30 +00:00
|
|
|
ret = -errno;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-06-25 22:34:59 +00:00
|
|
|
_("cannot close file '%s'"),
|
|
|
|
inputvol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
inputfd = -1;
|
|
|
|
|
|
|
|
*total -= remain;
|
|
|
|
|
|
|
|
cleanup:
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(inputfd);
|
2009-06-25 22:34:59 +00:00
|
|
|
|
2011-03-08 11:06:51 +00:00
|
|
|
VIR_FREE(zerobuf);
|
2009-12-10 23:54:49 +00:00
|
|
|
VIR_FREE(buf);
|
|
|
|
|
2009-06-25 22:34:59 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-07-09 23:14:51 +00:00
|
|
|
static int
|
2010-02-04 20:02:58 +00:00
|
|
|
virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2010-01-20 23:41:52 +00:00
|
|
|
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
2009-07-09 23:14:51 +00:00
|
|
|
virStorageVolDefPtr vol,
|
|
|
|
virStorageVolDefPtr inputvol,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
unsigned long long remain;
|
2010-01-20 23:41:52 +00:00
|
|
|
struct stat st;
|
|
|
|
gid_t gid;
|
|
|
|
uid_t uid;
|
2009-07-09 23:14:51 +00:00
|
|
|
|
|
|
|
if ((fd = open(vol->target.path, O_RDWR)) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-07-09 23:14:51 +00:00
|
|
|
_("cannot create path '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
remain = vol->allocation;
|
|
|
|
|
|
|
|
if (inputvol) {
|
2010-02-04 20:02:58 +00:00
|
|
|
int res = virStorageBackendCopyToFD(vol, inputvol,
|
2009-07-10 18:04:27 +00:00
|
|
|
fd, &remain, 0);
|
2009-07-09 23:14:51 +00:00
|
|
|
if (res < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-01-20 23:41:52 +00:00
|
|
|
if (fstat(fd, &st) == -1) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno, _("stat of '%s' failed"),
|
2010-01-20 23:41:52 +00:00
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
uid = (vol->target.perms.uid != st.st_uid) ? vol->target.perms.uid : -1;
|
|
|
|
gid = (vol->target.perms.gid != st.st_gid) ? vol->target.perms.gid : -1;
|
|
|
|
if (((uid != -1) || (gid != -1))
|
2010-03-04 22:35:27 +00:00
|
|
|
&& (fchown(fd, uid, gid) < 0)) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-20 23:41:52 +00:00
|
|
|
_("cannot chown '%s' to (%u, %u)"),
|
2010-03-04 22:35:27 +00:00
|
|
|
vol->target.path, uid, gid);
|
2010-01-20 23:41:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (fchmod(fd, vol->target.perms.mode) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-20 23:41:52 +00:00
|
|
|
_("cannot set mode of '%s' to %04o"),
|
|
|
|
vol->target.path, vol->target.perms.mode);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-11-09 20:48:48 +00:00
|
|
|
if (VIR_CLOSE(fd) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-07-09 23:14:51 +00:00
|
|
|
_("cannot close file '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
fd = -1;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2009-07-09 23:14:51 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-02-19 17:12:01 +00:00
|
|
|
struct createRawFileOpHookData {
|
|
|
|
virStorageVolDefPtr vol;
|
|
|
|
virStorageVolDefPtr inputvol;
|
|
|
|
};
|
2009-07-16 16:09:26 +00:00
|
|
|
|
2010-02-19 17:12:01 +00:00
|
|
|
static int createRawFileOpHook(int fd, void *data) {
|
|
|
|
struct createRawFileOpHookData *hdata = data;
|
|
|
|
int ret = 0;
|
|
|
|
unsigned long long remain;
|
2010-01-20 23:41:52 +00:00
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
/* Seek to the final size, so the capacity is available upfront
|
|
|
|
* for progress reporting */
|
2010-02-19 17:12:01 +00:00
|
|
|
if (ftruncate(fd, hdata->vol->capacity) < 0) {
|
2010-07-19 23:25:58 +00:00
|
|
|
ret = -errno;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-07-16 16:09:26 +00:00
|
|
|
_("cannot extend file '%s'"),
|
2010-02-19 17:12:01 +00:00
|
|
|
hdata->vol->target.path);
|
2009-07-16 16:09:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-02-19 17:12:01 +00:00
|
|
|
remain = hdata->vol->allocation;
|
2009-07-16 16:09:26 +00:00
|
|
|
|
2010-02-19 17:12:01 +00:00
|
|
|
if (hdata->inputvol) {
|
2010-07-19 23:25:58 +00:00
|
|
|
ret = virStorageBackendCopyToFD(hdata->vol, hdata->inputvol,
|
|
|
|
fd, &remain, 1);
|
|
|
|
if (ret < 0) {
|
2009-07-16 16:09:26 +00:00
|
|
|
goto cleanup;
|
2010-07-19 22:53:38 +00:00
|
|
|
}
|
2009-07-16 16:09:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (bytes > remain)
|
|
|
|
bytes = remain;
|
2010-04-07 16:30:55 +00:00
|
|
|
if (safezero(fd, 0, hdata->vol->allocation - remain,
|
|
|
|
bytes) != 0) {
|
2010-07-19 23:25:58 +00:00
|
|
|
ret = -errno;
|
2010-03-02 15:11:24 +00:00
|
|
|
virReportSystemError(errno, _("cannot fill file '%s'"),
|
2010-02-19 17:12:01 +00:00
|
|
|
hdata->vol->target.path);
|
2009-07-16 16:09:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
remain -= bytes;
|
|
|
|
}
|
|
|
|
} else { /* No progress bars to be shown */
|
2010-04-07 16:30:55 +00:00
|
|
|
if (safezero(fd, 0, 0, remain) != 0) {
|
2010-07-19 23:25:58 +00:00
|
|
|
ret = -errno;
|
2010-03-02 15:11:24 +00:00
|
|
|
virReportSystemError(errno, _("cannot fill file '%s'"),
|
2010-02-19 17:12:01 +00:00
|
|
|
hdata->vol->target.path);
|
2009-07-16 16:09:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2010-03-16 15:03:59 +00:00
|
|
|
|
2010-07-19 22:59:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fsync(fd) < 0) {
|
2010-07-19 23:25:58 +00:00
|
|
|
ret = -errno;
|
2010-07-19 22:59:07 +00:00
|
|
|
virReportSystemError(errno, _("cannot sync data to file '%s'"),
|
|
|
|
hdata->vol->target.path);
|
|
|
|
goto cleanup;
|
2009-07-16 16:09:26 +00:00
|
|
|
}
|
|
|
|
|
2010-02-19 17:12:01 +00:00
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virStoragePoolObjPtr pool,
|
|
|
|
virStorageVolDefPtr vol,
|
|
|
|
virStorageVolDefPtr inputvol,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
int createstat;
|
|
|
|
struct createRawFileOpHookData hdata = { vol, inputvol };
|
|
|
|
|
|
|
|
if (vol->target.encryption != NULL) {
|
|
|
|
virStorageReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("storage pool does not support encrypted "
|
|
|
|
"volumes"));
|
2009-07-16 16:09:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-02-19 17:12:01 +00:00
|
|
|
|
2010-03-04 22:35:27 +00:00
|
|
|
uid_t uid = (vol->target.perms.uid == -1) ? getuid() : vol->target.perms.uid;
|
|
|
|
gid_t gid = (vol->target.perms.gid == -1) ? getgid() : vol->target.perms.gid;
|
|
|
|
|
2010-02-22 11:24:02 +00:00
|
|
|
if ((createstat = virFileOperation(vol->target.path,
|
2010-03-16 15:03:59 +00:00
|
|
|
O_RDWR | O_CREAT | O_EXCL,
|
2010-03-04 22:35:27 +00:00
|
|
|
vol->target.perms.mode, uid, gid,
|
2010-02-19 17:12:01 +00:00
|
|
|
createRawFileOpHook, &hdata,
|
|
|
|
VIR_FILE_OP_FORCE_PERMS |
|
|
|
|
(pool->def->type == VIR_STORAGE_POOL_NETFS
|
|
|
|
? VIR_FILE_OP_AS_UID : 0))) < 0) {
|
2010-07-19 23:25:58 +00:00
|
|
|
virReportSystemError(-createstat,
|
2010-02-19 17:12:01 +00:00
|
|
|
_("cannot create path '%s'"),
|
|
|
|
vol->target.path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-07-16 16:09:26 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
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) {
|
2010-02-10 12:33:34 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unable to generate uuid"));
|
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
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
tmp = conn->secretDriver->lookupByUUID(conn, uuid);
|
|
|
|
if (tmp == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virSecretFree(tmp);
|
|
|
|
}
|
|
|
|
|
2010-02-10 12:33:34 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("too many conflicts when generating an uuid"));
|
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
|
|
|
|
|
|
|
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) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_NO_SUPPORT, "%s",
|
2009-08-14 18:06:59 +00:00
|
|
|
_("secret storage not supported"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
enc = vol->target.encryption;
|
|
|
|
if (enc->nsecrets != 0) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-08-14 18:06:59 +00:00
|
|
|
_("secrets already defined"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(enc_secret) < 0 || VIR_REALLOC_N(enc->secrets, 1) < 0 ||
|
|
|
|
VIR_ALLOC(def) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-08-14 18:06:59 +00:00
|
|
|
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) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-08-14 18:06:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-02-10 12:33:34 +00:00
|
|
|
xml = virSecretDefFormat(def);
|
2009-08-14 18:06:59 +00:00
|
|
|
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);
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStorageGenerateQcowPassphrase(value) < 0)
|
2009-08-14 18:06:59 +00:00
|
|
|
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);
|
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2009-08-14 18:06:59 +00:00
|
|
|
virSecretDefFree(def);
|
|
|
|
VIR_FREE(enc_secret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-01-20 23:41:52 +00:00
|
|
|
static int virStorageBuildSetUIDHook(void *data) {
|
|
|
|
virStorageVolDefPtr vol = data;
|
|
|
|
|
2010-03-04 22:35:27 +00:00
|
|
|
if ((vol->target.perms.gid != -1)
|
2010-01-20 23:41:52 +00:00
|
|
|
&& (setgid(vol->target.perms.gid) != 0)) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-20 23:41:52 +00:00
|
|
|
_("Cannot set gid to %u before creating %s"),
|
|
|
|
vol->target.perms.gid, vol->target.path);
|
|
|
|
return -1;
|
|
|
|
}
|
2010-03-04 22:35:27 +00:00
|
|
|
if ((vol->target.perms.uid != -1)
|
2010-01-20 23:41:52 +00:00
|
|
|
&& (setuid(vol->target.perms.uid) != 0)) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-20 23:41:52 +00:00
|
|
|
_("Cannot set uid to %u before creating %s"),
|
|
|
|
vol->target.perms.uid, vol->target.path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:41:52 +00:00
|
|
|
static int virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
|
2010-01-20 23:41:52 +00:00
|
|
|
virStorageVolDefPtr vol,
|
|
|
|
const char **cmdargv) {
|
|
|
|
struct stat st;
|
|
|
|
gid_t gid;
|
|
|
|
uid_t uid;
|
|
|
|
int filecreated = 0;
|
|
|
|
|
|
|
|
if ((pool->def->type == VIR_STORAGE_POOL_NETFS)
|
2010-03-04 22:35:27 +00:00
|
|
|
&& (((getuid() == 0)
|
|
|
|
&& (vol->target.perms.uid != -1)
|
|
|
|
&& (vol->target.perms.uid != 0))
|
|
|
|
|| ((vol->target.perms.gid != -1)
|
|
|
|
&& (vol->target.perms.gid != getgid())))) {
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virRunWithHook(cmdargv,
|
2010-01-20 23:41:52 +00:00
|
|
|
virStorageBuildSetUIDHook, vol, NULL) == 0) {
|
|
|
|
/* command was successfully run, check if the file was created */
|
|
|
|
if (stat(vol->target.path, &st) >=0)
|
|
|
|
filecreated = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!filecreated) {
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virRun(cmdargv, NULL) < 0) {
|
2010-01-20 23:41:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (stat(vol->target.path, &st) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-20 23:41:52 +00:00
|
|
|
_("%s failed to create %s"),
|
|
|
|
cmdargv[0], vol->target.path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uid = (vol->target.perms.uid != st.st_uid) ? vol->target.perms.uid : -1;
|
|
|
|
gid = (vol->target.perms.gid != st.st_gid) ? vol->target.perms.gid : -1;
|
|
|
|
if (((uid != -1) || (gid != -1))
|
|
|
|
&& (chown(vol->target.path, uid, gid) < 0)) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-20 23:41:52 +00:00
|
|
|
_("cannot chown %s to (%u, %u)"),
|
2010-03-04 22:35:27 +00:00
|
|
|
vol->target.path, uid, gid);
|
2010-01-20 23:41:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (chmod(vol->target.path, vol->target.perms.mode) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-20 23:41:52 +00:00
|
|
|
_("cannot set mode of '%s' to %04o"),
|
|
|
|
vol->target.path, vol->target.perms.mode);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-16 13:14:05 +00:00
|
|
|
enum {
|
|
|
|
QEMU_IMG_BACKING_FORMAT_NONE = 0,
|
|
|
|
QEMU_IMG_BACKING_FORMAT_FLAG,
|
|
|
|
QEMU_IMG_BACKING_FORMAT_OPTIONS,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int virStorageBackendQEMUImgBackingFormat(const char *qemuimg)
|
|
|
|
{
|
|
|
|
const char *const qemuarg[] = { qemuimg, "-h", NULL };
|
|
|
|
const char *const qemuenv[] = { "LC_ALL=C", NULL };
|
|
|
|
pid_t child = 0;
|
|
|
|
int status;
|
|
|
|
int newstdout = -1;
|
|
|
|
char *help = NULL;
|
|
|
|
enum { MAX_HELP_OUTPUT_SIZE = 1024*8 };
|
|
|
|
char *start;
|
|
|
|
char *end;
|
|
|
|
char *tmp;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virExec(qemuarg, qemuenv, NULL,
|
|
|
|
&child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-07-30 16:24:17 +00:00
|
|
|
if (virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help) < 0) {
|
2010-06-16 13:14:05 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to read '%s -h' output"),
|
|
|
|
qemuimg);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = strstr(help, " create ");
|
|
|
|
end = strstr(start, "\n");
|
2011-03-10 07:02:28 +00:00
|
|
|
if (((tmp = strstr(start, "-F fmt")) && tmp < end) ||
|
|
|
|
((tmp = strstr(start, "-F backing_fmt")) && tmp < end))
|
2010-06-16 13:14:05 +00:00
|
|
|
ret = QEMU_IMG_BACKING_FORMAT_FLAG;
|
|
|
|
else if ((tmp = strstr(start, "[-o options]")) && tmp < end)
|
|
|
|
ret = QEMU_IMG_BACKING_FORMAT_OPTIONS;
|
|
|
|
else
|
|
|
|
ret = QEMU_IMG_BACKING_FORMAT_NONE;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(help);
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(newstdout);
|
2010-06-16 13:14:05 +00:00
|
|
|
rewait:
|
|
|
|
if (child) {
|
|
|
|
if (waitpid(child, &status, 0) != child) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto rewait;
|
|
|
|
|
|
|
|
VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
|
|
|
|
WEXITSTATUS(status), (unsigned long)child);
|
|
|
|
}
|
|
|
|
if (WEXITSTATUS(status) != 0) {
|
|
|
|
VIR_WARN("Unexpected exit status '%d', qemu probably failed",
|
|
|
|
WEXITSTATUS(status));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
static int
|
|
|
|
virStorageBackendCreateQemuImg(virConnectPtr conn,
|
2010-01-20 23:41:52 +00:00
|
|
|
virStoragePoolObjPtr pool,
|
2009-07-16 16:09:26 +00:00
|
|
|
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
|
|
|
{
|
2010-06-16 13:14:05 +00:00
|
|
|
int ret = -1;
|
2010-08-18 21:54:11 +00:00
|
|
|
char *size = NULL;
|
2009-07-16 16:09:26 +00:00
|
|
|
char *create_tool;
|
2011-03-10 02:05:14 +00:00
|
|
|
int imgformat = -1;
|
2009-07-16 16:09:26 +00:00
|
|
|
|
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 ?
|
2010-06-16 13:14:05 +00:00
|
|
|
virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ?
|
|
|
|
VIR_STORAGE_FILE_RAW :
|
|
|
|
inputvol->target.format) :
|
|
|
|
NULL;
|
2009-07-16 16:09:26 +00:00
|
|
|
|
|
|
|
if (type == NULL) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-16 16:09:26 +00:00
|
|
|
_("unknown storage vol type %d"),
|
|
|
|
vol->target.format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (inputvol && inputType == NULL) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-16 16:09:26 +00:00
|
|
|
_("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))) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-16 16:09:26 +00:00
|
|
|
"%s", _("a different backing store can not "
|
|
|
|
"be specified."));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (backingType == NULL) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-16 16:09:26 +00:00
|
|
|
_("unknown storage vol backing store type %d"),
|
|
|
|
vol->backingStore.format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (access(vol->backingStore.path, R_OK) != 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-07-16 16:09:26 +00:00
|
|
|
_("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) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_NO_SUPPORT,
|
2009-07-21 02:40:50 +00:00
|
|
|
_("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) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_NO_SUPPORT,
|
2009-07-21 02:40:50 +00:00
|
|
|
_("unsupported volume encryption format %d"),
|
|
|
|
vol->target.encryption->format);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-08-14 18:06:59 +00:00
|
|
|
if (enc->nsecrets > 1) {
|
2011-01-15 15:31:29 +00:00
|
|
|
virStorageReportError(VIR_ERR_XML_ERROR, "%s",
|
2009-07-21 02:40:50 +00:00
|
|
|
_("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
|
|
|
}
|
|
|
|
|
2010-06-16 13:14:05 +00:00
|
|
|
/* Size in KB */
|
2011-01-28 21:03:24 +00:00
|
|
|
if (virAsprintf(&size, "%lluK", VIR_DIV_UP(vol->capacity, 1024)) < 0) {
|
2010-08-18 21:54:11 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-06-16 13:14:05 +00:00
|
|
|
|
|
|
|
/* KVM is usually ahead of qemu on features, so try that first */
|
|
|
|
create_tool = virFindFileInPath("kvm-img");
|
|
|
|
if (!create_tool)
|
|
|
|
create_tool = virFindFileInPath("qemu-img");
|
|
|
|
|
|
|
|
if (!create_tool) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(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;
|
|
|
|
}
|
|
|
|
|
2011-03-10 02:05:14 +00:00
|
|
|
imgformat = virStorageBackendQEMUImgBackingFormat(create_tool);
|
|
|
|
if (imgformat < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-07-16 16:09:26 +00:00
|
|
|
if (inputvol) {
|
2010-06-16 13:14:05 +00:00
|
|
|
const char *imgargv[] = {
|
|
|
|
create_tool,
|
|
|
|
"convert",
|
|
|
|
"-f", inputType,
|
|
|
|
"-O", type,
|
|
|
|
inputPath,
|
|
|
|
vol->target.path,
|
|
|
|
NULL,
|
2011-03-10 02:05:14 +00:00
|
|
|
NULL,
|
|
|
|
NULL
|
2010-06-16 13:14:05 +00:00
|
|
|
};
|
|
|
|
|
2011-03-10 02:05:14 +00:00
|
|
|
if (vol->target.encryption != NULL) {
|
2011-03-10 07:02:28 +00:00
|
|
|
if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) {
|
2011-03-10 02:05:14 +00:00
|
|
|
imgargv[8] = "-o";
|
|
|
|
imgargv[9] = "encryption=on";
|
|
|
|
} else {
|
|
|
|
imgargv[8] = "-e";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-16 13:14:05 +00:00
|
|
|
ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
2009-07-16 16:09:26 +00:00
|
|
|
} else if (vol->backingStore.path) {
|
2010-06-16 13:14:05 +00:00
|
|
|
const char *imgargv[] = {
|
|
|
|
create_tool,
|
|
|
|
"create",
|
|
|
|
"-f", type,
|
|
|
|
"-b", vol->backingStore.path,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2011-03-10 02:05:14 +00:00
|
|
|
char *optflag = NULL;
|
2010-06-16 13:14:05 +00:00
|
|
|
switch (imgformat) {
|
|
|
|
case QEMU_IMG_BACKING_FORMAT_FLAG:
|
|
|
|
imgargv[6] = "-F";
|
|
|
|
imgargv[7] = backingType;
|
|
|
|
imgargv[8] = vol->target.path;
|
|
|
|
imgargv[9] = size;
|
2009-07-21 02:40:50 +00:00
|
|
|
if (vol->target.encryption != NULL)
|
2010-06-16 13:14:05 +00:00
|
|
|
imgargv[10] = "-e";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_IMG_BACKING_FORMAT_OPTIONS:
|
|
|
|
if (virAsprintf(&optflag, "backing_fmt=%s", backingType) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-03-10 02:05:14 +00:00
|
|
|
|
|
|
|
if (vol->target.encryption != NULL) {
|
|
|
|
char *tmp = NULL;
|
|
|
|
if (virAsprintf(&tmp, "%s,%s", optflag, "encryption=on") < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(optflag);
|
|
|
|
optflag = tmp;
|
|
|
|
}
|
|
|
|
|
2010-06-16 13:14:05 +00:00
|
|
|
imgargv[6] = "-o";
|
|
|
|
imgargv[7] = optflag;
|
|
|
|
imgargv[8] = vol->target.path;
|
|
|
|
imgargv[9] = size;
|
|
|
|
|
|
|
|
default:
|
|
|
|
VIR_INFO("Unable to set backing store format for %s with %s",
|
|
|
|
vol->target.path, create_tool);
|
|
|
|
imgargv[6] = vol->target.path;
|
|
|
|
imgargv[7] = size;
|
|
|
|
if (vol->target.encryption != NULL)
|
|
|
|
imgargv[8] = "-e";
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
|
|
|
VIR_FREE(optflag);
|
2009-07-16 16:09:26 +00:00
|
|
|
} else {
|
2010-06-16 13:14:05 +00:00
|
|
|
/* The extra NULL field is for indicating encryption (-e). */
|
|
|
|
const char *imgargv[] = {
|
|
|
|
create_tool,
|
|
|
|
"create",
|
|
|
|
"-f", type,
|
|
|
|
vol->target.path,
|
|
|
|
size,
|
|
|
|
NULL,
|
2011-03-10 02:05:14 +00:00
|
|
|
NULL,
|
2010-06-16 13:14:05 +00:00
|
|
|
NULL
|
|
|
|
};
|
2011-03-10 02:05:14 +00:00
|
|
|
|
|
|
|
if (vol->target.encryption != NULL) {
|
2011-03-10 07:02:28 +00:00
|
|
|
if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) {
|
2011-03-10 02:05:14 +00:00
|
|
|
imgargv[6] = "-o";
|
|
|
|
imgargv[7] = "encryption=on";
|
|
|
|
} else {
|
|
|
|
imgargv[6] = "-e";
|
|
|
|
}
|
|
|
|
}
|
2009-07-16 16:09:26 +00:00
|
|
|
|
2010-06-16 13:14:05 +00:00
|
|
|
ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
|
|
|
}
|
2009-07-16 16:09:26 +00:00
|
|
|
|
2010-06-16 13:14:05 +00:00
|
|
|
cleanup:
|
2010-08-18 21:54:11 +00:00
|
|
|
VIR_FREE(size);
|
2010-06-16 13:14:05 +00:00
|
|
|
VIR_FREE(create_tool);
|
2009-07-16 16:09:26 +00:00
|
|
|
|
2010-01-20 23:41:52 +00:00
|
|
|
return ret;
|
2009-07-16 16:09:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Xen removed the fully-functional qemu-img, and replaced it
|
|
|
|
* with a partially functional qcow-create. Go figure ??!?
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageBackendCreateQcowCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2010-01-20 23:41:52 +00:00
|
|
|
virStoragePoolObjPtr pool,
|
2009-07-16 16:09:26 +00:00
|
|
|
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
|
|
|
{
|
2010-01-20 23:41:52 +00:00
|
|
|
int ret;
|
2010-08-18 21:54:11 +00:00
|
|
|
char *size;
|
2009-07-16 16:09:26 +00:00
|
|
|
const char *imgargv[4];
|
|
|
|
|
|
|
|
if (inputvol) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(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) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-16 16:09:26 +00:00
|
|
|
_("unsupported storage vol type %d"),
|
|
|
|
vol->target.format);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (vol->backingStore.path != NULL) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(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) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_NO_SUPPORT,
|
2009-07-21 02:40:50 +00:00
|
|
|
"%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 :-( */
|
2011-01-28 21:03:24 +00:00
|
|
|
if (virAsprintf(&size, "%llu",
|
|
|
|
VIR_DIV_UP(vol->capacity, (1024 * 1024))) < 0) {
|
2010-08-18 21:54:11 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
2009-07-16 16:09:26 +00:00
|
|
|
|
|
|
|
imgargv[0] = virFindFileInPath("qcow-create");
|
|
|
|
imgargv[1] = size;
|
|
|
|
imgargv[2] = vol->target.path;
|
|
|
|
imgargv[3] = NULL;
|
|
|
|
|
2010-02-04 22:41:52 +00:00
|
|
|
ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
2009-07-16 16:09:26 +00:00
|
|
|
VIR_FREE(imgargv[0]);
|
2010-08-18 21:54:11 +00:00
|
|
|
VIR_FREE(size);
|
2009-07-16 16:09:26 +00:00
|
|
|
|
2010-01-20 23:41:52 +00:00
|
|
|
return ret;
|
2009-07-16 16:09:26 +00:00
|
|
|
}
|
|
|
|
|
2009-07-16 16:27:07 +00:00
|
|
|
virStorageBackendBuildVolFrom
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageBackendFSImageToolTypeToFunc(int tool_type)
|
2009-07-16 16:09:26 +00:00
|
|
|
{
|
|
|
|
switch (tool_type) {
|
|
|
|
case TOOL_KVM_IMG:
|
|
|
|
case TOOL_QEMU_IMG:
|
|
|
|
return virStorageBackendCreateQemuImg;
|
|
|
|
case TOOL_QCOW_CREATE:
|
|
|
|
return virStorageBackendCreateQcowCreate;
|
|
|
|
default:
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-16 16:09:26 +00:00
|
|
|
_("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
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol,
|
2009-07-16 16:09:26 +00:00
|
|
|
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) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-16 16:09:26 +00:00
|
|
|
"%s", _("creation of non-raw file images is "
|
|
|
|
"not supported without qemu-img."));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
return virStorageBackendFSImageToolTypeToFunc(tool_type);
|
2009-07-16 16:09:26 +00:00
|
|
|
}
|
|
|
|
|
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];
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-02-20 15:34:52 +00:00
|
|
|
_("missing backend for pool type %d"), type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
/*
|
|
|
|
* Allows caller to silently ignore files with improper mode
|
|
|
|
*
|
2010-12-21 06:45:24 +00:00
|
|
|
* Returns -1 on error, -2 if file mode is unexpected or the
|
|
|
|
* volume is a dangling symbolic link.
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
*/
|
2008-02-20 15:38:29 +00:00
|
|
|
int
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags)
|
2008-02-20 15:38:29 +00:00
|
|
|
{
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
int fd, mode = 0;
|
|
|
|
struct stat sb;
|
2008-02-20 15:38:29 +00:00
|
|
|
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
|
2010-12-21 06:45:24 +00:00
|
|
|
if ((errno == ENOENT || errno == ELOOP) &&
|
|
|
|
lstat(path, &sb) == 0) {
|
|
|
|
VIR_WARN("ignoring dangling symlink '%s'", path);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot open volume '%s'"),
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
path);
|
2008-02-20 15:38:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
if (fstat(fd, &sb) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("cannot stat file '%s'"),
|
|
|
|
path);
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (S_ISREG(sb.st_mode))
|
|
|
|
mode = VIR_STORAGE_VOL_OPEN_REG;
|
|
|
|
else if (S_ISCHR(sb.st_mode))
|
|
|
|
mode = VIR_STORAGE_VOL_OPEN_CHAR;
|
|
|
|
else if (S_ISBLK(sb.st_mode))
|
|
|
|
mode = VIR_STORAGE_VOL_OPEN_BLOCK;
|
|
|
|
|
|
|
|
if (!(mode & flags)) {
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
|
|
|
|
if (mode & VIR_STORAGE_VOL_OPEN_ERROR) {
|
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected storage mode for '%s'"), path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virStorageBackendVolOpen(const char *path)
|
|
|
|
{
|
|
|
|
return virStorageBackendVolOpenCheckMode(path,
|
|
|
|
VIR_STORAGE_VOL_OPEN_DEFAULT);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target,
|
|
|
|
unsigned long long *allocation,
|
|
|
|
unsigned long long *capacity)
|
|
|
|
{
|
|
|
|
int ret, fd;
|
|
|
|
|
|
|
|
if ((ret = virStorageBackendVolOpen(target->path)) < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
fd = ret;
|
2010-02-04 20:02:58 +00:00
|
|
|
ret = virStorageBackendUpdateVolTargetInfoFD(target,
|
2009-01-27 18:30:03 +00:00
|
|
|
fd,
|
|
|
|
allocation,
|
|
|
|
capacity);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
int
|
2010-02-04 20:02:58 +00:00
|
|
|
virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
|
2009-01-27 18:30:03 +00:00
|
|
|
int withCapacity)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
if ((ret = virStorageBackendUpdateVolTargetInfo(&vol->target,
|
2009-01-27 18:30:03 +00:00
|
|
|
&vol->allocation,
|
|
|
|
withCapacity ? &vol->capacity : NULL)) < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (vol->backingStore.path &&
|
2010-02-04 20:02:58 +00:00
|
|
|
(ret = virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
|
2009-01-27 18:30:03 +00:00
|
|
|
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
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
* @fd: fd of storage volume to update, via virStorageBackendOpenVol*
|
2009-05-12 19:59:46 +00:00
|
|
|
* @allocation: If not NULL, updated allocation information will be stored
|
|
|
|
* @capacity: If not NULL, updated capacity info will be stored
|
|
|
|
*
|
storage: Check for invalid storage mode before opening
If a directory pool contains pipes or sockets, a pool start can fail or hang:
https://bugzilla.redhat.com/show_bug.cgi?id=589577
We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.
Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.
This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.
This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.
v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
O_NONBLOCK|O_NOCTTY.
v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
different error semantics.
v4: Make second VolOpen function more extensible. Didn't opt to change
FS backend defaults, this can just be to fix the original bug.
v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
2010-05-20 18:25:01 +00:00
|
|
|
* Returns 0 for success, -1 on a legitimate error condition.
|
2009-05-12 19:59:46 +00:00
|
|
|
*/
|
2008-02-20 15:38:29 +00:00
|
|
|
int
|
2010-02-04 20:02:58 +00:00
|
|
|
virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
|
2009-01-27 18:30:03 +00:00
|
|
|
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) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot stat file '%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
|
|
|
if (allocation) {
|
|
|
|
if (S_ISREG(sb.st_mode)) {
|
2010-05-03 20:44:12 +00:00
|
|
|
#ifndef WIN32
|
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) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-27 18:30:03 +00:00
|
|
|
_("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) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("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);
|
2010-11-24 21:09:58 +00:00
|
|
|
freecon(filecon);
|
2009-01-27 18:30:03 +00:00
|
|
|
if (target->perms.label == NULL) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-03-17 15:09:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
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
|
2010-05-20 17:29:24 +00:00
|
|
|
virStorageBackendDetectBlockVolFormatFD(virStorageVolTargetPtr target,
|
|
|
|
int fd)
|
2009-09-08 13:47:45 +00:00
|
|
|
{
|
|
|
|
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) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-09-08 13:47:45 +00:00
|
|
|
_("cannot seek to beginning of file '%s'"),
|
|
|
|
target->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
bytes = saferead(fd, buffer, sizeof(buffer));
|
|
|
|
if (bytes < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-09-08 13:47:45 +00:00
|
|
|
_("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 *
|
2010-02-04 20:02:58 +00:00
|
|
|
virStorageBackendStablePath(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;
|
|
|
|
}
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("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) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
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)
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
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
|
|
|
|
2010-05-03 20:44:12 +00:00
|
|
|
#ifndef WIN32
|
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
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageBackendRunProgRegex(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) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
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));
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-02-20 15:38:29 +00:00
|
|
|
_("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) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
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) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Run the program and capture its output */
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virExec(prog, NULL, NULL,
|
2008-08-27 11:42:52 +00:00
|
|
|
&child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) {
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-11-17 02:13:29 +00:00
|
|
|
if ((list = VIR_FDOPEN(fd, "r")) == NULL) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(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) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We're matching on the last regex, so callback time */
|
|
|
|
if (i == (nregex-1)) {
|
2010-02-10 11:42:56 +00:00
|
|
|
if (((*func)(pool, groups, data)) < 0)
|
2008-02-20 15:38:29 +00:00
|
|
|
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
|
|
|
|
2010-11-17 02:13:29 +00:00
|
|
|
VIR_FORCE_FCLOSE(list);
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
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) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("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 {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(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
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
|
2008-02-20 15:38:29 +00:00
|
|
|
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) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
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 */
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virExec(prog, NULL, NULL,
|
2008-08-27 11:42:52 +00:00
|
|
|
&child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) {
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-11-17 02:13:29 +00:00
|
|
|
if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-11-17 02:13:29 +00:00
|
|
|
"%s", _("cannot open file using 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. */
|
2010-02-10 11:42:56 +00:00
|
|
|
if (n_tok && func (pool, n_tok, v, data) < 0)
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++n_tok;
|
|
|
|
if (n_tok == n_columns) {
|
2010-02-10 11:42:56 +00:00
|
|
|
if (func (pool, n_tok, v, data) < 0)
|
2008-02-20 15:38:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
n_tok = 0;
|
|
|
|
for (i = 0; i < n_columns; i++) {
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(v[i]);
|
2008-02-20 15:38:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (feof (fp))
|
|
|
|
err = 0;
|
|
|
|
else
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("read error on pipe to '%s'"), prog[0]);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0; i < n_columns; i++)
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(v[i]);
|
|
|
|
VIR_FREE(v);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
2010-11-17 02:13:29 +00:00
|
|
|
VIR_FORCE_FCLOSE(fp);
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
2008-02-20 15:38:29 +00:00
|
|
|
|
|
|
|
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) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("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) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-02-20 15:38:29 +00:00
|
|
|
_("non-zero exit status from command %d"),
|
|
|
|
WEXITSTATUS(exitstatus));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(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
|
|
|
|
2010-05-03 20:44:12 +00:00
|
|
|
#else /* WIN32 */
|
2008-09-05 12:03:45 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("%s not implemented on Win32"), __FUNCTION__);
|
2008-09-05 12:03:45 +00:00
|
|
|
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)
|
|
|
|
{
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("%s not implemented on Win32"), __FUNCTION__);
|
2008-09-05 12:03:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2010-05-03 20:44:12 +00:00
|
|
|
#endif /* WIN32 */
|