storage_conf.c 65.5 KB
Newer Older
1 2 3
/*
 * storage_conf.c: config handling for storage driver
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2006-2012 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 "storage_conf.h"
39
#include "virstoragefile.h"
40

41
#include "virxml.h"
42
#include "viruuid.h"
43
#include "virbuffer.h"
44
#include "viralloc.h"
E
Eric Blake 已提交
45
#include "virfile.h"
46
#include "virstring.h"
47

48 49
#define VIR_FROM_THIS VIR_FROM_STORAGE

50 51
#define DEFAULT_POOL_PERM_MODE 0755
#define DEFAULT_VOL_PERM_MODE  0600
52

53 54 55 56
VIR_ENUM_IMPL(virStoragePool,
              VIR_STORAGE_POOL_LAST,
              "dir", "fs", "netfs",
              "logical", "disk", "iscsi",
57
              "scsi", "mpath", "rbd", "sheepdog")
58 59 60 61 62

VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
              VIR_STORAGE_POOL_FS_LAST,
              "auto", "ext2", "ext3",
              "ext4", "ufs", "iso9660", "udf",
J
Jim Fehlig 已提交
63
              "gfs", "gfs2", "vfat", "hfs+", "xfs", "ocfs2")
64 65 66

VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
              VIR_STORAGE_POOL_NETFS_LAST,
67
              "auto", "nfs", "glusterfs", "cifs")
68 69 70 71

VIR_ENUM_IMPL(virStoragePoolFormatDisk,
              VIR_STORAGE_POOL_DISK_LAST,
              "unknown", "dos", "dvh", "gpt",
72
              "mac", "bsd", "pc98", "sun", "lvm2")
73 74 75

VIR_ENUM_IMPL(virStoragePoolFormatLogical,
              VIR_STORAGE_POOL_LOGICAL_LAST,
76
              "unknown", "lvm2")
77 78 79 80 81 82 83


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

86 87
VIR_ENUM_IMPL(virStoragePartedFsType,
              VIR_STORAGE_PARTED_FS_TYPE_LAST,
88
              "ext2", "ext2", "fat16",
89 90 91
              "fat32", "linux-swap",
              "ext2", "ext2",
              "extended")
92

93 94 95 96
VIR_ENUM_IMPL(virStoragePoolSourceAdapterType,
              VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST,
              "default", "scsi_host", "fc_host")

97 98 99 100 101 102 103 104 105
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 {
106
    int defaultFormat;
107 108 109 110 111 112
    virStorageVolFormatToString formatToString;
    virStorageVolFormatFromString formatFromString;
};

/* Flags to indicate mandatory components in the pool source */
enum {
O
Osier Yang 已提交
113 114 115 116 117 118 119
    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),
120 121 122 123 124
};

typedef struct _virStoragePoolOptions virStoragePoolOptions;
typedef virStoragePoolOptions *virStoragePoolOptionsPtr;
struct _virStoragePoolOptions {
E
Eric Blake 已提交
125
    unsigned int flags;
126 127 128 129 130 131 132 133 134 135 136 137 138
    int defaultFormat;
    virStoragePoolFormatToString formatToString;
    virStoragePoolFormatFromString formatFromString;
};

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

E
Eric Blake 已提交
139 140 141 142 143 144 145 146 147
static int
virStorageVolumeFormatFromString(const char *format)
{
    int ret = virStorageFileFormatTypeFromString(format);
    if (ret == VIR_STORAGE_FILE_NONE)
        return -1;
    return ret;
}

148
static virStoragePoolTypeInfo poolTypeInfo[] = {
149 150 151 152 153 154 155 156
    {.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,
     },
157
    },
158 159 160 161 162 163
    {.poolType = VIR_STORAGE_POOL_DIR,
     .volOptions = {
         .defaultFormat = VIR_STORAGE_FILE_RAW,
         .formatFromString = virStorageVolumeFormatFromString,
         .formatToString = virStorageFileFormatTypeToString,
     },
164
    },
165 166 167 168 169 170 171
    {.poolType = VIR_STORAGE_POOL_FS,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
         .defaultFormat = VIR_STORAGE_POOL_FS_AUTO,
         .formatFromString = virStoragePoolFormatFileSystemTypeFromString,
         .formatToString = virStoragePoolFormatFileSystemTypeToString,
      },
172
      .volOptions = {
173 174 175 176
         .defaultFormat = VIR_STORAGE_FILE_RAW,
         .formatFromString = virStorageVolumeFormatFromString,
         .formatToString = virStorageFileFormatTypeToString,
      },
177
    },
178 179 180 181 182 183 184 185
    {.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,
      },
186
      .volOptions = {
187 188 189 190
         .defaultFormat = VIR_STORAGE_FILE_RAW,
         .formatFromString = virStorageVolumeFormatFromString,
         .formatToString = virStorageFileFormatTypeToString,
      },
191
    },
192 193 194 195 196 197
    {.poolType = VIR_STORAGE_POOL_ISCSI,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                   VIR_STORAGE_POOL_SOURCE_DEVICE |
                   VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
      },
198
      .volOptions = {
199 200 201 202 203 204 205 206 207 208
         .formatToString = virStoragePoolFormatDiskTypeToString,
      }
    },
    {.poolType = VIR_STORAGE_POOL_SCSI,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER),
     },
     .volOptions = {
         .formatToString = virStoragePoolFormatDiskTypeToString,
     }
209
    },
210 211 212 213 214 215
    {.poolType = VIR_STORAGE_POOL_RBD,
     .poolOptions = {
         .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                   VIR_STORAGE_POOL_SOURCE_NETWORK |
                   VIR_STORAGE_POOL_SOURCE_NAME),
      },
216
      .volOptions = {
217 218 219
          .defaultFormat = VIR_STORAGE_FILE_RAW,
          .formatToString = virStoragePoolFormatDiskTypeToString,
      }
220
    },
221 222 223 224 225 226 227 228 229 230
    {.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,
     }
231
    },
232 233 234 235
    {.poolType = VIR_STORAGE_POOL_MPATH,
     .volOptions = {
         .formatToString = virStoragePoolFormatDiskTypeToString,
     }
236
    },
237 238 239 240 241 242 243 244 245 246 247 248
    {.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,
     },
249 250 251 252 253
    }
};


static virStoragePoolTypeInfoPtr
254 255
virStoragePoolTypeInfoLookup(int type)
{
256
    unsigned int i;
257
    for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo); i++)
258 259 260
        if (poolTypeInfo[i].poolType == type)
            return &poolTypeInfo[i];

261 262
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("missing backend for pool type %d"), type);
263 264 265 266
    return NULL;
}

static virStoragePoolOptionsPtr
267 268
virStoragePoolOptionsForPoolType(int type)
{
269 270 271 272 273 274 275
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->poolOptions;
}

static virStorageVolOptionsPtr
276 277
virStorageVolOptionsForPoolType(int type)
{
278 279 280 281 282 283 284
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->volOptions;
}


285
void
286 287
virStorageVolDefFree(virStorageVolDefPtr def)
{
288
    int i;
289 290 291 292

    if (!def)
        return;

293 294
    VIR_FREE(def->name);
    VIR_FREE(def->key);
295

296
    for (i = 0; i < def->source.nextent; i++) {
297
        VIR_FREE(def->source.extents[i].path);
298
    }
299
    VIR_FREE(def->source.extents);
300

301 302
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
303
    VIR_FREE(def->target.timestamps);
304
    virStorageEncryptionFree(def->target.encryption);
305 306
    VIR_FREE(def->backingStore.path);
    VIR_FREE(def->backingStore.perms.label);
307
    VIR_FREE(def->backingStore.timestamps);
308
    virStorageEncryptionFree(def->backingStore.encryption);
309
    VIR_FREE(def);
310 311
}

312 313 314 315 316 317 318 319 320 321 322 323 324
static void
virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapter adapter)
{
    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);
    } else if (adapter.type ==
               VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
        VIR_FREE(adapter.data.name);
    }
}

325
void
326 327
virStoragePoolSourceClear(virStoragePoolSourcePtr source)
{
328 329
    int i;

330
    if (!source)
331 332
        return;

333
    for (i = 0; i < source->nhost; i++) {
334 335 336 337
        VIR_FREE(source->hosts[i].name);
    }
    VIR_FREE(source->hosts);

338
    for (i = 0; i < source->ndevice; i++) {
339 340
        VIR_FREE(source->devices[i].freeExtents);
        VIR_FREE(source->devices[i].path);
341
    }
342 343 344
    VIR_FREE(source->devices);
    VIR_FREE(source->dir);
    VIR_FREE(source->name);
345
    virStoragePoolSourceAdapterClear(source->adapter);
D
David Allan 已提交
346
    VIR_FREE(source->initiator.iqn);
347 348
    VIR_FREE(source->vendor);
    VIR_FREE(source->product);
349

350 351 352
    if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
        VIR_FREE(source->auth.chap.login);
        VIR_FREE(source->auth.chap.passwd);
353
    }
354 355 356 357 358

    if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
        VIR_FREE(source->auth.cephx.username);
        VIR_FREE(source->auth.cephx.secret.usage);
    }
359 360
}

361 362 363 364 365 366 367
void
virStoragePoolSourceFree(virStoragePoolSourcePtr source)
{
    virStoragePoolSourceClear(source);
    VIR_FREE(source);
}

368
void
369 370
virStoragePoolDefFree(virStoragePoolDefPtr def)
{
371 372 373 374 375
    if (!def)
        return;

    VIR_FREE(def->name);

376
    virStoragePoolSourceClear(&def->source);
377

378 379 380
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
    VIR_FREE(def);
381 382 383 384
}


void
385 386
virStoragePoolObjFree(virStoragePoolObjPtr obj)
{
387 388 389
    if (!obj)
        return;

390 391
    virStoragePoolObjClearVols(obj);

392 393
    virStoragePoolDefFree(obj->def);
    virStoragePoolDefFree(obj->newDef);
394

395 396
    VIR_FREE(obj->configFile);
    VIR_FREE(obj->autostartLink);
397 398 399

    virMutexDestroy(&obj->lock);

400
    VIR_FREE(obj);
401 402
}

403 404
void
virStoragePoolObjListFree(virStoragePoolObjListPtr pools)
405 406
{
    unsigned int i;
407
    for (i = 0; i < pools->count; i++)
408 409 410 411 412
        virStoragePoolObjFree(pools->objs[i]);
    VIR_FREE(pools->objs);
    pools->count = 0;
}

413
void
414
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
415 416
                        virStoragePoolObjPtr pool)
{
417
    unsigned int i;
418

419 420
    virStoragePoolObjUnlock(pool);

421
    for (i = 0; i < pools->count; i++) {
422
        virStoragePoolObjLock(pools->objs[i]);
423
        if (pools->objs[i] == pool) {
424
            virStoragePoolObjUnlock(pools->objs[i]);
425
            virStoragePoolObjFree(pools->objs[i]);
426

427 428 429
            if (i < (pools->count - 1))
                memmove(pools->objs + i, pools->objs + i + 1,
                        sizeof(*(pools->objs)) * (pools->count - (i + 1)));
430

431 432 433 434
            if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            pools->count--;
435

436 437
            break;
        }
438
        virStoragePoolObjUnlock(pools->objs[i]);
439
    }
440 441 442 443
}


static int
444
virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
445 446
                               virStoragePoolAuthChapPtr auth)
{
447
    auth->login = virXPathString("string(./auth/@login)", ctxt);
448
    if (auth->login == NULL) {
449
        virReportError(VIR_ERR_XML_ERROR,
450
                       "%s", _("missing auth login attribute"));
451 452 453
        return -1;
    }

454
    auth->passwd = virXPathString("string(./auth/@passwd)", ctxt);
455
    if (auth->passwd == NULL) {
456 457
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing auth passwd attribute"));
458 459 460 461 462 463
        return -1;
    }

    return 0;
}

464 465
static int
virStoragePoolDefParseAuthCephx(xmlXPathContextPtr ctxt,
466 467
                                virStoragePoolAuthCephxPtr auth)
{
468
    char *uuid = NULL;
469 470
    int ret = -1;

471 472
    auth->username = virXPathString("string(./auth/@username)", ctxt);
    if (auth->username == NULL) {
473 474
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing auth username attribute"));
475 476 477 478 479 480
        return -1;
    }

    uuid = virXPathString("string(./auth/secret/@uuid)", ctxt);
    auth->secret.usage = virXPathString("string(./auth/secret/@usage)", ctxt);
    if (uuid == NULL && auth->secret.usage == NULL) {
481 482
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing auth secret uuid or usage attribute"));
483 484 485
        return -1;
    }

486 487 488 489
    if (uuid != NULL) {
        if (auth->secret.usage != NULL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("either auth secret uuid or usage expected"));
490
            goto cleanup;
491 492 493 494
        }
        if (virUUIDParse(uuid, auth->secret.uuid) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("invalid auth secret uuid"));
495
            goto cleanup;
496 497 498 499
        }
        auth->secret.uuidUsable = true;
    } else {
        auth->secret.uuidUsable = false;
500 501
    }

502 503 504 505
    ret = 0;
cleanup:
    VIR_FREE(uuid);
    return ret;
506 507
}

508
static int
509
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
510 511
                             virStoragePoolSourcePtr source,
                             int pool_type,
512 513
                             xmlNodePtr node)
{
514 515 516 517 518
    int ret = -1;
    xmlNodePtr relnode, *nodeset = NULL;
    char *authType = NULL;
    int nsource, i;
    virStoragePoolOptionsPtr options;
519
    char *name = NULL;
520
    char *port = NULL;
521
    char *adapter_type = NULL;
522
    int n;
523 524 525 526 527 528 529 530

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

    if ((options = virStoragePoolOptionsForPoolType(pool_type)) == NULL) {
        goto cleanup;
    }

531
    source->name = virXPathString("string(./name)", ctxt);
532
    if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
533 534
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing mandatory 'name' field for RBD pool name"));
535 536
        goto cleanup;
    }
537 538

    if (options->formatFromString) {
539
        char *format = virXPathString("string(./format/@type)", ctxt);
540 541 542 543 544 545
        if (format == NULL)
            source->format = options->defaultFormat;
        else
            source->format = options->formatFromString(format);

        if (source->format < 0) {
546 547
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown pool format type %s"), format);
548 549 550 551 552 553
            VIR_FREE(format);
            goto cleanup;
        }
        VIR_FREE(format);
    }

554 555 556
    if ((n = virXPathNodeSet("./host", ctxt, &nodeset)) < 0)
        goto cleanup;
    source->nhost = n;
557 558 559 560

    if (source->nhost) {
        if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) {
            virReportOOMError();
561 562 563
            goto cleanup;
        }

564
        for (i = 0; i < source->nhost; i++) {
565 566
            name = virXMLPropString(nodeset[i], "name");
            if (name == NULL) {
567 568
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("missing storage pool host name"));
569 570 571 572 573 574 575
                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) {
576 577 578
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("Invalid port number: %s"),
                                   port);
579 580 581 582 583
                    goto cleanup;
                }
            }
        }
    }
584

585
    VIR_FREE(nodeset);
586
    source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
587

588
    nsource = virXPathNodeSet("./device", ctxt, &nodeset);
589 590 591
    if (nsource < 0)
        goto cleanup;

592 593 594
    if (nsource > 0) {
        if (VIR_ALLOC_N(source->devices, nsource) < 0) {
            VIR_FREE(nodeset);
595
            virReportOOMError();
596 597 598
            goto cleanup;
        }

599
        for (i = 0; i < nsource; i++) {
600
            char *path = virXMLPropString(nodeset[i], "path");
601 602
            if (path == NULL) {
                VIR_FREE(nodeset);
603 604
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("missing storage pool source device path"));
605 606
                goto cleanup;
            }
607
            source->devices[i].path = path;
608 609 610 611
        }
        source->ndevice = nsource;
    }

612
    source->dir = virXPathString("string(./dir/@path)", ctxt);
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662

    if ((adapter_type = virXPathString("string(./adapter/@type)", ctxt))) {
        if ((source->adapter.type =
             virStoragePoolSourceAdapterTypeTypeFromString(adapter_type)) <= 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("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 =
                virXPathString("string(./adapter/@parent)", ctxt);
            source->adapter.data.fchost.wwnn =
                virXPathString("string(./adapter/@wwnn)", ctxt);
            source->adapter.data.fchost.wwpn =
                virXPathString("string(./adapter/@wwpn)", ctxt);
        } else if (source->adapter.type ==
                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
            source->adapter.data.name =
                virXPathString("string(./adapter/@name)", ctxt);
        }
    } else {
        char *wwnn = NULL;
        char *wwpn = NULL;
        char *parent = NULL;

        wwnn = virXPathString("string(./adapter/@wwnn)", ctxt);
        wwpn = virXPathString("string(./adapter/@wwpn)", ctxt);
        parent = virXPathString("string(./adapter/@parent)", ctxt);

        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 the 'fc_host' adapter 'type'"));
            goto cleanup;
        }

        /* To keep back-compat, 'type' is not required to specify
         * for scsi_host adapter.
         */
        if ((source->adapter.data.name =
             virXPathString("string(./adapter/@name)", ctxt)))
            source->adapter.type =
                VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST;
    }
663

664
    authType = virXPathString("string(./auth/@type)", ctxt);
665 666 667 668 669
    if (authType == NULL) {
        source->authType = VIR_STORAGE_POOL_AUTH_NONE;
    } else {
        if (STREQ(authType, "chap")) {
            source->authType = VIR_STORAGE_POOL_AUTH_CHAP;
670 671
        } else if (STREQ(authType, "ceph")) {
            source->authType = VIR_STORAGE_POOL_AUTH_CEPHX;
672
        } else {
673 674
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown auth type '%s'"),
675
                           authType);
676 677 678 679 680
            goto cleanup;
        }
    }

    if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
681
        if (virStoragePoolDefParseAuthChap(ctxt, &source->auth.chap) < 0)
682 683 684
            goto cleanup;
    }

685 686 687 688 689
    if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
        if (virStoragePoolDefParseAuthCephx(ctxt, &source->auth.cephx) < 0)
            goto cleanup;
    }

690 691 692
    source->vendor = virXPathString("string(./vendor/@name)", ctxt);
    source->product = virXPathString("string(./product/@name)", ctxt);

693 694 695 696
    ret = 0;
cleanup:
    ctxt->node = relnode;

697
    VIR_FREE(port);
698 699
    VIR_FREE(authType);
    VIR_FREE(nodeset);
700
    VIR_FREE(adapter_type);
701 702
    return ret;
}
703

704
virStoragePoolSourcePtr
705
virStoragePoolDefParseSourceString(const char *srcSpec,
706 707 708 709 710 711 712
                                   int pool_type)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr node = NULL;
    xmlXPathContextPtr xpath_ctxt = NULL;
    virStoragePoolSourcePtr def = NULL, ret = NULL;

713 714 715
    if (!(doc = virXMLParseStringCtxt(srcSpec,
                                      _("(storage_source_specification)"),
                                      &xpath_ctxt)))
716 717 718
        goto cleanup;

    if (VIR_ALLOC(def) < 0) {
719
        virReportOOMError();
720 721 722
        goto cleanup;
    }

723
    if (!(node = virXPathNode("/source", xpath_ctxt))) {
724 725
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("root element was not source"));
726 727 728
        goto cleanup;
    }

729
    if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
730 731 732 733 734 735
                                     node) < 0)
        goto cleanup;

    ret = def;
    def = NULL;
cleanup:
736
    virStoragePoolSourceFree(def);
737 738 739 740 741
    xmlFreeDoc(doc);
    xmlXPathFreeContext(xpath_ctxt);

    return ret;
}
742

743
static int
744
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
745 746
                        virStoragePermsPtr perms,
                        const char *permxpath,
747 748
                        int defaultmode)
{
749 750
    char *mode;
    long v;
751 752 753
    int ret = -1;
    xmlNodePtr relnode;
    xmlNodePtr node;
754

755
    node = virXPathNode(permxpath, ctxt);
756 757 758
    if (node == NULL) {
        /* Set default values if there is not <permissions> element */
        perms->mode = defaultmode;
P
Philipp Hahn 已提交
759 760
        perms->uid = (uid_t) -1;
        perms->gid = (gid_t) -1;
761 762 763 764 765 766 767
        perms->label = NULL;
        return 0;
    }

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

768
    mode = virXPathString("string(./mode)", ctxt);
769
    if (!mode) {
770
        perms->mode = defaultmode;
771
    } else {
772 773 774
        int tmp;

        if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
775
            VIR_FREE(mode);
776 777
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("malformed octal mode"));
778
            goto error;
779
        }
780
        perms->mode = tmp;
781
        VIR_FREE(mode);
782 783
    }

784
    if (virXPathNode("./owner", ctxt) == NULL) {
P
Philipp Hahn 已提交
785
        perms->uid = (uid_t) -1;
786
    } else {
787
        if (virXPathLong("number(./owner)", ctxt, &v) < 0) {
788 789
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("malformed owner element"));
790
            goto error;
791 792 793 794
        }
        perms->uid = (int)v;
    }

795
    if (virXPathNode("./group", ctxt) == NULL) {
P
Philipp Hahn 已提交
796
        perms->gid = (gid_t) -1;
797
    } else {
798
        if (virXPathLong("number(./group)", ctxt, &v) < 0) {
799 800
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("malformed group element"));
801
            goto error;
802 803 804 805 806
        }
        perms->gid = (int)v;
    }

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

809 810 811 812
    ret = 0;
error:
    ctxt->node = relnode;
    return ret;
813 814 815
}

static virStoragePoolDefPtr
816 817
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
{
818
    virStoragePoolOptionsPtr options;
819
    virStoragePoolDefPtr ret;
820
    xmlNodePtr source_node;
821
    char *type = NULL;
822
    char *uuid = NULL;
823
    char *tmppath;
824

825
    if (VIR_ALLOC(ret) < 0) {
826
        virReportOOMError();
827
        return NULL;
828
    }
829

830
    type = virXPathString("string(./@type)", ctxt);
831
    if ((ret->type = virStoragePoolTypeFromString(type)) < 0) {
832
        virReportError(VIR_ERR_INTERNAL_ERROR,
833
                       _("unknown storage pool type %s"), type);
834
        goto cleanup;
835 836
    }

837 838 839
    xmlFree(type);
    type = NULL;

840
    if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) {
841 842 843
        goto cleanup;
    }

844
    source_node = virXPathNode("./source", ctxt);
845
    if (source_node) {
846
        if (virStoragePoolDefParseSource(ctxt, &ret->source, ret->type,
847 848 849 850
                                         source_node) < 0)
            goto cleanup;
    }

851
    ret->name = virXPathString("string(./name)", ctxt);
852
    if (ret->name == NULL &&
853
        options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
854
        ret->name = ret->source.name;
855
    if (ret->name == NULL) {
856 857
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing pool source name element"));
858 859 860
        goto cleanup;
    }

861
    uuid = virXPathString("string(./uuid)", ctxt);
862 863
    if (uuid == NULL) {
        if (virUUIDGenerate(ret->uuid) < 0) {
864 865
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("unable to generate uuid"));
866 867 868 869
            goto cleanup;
        }
    } else {
        if (virUUIDParse(uuid, ret->uuid) < 0) {
870 871
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("malformed uuid element"));
872 873
            goto cleanup;
        }
874
        VIR_FREE(uuid);
875 876
    }

877
    if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
878
        if (!ret->source.nhost) {
879 880 881
            virReportError(VIR_ERR_XML_ERROR,
                           "%s",
                           _("missing storage pool source host name"));
882 883 884 885
            goto cleanup;
        }
    }

886
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
887
        if (!ret->source.dir) {
888 889
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("missing storage pool source path"));
890 891 892
            goto cleanup;
        }
    }
893
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
894 895
        if (ret->source.name == NULL) {
            /* source name defaults to pool name */
896
            if (VIR_STRDUP(ret->source.name, ret->name) < 0)
897
                goto cleanup;
898 899
        }
    }
900

901
    if (options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) {
902 903 904
        if (!ret->source.adapter.type) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source adapter"));
905 906
            goto cleanup;
        }
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928

        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'"));
                goto cleanup;
            }

            if (!virValidateWWN(ret->source.adapter.data.fchost.wwnn) ||
                !virValidateWWN(ret->source.adapter.data.fchost.wwpn))
                goto cleanup;
        } else if (ret->source.adapter.type ==
                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
            if (!ret->source.adapter.data.name) {
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("missing storage pool source adapter name"));
                goto cleanup;
            }
        }
929
    }
930

931 932 933
    /* If DEVICE is the only source type, then its required */
    if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
        if (!ret->source.ndevice) {
934 935
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("missing storage pool source device name"));
936 937 938 939
            goto cleanup;
        }
    }

940 941 942 943
    /* When we are working with a virtual disk we can skip the target
     * path and permissions */
    if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
        if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
944 945
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("missing storage pool target path"));
946 947 948 949 950 951
            goto cleanup;
        }
        ret->target.path = virFileSanitizePath(tmppath);
        VIR_FREE(tmppath);
        if (!ret->target.path)
            goto cleanup;
952

953
        if (virStorageDefParsePerms(ctxt, &ret->target.perms,
954 955
                                    "./target/permissions",
                                    DEFAULT_POOL_PERM_MODE) < 0)
956 957
            goto cleanup;
    }
958 959 960

    return ret;

961
cleanup:
962
    VIR_FREE(uuid);
963
    xmlFree(type);
964 965 966 967 968
    virStoragePoolDefFree(ret);
    return NULL;
}

virStoragePoolDefPtr
969
virStoragePoolDefParseNode(xmlDocPtr xml,
970 971
                           xmlNodePtr root)
{
972 973 974 975
    xmlXPathContextPtr ctxt = NULL;
    virStoragePoolDefPtr def = NULL;

    if (STRNEQ((const char *)root->name, "pool")) {
976 977
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("unknown root element for storage pool"));
978 979 980 981 982
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
983
        virReportOOMError();
984 985 986 987
        goto cleanup;
    }

    ctxt->node = root;
988
    def = virStoragePoolDefParseXML(ctxt);
989 990 991 992 993 994
cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStoragePoolDefPtr
995
virStoragePoolDefParse(const char *xmlStr,
996 997
                       const char *filename)
{
998
    virStoragePoolDefPtr ret = NULL;
J
Jiri Denemark 已提交
999
    xmlDocPtr xml;
1000

1001
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_pool_definition)")))) {
J
Jiri Denemark 已提交
1002 1003
        ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1004 1005
    }

1006 1007 1008
    return ret;
}

1009
virStoragePoolDefPtr
1010
virStoragePoolDefParseString(const char *xmlStr)
1011
{
1012
    return virStoragePoolDefParse(xmlStr, NULL);
1013 1014 1015
}

virStoragePoolDefPtr
1016
virStoragePoolDefParseFile(const char *filename)
1017
{
1018
    return virStoragePoolDefParse(NULL, filename);
1019 1020
}

1021
static int
1022
virStoragePoolSourceFormat(virBufferPtr buf,
1023
                           virStoragePoolOptionsPtr options,
1024 1025 1026
                           virStoragePoolSourcePtr src)
{
    int i, j;
1027
    char uuid[VIR_UUID_STRING_BUFLEN];
1028 1029

    virBufferAddLit(buf,"  <source>\n");
1030 1031
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
        for (i = 0; i < src->nhost; i++) {
E
Eric Blake 已提交
1032
            virBufferAsprintf(buf, "    <host name='%s'", src->hosts[i].name);
1033 1034 1035 1036
            if (src->hosts[i].port)
                virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
            virBufferAddLit(buf, "/>\n");
        }
1037
    }
1038

1039
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
1040
        src->ndevice) {
1041
        for (i = 0; i < src->ndevice; i++) {
1042
            if (src->devices[i].nfreeExtent) {
1043
                virBufferAsprintf(buf,"    <device path='%s'>\n",
1044
                                  src->devices[i].path);
1045
                for (j = 0; j < src->devices[i].nfreeExtent; j++) {
1046
                    virBufferAsprintf(buf, "    <freeExtent start='%llu' end='%llu'/>\n",
1047 1048 1049 1050
                                      src->devices[i].freeExtents[j].start,
                                      src->devices[i].freeExtents[j].end);
                }
                virBufferAddLit(buf,"    </device>\n");
1051
            } else {
1052
                virBufferAsprintf(buf, "    <device path='%s'/>\n",
1053
                                  src->devices[i].path);
1054
            }
1055 1056
        }
    }
1057

1058
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) &&
1059
        src->dir)
1060
        virBufferAsprintf(buf,"    <dir path='%s'/>\n", src->dir);
1061

1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER)) {
        if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST ||
            src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST)
            virBufferAsprintf(buf, "    <adapter type='%s'",
                              virStoragePoolSourceAdapterTypeTypeToString(src->adapter.type));

        if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
            virBufferEscapeString(buf, " parent='%s'",
                                  src->adapter.data.fchost.parent);
            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) {
            virBufferAsprintf(buf," name='%s'/>\n", src->adapter.data.name);
        }
    }
1079

1080
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) &&
1081
        src->name)
1082
        virBufferAsprintf(buf,"    <name>%s</name>\n", src->name);
1083

D
David Allan 已提交
1084 1085 1086 1087 1088 1089 1090
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN) &&
        src->initiator.iqn) {
        virBufferAddLit(buf,"    <initiator>\n");
        virBufferEscapeString(buf,"      <iqn name='%s'/>\n", src->initiator.iqn);
        virBufferAddLit(buf,"    </initiator>\n");
    }

1091 1092 1093
    if (options->formatToString) {
        const char *format = (options->formatToString)(src->format);
        if (!format) {
1094 1095 1096
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown pool format number %d"),
                           src->format);
1097 1098
            return -1;
        }
1099
        virBufferAsprintf(buf,"    <format type='%s'/>\n", format);
1100 1101 1102
    }

    if (src->authType == VIR_STORAGE_POOL_AUTH_CHAP)
1103
        virBufferAsprintf(buf,"    <auth type='chap' login='%s' passwd='%s'/>\n",
1104 1105
                          src->auth.chap.login,
                          src->auth.chap.passwd);
1106

1107 1108 1109 1110
    if (src->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
        virBufferAsprintf(buf,"    <auth username='%s' type='ceph'>\n",
                          src->auth.cephx.username);

1111
        virBufferAddLit(buf,"      <secret");
1112
        if (src->auth.cephx.secret.uuidUsable) {
1113 1114 1115 1116 1117 1118 1119
            virUUIDFormat(src->auth.cephx.secret.uuid, uuid);
            virBufferAsprintf(buf," uuid='%s'", uuid);
        }

        if (src->auth.cephx.secret.usage != NULL) {
            virBufferAsprintf(buf," usage='%s'", src->auth.cephx.secret.usage);
        }
1120
        virBufferAddLit(buf,"/>\n");
1121

1122
        virBufferAddLit(buf,"    </auth>\n");
1123 1124
    }

1125 1126 1127 1128 1129 1130 1131 1132
    if (src->vendor != NULL) {
        virBufferEscapeString(buf,"    <vendor name='%s'/>\n", src->vendor);
    }

    if (src->product != NULL) {
        virBufferEscapeString(buf,"    <product name='%s'/>\n", src->product);
    }

1133 1134 1135 1136 1137
    virBufferAddLit(buf,"  </source>\n");

    return 0;
}

1138 1139

char *
1140 1141
virStoragePoolDefFormat(virStoragePoolDefPtr def)
{
1142
    virStoragePoolOptionsPtr options;
1143
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1144 1145 1146
    const char *type;
    char uuid[VIR_UUID_STRING_BUFLEN];

1147
    options = virStoragePoolOptionsForPoolType(def->type);
1148 1149 1150
    if (options == NULL)
        return NULL;

1151
    type = virStoragePoolTypeToString(def->type);
1152
    if (!type) {
1153 1154
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unexpected pool type"));
1155 1156
        goto cleanup;
    }
1157 1158
    virBufferAsprintf(&buf, "<pool type='%s'>\n", type);
    virBufferAsprintf(&buf,"  <name>%s</name>\n", def->name);
1159 1160

    virUUIDFormat(def->uuid, uuid);
1161
    virBufferAsprintf(&buf,"  <uuid>%s</uuid>\n", uuid);
1162

E
Eric Blake 已提交
1163
    virBufferAsprintf(&buf,"  <capacity unit='bytes'>%llu</capacity>\n",
1164
                      def->capacity);
E
Eric Blake 已提交
1165
    virBufferAsprintf(&buf,"  <allocation unit='bytes'>%llu</allocation>\n",
1166
                      def->allocation);
E
Eric Blake 已提交
1167
    virBufferAsprintf(&buf,"  <available unit='bytes'>%llu</available>\n",
1168
                      def->available);
1169

1170
    if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0)
1171
        goto cleanup;
1172

1173 1174 1175 1176
    /* RBD and Sheepdog devices are not local block devs nor files, so it
     * doesn't have a target */
    if (def->type != VIR_STORAGE_POOL_RBD &&
        def->type != VIR_STORAGE_POOL_SHEEPDOG) {
1177
        virBufferAddLit(&buf,"  <target>\n");
1178

1179 1180
        if (def->target.path)
            virBufferAsprintf(&buf,"    <path>%s</path>\n", def->target.path);
1181

1182 1183 1184
        virBufferAddLit(&buf,"    <permissions>\n");
        virBufferAsprintf(&buf,"      <mode>0%o</mode>\n",
                          def->target.perms.mode);
1185 1186 1187 1188
        virBufferAsprintf(&buf,"      <owner>%d</owner>\n",
                          (int) def->target.perms.uid);
        virBufferAsprintf(&buf,"      <group>%d</group>\n",
                          (int) def->target.perms.gid);
1189

1190 1191 1192
        if (def->target.perms.label)
            virBufferAsprintf(&buf,"      <label>%s</label>\n",
                            def->target.perms.label);
1193

1194 1195 1196
        virBufferAddLit(&buf,"    </permissions>\n");
        virBufferAddLit(&buf,"  </target>\n");
    }
1197
    virBufferAddLit(&buf,"</pool>\n");
1198

1199
    if (virBufferError(&buf))
1200 1201
        goto no_memory;

1202
    return virBufferContentAndReset(&buf);
1203

1204
no_memory:
1205
    virReportOOMError();
1206
cleanup:
1207
    virBufferFreeAndReset(&buf);
1208 1209 1210 1211 1212
    return NULL;
}


static int
1213
virStorageSize(const char *unit,
1214
               const char *val,
1215 1216 1217
               unsigned long long *ret)
{
    if (virStrToLong_ull(val, NULL, 10, ret) < 0) {
1218 1219
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("malformed capacity element"));
1220 1221
        return -1;
    }
1222 1223 1224 1225
    /* 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;
1226 1227 1228 1229 1230

    return 0;
}

static virStorageVolDefPtr
1231
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
1232 1233
                         xmlXPathContextPtr ctxt)
{
1234
    virStorageVolDefPtr ret;
1235
    virStorageVolOptionsPtr options;
1236 1237 1238
    char *allocation = NULL;
    char *capacity = NULL;
    char *unit = NULL;
1239
    xmlNodePtr node;
1240

1241
    options = virStorageVolOptionsForPoolType(pool->type);
1242 1243 1244
    if (options == NULL)
        return NULL;

1245
    if (VIR_ALLOC(ret) < 0) {
1246
        virReportOOMError();
1247
        return NULL;
1248
    }
1249

1250
    ret->name = virXPathString("string(./name)", ctxt);
1251
    if (ret->name == NULL) {
1252 1253
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing volume name element"));
1254 1255 1256
        goto cleanup;
    }

R
Richard W.M. Jones 已提交
1257
    /* Auto-generated so deliberately ignore */
1258
    /* ret->key = virXPathString("string(./key)", ctxt); */
1259

1260 1261
    capacity = virXPathString("string(./capacity)", ctxt);
    unit = virXPathString("string(./capacity/@unit)", ctxt);
1262
    if (capacity == NULL) {
1263 1264
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing capacity element"));
1265 1266
        goto cleanup;
    }
1267
    if (virStorageSize(unit, capacity, &ret->capacity) < 0)
1268
        goto cleanup;
1269 1270
    VIR_FREE(capacity);
    VIR_FREE(unit);
1271

1272
    allocation = virXPathString("string(./allocation)", ctxt);
1273
    if (allocation) {
1274
        unit = virXPathString("string(./allocation/@unit)", ctxt);
1275
        if (virStorageSize(unit, allocation, &ret->allocation) < 0)
1276
            goto cleanup;
1277 1278
        VIR_FREE(allocation);
        VIR_FREE(unit);
1279 1280 1281 1282
    } else {
        ret->allocation = ret->capacity;
    }

1283
    ret->target.path = virXPathString("string(./target/path)", ctxt);
1284
    if (options->formatFromString) {
1285
        char *format = virXPathString("string(./target/format/@type)", ctxt);
1286 1287 1288 1289 1290 1291
        if (format == NULL)
            ret->target.format = options->defaultFormat;
        else
            ret->target.format = (options->formatFromString)(format);

        if (ret->target.format < 0) {
1292 1293
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown volume format type %s"), format);
1294
            VIR_FREE(format);
1295 1296
            goto cleanup;
        }
1297
        VIR_FREE(format);
1298 1299
    }

1300
    if (virStorageDefParsePerms(ctxt, &ret->target.perms,
1301 1302
                                "./target/permissions",
                                DEFAULT_VOL_PERM_MODE) < 0)
1303 1304
        goto cleanup;

1305
    node = virXPathNode("./target/encryption", ctxt);
1306
    if (node != NULL) {
1307
        ret->target.encryption = virStorageEncryptionParseNode(ctxt->doc,
1308 1309 1310 1311 1312
                                                               node);
        if (ret->target.encryption == NULL)
            goto cleanup;
    }

1313
    ret->backingStore.path = virXPathString("string(./backingStore/path)", ctxt);
1314
    if (options->formatFromString) {
1315
        char *format = virXPathString("string(./backingStore/format/@type)", ctxt);
1316 1317 1318 1319 1320 1321
        if (format == NULL)
            ret->backingStore.format = options->defaultFormat;
        else
            ret->backingStore.format = (options->formatFromString)(format);

        if (ret->backingStore.format < 0) {
1322 1323
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown volume format type %s"), format);
1324 1325 1326 1327 1328 1329
            VIR_FREE(format);
            goto cleanup;
        }
        VIR_FREE(format);
    }

1330
    if (virStorageDefParsePerms(ctxt, &ret->backingStore.perms,
1331 1332
                                "./backingStore/permissions",
                                DEFAULT_VOL_PERM_MODE) < 0)
1333 1334
        goto cleanup;

1335 1336
    return ret;

1337
cleanup:
1338 1339 1340
    VIR_FREE(allocation);
    VIR_FREE(capacity);
    VIR_FREE(unit);
1341 1342 1343 1344 1345
    virStorageVolDefFree(ret);
    return NULL;
}

virStorageVolDefPtr
1346
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
1347
                          xmlDocPtr xml,
1348 1349
                          xmlNodePtr root)
{
1350 1351 1352 1353
    xmlXPathContextPtr ctxt = NULL;
    virStorageVolDefPtr def = NULL;

    if (STRNEQ((const char *)root->name, "volume")) {
1354 1355
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("unknown root element for storage vol"));
1356 1357 1358 1359 1360
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1361
        virReportOOMError();
1362 1363 1364 1365
        goto cleanup;
    }

    ctxt->node = root;
1366
    def = virStorageVolDefParseXML(pool, ctxt);
1367 1368 1369 1370 1371 1372
cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStorageVolDefPtr
1373
virStorageVolDefParse(virStoragePoolDefPtr pool,
1374
                      const char *xmlStr,
1375 1376
                      const char *filename)
{
1377
    virStorageVolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1378
    xmlDocPtr xml;
1379

1380
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_volume_definition)")))) {
J
Jiri Denemark 已提交
1381 1382
        ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1383 1384 1385 1386 1387
    }

    return ret;
}

1388
virStorageVolDefPtr
1389
virStorageVolDefParseString(virStoragePoolDefPtr pool,
1390 1391
                            const char *xmlStr)
{
1392
    return virStorageVolDefParse(pool, xmlStr, NULL);
1393 1394 1395
}

virStorageVolDefPtr
1396
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
1397 1398
                          const char *filename)
{
1399
    return virStorageVolDefParse(pool, NULL, filename);
1400
}
1401

1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
static void
virStorageVolTimestampFormat(virBufferPtr buf, const char *name,
                             struct timespec *ts)
{
    if (ts->tv_nsec < 0)
        return;
    virBufferAsprintf(buf, "      <%s>%llu", name,
                      (unsigned long long) ts->tv_sec);
    if (ts->tv_nsec)
       virBufferAsprintf(buf, ".%09ld", ts->tv_nsec);
    virBufferAsprintf(buf, "</%s>\n", name);
}

1415
static int
1416
virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
1417 1418 1419
                             virBufferPtr buf,
                             virStorageVolTargetPtr def,
                             const char *type) {
1420
    virBufferAsprintf(buf, "  <%s>\n", type);
1421 1422

    if (def->path)
1423
        virBufferAsprintf(buf,"    <path>%s</path>\n", def->path);
1424 1425 1426 1427

    if (options->formatToString) {
        const char *format = (options->formatToString)(def->format);
        if (!format) {
1428 1429 1430
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown volume format number %d"),
                           def->format);
1431 1432
            return -1;
        }
1433
        virBufferAsprintf(buf,"    <format type='%s'/>\n", format);
1434 1435 1436
    }

    virBufferAddLit(buf,"    <permissions>\n");
1437
    virBufferAsprintf(buf,"      <mode>0%o</mode>\n",
1438
                      def->perms.mode);
E
Eric Blake 已提交
1439 1440 1441 1442
    virBufferAsprintf(buf,"      <owner>%u</owner>\n",
                      (unsigned int) def->perms.uid);
    virBufferAsprintf(buf,"      <group>%u</group>\n",
                      (unsigned int) def->perms.gid);
1443 1444 1445


    if (def->perms.label)
1446
        virBufferAsprintf(buf,"      <label>%s</label>\n",
1447 1448 1449 1450
                          def->perms.label);

    virBufferAddLit(buf,"    </permissions>\n");

1451 1452 1453 1454 1455 1456 1457 1458 1459
    if (def->timestamps) {
        virBufferAddLit(buf, "    <timestamps>\n");
        virStorageVolTimestampFormat(buf, "atime", &def->timestamps->atime);
        virStorageVolTimestampFormat(buf, "mtime", &def->timestamps->mtime);
        virStorageVolTimestampFormat(buf, "ctime", &def->timestamps->ctime);
        virStorageVolTimestampFormat(buf, "btime", &def->timestamps->btime);
        virBufferAddLit(buf, "    </timestamps>\n");
    }

1460 1461 1462 1463 1464 1465
    if (def->encryption) {
        virBufferAdjustIndent(buf, 4);
        if (virStorageEncryptionFormat(buf, def->encryption) < 0)
            return -1;
        virBufferAdjustIndent(buf, -4);
    }
1466

1467
    virBufferAsprintf(buf, "  </%s>\n", type);
1468 1469 1470

    return 0;
}
1471 1472

char *
1473
virStorageVolDefFormat(virStoragePoolDefPtr pool,
1474 1475
                       virStorageVolDefPtr def)
{
1476
    virStorageVolOptionsPtr options;
1477
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1478

1479
    options = virStorageVolOptionsForPoolType(pool->type);
1480 1481 1482
    if (options == NULL)
        return NULL;

1483
    virBufferAddLit(&buf, "<volume>\n");
1484
    virBufferAsprintf(&buf,"  <name>%s</name>\n", def->name);
1485
    virBufferAsprintf(&buf,"  <key>%s</key>\n", def->key ? def->key : "(null)");
1486
    virBufferAddLit(&buf, "  <source>\n");
1487 1488 1489 1490

    if (def->source.nextent) {
        int i;
        const char *thispath = NULL;
1491
        for (i = 0; i < def->source.nextent; i++) {
1492 1493 1494
            if (thispath == NULL ||
                STRNEQ(thispath, def->source.extents[i].path)) {
                if (thispath != NULL)
1495 1496
                    virBufferAddLit(&buf, "    </device>\n");

1497
                virBufferAsprintf(&buf, "    <device path='%s'>\n",
1498
                                  def->source.extents[i].path);
1499 1500
            }

1501
            virBufferAsprintf(&buf,
1502 1503 1504
                              "      <extent start='%llu' end='%llu'/>\n",
                              def->source.extents[i].start,
                              def->source.extents[i].end);
1505 1506 1507
            thispath = def->source.extents[i].path;
        }
        if (thispath != NULL)
1508
            virBufferAddLit(&buf, "    </device>\n");
1509
    }
1510
    virBufferAddLit(&buf, "  </source>\n");
1511

E
Eric Blake 已提交
1512
    virBufferAsprintf(&buf,"  <capacity unit='bytes'>%llu</capacity>\n",
1513
                      def->capacity);
E
Eric Blake 已提交
1514
    virBufferAsprintf(&buf,"  <allocation unit='bytes'>%llu</allocation>\n",
1515
                      def->allocation);
1516

1517
    if (virStorageVolTargetDefFormat(options, &buf,
1518 1519
                                     &def->target, "target") < 0)
        goto cleanup;
1520

1521
    if (def->backingStore.path &&
1522
        virStorageVolTargetDefFormat(options, &buf,
1523 1524
                                     &def->backingStore, "backingStore") < 0)
        goto cleanup;
1525 1526

    virBufferAddLit(&buf,"</volume>\n");
1527

1528
    if (virBufferError(&buf))
1529 1530
        goto no_memory;

1531
    return virBufferContentAndReset(&buf);
1532

1533
no_memory:
1534
    virReportOOMError();
1535
cleanup:
1536
    virBufferFreeAndReset(&buf);
1537 1538 1539 1540 1541
    return NULL;
}


virStoragePoolObjPtr
1542
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
1543 1544
                            const unsigned char *uuid)
{
1545
    unsigned int i;
1546

1547
    for (i = 0; i < pools->count; i++) {
1548
        virStoragePoolObjLock(pools->objs[i]);
1549 1550
        if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
            return pools->objs[i];
1551 1552
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1553 1554 1555 1556 1557

    return NULL;
}

virStoragePoolObjPtr
1558
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
1559 1560
                            const char *name)
{
1561
    unsigned int i;
1562

1563
    for (i = 0; i < pools->count; i++) {
1564
        virStoragePoolObjLock(pools->objs[i]);
1565 1566
        if (STREQ(pools->objs[i]->def->name, name))
            return pools->objs[i];
1567 1568
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1569 1570 1571 1572

    return NULL;
}

1573 1574
virStoragePoolObjPtr
virStoragePoolSourceFindDuplicateDevices(virStoragePoolObjPtr pool,
1575 1576
                                         virStoragePoolDefPtr def)
{
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
    unsigned int i, j;

    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;
}

1589 1590 1591
void
virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
{
1592
    unsigned int i;
1593
    for (i = 0; i < pool->volumes.count; i++)
1594 1595 1596 1597
        virStorageVolDefFree(pool->volumes.objs[i]);

    VIR_FREE(pool->volumes.objs);
    pool->volumes.count = 0;
1598 1599 1600 1601
}

virStorageVolDefPtr
virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
1602 1603
                          const char *key)
{
1604
    unsigned int i;
1605

1606
    for (i = 0; i < pool->volumes.count; i++)
1607 1608
        if (STREQ(pool->volumes.objs[i]->key, key))
            return pool->volumes.objs[i];
1609 1610 1611 1612 1613 1614

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
1615 1616
                           const char *path)
{
1617
    unsigned int i;
1618

1619
    for (i = 0; i < pool->volumes.count; i++)
1620 1621
        if (STREQ(pool->volumes.objs[i]->target.path, path))
            return pool->volumes.objs[i];
1622 1623 1624 1625 1626 1627

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByName(virStoragePoolObjPtr pool,
1628 1629
                           const char *name)
{
1630
    unsigned int i;
1631

1632
    for (i = 0; i < pool->volumes.count; i++)
1633 1634
        if (STREQ(pool->volumes.objs[i]->name, name))
            return pool->volumes.objs[i];
1635 1636 1637 1638 1639

    return NULL;
}

virStoragePoolObjPtr
1640
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
1641 1642
                           virStoragePoolDefPtr def)
{
1643 1644
    virStoragePoolObjPtr pool;

1645
    if ((pool = virStoragePoolObjFindByName(pools, def->name))) {
1646 1647 1648 1649
        if (!virStoragePoolObjIsActive(pool)) {
            virStoragePoolDefFree(pool->def);
            pool->def = def;
        } else {
1650
            virStoragePoolDefFree(pool->newDef);
1651 1652 1653 1654 1655
            pool->newDef = def;
        }
        return pool;
    }

1656
    if (VIR_ALLOC(pool) < 0) {
1657
        virReportOOMError();
1658 1659 1660
        return NULL;
    }

1661
    if (virMutexInit(&pool->lock) < 0) {
1662 1663
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
1664 1665 1666
        VIR_FREE(pool);
        return NULL;
    }
1667
    virStoragePoolObjLock(pool);
1668 1669 1670
    pool->active = 0;
    pool->def = def;

1671 1672
    if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
        pool->def = NULL;
1673
        virStoragePoolObjUnlock(pool);
1674
        virStoragePoolObjFree(pool);
1675
        virReportOOMError();
1676 1677 1678
        return NULL;
    }
    pools->objs[pools->count++] = pool;
1679 1680 1681 1682 1683

    return pool;
}

static virStoragePoolObjPtr
1684
virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
1685 1686
                      const char *file,
                      const char *path,
1687 1688
                      const char *autostartLink)
{
1689 1690 1691
    virStoragePoolDefPtr def;
    virStoragePoolObjPtr pool;

1692
    if (!(def = virStoragePoolDefParseFile(path))) {
1693 1694 1695 1696
        return NULL;
    }

    if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
1697 1698 1699
        virReportError(VIR_ERR_XML_ERROR,
                       _("Storage pool config filename '%s' does not match pool name '%s'"),
                       path, def->name);
1700 1701 1702 1703
        virStoragePoolDefFree(def);
        return NULL;
    }

1704
    if (!(pool = virStoragePoolObjAssignDef(pools, def))) {
1705 1706 1707 1708
        virStoragePoolDefFree(def);
        return NULL;
    }

1709
    VIR_FREE(pool->configFile);  /* for driver reload */
1710
    if (VIR_STRDUP(pool->configFile, path) < 0) {
1711 1712 1713
        virStoragePoolDefFree(def);
        return NULL;
    }
1714
    VIR_FREE(pool->autostartLink); /* for driver reload */
1715
    if (VIR_STRDUP(pool->autostartLink, autostartLink) < 0) {
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
        virStoragePoolDefFree(def);
        return NULL;
    }

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

    return pool;
}


int
1728
virStoragePoolLoadAllConfigs(virStoragePoolObjListPtr pools,
1729
                             const char *configDir,
1730 1731
                             const char *autostartDir)
{
1732 1733 1734
    DIR *dir;
    struct dirent *entry;

1735
    if (!(dir = opendir(configDir))) {
1736 1737
        if (errno == ENOENT)
            return 0;
1738
        virReportSystemError(errno, _("Failed to open dir '%s'"),
1739
                             configDir);
1740 1741 1742 1743
        return -1;
    }

    while ((entry = readdir(dir))) {
1744 1745
        char *path;
        char *autostartLink;
1746
        virStoragePoolObjPtr pool;
1747 1748 1749 1750 1751 1752 1753

        if (entry->d_name[0] == '.')
            continue;

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

1754
        if (!(path = virFileBuildPath(configDir, entry->d_name, NULL)))
1755 1756
            continue;

1757 1758 1759
        if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
                                               NULL))) {
            VIR_FREE(path);
1760 1761 1762
            continue;
        }

1763
        pool = virStoragePoolObjLoad(pools, entry->d_name, path,
1764
                                     autostartLink);
1765 1766
        if (pool)
            virStoragePoolObjUnlock(pool);
1767 1768 1769

        VIR_FREE(path);
        VIR_FREE(autostartLink);
1770 1771 1772 1773 1774 1775 1776 1777
    }

    closedir(dir);

    return 0;
}

int
1778
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
1779
                         virStoragePoolObjPtr pool,
1780 1781
                         virStoragePoolDefPtr def)
{
J
Ján Tomko 已提交
1782
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1783
    char *xml;
1784
    int ret = -1;
1785 1786

    if (!pool->configFile) {
1787 1788
        if (virFileMakePath(driver->configDir) < 0) {
            virReportSystemError(errno,
C
Cole Robinson 已提交
1789 1790
                                 _("cannot create config directory %s"),
                                 driver->configDir);
1791 1792 1793
            return -1;
        }

1794 1795
        if (!(pool->configFile = virFileBuildPath(driver->configDir,
                                                  def->name, ".xml"))) {
1796 1797 1798
            return -1;
        }

1799 1800
        if (!(pool->autostartLink = virFileBuildPath(driver->autostartDir,
                                                     def->name, ".xml"))) {
1801
            VIR_FREE(pool->configFile);
1802 1803 1804 1805
            return -1;
        }
    }

1806
    if (!(xml = virStoragePoolDefFormat(def))) {
1807 1808
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("failed to generate XML"));
1809 1810 1811
        return -1;
    }

J
Ján Tomko 已提交
1812 1813 1814 1815
    virUUIDFormat(def->uuid, uuidstr);
    ret = virXMLSaveFile(pool->configFile,
                         virXMLPickShellSafeComment(def->name, uuidstr),
                         "pool-edit", xml);
1816
    VIR_FREE(xml);
1817 1818 1819 1820 1821

    return ret;
}

int
1822 1823
virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool)
{
1824
    if (!pool->configFile) {
1825 1826
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no config file for %s"), pool->def->name);
1827 1828 1829 1830
        return -1;
    }

    if (unlink(pool->configFile) < 0) {
1831 1832 1833
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot remove config for %s"),
                       pool->def->name);
1834 1835 1836 1837 1838
        return -1;
    }

    return 0;
}
1839

1840
virStoragePoolSourcePtr
1841
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
1842 1843 1844
{
    virStoragePoolSourcePtr source;

1845
    if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0) {
1846
        virReportOOMError();
1847 1848 1849 1850 1851 1852 1853 1854 1855
        return NULL;
    }

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

    return source;
}

1856 1857
char *
virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def)
1858
{
1859
    virStoragePoolOptionsPtr options;
1860
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1861 1862
    const char *type;
    int i;
1863

1864
    options = virStoragePoolOptionsForPoolType(def->type);
1865 1866 1867
    if (options == NULL)
        return NULL;

1868
    type = virStoragePoolTypeToString(def->type);
1869
    if (!type) {
1870 1871
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unexpected pool type"));
1872 1873 1874 1875
        goto cleanup;
    }

    virBufferAddLit(&buf, "<sources>\n");
1876 1877

    for (i = 0; i < def->nsources; i++) {
1878
        virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
1879 1880
    }

1881 1882 1883 1884
    virBufferAddLit(&buf, "</sources>\n");

    if (virBufferError(&buf))
        goto no_memory;
1885 1886

    return virBufferContentAndReset(&buf);
1887

1888
no_memory:
1889
    virReportOOMError();
1890
cleanup:
1891
    virBufferFreeAndReset(&buf);
1892
    return NULL;
1893
}
D
Daniel P. Berrange 已提交
1894 1895


1896 1897 1898 1899 1900 1901 1902 1903 1904 1905
/*
 * 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
 */
1906 1907 1908 1909
int
virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
                             virStoragePoolDefPtr def,
                             unsigned int check_active)
1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
{
    int ret = -1;
    int dupPool = 0;
    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);
1922 1923 1924
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("pool '%s' is already defined with uuid %s"),
                           pool->def->name, uuidstr);
1925 1926 1927 1928 1929 1930
            goto cleanup;
        }

        if (check_active) {
            /* UUID & name match, but if Pool is already active, refuse it */
            if (virStoragePoolObjIsActive(pool)) {
1931 1932 1933
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("pool is already active as '%s'"),
                               pool->def->name);
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
                goto cleanup;
            }
        }

        dupPool = 1;
    } 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);
1945 1946 1947
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("pool '%s' already exists with uuid %s"),
                           def->name, uuidstr);
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
            goto cleanup;
        }
    }

    ret = dupPool;
cleanup:
    if (pool)
        virStoragePoolObjUnlock(pool);
    return ret;
}

1959 1960 1961
int
virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
                                  virStoragePoolDefPtr def)
1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973
{
    int i;
    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;

1974 1975 1976 1977
        /* Don't mach against ourself if re-defining existing pool ! */
        if (STREQ(pool->def->name, def->name))
            continue;

1978 1979 1980 1981 1982 1983 1984 1985 1986
        virStoragePoolObjLock(pool);

        switch (pool->def->type) {
        case VIR_STORAGE_POOL_DIR:
            if (STREQ(pool->def->target.path, def->target.path))
                matchpool = pool;
            break;
        case VIR_STORAGE_POOL_NETFS:
            if ((STREQ(pool->def->source.dir, def->source.dir)) \
1987 1988
                && (pool->def->source.nhost == 1 && def->source.nhost == 1) \
                && (STREQ(pool->def->source.hosts[0].name, def->source.hosts[0].name)))
1989 1990 1991
                matchpool = pool;
            break;
        case VIR_STORAGE_POOL_SCSI:
1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
            if (pool->def->source.adapter.type ==
                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 ==
                       VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST){
                if (STREQ(pool->def->source.adapter.data.name,
                          def->source.adapter.data.name))
                    matchpool = pool;
            }
2005 2006 2007 2008
            break;
        case VIR_STORAGE_POOL_ISCSI:
            matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
            if (matchpool) {
2009 2010 2011 2012 2013 2014 2015 2016
                if (matchpool->def->source.nhost == 1 && def->source.nhost == 1) {
                    if (STREQ(matchpool->def->source.hosts[0].name, def->source.hosts[0].name)) {
                        if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) {
                            if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn))
                                break;
                            matchpool = NULL;
                        }
                        break;
2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
                    }
                }
                matchpool = NULL;
            }
            break;
        case VIR_STORAGE_POOL_FS:
        case VIR_STORAGE_POOL_LOGICAL:
        case VIR_STORAGE_POOL_DISK:
            matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
            break;
        default:
            break;
        }
        virStoragePoolObjUnlock(pool);
2031 2032 2033

        if (matchpool)
            break;
2034 2035 2036
    }

    if (matchpool) {
2037 2038 2039
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Storage source conflict with pool: '%s'"),
                       matchpool->def->name);
2040 2041 2042 2043
        ret = -1;
    }
    return ret;
}
2044

2045 2046
void
virStoragePoolObjLock(virStoragePoolObjPtr obj)
2047
{
2048
    virMutexLock(&obj->lock);
2049 2050
}

2051 2052
void
virStoragePoolObjUnlock(virStoragePoolObjPtr obj)
2053
{
2054
    virMutexUnlock(&obj->lock);
2055
}
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140

#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) &&
               (poolobj->def->type == VIR_STORAGE_POOL_SHEEPDOG))))
            return false;
    }

    return true;
}
#undef MATCH

int
virStoragePoolList(virConnectPtr conn,
                   virStoragePoolObjList poolobjs,
                   virStoragePoolPtr **pools,
                   unsigned int flags)
{
    virStoragePoolPtr *tmp_pools = NULL;
    virStoragePoolPtr pool = NULL;
    int npools = 0;
    int ret = -1;
    int i;

    if (pools) {
        if (VIR_ALLOC_N(tmp_pools, poolobjs.count + 1) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    }

    for (i = 0; i < poolobjs.count; i++) {
        virStoragePoolObjPtr poolobj = poolobjs.objs[i];
        virStoragePoolObjLock(poolobj);
        if (virStoragePoolMatch(poolobj, flags)) {
            if (pools) {
                if (!(pool = virGetStoragePool(conn,
                                               poolobj->def->name,
2141 2142
                                               poolobj->def->uuid,
                                               NULL, NULL))) {
2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172
                    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;

cleanup:
    if (tmp_pools) {
        for (i = 0; i < npools; i++) {
            if (tmp_pools[i])
                virStoragePoolFree(tmp_pools[i]);
        }
    }

    VIR_FREE(tmp_pools);
    return ret;
}