storage_conf.c 87.4 KB
Newer Older
1 2 3
/*
 * storage_conf.c: config handling for storage driver
 *
4
 * Copyright (C) 2006-2016 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>

36
#include "virerror.h"
37
#include "datatypes.h"
38
#include "node_device_conf.h"
39
#include "storage_conf.h"
40
#include "virstoragefile.h"
41

42
#include "virxml.h"
43
#include "viruuid.h"
44
#include "virbuffer.h"
45
#include "viralloc.h"
E
Eric Blake 已提交
46
#include "virfile.h"
47
#include "virscsihost.h"
48
#include "virstring.h"
49
#include "virlog.h"
50
#include "virvhba.h"
51

52 53
#define VIR_FROM_THIS VIR_FROM_STORAGE

54 55
VIR_LOG_INIT("conf.storage_conf");

56 57
VIR_ENUM_IMPL(virStorageVol,
              VIR_STORAGE_VOL_LAST,
O
Olga Krishtal 已提交
58 59
              "file", "block", "dir", "network",
              "netdir", "ploop")
60

61 62 63 64
VIR_ENUM_IMPL(virStoragePool,
              VIR_STORAGE_POOL_LAST,
              "dir", "fs", "netfs",
              "logical", "disk", "iscsi",
R
Roman Bogorodskiy 已提交
65
              "scsi", "mpath", "rbd",
66 67
              "sheepdog", "gluster", "zfs",
              "vstorage")
68 69 70 71 72

VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
              VIR_STORAGE_POOL_FS_LAST,
              "auto", "ext2", "ext3",
              "ext4", "ufs", "iso9660", "udf",
J
Jim Fehlig 已提交
73
              "gfs", "gfs2", "vfat", "hfs+", "xfs", "ocfs2")
74 75 76

VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
              VIR_STORAGE_POOL_NETFS_LAST,
77
              "auto", "nfs", "glusterfs", "cifs")
78 79 80 81

VIR_ENUM_IMPL(virStoragePoolFormatDisk,
              VIR_STORAGE_POOL_DISK_LAST,
              "unknown", "dos", "dvh", "gpt",
82
              "mac", "bsd", "pc98", "sun", "lvm2")
83 84 85

VIR_ENUM_IMPL(virStoragePoolFormatLogical,
              VIR_STORAGE_POOL_LOGICAL_LAST,
86
              "unknown", "lvm2")
87 88 89 90 91 92 93


VIR_ENUM_IMPL(virStorageVolFormatDisk,
              VIR_STORAGE_VOL_DISK_LAST,
              "none", "linux", "fat16",
              "fat32", "linux-swap",
              "linux-lvm", "linux-raid",
94
              "extended")
95

96
VIR_ENUM_IMPL(virStoragePartedFs,
97
              VIR_STORAGE_PARTED_FS_TYPE_LAST,
98
              "ext2", "ext2", "fat16",
99 100 101
              "fat32", "linux-swap",
              "ext2", "ext2",
              "extended")
102

103
VIR_ENUM_IMPL(virStoragePoolSourceAdapter,
104 105 106
              VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST,
              "default", "scsi_host", "fc_host")

107 108 109 110 111 112 113 114 115
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;
typedef virStorageVolOptions *virStorageVolOptionsPtr;
struct _virStorageVolOptions {
116
    int defaultFormat;
117 118 119 120 121 122
    virStorageVolFormatToString formatToString;
    virStorageVolFormatFromString formatFromString;
};

/* Flags to indicate mandatory components in the pool source */
enum {
O
Osier Yang 已提交
123 124 125 126 127 128 129
    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),
130 131 132 133 134
};

typedef struct _virStoragePoolOptions virStoragePoolOptions;
typedef virStoragePoolOptions *virStoragePoolOptionsPtr;
struct _virStoragePoolOptions {
E
Eric Blake 已提交
135
    unsigned int flags;
136 137 138 139 140 141 142 143 144 145 146 147 148
    int defaultFormat;
    virStoragePoolFormatToString formatToString;
    virStoragePoolFormatFromString formatFromString;
};

typedef struct _virStoragePoolTypeInfo virStoragePoolTypeInfo;
typedef virStoragePoolTypeInfo *virStoragePoolTypeInfoPtr;
struct _virStoragePoolTypeInfo {
    int poolType;
    virStoragePoolOptions poolOptions;
    virStorageVolOptions volOptions;
};

E
Eric Blake 已提交
149 150 151 152 153 154 155 156 157
static int
virStorageVolumeFormatFromString(const char *format)
{
    int ret = virStorageFileFormatTypeFromString(format);
    if (ret == VIR_STORAGE_FILE_NONE)
        return -1;
    return ret;
}

158
static virStoragePoolTypeInfo poolTypeInfo[] = {
159 160 161 162 163 164 165 166
    {.poolType = VIR_STORAGE_POOL_LOGICAL,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_NAME |
                   VIR_STORAGE_POOL_SOURCE_DEVICE),
         .defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2,
         .formatFromString = virStoragePoolFormatLogicalTypeFromString,
         .formatToString = virStoragePoolFormatLogicalTypeToString,
     },
167
    },
168 169 170 171 172 173
    {.poolType = VIR_STORAGE_POOL_DIR,
     .volOptions = {
         .defaultFormat = VIR_STORAGE_FILE_RAW,
         .formatFromString = virStorageVolumeFormatFromString,
         .formatToString = virStorageFileFormatTypeToString,
     },
174
    },
175 176 177 178 179 180 181
    {.poolType = VIR_STORAGE_POOL_FS,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
         .defaultFormat = VIR_STORAGE_POOL_FS_AUTO,
         .formatFromString = virStoragePoolFormatFileSystemTypeFromString,
         .formatToString = virStoragePoolFormatFileSystemTypeToString,
      },
182
      .volOptions = {
183 184 185 186
         .defaultFormat = VIR_STORAGE_FILE_RAW,
         .formatFromString = virStorageVolumeFormatFromString,
         .formatToString = virStorageFileFormatTypeToString,
      },
187
    },
188 189 190 191 192 193 194 195
    {.poolType = VIR_STORAGE_POOL_NETFS,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                   VIR_STORAGE_POOL_SOURCE_DIR),
         .defaultFormat = VIR_STORAGE_POOL_NETFS_AUTO,
         .formatFromString = virStoragePoolFormatFileSystemNetTypeFromString,
         .formatToString = virStoragePoolFormatFileSystemNetTypeToString,
      },
196
      .volOptions = {
197 198 199 200
         .defaultFormat = VIR_STORAGE_FILE_RAW,
         .formatFromString = virStorageVolumeFormatFromString,
         .formatToString = virStorageFileFormatTypeToString,
      },
201
    },
202 203 204 205 206 207
    {.poolType = VIR_STORAGE_POOL_ISCSI,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                   VIR_STORAGE_POOL_SOURCE_DEVICE |
                   VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
      },
208
      .volOptions = {
209 210 211 212 213 214 215 216 217 218
         .formatToString = virStoragePoolFormatDiskTypeToString,
      }
    },
    {.poolType = VIR_STORAGE_POOL_SCSI,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER),
     },
     .volOptions = {
         .formatToString = virStoragePoolFormatDiskTypeToString,
     }
219
    },
220 221 222 223 224 225
    {.poolType = VIR_STORAGE_POOL_RBD,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                   VIR_STORAGE_POOL_SOURCE_NETWORK |
                   VIR_STORAGE_POOL_SOURCE_NAME),
      },
226
      .volOptions = {
227
          .defaultFormat = VIR_STORAGE_FILE_RAW,
228 229
          .formatFromString = virStorageVolumeFormatFromString,
          .formatToString = virStorageFileFormatTypeToString,
230
      }
231
    },
232 233 234 235 236 237 238 239 240 241
    {.poolType = VIR_STORAGE_POOL_SHEEPDOG,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                   VIR_STORAGE_POOL_SOURCE_NETWORK |
                   VIR_STORAGE_POOL_SOURCE_NAME),
     },
     .volOptions = {
         .defaultFormat = VIR_STORAGE_FILE_RAW,
         .formatToString = virStoragePoolFormatDiskTypeToString,
     }
242
    },
243 244 245 246 247 248 249 250 251 252 253 254 255
    {.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,
         .formatToString = virStorageFileFormatTypeToString,
         .formatFromString = virStorageVolumeFormatFromString,
     }
    },
256 257 258 259
    {.poolType = VIR_STORAGE_POOL_MPATH,
     .volOptions = {
         .formatToString = virStoragePoolFormatDiskTypeToString,
     }
260
    },
261 262 263 264 265 266 267 268 269 270 271 272
    {.poolType = VIR_STORAGE_POOL_DISK,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
         .defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN,
         .formatFromString = virStoragePoolFormatDiskTypeFromString,
         .formatToString = virStoragePoolFormatDiskTypeToString,
     },
     .volOptions = {
         .defaultFormat = VIR_STORAGE_VOL_DISK_NONE,
         .formatFromString = virStorageVolFormatDiskTypeFromString,
         .formatToString = virStorageVolFormatDiskTypeToString,
     },
R
Roman Bogorodskiy 已提交
273 274 275
    },
    {.poolType = VIR_STORAGE_POOL_ZFS,
     .poolOptions = {
276 277
         .flags = (VIR_STORAGE_POOL_SOURCE_NAME |
                   VIR_STORAGE_POOL_SOURCE_DEVICE),
R
Roman Bogorodskiy 已提交
278 279 280
         .defaultFormat = VIR_STORAGE_FILE_RAW,
     },
    },
281 282 283 284 285 286 287 288 289 290
    {.poolType = VIR_STORAGE_POOL_VSTORAGE,
     .poolOptions = {
        .flags = VIR_STORAGE_POOL_SOURCE_NAME,
     },
     .volOptions = {
        .defaultFormat = VIR_STORAGE_FILE_RAW,
        .formatFromString = virStorageVolumeFormatFromString,
        .formatToString = virStorageFileFormatTypeToString,
     },
    },
291 292 293 294
};


static virStoragePoolTypeInfoPtr
295 296
virStoragePoolTypeInfoLookup(int type)
{
297
    size_t i;
298
    for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo); i++)
299 300 301
        if (poolTypeInfo[i].poolType == type)
            return &poolTypeInfo[i];

302 303
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("missing backend for pool type %d"), type);
304 305 306 307
    return NULL;
}

static virStoragePoolOptionsPtr
308 309
virStoragePoolOptionsForPoolType(int type)
{
310 311 312 313 314 315 316
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->poolOptions;
}

static virStorageVolOptionsPtr
317 318
virStorageVolOptionsForPoolType(int type)
{
319 320 321 322 323 324 325
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->volOptions;
}


326
void
327 328
virStorageVolDefFree(virStorageVolDefPtr def)
{
329
    size_t i;
330 331 332 333

    if (!def)
        return;

334 335
    VIR_FREE(def->name);
    VIR_FREE(def->key);
336

337
    for (i = 0; i < def->source.nextent; i++)
338 339
        VIR_FREE(def->source.extents[i].path);
    VIR_FREE(def->source.extents);
340

341
    virStorageSourceClear(&def->target);
342
    VIR_FREE(def);
343 344
}

345
static void
346
virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapterPtr adapter)
347
{
348 349 350 351
    if (adapter->type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
        VIR_FREE(adapter->data.fchost.wwnn);
        VIR_FREE(adapter->data.fchost.wwpn);
        VIR_FREE(adapter->data.fchost.parent);
352 353 354
        VIR_FREE(adapter->data.fchost.parent_wwnn);
        VIR_FREE(adapter->data.fchost.parent_wwpn);
        VIR_FREE(adapter->data.fchost.parent_fabric_wwn);
355
    } else if (adapter->type ==
356
               VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
357
        VIR_FREE(adapter->data.scsi_host.name);
358 359 360
    }
}

361 362 363 364 365 366 367
void
virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev)
{
    VIR_FREE(dev->freeExtents);
    VIR_FREE(dev->path);
}

368
void
369 370
virStoragePoolSourceClear(virStoragePoolSourcePtr source)
{
371
    size_t i;
372

373
    if (!source)
374 375
        return;

376
    for (i = 0; i < source->nhost; i++)
377 378 379
        VIR_FREE(source->hosts[i].name);
    VIR_FREE(source->hosts);

380 381
    for (i = 0; i < source->ndevice; i++)
        virStoragePoolSourceDeviceClear(&source->devices[i]);
382 383 384
    VIR_FREE(source->devices);
    VIR_FREE(source->dir);
    VIR_FREE(source->name);
385
    virStoragePoolSourceAdapterClear(&source->adapter);
D
David Allan 已提交
386
    VIR_FREE(source->initiator.iqn);
387
    virStorageAuthDefFree(source->auth);
388 389
    VIR_FREE(source->vendor);
    VIR_FREE(source->product);
390 391
}

392 393 394 395 396 397 398
void
virStoragePoolSourceFree(virStoragePoolSourcePtr source)
{
    virStoragePoolSourceClear(source);
    VIR_FREE(source);
}

399
void
400 401
virStoragePoolDefFree(virStoragePoolDefPtr def)
{
402 403 404 405 406
    if (!def)
        return;

    VIR_FREE(def->name);

407
    virStoragePoolSourceClear(&def->source);
408

409 410 411
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
    VIR_FREE(def);
412 413 414 415
}


void
416 417
virStoragePoolObjFree(virStoragePoolObjPtr obj)
{
418 419 420
    if (!obj)
        return;

421 422
    virStoragePoolObjClearVols(obj);

423 424
    virStoragePoolDefFree(obj->def);
    virStoragePoolDefFree(obj->newDef);
425

426 427
    VIR_FREE(obj->configFile);
    VIR_FREE(obj->autostartLink);
428 429 430

    virMutexDestroy(&obj->lock);

431
    VIR_FREE(obj);
432 433
}

434 435
void
virStoragePoolObjListFree(virStoragePoolObjListPtr pools)
436
{
437
    size_t i;
438
    for (i = 0; i < pools->count; i++)
439 440 441 442 443
        virStoragePoolObjFree(pools->objs[i]);
    VIR_FREE(pools->objs);
    pools->count = 0;
}

444
void
445
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
446 447
                        virStoragePoolObjPtr pool)
{
448
    size_t i;
449

450 451
    virStoragePoolObjUnlock(pool);

452
    for (i = 0; i < pools->count; i++) {
453
        virStoragePoolObjLock(pools->objs[i]);
454
        if (pools->objs[i] == pool) {
455
            virStoragePoolObjUnlock(pools->objs[i]);
456
            virStoragePoolObjFree(pools->objs[i]);
457

458
            VIR_DELETE_ELEMENT(pools->objs, i, pools->count);
459 460
            break;
        }
461
        virStoragePoolObjUnlock(pools->objs[i]);
462
    }
463 464
}

465 466
static int
virStoragePoolDefParseSourceAdapter(virStoragePoolSourcePtr source,
467
                                    xmlNodePtr node,
468 469 470
                                    xmlXPathContextPtr ctxt)
{
    int ret = -1;
471
    xmlNodePtr relnode = ctxt->node;
472 473 474
    char *adapter_type = NULL;
    char *managed = NULL;

475 476 477
    ctxt->node = node;

    if ((adapter_type = virXMLPropString(node, "type"))) {
478 479 480 481 482 483 484 485 486 487 488
        if ((source->adapter.type =
             virStoragePoolSourceAdapterTypeFromString(adapter_type)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown pool adapter type '%s'"),
                           adapter_type);
            goto cleanup;
        }

        if (source->adapter.type ==
            VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
            source->adapter.data.fchost.parent =
489 490
                virXMLPropString(node, "parent");
            managed = virXMLPropString(node, "managed");
491 492 493 494 495 496 497 498 499 500 501 502
            if (managed) {
                source->adapter.data.fchost.managed =
                    virTristateBoolTypeFromString(managed);
                if (source->adapter.data.fchost.managed < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown fc_host managed setting '%s'"),
                                   managed);
                    goto cleanup;
                }
            }

            source->adapter.data.fchost.parent_wwnn =
503
                virXMLPropString(node, "parent_wwnn");
504
            source->adapter.data.fchost.parent_wwpn =
505
                virXMLPropString(node, "parent_wwpn");
506
            source->adapter.data.fchost.parent_fabric_wwn =
507
                virXMLPropString(node, "parent_fabric_wwn");
508

509 510
            source->adapter.data.fchost.wwpn = virXMLPropString(node, "wwpn");
            source->adapter.data.fchost.wwnn = virXMLPropString(node, "wwnn");
511 512 513 514
        } else if (source->adapter.type ==
                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {

            source->adapter.data.scsi_host.name =
515 516 517
                virXMLPropString(node, "name");
            if (virXPathNode("./parentaddr", ctxt)) {
                xmlNodePtr addrnode = virXPathNode("./parentaddr/address",
518 519 520 521 522 523 524 525 526 527 528 529
                                                   ctxt);
                virPCIDeviceAddressPtr addr =
                    &source->adapter.data.scsi_host.parentaddr;

                if (!addrnode) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Missing scsi_host PCI address element"));
                    goto cleanup;
                }
                source->adapter.data.scsi_host.has_parent = true;
                if (virPCIDeviceAddressParseXML(addrnode, addr) < 0)
                    goto cleanup;
530
                if ((virXPathInt("string(./parentaddr/@unique_id)",
531 532 533 534 535 536 537 538 539 540 541
                                 ctxt,
                                 &source->adapter.data.scsi_host.unique_id) < 0) ||
                    (source->adapter.data.scsi_host.unique_id < 0)) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Missing or invalid scsi adapter "
                                     "'unique_id' value"));
                    goto cleanup;
                }
            }
        }
    } else {
542 543 544
        char *wwnn = virXMLPropString(node, "wwnn");
        char *wwpn = virXMLPropString(node, "wwpn");
        char *parent = virXMLPropString(node, "parent");
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560

        /* "type" was not specified in the XML, so we must verify that
         * "wwnn", "wwpn", "parent", or "parentaddr" are also not in the
         * XML. If any are found, then we cannot just use "name" alone".
         */

        if (wwnn || wwpn || parent) {
            VIR_FREE(wwnn);
            VIR_FREE(wwpn);
            VIR_FREE(parent);
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Use of 'wwnn', 'wwpn', and 'parent' attributes "
                             "requires use of the adapter 'type'"));
            goto cleanup;
        }

561
        if (virXPathNode("./parentaddr", ctxt)) {
562 563 564 565 566 567 568 569 570 571
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Use of 'parent' element requires use "
                             "of the adapter 'type'"));
            goto cleanup;
        }

        /* To keep back-compat, 'type' is not required to specify
         * for scsi_host adapter.
         */
        if ((source->adapter.data.scsi_host.name =
572
             virXMLPropString(node, "name")))
573 574 575 576 577 578 579
            source->adapter.type =
                VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST;
    }

    ret = 0;

 cleanup:
580
    ctxt->node = relnode;
581 582 583 584 585 586
    VIR_FREE(adapter_type);
    VIR_FREE(managed);
    return ret;
}


587
static int
588
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
589 590
                             virStoragePoolSourcePtr source,
                             int pool_type,
591 592
                             xmlNodePtr node)
{
593
    int ret = -1;
594
    xmlNodePtr relnode, authnode, *nodeset = NULL;
595
    xmlNodePtr adapternode;
596 597
    int nsource;
    size_t i;
598
    virStoragePoolOptionsPtr options;
599
    virStorageAuthDefPtr authdef = NULL;
600
    char *name = NULL;
601
    char *port = NULL;
602
    int n;
603 604 605 606

    relnode = ctxt->node;
    ctxt->node = node;

607
    if ((options = virStoragePoolOptionsForPoolType(pool_type)) == NULL)
608 609
        goto cleanup;

610
    source->name = virXPathString("string(./name)", ctxt);
611
    if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
612
        virReportError(VIR_ERR_XML_ERROR, "%s",
613
                       _("element 'name' is mandatory for RBD pool"));
614 615
        goto cleanup;
    }
616 617

    if (options->formatFromString) {
618
        char *format = virXPathString("string(./format/@type)", ctxt);
619 620 621 622 623 624
        if (format == NULL)
            source->format = options->defaultFormat;
        else
            source->format = options->formatFromString(format);

        if (source->format < 0) {
625
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
626
                           _("unknown pool format type %s"), format);
627 628 629 630 631 632
            VIR_FREE(format);
            goto cleanup;
        }
        VIR_FREE(format);
    }

633 634
    if ((n = virXPathNodeSet("./host", ctxt, &nodeset)) < 0)
        goto cleanup;
635

636 637
    if (n) {
        if (VIR_ALLOC_N(source->hosts, n) < 0)
638
            goto cleanup;
639
        source->nhost = n;
640

641
        for (i = 0; i < source->nhost; i++) {
642 643
            name = virXMLPropString(nodeset[i], "name");
            if (name == NULL) {
644 645
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing storage pool host name"));
646 647 648 649 650 651 652
                goto cleanup;
            }
            source->hosts[i].name = name;

            port = virXMLPropString(nodeset[i], "port");
            if (port) {
                if (virStrToLong_i(port, NULL, 10, &source->hosts[i].port) < 0) {
653 654 655
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("Invalid port number: %s"),
                                   port);
656 657 658 659 660
                    goto cleanup;
                }
            }
        }
    }
661

662
    VIR_FREE(nodeset);
663
    source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
664

665
    nsource = virXPathNodeSet("./device", ctxt, &nodeset);
666 667 668
    if (nsource < 0)
        goto cleanup;

669
    for (i = 0; i < nsource; i++) {
670
        char *partsep;
671 672 673 674 675 676
        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"));
677 678 679
            goto cleanup;
        }

680 681 682 683 684 685 686 687 688 689 690 691 692 693
        partsep = virXMLPropString(nodeset[i], "part_separator");
        if (partsep) {
            dev.part_separator = virTristateBoolTypeFromString(partsep);
            if (dev.part_separator <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("invalid part_separator setting '%s'"),
                               partsep);
                virStoragePoolSourceDeviceClear(&dev);
                VIR_FREE(partsep);
                goto cleanup;
            }
            VIR_FREE(partsep);
        }

694 695 696
        if (VIR_APPEND_ELEMENT(source->devices, source->ndevice, dev) < 0) {
            virStoragePoolSourceDeviceClear(&dev);
            goto cleanup;
697
        }
698

699 700
    }

701
    source->dir = virXPathString("string(./dir/@path)", ctxt);
702 703 704 705
    /* In gluster, a missing dir defaults to "/" */
    if (!source->dir && pool_type == VIR_STORAGE_POOL_GLUSTER &&
        VIR_STRDUP(source->dir, "/") < 0)
        goto cleanup;
706

707 708 709 710
    if ((adapternode = virXPathNode("./adapter", ctxt))) {
        if (virStoragePoolDefParseSourceAdapter(source, adapternode, ctxt) < 0)
            goto cleanup;
    }
711

712 713 714 715 716 717 718 719 720 721 722
    if ((authnode = virXPathNode("./auth", ctxt))) {
        if (!(authdef = virStorageAuthDefParse(node->doc, authnode)))
            goto cleanup;

        if (authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("storage pool missing auth type"));
            goto cleanup;
        }

        source->auth = authdef;
723
        authdef = NULL;
724
    }
725

726 727 728
    source->vendor = virXPathString("string(./vendor/@name)", ctxt);
    source->product = virXPathString("string(./product/@name)", ctxt);

729
    ret = 0;
730
 cleanup:
731 732
    ctxt->node = relnode;

733
    VIR_FREE(port);
734
    VIR_FREE(nodeset);
735
    virStorageAuthDefFree(authdef);
736 737
    return ret;
}
738

739
virStoragePoolSourcePtr
740
virStoragePoolDefParseSourceString(const char *srcSpec,
741 742 743 744 745 746 747
                                   int pool_type)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr node = NULL;
    xmlXPathContextPtr xpath_ctxt = NULL;
    virStoragePoolSourcePtr def = NULL, ret = NULL;

748 749 750
    if (!(doc = virXMLParseStringCtxt(srcSpec,
                                      _("(storage_source_specification)"),
                                      &xpath_ctxt)))
751 752
        goto cleanup;

753
    if (VIR_ALLOC(def) < 0)
754 755
        goto cleanup;

756
    if (!(node = virXPathNode("/source", xpath_ctxt))) {
757 758
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("root element was not source"));
759 760 761
        goto cleanup;
    }

762
    if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
763 764 765 766 767
                                     node) < 0)
        goto cleanup;

    ret = def;
    def = NULL;
768
 cleanup:
769
    virStoragePoolSourceFree(def);
770 771 772 773 774
    xmlFreeDoc(doc);
    xmlXPathFreeContext(xpath_ctxt);

    return ret;
}
775

776
static int
777
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
778
                        virStoragePermsPtr perms,
779
                        const char *permxpath)
780
{
781
    char *mode;
782
    long long val;
783 784 785
    int ret = -1;
    xmlNodePtr relnode;
    xmlNodePtr node;
786

787
    node = virXPathNode(permxpath, ctxt);
788 789
    if (node == NULL) {
        /* Set default values if there is not <permissions> element */
790
        perms->mode = (mode_t) -1;
P
Philipp Hahn 已提交
791 792
        perms->uid = (uid_t) -1;
        perms->gid = (gid_t) -1;
793 794 795 796 797 798 799
        perms->label = NULL;
        return 0;
    }

    relnode = ctxt->node;
    ctxt->node = node;

800
    if ((mode = virXPathString("string(./mode)", ctxt))) {
801 802 803
        int tmp;

        if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
804
            VIR_FREE(mode);
805 806
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed octal mode"));
807
            goto error;
808
        }
809
        perms->mode = tmp;
810
        VIR_FREE(mode);
811 812
    } else {
        perms->mode = (mode_t) -1;
813 814
    }

815
    if (virXPathNode("./owner", ctxt) == NULL) {
P
Philipp Hahn 已提交
816
        perms->uid = (uid_t) -1;
817
    } else {
818
        /* We previously could output -1, so continue to parse it */
819
        if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 ||
820 821
            ((uid_t)val != val &&
             val != -1)) {
822 823
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed owner element"));
824
            goto error;
825
        }
826 827

        perms->uid = val;
828 829
    }

830
    if (virXPathNode("./group", ctxt) == NULL) {
P
Philipp Hahn 已提交
831
        perms->gid = (gid_t) -1;
832
    } else {
833
        /* We previously could output -1, so continue to parse it */
834
        if (virXPathLongLong("number(./group)", ctxt, &val) < 0 ||
835 836
            ((gid_t) val != val &&
             val != -1)) {
837 838
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed group element"));
839
            goto error;
840
        }
841
        perms->gid = val;
842 843 844
    }

    /* NB, we're ignoring missing labels here - they'll simply inherit */
845
    perms->label = virXPathString("string(./label)", ctxt);
846

847
    ret = 0;
848
 error:
849 850
    ctxt->node = relnode;
    return ret;
851 852
}

853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
static int
virStoragePoolSourceAdapterValidate(virStoragePoolDefPtr ret)
{
    if (!ret->source.adapter.type) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing storage pool source adapter"));
        return -1;
    }

    if (ret->source.adapter.type ==
        VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
        if (!ret->source.adapter.data.fchost.wwnn ||
            !ret->source.adapter.data.fchost.wwpn) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("'wwnn' and 'wwpn' must be specified for adapter "
                             "type 'fchost'"));
            return -1;
        }

        if (!virValidateWWN(ret->source.adapter.data.fchost.wwnn) ||
            !virValidateWWN(ret->source.adapter.data.fchost.wwpn))
            return -1;

        if ((ret->source.adapter.data.fchost.parent_wwnn &&
             !ret->source.adapter.data.fchost.parent_wwpn)) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("when providing parent_wwnn='%s', the "
                             "parent_wwpn must also be provided"),
                           ret->source.adapter.data.fchost.parent_wwnn);
            return -1;
        }

        if (!ret->source.adapter.data.fchost.parent_wwnn &&
             ret->source.adapter.data.fchost.parent_wwpn) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("when providing parent_wwpn='%s', the "
                             "parent_wwnn must also be provided"),
                           ret->source.adapter.data.fchost.parent_wwpn);
            return -1;
        }

        if (ret->source.adapter.data.fchost.parent_wwnn &&
            !virValidateWWN(ret->source.adapter.data.fchost.parent_wwnn))
            return -1;

        if (ret->source.adapter.data.fchost.parent_wwpn &&
            !virValidateWWN(ret->source.adapter.data.fchost.parent_wwpn))
            return -1;

        if (ret->source.adapter.data.fchost.parent_fabric_wwn &&
            !virValidateWWN(ret->source.adapter.data.fchost.parent_fabric_wwn))
            return -1;

    } else if (ret->source.adapter.type ==
               VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
        if (!ret->source.adapter.data.scsi_host.name &&
            !ret->source.adapter.data.scsi_host.has_parent) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Either 'name' or 'parent' must be specified "
                             "for the 'scsi_host' adapter"));
            return -1;
        }

        if (ret->source.adapter.data.scsi_host.name &&
            ret->source.adapter.data.scsi_host.has_parent) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Both 'name' and 'parent' cannot be specified "
                             "for the 'scsi_host' adapter"));
            return -1;
        }
    }

    return 0;
}


929
static virStoragePoolDefPtr
930 931
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
{
932
    virStoragePoolOptionsPtr options;
933
    virStoragePoolDefPtr ret;
934
    xmlNodePtr source_node;
935
    char *type = NULL;
936
    char *uuid = NULL;
937
    char *target_path = NULL;
938

939
    if (VIR_ALLOC(ret) < 0)
940 941
        return NULL;

942
    type = virXPathString("string(./@type)", ctxt);
943 944 945 946 947 948
    if (type == NULL) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("storage pool missing type attribute"));
        goto error;
    }

949
    if ((ret->type = virStoragePoolTypeFromString(type)) < 0) {
950
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
951
                       _("unknown storage pool type %s"), type);
952
        goto error;
953 954
    }

955
    if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL)
956
        goto error;
957

958
    source_node = virXPathNode("./source", ctxt);
959
    if (source_node) {
960
        if (virStoragePoolDefParseSource(ctxt, &ret->source, ret->type,
961
                                         source_node) < 0)
962
            goto error;
963 964
    }

965
    ret->name = virXPathString("string(./name)", ctxt);
966
    if (ret->name == NULL &&
967
        options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
968
        ret->name = ret->source.name;
969
    if (ret->name == NULL) {
970 971
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing pool source name element"));
972
        goto error;
973 974
    }

975 976 977 978 979 980
    if (strchr(ret->name, '/')) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("name %s cannot contain '/'"), ret->name);
        goto error;
    }

981
    uuid = virXPathString("string(./uuid)", ctxt);
982 983
    if (uuid == NULL) {
        if (virUUIDGenerate(ret->uuid) < 0) {
984 985
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unable to generate uuid"));
986
            goto error;
987 988 989
        }
    } else {
        if (virUUIDParse(uuid, ret->uuid) < 0) {
990 991
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed uuid element"));
992
            goto error;
993 994 995
        }
    }

996
    if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
997
        if (!ret->source.nhost) {
998
            virReportError(VIR_ERR_XML_ERROR, "%s",
999
                           _("missing storage pool source host name"));
1000
            goto error;
1001 1002 1003
        }
    }

1004
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
1005
        if (!ret->source.dir) {
1006 1007
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source path"));
1008
            goto error;
1009 1010
        }
    }
1011
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
1012 1013
        if (ret->source.name == NULL) {
            /* source name defaults to pool name */
1014
            if (VIR_STRDUP(ret->source.name, ret->name) < 0)
1015
                goto error;
1016 1017
        }
    }
1018

1019 1020
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
        (virStoragePoolSourceAdapterValidate(ret)) < 0)
1021
            goto error;
1022

1023 1024 1025
    /* If DEVICE is the only source type, then its required */
    if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
        if (!ret->source.ndevice) {
1026 1027
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source device name"));
1028
            goto error;
1029 1030 1031
        }
    }

1032 1033 1034
    /* When we are working with a virtual disk we can skip the target
     * path and permissions */
    if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
1035
        if (ret->type == VIR_STORAGE_POOL_LOGICAL) {
1036
            if (virAsprintf(&target_path, "/dev/%s", ret->source.name) < 0)
1037
                goto error;
R
Roman Bogorodskiy 已提交
1038
        } else if (ret->type == VIR_STORAGE_POOL_ZFS) {
1039
            if (virAsprintf(&target_path, "/dev/zvol/%s", ret->source.name) < 0)
R
Roman Bogorodskiy 已提交
1040
                goto error;
1041 1042 1043 1044 1045 1046 1047
        } else {
            target_path = virXPathString("string(./target/path)", ctxt);
            if (!target_path) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing storage pool target path"));
                goto error;
            }
1048
        }
1049
        ret->target.path = virFileSanitizePath(target_path);
1050
        if (!ret->target.path)
1051
            goto error;
1052

1053
        if (virStorageDefParsePerms(ctxt, &ret->target.perms,
1054
                                    "./target/permissions") < 0)
1055
            goto error;
1056
    }
1057

1058
 cleanup:
1059
    VIR_FREE(uuid);
1060 1061 1062 1063
    VIR_FREE(type);
    VIR_FREE(target_path);
    return ret;

1064
 error:
1065
    virStoragePoolDefFree(ret);
1066 1067
    ret = NULL;
    goto cleanup;
1068 1069 1070
}

virStoragePoolDefPtr
1071
virStoragePoolDefParseNode(xmlDocPtr xml,
1072 1073
                           xmlNodePtr root)
{
1074 1075 1076
    xmlXPathContextPtr ctxt = NULL;
    virStoragePoolDefPtr def = NULL;

1077
    if (!xmlStrEqual(root->name, BAD_CAST "pool")) {
1078
        virReportError(VIR_ERR_XML_ERROR,
1079 1080 1081
                       _("unexpected root element <%s>, "
                         "expecting <pool>"),
                       root->name);
1082 1083 1084 1085 1086
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1087
        virReportOOMError();
1088 1089 1090 1091
        goto cleanup;
    }

    ctxt->node = root;
1092
    def = virStoragePoolDefParseXML(ctxt);
1093
 cleanup:
1094 1095 1096 1097 1098
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStoragePoolDefPtr
1099
virStoragePoolDefParse(const char *xmlStr,
1100 1101
                       const char *filename)
{
1102
    virStoragePoolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1103
    xmlDocPtr xml;
1104

1105
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_pool_definition)")))) {
J
Jiri Denemark 已提交
1106 1107
        ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1108 1109
    }

1110 1111 1112
    return ret;
}

1113
virStoragePoolDefPtr
1114
virStoragePoolDefParseString(const char *xmlStr)
1115
{
1116
    return virStoragePoolDefParse(xmlStr, NULL);
1117 1118 1119
}

virStoragePoolDefPtr
1120
virStoragePoolDefParseFile(const char *filename)
1121
{
1122
    return virStoragePoolDefParse(NULL, filename);
1123 1124
}

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
static void
virStoragePoolSourceAdapterFormat(virBufferPtr buf,
                                  virStoragePoolSourcePtr src)
{
    virBufferAsprintf(buf, "<adapter type='%s'",
                      virStoragePoolSourceAdapterTypeToString(src->adapter.type));

    if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
        virBufferEscapeString(buf, " parent='%s'",
                              src->adapter.data.fchost.parent);
        if (src->adapter.data.fchost.managed)
            virBufferAsprintf(buf, " managed='%s'",
                              virTristateBoolTypeToString(src->adapter.data.fchost.managed));
        virBufferEscapeString(buf, " parent_wwnn='%s'",
                              src->adapter.data.fchost.parent_wwnn);
        virBufferEscapeString(buf, " parent_wwpn='%s'",
                              src->adapter.data.fchost.parent_wwpn);
        virBufferEscapeString(buf, " parent_fabric_wwn='%s'",
                              src->adapter.data.fchost.parent_fabric_wwn);

        virBufferAsprintf(buf, " wwnn='%s' wwpn='%s'/>\n",
                          src->adapter.data.fchost.wwnn,
                          src->adapter.data.fchost.wwpn);
    } else if (src->adapter.type ==
               VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
        if (src->adapter.data.scsi_host.name) {
            virBufferAsprintf(buf, " name='%s'/>\n",
                              src->adapter.data.scsi_host.name);
        } else {
            virPCIDeviceAddress addr;
            virBufferAddLit(buf, ">\n");
            virBufferAdjustIndent(buf, 2);
            virBufferAsprintf(buf, "<parentaddr unique_id='%d'>\n",
                              src->adapter.data.scsi_host.unique_id);
            virBufferAdjustIndent(buf, 2);
            addr = src->adapter.data.scsi_host.parentaddr;
            ignore_value(virPCIDeviceAddressFormat(buf, addr, false));
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</parentaddr>\n");
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</adapter>\n");
        }
    }
}

1170
static int
1171
virStoragePoolSourceFormat(virBufferPtr buf,
1172
                           virStoragePoolOptionsPtr options,
1173 1174
                           virStoragePoolSourcePtr src)
{
1175
    size_t i, j;
1176

1177 1178 1179
    virBufferAddLit(buf, "<source>\n");
    virBufferAdjustIndent(buf, 2);

1180 1181
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
        for (i = 0; i < src->nhost; i++) {
1182
            virBufferEscapeString(buf, "<host name='%s'",
1183
                                  src->hosts[i].name);
1184 1185 1186 1187
            if (src->hosts[i].port)
                virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
            virBufferAddLit(buf, "/>\n");
        }
1188
    }
1189

1190
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
1191
        src->ndevice) {
1192
        for (i = 0; i < src->ndevice; i++) {
1193 1194 1195 1196 1197 1198 1199
            virBufferEscapeString(buf, "<device path='%s'",
                                  src->devices[i].path);
            if (src->devices[i].part_separator !=
                VIR_TRISTATE_SWITCH_ABSENT) {
                virBufferAsprintf(buf, " part_separator='%s'",
                                  virTristateBoolTypeToString(src->devices[i].part_separator));
            }
1200
            if (src->devices[i].nfreeExtent) {
1201
                virBufferAddLit(buf, ">\n");
1202
                virBufferAdjustIndent(buf, 2);
1203
                for (j = 0; j < src->devices[i].nfreeExtent; j++) {
1204
                    virBufferAsprintf(buf, "<freeExtent start='%llu' end='%llu'/>\n",
1205 1206 1207
                                      src->devices[i].freeExtents[j].start,
                                      src->devices[i].freeExtents[j].end);
                }
1208 1209
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</device>\n");
1210
            } else {
1211
                virBufferAddLit(buf, "/>\n");
1212
            }
1213 1214
        }
    }
1215

1216
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR)
1217
        virBufferEscapeString(buf, "<dir path='%s'/>\n", src->dir);
1218

1219 1220 1221 1222
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
        (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST ||
         src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST))
        virStoragePoolSourceAdapterFormat(buf, src);
1223

1224
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
1225
        virBufferEscapeString(buf, "<name>%s</name>\n", src->name);
1226

D
David Allan 已提交
1227 1228
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN) &&
        src->initiator.iqn) {
1229 1230 1231
        virBufferAddLit(buf, "<initiator>\n");
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<iqn name='%s'/>\n",
E
Eric Blake 已提交
1232
                              src->initiator.iqn);
1233 1234
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</initiator>\n");
D
David Allan 已提交
1235 1236
    }

1237 1238 1239
    if (options->formatToString) {
        const char *format = (options->formatToString)(src->format);
        if (!format) {
1240 1241 1242
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown pool format number %d"),
                           src->format);
1243 1244
            return -1;
        }
1245
        virBufferAsprintf(buf, "<format type='%s'/>\n", format);
1246 1247
    }

1248 1249 1250
    if (src->auth) {
        if (virStorageAuthDefFormat(buf, src->auth) < 0)
            return -1;
1251 1252
    }

1253 1254
    virBufferEscapeString(buf, "<vendor name='%s'/>\n", src->vendor);
    virBufferEscapeString(buf, "<product name='%s'/>\n", src->product);
1255

1256 1257
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</source>\n");
1258 1259 1260
    return 0;
}

1261

1262 1263 1264
static int
virStoragePoolDefFormatBuf(virBufferPtr buf,
                           virStoragePoolDefPtr def)
1265
{
1266
    virStoragePoolOptionsPtr options;
1267
    char uuid[VIR_UUID_STRING_BUFLEN];
1268
    const char *type;
1269

1270
    options = virStoragePoolOptionsForPoolType(def->type);
1271
    if (options == NULL)
1272
        return -1;
1273

1274
    type = virStoragePoolTypeToString(def->type);
1275
    if (!type) {
1276 1277
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected pool type"));
1278
        return -1;
1279
    }
1280 1281 1282
    virBufferAsprintf(buf, "<pool type='%s'>\n", type);
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
1283 1284

    virUUIDFormat(def->uuid, uuid);
1285
    virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuid);
1286

1287
    virBufferAsprintf(buf, "<capacity unit='bytes'>%llu</capacity>\n",
1288
                      def->capacity);
1289
    virBufferAsprintf(buf, "<allocation unit='bytes'>%llu</allocation>\n",
1290
                      def->allocation);
1291
    virBufferAsprintf(buf, "<available unit='bytes'>%llu</available>\n",
1292
                      def->available);
1293

1294 1295
    if (virStoragePoolSourceFormat(buf, options, &def->source) < 0)
        return -1;
1296

1297 1298
    /* RBD, Sheepdog, and Gluster devices are not local block devs nor
     * files, so they don't have a target */
1299
    if (def->type != VIR_STORAGE_POOL_RBD &&
1300 1301
        def->type != VIR_STORAGE_POOL_SHEEPDOG &&
        def->type != VIR_STORAGE_POOL_GLUSTER) {
1302 1303
        virBufferAddLit(buf, "<target>\n");
        virBufferAdjustIndent(buf, 2);
1304

1305
        virBufferEscapeString(buf, "<path>%s</path>\n", def->target.path);
1306

1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
        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");
        }
1328

1329 1330
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</target>\n");
1331
    }
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</pool>\n");

    return 0;
}

char *
virStoragePoolDefFormat(virStoragePoolDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (virStoragePoolDefFormatBuf(&buf, def) < 0)
        goto error;
1345

1346
    if (virBufferCheckError(&buf) < 0)
1347
        goto error;
1348

1349
    return virBufferContentAndReset(&buf);
1350

1351
 error:
1352
    virBufferFreeAndReset(&buf);
1353 1354 1355 1356 1357
    return NULL;
}


static int
1358
virStorageSize(const char *unit,
1359
               const char *val,
1360 1361 1362
               unsigned long long *ret)
{
    if (virStrToLong_ull(val, NULL, 10, ret) < 0) {
1363 1364
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("malformed capacity element"));
1365 1366
        return -1;
    }
1367 1368 1369 1370
    /* 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;
1371 1372 1373 1374 1375

    return 0;
}

static virStorageVolDefPtr
1376
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
1377 1378
                         xmlXPathContextPtr ctxt,
                         unsigned int flags)
1379
{
1380
    virStorageVolDefPtr ret;
1381
    virStorageVolOptionsPtr options;
1382
    char *type = NULL;
1383 1384 1385
    char *allocation = NULL;
    char *capacity = NULL;
    char *unit = NULL;
1386
    char *backingStore = NULL;
1387
    xmlNodePtr node;
1388
    xmlNodePtr *nodes = NULL;
1389 1390
    size_t i;
    int n;
1391

1392 1393
    virCheckFlags(VIR_VOL_XML_PARSE_NO_CAPACITY |
                  VIR_VOL_XML_PARSE_OPT_CAPACITY, NULL);
1394

1395
    options = virStorageVolOptionsForPoolType(pool->type);
1396 1397 1398
    if (options == NULL)
        return NULL;

1399
    if (VIR_ALLOC(ret) < 0)
1400 1401
        return NULL;

1402
    ret->name = virXPathString("string(./name)", ctxt);
1403
    if (ret->name == NULL) {
1404 1405
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing volume name element"));
1406
        goto error;
1407 1408
    }

1409 1410
    /* Normally generated by pool refresh, but useful for unit tests */
    ret->key = virXPathString("string(./key)", ctxt);
1411

1412 1413 1414 1415
    /* Technically overridden by pool refresh, but useful for unit tests */
    type = virXPathString("string(./@type)", ctxt);
    if (type) {
        if ((ret->type = virStorageVolTypeFromString(type)) < 0) {
1416
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1417 1418 1419 1420 1421
                           _("unknown volume type '%s'"), type);
            goto error;
        }
    }

1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
    if ((backingStore = virXPathString("string(./backingStore/path)", ctxt))) {
        if (VIR_ALLOC(ret->target.backingStore) < 0)
            goto error;

        ret->target.backingStore->path = backingStore;
        backingStore = NULL;

        if (options->formatFromString) {
            char *format = virXPathString("string(./backingStore/format/@type)", ctxt);
            if (format == NULL)
                ret->target.backingStore->format = options->defaultFormat;
            else
                ret->target.backingStore->format = (options->formatFromString)(format);

            if (ret->target.backingStore->format < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown volume format type %s"), format);
                VIR_FREE(format);
                goto error;
            }
            VIR_FREE(format);
        }

        if (VIR_ALLOC(ret->target.backingStore->perms) < 0)
            goto error;
        if (virStorageDefParsePerms(ctxt, ret->target.backingStore->perms,
1448
                                    "./backingStore/permissions") < 0)
1449 1450 1451
            goto error;
    }

1452 1453
    capacity = virXPathString("string(./capacity)", ctxt);
    unit = virXPathString("string(./capacity/@unit)", ctxt);
1454 1455 1456
    if (capacity) {
        if (virStorageSize(unit, capacity, &ret->target.capacity) < 0)
            goto error;
1457 1458
    } else if (!(flags & VIR_VOL_XML_PARSE_NO_CAPACITY) &&
               !((flags & VIR_VOL_XML_PARSE_OPT_CAPACITY) && ret->target.backingStore)) {
1459
        virReportError(VIR_ERR_XML_ERROR, "%s", _("missing capacity element"));
1460
        goto error;
1461
    }
1462
    VIR_FREE(unit);
1463

1464
    allocation = virXPathString("string(./allocation)", ctxt);
1465
    if (allocation) {
1466
        unit = virXPathString("string(./allocation/@unit)", ctxt);
1467
        if (virStorageSize(unit, allocation, &ret->target.allocation) < 0)
1468
            goto error;
1469
        ret->target.has_allocation = true;
1470
    } else {
1471
        ret->target.allocation = ret->target.capacity;
1472 1473
    }

1474
    ret->target.path = virXPathString("string(./target/path)", ctxt);
1475
    if (options->formatFromString) {
1476
        char *format = virXPathString("string(./target/format/@type)", ctxt);
1477 1478 1479 1480 1481 1482
        if (format == NULL)
            ret->target.format = options->defaultFormat;
        else
            ret->target.format = (options->formatFromString)(format);

        if (ret->target.format < 0) {
1483
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1484
                           _("unknown volume format type %s"), format);
1485
            VIR_FREE(format);
1486
            goto error;
1487
        }
1488
        VIR_FREE(format);
1489 1490
    }

1491 1492 1493
    if (VIR_ALLOC(ret->target.perms) < 0)
        goto error;
    if (virStorageDefParsePerms(ctxt, ret->target.perms,
1494
                                "./target/permissions") < 0)
1495
        goto error;
1496

1497
    node = virXPathNode("./target/encryption", ctxt);
1498
    if (node != NULL) {
1499
        ret->target.encryption = virStorageEncryptionParseNode(ctxt->doc,
1500 1501
                                                               node);
        if (ret->target.encryption == NULL)
1502
            goto error;
1503 1504
    }

1505
    ret->target.compat = virXPathString("string(./target/compat)", ctxt);
1506 1507
    if (virStorageFileCheckCompat(ret->target.compat) < 0)
        goto error;
1508

C
Chunyan Liu 已提交
1509 1510 1511
    if (virXPathNode("./target/nocow", ctxt))
        ret->target.nocow = true;

1512
    if (virXPathNode("./target/features", ctxt)) {
1513 1514 1515 1516 1517 1518 1519
        if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
            goto error;

        if (!ret->target.compat && VIR_STRDUP(ret->target.compat, "1.1") < 0)
            goto error;

        if (!(ret->target.features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST)))
1520
            goto error;
1521 1522

        for (i = 0; i < n; i++) {
1523
            int f = virStorageFileFeatureTypeFromString((const char*)nodes[i]->name);
1524 1525

            if (f < 0) {
1526
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported feature %s"),
1527 1528 1529 1530 1531 1532 1533 1534
                               (const char*)nodes[i]->name);
                goto error;
            }
            ignore_value(virBitmapSetBit(ret->target.features, f));
        }
        VIR_FREE(nodes);
    }

1535
 cleanup:
1536
    VIR_FREE(nodes);
1537 1538 1539
    VIR_FREE(allocation);
    VIR_FREE(capacity);
    VIR_FREE(unit);
1540
    VIR_FREE(type);
1541
    VIR_FREE(backingStore);
1542 1543
    return ret;

1544
 error:
1545
    virStorageVolDefFree(ret);
1546 1547
    ret = NULL;
    goto cleanup;
1548 1549 1550
}

virStorageVolDefPtr
1551
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
1552
                          xmlDocPtr xml,
1553 1554
                          xmlNodePtr root,
                          unsigned int flags)
1555
{
1556 1557 1558
    xmlXPathContextPtr ctxt = NULL;
    virStorageVolDefPtr def = NULL;

1559
    if (!xmlStrEqual(root->name, BAD_CAST "volume")) {
1560
        virReportError(VIR_ERR_XML_ERROR,
1561 1562 1563
                       _("unexpected root element <%s>, "
                         "expecting <volume>"),
                       root->name);
1564 1565 1566 1567 1568
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1569
        virReportOOMError();
1570 1571 1572 1573
        goto cleanup;
    }

    ctxt->node = root;
1574
    def = virStorageVolDefParseXML(pool, ctxt, flags);
1575
 cleanup:
1576 1577 1578 1579 1580
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStorageVolDefPtr
1581
virStorageVolDefParse(virStoragePoolDefPtr pool,
1582
                      const char *xmlStr,
1583 1584
                      const char *filename,
                      unsigned int flags)
1585
{
1586
    virStorageVolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1587
    xmlDocPtr xml;
1588

1589
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_volume_definition)")))) {
1590
        ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml), flags);
J
Jiri Denemark 已提交
1591
        xmlFreeDoc(xml);
1592 1593 1594 1595 1596
    }

    return ret;
}

1597
virStorageVolDefPtr
1598
virStorageVolDefParseString(virStoragePoolDefPtr pool,
1599 1600
                            const char *xmlStr,
                            unsigned int flags)
1601
{
1602
    return virStorageVolDefParse(pool, xmlStr, NULL, flags);
1603 1604 1605
}

virStorageVolDefPtr
1606
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
1607 1608
                          const char *filename,
                          unsigned int flags)
1609
{
1610
    return virStorageVolDefParse(pool, NULL, filename, flags);
1611
}
1612

1613 1614 1615 1616 1617 1618
static void
virStorageVolTimestampFormat(virBufferPtr buf, const char *name,
                             struct timespec *ts)
{
    if (ts->tv_nsec < 0)
        return;
1619
    virBufferAsprintf(buf, "<%s>%llu", name,
1620 1621 1622 1623 1624 1625
                      (unsigned long long) ts->tv_sec);
    if (ts->tv_nsec)
       virBufferAsprintf(buf, ".%09ld", ts->tv_nsec);
    virBufferAsprintf(buf, "</%s>\n", name);
}

1626
static int
1627
virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
1628
                             virBufferPtr buf,
1629
                             virStorageSourcePtr def,
1630 1631
                             const char *type)
{
1632 1633
    virBufferAsprintf(buf, "<%s>\n", type);
    virBufferAdjustIndent(buf, 2);
1634

1635
    virBufferEscapeString(buf, "<path>%s</path>\n", def->path);
1636 1637 1638 1639

    if (options->formatToString) {
        const char *format = (options->formatToString)(def->format);
        if (!format) {
1640 1641 1642
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown volume format number %d"),
                           def->format);
1643 1644
            return -1;
        }
1645
        virBufferAsprintf(buf, "<format type='%s'/>\n", format);
1646 1647
    }

1648 1649 1650 1651 1652
    if (def->perms &&
        (def->perms->mode != (mode_t) -1 ||
         def->perms->uid != (uid_t) -1 ||
         def->perms->gid != (gid_t) -1 ||
         def->perms->label)) {
1653 1654
        virBufferAddLit(buf, "<permissions>\n");
        virBufferAdjustIndent(buf, 2);
1655

1656 1657 1658
        if (def->perms->mode != (mode_t) -1)
            virBufferAsprintf(buf, "<mode>0%o</mode>\n",
                              def->perms->mode);
1659 1660 1661 1662 1663 1664
        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);
1665

1666 1667
        virBufferEscapeString(buf, "<label>%s</label>\n",
                              def->perms->label);
1668

1669 1670 1671
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</permissions>\n");
    }
1672

1673
    if (def->timestamps) {
1674 1675
        virBufferAddLit(buf, "<timestamps>\n");
        virBufferAdjustIndent(buf, 2);
1676 1677 1678 1679
        virStorageVolTimestampFormat(buf, "atime", &def->timestamps->atime);
        virStorageVolTimestampFormat(buf, "mtime", &def->timestamps->mtime);
        virStorageVolTimestampFormat(buf, "ctime", &def->timestamps->ctime);
        virStorageVolTimestampFormat(buf, "btime", &def->timestamps->btime);
1680 1681
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</timestamps>\n");
1682 1683
    }

1684 1685
    if (def->encryption &&
        virStorageEncryptionFormat(buf, def->encryption) < 0)
1686
            return -1;
1687

1688
    virBufferEscapeString(buf, "<compat>%s</compat>\n", def->compat);
1689

1690
    if (def->features) {
1691
        size_t i;
1692 1693
        bool empty = virBitmapIsAllClear(def->features);

1694 1695 1696 1697 1698 1699
        if (empty) {
            virBufferAddLit(buf, "<features/>\n");
        } else {
            virBufferAddLit(buf, "<features>\n");
            virBufferAdjustIndent(buf, 2);
        }
1700 1701

        for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
1702
            if (virBitmapIsBitSet(def->features, i))
1703
                virBufferAsprintf(buf, "<%s/>\n",
1704
                                  virStorageFileFeatureTypeToString(i));
1705
        }
1706 1707 1708 1709
        if (!empty) {
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</features>\n");
        }
1710 1711
    }

1712 1713
    virBufferAdjustIndent(buf, -2);
    virBufferAsprintf(buf, "</%s>\n", type);
1714 1715
    return 0;
}
1716 1717

char *
1718
virStorageVolDefFormat(virStoragePoolDefPtr pool,
1719 1720
                       virStorageVolDefPtr def)
{
1721
    virStorageVolOptionsPtr options;
1722
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1723

1724
    options = virStorageVolOptionsForPoolType(pool->type);
1725 1726 1727
    if (options == NULL)
        return NULL;

1728 1729
    virBufferAsprintf(&buf, "<volume type='%s'>\n",
                      virStorageVolTypeToString(def->type));
1730 1731 1732 1733 1734 1735
    virBufferAdjustIndent(&buf, 2);

    virBufferEscapeString(&buf, "<name>%s</name>\n", def->name);
    virBufferEscapeString(&buf, "<key>%s</key>\n", def->key);
    virBufferAddLit(&buf, "<source>\n");
    virBufferAdjustIndent(&buf, 2);
1736 1737

    if (def->source.nextent) {
1738
        size_t i;
1739
        const char *thispath = NULL;
1740
        for (i = 0; i < def->source.nextent; i++) {
1741 1742 1743
            if (thispath == NULL ||
                STRNEQ(thispath, def->source.extents[i].path)) {
                if (thispath != NULL)
1744
                    virBufferAddLit(&buf, "</device>\n");
1745

1746
                virBufferEscapeString(&buf, "<device path='%s'>\n",
1747
                                      def->source.extents[i].path);
1748 1749
            }

1750 1751
            virBufferAdjustIndent(&buf, 2);
            virBufferAsprintf(&buf, "<extent start='%llu' end='%llu'/>\n",
1752 1753
                              def->source.extents[i].start,
                              def->source.extents[i].end);
1754
            virBufferAdjustIndent(&buf, -2);
1755 1756 1757
            thispath = def->source.extents[i].path;
        }
        if (thispath != NULL)
1758
            virBufferAddLit(&buf, "</device>\n");
1759 1760
    }

1761 1762 1763 1764
    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</source>\n");

    virBufferAsprintf(&buf, "<capacity unit='bytes'>%llu</capacity>\n",
1765
                      def->target.capacity);
1766
    virBufferAsprintf(&buf, "<allocation unit='bytes'>%llu</allocation>\n",
1767
                      def->target.allocation);
1768 1769 1770 1771 1772 1773
    /* 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);
1774

1775
    if (virStorageVolTargetDefFormat(options, &buf,
1776 1777
                                     &def->target, "target") < 0)
        goto cleanup;
1778

1779
    if (def->target.backingStore &&
1780
        virStorageVolTargetDefFormat(options, &buf,
1781 1782
                                     def->target.backingStore,
                                     "backingStore") < 0)
1783
        goto cleanup;
1784

1785
    virBufferAdjustIndent(&buf, -2);
E
Eric Blake 已提交
1786
    virBufferAddLit(&buf, "</volume>\n");
1787

1788 1789
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
1790

1791
    return virBufferContentAndReset(&buf);
1792

1793
 cleanup:
1794
    virBufferFreeAndReset(&buf);
1795 1796 1797 1798 1799
    return NULL;
}


virStoragePoolObjPtr
1800
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
1801 1802
                            const unsigned char *uuid)
{
1803
    size_t i;
1804

1805
    for (i = 0; i < pools->count; i++) {
1806
        virStoragePoolObjLock(pools->objs[i]);
1807 1808
        if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
            return pools->objs[i];
1809 1810
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1811 1812 1813 1814 1815

    return NULL;
}

virStoragePoolObjPtr
1816
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
1817 1818
                            const char *name)
{
1819
    size_t i;
1820

1821
    for (i = 0; i < pools->count; i++) {
1822
        virStoragePoolObjLock(pools->objs[i]);
1823 1824
        if (STREQ(pools->objs[i]->def->name, name))
            return pools->objs[i];
1825 1826
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1827 1828 1829 1830

    return NULL;
}

1831 1832
virStoragePoolObjPtr
virStoragePoolSourceFindDuplicateDevices(virStoragePoolObjPtr pool,
1833 1834
                                         virStoragePoolDefPtr def)
{
1835
    size_t i, j;
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846

    for (i = 0; i < pool->def->source.ndevice; i++) {
        for (j = 0; j < def->source.ndevice; j++) {
            if (STREQ(pool->def->source.devices[i].path, def->source.devices[j].path))
                return pool;
        }
    }

    return NULL;
}

1847 1848 1849
void
virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
{
1850
    size_t i;
1851
    for (i = 0; i < pool->volumes.count; i++)
1852 1853 1854 1855
        virStorageVolDefFree(pool->volumes.objs[i]);

    VIR_FREE(pool->volumes.objs);
    pool->volumes.count = 0;
1856 1857 1858 1859
}

virStorageVolDefPtr
virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
1860 1861
                          const char *key)
{
1862
    size_t i;
1863

1864
    for (i = 0; i < pool->volumes.count; i++)
1865 1866
        if (STREQ(pool->volumes.objs[i]->key, key))
            return pool->volumes.objs[i];
1867 1868 1869 1870 1871 1872

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
1873 1874
                           const char *path)
{
1875
    size_t i;
1876

1877
    for (i = 0; i < pool->volumes.count; i++)
1878 1879
        if (STREQ(pool->volumes.objs[i]->target.path, path))
            return pool->volumes.objs[i];
1880 1881 1882 1883 1884 1885

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByName(virStoragePoolObjPtr pool,
1886 1887
                           const char *name)
{
1888
    size_t i;
1889

1890
    for (i = 0; i < pool->volumes.count; i++)
1891 1892
        if (STREQ(pool->volumes.objs[i]->name, name))
            return pool->volumes.objs[i];
1893 1894 1895 1896 1897

    return NULL;
}

virStoragePoolObjPtr
1898
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
1899 1900
                           virStoragePoolDefPtr def)
{
1901 1902
    virStoragePoolObjPtr pool;

1903
    if ((pool = virStoragePoolObjFindByName(pools, def->name))) {
1904 1905 1906 1907
        if (!virStoragePoolObjIsActive(pool)) {
            virStoragePoolDefFree(pool->def);
            pool->def = def;
        } else {
1908
            virStoragePoolDefFree(pool->newDef);
1909 1910 1911 1912 1913
            pool->newDef = def;
        }
        return pool;
    }

1914
    if (VIR_ALLOC(pool) < 0)
1915 1916
        return NULL;

1917
    if (virMutexInit(&pool->lock) < 0) {
1918 1919
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot initialize mutex"));
1920 1921 1922
        VIR_FREE(pool);
        return NULL;
    }
1923
    virStoragePoolObjLock(pool);
1924 1925
    pool->active = 0;

1926
    if (VIR_APPEND_ELEMENT_COPY(pools->objs, pools->count, pool) < 0) {
1927
        virStoragePoolObjUnlock(pool);
1928 1929 1930
        virStoragePoolObjFree(pool);
        return NULL;
    }
1931
    pool->def = def;
1932 1933 1934 1935 1936

    return pool;
}

static virStoragePoolObjPtr
1937
virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
1938 1939
                      const char *file,
                      const char *path,
1940 1941
                      const char *autostartLink)
{
1942 1943 1944
    virStoragePoolDefPtr def;
    virStoragePoolObjPtr pool;

1945
    if (!(def = virStoragePoolDefParseFile(path)))
1946 1947 1948
        return NULL;

    if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
1949
        virReportError(VIR_ERR_XML_ERROR,
1950 1951
                       _("Storage pool config filename '%s' does "
                         "not match pool name '%s'"),
1952
                       path, def->name);
1953 1954 1955 1956
        virStoragePoolDefFree(def);
        return NULL;
    }

1957
    if (!(pool = virStoragePoolObjAssignDef(pools, def))) {
1958 1959 1960 1961
        virStoragePoolDefFree(def);
        return NULL;
    }

1962
    VIR_FREE(pool->configFile);  /* for driver reload */
1963
    if (VIR_STRDUP(pool->configFile, path) < 0) {
1964
        virStoragePoolObjRemove(pools, pool);
1965 1966
        return NULL;
    }
1967
    VIR_FREE(pool->autostartLink); /* for driver reload */
1968
    if (VIR_STRDUP(pool->autostartLink, autostartLink) < 0) {
1969
        virStoragePoolObjRemove(pools, pool);
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
        return NULL;
    }

    pool->autostart = virFileLinkPointsTo(pool->autostartLink,
                                          pool->configFile);

    return pool;
}


1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
virStoragePoolObjPtr
virStoragePoolLoadState(virStoragePoolObjListPtr pools,
                        const char *stateDir,
                        const char *name)
{
    char *stateFile = NULL;
    virStoragePoolDefPtr def = NULL;
    virStoragePoolObjPtr pool = NULL;
    xmlDocPtr xml = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr node = NULL;

    if (!(stateFile = virFileBuildPath(stateDir, name, ".xml")))
        goto error;

    if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(pool state)"), &ctxt)))
        goto error;

    if (!(node = virXPathNode("//pool", ctxt))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not find any 'pool' element in state file"));
        goto error;
    }

    ctxt->node = node;
    if (!(def = virStoragePoolDefParseXML(ctxt)))
        goto error;

2008
    if (STRNEQ(name, def->name)) {
2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Storage pool state file '%s' does not match "
                         "pool name '%s'"),
                       stateFile, def->name);
        goto error;
    }

    /* create the object */
    if (!(pool = virStoragePoolObjAssignDef(pools, def)))
        goto error;

    /* XXX: future handling of some additional useful status data,
     * for now, if a status file for a pool exists, the pool will be marked
     * as active
     */

    pool->active = 1;

 cleanup:
    VIR_FREE(stateFile);
2029
    xmlFreeDoc(xml);
2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
    xmlXPathFreeContext(ctxt);
    return pool;

 error:
    virStoragePoolDefFree(def);
    goto cleanup;
}


int
virStoragePoolLoadAllState(virStoragePoolObjListPtr pools,
                           const char *stateDir)
{
    DIR *dir;
    struct dirent *entry;
    int ret = -1;
J
Ján Tomko 已提交
2046
    int rc;
2047

J
Ján Tomko 已提交
2048 2049
    if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
        return rc;
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061

    while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
        virStoragePoolObjPtr pool;

        if (!virFileStripSuffix(entry->d_name, ".xml"))
            continue;

        if (!(pool = virStoragePoolLoadState(pools, stateDir, entry->d_name)))
            continue;
        virStoragePoolObjUnlock(pool);
    }

J
Ján Tomko 已提交
2062
    VIR_DIR_CLOSE(dir);
2063 2064 2065 2066
    return ret;
}


2067
int
2068
virStoragePoolLoadAllConfigs(virStoragePoolObjListPtr pools,
2069
                             const char *configDir,
2070 2071
                             const char *autostartDir)
{
2072 2073
    DIR *dir;
    struct dirent *entry;
E
Eric Blake 已提交
2074
    int ret;
J
Ján Tomko 已提交
2075
    int rc;
2076

J
Ján Tomko 已提交
2077 2078
    if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
        return rc;
2079

E
Eric Blake 已提交
2080
    while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
2081 2082
        char *path;
        char *autostartLink;
2083
        virStoragePoolObjPtr pool;
2084 2085 2086 2087

        if (!virFileHasSuffix(entry->d_name, ".xml"))
            continue;

2088
        if (!(path = virFileBuildPath(configDir, entry->d_name, NULL)))
2089 2090
            continue;

2091 2092 2093
        if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
                                               NULL))) {
            VIR_FREE(path);
2094 2095 2096
            continue;
        }

2097
        pool = virStoragePoolObjLoad(pools, entry->d_name, path,
2098
                                     autostartLink);
2099 2100
        if (pool)
            virStoragePoolObjUnlock(pool);
2101 2102 2103

        VIR_FREE(path);
        VIR_FREE(autostartLink);
2104 2105
    }

J
Ján Tomko 已提交
2106
    VIR_DIR_CLOSE(dir);
E
Eric Blake 已提交
2107
    return ret;
2108 2109
}

2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124

static int virStoragePoolSaveXML(const char *path,
                                 virStoragePoolDefPtr def,
                                 const char *xml)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;

    virUUIDFormat(def->uuid, uuidstr);
    ret = virXMLSaveFile(path,
                         virXMLPickShellSafeComment(def->name, uuidstr),
                         "pool-edit", xml);

    return ret;
}
2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158


int
virStoragePoolSaveState(const char *stateFile,
                        virStoragePoolDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    int ret = -1;
    char *xml;

    virBufferAddLit(&buf, "<poolstate>\n");
    virBufferAdjustIndent(&buf, 2);

    if (virStoragePoolDefFormatBuf(&buf, def) < 0)
        goto error;

    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</poolstate>\n");

    if (virBufferCheckError(&buf) < 0)
        goto error;

    if (!(xml = virBufferContentAndReset(&buf)))
        goto error;

    if (virStoragePoolSaveXML(stateFile, def, xml))
        goto error;

    ret = 0;

 error:
    VIR_FREE(xml);
    return ret;
}
2159 2160


2161
int
2162
virStoragePoolSaveConfig(const char *configFile,
2163 2164
                         virStoragePoolDefPtr def)
{
2165
    char *xml;
2166
    int ret = -1;
2167

2168 2169 2170 2171 2172 2173
    if (!(xml = virStoragePoolDefFormat(def))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to generate XML"));
        return -1;
    }

2174 2175
    if (virStoragePoolSaveXML(configFile, def, xml))
        goto cleanup;
2176

2177 2178 2179
    ret = 0;
 cleanup:
    VIR_FREE(xml);
2180 2181 2182 2183 2184 2185 2186 2187
    return ret;
}

int
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
                         virStoragePoolObjPtr pool,
                         virStoragePoolDefPtr def)
{
2188
    if (!pool->configFile) {
2189 2190
        if (virFileMakePath(driver->configDir) < 0) {
            virReportSystemError(errno,
C
Cole Robinson 已提交
2191 2192
                                 _("cannot create config directory %s"),
                                 driver->configDir);
2193 2194 2195
            return -1;
        }

2196 2197
        if (!(pool->configFile = virFileBuildPath(driver->configDir,
                                                  def->name, ".xml"))) {
2198 2199 2200
            return -1;
        }

2201 2202
        if (!(pool->autostartLink = virFileBuildPath(driver->autostartDir,
                                                     def->name, ".xml"))) {
2203
            VIR_FREE(pool->configFile);
2204 2205 2206 2207
            return -1;
        }
    }

2208
    return virStoragePoolSaveConfig(pool->configFile, def);
2209 2210 2211
}

int
2212 2213
virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool)
{
2214
    if (!pool->configFile) {
2215 2216
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no config file for %s"), pool->def->name);
2217 2218 2219 2220
        return -1;
    }

    if (unlink(pool->configFile) < 0) {
2221 2222 2223
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot remove config for %s"),
                       pool->def->name);
2224 2225 2226 2227 2228
        return -1;
    }

    return 0;
}
2229

2230
virStoragePoolSourcePtr
2231
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
2232 2233 2234
{
    virStoragePoolSourcePtr source;

2235
    if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0)
2236 2237 2238 2239 2240 2241 2242 2243
        return NULL;

    source = &list->sources[list->nsources++];
    memset(source, 0, sizeof(*source));

    return source;
}

2244 2245
char *
virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def)
2246
{
2247
    virStoragePoolOptionsPtr options;
2248
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2249
    const char *type;
2250
    size_t i;
2251

2252
    options = virStoragePoolOptionsForPoolType(def->type);
2253 2254 2255
    if (options == NULL)
        return NULL;

2256
    type = virStoragePoolTypeToString(def->type);
2257
    if (!type) {
2258 2259
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected pool type"));
2260 2261 2262 2263
        goto cleanup;
    }

    virBufferAddLit(&buf, "<sources>\n");
2264
    virBufferAdjustIndent(&buf, 2);
2265

2266
    for (i = 0; i < def->nsources; i++)
2267
        virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
2268

2269
    virBufferAdjustIndent(&buf, -2);
2270 2271
    virBufferAddLit(&buf, "</sources>\n");

2272 2273
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
2274 2275

    return virBufferContentAndReset(&buf);
2276

2277
 cleanup:
2278
    virBufferFreeAndReset(&buf);
2279
    return NULL;
2280
}
D
Daniel P. Berrange 已提交
2281 2282


2283 2284 2285 2286 2287 2288 2289 2290 2291 2292
/*
 * virStoragePoolObjIsDuplicate:
 * @doms : virStoragePoolObjListPtr to search
 * @def  : virStoragePoolDefPtr definition of pool to lookup
 * @check_active: If true, ensure that pool is not active
 *
 * Returns: -1 on error
 *          0 if pool is new
 *          1 if pool is a duplicate
 */
2293 2294 2295 2296
int
virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
                             virStoragePoolDefPtr def,
                             unsigned int check_active)
2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307
{
    int ret = -1;
    virStoragePoolObjPtr pool = NULL;

    /* See if a Pool with matching UUID already exists */
    pool = virStoragePoolObjFindByUUID(pools, def->uuid);
    if (pool) {
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(pool->def->name, def->name)) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(pool->def->uuid, uuidstr);
2308 2309 2310
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("pool '%s' is already defined with uuid %s"),
                           pool->def->name, uuidstr);
2311 2312 2313 2314 2315 2316
            goto cleanup;
        }

        if (check_active) {
            /* UUID & name match, but if Pool is already active, refuse it */
            if (virStoragePoolObjIsActive(pool)) {
2317 2318 2319
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("pool is already active as '%s'"),
                               pool->def->name);
2320 2321 2322 2323
                goto cleanup;
            }
        }

J
Ján Tomko 已提交
2324
        ret = 1;
2325 2326 2327 2328 2329 2330
    } else {
        /* UUID does not match, but if a name matches, refuse it */
        pool = virStoragePoolObjFindByName(pools, def->name);
        if (pool) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(pool->def->uuid, uuidstr);
2331 2332 2333
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("pool '%s' already exists with uuid %s"),
                           def->name, uuidstr);
2334 2335
            goto cleanup;
        }
J
Ján Tomko 已提交
2336
        ret = 0;
2337 2338
    }

2339
 cleanup:
2340 2341 2342 2343 2344
    if (pool)
        virStoragePoolObjUnlock(pool);
    return ret;
}

2345

2346 2347 2348
static int
getSCSIHostNumber(virStoragePoolSourceAdapter adapter,
                  unsigned int *hostnum)
2349
{
2350 2351 2352 2353 2354
    int ret = -1;
    unsigned int num;
    char *name = NULL;

    if (adapter.data.scsi_host.has_parent) {
2355
        virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
2356 2357
        unsigned int unique_id = adapter.data.scsi_host.unique_id;

2358
        if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
2359 2360 2361 2362 2363
                                                    addr.bus,
                                                    addr.slot,
                                                    addr.function,
                                                    unique_id)))
            goto cleanup;
2364
        if (virSCSIHostGetNumber(name, &num) < 0)
2365 2366
            goto cleanup;
    } else {
2367
        if (virSCSIHostGetNumber(adapter.data.scsi_host.name, &num) < 0)
2368 2369 2370 2371 2372 2373 2374 2375 2376
            goto cleanup;
    }

    *hostnum = num;
    ret = 0;

 cleanup:
    VIR_FREE(name);
    return ret;
2377
}
2378

2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393

static bool
virStorageIsSameHostnum(const char *name,
                        unsigned int scsi_hostnum)
{
    unsigned int fc_hostnum;

    if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 &&
        scsi_hostnum == fc_hostnum)
        return true;

    return false;
}


2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408
/*
 * matchFCHostToSCSIHost:
 *
 * @conn: Connection pointer
 * @fc_adapter: fc_host adapter (either def or pool->def)
 * @scsi_hostnum: Already determined "scsi_pool" hostnum
 *
 * Returns true/false whether there is a match between the incoming
 *         fc_adapter host# and the scsi_host host#
 */
static bool
matchFCHostToSCSIHost(virConnectPtr conn,
                      virStoragePoolSourceAdapter fc_adapter,
                      unsigned int scsi_hostnum)
{
2409
    bool ret = false;
2410
    char *name = NULL;
2411
    char *scsi_host_name = NULL;
2412 2413
    char *parent_name = NULL;

2414
    /* If we have a parent defined, get its hostnum, and compare to the
2415 2416 2417
     * scsi_hostnum. If they are the same, then we have a match
     */
    if (fc_adapter.data.fchost.parent &&
2418
        virStorageIsSameHostnum(fc_adapter.data.fchost.parent, scsi_hostnum))
2419 2420 2421 2422 2423
        return true;

    /* If we find an fc_adapter name, then either libvirt created a vHBA
     * for this fc_host or a 'virsh nodedev-create' generated a vHBA.
     */
2424 2425
    if ((name = virVHBAGetHostByWWN(NULL, fc_adapter.data.fchost.wwnn,
                                    fc_adapter.data.fchost.wwpn))) {
2426 2427 2428 2429

        /* Get the scsi_hostN for the vHBA in order to see if it
         * matches our scsi_hostnum
         */
2430
        if (virStorageIsSameHostnum(name, scsi_hostnum)) {
2431 2432
            ret = true;
            goto cleanup;
2433 2434 2435 2436 2437 2438 2439 2440
        }

        /* We weren't provided a parent, so we have to query the node
         * device driver in order to ascertain the parent of the vHBA.
         * If the parent fc_hostnum is the same as the scsi_hostnum, we
         * have a match.
         */
        if (conn && !fc_adapter.data.fchost.parent) {
2441 2442
            if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
                goto cleanup;
2443 2444
            if ((parent_name = virNodeDeviceGetParentName(conn,
                                                          scsi_host_name))) {
2445
                if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) {
2446 2447
                    ret = true;
                    goto cleanup;
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
                }
            } else {
                /* Throw away the error and fall through */
                virResetLastError();
                VIR_DEBUG("Could not determine parent vHBA");
            }
        }
    }

    /* NB: Lack of a name means that this vHBA hasn't yet been created,
     *     which means our scsi_host cannot be using the vHBA. Furthermore,
     *     lack of a provided parent means libvirt is going to choose the
     *     "best" fc_host capable adapter based on availabilty. That could
     *     conflict with an existing scsi_host definition, but there's no
     *     way to know that now.
     */
2464 2465 2466 2467 2468 2469

 cleanup:
    VIR_FREE(name);
    VIR_FREE(parent_name);
    VIR_FREE(scsi_host_name);
    return ret;
2470 2471
}

2472 2473 2474 2475
static bool
matchSCSIAdapterParent(virStoragePoolObjPtr pool,
                       virStoragePoolDefPtr def)
{
2476
    virPCIDeviceAddressPtr pooladdr =
2477
        &pool->def->source.adapter.data.scsi_host.parentaddr;
2478
    virPCIDeviceAddressPtr defaddr =
2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493
        &def->source.adapter.data.scsi_host.parentaddr;
    int pool_unique_id =
        pool->def->source.adapter.data.scsi_host.unique_id;
    int def_unique_id =
        def->source.adapter.data.scsi_host.unique_id;
    if (pooladdr->domain == defaddr->domain &&
        pooladdr->bus == defaddr->bus &&
        pooladdr->slot == defaddr->slot &&
        pooladdr->function == defaddr->function &&
        pool_unique_id == def_unique_id) {
        return true;
    }
    return false;
}

2494 2495 2496 2497 2498 2499 2500
static bool
virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc,
                                    virStoragePoolSourcePtr defsrc)
{
    if (poolsrc->nhost != 1 && defsrc->nhost != 1)
        return false;

2501 2502
    if (defsrc->hosts[0].port &&
        poolsrc->hosts[0].port != defsrc->hosts[0].port)
2503 2504
        return false;

2505 2506 2507
    return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name);
}

2508

2509 2510 2511 2512 2513 2514 2515
static bool
virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr matchpool,
                               virStoragePoolDefPtr def)
{
    virStoragePoolSourcePtr poolsrc = &matchpool->def->source;
    virStoragePoolSourcePtr defsrc = &def->source;

2516
    /* NB: Do not check the source host name */
2517 2518 2519 2520 2521 2522 2523
    if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn))
        return false;

    return true;
}


2524
int
2525 2526
virStoragePoolSourceFindDuplicate(virConnectPtr conn,
                                  virStoragePoolObjListPtr pools,
2527
                                  virStoragePoolDefPtr def)
2528
{
2529
    size_t i;
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539
    int ret = 1;
    virStoragePoolObjPtr pool = NULL;
    virStoragePoolObjPtr matchpool = NULL;

    /* Check the pool list for duplicate underlying storage */
    for (i = 0; i < pools->count; i++) {
        pool = pools->objs[i];
        if (def->type != pool->def->type)
            continue;

N
Nitesh Konkar 已提交
2540
        /* Don't match against ourself if re-defining existing pool ! */
2541 2542 2543
        if (STREQ(pool->def->name, def->name))
            continue;

2544 2545
        virStoragePoolObjLock(pool);

2546
        switch ((virStoragePoolType)pool->def->type) {
2547 2548 2549 2550
        case VIR_STORAGE_POOL_DIR:
            if (STREQ(pool->def->target.path, def->target.path))
                matchpool = pool;
            break;
2551

2552
        case VIR_STORAGE_POOL_GLUSTER:
2553 2554 2555 2556 2557 2558 2559 2560
            if (STREQ(pool->def->source.name, def->source.name) &&
                STREQ_NULLABLE(pool->def->source.dir, def->source.dir) &&
                virStoragePoolSourceMatchSingleHost(&pool->def->source,
                                                    &def->source))
                matchpool = pool;
            break;

        case VIR_STORAGE_POOL_NETFS:
2561 2562 2563
            if (STREQ(pool->def->source.dir, def->source.dir) &&
                virStoragePoolSourceMatchSingleHost(&pool->def->source,
                                                    &def->source))
2564 2565
                matchpool = pool;
            break;
2566

2567
        case VIR_STORAGE_POOL_SCSI:
2568
            if (pool->def->source.adapter.type ==
2569 2570
                VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST &&
                def->source.adapter.type ==
2571 2572 2573 2574 2575 2576 2577
                VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
                if (STREQ(pool->def->source.adapter.data.fchost.wwnn,
                          def->source.adapter.data.fchost.wwnn) &&
                    STREQ(pool->def->source.adapter.data.fchost.wwpn,
                          def->source.adapter.data.fchost.wwpn))
                    matchpool = pool;
            } else if (pool->def->source.adapter.type ==
2578 2579
                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST &&
                       def->source.adapter.type ==
2580
                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
2581 2582
                unsigned int pool_hostnum, def_hostnum;

2583 2584 2585 2586 2587 2588 2589
                if (pool->def->source.adapter.data.scsi_host.has_parent &&
                    def->source.adapter.data.scsi_host.has_parent &&
                    matchSCSIAdapterParent(pool, def)) {
                    matchpool = pool;
                    break;
                }

2590 2591 2592
                if (getSCSIHostNumber(pool->def->source.adapter,
                                      &pool_hostnum) < 0 ||
                    getSCSIHostNumber(def->source.adapter, &def_hostnum) < 0)
2593
                    break;
2594 2595
                if (pool_hostnum == def_hostnum)
                    matchpool = pool;
2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627
            } else if (pool->def->source.adapter.type ==
                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST &&
                       def->source.adapter.type ==
                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
                unsigned int scsi_hostnum;

                /* Get the scsi_hostN for the scsi_host source adapter def */
                if (getSCSIHostNumber(def->source.adapter,
                                      &scsi_hostnum) < 0)
                    break;

                if (matchFCHostToSCSIHost(conn, pool->def->source.adapter,
                                          scsi_hostnum)) {
                    matchpool = pool;
                    break;
                }

            } else if (pool->def->source.adapter.type ==
                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST &&
                       def->source.adapter.type ==
                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
                unsigned int scsi_hostnum;

                if (getSCSIHostNumber(pool->def->source.adapter,
                                      &scsi_hostnum) < 0)
                    break;

                if (matchFCHostToSCSIHost(conn, def->source.adapter,
                                          scsi_hostnum)) {
                    matchpool = pool;
                    break;
                }
2628
            }
2629 2630 2631 2632
            break;
        case VIR_STORAGE_POOL_ISCSI:
            matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
            if (matchpool) {
2633 2634
                if (!virStoragePoolSourceISCSIMatch(matchpool, def))
                    matchpool = NULL;
2635 2636 2637 2638 2639
            }
            break;
        case VIR_STORAGE_POOL_FS:
        case VIR_STORAGE_POOL_LOGICAL:
        case VIR_STORAGE_POOL_DISK:
2640
        case VIR_STORAGE_POOL_ZFS:
2641 2642
            matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
            break;
2643 2644 2645 2646 2647
        case VIR_STORAGE_POOL_SHEEPDOG:
            if (virStoragePoolSourceMatchSingleHost(&pool->def->source,
                                                    &def->source))
                matchpool = pool;
            break;
2648
        case VIR_STORAGE_POOL_MPATH:
2649 2650 2651
            /* Only one mpath pool is valid per host */
            matchpool = pool;
            break;
2652 2653 2654 2655
        case VIR_STORAGE_POOL_VSTORAGE:
            if (STREQ(pool->def->source.name, def->source.name))
                matchpool = pool;
            break;
2656 2657
        case VIR_STORAGE_POOL_RBD:
        case VIR_STORAGE_POOL_LAST:
2658 2659 2660
            break;
        }
        virStoragePoolObjUnlock(pool);
2661 2662 2663

        if (matchpool)
            break;
2664 2665 2666
    }

    if (matchpool) {
2667 2668 2669
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Storage source conflict with pool: '%s'"),
                       matchpool->def->name);
2670 2671 2672 2673
        ret = -1;
    }
    return ret;
}
2674

2675 2676
void
virStoragePoolObjLock(virStoragePoolObjPtr obj)
2677
{
2678
    virMutexLock(&obj->lock);
2679 2680
}

2681 2682
void
virStoragePoolObjUnlock(virStoragePoolObjPtr obj)
2683
{
2684
    virMutexUnlock(&obj->lock);
2685
}
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736

#define MATCH(FLAG) (flags & (FLAG))
static bool
virStoragePoolMatch(virStoragePoolObjPtr poolobj,
                    unsigned int flags)
{
    /* filter by active state */
    if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) &&
        !((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE) &&
           virStoragePoolObjIsActive(poolobj)) ||
          (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE) &&
           !virStoragePoolObjIsActive(poolobj))))
        return false;

    /* filter by persistence */
    if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT) &&
        !((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT) &&
           poolobj->configFile) ||
          (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT) &&
           !poolobj->configFile)))
        return false;

    /* filter by autostart option */
    if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART) &&
        !((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART) &&
           poolobj->autostart) ||
          (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART) &&
           !poolobj->autostart)))
        return false;

    /* filter by pool type */
    if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)) {
        if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DIR) &&
               (poolobj->def->type == VIR_STORAGE_POOL_DIR))     ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FS) &&
               (poolobj->def->type == VIR_STORAGE_POOL_FS))      ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) &&
               (poolobj->def->type == VIR_STORAGE_POOL_NETFS))   ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL) &&
               (poolobj->def->type == VIR_STORAGE_POOL_LOGICAL)) ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DISK) &&
               (poolobj->def->type == VIR_STORAGE_POOL_DISK))    ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI) &&
               (poolobj->def->type == VIR_STORAGE_POOL_ISCSI))   ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SCSI) &&
               (poolobj->def->type == VIR_STORAGE_POOL_SCSI))    ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_MPATH) &&
               (poolobj->def->type == VIR_STORAGE_POOL_MPATH))   ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) &&
               (poolobj->def->type == VIR_STORAGE_POOL_RBD))     ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) &&
2737 2738
               (poolobj->def->type == VIR_STORAGE_POOL_SHEEPDOG)) ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER) &&
2739 2740 2741 2742 2743
               (poolobj->def->type == VIR_STORAGE_POOL_GLUSTER)) ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ZFS) &&
               poolobj->def->type == VIR_STORAGE_POOL_ZFS)       ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE) &&
               poolobj->def->type == VIR_STORAGE_POOL_VSTORAGE)))
2744 2745 2746 2747 2748 2749 2750 2751
            return false;
    }

    return true;
}
#undef MATCH

int
2752 2753 2754 2755 2756
virStoragePoolObjListExport(virConnectPtr conn,
                            virStoragePoolObjList poolobjs,
                            virStoragePoolPtr **pools,
                            virStoragePoolObjListFilter filter,
                            unsigned int flags)
2757 2758 2759 2760 2761
{
    virStoragePoolPtr *tmp_pools = NULL;
    virStoragePoolPtr pool = NULL;
    int npools = 0;
    int ret = -1;
2762
    size_t i;
2763

2764 2765
    if (pools && VIR_ALLOC_N(tmp_pools, poolobjs.count + 1) < 0)
        goto cleanup;
2766 2767 2768 2769

    for (i = 0; i < poolobjs.count; i++) {
        virStoragePoolObjPtr poolobj = poolobjs.objs[i];
        virStoragePoolObjLock(poolobj);
2770 2771
        if ((!filter || filter(conn, poolobj->def)) &&
            virStoragePoolMatch(poolobj, flags)) {
2772 2773 2774
            if (pools) {
                if (!(pool = virGetStoragePool(conn,
                                               poolobj->def->name,
2775 2776
                                               poolobj->def->uuid,
                                               NULL, NULL))) {
2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795
                    virStoragePoolObjUnlock(poolobj);
                    goto cleanup;
                }
                tmp_pools[npools] = pool;
            }
            npools++;
        }
        virStoragePoolObjUnlock(poolobj);
    }

    if (tmp_pools) {
        /* trim the array to the final size */
        ignore_value(VIR_REALLOC_N(tmp_pools, npools + 1));
        *pools = tmp_pools;
        tmp_pools = NULL;
    }

    ret = npools;

2796
 cleanup:
2797
    if (tmp_pools) {
2798 2799
        for (i = 0; i < npools; i++)
            virObjectUnref(tmp_pools[i]);
2800 2801 2802 2803 2804
    }

    VIR_FREE(tmp_pools);
    return ret;
}