You need to sign in or sign up before continuing.
storage_conf.c 52.1 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 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * 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 "virterror_internal.h"
37
#include "datatypes.h"
38
#include "storage_conf.h"
39
#include "storage_file.h"
40

41 42 43 44
#include "xml.h"
#include "uuid.h"
#include "buf.h"
#include "util.h"
45
#include "memory.h"
E
Eric Blake 已提交
46
#include "virfile.h"
47

48 49
#define VIR_FROM_THIS VIR_FROM_STORAGE

50

51 52 53 54
VIR_ENUM_IMPL(virStoragePool,
              VIR_STORAGE_POOL_LAST,
              "dir", "fs", "netfs",
              "logical", "disk", "iscsi",
D
Dave Allan 已提交
55
              "scsi", "mpath")
56 57 58 59 60

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

VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
              VIR_STORAGE_POOL_NETFS_LAST,
65
              "auto", "nfs", "glusterfs", "cifs")
66 67 68 69

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

VIR_ENUM_IMPL(virStoragePoolFormatLogical,
              VIR_STORAGE_POOL_LOGICAL_LAST,
74
              "unknown", "lvm2")
75 76 77 78 79 80 81


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

84 85
VIR_ENUM_IMPL(virStoragePartedFsType,
              VIR_STORAGE_PARTED_FS_TYPE_LAST,
86
              "ext2", "ext2", "fat16",
87 88 89
              "fat32", "linux-swap",
              "ext2", "ext2",
              "extended")
90 91 92 93 94 95 96 97 98 99

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 {
100
    int defaultFormat;
101 102 103 104 105 106
    virStorageVolFormatToString formatToString;
    virStorageVolFormatFromString formatFromString;
};

/* Flags to indicate mandatory components in the pool source */
enum {
D
David Allan 已提交
107 108 109 110 111 112
    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),
113 114 115 116 117 118 119
};



typedef struct _virStoragePoolOptions virStoragePoolOptions;
typedef virStoragePoolOptions *virStoragePoolOptionsPtr;
struct _virStoragePoolOptions {
E
Eric Blake 已提交
120
    unsigned int flags;
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    int defaultFormat;
    virStoragePoolFormatToString formatToString;
    virStoragePoolFormatFromString formatFromString;
};

typedef struct _virStoragePoolTypeInfo virStoragePoolTypeInfo;
typedef virStoragePoolTypeInfo *virStoragePoolTypeInfoPtr;

struct _virStoragePoolTypeInfo {
    int poolType;
    virStoragePoolOptions poolOptions;
    virStorageVolOptions volOptions;
};

static virStoragePoolTypeInfo poolTypeInfo[] = {
    { .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,
        },
    },
    { .poolType = VIR_STORAGE_POOL_DIR,
      .volOptions = {
147 148 149
            .defaultFormat = VIR_STORAGE_FILE_RAW,
            .formatFromString = virStorageFileFormatTypeFromString,
            .formatToString = virStorageFileFormatTypeToString,
150 151 152 153 154
        },
    },
    { .poolType = VIR_STORAGE_POOL_FS,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
155
            .defaultFormat = VIR_STORAGE_POOL_FS_AUTO,
156 157 158 159
            .formatFromString = virStoragePoolFormatFileSystemTypeFromString,
            .formatToString = virStoragePoolFormatFileSystemTypeToString,
        },
      .volOptions = {
160 161 162
            .defaultFormat = VIR_STORAGE_FILE_RAW,
            .formatFromString = virStorageFileFormatTypeFromString,
            .formatToString = virStorageFileFormatTypeToString,
163 164 165 166 167 168
        },
    },
    { .poolType = VIR_STORAGE_POOL_NETFS,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                      VIR_STORAGE_POOL_SOURCE_DIR),
169
            .defaultFormat = VIR_STORAGE_POOL_NETFS_AUTO,
170 171 172 173
            .formatFromString = virStoragePoolFormatFileSystemNetTypeFromString,
            .formatToString = virStoragePoolFormatFileSystemNetTypeToString,
        },
      .volOptions = {
174 175 176
            .defaultFormat = VIR_STORAGE_FILE_RAW,
            .formatFromString = virStorageFileFormatTypeFromString,
            .formatToString = virStorageFileFormatTypeToString,
177 178 179 180 181
        },
    },
    { .poolType = VIR_STORAGE_POOL_ISCSI,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
D
David Allan 已提交
182 183
                      VIR_STORAGE_POOL_SOURCE_DEVICE |
                      VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
184 185 186 187 188
        },
      .volOptions = {
            .formatToString = virStoragePoolFormatDiskTypeToString,
        }
    },
189 190 191 192 193 194 195 196
    { .poolType = VIR_STORAGE_POOL_SCSI,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER),
        },
      .volOptions = {
            .formatToString = virStoragePoolFormatDiskTypeToString,
        }
    },
D
Dave Allan 已提交
197 198 199 200 201
    { .poolType = VIR_STORAGE_POOL_MPATH,
      .volOptions = {
            .formatToString = virStoragePoolFormatDiskTypeToString,
        }
    },
202 203 204 205 206 207 208 209
    { .poolType = VIR_STORAGE_POOL_DISK,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
            .defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN,
            .formatFromString = virStoragePoolFormatDiskTypeFromString,
            .formatToString = virStoragePoolFormatDiskTypeToString,
        },
      .volOptions = {
210
            .defaultFormat = VIR_STORAGE_VOL_DISK_NONE,
211 212 213 214 215 216 217 218 219 220 221 222 223 224
            .formatFromString = virStorageVolFormatDiskTypeFromString,
            .formatToString = virStorageVolFormatDiskTypeToString,
        },
    }
};


static virStoragePoolTypeInfoPtr
virStoragePoolTypeInfoLookup(int type) {
    unsigned int i;
    for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo) ; i++)
        if (poolTypeInfo[i].poolType == type)
            return &poolTypeInfo[i];

225
    virStorageReportError(VIR_ERR_INTERNAL_ERROR,
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
                          _("missing backend for pool type %d"), type);
    return NULL;
}

static virStoragePoolOptionsPtr
virStoragePoolOptionsForPoolType(int type) {
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->poolOptions;
}

static virStorageVolOptionsPtr
virStorageVolOptionsForPoolType(int type) {
    virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
    if (backend == NULL)
        return NULL;
    return &backend->volOptions;
}


247 248 249
void
virStorageVolDefFree(virStorageVolDefPtr def) {
    int i;
250 251 252 253

    if (!def)
        return;

254 255
    VIR_FREE(def->name);
    VIR_FREE(def->key);
256 257

    for (i = 0 ; i < def->source.nextent ; i++) {
258
        VIR_FREE(def->source.extents[i].path);
259
    }
260
    VIR_FREE(def->source.extents);
261

262 263
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
264
    virStorageEncryptionFree(def->target.encryption);
265 266
    VIR_FREE(def->backingStore.path);
    VIR_FREE(def->backingStore.perms.label);
267
    virStorageEncryptionFree(def->backingStore.encryption);
268
    VIR_FREE(def);
269 270 271
}

void
272 273
virStoragePoolSourceClear(virStoragePoolSourcePtr source)
{
274 275
    int i;

276
    if (!source)
277 278
        return;

279 280 281 282 283
    for (i = 0 ; i < source->nhost ; i++) {
        VIR_FREE(source->hosts[i].name);
    }
    VIR_FREE(source->hosts);

284 285 286
    for (i = 0 ; i < source->ndevice ; i++) {
        VIR_FREE(source->devices[i].freeExtents);
        VIR_FREE(source->devices[i].path);
287
    }
288 289 290
    VIR_FREE(source->devices);
    VIR_FREE(source->dir);
    VIR_FREE(source->name);
291
    VIR_FREE(source->adapter);
D
David Allan 已提交
292
    VIR_FREE(source->initiator.iqn);
293 294
    VIR_FREE(source->vendor);
    VIR_FREE(source->product);
295

296 297 298
    if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
        VIR_FREE(source->auth.chap.login);
        VIR_FREE(source->auth.chap.passwd);
299
    }
300 301
}

302 303 304 305 306 307 308
void
virStoragePoolSourceFree(virStoragePoolSourcePtr source)
{
    virStoragePoolSourceClear(source);
    VIR_FREE(source);
}

309 310 311 312 313 314 315
void
virStoragePoolDefFree(virStoragePoolDefPtr def) {
    if (!def)
        return;

    VIR_FREE(def->name);

316
    virStoragePoolSourceClear(&def->source);
317

318 319 320
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
    VIR_FREE(def);
321 322 323 324 325
}


void
virStoragePoolObjFree(virStoragePoolObjPtr obj) {
326 327 328
    if (!obj)
        return;

329 330
    virStoragePoolObjClearVols(obj);

331 332
    virStoragePoolDefFree(obj->def);
    virStoragePoolDefFree(obj->newDef);
333

334 335
    VIR_FREE(obj->configFile);
    VIR_FREE(obj->autostartLink);
336 337 338

    virMutexDestroy(&obj->lock);

339
    VIR_FREE(obj);
340 341
}

342 343 344 345 346 347 348 349 350
void virStoragePoolObjListFree(virStoragePoolObjListPtr pools)
{
    unsigned int i;
    for (i = 0 ; i < pools->count ; i++)
        virStoragePoolObjFree(pools->objs[i]);
    VIR_FREE(pools->objs);
    pools->count = 0;
}

351
void
352
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
353 354
                        virStoragePoolObjPtr pool)
{
355
    unsigned int i;
356

357 358
    virStoragePoolObjUnlock(pool);

359
    for (i = 0 ; i < pools->count ; i++) {
360
        virStoragePoolObjLock(pools->objs[i]);
361
        if (pools->objs[i] == pool) {
362
            virStoragePoolObjUnlock(pools->objs[i]);
363
            virStoragePoolObjFree(pools->objs[i]);
364

365 366 367
            if (i < (pools->count - 1))
                memmove(pools->objs + i, pools->objs + i + 1,
                        sizeof(*(pools->objs)) * (pools->count - (i + 1)));
368

369 370 371 372
            if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            pools->count--;
373

374 375
            break;
        }
376
        virStoragePoolObjUnlock(pools->objs[i]);
377
    }
378 379 380 381
}


static int
382
virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
383
                               virStoragePoolAuthChapPtr auth) {
384
    auth->login = virXPathString("string(./auth/@login)", ctxt);
385
    if (auth->login == NULL) {
386
        virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
387
                              "%s", _("missing auth host attribute"));
388 389 390
        return -1;
    }

391
    auth->passwd = virXPathString("string(./auth/@passwd)", ctxt);
392
    if (auth->passwd == NULL) {
393
        virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
394
                              "%s", _("missing auth passwd attribute"));
395 396 397 398 399 400
        return -1;
    }

    return 0;
}

401
static int
402
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
403 404 405 406 407 408 409 410
                             virStoragePoolSourcePtr source,
                             int pool_type,
                             xmlNodePtr node) {
    int ret = -1;
    xmlNodePtr relnode, *nodeset = NULL;
    char *authType = NULL;
    int nsource, i;
    virStoragePoolOptionsPtr options;
411
    char *name = NULL;
412
    char *port = NULL;
413 414 415 416 417 418 419 420

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

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

421
    source->name = virXPathString("string(./name)", ctxt);
422 423

    if (options->formatFromString) {
424
        char *format = virXPathString("string(./format/@type)", ctxt);
425 426 427 428 429 430
        if (format == NULL)
            source->format = options->defaultFormat;
        else
            source->format = options->formatFromString(format);

        if (source->format < 0) {
431
            virStorageReportError(VIR_ERR_XML_ERROR,
432 433 434 435 436 437 438
                                  _("unknown pool format type %s"), format);
            VIR_FREE(format);
            goto cleanup;
        }
        VIR_FREE(format);
    }

439 440 441 442 443
    source->nhost = virXPathNodeSet("./host", ctxt, &nodeset);

    if (source->nhost) {
        if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) {
            virReportOOMError();
444 445 446
            goto cleanup;
        }

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
        for (i = 0 ; i < source->nhost ; i++) {
            name = virXMLPropString(nodeset[i], "name");
            if (name == NULL) {
                virStorageReportError(VIR_ERR_XML_ERROR,
                        "%s", _("missing storage pool host name"));
                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) {
                    virStorageReportError(VIR_ERR_XML_ERROR,
                                          _("Invalid port number: %s"),
                                          port);
                    goto cleanup;
                }
            }
        }
    }
467

468
    source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
469

470
    nsource = virXPathNodeSet("./device", ctxt, &nodeset);
471 472 473
    if (nsource < 0)
        goto cleanup;

474 475 476
    if (nsource > 0) {
        if (VIR_ALLOC_N(source->devices, nsource) < 0) {
            VIR_FREE(nodeset);
477
            virReportOOMError();
478 479 480 481
            goto cleanup;
        }

        for (i = 0 ; i < nsource ; i++) {
482
            char *path = virXMLPropString(nodeset[i], "path");
483 484
            if (path == NULL) {
                VIR_FREE(nodeset);
485
                virStorageReportError(VIR_ERR_XML_ERROR,
486 487 488
                        "%s", _("missing storage pool source device path"));
                goto cleanup;
            }
489
            source->devices[i].path = path;
490 491 492 493
        }
        source->ndevice = nsource;
    }

494 495
    source->dir = virXPathString("string(./dir/@path)", ctxt);
    source->adapter = virXPathString("string(./adapter/@name)", ctxt);
496

497
    authType = virXPathString("string(./auth/@type)", ctxt);
498 499 500 501 502 503
    if (authType == NULL) {
        source->authType = VIR_STORAGE_POOL_AUTH_NONE;
    } else {
        if (STREQ(authType, "chap")) {
            source->authType = VIR_STORAGE_POOL_AUTH_CHAP;
        } else {
504
            virStorageReportError(VIR_ERR_XML_ERROR,
505 506 507 508 509 510 511
                                  _("unknown auth type '%s'"),
                                  (const char *)authType);
            goto cleanup;
        }
    }

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

516 517 518
    source->vendor = virXPathString("string(./vendor/@name)", ctxt);
    source->product = virXPathString("string(./product/@name)", ctxt);

519 520 521 522
    ret = 0;
cleanup:
    ctxt->node = relnode;

523
    VIR_FREE(port);
524 525 526 527
    VIR_FREE(authType);
    VIR_FREE(nodeset);
    return ret;
}
528

529
virStoragePoolSourcePtr
530
virStoragePoolDefParseSourceString(const char *srcSpec,
531 532 533 534 535 536 537
                                   int pool_type)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr node = NULL;
    xmlXPathContextPtr xpath_ctxt = NULL;
    virStoragePoolSourcePtr def = NULL, ret = NULL;

538
    if (!(doc = virXMLParseStringCtxt(srcSpec, _("(storage_source_specification)"), &xpath_ctxt))) {
539 540 541 542
        goto cleanup;
    }

    if (VIR_ALLOC(def) < 0) {
543
        virReportOOMError();
544 545 546
        goto cleanup;
    }

547
    node = virXPathNode("/source", xpath_ctxt);
548
    if (!node) {
549
        virStorageReportError(VIR_ERR_XML_ERROR,
550 551 552 553
                              "%s", _("root element was not source"));
        goto cleanup;
    }

554
    if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
555 556 557 558 559 560
                                     node) < 0)
        goto cleanup;

    ret = def;
    def = NULL;
cleanup:
561
    virStoragePoolSourceFree(def);
562 563 564 565 566
    xmlFreeDoc(doc);
    xmlXPathFreeContext(xpath_ctxt);

    return ret;
}
567
static int
568
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
569 570 571
                        virStoragePermsPtr perms,
                        const char *permxpath,
                        int defaultmode) {
572 573
    char *mode;
    long v;
574 575 576
    int ret = -1;
    xmlNodePtr relnode;
    xmlNodePtr node;
577

578
    node = virXPathNode(permxpath, ctxt);
579 580 581
    if (node == NULL) {
        /* Set default values if there is not <permissions> element */
        perms->mode = defaultmode;
582 583
        perms->uid = -1;
        perms->gid = -1;
584 585 586 587 588 589 590
        perms->label = NULL;
        return 0;
    }

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

591
    mode = virXPathString("string(./mode)", ctxt);
592
    if (!mode) {
593
        perms->mode = defaultmode;
594
    } else {
595 596 597
        int tmp;

        if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
598
            VIR_FREE(mode);
599
            virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
600
                                  "%s", _("malformed octal mode"));
601
            goto error;
602
        }
603
        perms->mode = tmp;
604
        VIR_FREE(mode);
605 606
    }

607
    if (virXPathNode("./owner", ctxt) == NULL) {
608
        perms->uid = -1;
609
    } else {
610
        if (virXPathLong("number(./owner)", ctxt, &v) < 0) {
611
            virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
612
                                  "%s", _("malformed owner element"));
613
            goto error;
614 615 616 617
        }
        perms->uid = (int)v;
    }

618
    if (virXPathNode("./group", ctxt) == NULL) {
619
        perms->gid = -1;
620
    } else {
621
        if (virXPathLong("number(./group)", ctxt, &v) < 0) {
622
            virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
623
                                  "%s", _("malformed group element"));
624
            goto error;
625 626 627 628 629
        }
        perms->gid = (int)v;
    }

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

632 633 634 635
    ret = 0;
error:
    ctxt->node = relnode;
    return ret;
636 637 638
}

static virStoragePoolDefPtr
639
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
640
    virStoragePoolOptionsPtr options;
641
    virStoragePoolDefPtr ret;
642
    xmlNodePtr source_node;
643
    char *type = NULL;
644
    char *uuid = NULL;
645
    char *tmppath;
646

647
    if (VIR_ALLOC(ret) < 0) {
648
        virReportOOMError();
649
        return NULL;
650
    }
651

652
    type = virXPathString("string(./@type)", ctxt);
653
    if ((ret->type = virStoragePoolTypeFromString((const char *)type)) < 0) {
654
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
655
                              _("unknown storage pool type %s"), (const char*)type);
656
        goto cleanup;
657 658
    }

659 660 661
    xmlFree(type);
    type = NULL;

662
    if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) {
663 664 665
        goto cleanup;
    }

666
    source_node = virXPathNode("./source", ctxt);
667
    if (source_node) {
668
        if (virStoragePoolDefParseSource(ctxt, &ret->source, ret->type,
669 670 671 672
                                         source_node) < 0)
            goto cleanup;
    }

673
    ret->name = virXPathString("string(./name)", ctxt);
674
    if (ret->name == NULL &&
675
        options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
676
        ret->name = ret->source.name;
677
    if (ret->name == NULL) {
678
        virStorageReportError(VIR_ERR_XML_ERROR,
679
                              "%s", _("missing pool source name element"));
680 681 682
        goto cleanup;
    }

683
    uuid = virXPathString("string(./uuid)", ctxt);
684 685
    if (uuid == NULL) {
        if (virUUIDGenerate(ret->uuid) < 0) {
686
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
687
                                  "%s", _("unable to generate uuid"));
688 689 690 691
            goto cleanup;
        }
    } else {
        if (virUUIDParse(uuid, ret->uuid) < 0) {
692
            virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
693
                                  "%s", _("malformed uuid element"));
694 695
            goto cleanup;
        }
696
        VIR_FREE(uuid);
697 698
    }

699
    if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
700
        if (!ret->source.nhost) {
701
            virStorageReportError(VIR_ERR_XML_ERROR,
702 703
                                  "%s",
                                  _("missing storage pool source host name"));
704 705 706 707
            goto cleanup;
        }
    }

708
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
709
        if (!ret->source.dir) {
710
            virStorageReportError(VIR_ERR_XML_ERROR,
711
                                  "%s", _("missing storage pool source path"));
712 713 714
            goto cleanup;
        }
    }
715
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
716 717 718
        if (ret->source.name == NULL) {
            /* source name defaults to pool name */
            ret->source.name = strdup(ret->name);
719
            if (ret->source.name == NULL) {
720
                virReportOOMError();
721 722
                goto cleanup;
            }
723 724
        }
    }
725

726
    if (options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) {
727
        if (!ret->source.adapter) {
728
            virStorageReportError(VIR_ERR_XML_ERROR,
729
                                  "%s", _("missing storage pool source adapter name"));
730 731 732
            goto cleanup;
        }
    }
733

734 735 736 737 738 739 740 741 742
    /* If DEVICE is the only source type, then its required */
    if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
        if (!ret->source.ndevice) {
            virStorageReportError(VIR_ERR_XML_ERROR,
                                  "%s", _("missing storage pool source device name"));
            goto cleanup;
        }
    }

743
    if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
744
        virStorageReportError(VIR_ERR_XML_ERROR,
745
                              "%s", _("missing storage pool target path"));
746 747
        goto cleanup;
    }
748 749 750 751 752
    ret->target.path = virFileSanitizePath(tmppath);
    VIR_FREE(tmppath);
    if (!ret->target.path)
        goto cleanup;

753

754
    if (virStorageDefParsePerms(ctxt, &ret->target.perms,
755
                                "./target/permissions", 0700) < 0)
756 757 758 759 760
        goto cleanup;

    return ret;

 cleanup:
761
    VIR_FREE(uuid);
762
    xmlFree(type);
763 764 765 766 767
    virStoragePoolDefFree(ret);
    return NULL;
}

virStoragePoolDefPtr
768
virStoragePoolDefParseNode(xmlDocPtr xml,
769 770 771 772 773
                           xmlNodePtr root) {
    xmlXPathContextPtr ctxt = NULL;
    virStoragePoolDefPtr def = NULL;

    if (STRNEQ((const char *)root->name, "pool")) {
774 775
        virStorageReportError(VIR_ERR_XML_ERROR,
                              "%s", _("unknown root element for storage pool"));
776 777 778 779 780
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
781
        virReportOOMError();
782 783 784 785
        goto cleanup;
    }

    ctxt->node = root;
786
    def = virStoragePoolDefParseXML(ctxt);
787 788 789 790 791 792
cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStoragePoolDefPtr
793
virStoragePoolDefParse(const char *xmlStr,
794 795
                       const char *filename) {
    virStoragePoolDefPtr ret = NULL;
J
Jiri Denemark 已提交
796
    xmlDocPtr xml;
797

798
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_pool_definition)")))) {
J
Jiri Denemark 已提交
799 800
        ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
801 802
    }

803 804 805
    return ret;
}

806
virStoragePoolDefPtr
807
virStoragePoolDefParseString(const char *xmlStr)
808
{
809
    return virStoragePoolDefParse(xmlStr, NULL);
810 811 812
}

virStoragePoolDefPtr
813
virStoragePoolDefParseFile(const char *filename)
814
{
815
    return virStoragePoolDefParse(NULL, filename);
816 817
}

818
static int
819
virStoragePoolSourceFormat(virBufferPtr buf,
820
                           virStoragePoolOptionsPtr options,
821 822 823 824 825
                           virStoragePoolSourcePtr src)
{
    int i, j;

    virBufferAddLit(buf,"  <source>\n");
826 827 828 829 830 831 832
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
        for (i = 0; i < src->nhost; i++) {
            virBufferAsprintf(buf, " <host name='%s'", src->hosts[i].name);
            if (src->hosts[i].port)
                virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
            virBufferAddLit(buf, "/>\n");
        }
833
    }
834

835
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
836 837 838
        src->ndevice) {
        for (i = 0 ; i < src->ndevice ; i++) {
            if (src->devices[i].nfreeExtent) {
839
                virBufferAsprintf(buf,"    <device path='%s'>\n",
840 841
                                  src->devices[i].path);
                for (j = 0 ; j < src->devices[i].nfreeExtent ; j++) {
842
                    virBufferAsprintf(buf, "    <freeExtent start='%llu' end='%llu'/>\n",
843 844 845 846 847 848
                                      src->devices[i].freeExtents[j].start,
                                      src->devices[i].freeExtents[j].end);
                }
                virBufferAddLit(buf,"    </device>\n");
            }
            else
849
                virBufferAsprintf(buf, "    <device path='%s'/>\n",
850 851 852
                                  src->devices[i].path);
        }
    }
853
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) &&
854
        src->dir)
855
        virBufferAsprintf(buf,"    <dir path='%s'/>\n", src->dir);
856
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
857
        src->adapter)
858
        virBufferAsprintf(buf,"    <adapter name='%s'/>\n", src->adapter);
859
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) &&
860
        src->name)
861
        virBufferAsprintf(buf,"    <name>%s</name>\n", src->name);
862

D
David Allan 已提交
863 864 865 866 867 868 869
    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");
    }

870 871 872
    if (options->formatToString) {
        const char *format = (options->formatToString)(src->format);
        if (!format) {
873
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
874 875 876 877
                                  _("unknown pool format number %d"),
                                  src->format);
            return -1;
        }
878
        virBufferAsprintf(buf,"    <format type='%s'/>\n", format);
879 880 881 882
    }


    if (src->authType == VIR_STORAGE_POOL_AUTH_CHAP)
883
        virBufferAsprintf(buf,"    <auth type='chap' login='%s' passwd='%s'/>\n",
884 885
                          src->auth.chap.login,
                          src->auth.chap.passwd);
886 887 888 889 890 891 892 893 894

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

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

895 896 897 898 899
    virBufferAddLit(buf,"  </source>\n");

    return 0;
}

900 901

char *
902
virStoragePoolDefFormat(virStoragePoolDefPtr def) {
903
    virStoragePoolOptionsPtr options;
904
    virBuffer buf = VIR_BUFFER_INITIALIZER;
905 906 907
    const char *type;
    char uuid[VIR_UUID_STRING_BUFLEN];

908
    options = virStoragePoolOptionsForPoolType(def->type);
909 910 911
    if (options == NULL)
        return NULL;

912
    type = virStoragePoolTypeToString(def->type);
913
    if (!type) {
914
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
915
                              "%s", _("unexpected pool type"));
916 917
        goto cleanup;
    }
918 919
    virBufferAsprintf(&buf, "<pool type='%s'>\n", type);
    virBufferAsprintf(&buf,"  <name>%s</name>\n", def->name);
920 921

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

E
Eric Blake 已提交
924
    virBufferAsprintf(&buf,"  <capacity unit='bytes'>%llu</capacity>\n",
925
                      def->capacity);
E
Eric Blake 已提交
926
    virBufferAsprintf(&buf,"  <allocation unit='bytes'>%llu</allocation>\n",
927
                      def->allocation);
E
Eric Blake 已提交
928
    virBufferAsprintf(&buf,"  <available unit='bytes'>%llu</available>\n",
929
                      def->available);
930

931
    if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0)
932
        goto cleanup;
933

934
    virBufferAddLit(&buf,"  <target>\n");
935

936
    if (def->target.path)
937
        virBufferAsprintf(&buf,"    <path>%s</path>\n", def->target.path);
938

939
    virBufferAddLit(&buf,"    <permissions>\n");
940
    virBufferAsprintf(&buf,"      <mode>0%o</mode>\n",
941
                      def->target.perms.mode);
E
Eric Blake 已提交
942 943 944 945
    virBufferAsprintf(&buf,"      <owner>%u</owner>\n",
                      (unsigned int) def->target.perms.uid);
    virBufferAsprintf(&buf,"      <group>%u</group>\n",
                      (unsigned int) def->target.perms.gid);
946

947
    if (def->target.perms.label)
948
        virBufferAsprintf(&buf,"      <label>%s</label>\n",
949
                          def->target.perms.label);
950

951 952 953
    virBufferAddLit(&buf,"    </permissions>\n");
    virBufferAddLit(&buf,"  </target>\n");
    virBufferAddLit(&buf,"</pool>\n");
954

955
    if (virBufferError(&buf))
956 957
        goto no_memory;

958
    return virBufferContentAndReset(&buf);
959 960

 no_memory:
961
    virReportOOMError();
962
 cleanup:
963
    virBufferFreeAndReset(&buf);
964 965 966 967 968
    return NULL;
}


static int
969
virStorageSize(const char *unit,
970
               const char *val,
971 972 973
               unsigned long long *ret)
{
    if (virStrToLong_ull(val, NULL, 10, ret) < 0) {
974
        virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
975
                              "%s", _("malformed capacity element"));
976 977
        return -1;
    }
978 979 980 981
    /* 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;
982 983 984 985 986

    return 0;
}

static virStorageVolDefPtr
987
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
988
                         xmlXPathContextPtr ctxt) {
989
    virStorageVolDefPtr ret;
990
    virStorageVolOptionsPtr options;
991 992 993
    char *allocation = NULL;
    char *capacity = NULL;
    char *unit = NULL;
994
    xmlNodePtr node;
995

996
    options = virStorageVolOptionsForPoolType(pool->type);
997 998 999
    if (options == NULL)
        return NULL;

1000
    if (VIR_ALLOC(ret) < 0) {
1001
        virReportOOMError();
1002
        return NULL;
1003
    }
1004

1005
    ret->name = virXPathString("string(./name)", ctxt);
1006
    if (ret->name == NULL) {
1007
        virStorageReportError(VIR_ERR_XML_ERROR,
1008
                              "%s", _("missing volume name element"));
1009 1010 1011
        goto cleanup;
    }

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

1015 1016
    capacity = virXPathString("string(./capacity)", ctxt);
    unit = virXPathString("string(./capacity/@unit)", ctxt);
1017
    if (capacity == NULL) {
1018
        virStorageReportError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
1019
                              "%s", _("missing capacity element"));
1020 1021
        goto cleanup;
    }
1022
    if (virStorageSize(unit, capacity, &ret->capacity) < 0)
1023
        goto cleanup;
1024 1025
    VIR_FREE(capacity);
    VIR_FREE(unit);
1026

1027
    allocation = virXPathString("string(./allocation)", ctxt);
1028
    if (allocation) {
1029
        unit = virXPathString("string(./allocation/@unit)", ctxt);
1030
        if (virStorageSize(unit, allocation, &ret->allocation) < 0)
1031
            goto cleanup;
1032 1033
        VIR_FREE(allocation);
        VIR_FREE(unit);
1034 1035 1036 1037
    } else {
        ret->allocation = ret->capacity;
    }

1038
    ret->target.path = virXPathString("string(./target/path)", ctxt);
1039
    if (options->formatFromString) {
1040
        char *format = virXPathString("string(./target/format/@type)", ctxt);
1041 1042 1043 1044 1045 1046
        if (format == NULL)
            ret->target.format = options->defaultFormat;
        else
            ret->target.format = (options->formatFromString)(format);

        if (ret->target.format < 0) {
1047
            virStorageReportError(VIR_ERR_XML_ERROR,
1048
                                  _("unknown volume format type %s"), format);
1049
            VIR_FREE(format);
1050 1051
            goto cleanup;
        }
1052
        VIR_FREE(format);
1053 1054
    }

1055
    if (virStorageDefParsePerms(ctxt, &ret->target.perms,
1056
                                "./target/permissions", 0600) < 0)
1057 1058
        goto cleanup;

1059
    node = virXPathNode("./target/encryption", ctxt);
1060
    if (node != NULL) {
1061
        ret->target.encryption = virStorageEncryptionParseNode(ctxt->doc,
1062 1063 1064 1065 1066
                                                               node);
        if (ret->target.encryption == NULL)
            goto cleanup;
    }

1067 1068


1069
    ret->backingStore.path = virXPathString("string(./backingStore/path)", ctxt);
1070
    if (options->formatFromString) {
1071
        char *format = virXPathString("string(./backingStore/format/@type)", ctxt);
1072 1073 1074 1075 1076 1077
        if (format == NULL)
            ret->backingStore.format = options->defaultFormat;
        else
            ret->backingStore.format = (options->formatFromString)(format);

        if (ret->backingStore.format < 0) {
1078
            virStorageReportError(VIR_ERR_XML_ERROR,
1079 1080 1081 1082 1083 1084 1085
                                  _("unknown volume format type %s"), format);
            VIR_FREE(format);
            goto cleanup;
        }
        VIR_FREE(format);
    }

1086
    if (virStorageDefParsePerms(ctxt, &ret->backingStore.perms,
1087
                                "./backingStore/permissions", 0600) < 0)
1088 1089
        goto cleanup;

1090 1091 1092
    return ret;

 cleanup:
1093 1094 1095
    VIR_FREE(allocation);
    VIR_FREE(capacity);
    VIR_FREE(unit);
1096 1097 1098 1099 1100
    virStorageVolDefFree(ret);
    return NULL;
}

virStorageVolDefPtr
1101
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
1102 1103 1104 1105 1106 1107
                          xmlDocPtr xml,
                          xmlNodePtr root) {
    xmlXPathContextPtr ctxt = NULL;
    virStorageVolDefPtr def = NULL;

    if (STRNEQ((const char *)root->name, "volume")) {
1108
        virStorageReportError(VIR_ERR_XML_ERROR,
1109 1110 1111 1112 1113 1114
                          "%s", _("unknown root element for storage vol"));
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1115
        virReportOOMError();
1116 1117 1118 1119
        goto cleanup;
    }

    ctxt->node = root;
1120
    def = virStorageVolDefParseXML(pool, ctxt);
1121 1122 1123 1124 1125 1126
cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

static virStorageVolDefPtr
1127
virStorageVolDefParse(virStoragePoolDefPtr pool,
1128 1129 1130
                      const char *xmlStr,
                      const char *filename) {
    virStorageVolDefPtr ret = NULL;
J
Jiri Denemark 已提交
1131
    xmlDocPtr xml;
1132

1133
    if ((xml = virXMLParse(filename, xmlStr, _("(storage_volume_definition)")))) {
J
Jiri Denemark 已提交
1134 1135
        ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1136 1137 1138 1139 1140
    }

    return ret;
}

1141
virStorageVolDefPtr
1142
virStorageVolDefParseString(virStoragePoolDefPtr pool,
1143 1144
                            const char *xmlStr)
{
1145
    return virStorageVolDefParse(pool, xmlStr, NULL);
1146 1147 1148
}

virStorageVolDefPtr
1149
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
1150 1151
                          const char *filename)
{
1152
    return virStorageVolDefParse(pool, NULL, filename);
1153
}
1154

1155
static int
1156
virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
1157 1158 1159
                             virBufferPtr buf,
                             virStorageVolTargetPtr def,
                             const char *type) {
1160
    virBufferAsprintf(buf, "  <%s>\n", type);
1161 1162

    if (def->path)
1163
        virBufferAsprintf(buf,"    <path>%s</path>\n", def->path);
1164 1165 1166 1167

    if (options->formatToString) {
        const char *format = (options->formatToString)(def->format);
        if (!format) {
1168
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1169 1170 1171 1172
                                  _("unknown volume format number %d"),
                                  def->format);
            return -1;
        }
1173
        virBufferAsprintf(buf,"    <format type='%s'/>\n", format);
1174 1175 1176
    }

    virBufferAddLit(buf,"    <permissions>\n");
1177
    virBufferAsprintf(buf,"      <mode>0%o</mode>\n",
1178
                      def->perms.mode);
E
Eric Blake 已提交
1179 1180 1181 1182
    virBufferAsprintf(buf,"      <owner>%u</owner>\n",
                      (unsigned int) def->perms.uid);
    virBufferAsprintf(buf,"      <group>%u</group>\n",
                      (unsigned int) def->perms.gid);
1183 1184 1185


    if (def->perms.label)
1186
        virBufferAsprintf(buf,"      <label>%s</label>\n",
1187 1188 1189 1190
                          def->perms.label);

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

1191 1192 1193 1194 1195 1196
    if (def->encryption) {
        virBufferAdjustIndent(buf, 4);
        if (virStorageEncryptionFormat(buf, def->encryption) < 0)
            return -1;
        virBufferAdjustIndent(buf, -4);
    }
1197

1198
    virBufferAsprintf(buf, "  </%s>\n", type);
1199 1200 1201

    return 0;
}
1202 1203

char *
1204
virStorageVolDefFormat(virStoragePoolDefPtr pool,
1205
                       virStorageVolDefPtr def) {
1206
    virStorageVolOptionsPtr options;
1207
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1208

1209
    options = virStorageVolOptionsForPoolType(pool->type);
1210 1211 1212
    if (options == NULL)
        return NULL;

1213
    virBufferAddLit(&buf, "<volume>\n");
1214 1215
    virBufferAsprintf(&buf,"  <name>%s</name>\n", def->name);
    virBufferAsprintf(&buf,"  <key>%s</key>\n", def->key);
1216
    virBufferAddLit(&buf, "  <source>\n");
1217 1218 1219 1220 1221 1222 1223 1224

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

1227
                virBufferAsprintf(&buf, "    <device path='%s'>\n",
1228
                                  def->source.extents[i].path);
1229 1230
            }

1231
            virBufferAsprintf(&buf,
1232 1233 1234
                              "      <extent start='%llu' end='%llu'/>\n",
                              def->source.extents[i].start,
                              def->source.extents[i].end);
1235 1236 1237
            thispath = def->source.extents[i].path;
        }
        if (thispath != NULL)
1238
            virBufferAddLit(&buf, "    </device>\n");
1239
    }
1240
    virBufferAddLit(&buf, "  </source>\n");
1241

E
Eric Blake 已提交
1242
    virBufferAsprintf(&buf,"  <capacity unit='bytes'>%llu</capacity>\n",
1243
                      def->capacity);
E
Eric Blake 已提交
1244
    virBufferAsprintf(&buf,"  <allocation unit='bytes'>%llu</allocation>\n",
1245
                      def->allocation);
1246

1247
    if (virStorageVolTargetDefFormat(options, &buf,
1248 1249
                                     &def->target, "target") < 0)
        goto cleanup;
1250

1251
    if (def->backingStore.path &&
1252
        virStorageVolTargetDefFormat(options, &buf,
1253 1254
                                     &def->backingStore, "backingStore") < 0)
        goto cleanup;
1255 1256

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

1258
    if (virBufferError(&buf))
1259 1260
        goto no_memory;

1261
    return virBufferContentAndReset(&buf);
1262 1263

 no_memory:
1264
    virReportOOMError();
1265
 cleanup:
1266
    virBufferFreeAndReset(&buf);
1267 1268 1269 1270 1271
    return NULL;
}


virStoragePoolObjPtr
1272
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
1273
                            const unsigned char *uuid) {
1274
    unsigned int i;
1275

1276 1277
    for (i = 0 ; i < pools->count ; i++) {
        virStoragePoolObjLock(pools->objs[i]);
1278 1279
        if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
            return pools->objs[i];
1280 1281
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1282 1283 1284 1285 1286

    return NULL;
}

virStoragePoolObjPtr
1287
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
1288
                            const char *name) {
1289
    unsigned int i;
1290

1291 1292
    for (i = 0 ; i < pools->count ; i++) {
        virStoragePoolObjLock(pools->objs[i]);
1293 1294
        if (STREQ(pools->objs[i]->def->name, name))
            return pools->objs[i];
1295 1296
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1297 1298 1299 1300

    return NULL;
}

1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
virStoragePoolObjPtr
virStoragePoolSourceFindDuplicateDevices(virStoragePoolObjPtr pool,
                                         virStoragePoolDefPtr def) {
    unsigned int i, j;

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

    return NULL;
}

1316 1317 1318
void
virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
{
1319 1320 1321 1322 1323 1324
    unsigned int i;
    for (i = 0 ; i < pool->volumes.count ; i++)
        virStorageVolDefFree(pool->volumes.objs[i]);

    VIR_FREE(pool->volumes.objs);
    pool->volumes.count = 0;
1325 1326 1327 1328 1329
}

virStorageVolDefPtr
virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
                          const char *key) {
1330
    unsigned int i;
1331

1332 1333 1334
    for (i = 0 ; i < pool->volumes.count ; i++)
        if (STREQ(pool->volumes.objs[i]->key, key))
            return pool->volumes.objs[i];
1335 1336 1337 1338 1339 1340 1341

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
                           const char *path) {
1342
    unsigned int i;
1343

1344 1345 1346
    for (i = 0 ; i < pool->volumes.count ; i++)
        if (STREQ(pool->volumes.objs[i]->target.path, path))
            return pool->volumes.objs[i];
1347 1348 1349 1350 1351 1352 1353

    return NULL;
}

virStorageVolDefPtr
virStorageVolDefFindByName(virStoragePoolObjPtr pool,
                           const char *name) {
1354
    unsigned int i;
1355

1356 1357 1358
    for (i = 0 ; i < pool->volumes.count ; i++)
        if (STREQ(pool->volumes.objs[i]->name, name))
            return pool->volumes.objs[i];
1359 1360 1361 1362 1363

    return NULL;
}

virStoragePoolObjPtr
1364
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
1365 1366 1367
                           virStoragePoolDefPtr def) {
    virStoragePoolObjPtr pool;

1368
    if ((pool = virStoragePoolObjFindByName(pools, def->name))) {
1369 1370 1371 1372
        if (!virStoragePoolObjIsActive(pool)) {
            virStoragePoolDefFree(pool->def);
            pool->def = def;
        } else {
1373
            virStoragePoolDefFree(pool->newDef);
1374 1375 1376 1377 1378
            pool->newDef = def;
        }
        return pool;
    }

1379
    if (VIR_ALLOC(pool) < 0) {
1380
        virReportOOMError();
1381 1382 1383
        return NULL;
    }

1384
    if (virMutexInit(&pool->lock) < 0) {
1385
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1386 1387 1388 1389
                              "%s", _("cannot initialize mutex"));
        VIR_FREE(pool);
        return NULL;
    }
1390
    virStoragePoolObjLock(pool);
1391 1392 1393
    pool->active = 0;
    pool->def = def;

1394 1395
    if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
        pool->def = NULL;
1396
        virStoragePoolObjUnlock(pool);
1397
        virStoragePoolObjFree(pool);
1398
        virReportOOMError();
1399 1400 1401
        return NULL;
    }
    pools->objs[pools->count++] = pool;
1402 1403 1404 1405 1406

    return pool;
}

static virStoragePoolObjPtr
1407
virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
1408 1409 1410 1411 1412 1413
                      const char *file,
                      const char *path,
                      const char *autostartLink) {
    virStoragePoolDefPtr def;
    virStoragePoolObjPtr pool;

1414
    if (!(def = virStoragePoolDefParseFile(path))) {
1415 1416 1417 1418
        return NULL;
    }

    if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
1419
        virStorageReportError(VIR_ERR_XML_ERROR,
1420
                              _("Storage pool config filename '%s' does not match pool name '%s'"),
1421
                              path, def->name);
1422 1423 1424 1425
        virStoragePoolDefFree(def);
        return NULL;
    }

1426
    if (!(pool = virStoragePoolObjAssignDef(pools, def))) {
1427 1428 1429 1430
        virStoragePoolDefFree(def);
        return NULL;
    }

1431
    VIR_FREE(pool->configFile);  /* for driver reload */
1432 1433
    pool->configFile = strdup(path);
    if (pool->configFile == NULL) {
1434
        virReportOOMError();
1435 1436 1437
        virStoragePoolDefFree(def);
        return NULL;
    }
1438
    VIR_FREE(pool->autostartLink); /* for driver reload */
1439 1440
    pool->autostartLink = strdup(autostartLink);
    if (pool->autostartLink == NULL) {
1441
        virReportOOMError();
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
        virStoragePoolDefFree(def);
        return NULL;
    }

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

    return pool;
}


int
1454
virStoragePoolLoadAllConfigs(virStoragePoolObjListPtr pools,
1455 1456
                             const char *configDir,
                             const char *autostartDir) {
1457 1458 1459
    DIR *dir;
    struct dirent *entry;

1460
    if (!(dir = opendir(configDir))) {
1461 1462
        if (errno == ENOENT)
            return 0;
1463
        virReportSystemError(errno, _("Failed to open dir '%s'"),
1464
                             configDir);
1465 1466 1467 1468
        return -1;
    }

    while ((entry = readdir(dir))) {
1469 1470
        char *path;
        char *autostartLink;
1471
        virStoragePoolObjPtr pool;
1472 1473 1474 1475 1476 1477 1478

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

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

1479
        if (!(path = virFileBuildPath(configDir, entry->d_name, NULL)))
1480 1481
            continue;

1482 1483 1484
        if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
                                               NULL))) {
            VIR_FREE(path);
1485 1486 1487
            continue;
        }

1488
        pool = virStoragePoolObjLoad(pools, entry->d_name, path,
1489
                                     autostartLink);
1490 1491
        if (pool)
            virStoragePoolObjUnlock(pool);
1492 1493 1494

        VIR_FREE(path);
        VIR_FREE(autostartLink);
1495 1496 1497 1498 1499 1500 1501 1502
    }

    closedir(dir);

    return 0;
}

int
1503
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
1504
                         virStoragePoolObjPtr pool,
1505 1506
                         virStoragePoolDefPtr def)
{
1507
    char *xml;
1508
    int ret = -1;
1509 1510

    if (!pool->configFile) {
1511 1512
        if (virFileMakePath(driver->configDir) < 0) {
            virReportSystemError(errno,
C
Cole Robinson 已提交
1513 1514
                                 _("cannot create config directory %s"),
                                 driver->configDir);
1515 1516 1517
            return -1;
        }

1518 1519
        if (!(pool->configFile = virFileBuildPath(driver->configDir,
                                                  def->name, ".xml"))) {
1520 1521 1522
            return -1;
        }

1523 1524
        if (!(pool->autostartLink = virFileBuildPath(driver->autostartDir,
                                                     def->name, ".xml"))) {
1525
            VIR_FREE(pool->configFile);
1526 1527 1528 1529
            return -1;
        }
    }

1530 1531
    if (!(xml = virStoragePoolDefFormat(def))) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1532
                              "%s", _("failed to generate XML"));
1533 1534 1535
        return -1;
    }

1536
    ret = virXMLSaveFile(pool->configFile, def->name, "pool-edit", xml);
1537
    VIR_FREE(xml);
1538 1539 1540 1541 1542

    return ret;
}

int
1543
virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool) {
1544
    if (!pool->configFile) {
1545
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1546 1547 1548 1549 1550
                              _("no config file for %s"), pool->def->name);
        return -1;
    }

    if (unlink(pool->configFile) < 0) {
1551
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1552 1553 1554 1555 1556 1557 1558
                              _("cannot remove config for %s"),
                              pool->def->name);
        return -1;
    }

    return 0;
}
1559

1560
virStoragePoolSourcePtr
1561
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
1562 1563 1564 1565
{
    virStoragePoolSourcePtr source;

    if (VIR_REALLOC_N(list->sources, list->nsources+1) < 0) {
1566
        virReportOOMError();
1567 1568 1569 1570 1571 1572 1573 1574 1575
        return NULL;
    }

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

    return source;
}

1576
char *virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def)
1577
{
1578
    virStoragePoolOptionsPtr options;
1579
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1580 1581
    const char *type;
    int i;
1582

1583
    options = virStoragePoolOptionsForPoolType(def->type);
1584 1585 1586
    if (options == NULL)
        return NULL;

1587
    type = virStoragePoolTypeToString(def->type);
1588
    if (!type) {
1589
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1590 1591 1592 1593 1594
                              "%s", _("unexpected pool type"));
        goto cleanup;
    }

    virBufferAddLit(&buf, "<sources>\n");
1595 1596

    for (i = 0; i < def->nsources; i++) {
1597
        virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
1598 1599
    }

1600 1601 1602 1603
    virBufferAddLit(&buf, "</sources>\n");

    if (virBufferError(&buf))
        goto no_memory;
1604 1605

    return virBufferContentAndReset(&buf);
1606 1607

 no_memory:
1608
    virReportOOMError();
1609
 cleanup:
1610
    virBufferFreeAndReset(&buf);
1611
    return NULL;
1612
}
D
Daniel P. Berrange 已提交
1613 1614


1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
/*
 * 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
 */
int virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
                                 virStoragePoolDefPtr def,
                                 unsigned int check_active)
{
    int ret = -1;
    int dupPool = 0;
    virStoragePoolObjPtr pool = NULL;

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

        if (check_active) {
            /* UUID & name match, but if Pool is already active, refuse it */
            if (virStoragePoolObjIsActive(pool)) {
                virStorageReportError(VIR_ERR_OPERATION_INVALID,
                                      _("pool is already active as '%s'"),
                                      pool->def->name);
                goto cleanup;
            }
        }

        dupPool = 1;
    } else {
        /* UUID does not match, but if a name matches, refuse it */
        pool = virStoragePoolObjFindByName(pools, def->name);
        if (pool) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(pool->def->uuid, uuidstr);
            virStorageReportError(VIR_ERR_OPERATION_FAILED,
                                  _("pool '%s' already exists with uuid %s"),
                                  def->name, uuidstr);
            goto cleanup;
        }
    }

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

1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690
int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
                                      virStoragePoolDefPtr def)
{
    int i;
    int ret = 1;
    virStoragePoolObjPtr pool = NULL;
    virStoragePoolObjPtr matchpool = NULL;

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

1691 1692 1693 1694
        /* Don't mach against ourself if re-defining existing pool ! */
        if (STREQ(pool->def->name, def->name))
            continue;

1695 1696 1697 1698 1699 1700 1701 1702 1703
        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)) \
1704 1705
                && (pool->def->source.nhost == 1 && def->source.nhost == 1) \
                && (STREQ(pool->def->source.hosts[0].name, def->source.hosts[0].name)))
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715
                matchpool = pool;
            break;
        case VIR_STORAGE_POOL_SCSI:
            if (STREQ(pool->def->source.adapter, def->source.adapter))
                matchpool = pool;
            break;
        case VIR_STORAGE_POOL_ISCSI:
        {
            matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
            if (matchpool) {
1716 1717 1718 1719 1720 1721 1722 1723
                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;
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
                    }
                }
                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);
1739 1740 1741

        if (matchpool)
            break;
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
    }

    if (matchpool) {
        virStorageReportError(VIR_ERR_OPERATION_FAILED,
                              _("Storage source conflict with pool: '%s'"),
                              matchpool->def->name);
        ret = -1;
    }
    return ret;
}
1752

1753 1754
void virStoragePoolObjLock(virStoragePoolObjPtr obj)
{
1755
    virMutexLock(&obj->lock);
1756 1757 1758 1759
}

void virStoragePoolObjUnlock(virStoragePoolObjPtr obj)
{
1760
    virMutexUnlock(&obj->lock);
1761
}