2008-02-20 15:34:52 +00:00
|
|
|
/*
|
|
|
|
* storage_conf.c: config handling for storage driver
|
|
|
|
*
|
2016-01-07 11:57:28 +00:00
|
|
|
* Copyright (C) 2006-2016 Red Hat, Inc.
|
2008-02-20 15:34:52 +00:00
|
|
|
* Copyright (C) 2006-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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-02-20 15:34:52 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2017-03-10 12:32:46 +00:00
|
|
|
#include "storage_adapter_conf.h"
|
2008-02-20 15:34:52 +00:00
|
|
|
#include "storage_conf.h"
|
2021-01-21 14:44:53 +00:00
|
|
|
#include "storage_source_conf.h"
|
2008-11-17 11:19:33 +00:00
|
|
|
|
2012-12-13 18:13:21 +00:00
|
|
|
#include "virxml.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2014-06-26 12:18:09 +00:00
|
|
|
#include "virlog.h"
|
2020-02-16 21:59:28 +00:00
|
|
|
#include "virutil.h"
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
|
|
2014-06-26 12:18:09 +00:00
|
|
|
VIR_LOG_INIT("conf.storage_conf");
|
|
|
|
|
2013-11-19 20:14:54 +00:00
|
|
|
VIR_ENUM_IMPL(virStorageVol,
|
|
|
|
VIR_STORAGE_VOL_LAST,
|
2016-04-11 16:16:19 +00:00
|
|
|
"file", "block", "dir", "network",
|
2019-01-20 16:30:15 +00:00
|
|
|
"netdir", "ploop",
|
|
|
|
);
|
2013-11-19 20:14:54 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePool,
|
|
|
|
VIR_STORAGE_POOL_LAST,
|
|
|
|
"dir", "fs", "netfs",
|
|
|
|
"logical", "disk", "iscsi",
|
2018-07-31 08:44:21 +00:00
|
|
|
"iscsi-direct", "scsi", "mpath",
|
|
|
|
"rbd", "sheepdog", "gluster",
|
2019-01-20 16:30:15 +00:00
|
|
|
"zfs", "vstorage",
|
|
|
|
);
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
|
|
|
|
VIR_STORAGE_POOL_FS_LAST,
|
|
|
|
"auto", "ext2", "ext3",
|
|
|
|
"ext4", "ufs", "iso9660", "udf",
|
2019-01-20 16:30:15 +00:00
|
|
|
"gfs", "gfs2", "vfat", "hfs+", "xfs", "ocfs2",
|
2019-11-15 11:45:19 +00:00
|
|
|
"vmfs",
|
2019-01-20 16:30:15 +00:00
|
|
|
);
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
|
|
|
|
VIR_STORAGE_POOL_NETFS_LAST,
|
2019-01-20 16:30:15 +00:00
|
|
|
"auto", "nfs", "glusterfs", "cifs",
|
|
|
|
);
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatDisk,
|
|
|
|
VIR_STORAGE_POOL_DISK_LAST,
|
|
|
|
"unknown", "dos", "dvh", "gpt",
|
2019-01-20 16:30:15 +00:00
|
|
|
"mac", "bsd", "pc98", "sun", "lvm2",
|
|
|
|
);
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatLogical,
|
|
|
|
VIR_STORAGE_POOL_LOGICAL_LAST,
|
2019-01-20 16:30:15 +00:00
|
|
|
"unknown", "lvm2",
|
|
|
|
);
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStorageVolFormatDisk,
|
|
|
|
VIR_STORAGE_VOL_DISK_LAST,
|
|
|
|
"none", "linux", "fat16",
|
|
|
|
"fat32", "linux-swap",
|
|
|
|
"linux-lvm", "linux-raid",
|
2019-01-20 16:30:15 +00:00
|
|
|
"extended",
|
|
|
|
);
|
2008-11-17 11:19:33 +00:00
|
|
|
|
2019-03-19 13:42:17 +00:00
|
|
|
VIR_ENUM_IMPL(virStorageVolDefRefreshAllocation,
|
|
|
|
VIR_STORAGE_VOL_DEF_REFRESH_ALLOCATION_LAST,
|
|
|
|
"default", "capacity",
|
|
|
|
);
|
|
|
|
|
2014-05-14 19:48:15 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePartedFs,
|
2009-06-26 16:18:59 +00:00
|
|
|
VIR_STORAGE_PARTED_FS_TYPE_LAST,
|
2009-07-10 13:02:30 +00:00
|
|
|
"ext2", "ext2", "fat16",
|
2009-06-26 16:18:59 +00:00
|
|
|
"fat32", "linux-swap",
|
|
|
|
"ext2", "ext2",
|
2019-01-20 16:30:15 +00:00
|
|
|
"extended",
|
|
|
|
);
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
typedef const char *(*virStorageVolFormatToString)(int format);
|
|
|
|
typedef int (*virStorageVolFormatFromString)(const char *format);
|
|
|
|
|
|
|
|
typedef const char *(*virStoragePoolFormatToString)(int format);
|
|
|
|
typedef int (*virStoragePoolFormatFromString)(const char *format);
|
|
|
|
|
|
|
|
typedef struct _virStorageVolOptions virStorageVolOptions;
|
|
|
|
struct _virStorageVolOptions {
|
2008-12-04 15:22:04 +00:00
|
|
|
int defaultFormat;
|
2019-02-07 17:29:43 +00:00
|
|
|
int lastFormat;
|
2008-11-17 11:19:33 +00:00
|
|
|
virStorageVolFormatToString formatToString;
|
|
|
|
virStorageVolFormatFromString formatFromString;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Flags to indicate mandatory components in the pool source */
|
|
|
|
enum {
|
2013-05-16 03:10:28 +00:00
|
|
|
VIR_STORAGE_POOL_SOURCE_HOST = (1 << 0),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE = (1 << 1),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DIR = (1 << 2),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER = (1 << 3),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NAME = (1 << 4),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN = (1 << 5),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK = (1 << 6),
|
2008-11-17 11:19:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _virStoragePoolOptions virStoragePoolOptions;
|
|
|
|
struct _virStoragePoolOptions {
|
2011-07-07 23:29:42 +00:00
|
|
|
unsigned int flags;
|
2008-11-17 11:19:33 +00:00
|
|
|
int defaultFormat;
|
2019-02-07 17:29:43 +00:00
|
|
|
int lastFormat;
|
2019-01-03 16:47:48 +00:00
|
|
|
|
2019-08-20 21:17:37 +00:00
|
|
|
virXMLNamespace ns;
|
2019-01-03 16:47:48 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolFormatToString formatToString;
|
|
|
|
virStoragePoolFormatFromString formatFromString;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _virStoragePoolTypeInfo virStoragePoolTypeInfo;
|
|
|
|
struct _virStoragePoolTypeInfo {
|
|
|
|
int poolType;
|
|
|
|
virStoragePoolOptions poolOptions;
|
|
|
|
virStorageVolOptions volOptions;
|
|
|
|
};
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
storage: list more file types
When an image has no backing file, using VIR_STORAGE_FILE_AUTO
for its type is a bit confusing. Additionally, a future patch
would like to reserve a default value for the case of no file
type specified in the XML, but different from the current use
of -1 to imply probing, since probing is not always safe.
Also, a couple of file types were missing compared to supported
code: libxl supports 'vhd', and qemu supports 'fat' for directories
passed through as a file system.
* src/util/storage_file.h (virStorageFileFormat): Add
VIR_STORAGE_FILE_NONE, VIR_STORAGE_FILE_FAT, VIR_STORAGE_FILE_VHD.
* src/util/storage_file.c (virStorageFileMatchesVersion): Match
documentation when version probing not supported.
(cowGetBackingStore, qcowXGetBackingStore, qcow1GetBackingStore)
(qcow2GetBackingStoreFormat, qedGetBackingStore)
(virStorageFileGetMetadataFromBuf)
(virStorageFileGetMetadataFromFD): Take NONE into account.
* src/conf/domain_conf.c (virDomainDiskDefForeachPath): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo): Likewise.
* src/conf/storage_conf.c (virStorageVolumeFormatFromString): New
function.
(poolTypeInfo): Use it.
2012-09-28 17:11:07 +00:00
|
|
|
static int
|
|
|
|
virStorageVolumeFormatFromString(const char *format)
|
|
|
|
{
|
|
|
|
int ret = virStorageFileFormatTypeFromString(format);
|
|
|
|
if (ret == VIR_STORAGE_FILE_NONE)
|
|
|
|
return -1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
static virStoragePoolTypeInfo poolTypeInfo[] = {
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_LOGICAL,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_NAME |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_POOL_LOGICAL_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStoragePoolFormatLogicalTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatLogicalTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_DIR,
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_FILE_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_FS,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_FS_AUTO,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_POOL_FS_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStoragePoolFormatFileSystemTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatFileSystemTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
.volOptions = {
|
2013-05-16 12:40:51 +00:00
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_FILE_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_NETFS,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DIR),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_NETFS_AUTO,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_POOL_NETFS_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStoragePoolFormatFileSystemNetTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatFileSystemNetTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
.volOptions = {
|
2013-05-16 12:40:51 +00:00
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_FILE_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_ISCSI,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
|
|
|
|
},
|
|
|
|
},
|
2018-07-31 08:44:21 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_ISCSI_DIRECT,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
|
|
|
|
},
|
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_SCSI,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER),
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_RBD,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NAME),
|
|
|
|
},
|
2019-07-12 14:13:17 +00:00
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
}
|
2009-04-01 16:03:22 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_SHEEPDOG,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NAME),
|
|
|
|
},
|
2012-05-14 09:06:42 +00:00
|
|
|
},
|
2013-11-19 23:26:05 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_GLUSTER,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NAME |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DIR),
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_FILE_LAST,
|
2013-11-19 23:26:05 +00:00
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
}
|
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_MPATH,
|
2012-07-18 19:06:58 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_DISK,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_POOL_DISK_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStoragePoolFormatDiskTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatDiskTypeToString,
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_VOL_DISK_NONE,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_VOL_DISK_LAST,
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatFromString = virStorageVolFormatDiskTypeFromString,
|
|
|
|
.formatToString = virStorageVolFormatDiskTypeToString,
|
|
|
|
},
|
2014-07-21 14:38:42 +00:00
|
|
|
},
|
|
|
|
{.poolType = VIR_STORAGE_POOL_ZFS,
|
|
|
|
.poolOptions = {
|
2014-09-07 14:01:34 +00:00
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_NAME |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE),
|
2014-07-21 14:38:42 +00:00
|
|
|
},
|
|
|
|
},
|
2017-01-17 14:10:55 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_VSTORAGE,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = VIR_STORAGE_POOL_SOURCE_NAME,
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
2019-02-07 17:29:43 +00:00
|
|
|
.lastFormat = VIR_STORAGE_FILE_LAST,
|
2017-01-17 14:10:55 +00:00
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virStoragePoolTypeInfo *
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolTypeInfoLookup(int type)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(poolTypeInfo); i++)
|
2008-11-17 11:19:33 +00:00
|
|
|
if (poolTypeInfo[i].poolType == type)
|
|
|
|
return &poolTypeInfo[i];
|
|
|
|
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing backend for pool type %d"), type);
|
2008-11-17 11:19:33 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virStoragePoolOptions *
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolOptionsForPoolType(int type)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolTypeInfo *backend = virStoragePoolTypeInfoLookup(type);
|
2008-11-17 11:19:33 +00:00
|
|
|
if (backend == NULL)
|
|
|
|
return NULL;
|
|
|
|
return &backend->poolOptions;
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2019-01-03 16:47:48 +00:00
|
|
|
/* virStoragePoolOptionsPoolTypeSetXMLNamespace:
|
|
|
|
* @type: virStoragePoolType
|
|
|
|
* @ns: xmlopt namespace pointer
|
|
|
|
*
|
|
|
|
* Store the @ns in the pool options for the particular backend.
|
|
|
|
* This allows the parse/format code to then directly call the Namespace
|
|
|
|
* method space (parse, format, href, free) as needed during processing.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virStoragePoolOptionsPoolTypeSetXMLNamespace(int type,
|
2021-03-11 07:16:13 +00:00
|
|
|
virXMLNamespace *ns)
|
2019-01-03 16:47:48 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolTypeInfo *backend = virStoragePoolTypeInfoLookup(type);
|
2019-01-03 16:47:48 +00:00
|
|
|
|
|
|
|
if (!backend)
|
2019-10-21 18:18:51 +00:00
|
|
|
return -1;
|
2019-01-03 16:47:48 +00:00
|
|
|
|
|
|
|
backend->poolOptions.ns = *ns;
|
|
|
|
|
2019-10-21 18:18:51 +00:00
|
|
|
return 0;
|
2019-01-03 16:47:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virStorageVolOptions *
|
2013-05-16 12:40:50 +00:00
|
|
|
virStorageVolOptionsForPoolType(int type)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolTypeInfo *backend = virStoragePoolTypeInfoLookup(type);
|
2008-11-17 11:19:33 +00:00
|
|
|
if (backend == NULL)
|
|
|
|
return NULL;
|
|
|
|
return &backend->volOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-07 17:29:43 +00:00
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolOptionsFormatPool(virBuffer *buf,
|
2019-02-07 17:29:43 +00:00
|
|
|
int type)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolOptions *poolOptions;
|
2019-02-07 17:29:43 +00:00
|
|
|
|
|
|
|
if (!(poolOptions = virStoragePoolOptionsForPoolType(type)))
|
|
|
|
return -1;
|
|
|
|
|
2019-03-06 17:59:39 +00:00
|
|
|
if (!poolOptions->formatToString)
|
2019-02-07 17:29:43 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<poolOptions>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
|
|
|
if (poolOptions->formatToString) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
virBufferAsprintf(buf, "<defaultFormat type='%s'/>\n",
|
|
|
|
(poolOptions->formatToString)(poolOptions->defaultFormat));
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<enum name='sourceFormatType'>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
|
|
|
for (i = 0; i < poolOptions->lastFormat; i++)
|
|
|
|
virBufferAsprintf(buf, "<value>%s</value>\n",
|
|
|
|
(poolOptions->formatToString)(i));
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</enum>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</poolOptions>\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolOptionsFormatVolume(virBuffer *buf,
|
2019-02-07 17:29:43 +00:00
|
|
|
int type)
|
|
|
|
{
|
|
|
|
size_t i;
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolOptions *volOptions;
|
2019-02-07 17:29:43 +00:00
|
|
|
|
|
|
|
if (!(volOptions = virStorageVolOptionsForPoolType(type)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!volOptions->formatToString)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<volOptions>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
|
|
|
virBufferAsprintf(buf, "<defaultFormat type='%s'/>\n",
|
|
|
|
(volOptions->formatToString)(volOptions->defaultFormat));
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<enum name='targetFormatType'>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
|
|
|
for (i = 0; i < volOptions->lastFormat; i++)
|
|
|
|
virBufferAsprintf(buf, "<value>%s</value>\n",
|
|
|
|
(volOptions->formatToString)(i));
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</enum>\n");
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</volOptions>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolDefFree(virStorageVolDef *def)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-10-10 15:13:28 +00:00
|
|
|
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2021-01-30 19:05:50 +00:00
|
|
|
g_free(def->name);
|
|
|
|
g_free(def->key);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-11-13 14:23:27 +00:00
|
|
|
for (i = 0; i < def->source.nextent; i++)
|
2021-01-30 19:05:50 +00:00
|
|
|
g_free(def->source.extents[i].path);
|
|
|
|
g_free(def->source.extents);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-04-01 21:11:30 +00:00
|
|
|
virStorageSourceClear(&def->target);
|
2021-01-30 19:05:50 +00:00
|
|
|
g_free(def);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2014-03-11 07:44:22 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSourceDeviceClear(virStoragePoolSourceDevice *dev)
|
2014-03-11 07:44:22 +00:00
|
|
|
{
|
|
|
|
VIR_FREE(dev->freeExtents);
|
|
|
|
VIR_FREE(dev->path);
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSourceClear(virStoragePoolSource *source)
|
2011-10-21 22:44:52 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
if (!source)
|
2008-10-10 15:13:28 +00:00
|
|
|
return;
|
|
|
|
|
2014-11-13 14:23:27 +00:00
|
|
|
for (i = 0; i < source->nhost; i++)
|
2012-04-25 10:43:09 +00:00
|
|
|
VIR_FREE(source->hosts[i].name);
|
|
|
|
VIR_FREE(source->hosts);
|
|
|
|
|
2014-03-11 07:44:22 +00:00
|
|
|
for (i = 0; i < source->ndevice; i++)
|
|
|
|
virStoragePoolSourceDeviceClear(&source->devices[i]);
|
2008-10-23 11:39:53 +00:00
|
|
|
VIR_FREE(source->devices);
|
|
|
|
VIR_FREE(source->dir);
|
|
|
|
VIR_FREE(source->name);
|
2017-03-10 18:24:56 +00:00
|
|
|
virStorageAdapterClear(&source->adapter);
|
2018-08-07 11:31:31 +00:00
|
|
|
virStorageSourceInitiatorClear(&source->initiator);
|
2014-06-26 12:18:09 +00:00
|
|
|
virStorageAuthDefFree(source->auth);
|
2010-08-17 17:44:27 +00:00
|
|
|
VIR_FREE(source->vendor);
|
|
|
|
VIR_FREE(source->product);
|
2022-06-23 15:17:06 +00:00
|
|
|
VIR_FREE(source->protocolVer);
|
2008-10-23 11:39:53 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2011-10-21 22:44:52 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSourceFree(virStoragePoolSource *source)
|
2011-10-21 22:44:52 +00:00
|
|
|
{
|
|
|
|
virStoragePoolSourceClear(source);
|
2021-01-30 19:05:50 +00:00
|
|
|
g_free(source);
|
2011-10-21 22:44:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDefFree(virStoragePoolDef *def)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2008-10-23 11:39:53 +00:00
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2021-01-30 19:05:50 +00:00
|
|
|
g_free(def->name);
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2011-10-21 22:44:52 +00:00
|
|
|
virStoragePoolSourceClear(&def->source);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2021-01-30 19:05:50 +00:00
|
|
|
g_free(def->target.path);
|
|
|
|
g_free(def->target.perms.label);
|
|
|
|
g_free(def->refresh);
|
2019-01-03 16:47:48 +00:00
|
|
|
if (def->namespaceData && def->ns.free)
|
|
|
|
(def->ns.free)(def->namespaceData);
|
2021-01-30 19:05:50 +00:00
|
|
|
g_free(def);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-15 14:55:19 +00:00
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSource *source,
|
2009-10-15 14:55:19 +00:00
|
|
|
int pool_type,
|
2013-05-16 12:40:50 +00:00
|
|
|
xmlNodePtr node)
|
|
|
|
{
|
2021-05-11 15:01:56 +00:00
|
|
|
xmlNodePtr authnode;
|
2017-03-10 13:18:48 +00:00
|
|
|
xmlNodePtr adapternode;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int nsource;
|
|
|
|
size_t i;
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolOptions *options;
|
2012-11-28 13:34:50 +00:00
|
|
|
int n;
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virStorageAuthDef) authdef = NULL;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree xmlNodePtr *nodeset = NULL;
|
|
|
|
g_autofree char *sourcedir = NULL;
|
2021-05-11 15:01:56 +00:00
|
|
|
VIR_XPATH_NODE_AUTORESTORE(ctxt)
|
2009-10-15 14:55:19 +00:00
|
|
|
|
|
|
|
ctxt->node = node;
|
|
|
|
|
2014-11-13 14:23:27 +00:00
|
|
|
if ((options = virStoragePoolOptionsForPoolType(pool_type)) == NULL)
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2009-10-15 14:55:19 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
source->name = virXPathString("string(./name)", ctxt);
|
2012-05-14 09:06:42 +00:00
|
|
|
if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2013-05-22 12:05:21 +00:00
|
|
|
_("element 'name' is mandatory for RBD pool"));
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
2009-10-15 14:55:19 +00:00
|
|
|
|
|
|
|
if (options->formatFromString) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *format = NULL;
|
2019-01-31 13:20:02 +00:00
|
|
|
|
|
|
|
format = virXPathString("string(./format/@type)", ctxt);
|
2009-10-15 14:55:19 +00:00
|
|
|
if (format == NULL)
|
|
|
|
source->format = options->defaultFormat;
|
|
|
|
else
|
|
|
|
source->format = options->formatFromString(format);
|
|
|
|
|
|
|
|
if (source->format < 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-07-18 10:50:44 +00:00
|
|
|
_("unknown pool format type %s"), format);
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-28 13:34:50 +00:00
|
|
|
if ((n = virXPathNodeSet("./host", ctxt, &nodeset)) < 0)
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2012-04-25 10:43:09 +00:00
|
|
|
|
2013-09-25 09:22:42 +00:00
|
|
|
if (n) {
|
2020-10-07 19:14:47 +00:00
|
|
|
source->hosts = g_new0(virStoragePoolSourceHost, n);
|
2013-09-25 09:22:42 +00:00
|
|
|
source->nhost = n;
|
2010-11-12 13:23:55 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < source->nhost; i++) {
|
2019-02-12 12:04:42 +00:00
|
|
|
source->hosts[i].name = virXMLPropString(nodeset[i], "name");
|
|
|
|
if (!source->hosts[i].name) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool host name"));
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2012-04-25 10:43:09 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 15:01:55 +00:00
|
|
|
if (virXMLPropInt(nodeset[i], "port", 10, VIR_XML_PROP_NONE,
|
|
|
|
&source->hosts[i].port, 0) < 0)
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2012-04-25 10:43:09 +00:00
|
|
|
}
|
|
|
|
}
|
2010-11-12 13:23:55 +00:00
|
|
|
|
2012-05-09 10:48:46 +00:00
|
|
|
VIR_FREE(nodeset);
|
2018-08-07 11:31:31 +00:00
|
|
|
|
|
|
|
virStorageSourceInitiatorParseXML(ctxt, &source->initiator);
|
2009-10-15 14:55:19 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
nsource = virXPathNodeSet("./device", ctxt, &nodeset);
|
2011-05-12 19:45:22 +00:00
|
|
|
if (nsource < 0)
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2011-05-12 19:45:22 +00:00
|
|
|
|
2014-03-11 08:13:15 +00:00
|
|
|
for (i = 0; i < nsource; i++) {
|
|
|
|
virStoragePoolSourceDevice dev = { .path = NULL };
|
|
|
|
dev.path = virXMLPropString(nodeset[i], "path");
|
|
|
|
|
|
|
|
if (dev.path == NULL) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source device path"));
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 15:01:55 +00:00
|
|
|
if (virXMLPropTristateBool(nodeset[i], "part_separator",
|
|
|
|
VIR_XML_PROP_NONE,
|
|
|
|
&dev.part_separator) < 0) {
|
|
|
|
virStoragePoolSourceDeviceClear(&dev);
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2016-01-07 11:57:28 +00:00
|
|
|
}
|
|
|
|
|
2021-08-03 12:14:20 +00:00
|
|
|
VIR_APPEND_ELEMENT(source->devices, source->ndevice, dev);
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
|
|
|
|
2019-06-25 11:37:16 +00:00
|
|
|
sourcedir = virXPathString("string(./dir/@path)", ctxt);
|
|
|
|
if (sourcedir)
|
|
|
|
source->dir = virFileSanitizePath(sourcedir);
|
2013-11-19 23:26:05 +00:00
|
|
|
/* In gluster, a missing dir defaults to "/" */
|
2019-10-20 11:49:46 +00:00
|
|
|
if (!source->dir && pool_type == VIR_STORAGE_POOL_GLUSTER)
|
|
|
|
source->dir = g_strdup("/");
|
2013-03-25 16:43:36 +00:00
|
|
|
|
2017-03-10 13:18:48 +00:00
|
|
|
if ((adapternode = virXPathNode("./adapter", ctxt))) {
|
2017-02-28 12:38:12 +00:00
|
|
|
if (virStorageAdapterParseXML(&source->adapter, adapternode, ctxt) < 0)
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2017-03-10 13:18:48 +00:00
|
|
|
}
|
2009-10-15 14:55:19 +00:00
|
|
|
|
2014-06-26 12:18:09 +00:00
|
|
|
if ((authnode = virXPathNode("./auth", ctxt))) {
|
2018-03-06 13:17:59 +00:00
|
|
|
if (!(authdef = virStorageAuthDefParse(authnode, ctxt)))
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2014-06-26 12:18:09 +00:00
|
|
|
|
|
|
|
if (authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("storage pool missing auth type"));
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2014-06-26 12:18:09 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 11:43:01 +00:00
|
|
|
source->auth = g_steal_pointer(&authdef);
|
2014-06-26 12:18:09 +00:00
|
|
|
}
|
2012-05-14 09:06:42 +00:00
|
|
|
|
2019-01-11 00:23:27 +00:00
|
|
|
/* Option protocol version string (NFSvN) */
|
2022-06-23 15:17:06 +00:00
|
|
|
if ((source->protocolVer = virXPathString("string(./protocol/@ver)", ctxt))) {
|
2019-01-11 00:23:27 +00:00
|
|
|
if ((source->format != VIR_STORAGE_POOL_NETFS_NFS) &&
|
|
|
|
(source->format != VIR_STORAGE_POOL_NETFS_AUTO)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("storage pool protocol ver unsupported for "
|
|
|
|
"pool type '%s'"),
|
|
|
|
virStoragePoolFormatFileSystemNetTypeToString(source->format));
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2019-01-11 00:23:27 +00:00
|
|
|
}
|
2022-06-23 15:17:06 +00:00
|
|
|
|
|
|
|
if (strchr(source->protocolVer, ',')) {
|
|
|
|
virReportError(VIR_ERR_XML_DETAIL,
|
|
|
|
_("storage pool protocol ver '%s' must not contain ','"),
|
|
|
|
source->protocolVer);
|
2021-05-11 15:01:56 +00:00
|
|
|
return -1;
|
2019-01-11 00:23:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-17 17:44:27 +00:00
|
|
|
source->vendor = virXPathString("string(./vendor/@name)", ctxt);
|
|
|
|
source->product = virXPathString("string(./product/@name)", ctxt);
|
|
|
|
|
2021-05-11 15:01:56 +00:00
|
|
|
return 0;
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSource *
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseSourceString(const char *srcSpec,
|
2009-10-15 15:58:35 +00:00
|
|
|
int pool_type)
|
|
|
|
{
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(xmlDoc) doc = NULL;
|
|
|
|
g_autoptr(xmlXPathContext) xpath_ctxt = NULL;
|
|
|
|
g_autoptr(virStoragePoolSource) def = NULL;
|
2009-10-15 15:58:35 +00:00
|
|
|
|
2022-09-23 13:38:49 +00:00
|
|
|
if (!(doc = virXMLParse(NULL, srcSpec, _("(storage_source_specification)"),
|
|
|
|
"source", &xpath_ctxt, NULL, false)))
|
2019-09-16 11:16:36 +00:00
|
|
|
return NULL;
|
2009-10-15 15:58:35 +00:00
|
|
|
|
2020-10-07 19:14:47 +00:00
|
|
|
def = g_new0(virStoragePoolSource, 1);
|
2009-10-15 15:58:35 +00:00
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
|
2021-04-14 12:16:28 +00:00
|
|
|
xpath_ctxt->node) < 0)
|
2019-09-16 11:16:36 +00:00
|
|
|
return NULL;
|
2009-10-15 15:58:35 +00:00
|
|
|
|
2019-10-16 11:35:54 +00:00
|
|
|
return g_steal_pointer(&def);
|
2009-10-15 15:58:35 +00:00
|
|
|
}
|
2013-05-16 12:40:50 +00:00
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePerms *perms,
|
2015-04-27 20:48:05 +00:00
|
|
|
const char *permxpath)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2014-12-16 16:38:59 +00:00
|
|
|
long long val;
|
2020-07-28 19:47:48 +00:00
|
|
|
VIR_XPATH_NODE_AUTORESTORE(ctxt)
|
2009-03-12 20:15:32 +00:00
|
|
|
xmlNodePtr node;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *mode = NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
node = virXPathNode(permxpath, ctxt);
|
2009-03-12 20:15:32 +00:00
|
|
|
if (node == NULL) {
|
|
|
|
/* Set default values if there is not <permissions> element */
|
2015-04-27 20:48:05 +00:00
|
|
|
perms->mode = (mode_t) -1;
|
2013-02-22 16:41:32 +00:00
|
|
|
perms->uid = (uid_t) -1;
|
|
|
|
perms->gid = (gid_t) -1;
|
2009-03-12 20:15:32 +00:00
|
|
|
perms->label = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = node;
|
|
|
|
|
2015-04-27 20:48:05 +00:00
|
|
|
if ((mode = virXPathString("string(./mode)", ctxt))) {
|
2012-04-18 23:58:44 +00:00
|
|
|
int tmp;
|
|
|
|
|
|
|
|
if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed octal mode"));
|
2021-11-04 14:26:07 +00:00
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2012-04-18 23:58:44 +00:00
|
|
|
perms->mode = tmp;
|
2015-04-27 20:48:05 +00:00
|
|
|
} else {
|
|
|
|
perms->mode = (mode_t) -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
if (virXPathNode("./owner", ctxt) == NULL) {
|
2013-02-22 16:41:32 +00:00
|
|
|
perms->uid = (uid_t) -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
2015-05-05 15:58:12 +00:00
|
|
|
/* We previously could output -1, so continue to parse it */
|
2022-10-04 15:06:14 +00:00
|
|
|
if (virXPathLongLong("string(./owner)", ctxt, &val) < 0 ||
|
2013-05-22 12:05:22 +00:00
|
|
|
((uid_t)val != val &&
|
|
|
|
val != -1)) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed owner element"));
|
2021-11-04 14:26:07 +00:00
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2013-05-22 12:05:22 +00:00
|
|
|
|
|
|
|
perms->uid = val;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
if (virXPathNode("./group", ctxt) == NULL) {
|
2013-02-22 16:41:32 +00:00
|
|
|
perms->gid = (gid_t) -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
2015-05-05 15:58:12 +00:00
|
|
|
/* We previously could output -1, so continue to parse it */
|
2022-10-04 15:06:14 +00:00
|
|
|
if (virXPathLongLong("string(./group)", ctxt, &val) < 0 ||
|
2013-05-22 12:05:22 +00:00
|
|
|
((gid_t) val != val &&
|
|
|
|
val != -1)) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed group element"));
|
2021-11-04 14:26:07 +00:00
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2013-05-22 12:05:22 +00:00
|
|
|
perms->gid = val;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* NB, we're ignoring missing labels here - they'll simply inherit */
|
2010-02-04 21:52:34 +00:00
|
|
|
perms->label = virXPathString("string(./label)", ctxt);
|
2021-11-04 14:26:07 +00:00
|
|
|
return 0;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-10 12:06:22 +00:00
|
|
|
|
2019-03-19 13:42:17 +00:00
|
|
|
static int
|
|
|
|
virStoragePoolDefRefreshParse(xmlXPathContextPtr ctxt,
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDef *def)
|
2019-03-19 13:42:17 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
g_autofree virStoragePoolDefRefresh *refresh = NULL;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *allocation = NULL;
|
2019-03-19 13:42:17 +00:00
|
|
|
int tmp;
|
|
|
|
|
|
|
|
allocation = virXPathString("string(./refresh/volume/@allocation)", ctxt);
|
|
|
|
|
|
|
|
if (!allocation)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((tmp = virStorageVolDefRefreshAllocationTypeFromString(allocation)) < 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unknown storage pool volume refresh allocation type %s"),
|
|
|
|
allocation);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-10-07 19:14:47 +00:00
|
|
|
refresh = g_new0(virStoragePoolDefRefresh, 1);
|
2019-03-19 13:42:17 +00:00
|
|
|
|
|
|
|
refresh->volume.allocation = tmp;
|
2019-10-16 11:43:01 +00:00
|
|
|
def->refresh = g_steal_pointer(&refresh);
|
2019-03-19 13:42:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDefRefreshFormat(virBuffer *buf,
|
|
|
|
virStoragePoolDefRefresh *refresh)
|
2019-03-19 13:42:17 +00:00
|
|
|
{
|
|
|
|
if (!refresh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<refresh>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<volume allocation='%s'/>\n",
|
|
|
|
virStorageVolDefRefreshAllocationTypeToString(refresh->volume.allocation));
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</refresh>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-17 18:32:18 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDefParseFeatures(virStoragePoolDef *def,
|
2020-07-17 18:32:18 +00:00
|
|
|
xmlXPathContextPtr ctxt)
|
|
|
|
{
|
2022-01-20 12:58:49 +00:00
|
|
|
xmlNodePtr node = virXPathNode("./features/cow", ctxt);
|
|
|
|
virTristateBool val;
|
|
|
|
int rv;
|
2020-07-17 18:32:18 +00:00
|
|
|
|
2022-01-20 12:58:49 +00:00
|
|
|
if ((rv = virXMLPropTristateBool(node, "state",
|
|
|
|
VIR_XML_PROP_NONE,
|
|
|
|
&val)) < 0) {
|
|
|
|
return -1;
|
|
|
|
} else if (rv > 0) {
|
2020-07-17 18:32:18 +00:00
|
|
|
if (def->type != VIR_STORAGE_POOL_FS &&
|
|
|
|
def->type != VIR_STORAGE_POOL_DIR) {
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("cow feature may only be used for 'fs' and 'dir' pools"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
def->features.cow = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDef *
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolOptions *options;
|
2009-10-15 14:55:19 +00:00
|
|
|
xmlNodePtr source_node;
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virStoragePoolDef) def = NULL;
|
2021-05-11 15:01:57 +00:00
|
|
|
virStoragePoolType type;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *uuid = NULL;
|
|
|
|
g_autofree char *target_path = NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2020-10-07 19:14:47 +00:00
|
|
|
def = g_new0(virStoragePoolDef, 1);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2021-05-11 15:01:57 +00:00
|
|
|
if (virXMLPropEnum(ctxt->node, "type", virStoragePoolTypeFromString,
|
|
|
|
VIR_XML_PROP_REQUIRED, &type) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2013-05-31 13:07:28 +00:00
|
|
|
|
2021-05-11 15:01:57 +00:00
|
|
|
def->type = type;
|
2008-11-17 11:19:33 +00:00
|
|
|
|
2019-02-07 23:41:58 +00:00
|
|
|
if ((options = virStoragePoolOptionsForPoolType(def->type)) == NULL)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
source_node = virXPathNode("./source", ctxt);
|
2009-10-15 14:55:19 +00:00
|
|
|
if (source_node) {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (virStoragePoolDefParseSource(ctxt, &def->source, def->type,
|
2009-10-15 14:55:19 +00:00
|
|
|
source_node) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2017-03-27 17:01:56 +00:00
|
|
|
} else {
|
|
|
|
if (options->formatFromString)
|
2019-02-07 23:41:58 +00:00
|
|
|
def->source.format = options->defaultFormat;
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 23:41:58 +00:00
|
|
|
def->name = virXPathString("string(./name)", ctxt);
|
|
|
|
if (def->name == NULL &&
|
2019-10-20 11:49:46 +00:00
|
|
|
options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
|
|
|
|
def->name = g_strdup(def->source.name);
|
2019-01-31 13:20:02 +00:00
|
|
|
|
2019-02-07 23:41:58 +00:00
|
|
|
if (def->name == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing pool source name element"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 23:41:58 +00:00
|
|
|
if (strchr(def->name, '/')) {
|
2016-04-26 18:51:33 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2019-02-07 23:41:58 +00:00
|
|
|
_("name %s cannot contain '/'"), def->name);
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2016-04-26 18:51:33 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
uuid = virXPathString("string(./uuid)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (uuid == NULL) {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (virUUIDGenerate(def->uuid) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unable to generate uuid"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (virUUIDParse(uuid, def->uuid) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed uuid element"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-17 18:32:18 +00:00
|
|
|
if (virStoragePoolDefParseFeatures(def, ctxt) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (!def->source.nhost) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2012-07-18 10:50:44 +00:00
|
|
|
_("missing storage pool source host name"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (!def->source.dir) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source path"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-17 11:19:33 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (def->source.name == NULL) {
|
2008-09-02 14:15:42 +00:00
|
|
|
/* source name defaults to pool name */
|
2019-10-20 11:49:46 +00:00
|
|
|
def->source.name = g_strdup(def->name);
|
2008-09-02 14:15:42 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2017-03-10 12:06:22 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
|
2019-02-07 23:41:58 +00:00
|
|
|
(virStorageAdapterValidate(&def->source.adapter)) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-03-03 18:47:12 +00:00
|
|
|
/* If DEVICE is the only source type, then its required */
|
|
|
|
if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (!def->source.ndevice) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source device name"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2010-03-03 18:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
/* When we are working with a virtual disk we can skip the target
|
|
|
|
* path and permissions */
|
|
|
|
if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
|
2019-02-07 23:41:58 +00:00
|
|
|
if (def->type == VIR_STORAGE_POOL_LOGICAL) {
|
2019-10-22 13:26:14 +00:00
|
|
|
target_path = g_strdup_printf("/dev/%s", def->source.name);
|
2019-02-07 23:41:58 +00:00
|
|
|
} else if (def->type == VIR_STORAGE_POOL_ZFS) {
|
2019-10-22 13:26:14 +00:00
|
|
|
target_path = g_strdup_printf("/dev/zvol/%s", def->source.name);
|
2013-04-30 11:48:46 +00:00
|
|
|
} else {
|
|
|
|
target_path = virXPathString("string(./target/path)", ctxt);
|
|
|
|
if (!target_path) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool target path"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2013-04-30 11:48:46 +00:00
|
|
|
}
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
2019-02-07 23:41:58 +00:00
|
|
|
def->target.path = virFileSanitizePath(target_path);
|
|
|
|
if (!def->target.path)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2019-02-07 23:41:58 +00:00
|
|
|
if (virStorageDefParsePerms(ctxt, &def->target.perms,
|
2015-04-27 20:48:05 +00:00
|
|
|
"./target/permissions") < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2019-02-07 23:41:58 +00:00
|
|
|
if (def->type == VIR_STORAGE_POOL_ISCSI_DIRECT &&
|
|
|
|
!def->source.initiator.iqn) {
|
2018-07-31 08:44:21 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("missing initiator IQN"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2018-07-31 08:44:21 +00:00
|
|
|
}
|
|
|
|
|
2019-03-19 13:42:17 +00:00
|
|
|
if (virStoragePoolDefRefreshParse(ctxt, def) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2019-01-03 16:47:48 +00:00
|
|
|
/* Make a copy of all the callback pointers here for easier use,
|
|
|
|
* especially during the virStoragePoolSourceClear method */
|
2019-02-07 23:41:58 +00:00
|
|
|
def->ns = options->ns;
|
2019-08-20 20:12:55 +00:00
|
|
|
if (def->ns.parse) {
|
2019-08-20 22:18:55 +00:00
|
|
|
if (virXMLNamespaceRegister(ctxt, &def->ns) < 0)
|
|
|
|
return NULL;
|
2019-08-20 20:12:55 +00:00
|
|
|
if ((def->ns.parse)(ctxt, &def->namespaceData) < 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-01-03 16:47:48 +00:00
|
|
|
|
2019-10-17 08:10:10 +00:00
|
|
|
return g_steal_pointer(&def);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2022-09-22 15:08:16 +00:00
|
|
|
virStoragePoolDef *
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParse(const char *xmlStr,
|
2021-08-24 14:51:09 +00:00
|
|
|
const char *filename,
|
|
|
|
unsigned int flags)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2021-08-11 11:57:18 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2022-09-22 15:00:25 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2022-09-22 12:30:53 +00:00
|
|
|
bool validate = flags & VIR_STORAGE_POOL_DEFINE_VALIDATE;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-06-22 16:41:34 +00:00
|
|
|
|
2022-09-22 15:00:25 +00:00
|
|
|
if (!(xml = virXMLParse(filename, xmlStr, _("(storage_pool_definition)"),
|
|
|
|
"pool", &ctxt, "storagepool.rng", validate)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return virStoragePoolDefParseXML(ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2008-11-04 21:54:21 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSourceFormat(virBuffer *buf,
|
|
|
|
virStoragePoolOptions *options,
|
|
|
|
virStoragePoolSource *src)
|
2008-11-04 21:54:21 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i, j;
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAddLit(buf, "<source>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
2012-04-25 10:43:09 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
|
|
|
|
for (i = 0; i < src->nhost; i++) {
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<host name='%s'",
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
src->hosts[i].name);
|
2012-04-25 10:43:09 +00:00
|
|
|
if (src->hosts[i].port)
|
|
|
|
virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
2010-11-12 13:23:55 +00:00
|
|
|
}
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
|
2008-11-04 21:54:21 +00:00
|
|
|
src->ndevice) {
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < src->ndevice; i++) {
|
2016-03-17 11:29:23 +00:00
|
|
|
virBufferEscapeString(buf, "<device path='%s'",
|
|
|
|
src->devices[i].path);
|
|
|
|
if (src->devices[i].part_separator !=
|
2021-04-07 11:48:40 +00:00
|
|
|
VIR_TRISTATE_BOOL_ABSENT) {
|
2016-03-17 11:29:23 +00:00
|
|
|
virBufferAsprintf(buf, " part_separator='%s'",
|
|
|
|
virTristateBoolTypeToString(src->devices[i].part_separator));
|
|
|
|
}
|
2008-11-04 21:54:21 +00:00
|
|
|
if (src->devices[i].nfreeExtent) {
|
2016-03-17 11:29:23 +00:00
|
|
|
virBufferAddLit(buf, ">\n");
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, 2);
|
2013-05-16 12:40:50 +00:00
|
|
|
for (j = 0; j < src->devices[i].nfreeExtent; j++) {
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<freeExtent start='%llu' end='%llu'/>\n",
|
2008-11-04 21:54:21 +00:00
|
|
|
src->devices[i].freeExtents[j].start,
|
|
|
|
src->devices[i].freeExtents[j].end);
|
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</device>\n");
|
2013-05-16 12:40:50 +00:00
|
|
|
} else {
|
2016-01-07 11:57:28 +00:00
|
|
|
virBufferAddLit(buf, "/>\n");
|
2013-05-16 12:40:50 +00:00
|
|
|
}
|
2008-11-04 21:54:21 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-16 12:40:50 +00:00
|
|
|
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR)
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<dir path='%s'/>\n", src->dir);
|
2013-05-16 12:40:50 +00:00
|
|
|
|
2017-03-10 12:06:22 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
|
2017-02-28 12:38:12 +00:00
|
|
|
(src->adapter.type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST ||
|
|
|
|
src->adapter.type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST))
|
|
|
|
virStorageAdapterFormat(buf, &src->adapter);
|
2013-05-16 12:40:50 +00:00
|
|
|
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<name>%s</name>\n", src->name);
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2018-08-07 11:31:31 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN)
|
|
|
|
virStorageSourceInitiatorFormatXML(&src->initiator, buf);
|
2010-06-07 19:06:20 +00:00
|
|
|
|
2008-11-04 21:54:21 +00:00
|
|
|
if (options->formatToString) {
|
|
|
|
const char *format = (options->formatToString)(src->format);
|
|
|
|
if (!format) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown pool format number %d"),
|
|
|
|
src->format);
|
2008-11-04 21:54:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<format type='%s'/>\n", format);
|
2008-11-04 21:54:21 +00:00
|
|
|
}
|
|
|
|
|
2018-02-20 11:24:36 +00:00
|
|
|
if (src->auth)
|
|
|
|
virStorageAuthDefFormat(buf, src->auth);
|
2012-05-14 09:06:42 +00:00
|
|
|
|
2022-06-23 15:17:06 +00:00
|
|
|
virBufferEscapeString(buf, "<protocol ver='%s'/>\n", src->protocolVer);
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<vendor name='%s'/>\n", src->vendor);
|
|
|
|
virBufferEscapeString(buf, "<product name='%s'/>\n", src->product);
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</source>\n");
|
2008-11-04 21:54:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2020-07-17 18:32:18 +00:00
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDefFormatFeatures(virBuffer *buf,
|
|
|
|
virStoragePoolDef *def)
|
2020-07-17 18:32:18 +00:00
|
|
|
{
|
|
|
|
if (def->features.cow == VIR_TRISTATE_BOOL_ABSENT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<features>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
if (def->features.cow != VIR_TRISTATE_BOOL_ABSENT)
|
|
|
|
virBufferAsprintf(buf, "<cow state='%s'/>\n",
|
|
|
|
virTristateBoolTypeToString(def->features.cow));
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</features>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDefFormatBuf(virBuffer *buf,
|
|
|
|
virStoragePoolDef *def)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolOptions *options;
|
2008-02-20 15:34:52 +00:00
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
2015-03-26 15:44:38 +00:00
|
|
|
const char *type;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStoragePoolOptionsForPoolType(def->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options == NULL)
|
2015-03-26 15:44:38 +00:00
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
type = virStoragePoolTypeToString(def->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (!type) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected pool type"));
|
2015-03-26 15:44:38 +00:00
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2019-01-03 16:47:48 +00:00
|
|
|
virBufferAsprintf(buf, "<pool type='%s'", type);
|
2019-08-20 22:08:33 +00:00
|
|
|
if (def->namespaceData && def->ns.format)
|
|
|
|
virXMLNamespaceFormatNS(buf, &def->ns);
|
2019-01-03 16:47:48 +00:00
|
|
|
virBufferAddLit(buf, ">\n");
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuid);
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuid);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<capacity unit='bytes'>%llu</capacity>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->capacity);
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<allocation unit='bytes'>%llu</allocation>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->allocation);
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<available unit='bytes'>%llu</available>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->available);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2020-07-17 18:32:18 +00:00
|
|
|
virStoragePoolDefFormatFeatures(buf, def);
|
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
if (virStoragePoolSourceFormat(buf, options, &def->source) < 0)
|
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2018-07-31 08:44:21 +00:00
|
|
|
/* RBD, Sheepdog, Gluster and Iscsi-direct devices are not local block devs nor
|
2013-11-19 23:26:05 +00:00
|
|
|
* files, so they don't have a target */
|
2013-05-16 12:40:50 +00:00
|
|
|
if (def->type != VIR_STORAGE_POOL_RBD &&
|
2013-11-19 23:26:05 +00:00
|
|
|
def->type != VIR_STORAGE_POOL_SHEEPDOG &&
|
2018-07-31 08:44:21 +00:00
|
|
|
def->type != VIR_STORAGE_POOL_GLUSTER &&
|
|
|
|
def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) {
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAddLit(buf, "<target>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferEscapeString(buf, "<path>%s</path>\n", def->target.path);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-05-21 19:15:24 +00:00
|
|
|
if (def->target.perms.mode != (mode_t) -1 ||
|
|
|
|
def->target.perms.uid != (uid_t) -1 ||
|
|
|
|
def->target.perms.gid != (gid_t) -1 ||
|
|
|
|
def->target.perms.label) {
|
|
|
|
virBufferAddLit(buf, "<permissions>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
if (def->target.perms.mode != (mode_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<mode>0%o</mode>\n",
|
|
|
|
def->target.perms.mode);
|
|
|
|
if (def->target.perms.uid != (uid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<owner>%d</owner>\n",
|
|
|
|
(int) def->target.perms.uid);
|
|
|
|
if (def->target.perms.gid != (gid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<group>%d</group>\n",
|
|
|
|
(int) def->target.perms.gid);
|
|
|
|
virBufferEscapeString(buf, "<label>%s</label>\n",
|
|
|
|
def->target.perms.label);
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</permissions>\n");
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</target>\n");
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
2019-01-03 16:47:48 +00:00
|
|
|
|
2019-03-19 13:42:17 +00:00
|
|
|
virStoragePoolDefRefreshFormat(buf, def->refresh);
|
|
|
|
|
2019-01-03 16:47:48 +00:00
|
|
|
if (def->namespaceData && def->ns.format) {
|
|
|
|
if ((def->ns.format)(buf, def->namespaceData) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</pool>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
char *
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDefFormat(virStoragePoolDef *def)
|
2015-03-26 15:44:38 +00:00
|
|
|
{
|
2020-07-03 02:19:01 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2015-03-26 15:44:38 +00:00
|
|
|
|
|
|
|
if (virStoragePoolDefFormatBuf(&buf, def) < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageSize(const char *unit,
|
2008-02-20 15:34:52 +00:00
|
|
|
const char *val,
|
2012-03-05 21:06:33 +00:00
|
|
|
unsigned long long *ret)
|
|
|
|
{
|
2017-03-27 12:33:16 +00:00
|
|
|
if (virStrToLong_ullp(val, NULL, 10, ret) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed capacity element"));
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-03-05 21:06:33 +00:00
|
|
|
/* off_t is signed, so you cannot create a file larger than 2**63
|
|
|
|
* bytes in the first place. */
|
|
|
|
if (virScaleInteger(ret, unit, 1, LLONG_MAX) < 0)
|
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2020-12-07 12:34:18 +00:00
|
|
|
static int
|
|
|
|
virStorageCheckCompat(const char *compat)
|
|
|
|
{
|
|
|
|
unsigned int result;
|
|
|
|
g_auto(GStrv) version = NULL;
|
|
|
|
|
|
|
|
if (!compat)
|
|
|
|
return 0;
|
|
|
|
|
2021-02-05 17:35:07 +00:00
|
|
|
version = g_strsplit(compat, ".", 2);
|
2020-12-07 12:34:18 +00:00
|
|
|
if (!version || !version[1] ||
|
|
|
|
virStrToLong_ui(version[0], NULL, 10, &result) < 0 ||
|
|
|
|
virStrToLong_ui(version[1], NULL, 10, &result) < 0) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("forbidden characters in 'compat' attribute"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-09-22 15:17:21 +00:00
|
|
|
virStorageVolDef *
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolDefParseXML(virStoragePoolDef *pool,
|
2015-02-05 15:20:17 +00:00
|
|
|
xmlXPathContextPtr ctxt,
|
|
|
|
unsigned int flags)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolOptions *options;
|
2009-07-20 22:28:11 +00:00
|
|
|
xmlNodePtr node;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
|
|
|
int n;
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virStorageVolDef) def = NULL;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *type = NULL;
|
|
|
|
g_autofree char *allocation = NULL;
|
|
|
|
g_autofree char *capacity = NULL;
|
|
|
|
g_autofree char *unit = NULL;
|
|
|
|
g_autofree char *backingStore = NULL;
|
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-02-17 15:55:59 +00:00
|
|
|
virCheckFlags(VIR_VOL_XML_PARSE_NO_CAPACITY |
|
|
|
|
VIR_VOL_XML_PARSE_OPT_CAPACITY, NULL);
|
2015-02-05 15:20:17 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStorageVolOptionsForPoolType(pool->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2020-10-07 19:14:47 +00:00
|
|
|
def = g_new0(virStorageVolDef, 1);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.type = VIR_STORAGE_TYPE_FILE;
|
2017-10-12 18:31:33 +00:00
|
|
|
|
2019-02-07 22:43:27 +00:00
|
|
|
def->name = virXPathString("string(./name)", ctxt);
|
|
|
|
if (def->name == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing volume name element"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
/* Normally generated by pool refresh, but useful for unit tests */
|
2019-02-07 22:43:27 +00:00
|
|
|
def->key = virXPathString("string(./key)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-11-19 20:14:54 +00:00
|
|
|
/* Technically overridden by pool refresh, but useful for unit tests */
|
|
|
|
type = virXPathString("string(./@type)", ctxt);
|
|
|
|
if (type) {
|
2019-02-07 22:43:27 +00:00
|
|
|
if ((def->type = virStorageVolTypeFromString(type)) < 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2013-11-19 20:14:54 +00:00
|
|
|
_("unknown volume type '%s'"), type);
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2013-11-19 20:14:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-10 14:10:05 +00:00
|
|
|
if ((backingStore = virXPathString("string(./backingStore/path)", ctxt))) {
|
2020-09-22 09:04:17 +00:00
|
|
|
def->target.backingStore = virStorageSourceNew();
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.backingStore->type = VIR_STORAGE_TYPE_FILE;
|
2020-09-22 09:06:25 +00:00
|
|
|
def->target.backingStore->path = g_steal_pointer(&backingStore);
|
2015-02-10 14:10:05 +00:00
|
|
|
|
|
|
|
if (options->formatFromString) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *format = NULL;
|
2019-01-31 13:20:02 +00:00
|
|
|
|
|
|
|
format = virXPathString("string(./backingStore/format/@type)", ctxt);
|
2015-02-10 14:10:05 +00:00
|
|
|
if (format == NULL)
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.backingStore->format = options->defaultFormat;
|
2015-02-10 14:10:05 +00:00
|
|
|
else
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.backingStore->format = (options->formatFromString)(format);
|
2015-02-10 14:10:05 +00:00
|
|
|
|
2019-02-07 22:43:27 +00:00
|
|
|
if (def->target.backingStore->format < 0) {
|
2015-02-10 14:10:05 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unknown volume format type %s"), format);
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2015-02-10 14:10:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-07 19:14:47 +00:00
|
|
|
def->target.backingStore->perms = g_new0(virStoragePerms, 1);
|
2019-02-07 22:43:27 +00:00
|
|
|
if (virStorageDefParsePerms(ctxt, def->target.backingStore->perms,
|
2015-04-27 20:48:05 +00:00
|
|
|
"./backingStore/permissions") < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2015-02-10 14:10:05 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
capacity = virXPathString("string(./capacity)", ctxt);
|
|
|
|
unit = virXPathString("string(./capacity/@unit)", ctxt);
|
2015-02-17 15:47:04 +00:00
|
|
|
if (capacity) {
|
2019-02-07 22:43:27 +00:00
|
|
|
if (virStorageSize(unit, capacity, &def->target.capacity) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2015-02-17 15:55:59 +00:00
|
|
|
} else if (!(flags & VIR_VOL_XML_PARSE_NO_CAPACITY) &&
|
2017-10-12 17:27:40 +00:00
|
|
|
!((flags & VIR_VOL_XML_PARSE_OPT_CAPACITY) &&
|
2019-02-07 22:43:27 +00:00
|
|
|
virStorageSourceHasBacking(&def->target))) {
|
2015-02-17 15:47:04 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s", _("missing capacity element"));
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(unit);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
allocation = virXPathString("string(./allocation)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (allocation) {
|
2010-02-04 21:52:34 +00:00
|
|
|
unit = virXPathString("string(./allocation/@unit)", ctxt);
|
2019-02-07 22:43:27 +00:00
|
|
|
if (virStorageSize(unit, allocation, &def->target.allocation) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.has_allocation = true;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.allocation = def->target.capacity;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.path = virXPathString("string(./target/path)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options->formatFromString) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *format = NULL;
|
2019-01-31 13:20:02 +00:00
|
|
|
|
|
|
|
format = virXPathString("string(./target/format/@type)", ctxt);
|
2008-12-04 15:22:04 +00:00
|
|
|
if (format == NULL)
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.format = options->defaultFormat;
|
2008-12-04 15:22:04 +00:00
|
|
|
else
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.format = (options->formatFromString)(format);
|
2008-12-04 15:22:04 +00:00
|
|
|
|
2019-02-07 22:43:27 +00:00
|
|
|
if (def->target.format < 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-07-18 10:50:44 +00:00
|
|
|
_("unknown volume format type %s"), format);
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-07 19:14:47 +00:00
|
|
|
def->target.perms = g_new0(virStoragePerms, 1);
|
2019-02-07 22:43:27 +00:00
|
|
|
if (virStorageDefParsePerms(ctxt, def->target.perms,
|
2015-04-27 20:48:05 +00:00
|
|
|
"./target/permissions") < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
node = virXPathNode("./target/encryption", ctxt);
|
2009-07-20 22:28:11 +00:00
|
|
|
if (node != NULL) {
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.encryption = virStorageEncryptionParseNode(node, ctxt);
|
|
|
|
if (def->target.encryption == NULL)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2009-07-20 22:28:11 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.compat = virXPathString("string(./target/compat)", ctxt);
|
2020-12-07 12:34:18 +00:00
|
|
|
if (virStorageCheckCompat(def->target.compat) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2013-05-16 10:38:26 +00:00
|
|
|
|
2014-07-15 08:49:46 +00:00
|
|
|
if (virXPathNode("./target/nocow", ctxt))
|
2019-02-07 22:43:27 +00:00
|
|
|
def->target.nocow = true;
|
2014-07-15 08:49:46 +00:00
|
|
|
|
2021-05-12 15:43:36 +00:00
|
|
|
if (virParseScaledValue("./target/clusterSize",
|
|
|
|
"./target/clusterSize/@unit",
|
|
|
|
ctxt, &def->target.clusterSize,
|
|
|
|
1, ULLONG_MAX, false) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-04-09 12:02:53 +00:00
|
|
|
if (virXPathNode("./target/features", ctxt)) {
|
2013-05-16 10:38:26 +00:00
|
|
|
if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2013-05-16 10:38:26 +00:00
|
|
|
|
2019-10-18 13:08:21 +00:00
|
|
|
if (!def->target.compat)
|
|
|
|
def->target.compat = g_strdup("1.1");
|
2013-05-16 10:38:26 +00:00
|
|
|
|
2020-10-01 15:42:11 +00:00
|
|
|
def->target.features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST);
|
2013-05-16 10:38:26 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2015-04-09 12:02:53 +00:00
|
|
|
int f = virStorageFileFeatureTypeFromString((const char*)nodes[i]->name);
|
2013-05-16 10:38:26 +00:00
|
|
|
|
|
|
|
if (f < 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported feature %s"),
|
2013-05-16 10:38:26 +00:00
|
|
|
(const char*)nodes[i]->name);
|
2019-01-31 13:20:02 +00:00
|
|
|
return NULL;
|
2013-05-16 10:38:26 +00:00
|
|
|
}
|
2019-02-07 22:43:27 +00:00
|
|
|
ignore_value(virBitmapSetBit(def->target.features, f));
|
2013-05-16 10:38:26 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2019-10-17 08:10:10 +00:00
|
|
|
return g_steal_pointer(&def);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2022-09-22 15:22:55 +00:00
|
|
|
virStorageVolDef *
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolDefParse(virStoragePoolDef *pool,
|
2008-02-20 15:34:52 +00:00
|
|
|
const char *xmlStr,
|
2015-02-05 15:20:17 +00:00
|
|
|
const char *filename,
|
|
|
|
unsigned int flags)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2021-08-11 11:57:18 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2022-09-22 15:17:21 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2022-10-18 11:47:31 +00:00
|
|
|
bool validate = flags & VIR_VOL_XML_PARSE_VALIDATE;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2022-09-22 15:17:21 +00:00
|
|
|
if (!(xml = virXMLParse(filename, xmlStr, _("(storage_volume_definition)"),
|
2022-10-18 11:47:31 +00:00
|
|
|
"volume", &ctxt, "storagevol.rng", validate)))
|
2022-09-22 15:17:21 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2022-09-22 15:17:21 +00:00
|
|
|
return virStorageVolDefParseXML(pool, ctxt, flags);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2012-07-25 07:43:37 +00:00
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolTimestampFormat(virBuffer *buf, const char *name,
|
2012-07-25 07:43:37 +00:00
|
|
|
struct timespec *ts)
|
|
|
|
{
|
|
|
|
if (ts->tv_nsec < 0)
|
|
|
|
return;
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<%s>%llu", name,
|
2012-07-25 07:43:37 +00:00
|
|
|
(unsigned long long) ts->tv_sec);
|
|
|
|
if (ts->tv_nsec)
|
|
|
|
virBufferAsprintf(buf, ".%09ld", ts->tv_nsec);
|
|
|
|
virBufferAsprintf(buf, "</%s>\n", name);
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolTargetDefFormat(virStorageVolOptions *options,
|
|
|
|
virBuffer *buf,
|
|
|
|
virStorageSource *def,
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
const char *type)
|
|
|
|
{
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<%s>\n", type);
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<path>%s</path>\n", def->path);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
|
|
|
if (options->formatToString) {
|
|
|
|
const char *format = (options->formatToString)(def->format);
|
|
|
|
if (!format) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown volume format number %d"),
|
|
|
|
def->format);
|
2009-01-27 18:30:03 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<format type='%s'/>\n", format);
|
2009-01-27 18:30:03 +00:00
|
|
|
}
|
|
|
|
|
2015-05-21 19:15:24 +00:00
|
|
|
if (def->perms &&
|
|
|
|
(def->perms->mode != (mode_t) -1 ||
|
|
|
|
def->perms->uid != (uid_t) -1 ||
|
|
|
|
def->perms->gid != (gid_t) -1 ||
|
|
|
|
def->perms->label)) {
|
2014-07-11 16:13:34 +00:00
|
|
|
virBufferAddLit(buf, "<permissions>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2014-03-06 14:57:47 +00:00
|
|
|
|
2015-04-27 20:48:05 +00:00
|
|
|
if (def->perms->mode != (mode_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<mode>0%o</mode>\n",
|
|
|
|
def->perms->mode);
|
2015-05-05 15:58:12 +00:00
|
|
|
if (def->perms->uid != (uid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<owner>%d</owner>\n",
|
|
|
|
(int) def->perms->uid);
|
|
|
|
if (def->perms->gid != (gid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<group>%d</group>\n",
|
|
|
|
(int) def->perms->gid);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2014-07-11 16:13:34 +00:00
|
|
|
virBufferEscapeString(buf, "<label>%s</label>\n",
|
|
|
|
def->perms->label);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2014-07-11 16:13:34 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</permissions>\n");
|
|
|
|
}
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2012-07-25 07:43:37 +00:00
|
|
|
if (def->timestamps) {
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAddLit(buf, "<timestamps>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2012-07-25 07:43:37 +00:00
|
|
|
virStorageVolTimestampFormat(buf, "atime", &def->timestamps->atime);
|
|
|
|
virStorageVolTimestampFormat(buf, "mtime", &def->timestamps->mtime);
|
|
|
|
virStorageVolTimestampFormat(buf, "ctime", &def->timestamps->ctime);
|
|
|
|
virStorageVolTimestampFormat(buf, "btime", &def->timestamps->btime);
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</timestamps>\n");
|
2012-07-25 07:43:37 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
if (def->encryption &&
|
|
|
|
virStorageEncryptionFormat(buf, def->encryption) < 0)
|
2011-09-22 18:16:26 +00:00
|
|
|
return -1;
|
2009-07-20 22:28:11 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<compat>%s</compat>\n", def->compat);
|
2013-05-16 10:38:26 +00:00
|
|
|
|
2021-05-12 15:43:36 +00:00
|
|
|
if (def->clusterSize > 0) {
|
|
|
|
virBufferAsprintf(buf, "<clusterSize unit='B'>%llu</clusterSize>\n",
|
|
|
|
def->clusterSize);
|
|
|
|
}
|
|
|
|
|
2015-04-09 12:02:53 +00:00
|
|
|
if (def->features) {
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-05-16 10:38:26 +00:00
|
|
|
bool empty = virBitmapIsAllClear(def->features);
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
if (empty) {
|
|
|
|
virBufferAddLit(buf, "<features/>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "<features>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
}
|
2013-05-16 10:38:26 +00:00
|
|
|
|
|
|
|
for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
|
2015-03-11 15:41:57 +00:00
|
|
|
if (virBitmapIsBitSet(def->features, i))
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<%s/>\n",
|
2015-04-09 12:02:53 +00:00
|
|
|
virStorageFileFeatureTypeToString(i));
|
2013-05-16 10:38:26 +00:00
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
if (!empty) {
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</features>\n");
|
|
|
|
}
|
2013-05-16 10:38:26 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAsprintf(buf, "</%s>\n", type);
|
2009-01-27 18:30:03 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2021-02-25 13:03:15 +00:00
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolDefFormatSourceExtents(virBuffer *buf,
|
|
|
|
virStorageVolDef *def)
|
2021-02-25 13:03:15 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
const char *thispath = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < def->source.nextent; i++) {
|
|
|
|
if (thispath == NULL ||
|
|
|
|
STRNEQ(thispath, def->source.extents[i].path)) {
|
|
|
|
if (thispath != NULL)
|
|
|
|
virBufferAddLit(buf, "</device>\n");
|
|
|
|
|
|
|
|
virBufferEscapeString(buf, "<device path='%s'>\n",
|
|
|
|
def->source.extents[i].path);
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<extent start='%llu' end='%llu'/>\n",
|
|
|
|
def->source.extents[i].start,
|
|
|
|
def->source.extents[i].end);
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
thispath = def->source.extents[i].path;
|
|
|
|
}
|
|
|
|
if (thispath != NULL)
|
|
|
|
virBufferAddLit(buf, "</device>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
char *
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolDefFormat(virStoragePoolDef *pool,
|
|
|
|
virStorageVolDef *def)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStorageVolOptions *options;
|
2020-07-03 02:19:01 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2021-02-25 13:11:05 +00:00
|
|
|
g_auto(virBuffer) sourceChildBuf = VIR_BUFFER_INITIALIZER;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStorageVolOptionsForPoolType(pool->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2013-11-19 20:14:54 +00:00
|
|
|
virBufferAsprintf(&buf, "<volume type='%s'>\n",
|
|
|
|
virStorageVolTypeToString(def->type));
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
|
|
|
|
virBufferEscapeString(&buf, "<name>%s</name>\n", def->name);
|
|
|
|
virBufferEscapeString(&buf, "<key>%s</key>\n", def->key);
|
2021-02-25 13:11:05 +00:00
|
|
|
|
|
|
|
virBufferSetIndent(&sourceChildBuf, virBufferGetIndent(&buf) + 2);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2021-02-25 13:03:15 +00:00
|
|
|
if (def->source.nextent)
|
2021-02-25 13:11:05 +00:00
|
|
|
virStorageVolDefFormatSourceExtents(&sourceChildBuf, def);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2021-02-25 13:11:05 +00:00
|
|
|
virXMLFormatElement(&buf, "source", NULL, &sourceChildBuf);
|
2014-03-06 14:57:47 +00:00
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "<capacity unit='bytes'>%llu</capacity>\n",
|
conf: track sizes directly in source struct
One of the features of qcow2 is that a wrapper file can have
more capacity than its backing file from the guest's perspective;
what's more, sparse files make tracking allocation of both
the active and backing file worthwhile. As such, it makes
more sense to show allocation numbers for each file in a chain,
and not just the top-level file. This sets up the fields for
the tracking, although it does not modify XML to display any
new information.
* src/util/virstoragefile.h (_virStorageSource): Add fields.
* src/conf/storage_conf.h (_virStorageVolDef): Drop redundant
fields.
* src/storage/storage_backend.c (virStorageBackendCreateBlockFrom)
(createRawFile, virStorageBackendCreateQemuImgCmd)
(virStorageBackendCreateQcowCreate): Update clients.
* src/storage/storage_driver.c (storageVolDelete)
(storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize)
(storageVolWipeInternal, storageVolGetInfo): Likewise.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget)
(virStorageBackendFileSystemRefresh)
(virStorageBackendFileSystemVolResize)
(virStorageBackendFileSystemVolRefresh): Likewise.
* src/storage/storage_backend_logical.c
(virStorageBackendLogicalMakeVol)
(virStorageBackendLogicalCreateVol): Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSINewLun): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathNewVol): Likewise.
* src/storage/storage_backend_rbd.c
(volStorageBackendRBDRefreshVolInfo)
(virStorageBackendRBDCreateImage): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol): Likewise.
* src/storage/storage_backend_sheepdog.c
(virStorageBackendSheepdogBuildVol)
(virStorageBackendSheepdogParseVdiList): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageBackendGlusterRefreshVol): Likewise.
* src/conf/storage_conf.c (virStorageVolDefFormat)
(virStorageVolDefParseXML): Likewise.
* src/test/test_driver.c (testOpenVolumesForPool)
(testStorageVolCreateXML, testStorageVolCreateXMLFrom)
(testStorageVolDelete, testStorageVolGetInfo): Likewise.
* src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc):
Likewise.
* src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc)
(esxStorageVolCreateXML): Likewise.
* src/parallels/parallels_driver.c (parallelsAddHddByVolume):
Likewise.
* src/parallels/parallels_storage.c (parallelsDiskDescParseNode)
(parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom)
(parallelsStorageVolDefRemove, parallelsStorageVolGetInfo):
Likewise.
* src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML)
(vboxStorageVolGetXMLDesc): Likewise.
* tests/storagebackendsheepdogtest.c (test_vdi_list_parser):
Likewise.
* src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
|
|
|
def->target.capacity);
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(&buf, "<allocation unit='bytes'>%llu</allocation>\n",
|
conf: track sizes directly in source struct
One of the features of qcow2 is that a wrapper file can have
more capacity than its backing file from the guest's perspective;
what's more, sparse files make tracking allocation of both
the active and backing file worthwhile. As such, it makes
more sense to show allocation numbers for each file in a chain,
and not just the top-level file. This sets up the fields for
the tracking, although it does not modify XML to display any
new information.
* src/util/virstoragefile.h (_virStorageSource): Add fields.
* src/conf/storage_conf.h (_virStorageVolDef): Drop redundant
fields.
* src/storage/storage_backend.c (virStorageBackendCreateBlockFrom)
(createRawFile, virStorageBackendCreateQemuImgCmd)
(virStorageBackendCreateQcowCreate): Update clients.
* src/storage/storage_driver.c (storageVolDelete)
(storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize)
(storageVolWipeInternal, storageVolGetInfo): Likewise.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget)
(virStorageBackendFileSystemRefresh)
(virStorageBackendFileSystemVolResize)
(virStorageBackendFileSystemVolRefresh): Likewise.
* src/storage/storage_backend_logical.c
(virStorageBackendLogicalMakeVol)
(virStorageBackendLogicalCreateVol): Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSINewLun): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathNewVol): Likewise.
* src/storage/storage_backend_rbd.c
(volStorageBackendRBDRefreshVolInfo)
(virStorageBackendRBDCreateImage): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol): Likewise.
* src/storage/storage_backend_sheepdog.c
(virStorageBackendSheepdogBuildVol)
(virStorageBackendSheepdogParseVdiList): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageBackendGlusterRefreshVol): Likewise.
* src/conf/storage_conf.c (virStorageVolDefFormat)
(virStorageVolDefParseXML): Likewise.
* src/test/test_driver.c (testOpenVolumesForPool)
(testStorageVolCreateXML, testStorageVolCreateXMLFrom)
(testStorageVolDelete, testStorageVolGetInfo): Likewise.
* src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc):
Likewise.
* src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc)
(esxStorageVolCreateXML): Likewise.
* src/parallels/parallels_driver.c (parallelsAddHddByVolume):
Likewise.
* src/parallels/parallels_storage.c (parallelsDiskDescParseNode)
(parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom)
(parallelsStorageVolDefRemove, parallelsStorageVolGetInfo):
Likewise.
* src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML)
(vboxStorageVolGetXMLDesc): Likewise.
* tests/storagebackendsheepdogtest.c (test_vdi_list_parser):
Likewise.
* src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
|
|
|
def->target.allocation);
|
2016-12-13 15:56:21 +00:00
|
|
|
/* NB: Display only - since virStorageVolInfo is limited to just
|
|
|
|
* 'capacity' and 'allocation' on output. Since we don't read this
|
|
|
|
* in, be sure it was filled in before printing */
|
|
|
|
if (def->target.physical)
|
|
|
|
virBufferAsprintf(&buf, "<physical unit='bytes'>%llu</physical>\n",
|
|
|
|
def->target.physical);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStorageVolTargetDefFormat(options, &buf,
|
2009-01-27 18:30:03 +00:00
|
|
|
&def->target, "target") < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2017-10-12 17:27:40 +00:00
|
|
|
if (virStorageSourceHasBacking(&def->target) &&
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolTargetDefFormat(options, &buf,
|
2014-07-14 13:19:49 +00:00
|
|
|
def->target.backingStore,
|
|
|
|
"backingStore") < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return NULL;
|
2008-04-28 15:14:59 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
2013-11-19 22:21:40 +00:00
|
|
|
virBufferAddLit(&buf, "</volume>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
static int
|
|
|
|
virStoragePoolSaveXML(const char *path,
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDef *def,
|
2017-03-07 20:28:27 +00:00
|
|
|
const char *xml)
|
2015-03-26 15:49:20 +00:00
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
2019-10-17 08:10:10 +00:00
|
|
|
return virXMLSaveFile(path,
|
|
|
|
virXMLPickShellSafeComment(def->name, uuidstr),
|
|
|
|
"pool-edit", xml);
|
2015-03-26 15:49:20 +00:00
|
|
|
}
|
2015-04-02 14:41:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virStoragePoolSaveState(const char *stateFile,
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDef *def)
|
2015-04-02 14:41:51 +00:00
|
|
|
{
|
2020-07-03 02:19:01 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2015-04-02 14:41:51 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<poolstate>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
|
|
|
|
if (virStoragePoolDefFormatBuf(&buf, def) < 0)
|
2019-01-31 13:20:02 +00:00
|
|
|
return -1;
|
2015-04-02 14:41:51 +00:00
|
|
|
|
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</poolstate>\n");
|
|
|
|
|
|
|
|
if (!(xml = virBufferContentAndReset(&buf)))
|
2019-01-31 13:20:02 +00:00
|
|
|
return -1;
|
2015-04-02 14:41:51 +00:00
|
|
|
|
|
|
|
if (virStoragePoolSaveXML(stateFile, def, xml))
|
2019-01-31 13:20:02 +00:00
|
|
|
return -1;
|
2015-04-02 14:41:51 +00:00
|
|
|
|
2019-01-31 13:20:02 +00:00
|
|
|
return 0;
|
2015-04-02 14:41:51 +00:00
|
|
|
}
|
2015-03-26 15:49:20 +00:00
|
|
|
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
int
|
2014-11-10 17:23:46 +00:00
|
|
|
virStoragePoolSaveConfig(const char *configFile,
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolDef *def)
|
2011-10-27 16:55:47 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-11-10 17:23:46 +00:00
|
|
|
if (!(xml = virStoragePoolDefFormat(def))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to generate XML"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-01-31 13:20:02 +00:00
|
|
|
return virStoragePoolSaveXML(configFile, def, xml);
|
2014-11-10 17:23:46 +00:00
|
|
|
}
|
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSource *
|
|
|
|
virStoragePoolSourceListNewSource(virStoragePoolSourceList *list)
|
2009-10-15 15:41:53 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSource *source;
|
2009-10-15 15:41:53 +00:00
|
|
|
|
2021-03-19 23:37:05 +00:00
|
|
|
VIR_REALLOC_N(list->sources, list->nsources + 1);
|
2009-10-15 15:41:53 +00:00
|
|
|
|
|
|
|
source = &list->sources[list->nsources++];
|
|
|
|
memset(source, 0, sizeof(*source));
|
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:28:27 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
char *
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolSourceListFormat(virStoragePoolSourceList *def)
|
2008-10-23 11:39:53 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virStoragePoolOptions *options;
|
2020-07-03 02:19:01 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2008-11-04 21:54:21 +00:00
|
|
|
const char *type;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStoragePoolOptionsForPoolType(def->type);
|
2008-11-04 21:54:21 +00:00
|
|
|
if (options == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
type = virStoragePoolTypeToString(def->type);
|
2008-11-04 21:54:21 +00:00
|
|
|
if (!type) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected pool type"));
|
2020-07-03 03:19:26 +00:00
|
|
|
return NULL;
|
2008-11-04 21:54:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<sources>\n");
|
2014-03-26 18:16:48 +00:00
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2014-11-13 14:23:27 +00:00
|
|
|
for (i = 0; i < def->nsources; i++)
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2014-03-26 18:16:48 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
2008-11-04 21:54:21 +00:00
|
|
|
virBufferAddLit(&buf, "</sources>\n");
|
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
2021-06-16 08:04:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virStoragePoolSourceListFree(virStoragePoolSourceList *list)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!list)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < list->nsources; i++)
|
|
|
|
virStoragePoolSourceClear(&list->sources[i]);
|
|
|
|
|
|
|
|
g_free(list->sources);
|
|
|
|
g_free(list);
|
|
|
|
}
|