storage_conf.c 47.5 KB
Newer Older
1 2 3 4 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
/*
 * storage_conf.c: config handling for storage driver
 *
 * Copyright (C) 2006-2008 Red Hat, Inc.
 * 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

40 41 42 43
#include "xml.h"
#include "uuid.h"
#include "buf.h"
#include "util.h"
44
#include "memory.h"
45

46 47 48 49 50
/* Work around broken limits.h on debian etch */
#if defined __GNUC__ && defined _GCC_LIMITS_H_ && ! defined ULLONG_MAX
# define ULLONG_MAX   ULONG_LONG_MAX
#endif

51 52
#define virStorageLog(msg...) fprintf(stderr, msg)

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

VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
              VIR_STORAGE_POOL_FS_LAST,
              "auto", "ext2", "ext3",
              "ext4", "ufs", "iso9660", "udf",
63
              "gfs", "gfs2", "vfat", "hfs+", "xfs")
64 65 66

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

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

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


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

VIR_ENUM_IMPL(virStorageVolFormatFileSystem,
              VIR_STORAGE_VOL_FILE_LAST,
              "raw", "dir", "bochs",
              "cloop", "cow", "dmg", "iso",
90
              "qcow", "qcow2", "vmdk", "vpc")
91 92 93 94 95 96 97 98 99 100 101


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 {
102
    int defaultFormat;
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 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 147
    virStorageVolFormatToString formatToString;
    virStorageVolFormatFromString formatFromString;
};

/* Flags to indicate mandatory components in the pool source */
enum {
    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),
};



typedef struct _virStoragePoolOptions virStoragePoolOptions;
typedef virStoragePoolOptions *virStoragePoolOptionsPtr;
struct _virStoragePoolOptions {
    int flags;
    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 = {
148
            .defaultFormat = VIR_STORAGE_VOL_FILE_RAW,
149 150 151 152 153 154 155 156 157 158 159
            .formatFromString = virStorageVolFormatFileSystemTypeFromString,
            .formatToString = virStorageVolFormatFileSystemTypeToString,
        },
    },
    { .poolType = VIR_STORAGE_POOL_FS,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
            .formatFromString = virStoragePoolFormatFileSystemTypeFromString,
            .formatToString = virStoragePoolFormatFileSystemTypeToString,
        },
      .volOptions = {
160
            .defaultFormat = VIR_STORAGE_VOL_FILE_RAW,
161 162 163 164 165 166 167 168 169 170 171 172 173
            .formatFromString = virStorageVolFormatFileSystemTypeFromString,
            .formatToString = virStorageVolFormatFileSystemTypeToString,
        },
    },
    { .poolType = VIR_STORAGE_POOL_NETFS,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                      VIR_STORAGE_POOL_SOURCE_DIR),
            .defaultFormat = VIR_STORAGE_POOL_FS_AUTO,
            .formatFromString = virStoragePoolFormatFileSystemNetTypeFromString,
            .formatToString = virStoragePoolFormatFileSystemNetTypeToString,
        },
      .volOptions = {
174
            .defaultFormat = VIR_STORAGE_VOL_FILE_RAW,
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
            .formatFromString = virStorageVolFormatFileSystemTypeFromString,
            .formatToString = virStorageVolFormatFileSystemTypeToString,
        },
    },
    { .poolType = VIR_STORAGE_POOL_ISCSI,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
                      VIR_STORAGE_POOL_SOURCE_DEVICE),
        },
      .volOptions = {
            .formatToString = virStoragePoolFormatDiskTypeToString,
        }
    },
    { .poolType = VIR_STORAGE_POOL_DISK,
      .poolOptions = {
            .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
            .defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN,
            .formatFromString = virStoragePoolFormatDiskTypeFromString,
            .formatToString = virStoragePoolFormatDiskTypeToString,
        },
      .volOptions = {
196
            .defaultFormat = VIR_STORAGE_VOL_DISK_NONE,
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
            .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];

    virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
                          _("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;
}


233 234 235
void
virStorageVolDefFree(virStorageVolDefPtr def) {
    int i;
236 237 238 239

    if (!def)
        return;

240 241
    VIR_FREE(def->name);
    VIR_FREE(def->key);
242 243

    for (i = 0 ; i < def->source.nextent ; i++) {
244
        VIR_FREE(def->source.extents[i].path);
245
    }
246
    VIR_FREE(def->source.extents);
247

248 249 250
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
    VIR_FREE(def);
251 252 253
}

void
254
virStoragePoolSourceFree(virStoragePoolSourcePtr source) {
255 256
    int i;

257
    if (!source)
258 259
        return;

260 261 262 263
    VIR_FREE(source->host.name);
    for (i = 0 ; i < source->ndevice ; i++) {
        VIR_FREE(source->devices[i].freeExtents);
        VIR_FREE(source->devices[i].path);
264
    }
265 266 267
    VIR_FREE(source->devices);
    VIR_FREE(source->dir);
    VIR_FREE(source->name);
268

269 270 271
    if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
        VIR_FREE(source->auth.chap.login);
        VIR_FREE(source->auth.chap.passwd);
272
    }
273 274 275 276 277 278 279 280 281 282
}

void
virStoragePoolDefFree(virStoragePoolDefPtr def) {
    if (!def)
        return;

    VIR_FREE(def->name);

    virStoragePoolSourceFree(&def->source);
283

284 285 286
    VIR_FREE(def->target.path);
    VIR_FREE(def->target.perms.label);
    VIR_FREE(def);
287 288 289 290 291
}


void
virStoragePoolObjFree(virStoragePoolObjPtr obj) {
292 293 294 295 296
    if (!obj)
        return;

    virStoragePoolDefFree(obj->def);
    virStoragePoolDefFree(obj->newDef);
297

298 299
    VIR_FREE(obj->configFile);
    VIR_FREE(obj->autostartLink);
300 301 302

    virMutexDestroy(&obj->lock);

303
    VIR_FREE(obj);
304 305
}

306 307 308 309 310 311 312 313 314
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;
}

315
void
316
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
317 318
                        virStoragePoolObjPtr pool)
{
319
    unsigned int i;
320

321 322
    virStoragePoolObjUnlock(pool);

323
    for (i = 0 ; i < pools->count ; i++) {
324
        virStoragePoolObjLock(pools->objs[i]);
325
        if (pools->objs[i] == pool) {
326
            virStoragePoolObjUnlock(pools->objs[i]);
327
            virStoragePoolObjFree(pools->objs[i]);
328

329 330 331
            if (i < (pools->count - 1))
                memmove(pools->objs + i, pools->objs + i + 1,
                        sizeof(*(pools->objs)) * (pools->count - (i + 1)));
332

333 334 335 336
            if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            pools->count--;
337

338 339
            break;
        }
340
        virStoragePoolObjUnlock(pools->objs[i]);
341
    }
342 343 344 345 346 347 348
}


static int
virStoragePoolDefParseAuthChap(virConnectPtr conn,
                               xmlXPathContextPtr ctxt,
                               virStoragePoolAuthChapPtr auth) {
349
    auth->login = virXPathString(conn, "string(/pool/source/auth/@login)", ctxt);
350 351
    if (auth->login == NULL) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
352
                              "%s", _("missing auth host attribute"));
353 354 355
        return -1;
    }

356
    auth->passwd = virXPathString(conn, "string(/pool/source/auth/@passwd)", ctxt);
357 358
    if (auth->passwd == NULL) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
359
                              "%s", _("missing auth passwd attribute"));
360 361 362 363 364 365 366 367 368 369 370 371 372 373
        return -1;
    }

    return 0;
}


static int
virStoragePoolDefParsePerms(virConnectPtr conn,
                            xmlXPathContextPtr ctxt,
                            virStoragePermsPtr perms) {
    char *mode;
    long v;

374
    mode = virXPathString(conn, "string(/pool/permissions/mode)", ctxt);
375 376 377 378 379 380 381
    if (!mode) {
        perms->mode = 0700;
    } else {
        char *end;
        perms->mode = strtol(mode, &end, 8);
        if (*end || perms->mode < 0 || perms->mode > 0777) {
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
382
                                  "%s", _("malformed octal mode"));
383 384 385 386
            return -1;
        }
    }

387
    if (virXPathNode(conn, "/pool/permissions/owner", ctxt) == NULL) {
388 389
        perms->uid = getuid();
    } else {
390
        if (virXPathLong(conn, "number(/pool/permissions/owner)", ctxt, &v) < 0) {
391
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
392
                                  "%s", _("malformed owner element"));
393 394 395 396 397
            return -1;
        }
        perms->uid = (int)v;
    }

398
    if (virXPathNode(conn, "/pool/permissions/group", ctxt) == NULL) {
D
Daniel P. Berrange 已提交
399
        perms->gid = getgid();
400
    } else {
401
        if (virXPathLong(conn, "number(/pool/permissions/group)", ctxt, &v) < 0) {
402
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
403
                                  "%s", _("malformed group element"));
404 405 406 407 408 409
            return -1;
        }
        perms->gid = (int)v;
    }

    /* NB, we're ignoring missing labels here - they'll simply inherit */
410
    perms->label = virXPathString(conn, "string(/pool/permissions/label)", ctxt);
411 412 413 414 415 416 417 418 419

    return 0;
}


static virStoragePoolDefPtr
virStoragePoolDefParseDoc(virConnectPtr conn,
                          xmlXPathContextPtr ctxt,
                          xmlNodePtr root) {
420
    virStoragePoolOptionsPtr options;
421 422 423 424 425
    virStoragePoolDefPtr ret;
    xmlChar *type = NULL;
    char *uuid = NULL;
    char *authType = NULL;

426 427 428
    if (VIR_ALLOC(ret) < 0) {
        virStorageReportError(conn, VIR_ERR_NO_MEMORY,
                              "%s", _("cannot allocate storage pool"));
429
        return NULL;
430
    }
431 432 433

    if (STRNEQ((const char *)root->name, "pool")) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
434
                          "%s", _("unknown root element for storage pool"));
435 436 437 438
        goto cleanup;
    }

    type = xmlGetProp(root, BAD_CAST "type");
439 440 441
    if ((ret->type = virStoragePoolTypeFromString((const char *)type)) < 0) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("unknown storage pool type %s"), (const char*)type);
442
        goto cleanup;
443 444
    }

445 446 447
    xmlFree(type);
    type = NULL;

448
    if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) {
449 450 451
        goto cleanup;
    }

452 453
    ret->name = virXPathString(conn, "string(/pool/name)", ctxt);
    if (ret->name == NULL &&
454
        options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
455 456
        ret->name = virXPathString(conn, "string(/pool/source/name)", ctxt);
    if (ret->name == NULL) {
457
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
458
                              "%s", _("missing pool source name element"));
459 460 461
        goto cleanup;
    }

462
    uuid = virXPathString(conn, "string(/pool/uuid)", ctxt);
463 464 465
    if (uuid == NULL) {
        if (virUUIDGenerate(ret->uuid) < 0) {
            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
466
                                  "%s", _("unable to generate uuid"));
467 468 469 470 471
            goto cleanup;
        }
    } else {
        if (virUUIDParse(uuid, ret->uuid) < 0) {
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
472
                                  "%s", _("malformed uuid element"));
473 474
            goto cleanup;
        }
475
        VIR_FREE(uuid);
476 477 478
    }

    if (options->formatFromString) {
479
        char *format = virXPathString(conn, "string(/pool/source/format/@type)", ctxt);
480 481 482 483 484 485
        if (format == NULL)
            ret->source.format = options->defaultFormat;
        else
            ret->source.format = options->formatFromString(format);

        if (ret->source.format < 0) {
486 487
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
                                  _("unknown pool format type %s"), format);
488
            VIR_FREE(format);
489 490
            goto cleanup;
        }
491
        VIR_FREE(format);
492 493
    }

494
    if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
495
        if ((ret->source.host.name = virXPathString(conn, "string(/pool/source/host/@name)", ctxt)) == NULL) {
496
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
497
                             "%s", _("missing storage pool source host name"));
498 499 500
            goto cleanup;
        }
    }
501
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) {
502 503 504
        xmlNodePtr *nodeset = NULL;
        int nsource, i;

505
        if ((nsource = virXPathNodeSet(conn, "/pool/source/device", ctxt, &nodeset)) < 0) {
506
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
507
                        "%s", _("cannot extract storage pool source devices"));
508 509
            goto cleanup;
        }
510 511
        if (VIR_ALLOC_N(ret->source.devices, nsource) < 0) {
            VIR_FREE(nodeset);
J
Jim Meyering 已提交
512
            virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("device"));
513 514 515 516 517
            goto cleanup;
        }
        for (i = 0 ; i < nsource ; i++) {
            xmlChar *path = xmlGetProp(nodeset[i], BAD_CAST "path");
            if (path == NULL) {
518
                VIR_FREE(nodeset);
519
                virStorageReportError(conn, VIR_ERR_XML_ERROR,
520
                        "%s", _("missing storage pool source device path"));
521 522 523 524
                goto cleanup;
            }
            ret->source.devices[i].path = (char *)path;
        }
525
        VIR_FREE(nodeset);
526 527
        ret->source.ndevice = nsource;
    }
528
    if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
529
        if ((ret->source.dir = virXPathString(conn, "string(/pool/source/dir/@path)", ctxt)) == NULL) {
530
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
531
                                "%s", _("missing storage pool source path"));
532 533 534
            goto cleanup;
        }
    }
535
    if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
536 537 538 539 540
        ret->source.name = virXPathString(conn, "string(/pool/source/name)",
                                          ctxt);
        if (ret->source.name == NULL) {
            /* source name defaults to pool name */
            ret->source.name = strdup(ret->name);
541 542 543 544 545
            if (ret->source.name == NULL) {
                virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s",
                                      _("pool name"));
                goto cleanup;
            }
546 547
        }
    }
548 549


550
    authType = virXPathString(conn, "string(/pool/source/auth/@type)", ctxt);
551 552 553 554 555 556 557 558 559
    if (authType == NULL) {
        ret->source.authType = VIR_STORAGE_POOL_AUTH_NONE;
    } else {
        if (STREQ(authType, "chap")) {
            ret->source.authType = VIR_STORAGE_POOL_AUTH_CHAP;
        } else {
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
                                  _("unknown auth type '%s'"),
                                  (const char *)authType);
560
            VIR_FREE(authType);
561 562
            goto cleanup;
        }
563
        VIR_FREE(authType);
564 565 566 567 568 569 570
    }

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

571
    if ((ret->target.path = virXPathString(conn, "string(/pool/target/path)", ctxt)) == NULL) {
572
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
573
                              "%s", _("missing storage pool target path"));
574 575 576 577 578 579 580 581 582
        goto cleanup;
    }

    if (virStoragePoolDefParsePerms(conn, ctxt, &ret->target.perms) < 0)
        goto cleanup;

    return ret;

 cleanup:
583
    VIR_FREE(uuid);
584
    xmlFree(type);
585 586 587 588
    virStoragePoolDefFree(ret);
    return NULL;
}

589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
/* Called from SAX on parsing errors in the XML. */
static void
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

    if (ctxt) {
        virConnectPtr conn = ctxt->_private;

        if (conn &&
            conn->err.code == VIR_ERR_NONE &&
            ctxt->lastError.level == XML_ERR_FATAL &&
            ctxt->lastError.message != NULL) {
            virStorageReportError (conn, VIR_ERR_XML_DETAIL,
                                   _("at line %d: %s"),
                                   ctxt->lastError.line,
                                   ctxt->lastError.message);
        }
    }
}

610 611 612 613 614
virStoragePoolDefPtr
virStoragePoolDefParse(virConnectPtr conn,
                       const char *xmlStr,
                       const char *filename) {
    virStoragePoolDefPtr ret = NULL;
615
    xmlParserCtxtPtr pctxt;
616 617 618 619
    xmlDocPtr xml = NULL;
    xmlNodePtr node = NULL;
    xmlXPathContextPtr ctxt = NULL;

620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
    /* Set up a parser context so we can catch the details of XML errors. */
    pctxt = xmlNewParserCtxt ();
    if (!pctxt || !pctxt->sax)
        goto cleanup;
    pctxt->sax->error = catchXMLError;
    pctxt->_private = conn;

    if (conn) virResetError (&conn->err);
    xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr,
                          filename ? filename : "storage.xml", NULL,
                          XML_PARSE_NOENT | XML_PARSE_NONET |
                          XML_PARSE_NOWARNING);
    if (!xml) {
        if (conn && conn->err.code == VIR_ERR_NONE)
              virStorageReportError(conn, VIR_ERR_XML_ERROR,
D
Daniel P. Berrange 已提交
635
                                    "%s",_("failed to parse xml document"));
636 637 638 639 640 641
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        virStorageReportError(conn, VIR_ERR_NO_MEMORY,
J
Jim Meyering 已提交
642
                              "%s", _("xmlXPathContext"));
643 644 645 646 647 648
        goto cleanup;
    }

    node = xmlDocGetRootElement(xml);
    if (node == NULL) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
649
                              "%s", _("missing root element"));
650 651 652 653 654
        goto cleanup;
    }

    ret = virStoragePoolDefParseDoc(conn, ctxt, node);

655
    xmlFreeParserCtxt (pctxt);
656 657 658 659 660 661
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);

    return ret;

 cleanup:
662
    xmlFreeParserCtxt (pctxt);
663 664 665 666 667
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);
    return NULL;
}

668 669 670
static int
virStoragePoolSourceFormat(virConnectPtr conn,
                           virBufferPtr buf,
671
                           virStoragePoolOptionsPtr options,
672 673 674 675 676
                           virStoragePoolSourcePtr src)
{
    int i, j;

    virBufferAddLit(buf,"  <source>\n");
677
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) &&
678 679 680
        src->host.name)
        virBufferVSprintf(buf,"    <host name='%s'/>\n", src->host.name);

681
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
        src->ndevice) {
        for (i = 0 ; i < src->ndevice ; i++) {
            if (src->devices[i].nfreeExtent) {
                virBufferVSprintf(buf,"    <device path='%s'>\n",
                                  src->devices[i].path);
                for (j = 0 ; j < src->devices[i].nfreeExtent ; j++) {
                    virBufferVSprintf(buf, "    <freeExtent start='%llu' end='%llu'/>\n",
                                      src->devices[i].freeExtents[j].start,
                                      src->devices[i].freeExtents[j].end);
                }
                virBufferAddLit(buf,"    </device>\n");
            }
            else
                virBufferVSprintf(buf, "    <device path='%s'/>\n",
                                  src->devices[i].path);
        }
    }
699
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) &&
700 701
        src->dir)
        virBufferVSprintf(buf,"    <dir path='%s'/>\n", src->dir);
702
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
703 704
        src->adapter)
        virBufferVSprintf(buf,"    <adapter name='%s'/>\n", src->adapter);
705
    if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) &&
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
        src->name)
        virBufferVSprintf(buf,"    <name>%s</name>\n", src->name);

    if (options->formatToString) {
        const char *format = (options->formatToString)(src->format);
        if (!format) {
            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  _("unknown pool format number %d"),
                                  src->format);
            return -1;
        }
        virBufferVSprintf(buf,"    <format type='%s'/>\n", format);
    }


    if (src->authType == VIR_STORAGE_POOL_AUTH_CHAP)
        virBufferVSprintf(buf,"    <auth type='chap' login='%s' passwd='%s'>\n",
                          src->auth.chap.login,
                          src->auth.chap.passwd);
    virBufferAddLit(buf,"  </source>\n");

    return 0;
}

730 731 732 733

char *
virStoragePoolDefFormat(virConnectPtr conn,
                        virStoragePoolDefPtr def) {
734
    virStoragePoolOptionsPtr options;
735
    virBuffer buf = VIR_BUFFER_INITIALIZER;
736 737 738
    const char *type;
    char uuid[VIR_UUID_STRING_BUFLEN];

739
    options = virStoragePoolOptionsForPoolType(def->type);
740 741 742
    if (options == NULL)
        return NULL;

743
    type = virStoragePoolTypeToString(def->type);
744 745
    if (!type) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
746
                              "%s", _("unexpected pool type"));
747 748
        goto cleanup;
    }
749 750
    virBufferVSprintf(&buf, "<pool type='%s'>\n", type);
    virBufferVSprintf(&buf,"  <name>%s</name>\n", def->name);
751 752

    virUUIDFormat(def->uuid, uuid);
753
    virBufferVSprintf(&buf,"  <uuid>%s</uuid>\n", uuid);
754

755 756 757 758 759 760
    virBufferVSprintf(&buf,"  <capacity>%llu</capacity>\n",
                      def->capacity);
    virBufferVSprintf(&buf,"  <allocation>%llu</allocation>\n",
                      def->allocation);
    virBufferVSprintf(&buf,"  <available>%llu</available>\n",
                      def->available);
761

762 763
    if (virStoragePoolSourceFormat(conn, &buf, options, &def->source) < 0)
        goto cleanup;
764

765
    virBufferAddLit(&buf,"  <target>\n");
766

767 768
    if (def->target.path)
        virBufferVSprintf(&buf,"    <path>%s</path>\n", def->target.path);
769

770 771 772 773 774 775 776
    virBufferAddLit(&buf,"    <permissions>\n");
    virBufferVSprintf(&buf,"      <mode>0%o</mode>\n",
                      def->target.perms.mode);
    virBufferVSprintf(&buf,"      <owner>%d</owner>\n",
                      def->target.perms.uid);
    virBufferVSprintf(&buf,"      <group>%d</group>\n",
                      def->target.perms.gid);
777

778 779 780
    if (def->target.perms.label)
        virBufferVSprintf(&buf,"      <label>%s</label>\n",
                          def->target.perms.label);
781

782 783 784
    virBufferAddLit(&buf,"    </permissions>\n");
    virBufferAddLit(&buf,"  </target>\n");
    virBufferAddLit(&buf,"</pool>\n");
785

786
    if (virBufferError(&buf))
787 788
        goto no_memory;

789
    return virBufferContentAndReset(&buf);
790 791

 no_memory:
J
Jim Meyering 已提交
792
    virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("xml"));
793
 cleanup:
794
    free(virBufferContentAndReset(&buf));
795 796 797 798 799 800 801 802 803 804 805
    return NULL;
}


static int
virStorageVolDefParsePerms(virConnectPtr conn,
                           xmlXPathContextPtr ctxt,
                           virStoragePermsPtr perms) {
    char *mode;
    long v;

806
    mode = virXPathString(conn, "string(/volume/permissions/mode)", ctxt);
807 808 809 810 811 812 813
    if (!mode) {
        perms->mode = 0600;
    } else {
        char *end = NULL;
        perms->mode = strtol(mode, &end, 8);
        if (*end || perms->mode < 0 || perms->mode > 0777) {
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
814
                                  "%s", _("malformed octal mode"));
815 816 817 818
            return -1;
        }
    }

819
    if (virXPathNode(conn, "/volume/permissions/owner", ctxt) == NULL) {
820 821
        perms->uid = getuid();
    } else {
822
        if (virXPathLong(conn, "number(/volume/permissions/owner)", ctxt, &v) < 0) {
823
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
824
                                  "%s", _("missing owner element"));
825 826 827 828
            return -1;
        }
        perms->uid = (int)v;
    }
829
    if (virXPathNode(conn, "/volume/permissions/group", ctxt) == NULL) {
830 831
        perms->gid = getgid();
    } else {
832
        if (virXPathLong(conn, "number(/volume/permissions/group)", ctxt, &v) < 0) {
833
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
834
                                  "%s", _("missing owner element"));
835 836 837 838 839 840
            return -1;
        }
        perms->gid = (int)v;
    }

    /* NB, we're ignoring missing labels here - they'll simply inherit */
841
    perms->label = virXPathString(conn, "string(/volume/permissions/label)", ctxt);
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904

    return 0;
}


static int
virStorageSize(virConnectPtr conn,
               const char *unit,
               const char *val,
               unsigned long long *ret) {
    unsigned long long mult;
    char *end;

    if (!unit) {
        mult = 1;
    } else {
        switch (unit[0]) {
        case 'k':
        case 'K':
            mult = 1024ull;
            break;

        case 'm':
        case 'M':
            mult = 1024ull * 1024ull;
            break;

        case 'g':
        case 'G':
            mult = 1024ull * 1024ull * 1024ull;
            break;

        case 't':
        case 'T':
            mult = 1024ull * 1024ull * 1024ull * 1024ull;
            break;

        case 'p':
        case 'P':
            mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull;
            break;

        case 'y':
        case 'Y':
            mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull *
                1024ull;
            break;

        case 'z':
        case 'Z':
            mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull *
                1024ull * 1024ull;
            break;

        default:
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
                                  _("unknown size units '%s'"), unit);
            return -1;
        }
    }

    if (virStrToLong_ull (val, &end, 10, ret) < 0) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
905
                              "%s", _("malformed capacity element"));
906 907 908 909
        return -1;
    }
    if (*ret > (ULLONG_MAX / mult)) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
910
                              "%s", _("capacity element value too large"));
911 912 913 914 915 916 917 918 919 920 921 922 923 924
            return -1;
    }

    *ret *= mult;

    return 0;
}

static virStorageVolDefPtr
virStorageVolDefParseDoc(virConnectPtr conn,
                         virStoragePoolDefPtr pool,
                         xmlXPathContextPtr ctxt,
                         xmlNodePtr root) {
    virStorageVolDefPtr ret;
925
    virStorageVolOptionsPtr options;
926 927 928 929
    char *allocation = NULL;
    char *capacity = NULL;
    char *unit = NULL;

930
    options = virStorageVolOptionsForPoolType(pool->type);
931 932 933
    if (options == NULL)
        return NULL;

934 935 936
    if (VIR_ALLOC(ret) < 0) {
        virStorageReportError(conn, VIR_ERR_NO_MEMORY,
                              "%s", _("cannot allocate storage vol"));
937
        return NULL;
938
    }
939 940 941

    if (STRNEQ((const char *)root->name, "volume")) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
942
                              "%s", _("unknown root element"));
943 944 945
        goto cleanup;
    }

946
    ret->name = virXPathString(conn, "string(/volume/name)", ctxt);
947 948
    if (ret->name == NULL) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
949
                              "%s", _("missing volume name element"));
950 951 952
        goto cleanup;
    }

R
Richard W.M. Jones 已提交
953
    /* Auto-generated so deliberately ignore */
954
    /*ret->key = virXPathString(conn, "string(/volume/key)", ctxt);*/
955

956 957
    capacity = virXPathString(conn, "string(/volume/capacity)", ctxt);
    unit = virXPathString(conn, "string(/volume/capacity/@unit)", ctxt);
958 959
    if (capacity == NULL) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
960
                              "%s", _("missing capacity element"));
961 962 963 964
        goto cleanup;
    }
    if (virStorageSize(conn, unit, capacity, &ret->capacity) < 0)
        goto cleanup;
965 966
    VIR_FREE(capacity);
    VIR_FREE(unit);
967

968
    allocation = virXPathString(conn, "string(/volume/allocation)", ctxt);
969
    if (allocation) {
970
        unit = virXPathString(conn, "string(/volume/allocation/@unit)", ctxt);
971 972
        if (virStorageSize(conn, unit, allocation, &ret->allocation) < 0)
            goto cleanup;
973 974
        VIR_FREE(allocation);
        VIR_FREE(unit);
975 976 977 978
    } else {
        ret->allocation = ret->capacity;
    }

979
    ret->target.path = virXPathString(conn, "string(/volume/target/path)", ctxt);
980
    if (options->formatFromString) {
981
        char *format = virXPathString(conn, "string(/volume/target/format/@type)", ctxt);
982 983 984 985 986 987
        if (format == NULL)
            ret->target.format = options->defaultFormat;
        else
            ret->target.format = (options->formatFromString)(format);

        if (ret->target.format < 0) {
988 989
            virStorageReportError(conn, VIR_ERR_XML_ERROR,
                                  _("unknown volume format type %s"), format);
990
            VIR_FREE(format);
991 992
            goto cleanup;
        }
993
        VIR_FREE(format);
994 995 996 997 998 999 1000 1001
    }

    if (virStorageVolDefParsePerms(conn, ctxt, &ret->target.perms) < 0)
        goto cleanup;

    return ret;

 cleanup:
1002 1003 1004
    VIR_FREE(allocation);
    VIR_FREE(capacity);
    VIR_FREE(unit);
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
    virStorageVolDefFree(ret);
    return NULL;
}


virStorageVolDefPtr
virStorageVolDefParse(virConnectPtr conn,
                      virStoragePoolDefPtr pool,
                      const char *xmlStr,
                      const char *filename) {
    virStorageVolDefPtr ret = NULL;
1016
    xmlParserCtxtPtr pctxt;
1017 1018 1019 1020
    xmlDocPtr xml = NULL;
    xmlNodePtr node = NULL;
    xmlXPathContextPtr ctxt = NULL;

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
    /* Set up a parser context so we can catch the details of XML errors. */
    pctxt = xmlNewParserCtxt ();
    if (!pctxt || !pctxt->sax)
        goto cleanup;
    pctxt->sax->error = catchXMLError;
    pctxt->_private = conn;

    if (conn) virResetError (&conn->err);
    xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr,
                          filename ? filename : "storage.xml", NULL,
                          XML_PARSE_NOENT | XML_PARSE_NONET |
                          XML_PARSE_NOWARNING);
    if (!xml) {
        if (conn && conn->err.code == VIR_ERR_NONE)
              virStorageReportError(conn, VIR_ERR_XML_ERROR,
D
Daniel P. Berrange 已提交
1036
                                    "%s", _("failed to parse xml document"));
1037 1038 1039 1040 1041 1042
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        virStorageReportError(conn, VIR_ERR_NO_MEMORY,
J
Jim Meyering 已提交
1043
                              "%s", _("xmlXPathContext"));
1044 1045 1046 1047 1048 1049
        goto cleanup;
    }

    node = xmlDocGetRootElement(xml);
    if (node == NULL) {
        virStorageReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
1050
                              "%s", _("missing root element"));
1051 1052 1053 1054 1055
        goto cleanup;
    }

    ret = virStorageVolDefParseDoc(conn, pool, ctxt, node);

1056
    xmlFreeParserCtxt (pctxt);
1057 1058 1059 1060 1061 1062
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);

    return ret;

 cleanup:
1063
    xmlFreeParserCtxt (pctxt);
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);
    return NULL;
}



char *
virStorageVolDefFormat(virConnectPtr conn,
                       virStoragePoolDefPtr pool,
                       virStorageVolDefPtr def) {
1075
    virStorageVolOptionsPtr options;
1076
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1077
    char *tmp;
1078

1079
    options = virStorageVolOptionsForPoolType(pool->type);
1080 1081 1082
    if (options == NULL)
        return NULL;

1083 1084 1085 1086
    virBufferAddLit(&buf, "<volume>\n");
    virBufferVSprintf(&buf,"  <name>%s</name>\n", def->name);
    virBufferVSprintf(&buf,"  <key>%s</key>\n", def->key);
    virBufferAddLit(&buf, "  <source>\n");
1087 1088 1089 1090 1091 1092 1093 1094

    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)
1095 1096 1097 1098
                    virBufferAddLit(&buf, "    </device>\n");

                virBufferVSprintf(&buf, "    <device path='%s'>\n",
                                  def->source.extents[i].path);
1099 1100
            }

1101 1102 1103 1104
            virBufferVSprintf(&buf,
                              "      <extent start='%llu' end='%llu'/>\n",
                              def->source.extents[i].start,
                              def->source.extents[i].end);
1105 1106 1107
            thispath = def->source.extents[i].path;
        }
        if (thispath != NULL)
1108
            virBufferAddLit(&buf, "    </device>\n");
1109
    }
1110
    virBufferAddLit(&buf, "  </source>\n");
1111

1112 1113 1114 1115
    virBufferVSprintf(&buf,"  <capacity>%llu</capacity>\n",
                      def->capacity);
    virBufferVSprintf(&buf,"  <allocation>%llu</allocation>\n",
                      def->allocation);
1116

1117
    virBufferAddLit(&buf, "  <target>\n");
1118

1119 1120
    if (def->target.path)
        virBufferVSprintf(&buf,"    <path>%s</path>\n", def->target.path);
1121 1122

    if (options->formatToString) {
1123
        const char *format = (options->formatToString)(def->target.format);
1124 1125 1126 1127
        if (!format) {
            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  _("unknown volume format number %d"),
                                  def->target.format);
1128
            goto cleanup;
1129
        }
1130
        virBufferVSprintf(&buf,"    <format type='%s'/>\n", format);
1131 1132
    }

1133 1134 1135 1136 1137 1138 1139
    virBufferAddLit(&buf,"    <permissions>\n");
    virBufferVSprintf(&buf,"      <mode>0%o</mode>\n",
                      def->target.perms.mode);
    virBufferVSprintf(&buf,"      <owner>%d</owner>\n",
                      def->target.perms.uid);
    virBufferVSprintf(&buf,"      <group>%d</group>\n",
                      def->target.perms.gid);
1140 1141


1142 1143 1144 1145 1146 1147 1148
    if (def->target.perms.label)
        virBufferVSprintf(&buf,"      <label>%s</label>\n",
                          def->target.perms.label);

    virBufferAddLit(&buf,"    </permissions>\n");
    virBufferAddLit(&buf, "  </target>\n");
    virBufferAddLit(&buf,"</volume>\n");
1149

1150
    if (virBufferError(&buf))
1151 1152
        goto no_memory;

1153
    return virBufferContentAndReset(&buf);
1154 1155

 no_memory:
J
Jim Meyering 已提交
1156
    virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("xml"));
1157
 cleanup:
1158 1159
    tmp = virBufferContentAndReset(&buf);
    VIR_FREE(tmp);
1160 1161 1162 1163 1164
    return NULL;
}


virStoragePoolObjPtr
1165
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
1166
                            const unsigned char *uuid) {
1167
    unsigned int i;
1168

1169 1170
    for (i = 0 ; i < pools->count ; i++) {
        virStoragePoolObjLock(pools->objs[i]);
1171 1172
        if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
            return pools->objs[i];
1173 1174
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1175 1176 1177 1178 1179

    return NULL;
}

virStoragePoolObjPtr
1180
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
1181
                            const char *name) {
1182
    unsigned int i;
1183

1184 1185
    for (i = 0 ; i < pools->count ; i++) {
        virStoragePoolObjLock(pools->objs[i]);
1186 1187
        if (STREQ(pools->objs[i]->def->name, name))
            return pools->objs[i];
1188 1189
        virStoragePoolObjUnlock(pools->objs[i]);
    }
1190 1191 1192 1193 1194 1195 1196

    return NULL;
}

void
virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
{
1197 1198 1199 1200 1201 1202
    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;
1203 1204 1205 1206 1207
}

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

1210 1211 1212
    for (i = 0 ; i < pool->volumes.count ; i++)
        if (STREQ(pool->volumes.objs[i]->key, key))
            return pool->volumes.objs[i];
1213 1214 1215 1216 1217 1218 1219

    return NULL;
}

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

1222 1223 1224
    for (i = 0 ; i < pool->volumes.count ; i++)
        if (STREQ(pool->volumes.objs[i]->target.path, path))
            return pool->volumes.objs[i];
1225 1226 1227 1228 1229 1230 1231

    return NULL;
}

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

1234 1235 1236
    for (i = 0 ; i < pool->volumes.count ; i++)
        if (STREQ(pool->volumes.objs[i]->name, name))
            return pool->volumes.objs[i];
1237 1238 1239 1240 1241 1242

    return NULL;
}

virStoragePoolObjPtr
virStoragePoolObjAssignDef(virConnectPtr conn,
1243
                           virStoragePoolObjListPtr pools,
1244 1245 1246
                           virStoragePoolDefPtr def) {
    virStoragePoolObjPtr pool;

1247
    if ((pool = virStoragePoolObjFindByName(pools, def->name))) {
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
        if (!virStoragePoolObjIsActive(pool)) {
            virStoragePoolDefFree(pool->def);
            pool->def = def;
        } else {
            if (pool->newDef)
                virStoragePoolDefFree(pool->newDef);
            pool->newDef = def;
        }
        return pool;
    }

1259
    if (VIR_ALLOC(pool) < 0) {
1260
        virStorageReportError(conn, VIR_ERR_NO_MEMORY,
J
Jim Meyering 已提交
1261
                              "%s", _("pool"));
1262 1263 1264
        return NULL;
    }

1265 1266 1267 1268 1269 1270
    if (virMutexInit(&pool->lock) < 0) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("cannot initialize mutex"));
        VIR_FREE(pool);
        return NULL;
    }
1271
    virStoragePoolObjLock(pool);
1272 1273 1274
    pool->active = 0;
    pool->def = def;

1275 1276
    if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
        pool->def = NULL;
1277
        virStoragePoolObjUnlock(pool);
1278 1279 1280 1281 1282
        virStoragePoolObjFree(pool);
        virStorageReportError(conn, VIR_ERR_NO_MEMORY, NULL);
        return NULL;
    }
    pools->objs[pools->count++] = pool;
1283 1284 1285 1286 1287

    return pool;
}

static virStoragePoolObjPtr
1288 1289
virStoragePoolObjLoad(virConnectPtr conn,
                      virStoragePoolObjListPtr pools,
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
                      const char *file,
                      const char *path,
                      const char *xml,
                      const char *autostartLink) {
    virStoragePoolDefPtr def;
    virStoragePoolObjPtr pool;

    if (!(def = virStoragePoolDefParse(NULL, xml, file))) {
        virErrorPtr err = virGetLastError();
        virStorageLog("Error parsing storage pool config '%s' : %s",
1300
                      path, err ? err->message : NULL);
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
        return NULL;
    }

    if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
        virStorageLog("Storage pool config filename '%s' does not match pool name '%s'",
                      path, def->name);
        virStoragePoolDefFree(def);
        return NULL;
    }

1311
    if (!(pool = virStoragePoolObjAssignDef(conn, pools, def))) {
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
        virStorageLog("Failed to load storage pool config '%s': out of memory", path);
        virStoragePoolDefFree(def);
        return NULL;
    }

    pool->configFile = strdup(path);
    if (pool->configFile == NULL) {
        virStorageLog("Failed to load storage pool config '%s': out of memory", path);
        virStoragePoolDefFree(def);
        return NULL;
    }
    pool->autostartLink = strdup(autostartLink);
    if (pool->autostartLink == NULL) {
        virStorageLog("Failed to load storage pool config '%s': out of memory", path);
        virStoragePoolDefFree(def);
        return NULL;
    }

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

    return pool;
}


int
1338 1339 1340 1341
virStoragePoolLoadAllConfigs(virConnectPtr conn,
                             virStoragePoolObjListPtr pools,
                             const char *configDir,
                             const char *autostartDir) {
1342 1343 1344
    DIR *dir;
    struct dirent *entry;

1345
    if (!(dir = opendir(configDir))) {
1346 1347 1348
        if (errno == ENOENT)
            return 0;
        virStorageLog("Failed to open dir '%s': %s",
1349
                      configDir, strerror(errno));
1350 1351 1352 1353 1354 1355 1356
        return -1;
    }

    while ((entry = readdir(dir))) {
        char *xml = NULL;
        char path[PATH_MAX];
        char autostartLink[PATH_MAX];
1357
        virStoragePoolObjPtr pool;
1358 1359 1360 1361 1362 1363 1364

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

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

1365
        if (virFileBuildPath(configDir, entry->d_name,
1366 1367
                             NULL, path, PATH_MAX) < 0) {
            virStorageLog("Config filename '%s/%s' is too long",
1368
                          configDir, entry->d_name);
1369 1370 1371
            continue;
        }

1372
        if (virFileBuildPath(autostartDir, entry->d_name,
1373 1374
                             NULL, autostartLink, PATH_MAX) < 0) {
            virStorageLog("Autostart link path '%s/%s' is too long",
1375
                          autostartDir, entry->d_name);
1376 1377 1378 1379 1380 1381
            continue;
        }

        if (virFileReadAll(path, 8192, &xml) < 0)
            continue;

1382 1383 1384
        pool = virStoragePoolObjLoad(conn, pools, entry->d_name, path, xml, autostartLink);
        if (pool)
            virStoragePoolObjUnlock(pool);
1385

1386
        VIR_FREE(xml);
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
    }

    closedir(dir);

    return 0;
}

int
virStoragePoolObjSaveDef(virConnectPtr conn,
                         virStorageDriverStatePtr driver,
                         virStoragePoolObjPtr pool,
                         virStoragePoolDefPtr def) {
    char *xml;
    int fd = -1, ret = -1;
    ssize_t towrite;

    if (!pool->configFile) {
        int err;
        char path[PATH_MAX];

        if ((err = virFileMakePath(driver->configDir))) {
            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  _("cannot create config directory %s: %s"),
                                  driver->configDir, strerror(err));
            return -1;
        }

        if (virFileBuildPath(driver->configDir, def->name, ".xml",
                             path, sizeof(path)) < 0) {
            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1417
                                  "%s", _("cannot construct config file path"));
1418 1419 1420 1421
            return -1;
        }
        if (!(pool->configFile = strdup(path))) {
            virStorageReportError(conn, VIR_ERR_NO_MEMORY,
J
Jim Meyering 已提交
1422
                                  "%s", _("configFile"));
1423 1424 1425 1426 1427 1428
            return -1;
        }

        if (virFileBuildPath(driver->autostartDir, def->name, ".xml",
                             path, sizeof(path)) < 0) {
            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1429 1430
                                  "%s", _("cannot construct "
                                          "autostart link path"));
1431
            VIR_FREE(pool->configFile);
1432 1433 1434 1435
            return -1;
        }
        if (!(pool->autostartLink = strdup(path))) {
            virStorageReportError(conn, VIR_ERR_NO_MEMORY,
J
Jim Meyering 已提交
1436
                                  "%s", _("config file"));
1437
            VIR_FREE(pool->configFile);
1438 1439 1440 1441 1442 1443
            return -1;
        }
    }

    if (!(xml = virStoragePoolDefFormat(conn, def))) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1444
                              "%s", _("failed to generate XML"));
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
        return -1;
    }

    if ((fd = open(pool->configFile,
                   O_WRONLY | O_CREAT | O_TRUNC,
                   S_IRUSR | S_IWUSR )) < 0) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("cannot create config file %s: %s"),
                              pool->configFile, strerror(errno));
        goto cleanup;
    }

    towrite = strlen(xml);
    if (safewrite(fd, xml, towrite) != towrite) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("cannot write config file %s: %s"),
                              pool->configFile, strerror(errno));
        goto cleanup;
    }

    if (close(fd) < 0) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("cannot save config file %s: %s"),
                              pool->configFile, strerror(errno));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    if (fd != -1)
        close(fd);

1478
    VIR_FREE(xml);
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500

    return ret;
}

int
virStoragePoolObjDeleteDef(virConnectPtr conn,
                           virStoragePoolObjPtr pool) {
    if (!pool->configFile) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("no config file for %s"), pool->def->name);
        return -1;
    }

    if (unlink(pool->configFile) < 0) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("cannot remove config for %s"),
                              pool->def->name);
        return -1;
    }

    return 0;
}
1501

1502
char *virStoragePoolSourceListFormat(virConnectPtr conn,
1503 1504
                                     virStoragePoolSourceListPtr def)
{
1505
    virStoragePoolOptionsPtr options;
1506
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1507 1508
    const char *type;
    int i;
1509

1510
    options = virStoragePoolOptionsForPoolType(def->type);
1511 1512 1513
    if (options == NULL)
        return NULL;

1514
    type = virStoragePoolTypeToString(def->type);
1515 1516 1517 1518 1519 1520 1521
    if (!type) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("unexpected pool type"));
        goto cleanup;
    }

    virBufferAddLit(&buf, "<sources>\n");
1522 1523

    for (i = 0; i < def->nsources; i++) {
1524
        virStoragePoolSourceFormat(conn, &buf, options, &def->sources[i]);
1525 1526
    }

1527 1528 1529 1530
    virBufferAddLit(&buf, "</sources>\n");

    if (virBufferError(&buf))
        goto no_memory;
1531 1532

    return virBufferContentAndReset(&buf);
1533 1534 1535 1536 1537 1538

 no_memory:
    virStorageReportError(conn, VIR_ERR_NO_MEMORY, NULL);
 cleanup:
    free(virBufferContentAndReset(&buf));
    return NULL;
1539
}
D
Daniel P. Berrange 已提交
1540 1541


1542 1543
void virStoragePoolObjLock(virStoragePoolObjPtr obj)
{
1544
    virMutexLock(&obj->lock);
1545 1546 1547 1548
}

void virStoragePoolObjUnlock(virStoragePoolObjPtr obj)
{
1549
    virMutexUnlock(&obj->lock);
1550
}