storage_conf.c 69.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
#include "virlog.h"
48

49 50
#define VIR_FROM_THIS VIR_FROM_STORAGE

51 52
#define DEFAULT_POOL_PERM_MODE 0755
#define DEFAULT_VOL_PERM_MODE  0600
53

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

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

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

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

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


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

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

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

98 99 100 101
VIR_ENUM_IMPL(virStoragePoolAuthType,
              VIR_STORAGE_POOL_AUTH_LAST,
              "none", "chap", "ceph")

102 103
typedef const char *(*virStorageVolFormatToString)(int format);
typedef int (*virStorageVolFormatFromString)(const char *format);
104 105
typedef const char *(*virStorageVolFeatureToString)(int feature);
typedef int (*virStorageVolFeatureFromString)(const char *feature);
106 107 108 109 110 111 112

typedef const char *(*virStoragePoolFormatToString)(int format);
typedef int (*virStoragePoolFormatFromString)(const char *format);

typedef struct _virStorageVolOptions virStorageVolOptions;
typedef virStorageVolOptions *virStorageVolOptionsPtr;
struct _virStorageVolOptions {
113
    int defaultFormat;
114 115
    virStorageVolFormatToString formatToString;
    virStorageVolFormatFromString formatFromString;
116 117
    virStorageVolFeatureToString featureToString;
    virStorageVolFeatureFromString featureFromString;
118 119 120 121
};

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

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

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

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

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


static virStoragePoolTypeInfoPtr
269 270
virStoragePoolTypeInfoLookup(int type)
{
271
    size_t i;
272
    for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo); i++)
273 274 275
        if (poolTypeInfo[i].poolType == type)
            return &poolTypeInfo[i];

276 277
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("missing backend for pool type %d"), type);
278 279 280 281
    return NULL;
}

static virStoragePoolOptionsPtr
282 283
virStoragePoolOptionsForPoolType(int type)
{
284 285 286 287 288 289 290
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->poolOptions;
}

static virStorageVolOptionsPtr
291 292
virStorageVolOptionsForPoolType(int type)
{
293 294 295 296 297 298 299
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->volOptions;
}


300
void
301 302
virStorageVolDefFree(virStorageVolDefPtr def)
{
303
    size_t i;
304 305 306 307

    if (!def)
        return;

308 309
    VIR_FREE(def->name);
    VIR_FREE(def->key);
310

311
    for (i = 0; i < def->source.nextent; i++) {
312
        VIR_FREE(def->source.extents[i].path);
313
    }
314
    VIR_FREE(def->source.extents);
315

316 317
    VIR_FREE(def->target.compat);
    virBitmapFree(def->target.features);
318 319
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
320
    VIR_FREE(def->target.timestamps);
321
    virStorageEncryptionFree(def->target.encryption);
322 323
    VIR_FREE(def->backingStore.path);
    VIR_FREE(def->backingStore.perms.label);
324
    VIR_FREE(def->backingStore.timestamps);
325
    virStorageEncryptionFree(def->backingStore.encryption);
326
    VIR_FREE(def);
327 328
}

329 330 331 332 333 334 335 336 337 338 339 340 341
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);
    }
}

342
void
343 344
virStoragePoolSourceClear(virStoragePoolSourcePtr source)
{
345
    size_t i;
346

347
    if (!source)
348 349
        return;

350
    for (i = 0; i < source->nhost; i++) {
351 352 353 354
        VIR_FREE(source->hosts[i].name);
    }
    VIR_FREE(source->hosts);

355
    for (i = 0; i < source->ndevice; i++) {
356 357
        VIR_FREE(source->devices[i].freeExtents);
        VIR_FREE(source->devices[i].path);
358
    }
359 360 361
    VIR_FREE(source->devices);
    VIR_FREE(source->dir);
    VIR_FREE(source->name);
362
    virStoragePoolSourceAdapterClear(source->adapter);
D
David Allan 已提交
363
    VIR_FREE(source->initiator.iqn);
364 365
    VIR_FREE(source->vendor);
    VIR_FREE(source->product);
366

367
    if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
368 369
        VIR_FREE(source->auth.chap.username);
        VIR_FREE(source->auth.chap.secret.usage);
370
    }
371 372 373 374 375

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

378 379 380 381 382 383 384
void
virStoragePoolSourceFree(virStoragePoolSourcePtr source)
{
    virStoragePoolSourceClear(source);
    VIR_FREE(source);
}

385
void
386 387
virStoragePoolDefFree(virStoragePoolDefPtr def)
{
388 389 390 391 392
    if (!def)
        return;

    VIR_FREE(def->name);

393
    virStoragePoolSourceClear(&def->source);
394

395 396 397
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
    VIR_FREE(def);
398 399 400 401
}


void
402 403
virStoragePoolObjFree(virStoragePoolObjPtr obj)
{
404 405 406
    if (!obj)
        return;

407 408
    virStoragePoolObjClearVols(obj);

409 410
    virStoragePoolDefFree(obj->def);
    virStoragePoolDefFree(obj->newDef);
411

412 413
    VIR_FREE(obj->configFile);
    VIR_FREE(obj->autostartLink);
414 415 416

    virMutexDestroy(&obj->lock);

417
    VIR_FREE(obj);
418 419
}

420 421
void
virStoragePoolObjListFree(virStoragePoolObjListPtr pools)
422
{
423
    size_t i;
424
    for (i = 0; i < pools->count; i++)
425 426 427 428 429
        virStoragePoolObjFree(pools->objs[i]);
    VIR_FREE(pools->objs);
    pools->count = 0;
}

430
void
431
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
432 433
                        virStoragePoolObjPtr pool)
{
434
    size_t i;
435

436 437
    virStoragePoolObjUnlock(pool);

438
    for (i = 0; i < pools->count; i++) {
439
        virStoragePoolObjLock(pools->objs[i]);
440
        if (pools->objs[i] == pool) {
441
            virStoragePoolObjUnlock(pools->objs[i]);
442
            virStoragePoolObjFree(pools->objs[i]);
443

444 445 446
            if (i < (pools->count - 1))
                memmove(pools->objs + i, pools->objs + i + 1,
                        sizeof(*(pools->objs)) * (pools->count - (i + 1)));
447

448 449 450 451
            if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            pools->count--;
452

453 454
            break;
        }
455
        virStoragePoolObjUnlock(pools->objs[i]);
456
    }
457 458 459 460
}


static int
461
virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
462 463
                               virStoragePoolAuthChapPtr auth)
{
464 465 466 467 468
    char *uuid = NULL;
    int ret = -1;

    auth->username = virXPathString("string(./auth/@username)", ctxt);
    if (auth->username == NULL) {
469
        virReportError(VIR_ERR_XML_ERROR, "%s",
470
                       _("missing auth username attribute"));
471 472 473
        return -1;
    }

474 475 476
    uuid = virXPathString("string(./auth/secret/@uuid)", ctxt);
    auth->secret.usage = virXPathString("string(./auth/secret/@usage)", ctxt);
    if (uuid == NULL && auth->secret.usage == NULL) {
477
        virReportError(VIR_ERR_XML_ERROR, "%s",
478
                       _("missing auth secret uuid or usage attribute"));
479 480 481
        return -1;
    }

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

    ret = 0;
cleanup:
    VIR_FREE(uuid);
    return ret;
502 503
}

504 505
static int
virStoragePoolDefParseAuthCephx(xmlXPathContextPtr ctxt,
506 507
                                virStoragePoolAuthCephxPtr auth)
{
508
    char *uuid = NULL;
509 510
    int ret = -1;

511 512
    auth->username = virXPathString("string(./auth/@username)", ctxt);
    if (auth->username == NULL) {
513 514
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing auth username attribute"));
515 516 517 518 519 520
        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) {
521 522
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing auth secret uuid or usage attribute"));
523 524 525
        return -1;
    }

526 527 528 529
    if (uuid != NULL) {
        if (auth->secret.usage != NULL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("either auth secret uuid or usage expected"));
530
            goto cleanup;
531 532
        }
        if (virUUIDParse(uuid, auth->secret.uuid) < 0) {
533 534
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid auth secret uuid"));
535
            goto cleanup;
536 537 538 539
        }
        auth->secret.uuidUsable = true;
    } else {
        auth->secret.uuidUsable = false;
540 541
    }

542 543 544 545
    ret = 0;
cleanup:
    VIR_FREE(uuid);
    return ret;
546 547
}

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
static int
virStoragePoolDefParseAuth(xmlXPathContextPtr ctxt,
                           virStoragePoolSourcePtr source)
{
    int ret = -1;
    char *authType = NULL;

    authType = virXPathString("string(./auth/@type)", ctxt);
    if (authType == NULL) {
        source->authType = VIR_STORAGE_POOL_AUTH_NONE;
        ret = 0;
        goto cleanup;
    }

    if ((source->authType =
         virStoragePoolAuthTypeTypeFromString(authType)) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown auth type '%s'"),
                       authType);
        goto cleanup;
    }

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

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

    ret = 0;

cleanup:
    VIR_FREE(authType);
    return ret;
}

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

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

    if ((options = virStoragePoolOptionsForPoolType(pool_type)) == NULL) {
        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 626
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown pool format type %s"), format);
627 628 629 630 631 632
            VIR_FREE(format);
            goto cleanup;
        }
        VIR_FREE(format);
    }

633 634 635
    if ((n = virXPathNodeSet("./host", ctxt, &nodeset)) < 0)
        goto cleanup;
    source->nhost = n;
636 637

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

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 670 671 672 673 674
    if (nsource > 0) {
        if (VIR_ALLOC_N(source->devices, nsource) < 0) {
            VIR_FREE(nodeset);
            goto cleanup;
        }

675
        for (i = 0; i < nsource; i++) {
676
            char *path = virXMLPropString(nodeset[i], "path");
677 678
            if (path == NULL) {
                VIR_FREE(nodeset);
679 680
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing storage pool source device path"));
681 682
                goto cleanup;
            }
683
            source->devices[i].path = path;
684 685 686 687
        }
        source->ndevice = nsource;
    }

688
    source->dir = virXPathString("string(./dir/@path)", ctxt);
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738

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

740 741
    if (virStoragePoolDefParseAuth(ctxt, source) < 0)
        goto cleanup;
742

743 744 745
    source->vendor = virXPathString("string(./vendor/@name)", ctxt);
    source->product = virXPathString("string(./product/@name)", ctxt);

746 747 748 749
    ret = 0;
cleanup:
    ctxt->node = relnode;

750
    VIR_FREE(port);
751
    VIR_FREE(nodeset);
752
    VIR_FREE(adapter_type);
753 754
    return ret;
}
755

756
virStoragePoolSourcePtr
757
virStoragePoolDefParseSourceString(const char *srcSpec,
758 759 760 761 762 763 764
                                   int pool_type)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr node = NULL;
    xmlXPathContextPtr xpath_ctxt = NULL;
    virStoragePoolSourcePtr def = NULL, ret = NULL;

765 766 767
    if (!(doc = virXMLParseStringCtxt(srcSpec,
                                      _("(storage_source_specification)"),
                                      &xpath_ctxt)))
768 769
        goto cleanup;

770
    if (VIR_ALLOC(def) < 0)
771 772
        goto cleanup;

773
    if (!(node = virXPathNode("/source", xpath_ctxt))) {
774 775
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("root element was not source"));
776 777 778
        goto cleanup;
    }

779
    if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
780 781 782 783 784 785
                                     node) < 0)
        goto cleanup;

    ret = def;
    def = NULL;
cleanup:
786
    virStoragePoolSourceFree(def);
787 788 789 790 791
    xmlFreeDoc(doc);
    xmlXPathFreeContext(xpath_ctxt);

    return ret;
}
792

793
static int
794
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
795 796
                        virStoragePermsPtr perms,
                        const char *permxpath,
797 798
                        int defaultmode)
{
799
    char *mode;
800
    long val;
801 802 803
    int ret = -1;
    xmlNodePtr relnode;
    xmlNodePtr node;
804

805
    node = virXPathNode(permxpath, ctxt);
806 807 808
    if (node == NULL) {
        /* Set default values if there is not <permissions> element */
        perms->mode = defaultmode;
P
Philipp Hahn 已提交
809 810
        perms->uid = (uid_t) -1;
        perms->gid = (gid_t) -1;
811 812 813 814 815 816 817
        perms->label = NULL;
        return 0;
    }

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

818
    mode = virXPathString("string(./mode)", ctxt);
819
    if (!mode) {
820
        perms->mode = defaultmode;
821
    } else {
822 823 824
        int tmp;

        if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
825
            VIR_FREE(mode);
826 827
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed octal mode"));
828
            goto error;
829
        }
830
        perms->mode = tmp;
831
        VIR_FREE(mode);
832 833
    }

834
    if (virXPathNode("./owner", ctxt) == NULL) {
P
Philipp Hahn 已提交
835
        perms->uid = (uid_t) -1;
836
    } else {
837 838 839
        if (virXPathLong("number(./owner)", ctxt, &val) < 0 ||
            ((uid_t)val != val &&
             val != -1)) {
840 841
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed owner element"));
842
            goto error;
843
        }
844 845

        perms->uid = val;
846 847
    }

848
    if (virXPathNode("./group", ctxt) == NULL) {
P
Philipp Hahn 已提交
849
        perms->gid = (gid_t) -1;
850
    } else {
851 852 853
        if (virXPathLong("number(./group)", ctxt, &val) < 0 ||
            ((gid_t) val != val &&
             val != -1)) {
854 855
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed group element"));
856
            goto error;
857
        }
858
        perms->gid = val;
859 860 861
    }

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

864 865 866 867
    ret = 0;
error:
    ctxt->node = relnode;
    return ret;
868 869 870
}

static virStoragePoolDefPtr
871 872
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
{
873
    virStoragePoolOptionsPtr options;
874
    virStoragePoolDefPtr ret;
875
    xmlNodePtr source_node;
876
    char *type = NULL;
877
    char *uuid = NULL;
878
    char *target_path = NULL;
879

880
    if (VIR_ALLOC(ret) < 0)
881 882
        return NULL;

883
    type = virXPathString("string(./@type)", ctxt);
884 885 886 887 888 889
    if (type == NULL) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("storage pool missing type attribute"));
        goto error;
    }

890
    if ((ret->type = virStoragePoolTypeFromString(type)) < 0) {
O
Osier Yang 已提交
891
        virReportError(VIR_ERR_XML_ERROR,
892
                       _("unknown storage pool type %s"), type);
893
        goto error;
894 895 896
    }

    if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) {
897
        goto error;
898 899
    }

900
    source_node = virXPathNode("./source", ctxt);
901
    if (source_node) {
902
        if (virStoragePoolDefParseSource(ctxt, &ret->source, ret->type,
903
                                         source_node) < 0)
904
            goto error;
905 906
    }

907
    ret->name = virXPathString("string(./name)", ctxt);
908
    if (ret->name == NULL &&
909
        options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
910
        ret->name = ret->source.name;
911
    if (ret->name == NULL) {
912 913
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing pool source name element"));
914
        goto error;
915 916
    }

917
    uuid = virXPathString("string(./uuid)", ctxt);
918 919
    if (uuid == NULL) {
        if (virUUIDGenerate(ret->uuid) < 0) {
920 921
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unable to generate uuid"));
922
            goto error;
923 924 925
        }
    } else {
        if (virUUIDParse(uuid, ret->uuid) < 0) {
926 927
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed uuid element"));
928
            goto error;
929 930 931
        }
    }

932
    if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
933
        if (!ret->source.nhost) {
934
            virReportError(VIR_ERR_XML_ERROR, "%s",
935
                           _("missing storage pool source host name"));
936
            goto error;
937 938 939
        }
    }

940
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
941
        if (!ret->source.dir) {
942 943
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source path"));
944
            goto error;
945 946
        }
    }
947
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
948 949
        if (ret->source.name == NULL) {
            /* source name defaults to pool name */
950
            if (VIR_STRDUP(ret->source.name, ret->name) < 0)
951
                goto error;
952 953
        }
    }
954

955
    if (options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) {
956 957 958
        if (!ret->source.adapter.type) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source adapter"));
959
            goto error;
960
        }
961 962 963 964 965 966 967 968

        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'"));
969
                goto error;
970 971 972 973
            }

            if (!virValidateWWN(ret->source.adapter.data.fchost.wwnn) ||
                !virValidateWWN(ret->source.adapter.data.fchost.wwpn))
974
                goto error;
975 976 977
        } else if (ret->source.adapter.type ==
                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
            if (!ret->source.adapter.data.name) {
978 979
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing storage pool source adapter name"));
980
                goto error;
981 982
            }
        }
983
    }
984

985 986 987
    /* If DEVICE is the only source type, then its required */
    if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
        if (!ret->source.ndevice) {
988 989
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source device name"));
990
            goto error;
991 992 993
        }
    }

994 995 996
    /* When we are working with a virtual disk we can skip the target
     * path and permissions */
    if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
997
        if (!(target_path = virXPathString("string(./target/path)", ctxt))) {
998 999
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool target path"));
1000
            goto error;
1001
        }
1002
        ret->target.path = virFileSanitizePath(target_path);
1003
        if (!ret->target.path)
1004
            goto error;
1005

1006
        if (virStorageDefParsePerms(ctxt, &ret->target.perms,
1007 1008
                                    "./target/permissions",
                                    DEFAULT_POOL_PERM_MODE) < 0)
1009
            goto error;
1010
    }
1011

1012
cleanup:
1013
    VIR_FREE(uuid);
1014 1015 1016 1017 1018
    VIR_FREE(type);
    VIR_FREE(target_path);
    return ret;

error:
1019
    virStoragePoolDefFree(ret);
1020 1021
    ret = NULL;
    goto cleanup;
1022 1023 1024
}

virStoragePoolDefPtr
1025
virStoragePoolDefParseNode(xmlDocPtr xml,
1026 1027
                           xmlNodePtr root)
{
1028 1029 1030
    xmlXPathContextPtr ctxt = NULL;
    virStoragePoolDefPtr def = NULL;

1031
    if (!xmlStrEqual(root->name, BAD_CAST "pool")) {
1032
        virReportError(VIR_ERR_XML_ERROR,
1033 1034 1035
                       _("unexpected root element <%s>, "
                         "expecting <pool>"),
                       root->name);
1036 1037 1038 1039 1040
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1041
        virReportOOMError();
1042 1043 1044 1045
        goto cleanup;
    }

    ctxt->node = root;
1046
    def = virStoragePoolDefParseXML(ctxt);
1047 1048 1049 1050 1051 1052
cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStoragePoolDefPtr
1053
virStoragePoolDefParse(const char *xmlStr,
1054 1055
                       const char *filename)
{
1056
    virStoragePoolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1057
    xmlDocPtr xml;
1058

1059
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_pool_definition)")))) {
J
Jiri Denemark 已提交
1060 1061
        ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1062 1063
    }

1064 1065 1066
    return ret;
}

1067
virStoragePoolDefPtr
1068
virStoragePoolDefParseString(const char *xmlStr)
1069
{
1070
    return virStoragePoolDefParse(xmlStr, NULL);
1071 1072 1073
}

virStoragePoolDefPtr
1074
virStoragePoolDefParseFile(const char *filename)
1075
{
1076
    return virStoragePoolDefParse(NULL, filename);
1077 1078
}

1079
static int
1080
virStoragePoolSourceFormat(virBufferPtr buf,
1081
                           virStoragePoolOptionsPtr options,
1082 1083
                           virStoragePoolSourcePtr src)
{
1084
    size_t i, j;
1085
    char uuid[VIR_UUID_STRING_BUFLEN];
1086 1087

    virBufferAddLit(buf,"  <source>\n");
1088 1089
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
        for (i = 0; i < src->nhost; i++) {
E
Eric Blake 已提交
1090
            virBufferAsprintf(buf, "    <host name='%s'", src->hosts[i].name);
1091 1092 1093 1094
            if (src->hosts[i].port)
                virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
            virBufferAddLit(buf, "/>\n");
        }
1095
    }
1096

1097
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
1098
        src->ndevice) {
1099
        for (i = 0; i < src->ndevice; i++) {
1100
            if (src->devices[i].nfreeExtent) {
1101
                virBufferAsprintf(buf,"    <device path='%s'>\n",
1102
                                  src->devices[i].path);
1103
                for (j = 0; j < src->devices[i].nfreeExtent; j++) {
1104
                    virBufferAsprintf(buf, "    <freeExtent start='%llu' end='%llu'/>\n",
1105 1106 1107 1108
                                      src->devices[i].freeExtents[j].start,
                                      src->devices[i].freeExtents[j].end);
                }
                virBufferAddLit(buf,"    </device>\n");
1109
            } else {
1110
                virBufferAsprintf(buf, "    <device path='%s'/>\n",
1111
                                  src->devices[i].path);
1112
            }
1113 1114
        }
    }
1115

1116
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) &&
1117
        src->dir)
1118
        virBufferAsprintf(buf,"    <dir path='%s'/>\n", src->dir);
1119

1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
    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);
        }
    }
1137

1138
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) &&
1139
        src->name)
1140
        virBufferAsprintf(buf,"    <name>%s</name>\n", src->name);
1141

D
David Allan 已提交
1142 1143 1144 1145 1146 1147 1148
    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");
    }

1149 1150 1151
    if (options->formatToString) {
        const char *format = (options->formatToString)(src->format);
        if (!format) {
1152 1153 1154
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown pool format number %d"),
                           src->format);
1155 1156
            return -1;
        }
1157
        virBufferAsprintf(buf,"    <format type='%s'/>\n", format);
1158 1159
    }

1160 1161 1162
    if (src->authType == VIR_STORAGE_POOL_AUTH_CHAP ||
        src->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
        virBufferAsprintf(buf,"    <auth type='%s' username='%s'>\n",
1163
                          virStoragePoolAuthTypeTypeToString(src->authType),
1164 1165 1166
                          (src->authType == VIR_STORAGE_POOL_AUTH_CHAP ?
                           src->auth.chap.username :
                           src->auth.cephx.username));
1167

1168
        virBufferAddLit(buf,"      <secret");
1169
        if (src->auth.cephx.secret.uuidUsable) {
1170 1171 1172 1173 1174 1175 1176
            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);
        }
1177
        virBufferAddLit(buf,"/>\n");
1178

1179
        virBufferAddLit(buf,"    </auth>\n");
1180 1181
    }

1182 1183 1184 1185 1186 1187 1188 1189
    if (src->vendor != NULL) {
        virBufferEscapeString(buf,"    <vendor name='%s'/>\n", src->vendor);
    }

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

1190 1191 1192 1193 1194
    virBufferAddLit(buf,"  </source>\n");

    return 0;
}

1195 1196

char *
1197 1198
virStoragePoolDefFormat(virStoragePoolDefPtr def)
{
1199
    virStoragePoolOptionsPtr options;
1200
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1201 1202 1203
    const char *type;
    char uuid[VIR_UUID_STRING_BUFLEN];

1204
    options = virStoragePoolOptionsForPoolType(def->type);
1205 1206 1207
    if (options == NULL)
        return NULL;

1208
    type = virStoragePoolTypeToString(def->type);
1209
    if (!type) {
1210 1211
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected pool type"));
1212 1213
        goto cleanup;
    }
1214 1215
    virBufferAsprintf(&buf, "<pool type='%s'>\n", type);
    virBufferAsprintf(&buf,"  <name>%s</name>\n", def->name);
1216 1217

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

E
Eric Blake 已提交
1220
    virBufferAsprintf(&buf,"  <capacity unit='bytes'>%llu</capacity>\n",
1221
                      def->capacity);
E
Eric Blake 已提交
1222
    virBufferAsprintf(&buf,"  <allocation unit='bytes'>%llu</allocation>\n",
1223
                      def->allocation);
E
Eric Blake 已提交
1224
    virBufferAsprintf(&buf,"  <available unit='bytes'>%llu</available>\n",
1225
                      def->available);
1226

1227
    if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0)
1228
        goto cleanup;
1229

1230 1231 1232 1233
    /* 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) {
1234
        virBufferAddLit(&buf,"  <target>\n");
1235

1236 1237
        if (def->target.path)
            virBufferAsprintf(&buf,"    <path>%s</path>\n", def->target.path);
1238

1239 1240 1241
        virBufferAddLit(&buf,"    <permissions>\n");
        virBufferAsprintf(&buf,"      <mode>0%o</mode>\n",
                          def->target.perms.mode);
1242 1243 1244 1245
        virBufferAsprintf(&buf,"      <owner>%d</owner>\n",
                          (int) def->target.perms.uid);
        virBufferAsprintf(&buf,"      <group>%d</group>\n",
                          (int) def->target.perms.gid);
1246

1247 1248 1249
        if (def->target.perms.label)
            virBufferAsprintf(&buf,"      <label>%s</label>\n",
                            def->target.perms.label);
1250

1251 1252 1253
        virBufferAddLit(&buf,"    </permissions>\n");
        virBufferAddLit(&buf,"  </target>\n");
    }
1254
    virBufferAddLit(&buf,"</pool>\n");
1255

1256
    if (virBufferError(&buf))
1257 1258
        goto no_memory;

1259
    return virBufferContentAndReset(&buf);
1260

1261
no_memory:
1262
    virReportOOMError();
1263
cleanup:
1264
    virBufferFreeAndReset(&buf);
1265 1266 1267 1268 1269
    return NULL;
}


static int
1270
virStorageSize(const char *unit,
1271
               const char *val,
1272 1273 1274
               unsigned long long *ret)
{
    if (virStrToLong_ull(val, NULL, 10, ret) < 0) {
1275 1276
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("malformed capacity element"));
1277 1278
        return -1;
    }
1279 1280 1281 1282
    /* 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;
1283 1284 1285 1286 1287

    return 0;
}

static virStorageVolDefPtr
1288
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
1289 1290
                         xmlXPathContextPtr ctxt)
{
1291
    virStorageVolDefPtr ret;
1292
    virStorageVolOptionsPtr options;
1293 1294 1295
    char *allocation = NULL;
    char *capacity = NULL;
    char *unit = NULL;
1296
    xmlNodePtr node;
1297
    xmlNodePtr *nodes = NULL;
1298 1299
    size_t i;
    int n;
1300

1301
    options = virStorageVolOptionsForPoolType(pool->type);
1302 1303 1304
    if (options == NULL)
        return NULL;

1305
    if (VIR_ALLOC(ret) < 0)
1306 1307
        return NULL;

1308
    ret->name = virXPathString("string(./name)", ctxt);
1309
    if (ret->name == NULL) {
1310 1311
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing volume name element"));
1312
        goto error;
1313 1314
    }

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

1318 1319
    capacity = virXPathString("string(./capacity)", ctxt);
    unit = virXPathString("string(./capacity/@unit)", ctxt);
1320
    if (capacity == NULL) {
1321 1322
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing capacity element"));
1323
        goto error;
1324
    }
1325
    if (virStorageSize(unit, capacity, &ret->capacity) < 0)
1326
        goto error;
1327
    VIR_FREE(unit);
1328

1329
    allocation = virXPathString("string(./allocation)", ctxt);
1330
    if (allocation) {
1331
        unit = virXPathString("string(./allocation/@unit)", ctxt);
1332
        if (virStorageSize(unit, allocation, &ret->allocation) < 0)
1333
            goto error;
1334 1335 1336 1337
    } else {
        ret->allocation = ret->capacity;
    }

1338
    ret->target.path = virXPathString("string(./target/path)", ctxt);
1339
    if (options->formatFromString) {
1340
        char *format = virXPathString("string(./target/format/@type)", ctxt);
1341 1342 1343 1344 1345 1346
        if (format == NULL)
            ret->target.format = options->defaultFormat;
        else
            ret->target.format = (options->formatFromString)(format);

        if (ret->target.format < 0) {
1347 1348
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown volume format type %s"), format);
1349
            VIR_FREE(format);
1350
            goto error;
1351
        }
1352
        VIR_FREE(format);
1353 1354
    }

1355
    if (virStorageDefParsePerms(ctxt, &ret->target.perms,
1356 1357
                                "./target/permissions",
                                DEFAULT_VOL_PERM_MODE) < 0)
1358
        goto error;
1359

1360
    node = virXPathNode("./target/encryption", ctxt);
1361
    if (node != NULL) {
1362
        ret->target.encryption = virStorageEncryptionParseNode(ctxt->doc,
1363 1364
                                                               node);
        if (ret->target.encryption == NULL)
1365
            goto error;
1366 1367
    }

1368
    ret->backingStore.path = virXPathString("string(./backingStore/path)", ctxt);
1369
    if (options->formatFromString) {
1370
        char *format = virXPathString("string(./backingStore/format/@type)", ctxt);
1371 1372 1373 1374 1375 1376
        if (format == NULL)
            ret->backingStore.format = options->defaultFormat;
        else
            ret->backingStore.format = (options->formatFromString)(format);

        if (ret->backingStore.format < 0) {
1377 1378
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown volume format type %s"), format);
1379
            VIR_FREE(format);
1380
            goto error;
1381 1382 1383 1384
        }
        VIR_FREE(format);
    }

1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
    ret->target.compat = virXPathString("string(./target/compat)", ctxt);
    if (ret->target.compat) {
        char **version = virStringSplit(ret->target.compat, ".", 2);
        unsigned int result;

        if (!version || !version[1] ||
            virStrToLong_ui(version[0], NULL, 10, &result) < 0 ||
            virStrToLong_ui(version[1], NULL, 10, &result) < 0) {
            virStringFreeList(version);
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("forbidden characters in 'compat' attribute"));
            goto error;
        }
        virStringFreeList(version);
    }

    if (options->featureFromString && virXPathNode("./target/features", ctxt)) {
        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)))
1409
            goto error;
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423

        for (i = 0; i < n; i++) {
            int f = options->featureFromString((const char*)nodes[i]->name);

            if (f < 0) {
                virReportError(VIR_ERR_XML_ERROR, _("unsupported feature %s"),
                               (const char*)nodes[i]->name);
                goto error;
            }
            ignore_value(virBitmapSetBit(ret->target.features, f));
        }
        VIR_FREE(nodes);
    }

1424
    if (virStorageDefParsePerms(ctxt, &ret->backingStore.perms,
1425 1426
                                "./backingStore/permissions",
                                DEFAULT_VOL_PERM_MODE) < 0)
1427
        goto error;
1428

1429
cleanup:
1430
    VIR_FREE(nodes);
1431 1432 1433
    VIR_FREE(allocation);
    VIR_FREE(capacity);
    VIR_FREE(unit);
1434 1435 1436
    return ret;

error:
1437
    virStorageVolDefFree(ret);
1438 1439
    ret = NULL;
    goto cleanup;
1440 1441 1442
}

virStorageVolDefPtr
1443
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
1444
                          xmlDocPtr xml,
1445 1446
                          xmlNodePtr root)
{
1447 1448 1449
    xmlXPathContextPtr ctxt = NULL;
    virStorageVolDefPtr def = NULL;

1450
    if (!xmlStrEqual(root->name, BAD_CAST "volume")) {
1451
        virReportError(VIR_ERR_XML_ERROR,
1452 1453 1454
                       _("unexpected root element <%s>, "
                         "expecting <volume>"),
                       root->name);
1455 1456 1457 1458 1459
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1460
        virReportOOMError();
1461 1462 1463 1464
        goto cleanup;
    }

    ctxt->node = root;
1465
    def = virStorageVolDefParseXML(pool, ctxt);
1466 1467 1468 1469 1470 1471
cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStorageVolDefPtr
1472
virStorageVolDefParse(virStoragePoolDefPtr pool,
1473
                      const char *xmlStr,
1474 1475
                      const char *filename)
{
1476
    virStorageVolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1477
    xmlDocPtr xml;
1478

1479
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_volume_definition)")))) {
J
Jiri Denemark 已提交
1480 1481
        ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1482 1483 1484 1485 1486
    }

    return ret;
}

1487
virStorageVolDefPtr
1488
virStorageVolDefParseString(virStoragePoolDefPtr pool,
1489 1490
                            const char *xmlStr)
{
1491
    return virStorageVolDefParse(pool, xmlStr, NULL);
1492 1493 1494
}

virStorageVolDefPtr
1495
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
1496 1497
                          const char *filename)
{
1498
    return virStorageVolDefParse(pool, NULL, filename);
1499
}
1500

1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
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);
}

1514
static int
1515
virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
1516 1517 1518
                             virBufferPtr buf,
                             virStorageVolTargetPtr def,
                             const char *type) {
1519
    virBufferAsprintf(buf, "  <%s>\n", type);
1520 1521

    if (def->path)
1522
        virBufferAsprintf(buf,"    <path>%s</path>\n", def->path);
1523 1524 1525 1526

    if (options->formatToString) {
        const char *format = (options->formatToString)(def->format);
        if (!format) {
1527 1528 1529
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown volume format number %d"),
                           def->format);
1530 1531
            return -1;
        }
1532
        virBufferAsprintf(buf,"    <format type='%s'/>\n", format);
1533 1534 1535
    }

    virBufferAddLit(buf,"    <permissions>\n");
1536
    virBufferAsprintf(buf,"      <mode>0%o</mode>\n",
1537
                      def->perms.mode);
E
Eric Blake 已提交
1538 1539 1540 1541
    virBufferAsprintf(buf,"      <owner>%u</owner>\n",
                      (unsigned int) def->perms.uid);
    virBufferAsprintf(buf,"      <group>%u</group>\n",
                      (unsigned int) def->perms.gid);
1542 1543 1544


    if (def->perms.label)
1545
        virBufferAsprintf(buf,"      <label>%s</label>\n",
1546 1547 1548 1549
                          def->perms.label);

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

1550 1551 1552 1553 1554 1555 1556 1557 1558
    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");
    }

1559 1560 1561 1562 1563 1564
    if (def->encryption) {
        virBufferAdjustIndent(buf, 4);
        if (virStorageEncryptionFormat(buf, def->encryption) < 0)
            return -1;
        virBufferAdjustIndent(buf, -4);
    }
1565

1566 1567 1568
    virBufferEscapeString(buf, "    <compat>%s</compat>\n", def->compat);

    if (options->featureToString && def->features) {
1569
        size_t i;
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
        bool b;
        bool empty = virBitmapIsAllClear(def->features);

        if (empty)
            virBufferAddLit(buf, "    <features/>\n");
        else
            virBufferAddLit(buf, "    <features>\n");

        for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
            ignore_value(virBitmapGetBit(def->features, i, &b));
            if (b)
                virBufferAsprintf(buf, "      <%s/>\n",
                                  options->featureToString(i));
        }
        if (!empty)
            virBufferAddLit(buf, "    </features>\n");
    }

1588
    virBufferAsprintf(buf, "  </%s>\n", type);
1589 1590 1591

    return 0;
}
1592 1593

char *
1594
virStorageVolDefFormat(virStoragePoolDefPtr pool,
1595 1596
                       virStorageVolDefPtr def)
{
1597
    virStorageVolOptionsPtr options;
1598
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1599

1600
    options = virStorageVolOptionsForPoolType(pool->type);
1601 1602 1603
    if (options == NULL)
        return NULL;

1604
    virBufferAddLit(&buf, "<volume>\n");
1605
    virBufferAsprintf(&buf,"  <name>%s</name>\n", def->name);
O
Osier Yang 已提交
1606
    virBufferAsprintf(&buf,"  <key>%s</key>\n", NULLSTR(def->key));
1607
    virBufferAddLit(&buf, "  <source>\n");
1608 1609

    if (def->source.nextent) {
1610
        size_t i;
1611
        const char *thispath = NULL;
1612
        for (i = 0; i < def->source.nextent; i++) {
1613 1614 1615
            if (thispath == NULL ||
                STRNEQ(thispath, def->source.extents[i].path)) {
                if (thispath != NULL)
1616 1617
                    virBufferAddLit(&buf, "    </device>\n");

1618
                virBufferAsprintf(&buf, "    <device path='%s'>\n",
1619
                                  def->source.extents[i].path);
1620 1621
            }

1622
            virBufferAsprintf(&buf,
1623 1624 1625
                              "      <extent start='%llu' end='%llu'/>\n",
                              def->source.extents[i].start,
                              def->source.extents[i].end);
1626 1627 1628
            thispath = def->source.extents[i].path;
        }
        if (thispath != NULL)
1629
            virBufferAddLit(&buf, "    </device>\n");
1630
    }
1631
    virBufferAddLit(&buf, "  </source>\n");
1632

E
Eric Blake 已提交
1633
    virBufferAsprintf(&buf,"  <capacity unit='bytes'>%llu</capacity>\n",
1634
                      def->capacity);
E
Eric Blake 已提交
1635
    virBufferAsprintf(&buf,"  <allocation unit='bytes'>%llu</allocation>\n",
1636
                      def->allocation);
1637

1638
    if (virStorageVolTargetDefFormat(options, &buf,
1639 1640
                                     &def->target, "target") < 0)
        goto cleanup;
1641

1642
    if (def->backingStore.path &&
1643
        virStorageVolTargetDefFormat(options, &buf,
1644 1645
                                     &def->backingStore, "backingStore") < 0)
        goto cleanup;
1646 1647

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

1649
    if (virBufferError(&buf))
1650 1651
        goto no_memory;

1652
    return virBufferContentAndReset(&buf);
1653

1654
no_memory:
1655
    virReportOOMError();
1656
cleanup:
1657
    virBufferFreeAndReset(&buf);
1658 1659 1660 1661 1662
    return NULL;
}


virStoragePoolObjPtr
1663
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
1664 1665
                            const unsigned char *uuid)
{
1666
    size_t i;
1667

1668
    for (i = 0; i < pools->count; i++) {
1669
        virStoragePoolObjLock(pools->objs[i]);
1670 1671
        if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
            return pools->objs[i];
1672 1673
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1674 1675 1676 1677 1678

    return NULL;
}

virStoragePoolObjPtr
1679
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
1680 1681
                            const char *name)
{
1682
    size_t i;
1683

1684
    for (i = 0; i < pools->count; i++) {
1685
        virStoragePoolObjLock(pools->objs[i]);
1686 1687
        if (STREQ(pools->objs[i]->def->name, name))
            return pools->objs[i];
1688 1689
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1690 1691 1692 1693

    return NULL;
}

1694 1695
virStoragePoolObjPtr
virStoragePoolSourceFindDuplicateDevices(virStoragePoolObjPtr pool,
1696 1697
                                         virStoragePoolDefPtr def)
{
1698
    size_t i, j;
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709

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

1710 1711 1712
void
virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
{
1713
    size_t i;
1714
    for (i = 0; i < pool->volumes.count; i++)
1715 1716 1717 1718
        virStorageVolDefFree(pool->volumes.objs[i]);

    VIR_FREE(pool->volumes.objs);
    pool->volumes.count = 0;
1719 1720 1721 1722
}

virStorageVolDefPtr
virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
1723 1724
                          const char *key)
{
1725
    size_t i;
1726

1727
    for (i = 0; i < pool->volumes.count; i++)
1728 1729
        if (STREQ(pool->volumes.objs[i]->key, key))
            return pool->volumes.objs[i];
1730 1731 1732 1733 1734 1735

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
1736 1737
                           const char *path)
{
1738
    size_t i;
1739

1740
    for (i = 0; i < pool->volumes.count; i++)
1741 1742
        if (STREQ(pool->volumes.objs[i]->target.path, path))
            return pool->volumes.objs[i];
1743 1744 1745 1746 1747 1748

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByName(virStoragePoolObjPtr pool,
1749 1750
                           const char *name)
{
1751
    size_t i;
1752

1753
    for (i = 0; i < pool->volumes.count; i++)
1754 1755
        if (STREQ(pool->volumes.objs[i]->name, name))
            return pool->volumes.objs[i];
1756 1757 1758 1759 1760

    return NULL;
}

virStoragePoolObjPtr
1761
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
1762 1763
                           virStoragePoolDefPtr def)
{
1764 1765
    virStoragePoolObjPtr pool;

1766
    if ((pool = virStoragePoolObjFindByName(pools, def->name))) {
1767 1768 1769 1770
        if (!virStoragePoolObjIsActive(pool)) {
            virStoragePoolDefFree(pool->def);
            pool->def = def;
        } else {
1771
            virStoragePoolDefFree(pool->newDef);
1772 1773 1774 1775 1776
            pool->newDef = def;
        }
        return pool;
    }

1777
    if (VIR_ALLOC(pool) < 0)
1778 1779
        return NULL;

1780
    if (virMutexInit(&pool->lock) < 0) {
1781 1782
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot initialize mutex"));
1783 1784 1785
        VIR_FREE(pool);
        return NULL;
    }
1786
    virStoragePoolObjLock(pool);
1787 1788 1789
    pool->active = 0;
    pool->def = def;

1790 1791
    if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
        pool->def = NULL;
1792
        virStoragePoolObjUnlock(pool);
1793 1794 1795 1796
        virStoragePoolObjFree(pool);
        return NULL;
    }
    pools->objs[pools->count++] = pool;
1797 1798 1799 1800 1801

    return pool;
}

static virStoragePoolObjPtr
1802
virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
1803 1804
                      const char *file,
                      const char *path,
1805 1806
                      const char *autostartLink)
{
1807 1808 1809
    virStoragePoolDefPtr def;
    virStoragePoolObjPtr pool;

1810
    if (!(def = virStoragePoolDefParseFile(path))) {
1811 1812 1813 1814
        return NULL;
    }

    if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
1815
        virReportError(VIR_ERR_XML_ERROR,
1816 1817
                       _("Storage pool config filename '%s' does "
                         "not match pool name '%s'"),
1818
                       path, def->name);
1819 1820 1821 1822
        virStoragePoolDefFree(def);
        return NULL;
    }

1823
    if (!(pool = virStoragePoolObjAssignDef(pools, def))) {
1824 1825 1826 1827
        virStoragePoolDefFree(def);
        return NULL;
    }

1828
    VIR_FREE(pool->configFile);  /* for driver reload */
1829
    if (VIR_STRDUP(pool->configFile, path) < 0) {
1830 1831 1832
        virStoragePoolDefFree(def);
        return NULL;
    }
1833
    VIR_FREE(pool->autostartLink); /* for driver reload */
1834
    if (VIR_STRDUP(pool->autostartLink, autostartLink) < 0) {
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
        virStoragePoolDefFree(def);
        return NULL;
    }

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

    return pool;
}


int
1847
virStoragePoolLoadAllConfigs(virStoragePoolObjListPtr pools,
1848
                             const char *configDir,
1849 1850
                             const char *autostartDir)
{
1851 1852 1853
    DIR *dir;
    struct dirent *entry;

1854
    if (!(dir = opendir(configDir))) {
1855 1856
        if (errno == ENOENT)
            return 0;
1857
        virReportSystemError(errno, _("Failed to open dir '%s'"),
1858
                             configDir);
1859 1860 1861 1862
        return -1;
    }

    while ((entry = readdir(dir))) {
1863 1864
        char *path;
        char *autostartLink;
1865
        virStoragePoolObjPtr pool;
1866 1867 1868 1869 1870 1871 1872

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

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

1873
        if (!(path = virFileBuildPath(configDir, entry->d_name, NULL)))
1874 1875
            continue;

1876 1877 1878
        if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
                                               NULL))) {
            VIR_FREE(path);
1879 1880 1881
            continue;
        }

1882
        pool = virStoragePoolObjLoad(pools, entry->d_name, path,
1883
                                     autostartLink);
1884 1885
        if (pool)
            virStoragePoolObjUnlock(pool);
1886 1887 1888

        VIR_FREE(path);
        VIR_FREE(autostartLink);
1889 1890 1891 1892 1893 1894 1895 1896
    }

    closedir(dir);

    return 0;
}

int
1897
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
1898
                         virStoragePoolObjPtr pool,
1899 1900
                         virStoragePoolDefPtr def)
{
J
Ján Tomko 已提交
1901
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1902
    char *xml;
1903
    int ret = -1;
1904 1905

    if (!pool->configFile) {
1906 1907
        if (virFileMakePath(driver->configDir) < 0) {
            virReportSystemError(errno,
C
Cole Robinson 已提交
1908 1909
                                 _("cannot create config directory %s"),
                                 driver->configDir);
1910 1911 1912
            return -1;
        }

1913 1914
        if (!(pool->configFile = virFileBuildPath(driver->configDir,
                                                  def->name, ".xml"))) {
1915 1916 1917
            return -1;
        }

1918 1919
        if (!(pool->autostartLink = virFileBuildPath(driver->autostartDir,
                                                     def->name, ".xml"))) {
1920
            VIR_FREE(pool->configFile);
1921 1922 1923 1924
            return -1;
        }
    }

1925
    if (!(xml = virStoragePoolDefFormat(def))) {
1926 1927
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to generate XML"));
1928 1929 1930
        return -1;
    }

J
Ján Tomko 已提交
1931 1932 1933 1934
    virUUIDFormat(def->uuid, uuidstr);
    ret = virXMLSaveFile(pool->configFile,
                         virXMLPickShellSafeComment(def->name, uuidstr),
                         "pool-edit", xml);
1935
    VIR_FREE(xml);
1936 1937 1938 1939 1940

    return ret;
}

int
1941 1942
virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool)
{
1943
    if (!pool->configFile) {
1944 1945
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no config file for %s"), pool->def->name);
1946 1947 1948 1949
        return -1;
    }

    if (unlink(pool->configFile) < 0) {
1950 1951 1952
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot remove config for %s"),
                       pool->def->name);
1953 1954 1955 1956 1957
        return -1;
    }

    return 0;
}
1958

1959
virStoragePoolSourcePtr
1960
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
1961 1962 1963
{
    virStoragePoolSourcePtr source;

1964
    if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0)
1965 1966 1967 1968 1969 1970 1971 1972
        return NULL;

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

    return source;
}

1973 1974
char *
virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def)
1975
{
1976
    virStoragePoolOptionsPtr options;
1977
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1978
    const char *type;
1979
    size_t i;
1980

1981
    options = virStoragePoolOptionsForPoolType(def->type);
1982 1983 1984
    if (options == NULL)
        return NULL;

1985
    type = virStoragePoolTypeToString(def->type);
1986
    if (!type) {
1987 1988
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected pool type"));
1989 1990 1991 1992
        goto cleanup;
    }

    virBufferAddLit(&buf, "<sources>\n");
1993 1994

    for (i = 0; i < def->nsources; i++) {
1995
        virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
1996 1997
    }

1998 1999 2000 2001
    virBufferAddLit(&buf, "</sources>\n");

    if (virBufferError(&buf))
        goto no_memory;
2002 2003

    return virBufferContentAndReset(&buf);
2004

2005
no_memory:
2006
    virReportOOMError();
2007
cleanup:
2008
    virBufferFreeAndReset(&buf);
2009
    return NULL;
2010
}
D
Daniel P. Berrange 已提交
2011 2012


2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
/*
 * 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
 */
2023 2024 2025 2026
int
virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
                             virStoragePoolDefPtr def,
                             unsigned int check_active)
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
{
    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);
2038 2039 2040
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("pool '%s' is already defined with uuid %s"),
                           pool->def->name, uuidstr);
2041 2042 2043 2044 2045 2046
            goto cleanup;
        }

        if (check_active) {
            /* UUID & name match, but if Pool is already active, refuse it */
            if (virStoragePoolObjIsActive(pool)) {
2047 2048 2049
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("pool is already active as '%s'"),
                               pool->def->name);
2050 2051 2052 2053
                goto cleanup;
            }
        }

J
Ján Tomko 已提交
2054
        ret = 1;
2055 2056 2057 2058 2059 2060
    } 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);
2061 2062 2063
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("pool '%s' already exists with uuid %s"),
                           def->name, uuidstr);
2064 2065
            goto cleanup;
        }
J
Ján Tomko 已提交
2066
        ret = 0;
2067 2068 2069 2070 2071 2072 2073 2074
    }

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

2075 2076 2077
int
virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
                                  virStoragePoolDefPtr def)
2078
{
2079
    size_t i;
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089
    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;

2090 2091 2092 2093
        /* Don't mach against ourself if re-defining existing pool ! */
        if (STREQ(pool->def->name, def->name))
            continue;

2094 2095 2096 2097 2098 2099 2100 2101 2102
        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)) \
2103 2104
                && (pool->def->source.nhost == 1 && def->source.nhost == 1) \
                && (STREQ(pool->def->source.hosts[0].name, def->source.hosts[0].name)))
2105 2106 2107
                matchpool = pool;
            break;
        case VIR_STORAGE_POOL_SCSI:
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120
            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;
            }
2121 2122 2123 2124
            break;
        case VIR_STORAGE_POOL_ISCSI:
            matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
            if (matchpool) {
2125 2126 2127 2128 2129 2130 2131 2132
                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;
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146
                    }
                }
                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);
2147 2148 2149

        if (matchpool)
            break;
2150 2151 2152
    }

    if (matchpool) {
2153 2154 2155
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Storage source conflict with pool: '%s'"),
                       matchpool->def->name);
2156 2157 2158 2159
        ret = -1;
    }
    return ret;
}
2160

2161 2162
void
virStoragePoolObjLock(virStoragePoolObjPtr obj)
2163
{
2164
    virMutexLock(&obj->lock);
2165 2166
}

2167 2168
void
virStoragePoolObjUnlock(virStoragePoolObjPtr obj)
2169
{
2170
    virMutexUnlock(&obj->lock);
2171
}
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231

#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
2232 2233 2234 2235 2236
virStoragePoolObjListExport(virConnectPtr conn,
                            virStoragePoolObjList poolobjs,
                            virStoragePoolPtr **pools,
                            virStoragePoolObjListFilter filter,
                            unsigned int flags)
2237 2238 2239 2240 2241
{
    virStoragePoolPtr *tmp_pools = NULL;
    virStoragePoolPtr pool = NULL;
    int npools = 0;
    int ret = -1;
2242
    size_t i;
2243

2244 2245
    if (pools && VIR_ALLOC_N(tmp_pools, poolobjs.count + 1) < 0)
        goto cleanup;
2246 2247 2248 2249

    for (i = 0; i < poolobjs.count; i++) {
        virStoragePoolObjPtr poolobj = poolobjs.objs[i];
        virStoragePoolObjLock(poolobj);
2250 2251
        if ((!filter || filter(conn, poolobj->def)) &&
            virStoragePoolMatch(poolobj, flags)) {
2252 2253 2254
            if (pools) {
                if (!(pool = virGetStoragePool(conn,
                                               poolobj->def->name,
2255 2256
                                               poolobj->def->uuid,
                                               NULL, NULL))) {
2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286
                    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;
}