storage_backend_fs.c 48.9 KB
Newer Older
1 2 3
/*
 * storage_backend_fs.c: storage backend for FS and directory handling
 *
4
 * Copyright (C) 2007-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2007-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 <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

36 37 38 39
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>

40
#if WITH_BLKID
O
Osier Yang 已提交
41 42 43
# include <blkid/blkid.h>
#endif

44
#include "virerror.h"
45 46
#include "storage_backend_fs.h"
#include "storage_conf.h"
47
#include "virstoragefile.h"
48
#include "vircommand.h"
49
#include "viralloc.h"
50
#include "virxml.h"
E
Eric Blake 已提交
51
#include "virfile.h"
52
#include "virlog.h"
53
#include "virstring.h"
54

55
#define VIR_FROM_THIS VIR_FROM_STORAGE
56

57 58
VIR_LOG_INIT("storage.storage_backend_fs");

59 60 61 62
#define VIR_STORAGE_VOL_FS_OPEN_FLAGS    (VIR_STORAGE_VOL_OPEN_DEFAULT | \
                                          VIR_STORAGE_VOL_OPEN_DIR)
#define VIR_STORAGE_VOL_FS_PROBE_FLAGS   (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \
                                          VIR_STORAGE_VOL_OPEN_NOERROR)
63

64
static int
65
virStorageBackendProbeTarget(virStorageSourcePtr target,
66 67
                             virStorageEncryptionPtr *encryption)
{
68
    int backingStoreFormat;
69 70
    int fd = -1;
    int ret = -1;
71
    int rc;
72
    virStorageSourcePtr meta = NULL;
E
Eric Blake 已提交
73
    struct stat sb;
74 75 76 77

    if (encryption)
        *encryption = NULL;

78 79 80 81
    if ((rc = virStorageBackendVolOpen(target->path, &sb,
                                       VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
        return rc; /* Take care to propagate rc, it is not always -1 */
    fd = rc;
82

83
    if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0)
84
        goto cleanup;
85

86 87
    if (S_ISDIR(sb.st_mode)) {
        target->format = VIR_STORAGE_FILE_DIR;
88 89
        ret = 0;
        goto cleanup;
90
    }
91

92 93 94
    if (!(meta = virStorageFileGetMetadataFromFD(target->path,
                                                 fd,
                                                 VIR_STORAGE_FILE_AUTO,
95
                                                 &backingStoreFormat)))
96
        goto cleanup;
97

98
    if (meta->backingStoreRaw) {
99
        if (!(target->backingStore = virStorageSourceNewFromBacking(meta)))
100 101 102 103
            goto cleanup;

        target->backingStore->format = backingStoreFormat;

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
        /* XXX: Remote storage doesn't play nicely with volumes backed by
         * remote storage. To avoid trouble, just fake the backing store is RAW
         * and put the string from the metadata as the path of the target. */
        if (!virStorageSourceIsLocalStorage(target->backingStore)) {
            virStorageSourceFree(target->backingStore);

            if (VIR_ALLOC(target->backingStore) < 0)
                goto cleanup;

            target->backingStore->type = VIR_STORAGE_TYPE_NETWORK;
            target->backingStore->path = meta->backingStoreRaw;
            meta->backingStoreRaw = NULL;
            target->backingStore->format = VIR_STORAGE_FILE_RAW;
        }

119
        if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) {
120
            if ((rc = virStorageFileProbeFormat(target->backingStore->path,
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
                                                -1, -1)) < 0) {
                /* If the backing file is currently unavailable or is
                 * accessed via remote protocol only log an error, fake the
                 * format as RAW and continue. Returning -1 here would
                 * disable the whole storage pool, making it unavailable for
                 * even maintenance. */
                target->backingStore->format = VIR_STORAGE_FILE_RAW;
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot probe backing volume format: %s"),
                               target->backingStore->path);
            } else {
                target->backingStore->format = rc;
            }
        }
    }
136

J
Ján Tomko 已提交
137 138
    target->format = meta->format;

139 140
    /* Default to success below this point */
    ret = 0;
141

142
    if (meta->capacity)
143
        target->capacity = meta->capacity;
144

145
    if (encryption && meta->encryption) {
146 147
        *encryption = meta->encryption;
        meta->encryption = NULL;
148 149 150 151 152 153 154 155 156 157 158

        switch (target->format) {
        case VIR_STORAGE_FILE_QCOW:
        case VIR_STORAGE_FILE_QCOW2:
            (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
            break;
        default:
            break;
        }

        /* XXX ideally we'd fill in secret UUID here
E
Eric Blake 已提交
159
         * but we cannot guarantee 'conn' is non-NULL
160 161 162 163 164
         * at this point in time :-(  So we only fill
         * in secrets when someone first queries a vol
         */
    }

165
    virBitmapFree(target->features);
166 167
    target->features = meta->features;
    meta->features = NULL;
168

169
    if (meta->compat) {
170 171 172 173 174
        VIR_FREE(target->compat);
        target->compat = meta->compat;
        meta->compat = NULL;
    }

175
 cleanup:
176
    VIR_FORCE_CLOSE(fd);
177
    virStorageSourceFree(meta);
178 179
    return ret;

180 181 182
}

#if WITH_STORAGE_FS
183

184
# include <mntent.h>
185

186 187
struct _virNetfsDiscoverState {
    const char *host;
188
    virStoragePoolSourceList list;
189 190 191 192 193
};

typedef struct _virNetfsDiscoverState virNetfsDiscoverState;

static int
194
virStorageBackendFileSystemNetFindPoolSourcesFunc(char **const groups,
195 196 197 198
                                                  void *data)
{
    virNetfsDiscoverState *state = data;
    const char *name, *path;
199 200
    virStoragePoolSource *src = NULL;
    int ret = -1;
201 202 203

    path = groups[0];

204
    if (!(name = strrchr(path, '/'))) {
205 206
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid netfs path (no /): %s"), path);
207
        goto cleanup;
208 209 210
    }
    name += 1;
    if (*name == '\0') {
211 212
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid netfs path (ends in /): %s"), path);
213
        goto cleanup;
214 215
    }

216
    if (!(src = virStoragePoolSourceListNewSource(&state->list)))
217
        goto cleanup;
218

219
    if (VIR_ALLOC_N(src->hosts, 1) < 0)
220
        goto cleanup;
221
    src->nhost = 1;
222

223 224
    if (VIR_STRDUP(src->hosts[0].name, state->host) < 0 ||
        VIR_STRDUP(src->dir, path) < 0)
225
        goto cleanup;
226
    src->format = VIR_STORAGE_POOL_NETFS_NFS;
227

228
    ret = 0;
229
 cleanup:
230
    return ret;
231 232
}

233

234
static int
235
virStorageBackendFileSystemNetFindNFSPoolSources(virNetfsDiscoverState *state)
236
{
237 238
    int ret = -1;

239 240 241 242 243 244 245 246 247 248 249 250 251 252
    /*
     *  # showmount --no-headers -e HOSTNAME
     *  /tmp   *
     *  /A dir demo1.foo.bar,demo2.foo.bar
     *
     * Extract directory name (including possible interior spaces ...).
     */

    const char *regexes[] = {
        "^(/.*\\S) +\\S+$"
    };
    int vars[] = {
        1
    };
253 254 255 256 257 258 259 260 261 262 263

    virCommandPtr cmd = NULL;

    cmd = virCommandNewArgList(SHOWMOUNT,
                               "--no-headers",
                               "--exports",
                               state->host,
                               NULL);

    if (virCommandRunRegex(cmd, 1, regexes, vars,
                           virStorageBackendFileSystemNetFindPoolSourcesFunc,
264
                           state, NULL) < 0)
265
        goto cleanup;
266

267 268 269
    ret = 0;

 cleanup:
270
    virCommandFree(cmd);
271
    return ret;
272 273 274 275 276 277 278 279
}


static char *
virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
                                              const char *srcSpec,
                                              unsigned int flags)
{
280 281 282 283 284 285 286 287
    virNetfsDiscoverState state = {
        .host = NULL,
        .list = {
            .type = VIR_STORAGE_POOL_NETFS,
            .nsources = 0,
            .sources = NULL
        }
    };
288
    virStoragePoolSourcePtr source = NULL;
289
    char *ret = NULL;
290
    size_t i;
291
    int retNFS = -1, retGluster = -1;
292

E
Eric Blake 已提交
293 294
    virCheckFlags(0, NULL);

295
    if (!srcSpec) {
296 297
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("hostname must be specified for netfs sources"));
298 299 300 301 302 303
        return NULL;
    }

    if (!(source = virStoragePoolDefParseSourceString(srcSpec,
                                                      VIR_STORAGE_POOL_NETFS)))
        return NULL;
304

305
    if (source->nhost != 1) {
306 307
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Expected exactly 1 host for the storage pool"));
308 309 310 311
        goto cleanup;
    }

    state.host = source->hosts[0].name;
312

313
    retNFS = virStorageBackendFileSystemNetFindNFSPoolSources(&state);
314

315 316 317
# ifdef GLUSTER_CLI
    retGluster =
        virStorageBackendFindGlusterPoolSources(state.host,
318
                                                VIR_STORAGE_POOL_NETFS_GLUSTERFS,
319 320 321 322
                                                &state.list);
# endif
    /* If both fail, then we won't return an empty list - return an error */
    if (retNFS < 0 && retGluster < 0)
323 324
        goto cleanup;

325
    if (!(ret = virStoragePoolSourceListFormat(&state.list)))
326 327 328
        goto cleanup;

 cleanup:
329
    for (i = 0; i < state.list.nsources; i++)
330 331
        virStoragePoolSourceClear(&state.list.sources[i]);
    VIR_FREE(state.list.sources);
332

333
    virStoragePoolSourceFree(source);
334
    return ret;
335 336
}

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
/**
 * @pool storage pool to check FS types
 *
 * Determine if storage pool FS types are properly set up
 *
 * Return 0 if everything's OK, -1 on error
 */
static int
virStorageBackendFileSystemIsValid(virStoragePoolObjPtr pool)
{
    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
        if (pool->def->source.nhost != 1) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("expected exactly 1 host for the storage pool"));
            return -1;
        }
        if (pool->def->source.hosts[0].name == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source host"));
            return -1;
        }
        if (pool->def->source.dir == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source path"));
            return -1;
        }
    } else {
        if (pool->def->source.ndevice != 1) {
365 366 367 368 369 370 371
            if (pool->def->source.ndevice == 0)
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("missing source device"));
            else
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("expected exactly 1 device for the "
                                 "storage pool"));
372 373 374 375 376
            return -1;
        }
    }
    return 0;
}
377

378 379 380 381 382 383 384 385
/**
 * @pool storage pool to check for status
 *
 * Determine if a storage pool is already mounted
 *
 * Return 0 if not mounted, 1 if mounted, -1 on error
 */
static int
386 387
virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool)
{
388
    FILE *mtab;
389 390
    struct mntent ent;
    char buf[1024];
391 392

    if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
393
        virReportSystemError(errno,
394 395
                             _("cannot read mount list '%s'"),
                             _PATH_MOUNTED);
396 397 398
        return -1;
    }

399 400
    while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) {
        if (STREQ(ent.mnt_dir, pool->def->target.path)) {
401
            VIR_FORCE_FCLOSE(mtab);
402 403 404 405
            return 1;
        }
    }

406
    VIR_FORCE_FCLOSE(mtab);
407 408 409 410 411 412 413 414 415 416 417 418
    return 0;
}

/**
 * @pool storage pool to mount
 *
 * Ensure that a FS storage pool is mounted on its target location.
 * If already mounted, this is a no-op
 *
 * Returns 0 if successfully mounted, -1 on error
 */
static int
419 420
virStorageBackendFileSystemMount(virStoragePoolObjPtr pool)
{
421
    char *src = NULL;
422 423 424
    /* 'mount -t auto' doesn't seem to auto determine nfs (or cifs),
     *  while plain 'mount' does. We have to craft separate argvs to
     *  accommodate this */
425 426 427 428
    bool netauto = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                    pool->def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
    bool glusterfs = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                      pool->def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);
429 430
    bool cifsfs = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                   pool->def->source.format == VIR_STORAGE_POOL_NETFS_CIFS);
431 432
    virCommandPtr cmd = NULL;
    int ret = -1;
433
    int rc;
434

435 436
    if (virStorageBackendFileSystemIsValid(pool) < 0)
        return -1;
437

J
Jim Meyering 已提交
438
    /* Short-circuit if already mounted */
439 440 441 442 443 444
    if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 0) {
        if (rc == 1) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("Target '%s' is already mounted"),
                           pool->def->target.path);
        }
445
        return -1;
446 447 448
    }

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
449 450 451 452 453 454 455 456 457 458 459
        if (pool->def->source.format == VIR_STORAGE_POOL_NETFS_CIFS) {
            if (virAsprintf(&src, "//%s/%s",
                            pool->def->source.hosts[0].name,
                            pool->def->source.dir) == -1)
                return -1;
        } else {
            if (virAsprintf(&src, "%s:%s",
                            pool->def->source.hosts[0].name,
                            pool->def->source.dir) == -1)
                return -1;
        }
460
    } else {
461
        if (VIR_STRDUP(src, pool->def->source.devices[0].path) < 0)
462
            return -1;
463 464
    }

465 466 467 468 469 470
    if (netauto)
        cmd = virCommandNewArgList(MOUNT,
                                   src,
                                   pool->def->target.path,
                                   NULL);
    else if (glusterfs)
471 472
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
473
                                   virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
474 475 476 477 478
                                   src,
                                   "-o",
                                   "direct-io-mode=1",
                                   pool->def->target.path,
                                   NULL);
479 480 481 482 483 484 485 486 487
    else if (cifsfs)
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
                                   virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
                                   src,
                                   pool->def->target.path,
                                   "-o",
                                   "guest",
                                   NULL);
488 489 490 491 492 493 494 495 496 497 498 499 500 501
    else
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
                                   (pool->def->type == VIR_STORAGE_POOL_FS ?
                                    virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
                                    virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format)),
                                   src,
                                   pool->def->target.path,
                                   NULL);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;
502
 cleanup:
503
    virCommandFree(cmd);
504
    VIR_FREE(src);
505
    return ret;
506 507 508 509 510 511
}

/**
 * @pool storage pool to unmount
 *
 * Ensure that a FS storage pool is not mounted on its target location.
512
 * If already unmounted, this is a no-op.
513 514 515 516
 *
 * Returns 0 if successfully unmounted, -1 on error
 */
static int
517 518
virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool)
{
519 520
    virCommandPtr cmd = NULL;
    int ret = -1;
521
    int rc;
522

523 524
    if (virStorageBackendFileSystemIsValid(pool) < 0)
        return -1;
525 526

    /* Short-circuit if already unmounted */
527 528
    if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 1)
        return rc;
529

530 531 532
    cmd = virCommandNewArgList(UMOUNT,
                               pool->def->target.path,
                               NULL);
533

534 535 536 537
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;
538
 cleanup:
539 540
    virCommandFree(cmd);
    return ret;
541 542 543 544
}
#endif /* WITH_STORAGE_FS */


545
static int
546
virStorageBackendFileSystemCheck(virStoragePoolObjPtr pool,
547 548 549
                                 bool *isActive)
{
    if (pool->def->type == VIR_STORAGE_POOL_DIR) {
550
        *isActive = virFileExists(pool->def->target.path);
551 552 553
#if WITH_STORAGE_FS
    } else {
        int ret;
554
        *isActive = false;
555 556 557 558

        if (virStorageBackendFileSystemIsValid(pool) < 0)
            return -1;

559 560 561 562 563 564 565 566 567 568 569 570
        if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 0) {
            if (ret < 0)
                return -1;
            *isActive = true;
        }
#endif /* WITH_STORAGE_FS */
    }

    return 0;
}

#if WITH_STORAGE_FS
571 572 573 574
/**
 * @conn connection to report errors against
 * @pool storage pool to start
 *
575 576
 * Starts a directory or FS based storage pool.  The underlying source
 * device will be mounted for FS based pools.
577 578 579 580
 *
 * Returns 0 on success, -1 on error
 */
static int
581
virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED,
582 583 584
                                 virStoragePoolObjPtr pool)
{
    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
585
        virStorageBackendFileSystemMount(pool) < 0)
586 587 588 589 590 591
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */

592
#if WITH_BLKID
O
Osier Yang 已提交
593 594
static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device,
595 596
                                 const char *format)
{
O
Osier Yang 已提交
597 598 599 600 601 602 603 604 605 606

    virStoragePoolProbeResult ret = FILESYSTEM_PROBE_ERROR;
    blkid_probe probe = NULL;
    const char *fstype = NULL;
    char *names[2], *libblkid_format = NULL;

    VIR_DEBUG("Probing for existing filesystem of type %s on device %s",
              format, device);

    if (blkid_known_fstype(format) == 0) {
607 608 609 610
        virReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                       _("Not capable of probing for "
                         "filesystem of type %s"),
                       format);
O
Osier Yang 已提交
611 612 613 614 615
        goto error;
    }

    probe = blkid_new_probe_from_filename(device);
    if (probe == NULL) {
616 617 618 619
        virReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                       _("Failed to create filesystem probe "
                         "for device %s"),
                       device);
O
Osier Yang 已提交
620 621 622
        goto error;
    }

623
    if (VIR_STRDUP(libblkid_format, format) < 0)
O
Osier Yang 已提交
624 625 626 627 628 629 630 631 632 633 634 635 636 637
        goto error;

    names[0] = libblkid_format;
    names[1] = NULL;

    blkid_probe_filter_superblocks_type(probe,
                                        BLKID_FLTR_ONLYIN,
                                        names);

    if (blkid_do_probe(probe) != 0) {
        VIR_INFO("No filesystem of type '%s' found on device '%s'",
                 format, device);
        ret = FILESYSTEM_PROBE_NOT_FOUND;
    } else if (blkid_probe_lookup_value(probe, "TYPE", &fstype, NULL) == 0) {
638 639 640 641
        virReportError(VIR_ERR_STORAGE_POOL_BUILT,
                       _("Existing filesystem of type '%s' found on "
                         "device '%s'"),
                       fstype, device);
O
Osier Yang 已提交
642 643 644 645
        ret = FILESYSTEM_PROBE_FOUND;
    }

    if (blkid_do_probe(probe) != 1) {
646
        virReportError(VIR_ERR_STORAGE_PROBE_FAILED, "%s",
647 648
                       _("Found additional probes to run, "
                         "filesystem probing may be incorrect"));
O
Osier Yang 已提交
649 650 651
        ret = FILESYSTEM_PROBE_ERROR;
    }

652
 error:
O
Osier Yang 已提交
653 654
    VIR_FREE(libblkid_format);

655
    if (probe != NULL)
O
Osier Yang 已提交
656 657 658 659 660
        blkid_free_probe(probe);

    return ret;
}

661
#else /* #if WITH_BLKID */
O
Osier Yang 已提交
662 663 664 665 666

static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device ATTRIBUTE_UNUSED,
                                 const char *format ATTRIBUTE_UNUSED)
{
667
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
668 669
                   _("probing for filesystems is unsupported "
                     "by this build"));
O
Osier Yang 已提交
670 671 672 673

    return FILESYSTEM_PROBE_ERROR;
}

674
#endif /* #if WITH_BLKID */
O
Osier Yang 已提交
675

676 677
/* some platforms don't support mkfs */
#ifdef MKFS
O
Osier Yang 已提交
678 679 680 681 682 683 684
static int
virStorageBackendExecuteMKFS(const char *device,
                             const char *format)
{
    int ret = 0;
    virCommandPtr cmd = NULL;

J
Ján Tomko 已提交
685 686 687 688 689 690 691
    cmd = virCommandNewArgList(MKFS, "-t", format, NULL);

    /* use the force, otherwise mkfs.xfs won't overwrite existing fs */
    if (STREQ(format, "xfs"))
        virCommandAddArg(cmd, "-f");

    virCommandAddArg(cmd, device);
O
Osier Yang 已提交
692 693 694 695 696 697 698 699

    if (virCommandRun(cmd, NULL) < 0) {
        virReportSystemError(errno,
                             _("Failed to make filesystem of "
                               "type '%s' on device '%s'"),
                             format, device);
        ret = -1;
    }
700 701

    virCommandFree(cmd);
O
Osier Yang 已提交
702 703
    return ret;
}
704 705 706 707 708
#else /* #ifdef MKFS */
static int
virStorageBackendExecuteMKFS(const char *device ATTRIBUTE_UNUSED,
                             const char *format ATTRIBUTE_UNUSED)
{
709 710 711 712 713
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("mkfs is not supported on this platform: "
                     "Failed to make filesystem of "
                     "type '%s' on device '%s'"),
                   format, device);
714 715 716
    return -1;
}
#endif /* #ifdef MKFS */
O
Osier Yang 已提交
717 718 719 720 721 722 723 724 725 726

static int
virStorageBackendMakeFileSystem(virStoragePoolObjPtr pool,
                                unsigned int flags)
{
    const char *device = NULL, *format = NULL;
    bool ok_to_mkfs = false;
    int ret = -1;

    if (pool->def->source.devices == NULL) {
727 728 729
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("No source device specified when formatting pool '%s'"),
                       pool->def->name);
O
Osier Yang 已提交
730 731 732 733 734 735 736 737
        goto error;
    }

    device = pool->def->source.devices[0].path;
    format = virStoragePoolFormatFileSystemTypeToString(pool->def->source.format);
    VIR_DEBUG("source device: '%s' format: '%s'", device, format);

    if (!virFileExists(device)) {
738 739 740
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Source device does not exist when formatting pool '%s'"),
                       pool->def->name);
O
Osier Yang 已提交
741 742 743 744 745 746 747 748 749 750 751
        goto error;
    }

    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) {
        ok_to_mkfs = true;
    } else if (flags & VIR_STORAGE_POOL_BUILD_NO_OVERWRITE &&
               virStorageBackendFileSystemProbe(device, format) ==
               FILESYSTEM_PROBE_NOT_FOUND) {
        ok_to_mkfs = true;
    }

752
    if (ok_to_mkfs)
O
Osier Yang 已提交
753 754
        ret = virStorageBackendExecuteMKFS(device, format);

755
 error:
O
Osier Yang 已提交
756 757 758
    return ret;
}

759 760 761 762

/**
 * @conn connection to report errors against
 * @pool storage pool to build
E
Eric Blake 已提交
763
 * @flags controls the pool formatting behaviour
764 765 766
 *
 * Build a directory or FS based storage pool.
 *
O
Osier Yang 已提交
767 768 769 770 771 772 773
 * If no flag is set, it only makes the directory; If
 * VIR_STORAGE_POOL_BUILD_NO_OVERWRITE set, it probes to determine if
 * filesystem already exists on the target device, renurning an error
 * if exists, or using mkfs to format the target device if not; If
 * VIR_STORAGE_POOL_BUILD_OVERWRITE is set, mkfs is always executed,
 * any existed data on the target device is overwritten unconditionally.
 *
774
 * The underlying source device is mounted for FS based pools.
775 776 777 778
 *
 * Returns 0 on success, -1 on error
 */
static int
779
virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
780
                                 virStoragePoolObjPtr pool,
E
Eric Blake 已提交
781
                                 unsigned int flags)
782
{
783
    int ret = -1;
O
Osier Yang 已提交
784 785
    char *parent = NULL;
    char *p = NULL;
786
    mode_t mode;
787 788
    bool needs_create_as_uid;
    unsigned int dir_create_flags;
789

O
Osier Yang 已提交
790 791 792
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);

793 794 795
    VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE,
                             VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
                             error);
E
Eric Blake 已提交
796

797
    if (VIR_STRDUP(parent, pool->def->target.path) < 0)
798 799
        goto error;
    if (!(p = strrchr(parent, '/'))) {
800 801 802
        virReportError(VIR_ERR_INVALID_ARG,
                       _("path '%s' is not absolute"),
                       pool->def->target.path);
803
        goto error;
804 805
    }

806 807 808 809
    if (p != parent) {
        /* assure all directories in the path prior to the final dir
         * exist, with default uid/gid/mode. */
        *p = '\0';
810 811
        if (virFileMakePath(parent) < 0) {
            virReportSystemError(errno, _("cannot create path '%s'"),
812 813 814 815 816
                                 parent);
            goto error;
        }
    }

817 818 819 820 821 822 823 824
    dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST;
    needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS);
    mode = pool->def->target.perms.mode;

    if (mode == (mode_t) -1 &&
        (needs_create_as_uid || !virFileExists(pool->def->target.path)))
        mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE;
    if (needs_create_as_uid)
825
        dir_create_flags |= VIR_DIR_CREATE_AS_UID;
826

827 828 829
    /* Now create the final dir in the path with the uid/gid/mode
     * requested in the config. If the dir already exists, just set
     * the perms. */
830 831 832 833 834
    if (virDirCreate(pool->def->target.path,
                     mode,
                     pool->def->target.perms.uid,
                     pool->def->target.perms.gid,
                     dir_create_flags) < 0)
835
        goto error;
O
Osier Yang 已提交
836 837 838 839 840 841 842

    if (flags != 0) {
        ret = virStorageBackendMakeFileSystem(pool, flags);
    } else {
        ret = 0;
    }

843
 error:
844 845
    VIR_FREE(parent);
    return ret;
846 847 848 849 850 851 852 853
}


/**
 * Iterate over the pool's directory and enumerate all disk images
 * within it. This is non-recursive.
 */
static int
854
virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
855 856 857 858 859
                                   virStoragePoolObjPtr pool)
{
    DIR *dir;
    struct dirent *ent;
    struct statvfs sb;
860
    struct stat statbuf;
861
    virStorageVolDefPtr vol = NULL;
862
    virStorageSourcePtr target = NULL;
E
Eric Blake 已提交
863
    int direrr;
864
    int fd = -1, ret = -1;
865 866

    if (!(dir = opendir(pool->def->target.path))) {
867
        virReportSystemError(errno,
868 869
                             _("cannot open path '%s'"),
                             pool->def->target.path);
870
        goto cleanup;
871 872
    }

E
Eric Blake 已提交
873
    while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) {
874
        int err;
875

876 877 878 879 880 881
        if (virStringHasControlChars(ent->d_name)) {
            VIR_WARN("Ignoring file with control characters under '%s'",
                     pool->def->target.path);
            continue;
        }

882
        if (VIR_ALLOC(vol) < 0)
883
            goto cleanup;
884

885
        if (VIR_STRDUP(vol->name, ent->d_name) < 0)
886
            goto cleanup;
887

888
        vol->type = VIR_STORAGE_VOL_FILE;
889
        vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
890 891 892
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path,
                        vol->name) == -1)
893
            goto cleanup;
894

895
        if (VIR_STRDUP(vol->key, vol->target.path) < 0)
896
            goto cleanup;
897

898
        if ((err = virStorageBackendProbeTarget(&vol->target,
899
                                                &vol->target.encryption)) < 0) {
900
            if (err == -2) {
901
                /* Silently ignore non-regular files,
902
                 * eg '.' '..', 'lost+found', dangling symbolic link */
903 904
                virStorageVolDefFree(vol);
                vol = NULL;
905
                continue;
906
            } else if (err == -3) {
907 908 909 910 911
                /* The backing file is currently unavailable, its format is not
                 * explicitly specified, the probe to auto detect the format
                 * failed: continue with faked RAW format, since AUTO will
                 * break virStorageVolTargetDefFormat() generating the line
                 * <format type='...'/>. */
912
            } else {
913
                goto cleanup;
914
            }
915 916
        }

917 918 919 920
        /* directory based volume */
        if (vol->target.format == VIR_STORAGE_FILE_DIR)
            vol->type = VIR_STORAGE_VOL_DIR;

921
        if (vol->target.backingStore) {
922
            ignore_value(virStorageBackendUpdateVolTargetInfo(vol->target.backingStore,
923
                                                              false,
924
                                                              VIR_STORAGE_VOL_OPEN_DEFAULT));
925 926 927
            /* If this failed, the backing file is currently unavailable,
             * the capacity, allocation, owner, group and mode are unknown.
             * An error message was raised, but we just continue. */
928 929
        }

930
        if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
931
            goto cleanup;
932
    }
E
Eric Blake 已提交
933
    if (direrr < 0)
934
        goto cleanup;
935
    closedir(dir);
936 937
    dir = NULL;
    vol = NULL;
938

939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
    if (VIR_ALLOC(target))
        goto cleanup;

    if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) {
        virReportSystemError(errno,
                             _("cannot open path '%s'"),
                             pool->def->target.path);
        goto cleanup;
    }

    if (fstat(fd, &statbuf) < 0) {
        virReportSystemError(errno,
                             _("cannot stat path '%s'"),
                             pool->def->target.path);
        goto cleanup;
    }

    if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0)
        goto cleanup;

    /* VolTargetInfoFD doesn't update capacity correctly for the pool case */
960
    if (statvfs(pool->def->target.path, &sb) < 0) {
961
        virReportSystemError(errno,
962 963
                             _("cannot statvfs path '%s'"),
                             pool->def->target.path);
964
        goto cleanup;
965
    }
966

967 968 969
    pool->def->capacity = ((unsigned long long)sb.f_frsize *
                           (unsigned long long)sb.f_blocks);
    pool->def->available = ((unsigned long long)sb.f_bfree *
970
                            (unsigned long long)sb.f_frsize);
971 972
    pool->def->allocation = pool->def->capacity - pool->def->available;

973 974 975 976 977 978
    pool->def->target.perms.mode = target->perms->mode;
    pool->def->target.perms.uid = target->perms->uid;
    pool->def->target.perms.gid = target->perms->gid;
    VIR_FREE(pool->def->target.perms.label);
    if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0)
        goto cleanup;
979

980 981
    ret = 0;
 cleanup:
982 983
    if (dir)
        closedir(dir);
984
    VIR_FORCE_CLOSE(fd);
985
    virStorageVolDefFree(vol);
986 987 988 989
    virStorageSourceFree(target);
    if (ret < 0)
        virStoragePoolObjClearVols(pool);
    return ret;
990 991 992 993 994
}


/**
 * @conn connection to report errors against
995
 * @pool storage pool to stop
996
 *
997 998
 * Stops a file storage pool.  The underlying source device is unmounted
 * for FS based pools.  Any cached data about volumes is released.
999
 *
1000
 * Returns 0 on success, -1 on error.
1001 1002 1003
 */
#if WITH_STORAGE_FS
static int
1004
virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED,
1005 1006
                                virStoragePoolObjPtr pool)
{
1007
    if (virStorageBackendFileSystemUnmount(pool) < 0)
1008 1009 1010 1011 1012 1013 1014 1015 1016
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */


/**
 * @conn connection to report errors against
1017
 * @pool storage pool to delete
1018
 *
1019
 * Delete a directory based storage pool
1020 1021 1022 1023
 *
 * Returns 0 on success, -1 on error
 */
static int
1024
virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
1025
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
1026
                                  unsigned int flags)
1027
{
E
Eric Blake 已提交
1028 1029
    virCheckFlags(0, -1);

1030 1031
    /* XXX delete all vols first ? */

1032
    if (rmdir(pool->def->target.path) < 0) {
1033
        virReportSystemError(errno,
1034
                             _("failed to remove pool '%s'"),
1035
                             pool->def->target.path);
1036 1037 1038 1039 1040 1041 1042 1043
        return -1;
    }

    return 0;
}


/**
1044 1045 1046 1047
 * Set up a volume definition to be added to a pool's volume list, but
 * don't do any file creation or allocation. By separating the two processes,
 * we allow allocation progress reporting (by polling the volume's 'info'
 * function), and can drop the parent pool lock during the (slow) allocation.
1048 1049
 */
static int
1050
virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
1051 1052 1053 1054
                                     virStoragePoolObjPtr pool,
                                     virStorageVolDefPtr vol)
{

1055 1056 1057 1058
    if (vol->target.format == VIR_STORAGE_FILE_DIR)
        vol->type = VIR_STORAGE_VOL_DIR;
    else
        vol->type = VIR_STORAGE_VOL_FILE;
1059

R
Ryota Ozaki 已提交
1060
    VIR_FREE(vol->target.path);
1061 1062
    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path,
1063
                    vol->name) == -1)
1064
        return -1;
1065

1066 1067 1068 1069 1070 1071 1072
    if (virFileExists(vol->target.path)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("volume target path '%s' already exists"),
                       vol->target.path);
        return -1;
    }

R
Ryota Ozaki 已提交
1073
    VIR_FREE(vol->key);
1074
    return VIR_STRDUP(vol->key, vol->target.path);
1075 1076
}

1077
static int createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED,
1078
                         virStoragePoolObjPtr pool,
1079
                         virStorageVolDefPtr vol,
1080
                         virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1081 1082
                         unsigned int flags)
{
1083 1084
    int err;

E
Eric Blake 已提交
1085 1086
    virCheckFlags(0, -1);

1087
    if (inputvol) {
1088 1089 1090
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s",
                       _("cannot copy from volume to a directory volume"));
1091 1092 1093
        return -1;
    }

1094 1095 1096 1097 1098 1099 1100
    if (vol->target.backingStore) {
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("backing storage not supported for directories volumes"));
        return -1;
    }


1101 1102 1103 1104
    if ((err = virDirCreate(vol->target.path,
                            (vol->target.perms->mode == (mode_t) -1 ?
                             VIR_STORAGE_DEFAULT_VOL_PERM_MODE :
                             vol->target.perms->mode),
1105 1106
                            vol->target.perms->uid,
                            vol->target.perms->gid,
1107
                            (pool->def->type == VIR_STORAGE_POOL_NETFS
1108
                             ? VIR_DIR_CREATE_AS_UID : 0))) < 0) {
1109 1110
        return -1;
    }
1111

1112 1113
    return 0;
}
1114

1115
static int
1116
_virStorageBackendFileSystemVolBuild(virConnectPtr conn,
1117
                                     virStoragePoolObjPtr pool,
1118
                                     virStorageVolDefPtr vol,
1119 1120
                                     virStorageVolDefPtr inputvol,
                                     unsigned int flags)
1121
{
1122
    virStorageBackendBuildVolFrom create_func;
1123
    int tool_type;
1124

1125
    if (inputvol) {
1126
        if (vol->target.encryption != NULL) {
1127 1128 1129 1130
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("storage pool does not support "
                                   "building encrypted volumes from "
                                   "other volumes"));
1131 1132
            return -1;
        }
1133
        create_func = virStorageBackendGetBuildVolFromFunction(vol,
1134
                                                               inputvol);
1135 1136
        if (!create_func)
            return -1;
1137
    } else if (vol->target.format == VIR_STORAGE_FILE_RAW) {
1138
        create_func = virStorageBackendCreateRaw;
1139
    } else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
1140
        create_func = createFileDir;
1141
    } else if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) {
1142
        create_func = virStorageBackendFSImageToolTypeToFunc(tool_type);
1143 1144

        if (!create_func)
1145
            return -1;
1146
    } else {
1147 1148 1149
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("creation of non-raw images "
                               "is not supported without qemu-img"));
1150 1151 1152
        return -1;
    }

1153
    if (create_func(conn, pool, vol, inputvol, flags) < 0)
1154
        return -1;
1155 1156 1157
    return 0;
}

1158 1159 1160 1161 1162 1163 1164
/**
 * Allocate a new file as a volume. This is either done directly
 * for raw/sparse files, or by calling qemu-img/qcow-create for
 * special kinds of files
 */
static int
virStorageBackendFileSystemVolBuild(virConnectPtr conn,
1165
                                    virStoragePoolObjPtr pool,
1166
                                    virStorageVolDefPtr vol,
1167 1168
                                    unsigned int flags)
{
1169 1170 1171
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
                  VIR_STORAGE_VOL_CREATE_REFLINK,
                  -1);
1172 1173

    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL, flags);
1174 1175 1176 1177 1178 1179 1180
}

/*
 * Create a storage vol using 'inputvol' as input
 */
static int
virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
1181
                                        virStoragePoolObjPtr pool,
1182 1183
                                        virStorageVolDefPtr vol,
                                        virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1184 1185
                                        unsigned int flags)
{
1186 1187 1188
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
                  VIR_STORAGE_VOL_CREATE_REFLINK,
                  -1);
E
Eric Blake 已提交
1189

1190
    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol, flags);
1191
}
1192 1193

/**
1194
 * Remove a volume - no support for BLOCK and NETWORK yet
1195 1196
 */
static int
1197
virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
1198 1199
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
E
Eric Blake 已提交
1200
                                     unsigned int flags)
1201
{
E
Eric Blake 已提交
1202 1203
    virCheckFlags(0, -1);

1204
    switch ((virStorageVolType) vol->type) {
1205
    case VIR_STORAGE_VOL_FILE:
1206 1207
    case VIR_STORAGE_VOL_DIR:
        if (virFileRemove(vol->target.path, vol->target.perms->uid,
J
John Ferlan 已提交
1208
                          vol->target.perms->gid) < 0) {
1209 1210
            /* Silently ignore failures where the vol has already gone away */
            if (errno != ENOENT) {
1211 1212 1213 1214 1215 1216 1217 1218
                if (vol->type == VIR_STORAGE_VOL_FILE)
                    virReportSystemError(errno,
                                         _("cannot unlink file '%s'"),
                                         vol->target.path);
                else
                    virReportSystemError(errno,
                                         _("cannot remove directory '%s'"),
                                         vol->target.path);
1219 1220 1221 1222 1223 1224
                return -1;
            }
        }
        break;
    case VIR_STORAGE_VOL_BLOCK:
    case VIR_STORAGE_VOL_NETWORK:
1225 1226
    case VIR_STORAGE_VOL_NETDIR:
    case VIR_STORAGE_VOL_LAST:
1227 1228 1229
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("removing block or network volumes is not supported: %s"),
                       vol->target.path);
1230
        return -1;
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
    }
    return 0;
}


/**
 * Update info about a volume's capacity/allocation
 */
static int
virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
                                      virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                      virStorageVolDefPtr vol)
{
1244 1245
    int ret;

1246 1247
    /* Refresh allocation / capacity / permissions info in case its changed */
    ret = virStorageBackendUpdateVolInfo(vol, false,
1248
                                         VIR_STORAGE_VOL_FS_OPEN_FLAGS);
1249 1250 1251
    if (ret < 0)
        return ret;

N
Nehal J Wani 已提交
1252
    /* Load any secrets if possible */
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
    if (vol->target.encryption &&
        vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_QCOW &&
        vol->target.encryption->nsecrets == 0) {
        virSecretPtr sec;
        virStorageEncryptionSecretPtr encsec = NULL;

        sec = virSecretLookupByUsage(conn,
                                     VIR_SECRET_USAGE_TYPE_VOLUME,
                                     vol->target.path);
        if (sec) {
            if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 ||
                VIR_ALLOC(encsec) < 0) {
                VIR_FREE(vol->target.encryption->secrets);
1266
                virObjectUnref(sec);
1267 1268 1269 1270 1271 1272 1273 1274
                return -1;
            }

            vol->target.encryption->nsecrets = 1;
            vol->target.encryption->secrets[0] = encsec;

            encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
            virSecretGetUUID(sec, encsec->uuid);
1275
            virObjectUnref(sec);
1276 1277 1278 1279
        }
    }

    return 0;
1280 1281
}

1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
static int
virStorageBackendFilesystemResizeQemuImg(const char *path,
                                         unsigned long long capacity)
{
    int ret = -1;
    char *img_tool;
    virCommandPtr cmd = NULL;

    /* KVM is usually ahead of qemu on features, so try that first */
    img_tool = virFindFileInPath("kvm-img");
    if (!img_tool)
        img_tool = virFindFileInPath("qemu-img");

    if (!img_tool) {
1296 1297
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to find kvm-img or qemu-img"));
1298 1299 1300
        return -1;
    }

1301 1302 1303 1304
    /* Round capacity as qemu-img resize errors out on sizes which are not
     * a multiple of 512 */
    capacity = VIR_ROUND_UP(capacity, 512);

1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
    cmd = virCommandNew(img_tool);
    virCommandAddArgList(cmd, "resize", path, NULL);
    virCommandAddArgFormat(cmd, "%llu", capacity);

    ret = virCommandRun(cmd, NULL);

    VIR_FREE(img_tool);
    virCommandFree(cmd);

    return ret;
}

/**
 * Resize a volume
 */
static int
virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED,
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
                                     unsigned long long capacity,
                                     unsigned int flags)
{
1327 1328
    virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE |
                  VIR_STORAGE_VOL_RESIZE_SHRINK, -1);
1329 1330 1331 1332 1333

    bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE;

    if (vol->target.format == VIR_STORAGE_FILE_RAW) {
        return virStorageFileResize(vol->target.path, capacity,
1334
                                    vol->target.allocation, pre_allocate);
1335 1336 1337 1338 1339 1340 1341
    } else {
        if (pre_allocate) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("preallocate is only supported for raw "
                             "type volume"));
            return -1;
        }
1342 1343 1344

        return virStorageBackendFilesystemResizeQemuImg(vol->target.path,
                                                        capacity);
1345
    }
1346 1347
}

1348

1349 1350 1351 1352
virStorageBackend virStorageBackendDirectory = {
    .type = VIR_STORAGE_POOL_DIR,

    .buildPool = virStorageBackendFileSystemBuild,
1353
    .checkPool = virStorageBackendFileSystemCheck,
1354 1355
    .refreshPool = virStorageBackendFileSystemRefresh,
    .deletePool = virStorageBackendFileSystemDelete,
1356
    .buildVol = virStorageBackendFileSystemVolBuild,
1357
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1358 1359 1360
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
1361
    .resizeVol = virStorageBackendFileSystemVolResize,
1362 1363
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
1364
    .wipeVol = virStorageBackendVolWipeLocal,
1365 1366 1367 1368 1369 1370 1371
};

#if WITH_STORAGE_FS
virStorageBackend virStorageBackendFileSystem = {
    .type = VIR_STORAGE_POOL_FS,

    .buildPool = virStorageBackendFileSystemBuild,
1372
    .checkPool = virStorageBackendFileSystemCheck,
1373 1374 1375 1376
    .startPool = virStorageBackendFileSystemStart,
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1377
    .buildVol = virStorageBackendFileSystemVolBuild,
1378
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1379 1380 1381
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
1382
    .resizeVol = virStorageBackendFileSystemVolResize,
1383 1384
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
1385
    .wipeVol = virStorageBackendVolWipeLocal,
1386 1387 1388 1389 1390
};
virStorageBackend virStorageBackendNetFileSystem = {
    .type = VIR_STORAGE_POOL_NETFS,

    .buildPool = virStorageBackendFileSystemBuild,
1391
    .checkPool = virStorageBackendFileSystemCheck,
1392
    .startPool = virStorageBackendFileSystemStart,
1393
    .findPoolSources = virStorageBackendFileSystemNetFindPoolSources,
1394 1395 1396
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1397
    .buildVol = virStorageBackendFileSystemVolBuild,
1398
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1399 1400 1401
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
1402
    .resizeVol = virStorageBackendFileSystemVolResize,
1403 1404
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
1405
    .wipeVol = virStorageBackendVolWipeLocal,
1406
};
1407 1408


1409 1410 1411 1412 1413 1414 1415 1416
typedef struct _virStorageFileBackendFsPriv virStorageFileBackendFsPriv;
typedef virStorageFileBackendFsPriv *virStorageFileBackendFsPrivPtr;

struct _virStorageFileBackendFsPriv {
    char *canonpath; /* unique file identifier (canonical path) */
};


1417 1418 1419 1420 1421 1422 1423
static void
virStorageFileBackendFileDeinit(virStorageSourcePtr src)
{
    VIR_DEBUG("deinitializing FS storage file %p (%s:%s)", src,
              virStorageTypeToString(virStorageSourceGetActualType(src)),
              src->path);

1424 1425 1426 1427
    virStorageFileBackendFsPrivPtr priv = src->drv->priv;

    VIR_FREE(priv->canonpath);
    VIR_FREE(priv);
1428 1429 1430
}


1431
static int
1432
virStorageFileBackendFileInit(virStorageSourcePtr src)
1433
{
1434 1435
    virStorageFileBackendFsPrivPtr priv = NULL;

1436
    VIR_DEBUG("initializing FS storage file %p (%s:%s)[%u:%u]", src,
1437
              virStorageTypeToString(virStorageSourceGetActualType(src)),
1438 1439
              src->path,
              (unsigned int)src->drv->uid, (unsigned int)src->drv->gid);
1440

1441 1442 1443 1444 1445
    if (VIR_ALLOC(priv) < 0)
        return -1;

    src->drv->priv = priv;

1446 1447
    return 0;
}
1448 1449


1450 1451 1452 1453
static int
virStorageFileBackendFileCreate(virStorageSourcePtr src)
{
    int fd = -1;
1454
    mode_t mode = S_IRUSR;
1455

1456 1457 1458 1459
    if (!src->readonly)
        mode |= S_IWUSR;

    if ((fd = virFileOpenAs(src->path, O_WRONLY | O_TRUNC | O_CREAT, mode,
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
                            src->drv->uid, src->drv->gid, 0)) < 0) {
        errno = -fd;
        return -1;
    }

    VIR_FORCE_CLOSE(fd);
    return 0;
}


1470 1471 1472 1473
static int
virStorageFileBackendFileUnlink(virStorageSourcePtr src)
{
    return unlink(src->path);
1474 1475 1476 1477
}


static int
1478
virStorageFileBackendFileStat(virStorageSourcePtr src,
1479 1480
                              struct stat *st)
{
1481
    return stat(src->path, st);
1482 1483 1484
}


1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
static ssize_t
virStorageFileBackendFileReadHeader(virStorageSourcePtr src,
                                    ssize_t max_len,
                                    char **buf)
{
    int fd = -1;
    ssize_t ret = -1;

    if ((fd = virFileOpenAs(src->path, O_RDONLY, 0,
                            src->drv->uid, src->drv->gid, 0)) < 0) {
        virReportSystemError(-fd, _("Failed to open file '%s'"),
                             src->path);
        return -1;
    }

    if ((ret = virFileReadHeaderFD(fd, max_len, buf)) < 0) {
        virReportSystemError(errno,
                             _("cannot read header '%s'"), src->path);
        goto cleanup;
    }

 cleanup:
    VIR_FORCE_CLOSE(fd);

    return ret;
}


1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
static const char *
virStorageFileBackendFileGetUniqueIdentifier(virStorageSourcePtr src)
{
    virStorageFileBackendFsPrivPtr priv = src->drv->priv;

    if (!priv->canonpath) {
        if (!(priv->canonpath = canonicalize_file_name(src->path))) {
            virReportSystemError(errno, _("can't canonicalize path '%s'"),
                                 src->path);
            return NULL;
        }
    }

    return priv->canonpath;
}


1530 1531 1532 1533 1534 1535 1536 1537 1538
static int
virStorageFileBackendFileAccess(virStorageSourcePtr src,
                                int mode)
{
    return virFileAccessibleAs(src->path, mode,
                               src->drv->uid, src->drv->gid);
}


1539 1540 1541 1542 1543 1544 1545 1546 1547
static int
virStorageFileBackendFileChown(virStorageSourcePtr src,
                               uid_t uid,
                               gid_t gid)
{
    return chown(src->path, uid, gid);
}


1548
virStorageFileBackend virStorageFileBackendFile = {
E
Eric Blake 已提交
1549
    .type = VIR_STORAGE_TYPE_FILE,
1550

1551 1552 1553
    .backendInit = virStorageFileBackendFileInit,
    .backendDeinit = virStorageFileBackendFileDeinit,

1554
    .storageFileCreate = virStorageFileBackendFileCreate,
1555 1556
    .storageFileUnlink = virStorageFileBackendFileUnlink,
    .storageFileStat = virStorageFileBackendFileStat,
1557
    .storageFileReadHeader = virStorageFileBackendFileReadHeader,
1558
    .storageFileAccess = virStorageFileBackendFileAccess,
1559
    .storageFileChown = virStorageFileBackendFileChown,
1560 1561

    .storageFileGetUniqueIdentifier = virStorageFileBackendFileGetUniqueIdentifier,
1562 1563 1564 1565
};


virStorageFileBackend virStorageFileBackendBlock = {
E
Eric Blake 已提交
1566
    .type = VIR_STORAGE_TYPE_BLOCK,
1567

1568 1569 1570
    .backendInit = virStorageFileBackendFileInit,
    .backendDeinit = virStorageFileBackendFileDeinit,

1571
    .storageFileStat = virStorageFileBackendFileStat,
1572
    .storageFileReadHeader = virStorageFileBackendFileReadHeader,
1573
    .storageFileAccess = virStorageFileBackendFileAccess,
1574
    .storageFileChown = virStorageFileBackendFileChown,
1575 1576

    .storageFileGetUniqueIdentifier = virStorageFileBackendFileGetUniqueIdentifier,
1577 1578 1579
};


1580 1581 1582 1583 1584 1585
virStorageFileBackend virStorageFileBackendDir = {
    .type = VIR_STORAGE_TYPE_DIR,

    .backendInit = virStorageFileBackendFileInit,
    .backendDeinit = virStorageFileBackendFileDeinit,

1586
    .storageFileAccess = virStorageFileBackendFileAccess,
1587
    .storageFileChown = virStorageFileBackendFileChown,
1588

1589 1590 1591
    .storageFileGetUniqueIdentifier = virStorageFileBackendFileGetUniqueIdentifier,
};

1592
#endif /* WITH_STORAGE_FS */