storage_backend_fs.c 38.0 KB
Newer Older
1 2 3
/*
 * storage_backend_fs.c: storage backend for FS and directory handling
 *
4
 * Copyright (C) 2007-2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * Copyright (C) 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
 * 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 <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>

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

44
#include "virterror_internal.h"
45 46
#include "storage_backend_fs.h"
#include "storage_conf.h"
47
#include "storage_file.h"
48
#include "command.h"
49
#include "memory.h"
50
#include "xml.h"
E
Eric Blake 已提交
51
#include "virfile.h"
O
Osier Yang 已提交
52
#include "logging.h"
53

54
#define VIR_FROM_THIS VIR_FROM_STORAGE
55

56 57 58 59 60
#define VIR_STORAGE_VOL_FS_OPEN_FLAGS       (VIR_STORAGE_VOL_OPEN_DEFAULT   |\
                                             VIR_STORAGE_VOL_OPEN_DIR)
#define VIR_STORAGE_VOL_FS_REFRESH_FLAGS    (VIR_STORAGE_VOL_FS_OPEN_FLAGS  &\
                                             ~VIR_STORAGE_VOL_OPEN_ERROR)

E
Eric Blake 已提交
61
static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
62
virStorageBackendProbeTarget(virStorageVolTargetPtr target,
63
                             char **backingStore,
64
                             int *backingStoreFormat,
65 66 67 68
                             unsigned long long *allocation,
                             unsigned long long *capacity,
                             virStorageEncryptionPtr *encryption)
{
69 70 71 72 73 74 75 76
    int fd = -1;
    int ret = -1;
    virStorageFileMetadata *meta;

    if (VIR_ALLOC(meta) < 0) {
        virReportOOMError();
        return ret;
    }
77

E
Eric Blake 已提交
78 79
    *backingStore = NULL;
    *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
80 81 82
    if (encryption)
        *encryption = NULL;

83
    if ((ret = virStorageBackendVolOpenCheckMode(target->path,
84
                                        VIR_STORAGE_VOL_FS_REFRESH_FLAGS)) < 0)
85
        goto error; /* Take care to propagate ret, it is not always -1 */
86
    fd = ret;
87

88
    if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd,
89 90
                                                      allocation,
                                                      capacity)) < 0) {
91
        goto error;
92 93
    }

94
    if ((target->format = virStorageFileProbeFormatFromFD(target->path, fd)) < 0) {
95 96
        ret = -1;
        goto error;
97 98
    }

99 100
    if (virStorageFileGetMetadataFromFD(target->path, fd,
                                        target->format,
101 102 103
                                        meta) < 0) {
        ret = -1;
        goto error;
104
    }
105

106
    VIR_FORCE_CLOSE(fd);
107

108 109 110 111
    if (meta->backingStore) {
        *backingStore = meta->backingStore;
        meta->backingStore = NULL;
        if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO) {
112 113 114 115 116 117 118 119 120 121 122
            if ((ret = virStorageFileProbeFormat(*backingStore)) < 0) {
                /* If the backing file is currently unavailable, only log an error,
                 * but continue. Returning -1 here would disable the whole storage
                 * pool, making it unavailable for even maintenance. */
                virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                      _("cannot probe backing volume format: %s"),
                                      *backingStore);
                ret = -3;
            } else {
                *backingStoreFormat = ret;
                ret = 0;
123 124
            }
        } else {
125
            *backingStoreFormat = meta->backingStoreFormat;
126
            ret = 0;
127
        }
E
Eric Blake 已提交
128
    } else {
129
        ret = 0;
130 131
    }

132 133
    if (capacity && meta->capacity)
        *capacity = meta->capacity;
134

135
    if (encryption != NULL && meta->encrypted) {
136
        if (VIR_ALLOC(*encryption) < 0) {
137
            virReportOOMError();
138
            goto cleanup;
139 140 141 142 143 144 145 146 147 148 149 150
        }

        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 已提交
151
         * but we cannot guarantee 'conn' is non-NULL
152 153 154 155 156
         * at this point in time :-(  So we only fill
         * in secrets when someone first queries a vol
         */
    }

157 158
    virStorageFileFreeMetadata(meta);

159
    return ret;
160

161 162 163
error:
    VIR_FORCE_CLOSE(fd);

164
cleanup:
165 166 167
    virStorageFileFreeMetadata(meta);
    return ret;

168 169 170
}

#if WITH_STORAGE_FS
171

172
# include <mntent.h>
173

174 175
struct _virNetfsDiscoverState {
    const char *host;
176
    virStoragePoolSourceList list;
177 178 179 180 181
};

typedef struct _virNetfsDiscoverState virNetfsDiscoverState;

static int
182
virStorageBackendFileSystemNetFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
183 184 185 186 187
                                                  char **const groups,
                                                  void *data)
{
    virNetfsDiscoverState *state = data;
    const char *name, *path;
188 189
    virStoragePoolSource *src = NULL;
    int ret = -1;
190 191 192 193 194

    path = groups[0];

    name = strrchr(path, '/');
    if (name == NULL) {
195
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
196
                              _("invalid netfs path (no /): %s"), path);
197
        goto cleanup;
198 199 200
    }
    name += 1;
    if (*name == '\0') {
201
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
202
                              _("invalid netfs path (ends in /): %s"), path);
203
        goto cleanup;
204 205
    }

206
    if (!(src = virStoragePoolSourceListNewSource(&state->list)))
207
        goto cleanup;
208

209
    if (!(src->host.name = strdup(state->host)) ||
210
        !(src->dir = strdup(path))) {
211
        virReportOOMError();
212 213
        goto cleanup;
    }
214
    src->format = VIR_STORAGE_POOL_NETFS_NFS;
215

216 217 218
    src = NULL;
    ret = 0;
cleanup:
219 220
    virStoragePoolSourceFree(src);
    VIR_FREE(src);
221
    return ret;
222 223
}

224

225
static char *
226
virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
227
                                              const char *srcSpec,
E
Eric Blake 已提交
228
                                              unsigned int flags)
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
{
    /*
     *  # 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
    };
244 245 246 247 248 249 250 251
    virNetfsDiscoverState state = {
        .host = NULL,
        .list = {
            .type = VIR_STORAGE_POOL_NETFS,
            .nsources = 0,
            .sources = NULL
        }
    };
252
    const char *prog[] = { SHOWMOUNT, "--no-headers", "--exports", NULL, NULL };
253
    virStoragePoolSourcePtr source = NULL;
254
    char *retval = NULL;
255
    unsigned int i;
256

E
Eric Blake 已提交
257 258
    virCheckFlags(0, NULL);

259
    source = virStoragePoolDefParseSourceString(srcSpec,
260 261
                                                VIR_STORAGE_POOL_NETFS);
    if (!source)
262 263
        goto cleanup;

264 265
    state.host = source->host.name;
    prog[3] = source->host.name;
266

267
    if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
268
                            virStorageBackendFileSystemNetFindPoolSourcesFunc,
269
                            &state, NULL) < 0)
270 271
        goto cleanup;

272
    retval = virStoragePoolSourceListFormat(&state.list);
273
    if (retval == NULL) {
274
        virReportOOMError();
275 276 277 278
        goto cleanup;
    }

 cleanup:
279 280 281
    for (i = 0; i < state.list.nsources; i++)
        virStoragePoolSourceFree(&state.list.sources[i]);

282 283
    virStoragePoolSourceFree(source);
    VIR_FREE(source);
284

285
    VIR_FREE(state.list.sources);
286 287 288 289 290

    return retval;
}


291 292 293 294 295 296 297 298 299
/**
 * @conn connection to report errors against
 * @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
300
virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool) {
301
    FILE *mtab;
302 303
    struct mntent ent;
    char buf[1024];
304 305

    if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
306
        virReportSystemError(errno,
307 308
                             _("cannot read mount list '%s'"),
                             _PATH_MOUNTED);
309 310 311
        return -1;
    }

312 313
    while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) {
        if (STREQ(ent.mnt_dir, pool->def->target.path)) {
314
            VIR_FORCE_FCLOSE(mtab);
315 316 317 318
            return 1;
        }
    }

319
    VIR_FORCE_FCLOSE(mtab);
320 321 322 323 324 325 326 327 328 329 330 331 332
    return 0;
}

/**
 * @conn connection to report errors against
 * @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
333
virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
334
    char *src;
335 336 337 338 339 340 341
    const char **mntargv;

    /* '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 */
    int netauto = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                   pool->def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
342 343 344
    int glusterfs = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                 pool->def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);

345 346 347 348 349 350 351 352 353 354
    int source_index;

    const char *netfs_auto_argv[] = {
        MOUNT,
        NULL, /* source path */
        pool->def->target.path,
        NULL,
    };

    const char *fs_argv[] =  {
355 356 357
        MOUNT,
        "-t",
        pool->def->type == VIR_STORAGE_POOL_FS ?
358 359
        virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
        virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
360 361
        NULL, /* Fill in shortly - careful not to add extra fields
                 before this */
362 363 364
        pool->def->target.path,
        NULL,
    };
365

366 367 368 369 370 371 372 373
    const char *glusterfs_argv[] = {
        MOUNT,
        "-t",
        pool->def->type == VIR_STORAGE_POOL_FS ?
        virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
        virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
        NULL,
        "-o",
E
Eric Blake 已提交
374
        "direct-io-mode=1",
375 376 377 378
        pool->def->target.path,
        NULL,
    };

379 380 381
    if (netauto) {
        mntargv = netfs_auto_argv;
        source_index = 1;
382 383 384
    } else if (glusterfs) {
        mntargv = glusterfs_argv;
        source_index = 3;
385 386 387 388 389
    } else {
        mntargv = fs_argv;
        source_index = 3;
    }

390 391 392 393
    int ret;

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
        if (pool->def->source.host.name == NULL) {
394
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
395
                                  "%s", _("missing source host"));
396 397 398
            return -1;
        }
        if (pool->def->source.dir == NULL) {
399
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
400
                                  "%s", _("missing source path"));
401 402 403 404
            return -1;
        }
    } else {
        if (pool->def->source.ndevice != 1) {
405
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
406
                                  "%s", _("missing source device"));
407 408 409 410
            return -1;
        }
    }

J
Jim Meyering 已提交
411
    /* Short-circuit if already mounted */
412
    if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 0) {
413 414 415 416 417 418 419
        if (ret < 0)
            return -1;
        else
            return 0;
    }

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
420 421 422
        if (virAsprintf(&src, "%s:%s",
                        pool->def->source.host.name,
                        pool->def->source.dir) == -1) {
423
            virReportOOMError();
424 425
            return -1;
        }
426

427
    } else {
428
        if ((src = strdup(pool->def->source.devices[0].path)) == NULL) {
429
            virReportOOMError();
430 431
            return -1;
        }
432
    }
433
    mntargv[source_index] = src;
434

435
    if (virRun(mntargv, NULL) < 0) {
436
        VIR_FREE(src);
437 438
        return -1;
    }
439
    VIR_FREE(src);
440 441 442 443 444 445 446 447 448 449 450 451 452
    return 0;
}

/**
 * @conn connection to report errors against
 * @pool storage pool to unmount
 *
 * Ensure that a FS storage pool is not mounted on its target location.
 * If already unmounted, this is a no-op
 *
 * Returns 0 if successfully unmounted, -1 on error
 */
static int
453
virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) {
454 455 456 457 458
    const char *mntargv[3];
    int ret;

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
        if (pool->def->source.host.name == NULL) {
459
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
460
                                  "%s", _("missing source host"));
461 462 463
            return -1;
        }
        if (pool->def->source.dir == NULL) {
464
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
465
                                  "%s", _("missing source dir"));
466 467 468 469
            return -1;
        }
    } else {
        if (pool->def->source.ndevice != 1) {
470
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
471
                                  "%s", _("missing source device"));
472 473 474 475 476
            return -1;
        }
    }

    /* Short-circuit if already unmounted */
477
    if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 1) {
478 479 480 481 482 483 484 485 486 487
        if (ret < 0)
            return -1;
        else
            return 0;
    }

    mntargv[0] = UMOUNT;
    mntargv[1] = pool->def->target.path;
    mntargv[2] = NULL;

488
    if (virRun(mntargv, NULL) < 0) {
489 490 491 492 493 494 495
        return -1;
    }
    return 0;
}
#endif /* WITH_STORAGE_FS */


496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
static int
virStorageBackendFileSystemCheck(virConnectPtr conn ATTRIBUTE_UNUSED,
                                 virStoragePoolObjPtr pool,
                                 bool *isActive)
{
    *isActive = false;
    if (pool->def->type == VIR_STORAGE_POOL_DIR) {
        if (access(pool->def->target.path, F_OK) == 0)
            *isActive = true;
#if WITH_STORAGE_FS
    } else {
        int ret;
        if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 0) {
            if (ret < 0)
                return -1;
            *isActive = true;
        }
#endif /* WITH_STORAGE_FS */
    }

    return 0;
}

#if WITH_STORAGE_FS
520 521 522 523 524 525 526 527 528 529 530
/**
 * @conn connection to report errors against
 * @pool storage pool to start
 *
 * Starts a directory or FS based storage pool.
 *
 *  - If it is a FS based pool, mounts the unlying source device on the pool
 *
 * Returns 0 on success, -1 on error
 */
static int
531
virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED,
532 533 534
                                 virStoragePoolObjPtr pool)
{
    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
535
        virStorageBackendFileSystemMount(pool) < 0)
536 537 538 539 540 541
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */

O
Osier Yang 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
#if HAVE_LIBBLKID
static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device,
                                 const char *format) {

    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) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                              _("Not capable of probing for "
                                "filesystem of type %s"),
                              format);
        goto error;
    }

    probe = blkid_new_probe_from_filename(device);
    if (probe == NULL) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                                  _("Failed to create filesystem probe "
                                  "for device %s"),
                                  device);
        goto error;
    }

    if ((libblkid_format = strdup(format)) == NULL) {
        virReportOOMError();
        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) {
        virStorageReportError(VIR_ERR_STORAGE_POOL_BUILT,
                              _("Existing filesystem of type '%s' found on "
                                "device '%s'"),
                              fstype, device);
        ret = FILESYSTEM_PROBE_FOUND;
    }

    if (blkid_do_probe(probe) != 1) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                                  _("Found additional probes to run, "
                                    "filesystem probing may be incorrect"));
        ret = FILESYSTEM_PROBE_ERROR;
    }

error:
    VIR_FREE(libblkid_format);

    if (probe != NULL) {
        blkid_free_probe(probe);
    }

    return ret;
}

#else /* #if HAVE_LIBBLKID */

static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device ATTRIBUTE_UNUSED,
                                 const char *format ATTRIBUTE_UNUSED)
{
    virStorageReportError(VIR_ERR_OPERATION_INVALID,
                          _("probing for filesystems is unsupported "
                            "by this build"));

    return FILESYSTEM_PROBE_ERROR;
}

#endif /* #if HAVE_LIBBLKID */

628 629
/* some platforms don't support mkfs */
#ifdef MKFS
O
Osier Yang 已提交
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
static int
virStorageBackendExecuteMKFS(const char *device,
                             const char *format)
{
    int ret = 0;
    virCommandPtr cmd = NULL;

    cmd = virCommandNewArgList(MKFS,
                               "-t",
                               format,
                               device,
                               NULL);

    if (virCommandRun(cmd, NULL) < 0) {
        virReportSystemError(errno,
                             _("Failed to make filesystem of "
                               "type '%s' on device '%s'"),
                             format, device);
        ret = -1;
    }
    return ret;
}
652 653 654 655 656 657 658 659 660 661 662 663 664
#else /* #ifdef MKFS */
static int
virStorageBackendExecuteMKFS(const char *device ATTRIBUTE_UNUSED,
                             const char *format ATTRIBUTE_UNUSED)
{
    virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              _("mkfs is not supported on this platform: "
                                "Failed to make filesystem of "
                               "type '%s' on device '%s'"),
                             format, device);
    return -1;
}
#endif /* #ifdef MKFS */
O
Osier Yang 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707

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) {
        virStorageReportError(VIR_ERR_OPERATION_INVALID,
                              _("No source device specified when formatting pool '%s'"),
                              pool->def->name);
        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)) {
        virStorageReportError(VIR_ERR_OPERATION_INVALID,
                              _("Source device does not exist when formatting pool '%s'"),
                              pool->def->name);
        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;
    }

    if (ok_to_mkfs) {
        ret = virStorageBackendExecuteMKFS(device, format);
    }

error:
    return ret;
}

708 709 710 711

/**
 * @conn connection to report errors against
 * @pool storage pool to build
O
Osier Yang 已提交
712
 * @flags controls the pool formating behaviour
713 714 715
 *
 * Build a directory or FS based storage pool.
 *
O
Osier Yang 已提交
716 717 718 719 720 721 722
 * 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.
 *
723 724 725 726 727
 *  - If it is a FS based pool, mounts the unlying source device on the pool
 *
 * Returns 0 on success, -1 on error
 */
static int
728
virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
729
                                 virStoragePoolObjPtr pool,
E
Eric Blake 已提交
730
                                 unsigned int flags)
731
{
732
    int err, ret = -1;
O
Osier Yang 已提交
733 734
    char *parent = NULL;
    char *p = NULL;
735

O
Osier Yang 已提交
736 737 738 739 740 741 742 743 744 745 746
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);

    if (flags == (VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE)) {

        virStorageReportError(VIR_ERR_OPERATION_INVALID,
                              _("Overwrite and no overwrite flags"
                                " are mutually exclusive"));
        goto error;
    }
E
Eric Blake 已提交
747

748
    if ((parent = strdup(pool->def->target.path)) == NULL) {
749
        virReportOOMError();
750 751 752
        goto error;
    }
    if (!(p = strrchr(parent, '/'))) {
753
        virStorageReportError(VIR_ERR_INVALID_ARG,
754 755 756
                              _("path '%s' is not absolute"),
                              pool->def->target.path);
        goto error;
757 758
    }

759 760 761 762
    if (p != parent) {
        /* assure all directories in the path prior to the final dir
         * exist, with default uid/gid/mode. */
        *p = '\0';
763 764
        if (virFileMakePath(parent) < 0) {
            virReportSystemError(errno, _("cannot create path '%s'"),
765 766 767 768 769 770 771 772
                                 parent);
            goto error;
        }
    }

    /* 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. */
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789

    struct stat st;

    if ((stat(pool->def->target.path, &st) < 0)
        || (pool->def->target.perms.uid != -1)) {

        uid_t uid = (pool->def->target.perms.uid == -1)
            ? getuid() : pool->def->target.perms.uid;
        gid_t gid = (pool->def->target.perms.gid == -1)
            ? getgid() : pool->def->target.perms.gid;

        if ((err = virDirCreate(pool->def->target.path,
                                pool->def->target.perms.mode,
                                uid, gid,
                                VIR_DIR_CREATE_FORCE_PERMS |
                                VIR_DIR_CREATE_ALLOW_EXIST |
                                (pool->def->type == VIR_STORAGE_POOL_NETFS
790 791
                                 ? VIR_DIR_CREATE_AS_UID : 0)) < 0)) {
            virReportSystemError(-err, _("cannot create path '%s'"),
792 793 794
                                 pool->def->target.path);
            goto error;
        }
795
    }
O
Osier Yang 已提交
796 797 798 799 800 801 802

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

803 804 805
error:
    VIR_FREE(parent);
    return ret;
806 807 808 809 810 811 812 813
}


/**
 * Iterate over the pool's directory and enumerate all disk images
 * within it. This is non-recursive.
 */
static int
814
virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
815 816 817 818 819
                                   virStoragePoolObjPtr pool)
{
    DIR *dir;
    struct dirent *ent;
    struct statvfs sb;
820
    virStorageVolDefPtr vol = NULL;
821 822

    if (!(dir = opendir(pool->def->target.path))) {
823
        virReportSystemError(errno,
824 825
                             _("cannot open path '%s'"),
                             pool->def->target.path);
826 827 828 829 830
        goto cleanup;
    }

    while ((ent = readdir(dir)) != NULL) {
        int ret;
831
        char *backingStore;
832
        int backingStoreFormat;
833

834 835
        if (VIR_ALLOC(vol) < 0)
            goto no_memory;
836

837 838
        if ((vol->name = strdup(ent->d_name)) == NULL)
            goto no_memory;
839

840
        vol->type = VIR_STORAGE_VOL_FILE;
841
        vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
842 843 844
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path,
                        vol->name) == -1)
845 846 847 848
            goto no_memory;

        if ((vol->key = strdup(vol->target.path)) == NULL)
            goto no_memory;
849

850
        if ((ret = virStorageBackendProbeTarget(&vol->target,
851
                                                &backingStore,
852
                                                &backingStoreFormat,
853
                                                &vol->allocation,
854
                                                &vol->capacity,
855
                                                &vol->target.encryption)) < 0) {
856
            if (ret == -2) {
857
                /* Silently ignore non-regular files,
858
                 * eg '.' '..', 'lost+found', dangling symbolic link */
859 860
                virStorageVolDefFree(vol);
                vol = NULL;
861
                continue;
862 863 864 865 866 867 868 869 870
            } else if (ret == -3) {
                /* 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='...'/>. */
                backingStoreFormat = VIR_STORAGE_FILE_RAW;
            } else
                goto cleanup;
871 872
        }

873 874 875 876
        /* directory based volume */
        if (vol->target.format == VIR_STORAGE_FILE_DIR)
            vol->type = VIR_STORAGE_VOL_DIR;

877
        if (backingStore != NULL) {
878 879 880 881
            vol->backingStore.path = backingStore;
            vol->backingStore.format = backingStoreFormat;

            if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
882 883
                                        NULL, NULL,
                                        VIR_STORAGE_VOL_OPEN_DEFAULT) < 0) {
884 885 886 887 888 889 890 891 892
                /* The backing file is currently unavailable, the capacity,
                 * allocation, owner, group and mode are unknown. Just log the
                 * error an continue.
                 * Unfortunately virStorageBackendProbeTarget() might already
                 * have logged a similar message for the same problem, but only
                 * if AUTO format detection was used. */
                virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                      _("cannot probe backing volume info: %s"),
                                      vol->backingStore.path);
893 894 895 896
            }
        }


897 898 899 900 901
        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count+1) < 0)
            goto no_memory;
        pool->volumes.objs[pool->volumes.count++] = vol;
        vol = NULL;
902 903 904 905 906
    }
    closedir(dir);


    if (statvfs(pool->def->target.path, &sb) < 0) {
907
        virReportSystemError(errno,
908 909
                             _("cannot statvfs path '%s'"),
                             pool->def->target.path);
910 911 912 913 914 915 916 917 918 919
        return -1;
    }
    pool->def->capacity = ((unsigned long long)sb.f_frsize *
                           (unsigned long long)sb.f_blocks);
    pool->def->available = ((unsigned long long)sb.f_bfree *
                            (unsigned long long)sb.f_bsize);
    pool->def->allocation = pool->def->capacity - pool->def->available;

    return 0;

920
no_memory:
921
    virReportOOMError();
922 923
    /* fallthrough */

924
 cleanup:
925 926
    if (dir)
        closedir(dir);
927
    virStorageVolDefFree(vol);
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
    virStoragePoolObjClearVols(pool);
    return -1;
}


/**
 * @conn connection to report errors against
 * @pool storage pool to start
 *
 * Stops a directory or FS based storage pool.
 *
 *  - If it is a FS based pool, unmounts the unlying source device on the pool
 *  - Releases all cached data about volumes
 */
#if WITH_STORAGE_FS
static int
944
virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED,
945 946 947
                                virStoragePoolObjPtr pool)
{
    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
948
        virStorageBackendFileSystemUnmount(pool) < 0)
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */


/**
 * @conn connection to report errors against
 * @pool storage pool to build
 *
 * Build a directory or FS based storage pool.
 *
 *  - If it is a FS based pool, mounts the unlying source device on the pool
 *
 * Returns 0 on success, -1 on error
 */
static int
967
virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
968
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
969
                                  unsigned int flags)
970
{
E
Eric Blake 已提交
971 972
    virCheckFlags(0, -1);

973 974
    /* XXX delete all vols first ? */

975
    if (rmdir(pool->def->target.path) < 0) {
976
        virReportSystemError(errno,
977
                             _("failed to remove pool '%s'"),
978
                             pool->def->target.path);
979 980 981 982 983 984 985 986
        return -1;
    }

    return 0;
}


/**
987 988 989 990
 * 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.
991 992
 */
static int
993
virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
994 995 996 997
                                     virStoragePoolObjPtr pool,
                                     virStorageVolDefPtr vol)
{

998 999
    vol->type = VIR_STORAGE_VOL_FILE;

R
Ryota Ozaki 已提交
1000
    VIR_FREE(vol->target.path);
1001 1002 1003
    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path,
                    vol->name) == -1) {
1004
        virReportOOMError();
1005 1006
        return -1;
    }
1007

R
Ryota Ozaki 已提交
1008
    VIR_FREE(vol->key);
1009 1010
    vol->key = strdup(vol->target.path);
    if (vol->key == NULL) {
1011
        virReportOOMError();
1012 1013 1014
        return -1;
    }

1015 1016 1017
    return 0;
}

1018
static int createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED,
1019
                         virStoragePoolObjPtr pool,
1020
                         virStorageVolDefPtr vol,
1021
                         virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1022 1023
                         unsigned int flags)
{
1024 1025
    int err;

E
Eric Blake 已提交
1026 1027
    virCheckFlags(0, -1);

1028
    if (inputvol) {
1029
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1030 1031 1032 1033 1034
                              "%s",
                              _("cannot copy from volume to a directory volume"));
        return -1;
    }

1035 1036 1037 1038 1039
    uid_t uid = (vol->target.perms.uid == -1)
        ? getuid() : vol->target.perms.uid;
    gid_t gid = (vol->target.perms.gid == -1)
        ? getgid() : vol->target.perms.gid;

1040
    if ((err = virDirCreate(vol->target.path, vol->target.perms.mode,
1041
                            uid, gid,
1042
                            VIR_DIR_CREATE_FORCE_PERMS |
1043
                            (pool->def->type == VIR_STORAGE_POOL_NETFS
1044 1045
                             ? VIR_DIR_CREATE_AS_UID : 0))) < 0) {
        virReportSystemError(-err, _("cannot create path '%s'"),
1046 1047 1048
                             vol->target.path);
        return -1;
    }
1049

1050 1051
    return 0;
}
1052

1053
static int
1054
_virStorageBackendFileSystemVolBuild(virConnectPtr conn,
1055
                                     virStoragePoolObjPtr pool,
1056 1057
                                     virStorageVolDefPtr vol,
                                     virStorageVolDefPtr inputvol)
1058
{
1059
    virStorageBackendBuildVolFrom create_func;
1060
    int tool_type;
1061

1062
    if (inputvol) {
1063
        if (vol->target.encryption != NULL) {
O
Osier Yang 已提交
1064
            virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1065 1066 1067 1068 1069
                                  "%s", _("storage pool does not support "
                                          "building encrypted volumes from "
                                          "other volumes"));
            return -1;
        }
1070
        create_func = virStorageBackendGetBuildVolFromFunction(vol,
1071
                                                               inputvol);
1072 1073
        if (!create_func)
            return -1;
1074
    } else if (vol->target.format == VIR_STORAGE_FILE_RAW) {
1075
        create_func = virStorageBackendCreateRaw;
1076
    } else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
1077
        create_func = createFileDir;
1078
    } else if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) {
1079
        create_func = virStorageBackendFSImageToolTypeToFunc(tool_type);
1080 1081

        if (!create_func)
1082
            return -1;
1083
    } else {
1084
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1085 1086
                              "%s", _("creation of non-raw images "
                                      "is not supported without qemu-img"));
1087 1088 1089
        return -1;
    }

1090
    if (create_func(conn, pool, vol, inputvol, 0) < 0)
1091
        return -1;
1092 1093 1094
    return 0;
}

1095 1096 1097 1098 1099 1100 1101
/**
 * 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,
1102
                                    virStoragePoolObjPtr pool,
1103
                                    virStorageVolDefPtr vol) {
1104
    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL);
1105 1106 1107 1108 1109 1110 1111
}

/*
 * Create a storage vol using 'inputvol' as input
 */
static int
virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
1112
                                        virStoragePoolObjPtr pool,
1113 1114
                                        virStorageVolDefPtr vol,
                                        virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1115 1116 1117 1118
                                        unsigned int flags)
{
    virCheckFlags(0, -1);

1119
    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol);
1120
}
1121 1122 1123 1124 1125

/**
 * Remove a volume - just unlinks for now
 */
static int
1126
virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
1127 1128
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
E
Eric Blake 已提交
1129
                                     unsigned int flags)
1130
{
E
Eric Blake 已提交
1131 1132
    virCheckFlags(0, -1);

1133 1134 1135
    if (unlink(vol->target.path) < 0) {
        /* Silently ignore failures where the vol has already gone away */
        if (errno != ENOENT) {
1136
            virReportSystemError(errno,
1137 1138
                                 _("cannot unlink file '%s'"),
                                 vol->target.path);
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
            return -1;
        }
    }
    return 0;
}


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

1156
    /* Refresh allocation / permissions info in case its changed */
1157 1158
    ret = virStorageBackendUpdateVolInfoFlags(vol, 0,
                                              VIR_STORAGE_VOL_FS_OPEN_FLAGS);
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
    if (ret < 0)
        return ret;

    /* Load any secrets if posible */
    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);
1176
                virReportOOMError();
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
                virSecretFree(sec);
                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);
            virSecretFree(sec);
        }
    }

    return 0;
1191 1192 1193 1194 1195 1196
}

virStorageBackend virStorageBackendDirectory = {
    .type = VIR_STORAGE_POOL_DIR,

    .buildPool = virStorageBackendFileSystemBuild,
1197
    .checkPool = virStorageBackendFileSystemCheck,
1198 1199
    .refreshPool = virStorageBackendFileSystemRefresh,
    .deletePool = virStorageBackendFileSystemDelete,
1200
    .buildVol = virStorageBackendFileSystemVolBuild,
1201
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
};

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

    .buildPool = virStorageBackendFileSystemBuild,
1212
    .checkPool = virStorageBackendFileSystemCheck,
1213 1214 1215 1216
    .startPool = virStorageBackendFileSystemStart,
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1217
    .buildVol = virStorageBackendFileSystemVolBuild,
1218
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1219 1220 1221 1222 1223 1224 1225 1226
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
};
virStorageBackend virStorageBackendNetFileSystem = {
    .type = VIR_STORAGE_POOL_NETFS,

    .buildPool = virStorageBackendFileSystemBuild,
1227
    .checkPool = virStorageBackendFileSystemCheck,
1228
    .startPool = virStorageBackendFileSystemStart,
1229
    .findPoolSources = virStorageBackendFileSystemNetFindPoolSources,
1230 1231 1232
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1233
    .buildVol = virStorageBackendFileSystemVolBuild,
1234
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1235 1236 1237 1238 1239
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
};
#endif /* WITH_STORAGE_FS */