storage_conf.c 54.5 KB
Newer Older
1 2 3
/*
 * storage_conf.c: config handling for storage driver
 *
4
 * Copyright (C) 2006-2016 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28
 */

#include <config.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

29
#include "virerror.h"
30
#include "datatypes.h"
31
#include "node_device_conf.h"
32
#include "storage_adapter_conf.h"
33
#include "storage_conf.h"
34
#include "virstoragefile.h"
35

36
#include "virxml.h"
37
#include "viruuid.h"
38
#include "virbuffer.h"
39
#include "viralloc.h"
E
Eric Blake 已提交
40
#include "virfile.h"
41
#include "virscsihost.h"
42
#include "virstring.h"
43
#include "virlog.h"
44
#include "virvhba.h"
45

46 47
#define VIR_FROM_THIS VIR_FROM_STORAGE

48 49
VIR_LOG_INIT("conf.storage_conf");

50 51
VIR_ENUM_IMPL(virStorageVol,
              VIR_STORAGE_VOL_LAST,
O
Olga Krishtal 已提交
52
              "file", "block", "dir", "network",
53 54
              "netdir", "ploop",
);
55

56 57 58 59
VIR_ENUM_IMPL(virStoragePool,
              VIR_STORAGE_POOL_LAST,
              "dir", "fs", "netfs",
              "logical", "disk", "iscsi",
60 61
              "iscsi-direct", "scsi", "mpath",
              "rbd", "sheepdog", "gluster",
62 63
              "zfs", "vstorage",
);
64 65 66 67 68

VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
              VIR_STORAGE_POOL_FS_LAST,
              "auto", "ext2", "ext3",
              "ext4", "ufs", "iso9660", "udf",
69 70
              "gfs", "gfs2", "vfat", "hfs+", "xfs", "ocfs2",
);
71 72 73

VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
              VIR_STORAGE_POOL_NETFS_LAST,
74 75
              "auto", "nfs", "glusterfs", "cifs",
);
76 77 78 79

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

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


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

97 98 99 100 101
VIR_ENUM_IMPL(virStorageVolDefRefreshAllocation,
              VIR_STORAGE_VOL_DEF_REFRESH_ALLOCATION_LAST,
              "default", "capacity",
);

102
VIR_ENUM_IMPL(virStoragePartedFs,
103
              VIR_STORAGE_PARTED_FS_TYPE_LAST,
104
              "ext2", "ext2", "fat16",
105 106
              "fat32", "linux-swap",
              "ext2", "ext2",
107 108
              "extended",
);
109 110 111 112 113 114 115 116 117 118

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 {
119
    int defaultFormat;
120
    int lastFormat;
121 122 123 124 125 126
    virStorageVolFormatToString formatToString;
    virStorageVolFormatFromString formatFromString;
};

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

typedef struct _virStoragePoolOptions virStoragePoolOptions;
typedef virStoragePoolOptions *virStoragePoolOptionsPtr;
struct _virStoragePoolOptions {
E
Eric Blake 已提交
139
    unsigned int flags;
140
    int defaultFormat;
141
    int lastFormat;
142 143 144

    virStoragePoolXMLNamespace ns;

145 146 147 148 149 150 151 152 153 154 155 156
    virStoragePoolFormatToString formatToString;
    virStoragePoolFormatFromString formatFromString;
};

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

157

E
Eric Blake 已提交
158 159 160 161 162 163 164 165 166
static int
virStorageVolumeFormatFromString(const char *format)
{
    int ret = virStorageFileFormatTypeFromString(format);
    if (ret == VIR_STORAGE_FILE_NONE)
        return -1;
    return ret;
}

167

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


static virStoragePoolTypeInfoPtr
304 305
virStoragePoolTypeInfoLookup(int type)
{
306
    size_t i;
307
    for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo); i++)
308 309 310
        if (poolTypeInfo[i].poolType == type)
            return &poolTypeInfo[i];

311 312
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("missing backend for pool type %d"), type);
313 314 315
    return NULL;
}

316

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

326

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
/* virStoragePoolOptionsPoolTypeSetXMLNamespace:
 * @type: virStoragePoolType
 * @ns: xmlopt namespace pointer
 *
 * Store the @ns in the pool options for the particular backend.
 * This allows the parse/format code to then directly call the Namespace
 * method space (parse, format, href, free) as needed during processing.
 *
 * Returns: 0 on success, -1 on failure.
 */
int
virStoragePoolOptionsPoolTypeSetXMLNamespace(int type,
                                             virStoragePoolXMLNamespacePtr ns)
{
    int ret = -1;
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);

    if (!backend)
        goto cleanup;

    backend->poolOptions.ns = *ns;
    ret = 0;

 cleanup:
    return ret;
}


355
static virStorageVolOptionsPtr
356 357
virStorageVolOptionsForPoolType(int type)
{
358 359 360 361 362 363 364
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->volOptions;
}


365 366 367 368 369 370 371 372 373
int
virStoragePoolOptionsFormatPool(virBufferPtr buf,
                                int type)
{
    virStoragePoolOptionsPtr poolOptions;

    if (!(poolOptions = virStoragePoolOptionsForPoolType(type)))
        return -1;

374
    if (!poolOptions->formatToString)
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
        return 0;

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

    if (poolOptions->formatToString) {
        size_t i;

        virBufferAsprintf(buf, "<defaultFormat type='%s'/>\n",
                          (poolOptions->formatToString)(poolOptions->defaultFormat));

        virBufferAddLit(buf, "<enum name='sourceFormatType'>\n");
        virBufferAdjustIndent(buf, 2);

        for (i = 0; i < poolOptions->lastFormat; i++)
            virBufferAsprintf(buf, "<value>%s</value>\n",
                              (poolOptions->formatToString)(i));

        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</enum>\n");
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</poolOptions>\n");
    return 0;
}


int
virStoragePoolOptionsFormatVolume(virBufferPtr buf,
                                  int type)
{
    size_t i;
    virStorageVolOptionsPtr volOptions;

    if (!(volOptions = virStorageVolOptionsForPoolType(type)))
        return -1;

    if (!volOptions->formatToString)
        return 0;

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

    virBufferAsprintf(buf, "<defaultFormat type='%s'/>\n",
                      (volOptions->formatToString)(volOptions->defaultFormat));

    virBufferAddLit(buf, "<enum name='targetFormatType'>\n");
    virBufferAdjustIndent(buf, 2);

    for (i = 0; i < volOptions->lastFormat; i++)
        virBufferAsprintf(buf, "<value>%s</value>\n",
                          (volOptions->formatToString)(i));

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

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

    return 0;
}


439
void
440 441
virStorageVolDefFree(virStorageVolDefPtr def)
{
442
    size_t i;
443 444 445 446

    if (!def)
        return;

447 448
    VIR_FREE(def->name);
    VIR_FREE(def->key);
449

450
    for (i = 0; i < def->source.nextent; i++)
451 452
        VIR_FREE(def->source.extents[i].path);
    VIR_FREE(def->source.extents);
453

454
    virStorageSourceClear(&def->target);
455
    VIR_FREE(def);
456 457
}

458

459 460 461 462 463 464 465
void
virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev)
{
    VIR_FREE(dev->freeExtents);
    VIR_FREE(dev->path);
}

466

467
void
468 469
virStoragePoolSourceClear(virStoragePoolSourcePtr source)
{
470
    size_t i;
471

472
    if (!source)
473 474
        return;

475
    for (i = 0; i < source->nhost; i++)
476 477 478
        VIR_FREE(source->hosts[i].name);
    VIR_FREE(source->hosts);

479 480
    for (i = 0; i < source->ndevice; i++)
        virStoragePoolSourceDeviceClear(&source->devices[i]);
481 482 483
    VIR_FREE(source->devices);
    VIR_FREE(source->dir);
    VIR_FREE(source->name);
484
    virStorageAdapterClear(&source->adapter);
485
    virStorageSourceInitiatorClear(&source->initiator);
486
    virStorageAuthDefFree(source->auth);
487 488
    VIR_FREE(source->vendor);
    VIR_FREE(source->product);
489 490
}

491

492 493 494 495 496 497 498
void
virStoragePoolSourceFree(virStoragePoolSourcePtr source)
{
    virStoragePoolSourceClear(source);
    VIR_FREE(source);
}

499

500
void
501 502
virStoragePoolDefFree(virStoragePoolDefPtr def)
{
503 504 505 506 507
    if (!def)
        return;

    VIR_FREE(def->name);

508
    virStoragePoolSourceClear(&def->source);
509

510 511
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
512
    VIR_FREE(def->refresh);
513 514
    if (def->namespaceData && def->ns.free)
        (def->ns.free)(def->namespaceData);
515
    VIR_FREE(def);
516 517 518
}


519
static int
520
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
521 522
                             virStoragePoolSourcePtr source,
                             int pool_type,
523 524
                             xmlNodePtr node)
{
525
    int ret = -1;
526
    xmlNodePtr relnode, authnode;
527
    xmlNodePtr adapternode;
528 529
    int nsource;
    size_t i;
530
    virStoragePoolOptionsPtr options;
531
    int n;
532
    VIR_AUTOPTR(virStorageAuthDef) authdef = NULL;
533 534 535
    VIR_AUTOFREE(char *) port = NULL;
    VIR_AUTOFREE(char *) ver = NULL;
    VIR_AUTOFREE(xmlNodePtr *) nodeset = NULL;
536
    VIR_AUTOFREE(char *) sourcedir = NULL;
537 538 539 540

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

541
    if ((options = virStoragePoolOptionsForPoolType(pool_type)) == NULL)
542 543
        goto cleanup;

544
    source->name = virXPathString("string(./name)", ctxt);
545
    if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
546
        virReportError(VIR_ERR_XML_ERROR, "%s",
547
                       _("element 'name' is mandatory for RBD pool"));
548 549
        goto cleanup;
    }
550 551

    if (options->formatFromString) {
552 553 554
        VIR_AUTOFREE(char *) format = NULL;

        format = virXPathString("string(./format/@type)", ctxt);
555 556 557 558 559 560
        if (format == NULL)
            source->format = options->defaultFormat;
        else
            source->format = options->formatFromString(format);

        if (source->format < 0) {
561
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
562
                           _("unknown pool format type %s"), format);
563 564 565 566
            goto cleanup;
        }
    }

567 568
    if ((n = virXPathNodeSet("./host", ctxt, &nodeset)) < 0)
        goto cleanup;
569

570 571
    if (n) {
        if (VIR_ALLOC_N(source->hosts, n) < 0)
572
            goto cleanup;
573
        source->nhost = n;
574

575
        for (i = 0; i < source->nhost; i++) {
576 577
            source->hosts[i].name = virXMLPropString(nodeset[i], "name");
            if (!source->hosts[i].name) {
578 579
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing storage pool host name"));
580 581 582 583 584 585
                goto cleanup;
            }

            port = virXMLPropString(nodeset[i], "port");
            if (port) {
                if (virStrToLong_i(port, NULL, 10, &source->hosts[i].port) < 0) {
586 587 588
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("Invalid port number: %s"),
                                   port);
589 590 591
                    goto cleanup;
                }
            }
592
            VIR_FREE(port);
593 594
        }
    }
595

596
    VIR_FREE(nodeset);
597 598

    virStorageSourceInitiatorParseXML(ctxt, &source->initiator);
599

600
    nsource = virXPathNodeSet("./device", ctxt, &nodeset);
601 602 603
    if (nsource < 0)
        goto cleanup;

604
    for (i = 0; i < nsource; i++) {
605
        VIR_AUTOFREE(char *) partsep = NULL;
606 607 608 609 610 611
        virStoragePoolSourceDevice dev = { .path = NULL };
        dev.path = virXMLPropString(nodeset[i], "path");

        if (dev.path == NULL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source device path"));
612 613 614
            goto cleanup;
        }

615 616 617 618 619 620 621 622 623 624 625 626
        partsep = virXMLPropString(nodeset[i], "part_separator");
        if (partsep) {
            dev.part_separator = virTristateBoolTypeFromString(partsep);
            if (dev.part_separator <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("invalid part_separator setting '%s'"),
                               partsep);
                virStoragePoolSourceDeviceClear(&dev);
                goto cleanup;
            }
        }

627 628 629
        if (VIR_APPEND_ELEMENT(source->devices, source->ndevice, dev) < 0) {
            virStoragePoolSourceDeviceClear(&dev);
            goto cleanup;
630
        }
631

632 633
    }

634 635 636
    sourcedir = virXPathString("string(./dir/@path)", ctxt);
    if (sourcedir)
        source->dir = virFileSanitizePath(sourcedir);
637 638 639 640
    /* In gluster, a missing dir defaults to "/" */
    if (!source->dir && pool_type == VIR_STORAGE_POOL_GLUSTER &&
        VIR_STRDUP(source->dir, "/") < 0)
        goto cleanup;
641

642
    if ((adapternode = virXPathNode("./adapter", ctxt))) {
643
        if (virStorageAdapterParseXML(&source->adapter, adapternode, ctxt) < 0)
644 645
            goto cleanup;
    }
646

647
    if ((authnode = virXPathNode("./auth", ctxt))) {
648
        if (!(authdef = virStorageAuthDefParse(authnode, ctxt)))
649 650 651 652 653 654 655 656
            goto cleanup;

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

657
        VIR_STEAL_PTR(source->auth, authdef);
658
    }
659

660 661 662 663 664 665 666 667 668 669 670 671
    /* Option protocol version string (NFSvN) */
    if ((ver = virXPathString("string(./protocol/@ver)", ctxt))) {
        if ((source->format != VIR_STORAGE_POOL_NETFS_NFS) &&
            (source->format != VIR_STORAGE_POOL_NETFS_AUTO)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("storage pool protocol ver unsupported for "
                             "pool type '%s'"),
                           virStoragePoolFormatFileSystemNetTypeToString(source->format));
            goto cleanup;
        }
        if (virStrToLong_uip(ver, NULL, 0, &source->protocolVer) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
J
John Ferlan 已提交
672
                           _("storage pool protocol ver '%s' is malformed"),
673 674 675 676 677
                           ver);
            goto cleanup;
        }
    }

678 679 680
    source->vendor = virXPathString("string(./vendor/@name)", ctxt);
    source->product = virXPathString("string(./product/@name)", ctxt);

681
    ret = 0;
682
 cleanup:
683 684 685 686
    ctxt->node = relnode;

    return ret;
}
687

688

689
virStoragePoolSourcePtr
690
virStoragePoolDefParseSourceString(const char *srcSpec,
691 692 693 694 695
                                   int pool_type)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr node = NULL;
    xmlXPathContextPtr xpath_ctxt = NULL;
696 697
    virStoragePoolSourcePtr ret = NULL;
    VIR_AUTOPTR(virStoragePoolSource) def = NULL;
698

699 700 701
    if (!(doc = virXMLParseStringCtxt(srcSpec,
                                      _("(storage_source_specification)"),
                                      &xpath_ctxt)))
702 703
        goto cleanup;

704
    if (VIR_ALLOC(def) < 0)
705 706
        goto cleanup;

707
    if (!(node = virXPathNode("/source", xpath_ctxt))) {
708 709
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("root element was not source"));
710 711 712
        goto cleanup;
    }

713
    if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
714 715 716
                                     node) < 0)
        goto cleanup;

717
    VIR_STEAL_PTR(ret, def);
718
 cleanup:
719 720 721 722 723
    xmlFreeDoc(doc);
    xmlXPathFreeContext(xpath_ctxt);

    return ret;
}
724

725

726
static int
727
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
728
                        virStoragePermsPtr perms,
729
                        const char *permxpath)
730
{
731
    long long val;
732 733 734
    int ret = -1;
    xmlNodePtr relnode;
    xmlNodePtr node;
735
    VIR_AUTOFREE(char *) mode = NULL;
736

737
    node = virXPathNode(permxpath, ctxt);
738 739
    if (node == NULL) {
        /* Set default values if there is not <permissions> element */
740
        perms->mode = (mode_t) -1;
P
Philipp Hahn 已提交
741 742
        perms->uid = (uid_t) -1;
        perms->gid = (gid_t) -1;
743 744 745 746 747 748 749
        perms->label = NULL;
        return 0;
    }

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

750
    if ((mode = virXPathString("string(./mode)", ctxt))) {
751 752 753
        int tmp;

        if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
754 755
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed octal mode"));
756
            goto error;
757
        }
758
        perms->mode = tmp;
759 760
    } else {
        perms->mode = (mode_t) -1;
761 762
    }

763
    if (virXPathNode("./owner", ctxt) == NULL) {
P
Philipp Hahn 已提交
764
        perms->uid = (uid_t) -1;
765
    } else {
766
        /* We previously could output -1, so continue to parse it */
767
        if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 ||
768 769
            ((uid_t)val != val &&
             val != -1)) {
770 771
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed owner element"));
772
            goto error;
773
        }
774 775

        perms->uid = val;
776 777
    }

778
    if (virXPathNode("./group", ctxt) == NULL) {
P
Philipp Hahn 已提交
779
        perms->gid = (gid_t) -1;
780
    } else {
781
        /* We previously could output -1, so continue to parse it */
782
        if (virXPathLongLong("number(./group)", ctxt, &val) < 0 ||
783 784
            ((gid_t) val != val &&
             val != -1)) {
785 786
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed group element"));
787
            goto error;
788
        }
789
        perms->gid = val;
790 791 792
    }

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

795
    ret = 0;
796
 error:
797 798
    ctxt->node = relnode;
    return ret;
799 800
}

801

802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
static int
virStoragePoolDefRefreshParse(xmlXPathContextPtr ctxt,
                              virStoragePoolDefPtr def)
{
    VIR_AUTOFREE(virStoragePoolDefRefreshPtr) refresh = NULL;
    VIR_AUTOFREE(char *) allocation = NULL;
    int tmp;

    allocation = virXPathString("string(./refresh/volume/@allocation)", ctxt);

    if (!allocation)
        return 0;

    if ((tmp = virStorageVolDefRefreshAllocationTypeFromString(allocation)) < 0) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown storage pool volume refresh allocation type %s"),
                       allocation);
        return -1;
    }

    if (VIR_ALLOC(refresh) < 0)
        return -1;

    refresh->volume.allocation = tmp;
    VIR_STEAL_PTR(def->refresh, refresh);
    return 0;
}


static void
virStoragePoolDefRefreshFormat(virBufferPtr buf,
                               virStoragePoolDefRefreshPtr refresh)
{
    if (!refresh)
        return;

    virBufferAddLit(buf, "<refresh>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<volume allocation='%s'/>\n",
                      virStorageVolDefRefreshAllocationTypeToString(refresh->volume.allocation));
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</refresh>\n");
}


J
John Ferlan 已提交
847
virStoragePoolDefPtr
848 849
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
{
850
    virStoragePoolOptionsPtr options;
851
    virStoragePoolDefPtr ret = NULL;
852
    xmlNodePtr source_node;
853
    VIR_AUTOPTR(virStoragePoolDef) def = NULL;
854 855 856
    VIR_AUTOFREE(char *) type = NULL;
    VIR_AUTOFREE(char *) uuid = NULL;
    VIR_AUTOFREE(char *) target_path = NULL;
857

858
    if (VIR_ALLOC(def) < 0)
859 860
        return NULL;

861
    type = virXPathString("string(./@type)", ctxt);
862 863 864
    if (type == NULL) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("storage pool missing type attribute"));
865
        return NULL;
866 867
    }

868
    if ((def->type = virStoragePoolTypeFromString(type)) < 0) {
869
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
870
                       _("unknown storage pool type %s"), type);
871
        return NULL;
872 873
    }

874
    if ((options = virStoragePoolOptionsForPoolType(def->type)) == NULL)
875
        return NULL;
876

877
    source_node = virXPathNode("./source", ctxt);
878
    if (source_node) {
879
        if (virStoragePoolDefParseSource(ctxt, &def->source, def->type,
880
                                         source_node) < 0)
881
            return NULL;
882 883
    } else {
        if (options->formatFromString)
884
            def->source.format = options->defaultFormat;
885 886
    }

887 888
    def->name = virXPathString("string(./name)", ctxt);
    if (def->name == NULL &&
889
        options->flags & VIR_STORAGE_POOL_SOURCE_NAME &&
890
        VIR_STRDUP(def->name, def->source.name) < 0)
891 892
        return NULL;

893
    if (def->name == NULL) {
894 895
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing pool source name element"));
896
        return NULL;
897 898
    }

899
    if (strchr(def->name, '/')) {
900
        virReportError(VIR_ERR_XML_ERROR,
901
                       _("name %s cannot contain '/'"), def->name);
902
        return NULL;
903 904
    }

905
    uuid = virXPathString("string(./uuid)", ctxt);
906
    if (uuid == NULL) {
907
        if (virUUIDGenerate(def->uuid) < 0) {
908 909
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unable to generate uuid"));
910
            return NULL;
911 912
        }
    } else {
913
        if (virUUIDParse(uuid, def->uuid) < 0) {
914 915
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("malformed uuid element"));
916
            return NULL;
917 918 919
        }
    }

920
    if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
921
        if (!def->source.nhost) {
922
            virReportError(VIR_ERR_XML_ERROR, "%s",
923
                           _("missing storage pool source host name"));
924
            return NULL;
925 926 927
        }
    }

928
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
929
        if (!def->source.dir) {
930 931
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source path"));
932
            return NULL;
933 934
        }
    }
935
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
936
        if (def->source.name == NULL) {
937
            /* source name defaults to pool name */
938
            if (VIR_STRDUP(def->source.name, def->name) < 0)
939
                return NULL;
940 941
        }
    }
942

943
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
944
        (virStorageAdapterValidate(&def->source.adapter)) < 0)
945
            return NULL;
946

947 948
    /* If DEVICE is the only source type, then its required */
    if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
949
        if (!def->source.ndevice) {
950 951
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing storage pool source device name"));
952
            return NULL;
953 954 955
        }
    }

956 957 958
    /* When we are working with a virtual disk we can skip the target
     * path and permissions */
    if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
959 960
        if (def->type == VIR_STORAGE_POOL_LOGICAL) {
            if (virAsprintf(&target_path, "/dev/%s", def->source.name) < 0)
961
                return NULL;
962 963
        } else if (def->type == VIR_STORAGE_POOL_ZFS) {
            if (virAsprintf(&target_path, "/dev/zvol/%s", def->source.name) < 0)
964
                return NULL;
965 966 967 968 969
        } else {
            target_path = virXPathString("string(./target/path)", ctxt);
            if (!target_path) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing storage pool target path"));
970
                return NULL;
971
            }
972
        }
973 974
        def->target.path = virFileSanitizePath(target_path);
        if (!def->target.path)
975
            return NULL;
976

977
        if (virStorageDefParsePerms(ctxt, &def->target.perms,
978
                                    "./target/permissions") < 0)
979
            return NULL;
980
    }
981

982 983
    if (def->type == VIR_STORAGE_POOL_ISCSI_DIRECT &&
        !def->source.initiator.iqn) {
984 985
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("missing initiator IQN"));
986
        return NULL;
987 988
    }

989 990 991
    if (virStoragePoolDefRefreshParse(ctxt, def) < 0)
        return NULL;

992 993
    /* Make a copy of all the callback pointers here for easier use,
     * especially during the virStoragePoolSourceClear method */
994 995 996
    def->ns = options->ns;
    if (def->ns.parse &&
        (def->ns.parse)(ctxt, &def->namespaceData) < 0)
997
        return NULL;
998

999
    VIR_STEAL_PTR(ret, def);
1000
    return ret;
1001 1002
}

1003

1004
virStoragePoolDefPtr
1005
virStoragePoolDefParseNode(xmlDocPtr xml,
1006 1007
                           xmlNodePtr root)
{
1008 1009 1010
    xmlXPathContextPtr ctxt = NULL;
    virStoragePoolDefPtr def = NULL;

1011
    if (!virXMLNodeNameEqual(root, "pool")) {
1012
        virReportError(VIR_ERR_XML_ERROR,
1013 1014 1015
                       _("unexpected root element <%s>, "
                         "expecting <pool>"),
                       root->name);
1016 1017 1018 1019 1020
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1021
        virReportOOMError();
1022 1023 1024 1025
        goto cleanup;
    }

    ctxt->node = root;
1026
    def = virStoragePoolDefParseXML(ctxt);
1027
 cleanup:
1028 1029 1030 1031
    xmlXPathFreeContext(ctxt);
    return def;
}

1032

1033
static virStoragePoolDefPtr
1034
virStoragePoolDefParse(const char *xmlStr,
1035 1036
                       const char *filename)
{
1037
    virStoragePoolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1038
    xmlDocPtr xml;
1039

1040
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_pool_definition)")))) {
J
Jiri Denemark 已提交
1041 1042
        ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1043 1044
    }

1045 1046 1047
    return ret;
}

1048

1049
virStoragePoolDefPtr
1050
virStoragePoolDefParseString(const char *xmlStr)
1051
{
1052
    return virStoragePoolDefParse(xmlStr, NULL);
1053 1054
}

1055

1056
virStoragePoolDefPtr
1057
virStoragePoolDefParseFile(const char *filename)
1058
{
1059
    return virStoragePoolDefParse(NULL, filename);
1060 1061
}

1062

1063
static int
1064
virStoragePoolSourceFormat(virBufferPtr buf,
1065
                           virStoragePoolOptionsPtr options,
1066 1067
                           virStoragePoolSourcePtr src)
{
1068
    size_t i, j;
1069

1070 1071 1072
    virBufferAddLit(buf, "<source>\n");
    virBufferAdjustIndent(buf, 2);

1073 1074
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
        for (i = 0; i < src->nhost; i++) {
1075
            virBufferEscapeString(buf, "<host name='%s'",
1076
                                  src->hosts[i].name);
1077 1078 1079 1080
            if (src->hosts[i].port)
                virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
            virBufferAddLit(buf, "/>\n");
        }
1081
    }
1082

1083
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
1084
        src->ndevice) {
1085
        for (i = 0; i < src->ndevice; i++) {
1086 1087 1088 1089 1090 1091 1092
            virBufferEscapeString(buf, "<device path='%s'",
                                  src->devices[i].path);
            if (src->devices[i].part_separator !=
                VIR_TRISTATE_SWITCH_ABSENT) {
                virBufferAsprintf(buf, " part_separator='%s'",
                                  virTristateBoolTypeToString(src->devices[i].part_separator));
            }
1093
            if (src->devices[i].nfreeExtent) {
1094
                virBufferAddLit(buf, ">\n");
1095
                virBufferAdjustIndent(buf, 2);
1096
                for (j = 0; j < src->devices[i].nfreeExtent; j++) {
1097
                    virBufferAsprintf(buf, "<freeExtent start='%llu' end='%llu'/>\n",
1098 1099 1100
                                      src->devices[i].freeExtents[j].start,
                                      src->devices[i].freeExtents[j].end);
                }
1101 1102
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</device>\n");
1103
            } else {
1104
                virBufferAddLit(buf, "/>\n");
1105
            }
1106 1107
        }
    }
1108

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

1112
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
1113 1114 1115
        (src->adapter.type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST ||
         src->adapter.type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST))
        virStorageAdapterFormat(buf, &src->adapter);
1116

1117
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
1118
        virBufferEscapeString(buf, "<name>%s</name>\n", src->name);
1119

1120 1121
    if (options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN)
        virStorageSourceInitiatorFormatXML(&src->initiator, buf);
D
David Allan 已提交
1122

1123 1124 1125
    if (options->formatToString) {
        const char *format = (options->formatToString)(src->format);
        if (!format) {
1126 1127 1128
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown pool format number %d"),
                           src->format);
1129 1130
            return -1;
        }
1131
        virBufferAsprintf(buf, "<format type='%s'/>\n", format);
1132 1133
    }

1134 1135
    if (src->auth)
        virStorageAuthDefFormat(buf, src->auth);
1136

1137 1138 1139
    if (src->protocolVer)
        virBufferAsprintf(buf, "<protocol ver='%u'/>\n", src->protocolVer);

1140 1141
    virBufferEscapeString(buf, "<vendor name='%s'/>\n", src->vendor);
    virBufferEscapeString(buf, "<product name='%s'/>\n", src->product);
1142

1143 1144
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</source>\n");
1145 1146 1147
    return 0;
}

1148

1149 1150 1151
static int
virStoragePoolDefFormatBuf(virBufferPtr buf,
                           virStoragePoolDefPtr def)
1152
{
1153
    virStoragePoolOptionsPtr options;
1154
    char uuid[VIR_UUID_STRING_BUFLEN];
1155
    const char *type;
1156

1157
    options = virStoragePoolOptionsForPoolType(def->type);
1158
    if (options == NULL)
1159
        return -1;
1160

1161
    type = virStoragePoolTypeToString(def->type);
1162
    if (!type) {
1163 1164
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected pool type"));
1165
        return -1;
1166
    }
1167 1168 1169 1170
    virBufferAsprintf(buf, "<pool type='%s'", type);
    if (def->namespaceData && def->ns.href)
        virBufferAsprintf(buf, " %s", (def->ns.href)());
    virBufferAddLit(buf, ">\n");
1171 1172
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
1173 1174

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

1177
    virBufferAsprintf(buf, "<capacity unit='bytes'>%llu</capacity>\n",
1178
                      def->capacity);
1179
    virBufferAsprintf(buf, "<allocation unit='bytes'>%llu</allocation>\n",
1180
                      def->allocation);
1181
    virBufferAsprintf(buf, "<available unit='bytes'>%llu</available>\n",
1182
                      def->available);
1183

1184 1185
    if (virStoragePoolSourceFormat(buf, options, &def->source) < 0)
        return -1;
1186

1187
    /* RBD, Sheepdog, Gluster and Iscsi-direct devices are not local block devs nor
1188
     * files, so they don't have a target */
1189
    if (def->type != VIR_STORAGE_POOL_RBD &&
1190
        def->type != VIR_STORAGE_POOL_SHEEPDOG &&
1191 1192
        def->type != VIR_STORAGE_POOL_GLUSTER &&
        def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) {
1193 1194
        virBufferAddLit(buf, "<target>\n");
        virBufferAdjustIndent(buf, 2);
1195

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

1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
        if (def->target.perms.mode != (mode_t) -1 ||
            def->target.perms.uid != (uid_t) -1 ||
            def->target.perms.gid != (gid_t) -1 ||
            def->target.perms.label) {
            virBufferAddLit(buf, "<permissions>\n");
            virBufferAdjustIndent(buf, 2);
            if (def->target.perms.mode != (mode_t) -1)
                virBufferAsprintf(buf, "<mode>0%o</mode>\n",
                                  def->target.perms.mode);
            if (def->target.perms.uid != (uid_t) -1)
                virBufferAsprintf(buf, "<owner>%d</owner>\n",
                                  (int) def->target.perms.uid);
            if (def->target.perms.gid != (gid_t) -1)
                virBufferAsprintf(buf, "<group>%d</group>\n",
                                  (int) def->target.perms.gid);
            virBufferEscapeString(buf, "<label>%s</label>\n",
                                  def->target.perms.label);

            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</permissions>\n");
        }
1219

1220 1221
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</target>\n");
1222
    }
1223

1224 1225
    virStoragePoolDefRefreshFormat(buf, def->refresh);

1226 1227 1228 1229 1230
    if (def->namespaceData && def->ns.format) {
        if ((def->ns.format)(buf, def->namespaceData) < 0)
            return -1;
    }

1231 1232 1233 1234 1235 1236
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</pool>\n");

    return 0;
}

1237

1238 1239 1240 1241 1242 1243 1244
char *
virStoragePoolDefFormat(virStoragePoolDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

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

1246
    if (virBufferCheckError(&buf) < 0)
1247
        goto error;
1248

1249
    return virBufferContentAndReset(&buf);
1250

1251
 error:
1252
    virBufferFreeAndReset(&buf);
1253 1254 1255 1256 1257
    return NULL;
}


static int
1258
virStorageSize(const char *unit,
1259
               const char *val,
1260 1261
               unsigned long long *ret)
{
J
Ján Tomko 已提交
1262
    if (virStrToLong_ullp(val, NULL, 10, ret) < 0) {
1263 1264
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("malformed capacity element"));
1265 1266
        return -1;
    }
1267 1268 1269 1270
    /* 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;
1271 1272 1273 1274

    return 0;
}

1275

1276
static virStorageVolDefPtr
1277
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
1278 1279
                         xmlXPathContextPtr ctxt,
                         unsigned int flags)
1280
{
1281
    virStorageVolDefPtr ret = NULL;
1282
    virStorageVolOptionsPtr options;
1283
    xmlNodePtr node;
1284 1285
    size_t i;
    int n;
1286
    VIR_AUTOPTR(virStorageVolDef) def = NULL;
1287 1288 1289 1290 1291 1292
    VIR_AUTOFREE(char *) type = NULL;
    VIR_AUTOFREE(char *) allocation = NULL;
    VIR_AUTOFREE(char *) capacity = NULL;
    VIR_AUTOFREE(char *) unit = NULL;
    VIR_AUTOFREE(char *) backingStore = NULL;
    VIR_AUTOFREE(xmlNodePtr *) nodes = NULL;
1293

1294 1295
    virCheckFlags(VIR_VOL_XML_PARSE_NO_CAPACITY |
                  VIR_VOL_XML_PARSE_OPT_CAPACITY, NULL);
1296

1297
    options = virStorageVolOptionsForPoolType(pool->type);
1298 1299 1300
    if (options == NULL)
        return NULL;

1301
    if (VIR_ALLOC(def) < 0)
1302 1303
        return NULL;

1304
    def->target.type = VIR_STORAGE_TYPE_FILE;
1305

1306 1307
    def->name = virXPathString("string(./name)", ctxt);
    if (def->name == NULL) {
1308 1309
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing volume name element"));
1310
        return NULL;
1311 1312
    }

1313
    /* Normally generated by pool refresh, but useful for unit tests */
1314
    def->key = virXPathString("string(./key)", ctxt);
1315

1316 1317 1318
    /* Technically overridden by pool refresh, but useful for unit tests */
    type = virXPathString("string(./@type)", ctxt);
    if (type) {
1319
        if ((def->type = virStorageVolTypeFromString(type)) < 0) {
1320
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1321
                           _("unknown volume type '%s'"), type);
1322
            return NULL;
1323 1324 1325
        }
    }

1326
    if ((backingStore = virXPathString("string(./backingStore/path)", ctxt))) {
1327
        if (!(def->target.backingStore = virStorageSourceNew()))
1328
            return NULL;
1329

1330
        def->target.backingStore->type = VIR_STORAGE_TYPE_FILE;
1331

1332
        def->target.backingStore->path = backingStore;
1333 1334 1335
        backingStore = NULL;

        if (options->formatFromString) {
1336 1337 1338
            VIR_AUTOFREE(char *) format = NULL;

            format = virXPathString("string(./backingStore/format/@type)", ctxt);
1339
            if (format == NULL)
1340
                def->target.backingStore->format = options->defaultFormat;
1341
            else
1342
                def->target.backingStore->format = (options->formatFromString)(format);
1343

1344
            if (def->target.backingStore->format < 0) {
1345 1346
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown volume format type %s"), format);
1347
                return NULL;
1348 1349 1350
            }
        }

1351
        if (VIR_ALLOC(def->target.backingStore->perms) < 0)
1352
            return NULL;
1353
        if (virStorageDefParsePerms(ctxt, def->target.backingStore->perms,
1354
                                    "./backingStore/permissions") < 0)
1355
            return NULL;
1356 1357
    }

1358 1359
    capacity = virXPathString("string(./capacity)", ctxt);
    unit = virXPathString("string(./capacity/@unit)", ctxt);
1360
    if (capacity) {
1361
        if (virStorageSize(unit, capacity, &def->target.capacity) < 0)
1362
            return NULL;
1363
    } else if (!(flags & VIR_VOL_XML_PARSE_NO_CAPACITY) &&
1364
               !((flags & VIR_VOL_XML_PARSE_OPT_CAPACITY) &&
1365
                 virStorageSourceHasBacking(&def->target))) {
1366
        virReportError(VIR_ERR_XML_ERROR, "%s", _("missing capacity element"));
1367
        return NULL;
1368
    }
1369
    VIR_FREE(unit);
1370

1371
    allocation = virXPathString("string(./allocation)", ctxt);
1372
    if (allocation) {
1373
        unit = virXPathString("string(./allocation/@unit)", ctxt);
1374
        if (virStorageSize(unit, allocation, &def->target.allocation) < 0)
1375
            return NULL;
1376
        def->target.has_allocation = true;
1377
    } else {
1378
        def->target.allocation = def->target.capacity;
1379 1380
    }

1381
    def->target.path = virXPathString("string(./target/path)", ctxt);
1382
    if (options->formatFromString) {
1383 1384 1385
        VIR_AUTOFREE(char *) format = NULL;

        format = virXPathString("string(./target/format/@type)", ctxt);
1386
        if (format == NULL)
1387
            def->target.format = options->defaultFormat;
1388
        else
1389
            def->target.format = (options->formatFromString)(format);
1390

1391
        if (def->target.format < 0) {
1392
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1393
                           _("unknown volume format type %s"), format);
1394
            return NULL;
1395 1396 1397
        }
    }

1398
    if (VIR_ALLOC(def->target.perms) < 0)
1399
        return NULL;
1400
    if (virStorageDefParsePerms(ctxt, def->target.perms,
1401
                                "./target/permissions") < 0)
1402
        return NULL;
1403

1404
    node = virXPathNode("./target/encryption", ctxt);
1405
    if (node != NULL) {
1406 1407
        def->target.encryption = virStorageEncryptionParseNode(node, ctxt);
        if (def->target.encryption == NULL)
1408
            return NULL;
1409 1410
    }

1411 1412
    def->target.compat = virXPathString("string(./target/compat)", ctxt);
    if (virStorageFileCheckCompat(def->target.compat) < 0)
1413
        return NULL;
1414

C
Chunyan Liu 已提交
1415
    if (virXPathNode("./target/nocow", ctxt))
1416
        def->target.nocow = true;
C
Chunyan Liu 已提交
1417

1418
    if (virXPathNode("./target/features", ctxt)) {
1419
        if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
1420
            return NULL;
1421

1422
        if (!def->target.compat && VIR_STRDUP(def->target.compat, "1.1") < 0)
1423
            return NULL;
1424

1425
        if (!(def->target.features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST)))
1426
            return NULL;
1427 1428

        for (i = 0; i < n; i++) {
1429
            int f = virStorageFileFeatureTypeFromString((const char*)nodes[i]->name);
1430 1431

            if (f < 0) {
1432
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported feature %s"),
1433
                               (const char*)nodes[i]->name);
1434
                return NULL;
1435
            }
1436
            ignore_value(virBitmapSetBit(def->target.features, f));
1437 1438 1439 1440
        }
        VIR_FREE(nodes);
    }

1441
    VIR_STEAL_PTR(ret, def);
1442
    return ret;
1443 1444
}

1445

1446
virStorageVolDefPtr
1447
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
1448
                          xmlDocPtr xml,
1449 1450
                          xmlNodePtr root,
                          unsigned int flags)
1451
{
1452 1453 1454
    xmlXPathContextPtr ctxt = NULL;
    virStorageVolDefPtr def = NULL;

1455
    if (!virXMLNodeNameEqual(root, "volume")) {
1456
        virReportError(VIR_ERR_XML_ERROR,
1457 1458 1459
                       _("unexpected root element <%s>, "
                         "expecting <volume>"),
                       root->name);
1460 1461 1462 1463 1464
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1465
        virReportOOMError();
1466 1467 1468 1469
        goto cleanup;
    }

    ctxt->node = root;
1470
    def = virStorageVolDefParseXML(pool, ctxt, flags);
1471
 cleanup:
1472 1473 1474 1475
    xmlXPathFreeContext(ctxt);
    return def;
}

1476

1477
static virStorageVolDefPtr
1478
virStorageVolDefParse(virStoragePoolDefPtr pool,
1479
                      const char *xmlStr,
1480 1481
                      const char *filename,
                      unsigned int flags)
1482
{
1483
    virStorageVolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1484
    xmlDocPtr xml;
1485

1486
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_volume_definition)")))) {
1487
        ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml), flags);
J
Jiri Denemark 已提交
1488
        xmlFreeDoc(xml);
1489 1490 1491 1492 1493
    }

    return ret;
}

1494

1495
virStorageVolDefPtr
1496
virStorageVolDefParseString(virStoragePoolDefPtr pool,
1497 1498
                            const char *xmlStr,
                            unsigned int flags)
1499
{
1500
    return virStorageVolDefParse(pool, xmlStr, NULL, flags);
1501 1502
}

1503

1504
virStorageVolDefPtr
1505
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
1506 1507
                          const char *filename,
                          unsigned int flags)
1508
{
1509
    return virStorageVolDefParse(pool, NULL, filename, flags);
1510
}
1511

1512

1513 1514 1515 1516 1517 1518
static void
virStorageVolTimestampFormat(virBufferPtr buf, const char *name,
                             struct timespec *ts)
{
    if (ts->tv_nsec < 0)
        return;
1519
    virBufferAsprintf(buf, "<%s>%llu", name,
1520 1521 1522 1523 1524 1525
                      (unsigned long long) ts->tv_sec);
    if (ts->tv_nsec)
       virBufferAsprintf(buf, ".%09ld", ts->tv_nsec);
    virBufferAsprintf(buf, "</%s>\n", name);
}

1526

1527
static int
1528
virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
1529
                             virBufferPtr buf,
1530
                             virStorageSourcePtr def,
1531 1532
                             const char *type)
{
1533 1534
    virBufferAsprintf(buf, "<%s>\n", type);
    virBufferAdjustIndent(buf, 2);
1535

1536
    virBufferEscapeString(buf, "<path>%s</path>\n", def->path);
1537 1538 1539 1540

    if (options->formatToString) {
        const char *format = (options->formatToString)(def->format);
        if (!format) {
1541 1542 1543
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown volume format number %d"),
                           def->format);
1544 1545
            return -1;
        }
1546
        virBufferAsprintf(buf, "<format type='%s'/>\n", format);
1547 1548
    }

1549 1550 1551 1552 1553
    if (def->perms &&
        (def->perms->mode != (mode_t) -1 ||
         def->perms->uid != (uid_t) -1 ||
         def->perms->gid != (gid_t) -1 ||
         def->perms->label)) {
1554 1555
        virBufferAddLit(buf, "<permissions>\n");
        virBufferAdjustIndent(buf, 2);
1556

1557 1558 1559
        if (def->perms->mode != (mode_t) -1)
            virBufferAsprintf(buf, "<mode>0%o</mode>\n",
                              def->perms->mode);
1560 1561 1562 1563 1564 1565
        if (def->perms->uid != (uid_t) -1)
            virBufferAsprintf(buf, "<owner>%d</owner>\n",
                              (int) def->perms->uid);
        if (def->perms->gid != (gid_t) -1)
            virBufferAsprintf(buf, "<group>%d</group>\n",
                              (int) def->perms->gid);
1566

1567 1568
        virBufferEscapeString(buf, "<label>%s</label>\n",
                              def->perms->label);
1569

1570 1571 1572
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</permissions>\n");
    }
1573

1574
    if (def->timestamps) {
1575 1576
        virBufferAddLit(buf, "<timestamps>\n");
        virBufferAdjustIndent(buf, 2);
1577 1578 1579 1580
        virStorageVolTimestampFormat(buf, "atime", &def->timestamps->atime);
        virStorageVolTimestampFormat(buf, "mtime", &def->timestamps->mtime);
        virStorageVolTimestampFormat(buf, "ctime", &def->timestamps->ctime);
        virStorageVolTimestampFormat(buf, "btime", &def->timestamps->btime);
1581 1582
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</timestamps>\n");
1583 1584
    }

1585 1586
    if (def->encryption &&
        virStorageEncryptionFormat(buf, def->encryption) < 0)
1587
            return -1;
1588

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

1591
    if (def->features) {
1592
        size_t i;
1593 1594
        bool empty = virBitmapIsAllClear(def->features);

1595 1596 1597 1598 1599 1600
        if (empty) {
            virBufferAddLit(buf, "<features/>\n");
        } else {
            virBufferAddLit(buf, "<features>\n");
            virBufferAdjustIndent(buf, 2);
        }
1601 1602

        for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
1603
            if (virBitmapIsBitSet(def->features, i))
1604
                virBufferAsprintf(buf, "<%s/>\n",
1605
                                  virStorageFileFeatureTypeToString(i));
1606
        }
1607 1608 1609 1610
        if (!empty) {
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</features>\n");
        }
1611 1612
    }

1613 1614
    virBufferAdjustIndent(buf, -2);
    virBufferAsprintf(buf, "</%s>\n", type);
1615 1616
    return 0;
}
1617

1618

1619
char *
1620
virStorageVolDefFormat(virStoragePoolDefPtr pool,
1621 1622
                       virStorageVolDefPtr def)
{
1623
    virStorageVolOptionsPtr options;
1624
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1625

1626
    options = virStorageVolOptionsForPoolType(pool->type);
1627 1628 1629
    if (options == NULL)
        return NULL;

1630 1631
    virBufferAsprintf(&buf, "<volume type='%s'>\n",
                      virStorageVolTypeToString(def->type));
1632 1633 1634 1635 1636 1637
    virBufferAdjustIndent(&buf, 2);

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

    if (def->source.nextent) {
1640
        size_t i;
1641
        const char *thispath = NULL;
1642
        for (i = 0; i < def->source.nextent; i++) {
1643 1644 1645
            if (thispath == NULL ||
                STRNEQ(thispath, def->source.extents[i].path)) {
                if (thispath != NULL)
1646
                    virBufferAddLit(&buf, "</device>\n");
1647

1648
                virBufferEscapeString(&buf, "<device path='%s'>\n",
1649
                                      def->source.extents[i].path);
1650 1651
            }

1652 1653
            virBufferAdjustIndent(&buf, 2);
            virBufferAsprintf(&buf, "<extent start='%llu' end='%llu'/>\n",
1654 1655
                              def->source.extents[i].start,
                              def->source.extents[i].end);
1656
            virBufferAdjustIndent(&buf, -2);
1657 1658 1659
            thispath = def->source.extents[i].path;
        }
        if (thispath != NULL)
1660
            virBufferAddLit(&buf, "</device>\n");
1661 1662
    }

1663 1664 1665 1666
    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</source>\n");

    virBufferAsprintf(&buf, "<capacity unit='bytes'>%llu</capacity>\n",
1667
                      def->target.capacity);
1668
    virBufferAsprintf(&buf, "<allocation unit='bytes'>%llu</allocation>\n",
1669
                      def->target.allocation);
1670 1671 1672 1673 1674 1675
    /* NB: Display only - since virStorageVolInfo is limited to just
     * 'capacity' and 'allocation' on output. Since we don't read this
     * in, be sure it was filled in before printing */
    if (def->target.physical)
        virBufferAsprintf(&buf, "<physical unit='bytes'>%llu</physical>\n",
                          def->target.physical);
1676

1677
    if (virStorageVolTargetDefFormat(options, &buf,
1678 1679
                                     &def->target, "target") < 0)
        goto cleanup;
1680

1681
    if (virStorageSourceHasBacking(&def->target) &&
1682
        virStorageVolTargetDefFormat(options, &buf,
1683 1684
                                     def->target.backingStore,
                                     "backingStore") < 0)
1685
        goto cleanup;
1686

1687
    virBufferAdjustIndent(&buf, -2);
E
Eric Blake 已提交
1688
    virBufferAddLit(&buf, "</volume>\n");
1689

1690 1691
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
1692

1693
    return virBufferContentAndReset(&buf);
1694

1695
 cleanup:
1696
    virBufferFreeAndReset(&buf);
1697 1698 1699 1700
    return NULL;
}


1701 1702 1703 1704
static int
virStoragePoolSaveXML(const char *path,
                      virStoragePoolDefPtr def,
                      const char *xml)
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;

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

    return ret;
}
1716 1717 1718 1719 1720 1721 1722


int
virStoragePoolSaveState(const char *stateFile,
                        virStoragePoolDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1723
    VIR_AUTOFREE(char *) xml = NULL;
1724 1725 1726 1727 1728

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

    if (virStoragePoolDefFormatBuf(&buf, def) < 0)
1729
        return -1;
1730 1731 1732 1733 1734

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

    if (virBufferCheckError(&buf) < 0)
1735
        return -1;
1736 1737

    if (!(xml = virBufferContentAndReset(&buf)))
1738
        return -1;
1739 1740

    if (virStoragePoolSaveXML(stateFile, def, xml))
1741
        return -1;
1742

1743
    return 0;
1744
}
1745 1746


1747
int
1748
virStoragePoolSaveConfig(const char *configFile,
1749 1750
                         virStoragePoolDefPtr def)
{
1751
    VIR_AUTOFREE(char *) xml = NULL;
1752

1753 1754 1755 1756 1757 1758
    if (!(xml = virStoragePoolDefFormat(def))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to generate XML"));
        return -1;
    }

1759
    return virStoragePoolSaveXML(configFile, def, xml);
1760 1761
}

1762

1763
virStoragePoolSourcePtr
1764
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
1765 1766 1767
{
    virStoragePoolSourcePtr source;

1768
    if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0)
1769 1770 1771 1772 1773 1774 1775 1776
        return NULL;

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

    return source;
}

1777

1778 1779
char *
virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def)
1780
{
1781
    virStoragePoolOptionsPtr options;
1782
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1783
    const char *type;
1784
    size_t i;
1785

1786
    options = virStoragePoolOptionsForPoolType(def->type);
1787 1788 1789
    if (options == NULL)
        return NULL;

1790
    type = virStoragePoolTypeToString(def->type);
1791
    if (!type) {
1792 1793
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected pool type"));
1794 1795 1796 1797
        goto cleanup;
    }

    virBufferAddLit(&buf, "<sources>\n");
1798
    virBufferAdjustIndent(&buf, 2);
1799

1800
    for (i = 0; i < def->nsources; i++)
1801
        virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
1802

1803
    virBufferAdjustIndent(&buf, -2);
1804 1805
    virBufferAddLit(&buf, "</sources>\n");

1806 1807
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
1808 1809

    return virBufferContentAndReset(&buf);
1810

1811
 cleanup:
1812
    virBufferFreeAndReset(&buf);
1813
    return NULL;
1814
}