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

#include <config.h>

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

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

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

49 50
#define VIR_FROM_THIS VIR_FROM_STORAGE

51 52
#define DEFAULT_POOL_PERM_MODE 0755
#define DEFAULT_VOL_PERM_MODE  0600
53

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

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

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

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

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


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

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

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

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

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

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

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

/* Flags to indicate mandatory components in the pool source */
enum {
O
Osier Yang 已提交
122 123 124 125 126 127 128
    VIR_STORAGE_POOL_SOURCE_HOST            = (1 << 0),
    VIR_STORAGE_POOL_SOURCE_DEVICE          = (1 << 1),
    VIR_STORAGE_POOL_SOURCE_DIR             = (1 << 2),
    VIR_STORAGE_POOL_SOURCE_ADAPTER         = (1 << 3),
    VIR_STORAGE_POOL_SOURCE_NAME            = (1 << 4),
    VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN   = (1 << 5),
    VIR_STORAGE_POOL_SOURCE_NETWORK         = (1 << 6),
129 130 131 132 133
};

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

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

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

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


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

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

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

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


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

    if (!def)
        return;

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

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

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

329 330 331 332 333 334 335 336 337 338 339 340 341
static void
virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapter adapter)
{
    if (adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
        VIR_FREE(adapter.data.fchost.wwnn);
        VIR_FREE(adapter.data.fchost.wwpn);
        VIR_FREE(adapter.data.fchost.parent);
    } else if (adapter.type ==
               VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
        VIR_FREE(adapter.data.name);
    }
}

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

347
    if (!source)
348 349
        return;

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

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

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

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

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

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

    VIR_FREE(def->name);

393
    virStoragePoolSourceClear(&def->source);
394

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


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

407 408
    virStoragePoolObjClearVols(obj);

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

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

    virMutexDestroy(&obj->lock);

417
    VIR_FREE(obj);
418 419
}

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

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

436 437
    virStoragePoolObjUnlock(pool);

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

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

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

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


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

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

475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
    if (uuid != NULL) {
        if (auth->secret.usage != NULL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("either auth secret uuid or usage expected"));
            goto cleanup;
        }
        if (virUUIDParse(uuid, auth->secret.uuid) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid auth secret uuid"));
            goto cleanup;
        }
        auth->secret.uuidUsable = true;
    } else {
        auth->secret.uuidUsable = false;
    }

    ret = 0;
cleanup:
    VIR_FREE(uuid);
    return ret;
495 496
}

497 498
static int
virStoragePoolDefParseAuthCephx(xmlXPathContextPtr ctxt,
499 500
                                virStoragePoolAuthCephxPtr auth)
{
501
    char *uuid = NULL;
502 503
    int ret = -1;

504 505 506
    uuid = virXPathString("string(./auth/secret/@uuid)", ctxt);
    auth->secret.usage = virXPathString("string(./auth/secret/@usage)", ctxt);
    if (uuid == NULL && auth->secret.usage == NULL) {
507 508
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing auth secret uuid or usage attribute"));
509 510 511
        return -1;
    }

512 513 514 515
    if (uuid != NULL) {
        if (auth->secret.usage != NULL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("either auth secret uuid or usage expected"));
516
            goto cleanup;
517 518
        }
        if (virUUIDParse(uuid, auth->secret.uuid) < 0) {
519 520
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid auth secret uuid"));
521
            goto cleanup;
522 523 524 525
        }
        auth->secret.uuidUsable = true;
    } else {
        auth->secret.uuidUsable = false;
526 527
    }

528 529 530 531
    ret = 0;
cleanup:
    VIR_FREE(uuid);
    return ret;
532 533
}

534 535 536 537 538 539
static int
virStoragePoolDefParseAuth(xmlXPathContextPtr ctxt,
                           virStoragePoolSourcePtr source)
{
    int ret = -1;
    char *authType = NULL;
540
    char *username = NULL;
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556

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

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

557 558 559 560 561 562 563
    username = virXPathString("string(./auth/@username)", ctxt);
    if (username == NULL) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing auth username attribute"));
        goto cleanup;
    }

564
    if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
565 566
        source->auth.chap.username = username;
        username = NULL;
567 568 569
        if (virStoragePoolDefParseAuthChap(ctxt, &source->auth.chap) < 0)
            goto cleanup;
    }
570 571 572
    else if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
        source->auth.cephx.username = username;
        username = NULL;
573 574 575 576 577 578 579 580
        if (virStoragePoolDefParseAuthCephx(ctxt, &source->auth.cephx) < 0)
            goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(authType);
581
    VIR_FREE(username);
582 583 584
    return ret;
}

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

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

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

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

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

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

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

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

639
        for (i = 0; i < source->nhost; i++) {
640 641
            name = virXMLPropString(nodeset[i], "name");
            if (name == NULL) {
642 643
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing storage pool host name"));
644 645 646 647 648 649 650
                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) {
651 652 653
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("Invalid port number: %s"),
                                   port);
654 655 656 657 658
                    goto cleanup;
                }
            }
        }
    }
659

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

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

667 668 669 670 671 672
    if (nsource > 0) {
        if (VIR_ALLOC_N(source->devices, nsource) < 0) {
            VIR_FREE(nodeset);
            goto cleanup;
        }

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

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

    if ((adapter_type = virXPathString("string(./adapter/@type)", ctxt))) {
        if ((source->adapter.type =
             virStoragePoolSourceAdapterTypeTypeFromString(adapter_type)) <= 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Unknown pool adapter type '%s'"),
                           adapter_type);
            goto cleanup;
        }

        if (source->adapter.type ==
            VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
            source->adapter.data.fchost.parent =
                virXPathString("string(./adapter/@parent)", ctxt);
            source->adapter.data.fchost.wwnn =
                virXPathString("string(./adapter/@wwnn)", ctxt);
            source->adapter.data.fchost.wwpn =
                virXPathString("string(./adapter/@wwpn)", ctxt);
        } else if (source->adapter.type ==
                   VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
            source->adapter.data.name =
                virXPathString("string(./adapter/@name)", ctxt);
        }
    } else {
        char *wwnn = NULL;
        char *wwpn = NULL;
        char *parent = NULL;

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

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

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

738 739
    if (virStoragePoolDefParseAuth(ctxt, source) < 0)
        goto cleanup;
740

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

744 745 746 747
    ret = 0;
cleanup:
    ctxt->node = relnode;

748
    VIR_FREE(port);
749
    VIR_FREE(nodeset);
750
    VIR_FREE(adapter_type);
751 752
    return ret;
}
753

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

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

768
    if (VIR_ALLOC(def) < 0)
769 770
        goto cleanup;

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

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

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

    return ret;
}
790

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

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

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

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

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

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

        perms->uid = val;
844 845
    }

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

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

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

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

878
    if (VIR_ALLOC(ret) < 0)
879 880
        return NULL;

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

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

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

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

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

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

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

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

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

        if (ret->source.adapter.type ==
            VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
            if (!ret->source.adapter.data.fchost.wwnn ||
                !ret->source.adapter.data.fchost.wwpn) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("'wwnn' and 'wwpn' must be specified for adapter "
                                 "type 'fchost'"));
967
                goto error;
968 969 970 971
            }

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

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

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

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

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

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

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

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

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

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

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

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

1062 1063 1064
    return ret;
}

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

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

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

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

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

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

1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER)) {
        if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST ||
            src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST)
            virBufferAsprintf(buf, "    <adapter type='%s'",
                              virStoragePoolSourceAdapterTypeTypeToString(src->adapter.type));

        if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
            virBufferEscapeString(buf, " parent='%s'",
                                  src->adapter.data.fchost.parent);
            virBufferAsprintf(buf," wwnn='%s' wwpn='%s'/>\n",
                              src->adapter.data.fchost.wwnn,
                              src->adapter.data.fchost.wwpn);
        } else if (src->adapter.type ==
                 VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
            virBufferAsprintf(buf," name='%s'/>\n", src->adapter.data.name);
        }
    }
1135

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

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

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

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

1166
        virBufferAddLit(buf,"      <secret");
1167
        if (src->auth.cephx.secret.uuidUsable) {
1168 1169 1170 1171 1172 1173 1174
            virUUIDFormat(src->auth.cephx.secret.uuid, uuid);
            virBufferAsprintf(buf," uuid='%s'", uuid);
        }

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

1177
        virBufferAddLit(buf,"    </auth>\n");
1178 1179
    }

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

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

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

    return 0;
}

1193 1194

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

1202
    options = virStoragePoolOptionsForPoolType(def->type);
1203 1204 1205
    if (options == NULL)
        return NULL;

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

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

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

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

1228 1229 1230 1231
    /* RBD and Sheepdog devices are not local block devs nor files, so it
     * doesn't have a target */
    if (def->type != VIR_STORAGE_POOL_RBD &&
        def->type != VIR_STORAGE_POOL_SHEEPDOG) {
1232
        virBufferAddLit(&buf,"  <target>\n");
1233

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

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

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

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

1254
    if (virBufferError(&buf))
1255 1256
        goto no_memory;

1257
    return virBufferContentAndReset(&buf);
1258

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


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

    return 0;
}

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

1299
    options = virStorageVolOptionsForPoolType(pool->type);
1300 1301 1302
    if (options == NULL)
        return NULL;

1303
    if (VIR_ALLOC(ret) < 0)
1304 1305
        return NULL;

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

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

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

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

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

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

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

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

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

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

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

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

    if (options->featureFromString && virXPathNode("./target/features", ctxt)) {
        if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
            goto error;

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

        if (!(ret->target.features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST)))
1407
            goto error;
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421

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

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

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

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

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

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

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

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

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

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

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

    return ret;
}

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

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

1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
static void
virStorageVolTimestampFormat(virBufferPtr buf, const char *name,
                             struct timespec *ts)
{
    if (ts->tv_nsec < 0)
        return;
    virBufferAsprintf(buf, "      <%s>%llu", name,
                      (unsigned long long) ts->tv_sec);
    if (ts->tv_nsec)
       virBufferAsprintf(buf, ".%09ld", ts->tv_nsec);
    virBufferAsprintf(buf, "</%s>\n", name);
}

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

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

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

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


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

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

1548 1549 1550 1551 1552 1553 1554 1555 1556
    if (def->timestamps) {
        virBufferAddLit(buf, "    <timestamps>\n");
        virStorageVolTimestampFormat(buf, "atime", &def->timestamps->atime);
        virStorageVolTimestampFormat(buf, "mtime", &def->timestamps->mtime);
        virStorageVolTimestampFormat(buf, "ctime", &def->timestamps->ctime);
        virStorageVolTimestampFormat(buf, "btime", &def->timestamps->btime);
        virBufferAddLit(buf, "    </timestamps>\n");
    }

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

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

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

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

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

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

    return 0;
}
1590 1591

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

1598
    options = virStorageVolOptionsForPoolType(pool->type);
1599 1600 1601
    if (options == NULL)
        return NULL;

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

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

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

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

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

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

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

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

1647
    if (virBufferError(&buf))
1648 1649
        goto no_memory;

1650
    return virBufferContentAndReset(&buf);
1651

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


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

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

    return NULL;
}

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

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

    return NULL;
}

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

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

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

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

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

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

    return NULL;
}

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

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

    return NULL;
}

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

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

    return NULL;
}

virStoragePoolObjPtr
1759
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
1760 1761
                           virStoragePoolDefPtr def)
{
1762 1763
    virStoragePoolObjPtr pool;

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

1775
    if (VIR_ALLOC(pool) < 0)
1776 1777
        return NULL;

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

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

    return pool;
}

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

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

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

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

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

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

    return pool;
}


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

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

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

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

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

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

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

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

        VIR_FREE(path);
        VIR_FREE(autostartLink);
1887 1888 1889 1890 1891 1892 1893 1894
    }

    closedir(dir);

    return 0;
}

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

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

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

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

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

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

    return ret;
}

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

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

    return 0;
}
1956

1957
virStoragePoolSourcePtr
1958
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
1959 1960 1961
{
    virStoragePoolSourcePtr source;

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

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

    return source;
}

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

1979
    options = virStoragePoolOptionsForPoolType(def->type);
1980 1981 1982
    if (options == NULL)
        return NULL;

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

    virBufferAddLit(&buf, "<sources>\n");
1991 1992

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

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

    if (virBufferError(&buf))
        goto no_memory;
2000 2001

    return virBufferContentAndReset(&buf);
2002

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


2011 2012 2013 2014 2015 2016 2017 2018 2019 2020
/*
 * 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
 */
2021 2022 2023 2024
int
virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
                             virStoragePoolDefPtr def,
                             unsigned int check_active)
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035
{
    int ret = -1;
    virStoragePoolObjPtr pool = NULL;

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

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

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

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

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

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

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

        if (matchpool)
            break;
2148 2149 2150
    }

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

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

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

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

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

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

    /* filter by pool type */
    if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)) {
        if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DIR) &&
               (poolobj->def->type == VIR_STORAGE_POOL_DIR))     ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FS) &&
               (poolobj->def->type == VIR_STORAGE_POOL_FS))      ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) &&
               (poolobj->def->type == VIR_STORAGE_POOL_NETFS))   ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL) &&
               (poolobj->def->type == VIR_STORAGE_POOL_LOGICAL)) ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DISK) &&
               (poolobj->def->type == VIR_STORAGE_POOL_DISK))    ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI) &&
               (poolobj->def->type == VIR_STORAGE_POOL_ISCSI))   ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SCSI) &&
               (poolobj->def->type == VIR_STORAGE_POOL_SCSI))    ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_MPATH) &&
               (poolobj->def->type == VIR_STORAGE_POOL_MPATH))   ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) &&
               (poolobj->def->type == VIR_STORAGE_POOL_RBD))     ||
              (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) &&
               (poolobj->def->type == VIR_STORAGE_POOL_SHEEPDOG))))
            return false;
    }

    return true;
}
#undef MATCH

int
2230 2231 2232 2233 2234
virStoragePoolObjListExport(virConnectPtr conn,
                            virStoragePoolObjList poolobjs,
                            virStoragePoolPtr **pools,
                            virStoragePoolObjListFilter filter,
                            unsigned int flags)
2235 2236 2237 2238 2239
{
    virStoragePoolPtr *tmp_pools = NULL;
    virStoragePoolPtr pool = NULL;
    int npools = 0;
    int ret = -1;
2240
    size_t i;
2241

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

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

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

    ret = npools;

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

    VIR_FREE(tmp_pools);
    return ret;
}