storage_backend.c 61.8 KB
Newer Older
1
/*
2
 * storage_backend.c: internal storage driver backend contract
3
 *
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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <string.h>
27
#include <stdio.h>
28
#include <regex.h>
29
#include <sys/types.h>
E
Eric Blake 已提交
30
#include <sys/wait.h>
31
#include <unistd.h>
32 33
#include <fcntl.h>
#include <sys/stat.h>
34
#include <sys/param.h>
35
#include <dirent.h>
36
#include "dirname.h"
37 38 39
#ifdef __linux__
# include <sys/ioctl.h>
# include <linux/fs.h>
C
Chunyan Liu 已提交
40 41 42
# ifndef FS_NOCOW_FL
#  define FS_NOCOW_FL                     0x00800000 /* Do not cow file */
# endif
43
#endif
44

45
#if WITH_SELINUX
46
# include <selinux/selinux.h>
47
#endif
48

49
#include "datatypes.h"
50
#include "virerror.h"
51
#include "viralloc.h"
52
#include "internal.h"
53
#include "secret_conf.h"
54
#include "viruuid.h"
55
#include "virstoragefile.h"
D
Daniel P. Berrange 已提交
56
#include "storage_backend.h"
57
#include "virlog.h"
E
Eric Blake 已提交
58
#include "virfile.h"
59
#include "stat-time.h"
60
#include "virstring.h"
61
#include "virxml.h"
62
#include "fdstream.h"
63

64
#if WITH_STORAGE_LVM
65
# include "storage_backend_logical.h"
66 67
#endif
#if WITH_STORAGE_ISCSI
68
# include "storage_backend_iscsi.h"
69
#endif
70
#if WITH_STORAGE_SCSI
71
# include "storage_backend_scsi.h"
72
#endif
D
Dave Allan 已提交
73
#if WITH_STORAGE_MPATH
74
# include "storage_backend_mpath.h"
D
Dave Allan 已提交
75
#endif
76
#if WITH_STORAGE_DISK
77
# include "storage_backend_disk.h"
78 79
#endif
#if WITH_STORAGE_DIR
80
# include "storage_backend_fs.h"
81
#endif
82 83 84
#if WITH_STORAGE_RBD
# include "storage_backend_rbd.h"
#endif
85 86 87
#if WITH_STORAGE_SHEEPDOG
# include "storage_backend_sheepdog.h"
#endif
88 89 90
#if WITH_STORAGE_GLUSTER
# include "storage_backend_gluster.h"
#endif
91

92 93
#define VIR_FROM_THIS VIR_FROM_STORAGE

94 95
VIR_LOG_INIT("storage.storage_backend");

96 97 98 99 100 101 102 103 104 105 106 107 108 109
static virStorageBackendPtr backends[] = {
#if WITH_STORAGE_DIR
    &virStorageBackendDirectory,
#endif
#if WITH_STORAGE_FS
    &virStorageBackendFileSystem,
    &virStorageBackendNetFileSystem,
#endif
#if WITH_STORAGE_LVM
    &virStorageBackendLogical,
#endif
#if WITH_STORAGE_ISCSI
    &virStorageBackendISCSI,
#endif
110 111 112
#if WITH_STORAGE_SCSI
    &virStorageBackendSCSI,
#endif
D
Dave Allan 已提交
113 114 115
#if WITH_STORAGE_MPATH
    &virStorageBackendMpath,
#endif
116 117
#if WITH_STORAGE_DISK
    &virStorageBackendDisk,
118 119 120
#endif
#if WITH_STORAGE_RBD
    &virStorageBackendRBD,
121 122 123
#endif
#if WITH_STORAGE_SHEEPDOG
    &virStorageBackendSheepdog,
124 125 126
#endif
#if WITH_STORAGE_GLUSTER
    &virStorageBackendGluster,
127 128 129
#endif
    NULL
};
130

131 132

static virStorageFileBackendPtr fileBackends[] = {
133 134 135
#if WITH_STORAGE_FS
    &virStorageFileBackendFile,
    &virStorageFileBackendBlock,
136 137 138
#endif
#if WITH_STORAGE_GLUSTER
    &virStorageFileBackendGluster,
139
#endif
140 141 142 143
    NULL
};


144 145 146 147 148 149
enum {
    TOOL_QEMU_IMG,
    TOOL_KVM_IMG,
    TOOL_QCOW_CREATE,
};

150 151 152
#define READ_BLOCK_SIZE_DEFAULT  (1024 * 1024)
#define WRITE_BLOCK_SIZE_DEFAULT (4 * 1024)

153
static int ATTRIBUTE_NONNULL(2)
154
virStorageBackendCopyToFD(virStorageVolDefPtr vol,
155 156
                          virStorageVolDefPtr inputvol,
                          int fd,
157
                          unsigned long long *total,
J
Ján Tomko 已提交
158
                          bool want_sparse)
159 160 161
{
    int inputfd = -1;
    int amtread = -1;
162
    int ret = 0;
163
    size_t rbytes = READ_BLOCK_SIZE_DEFAULT;
L
Li Zhang 已提交
164
    int wbytes = 0;
165
    int interval;
166
    char *zerobuf = NULL;
167
    char *buf = NULL;
168
    struct stat st;
169

170
    if ((inputfd = open(inputvol->target.path, O_RDONLY)) < 0) {
171
        ret = -errno;
172
        virReportSystemError(errno,
173 174 175
                             _("could not open input path '%s'"),
                             inputvol->target.path);
        goto cleanup;
176 177
    }

178 179 180 181 182 183 184 185 186 187 188 189 190 191
#ifdef __linux__
    if (ioctl(fd, BLKBSZGET, &wbytes) < 0) {
        wbytes = 0;
    }
#endif
    if ((wbytes == 0) && fstat(fd, &st) == 0)
        wbytes = st.st_blksize;
    if (wbytes < WRITE_BLOCK_SIZE_DEFAULT)
        wbytes = WRITE_BLOCK_SIZE_DEFAULT;

    if (VIR_ALLOC_N(zerobuf, wbytes) < 0) {
        ret = -errno;
        goto cleanup;
    }
192

193
    if (VIR_ALLOC_N(buf, rbytes) < 0) {
194
        ret = -errno;
195 196 197 198 199 200
        goto cleanup;
    }

    while (amtread != 0) {
        int amtleft;

201 202
        if (*total < rbytes)
            rbytes = *total;
203

204
        if ((amtread = saferead(inputfd, buf, rbytes)) < 0) {
205
            ret = -errno;
206
            virReportSystemError(errno,
207 208 209 210
                                 _("failed reading from file '%s'"),
                                 inputvol->target.path);
            goto cleanup;
        }
211
        *total -= amtread;
212 213 214 215 216

        /* Loop over amt read in 512 byte increments, looking for sparse
         * blocks */
        amtleft = amtread;
        do {
217
            interval = ((wbytes > amtleft) ? amtleft : wbytes);
218 219
            int offset = amtread - amtleft;

220
            if (want_sparse && memcmp(buf+offset, zerobuf, interval) == 0) {
221
                if (lseek(fd, interval, SEEK_CUR) < 0) {
222
                    ret = -errno;
223
                    virReportSystemError(errno,
224 225 226 227 228
                                         _("cannot extend file '%s'"),
                                         vol->target.path);
                    goto cleanup;
                }
            } else if (safewrite(fd, buf+offset, interval) < 0) {
229
                ret = -errno;
230
                virReportSystemError(errno,
231 232 233 234 235
                                     _("failed writing to file '%s'"),
                                     vol->target.path);
                goto cleanup;

            }
236
        } while ((amtleft -= interval) > 0);
237 238
    }

239 240 241 242 243 244 245 246
    if (fdatasync(fd) < 0) {
        ret = -errno;
        virReportSystemError(errno, _("cannot sync data to file '%s'"),
                             vol->target.path);
        goto cleanup;
    }


247
    if (VIR_CLOSE(inputfd) < 0) {
248
        ret = -errno;
249
        virReportSystemError(errno,
250 251 252 253 254 255
                             _("cannot close file '%s'"),
                             inputvol->target.path);
        goto cleanup;
    }
    inputfd = -1;

256
 cleanup:
257
    VIR_FORCE_CLOSE(inputfd);
258

259
    VIR_FREE(zerobuf);
260 261
    VIR_FREE(buf);

262 263 264
    return ret;
}

265
static int
266
virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
267
                                 virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
268 269
                                 virStorageVolDefPtr vol,
                                 virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
270
                                 unsigned int flags)
271 272 273 274
{
    int fd = -1;
    int ret = -1;
    unsigned long long remain;
275 276 277
    struct stat st;
    gid_t gid;
    uid_t uid;
278

279 280 281 282 283 284 285 286
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);

    if (flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("metadata preallocation is not supported for block "
                         "volumes"));
        goto cleanup;
    }
E
Eric Blake 已提交
287

288
    if ((fd = open(vol->target.path, O_RDWR)) < 0) {
289
        virReportSystemError(errno,
290 291 292 293 294
                             _("cannot create path '%s'"),
                             vol->target.path);
        goto cleanup;
    }

295
    remain = vol->target.allocation;
296 297

    if (inputvol) {
298
        int res = virStorageBackendCopyToFD(vol, inputvol,
J
Ján Tomko 已提交
299
                                            fd, &remain, false);
300 301 302 303
        if (res < 0)
            goto cleanup;
    }

304
    if (fstat(fd, &st) == -1) {
305
        virReportSystemError(errno, _("stat of '%s' failed"),
306 307 308
                             vol->target.path);
        goto cleanup;
    }
309 310 311 312
    uid = (vol->target.perms->uid != st.st_uid) ? vol->target.perms->uid
        : (uid_t) -1;
    gid = (vol->target.perms->gid != st.st_gid) ? vol->target.perms->gid
        : (gid_t) -1;
P
Philipp Hahn 已提交
313
    if (((uid != (uid_t) -1) || (gid != (gid_t) -1))
314
        && (fchown(fd, uid, gid) < 0)) {
315
        virReportSystemError(errno,
316
                             _("cannot chown '%s' to (%u, %u)"),
317 318
                             vol->target.path, (unsigned int) uid,
                             (unsigned int) gid);
319 320
        goto cleanup;
    }
321
    if (fchmod(fd, vol->target.perms->mode) < 0) {
322
        virReportSystemError(errno,
323
                             _("cannot set mode of '%s' to %04o"),
324
                             vol->target.path, vol->target.perms->mode);
325 326
        goto cleanup;
    }
327
    if (VIR_CLOSE(fd) < 0) {
328
        virReportSystemError(errno,
329 330 331 332 333 334 335
                             _("cannot close file '%s'"),
                             vol->target.path);
        goto cleanup;
    }
    fd = -1;

    ret = 0;
336
 cleanup:
337
    VIR_FORCE_CLOSE(fd);
338 339 340 341

    return ret;
}

E
Eric Blake 已提交
342 343 344 345
static int
createRawFile(int fd, virStorageVolDefPtr vol,
              virStorageVolDefPtr inputvol)
{
J
Ján Tomko 已提交
346
    bool need_alloc = true;
347 348
    int ret = 0;
    unsigned long long remain;
349

350 351
    /* Seek to the final size, so the capacity is available upfront
     * for progress reporting */
352
    if (ftruncate(fd, vol->target.capacity) < 0) {
353
        ret = -errno;
354
        virReportSystemError(errno,
355
                             _("cannot extend file '%s'"),
E
Eric Blake 已提交
356
                             vol->target.path);
357 358 359
        goto cleanup;
    }

E
Eric Blake 已提交
360 361
/* Avoid issues with older kernel's <linux/fs.h> namespace pollution. */
#if HAVE_FALLOCATE - 0
362
    /* Try to preallocate all requested disk space, but fall back to
363 364
     * other methods if this fails with ENOSYS or EOPNOTSUPP. If allocation
     * is 0 (or less than 0), then fallocate will fail with EINVAL.
365 366 367 368
     * NOTE: do not use posix_fallocate; posix_fallocate falls back
     * to writing zeroes block by block in case fallocate isn't
     * available, and since we're going to copy data from another
     * file it doesn't make sense to write the file twice. */
369 370
    if (vol->target.allocation) {
        if (fallocate(fd, 0, 0, vol->target.allocation) == 0) {
371 372 373 374 375
            need_alloc = false;
        } else if (errno != ENOSYS && errno != EOPNOTSUPP) {
            ret = -errno;
            virReportSystemError(errno,
                                 _("cannot allocate %llu bytes in file '%s'"),
376
                                 vol->target.allocation, vol->target.path);
377 378
            goto cleanup;
        }
379 380 381
    }
#endif

382
    remain = vol->target.allocation;
383

E
Eric Blake 已提交
384
    if (inputvol) {
385 386 387
        /* allow zero blocks to be skipped if we've requested sparse
         * allocation (allocation < capacity) or we have already
         * been able to allocate the required space. */
J
Ján Tomko 已提交
388
        bool want_sparse = !need_alloc ||
389
            (vol->target.allocation < inputvol->target.capacity);
390 391

        ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain, want_sparse);
392
        if (ret < 0) {
393
            goto cleanup;
394
        }
395 396
    }

397
    if (remain && need_alloc) {
398
        if (safezero(fd, vol->target.allocation - remain, remain) < 0) {
399 400 401 402
            ret = -errno;
            virReportSystemError(errno, _("cannot fill file '%s'"),
                                 vol->target.path);
            goto cleanup;
403
        }
404 405 406
    }

    if (fsync(fd) < 0) {
407
        ret = -errno;
408
        virReportSystemError(errno, _("cannot sync data to file '%s'"),
E
Eric Blake 已提交
409
                             vol->target.path);
410
        goto cleanup;
411 412
    }

413
 cleanup:
414 415 416 417 418 419 420 421
    return ret;
}

int
virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
                           virStoragePoolObjPtr pool,
                           virStorageVolDefPtr vol,
                           virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
422
                           unsigned int flags)
423 424
{
    int ret = -1;
E
Eric Blake 已提交
425 426 427
    int fd = -1;
    int operation_flags;

428 429 430 431 432 433 434 435
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);

    if (flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("metadata preallocation is not supported for raw "
                         "volumes"));
        goto cleanup;
    }
436 437

    if (vol->target.encryption != NULL) {
438 439
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("storage pool does not support encrypted volumes"));
440 441
        goto cleanup;
    }
442

L
Laine Stump 已提交
443
    operation_flags = VIR_FILE_OPEN_FORCE_MODE | VIR_FILE_OPEN_FORCE_OWNER;
E
Eric Blake 已提交
444
    if (pool->def->type == VIR_STORAGE_POOL_NETFS)
L
Laine Stump 已提交
445
        operation_flags |= VIR_FILE_OPEN_FORK;
E
Eric Blake 已提交
446

447 448
    if ((fd = virFileOpenAs(vol->target.path,
                            O_RDWR | O_CREAT | O_EXCL,
449 450 451
                            vol->target.perms->mode,
                            vol->target.perms->uid,
                            vol->target.perms->gid,
452
                            operation_flags)) < 0) {
E
Eric Blake 已提交
453
        virReportSystemError(-fd,
454
                             _("Failed to create file '%s'"),
E
Eric Blake 已提交
455 456 457 458
                             vol->target.path);
        goto cleanup;
    }

C
Chunyan Liu 已提交
459 460 461 462 463 464
    if (vol->target.nocow) {
#ifdef __linux__
        int attr;

        /* Set NOCOW flag. This is an optimisation for btrfs.
         * The FS_IOC_SETFLAGS ioctl return value will be ignored since any
465
         * failure of this operation should not block the volume creation.
C
Chunyan Liu 已提交
466
         */
467 468 469
        if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0) {
            virReportSystemError(errno, "%s", _("Failed to get fs flags"));
        } else {
C
Chunyan Liu 已提交
470
            attr |= FS_NOCOW_FL;
471 472 473 474
            if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0) {
                virReportSystemError(errno, "%s",
                                     _("Failed to set NOCOW flag"));
            }
C
Chunyan Liu 已提交
475 476 477 478
        }
#endif
    }

479 480
    if ((ret = createRawFile(fd, vol, inputvol)) < 0)
        /* createRawFile already reported the exact error. */
E
Eric Blake 已提交
481
        ret = -1;
482

483
 cleanup:
E
Eric Blake 已提交
484
    VIR_FORCE_CLOSE(fd);
485 486 487
    return ret;
}

488 489 490 491 492 493 494 495 496
static int
virStorageGenerateSecretUUID(virConnectPtr conn,
                             unsigned char *uuid)
{
    unsigned attempt;

    for (attempt = 0; attempt < 65536; attempt++) {
        virSecretPtr tmp;
        if (virUUIDGenerate(uuid) < 0) {
497 498
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unable to generate uuid"));
499 500
            return -1;
        }
501
        tmp = conn->secretDriver->secretLookupByUUID(conn, uuid);
502 503 504 505 506 507
        if (tmp == NULL)
            return 0;

        virSecretFree(tmp);
    }

508
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
N
Nehal J Wani 已提交
509
                   _("too many conflicts when generating a uuid"));
510 511 512 513

    return -1;
}

514 515 516 517 518 519 520 521 522
static int
virStorageGenerateQcowEncryption(virConnectPtr conn,
                                 virStorageVolDefPtr vol)
{
    virSecretDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    virStorageEncryptionPtr enc;
    virStorageEncryptionSecretPtr enc_secret = NULL;
    virSecretPtr secret = NULL;
523
    char *xml;
524 525 526
    unsigned char value[VIR_STORAGE_QCOW_PASSPHRASE_SIZE];
    int ret = -1;

527
    if (conn->secretDriver == NULL ||
528 529 530
        conn->secretDriver->secretLookupByUUID == NULL ||
        conn->secretDriver->secretDefineXML == NULL ||
        conn->secretDriver->secretSetValue == NULL) {
531 532
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("secret storage not supported"));
533 534 535 536 537
        goto cleanup;
    }

    enc = vol->target.encryption;
    if (enc->nsecrets != 0) {
538 539
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("secrets already defined"));
540 541 542 543
        goto cleanup;
    }

    if (VIR_ALLOC(enc_secret) < 0 || VIR_REALLOC_N(enc->secrets, 1) < 0 ||
544
        VIR_ALLOC(def) < 0)
545 546
        goto cleanup;

547
    def->ephemeral = false;
548
    def->private = false;
549
    if (virStorageGenerateSecretUUID(conn, def->uuid) < 0)
550
        goto cleanup;
551

552
    def->usage_type = VIR_SECRET_USAGE_TYPE_VOLUME;
553
    if (VIR_STRDUP(def->usage.volume, vol->target.path) < 0)
554
        goto cleanup;
555
    xml = virSecretDefFormat(def);
556 557 558 559 560
    virSecretDefFree(def);
    def = NULL;
    if (xml == NULL)
        goto cleanup;

561
    secret = conn->secretDriver->secretDefineXML(conn, xml, 0);
562 563 564 565 566 567
    if (secret == NULL) {
        VIR_FREE(xml);
        goto cleanup;
    }
    VIR_FREE(xml);

568
    if (virStorageGenerateQcowPassphrase(value) < 0)
569 570
        goto cleanup;

571
    if (conn->secretDriver->secretSetValue(secret, value, sizeof(value), 0) < 0)
572 573 574
        goto cleanup;

    enc_secret->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
575
    memcpy(enc_secret->uuid, secret->uuid, VIR_UUID_BUFLEN);
576 577 578 579 580 581 582
    enc->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
    enc->secrets[0] = enc_secret; /* Space for secrets[0] allocated above */
    enc_secret = NULL;
    enc->nsecrets = 1;

    ret = 0;

583
 cleanup:
584
    if (secret != NULL) {
585
        if (ret != 0 &&
586 587
            conn->secretDriver->secretUndefine != NULL)
            conn->secretDriver->secretUndefine(secret);
588 589
        virSecretFree(secret);
    }
590
    virBufferFreeAndReset(&buf);
591 592 593 594 595
    virSecretDefFree(def);
    VIR_FREE(enc_secret);
    return ret;
}

596 597 598 599 600
static int
virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
                                   virStorageVolDefPtr vol,
                                   virCommandPtr cmd)
{
601 602 603
    struct stat st;
    gid_t gid;
    uid_t uid;
604
    bool filecreated = false;
605 606

    if ((pool->def->type == VIR_STORAGE_POOL_NETFS)
607
        && (((geteuid() == 0)
608 609 610 611
             && (vol->target.perms->uid != (uid_t) -1)
             && (vol->target.perms->uid != 0))
            || ((vol->target.perms->gid != (gid_t) -1)
                && (vol->target.perms->gid != getegid())))) {
612

613 614
        virCommandSetUID(cmd, vol->target.perms->uid);
        virCommandSetGID(cmd, vol->target.perms->gid);
615 616

        if (virCommandRun(cmd, NULL) == 0) {
617 618
            /* command was successfully run, check if the file was created */
            if (stat(vol->target.path, &st) >=0)
619
                filecreated = true;
620 621
        }
    }
622

623 624 625
    /* don't change uid/gid if we retry */
    virCommandSetUID(cmd, -1);
    virCommandSetGID(cmd, -1);
626

627
    if (!filecreated) {
628
        if (virCommandRun(cmd, NULL) < 0) {
629 630 631
            return -1;
        }
        if (stat(vol->target.path, &st) < 0) {
632
            virReportSystemError(errno,
633
                                 _("failed to create %s"), vol->target.path);
634 635 636 637
            return -1;
        }
    }

638 639 640 641
    uid = (vol->target.perms->uid != st.st_uid) ? vol->target.perms->uid
        : (uid_t) -1;
    gid = (vol->target.perms->gid != st.st_gid) ? vol->target.perms->gid
        : (gid_t) -1;
P
Philipp Hahn 已提交
642
    if (((uid != (uid_t) -1) || (gid != (gid_t) -1))
643
        && (chown(vol->target.path, uid, gid) < 0)) {
644
        virReportSystemError(errno,
645
                             _("cannot chown %s to (%u, %u)"),
646 647
                             vol->target.path, (unsigned int) uid,
                             (unsigned int) gid);
648 649
        return -1;
    }
650
    if (chmod(vol->target.path, vol->target.perms->mode) < 0) {
651
        virReportSystemError(errno,
652
                             _("cannot set mode of '%s' to %04o"),
653
                             vol->target.path, vol->target.perms->mode);
654 655 656 657 658
        return -1;
    }
    return 0;
}

659 660 661 662
enum {
    QEMU_IMG_BACKING_FORMAT_NONE = 0,
    QEMU_IMG_BACKING_FORMAT_FLAG,
    QEMU_IMG_BACKING_FORMAT_OPTIONS,
663
    QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT,
664 665
};

666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
static bool
virStorageBackendQemuImgSupportsCompat(const char *qemuimg)
{
    bool ret = false;
    char *output;
    virCommandPtr cmd = NULL;

    cmd = virCommandNewArgList(qemuimg, "create", "-o", "?", "-f", "qcow2",
                               "/dev/null", NULL);

    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &output);

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

    if (strstr(output, "\ncompat "))
        ret = true;

685
 cleanup:
686 687 688 689 690
    virCommandFree(cmd);
    VIR_FREE(output);
    return ret;
}

691 692
static int
virStorageBackendQEMUImgBackingFormat(const char *qemuimg)
693 694 695 696 697 698
{
    char *help = NULL;
    char *start;
    char *end;
    char *tmp;
    int ret = -1;
699
    int exitstatus;
700
    virCommandPtr cmd = virCommandNewArgList(qemuimg, "-h", NULL);
701

702 703 704
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &help);
    virCommandClearCaps(cmd);
705

706 707 708
    /* qemuimg doesn't return zero exit status on -h,
     * therefore we need to provide pointer for storing
     * exit status, although we don't parse it any later */
709
    if (virCommandRun(cmd, &exitstatus) < 0)
710 711
        goto cleanup;

712 713
    if ((start = strstr(help, " create ")) == NULL ||
        (end = strstr(start, "\n")) == NULL) {
714 715 716
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unable to parse qemu-img output '%s'"),
                       help);
717 718
        goto cleanup;
    }
719
    if (((tmp = strstr(start, "-F fmt")) && tmp < end) ||
720
        ((tmp = strstr(start, "-F backing_fmt")) && tmp < end)) {
721
        ret = QEMU_IMG_BACKING_FORMAT_FLAG;
722 723 724 725 726 727
    } else if ((tmp = strstr(start, "[-o options]")) && tmp < end) {
        if (virStorageBackendQemuImgSupportsCompat(qemuimg))
            ret = QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT;
        else
            ret = QEMU_IMG_BACKING_FORMAT_OPTIONS;
    } else {
728
        ret = QEMU_IMG_BACKING_FORMAT_NONE;
729
    }
730

731
 cleanup:
732
    virCommandFree(cmd);
733 734 735 736
    VIR_FREE(help);
    return ret;
}

737 738 739 740
static int
virStorageBackendCreateQemuImgOpts(char **opts,
                                   const char *backingType,
                                   bool encryption,
741 742 743
                                   bool preallocate,
                                   int format,
                                   const char *compat,
C
Chunyan Liu 已提交
744
                                   bool nocow,
745
                                   virBitmapPtr features)
746 747
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
748
    bool b;
749
    size_t i;
750

751 752 753 754 755 756
    if (backingType)
        virBufferAsprintf(&buf, "backing_fmt=%s,", backingType);
    if (encryption)
        virBufferAddLit(&buf, "encryption=on,");
    if (preallocate)
        virBufferAddLit(&buf, "preallocation=metadata,");
C
Chunyan Liu 已提交
757 758
    if (nocow)
        virBufferAddLit(&buf, "nocow=on,");
759

760 761 762 763 764 765
    if (compat)
        virBufferAsprintf(&buf, "compat=%s,", compat);
    if (features && format == VIR_STORAGE_FILE_QCOW2) {
        for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
            ignore_value(virBitmapGetBit(features, i, &b));
            if (b) {
766
                switch ((virStorageFileFeature) i) {
767 768 769 770 771 772 773 774 775 776
                case VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS:
                    if (STREQ_NULLABLE(compat, "0.10")) {
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("Feature %s not supported with compat"
                                         " level %s"),
                                       virStorageFileFeatureTypeToString(i),
                                       compat);
                        goto error;
                    }
                    break;
777

778
                /* coverity[dead_error_begin] */
779 780 781 782 783 784 785 786 787
                case VIR_STORAGE_FILE_FEATURE_LAST:
                    ;
                }
                virBufferAsprintf(&buf, "%s,",
                                  virStorageFileFeatureTypeToString(i));
            }
        }
    }

788 789
    virBufferTrim(&buf, ",", -1);

790 791
    if (virBufferCheckError(&buf) < 0)
        goto error;
792 793 794

    *opts = virBufferContentAndReset(&buf);
    return 0;
795

796
 error:
797 798
    virBufferFreeAndReset(&buf);
    return -1;
799 800
}

801 802 803 804 805 806 807 808
virCommandPtr
virStorageBackendCreateQemuImgCmd(virConnectPtr conn,
                                  virStoragePoolObjPtr pool,
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags,
                                  const char *create_tool,
                                  int imgformat)
809
{
810 811
    virCommandPtr cmd = NULL;
    bool do_encryption = (vol->target.encryption != NULL);
812
    unsigned long long int size_arg;
813 814 815 816 817
    bool preallocate = !!(flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA);
    const char *type;
    const char *backingType = NULL;
    const char *inputPath = NULL;
    const char *inputType = NULL;
818
    const char *compat = vol->target.compat;
819 820 821
    char *opts = NULL;
    bool convert = false;
    bool backing = false;
822

823 824
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, NULL);

825 826 827 828
    /* Treat output block devices as 'raw' format */
    type = virStorageFileFormatTypeToString(vol->type == VIR_STORAGE_VOL_BLOCK ?
                                            VIR_STORAGE_FILE_RAW :
                                            vol->target.format);
829

830
    if (!type) {
831 832 833
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown storage vol type %d"),
                       vol->target.format);
834
        return NULL;
835
    }
836

837 838 839
    if (preallocate && vol->target.format != VIR_STORAGE_FILE_QCOW2) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("metadata preallocation only available with qcow2"));
840
        return NULL;
841
    }
842 843 844 845 846 847 848 849 850 851
    if (vol->target.compat && vol->target.format != VIR_STORAGE_FILE_QCOW2) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("compatibility option only available with qcow2"));
        return NULL;
    }
    if (vol->target.features && vol->target.format != VIR_STORAGE_FILE_QCOW2) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("format features only available with qcow2"));
        return NULL;
    }
852

853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
    if (inputvol) {
        if (!(inputPath = inputvol->target.path)) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("missing input volume target path"));
            return NULL;
        }

        inputType = virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ?
                                                     VIR_STORAGE_FILE_RAW :
                                                     inputvol->target.format);

        if (!inputType) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage vol type %d"),
                           inputvol->target.format);
            return NULL;
        }

    }

873
    if (vol->target.backingStore) {
874 875
        int accessRetCode = -1;
        char *absolutePath = NULL;
876

877
        backingType = virStorageFileFormatTypeToString(vol->target.backingStore->format);
878

879 880 881 882
        if (preallocate) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("metadata preallocation conflicts with backing"
                             " store"));
883
            return NULL;
884 885
        }

886 887 888 889 890
        /* XXX: Not strictly required: qemu-img has an option a different
         * backing store, not really sure what use it serves though, and it
         * may cause issues with lvm. Untested essentially.
         */
        if (inputvol &&
891 892
            STRNEQ_NULLABLE(inputvol->target.backingStore->path,
                            vol->target.backingStore->path)) {
893 894
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("a different backing store cannot be specified."));
895
            return NULL;
896 897 898
        }

        if (backingType == NULL) {
899 900
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage vol backing store type %d"),
901
                           vol->target.backingStore->format);
902
            return NULL;
903
        }
904 905 906 907

        /* Convert relative backing store paths to absolute paths for access
         * validation.
         */
908
        if ('/' != *(vol->target.backingStore->path) &&
909
            virAsprintf(&absolutePath, "%s/%s", pool->def->target.path,
910
                        vol->target.backingStore->path) < 0)
911
            return NULL;
912
        accessRetCode = access(absolutePath ? absolutePath
913
                               : vol->target.backingStore->path, R_OK);
914 915
        VIR_FREE(absolutePath);
        if (accessRetCode != 0) {
916
            virReportSystemError(errno,
917
                                 _("inaccessible backing store volume %s"),
918
                                 vol->target.backingStore->path);
919
            return NULL;
920 921 922
        }
    }

923
    if (do_encryption) {
924 925
        virStorageEncryptionPtr enc;

926 927
        if (vol->target.format != VIR_STORAGE_FILE_QCOW &&
            vol->target.format != VIR_STORAGE_FILE_QCOW2) {
928 929 930
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("qcow volume encryption unsupported with "
                             "volume format %s"), type);
931
            return NULL;
932
        }
933 934 935
        enc = vol->target.encryption;
        if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW &&
            enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT) {
936 937 938
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unsupported volume encryption format %d"),
                           vol->target.encryption->format);
939
            return NULL;
940
        }
941
        if (enc->nsecrets > 1) {
942 943
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("too many secrets for qcow encryption"));
944
            return NULL;
945
        }
946 947 948
        if (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT ||
            enc->nsecrets == 0) {
            if (virStorageGenerateQcowEncryption(conn, vol) < 0)
949
                return NULL;
950
        }
951 952
    }

953
    /* Size in KB */
954
    size_arg = VIR_DIV_UP(vol->target.capacity, 1024);
955

956 957
    cmd = virCommandNew(create_tool);

958
    convert = !!inputvol;
959
    backing = !inputvol && vol->target.backingStore;
960

961 962 963
    if (convert)
        virCommandAddArgList(cmd, "convert", "-f", inputType, "-O", type, NULL);
    else
964
        virCommandAddArgList(cmd, "create", "-f", type, NULL);
965

966
    if (backing)
967
        virCommandAddArgList(cmd, "-b", vol->target.backingStore->path, NULL);
968

969 970 971 972 973
    if (imgformat >= QEMU_IMG_BACKING_FORMAT_OPTIONS) {
        if (vol->target.format == VIR_STORAGE_FILE_QCOW2 && !compat &&
            imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT)
            compat = "0.10";

974 975
        if (virStorageBackendCreateQemuImgOpts(&opts,
                                               backing ? backingType : NULL,
976 977
                                               do_encryption, preallocate,
                                               vol->target.format,
978
                                               compat,
C
Chunyan Liu 已提交
979
                                               vol->target.nocow,
980 981
                                               vol->target.features) < 0) {
            virCommandFree(cmd);
982
            return NULL;
983
        }
984 985 986 987 988 989 990 991 992 993
        if (opts)
            virCommandAddArgList(cmd, "-o", opts, NULL);
        VIR_FREE(opts);
    } else {
        if (backing) {
            if (imgformat == QEMU_IMG_BACKING_FORMAT_FLAG)
                virCommandAddArgList(cmd, "-F", backingType, NULL);
            else
                VIR_DEBUG("Unable to set backing store format for %s with %s",
                          vol->target.path, create_tool);
994
        }
995 996
        if (do_encryption)
            virCommandAddArg(cmd, "-e");
997
    }
998

999 1000 1001 1002 1003 1004
    if (convert)
        virCommandAddArg(cmd, inputPath);
    virCommandAddArg(cmd, vol->target.path);
    if (!convert)
        virCommandAddArgFormat(cmd, "%lluK", size_arg);

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
    return cmd;
}

static int
virStorageBackendCreateQemuImg(virConnectPtr conn,
                               virStoragePoolObjPtr pool,
                               virStorageVolDefPtr vol,
                               virStorageVolDefPtr inputvol,
                               unsigned int flags)
{
    int ret = -1;
1016
    char *create_tool;
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
    int imgformat;
    virCommandPtr cmd;

    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);

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

    if (!create_tool) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to find kvm-img or qemu-img"));
        return -1;
    }

    imgformat = virStorageBackendQEMUImgBackingFormat(create_tool);
    if (imgformat < 0)
        goto cleanup;

    cmd = virStorageBackendCreateQemuImgCmd(conn, pool, vol, inputvol, flags,
                                            create_tool, imgformat);
    if (!cmd)
        goto cleanup;

1042
    ret = virStorageBackendCreateExecCommand(pool, vol, cmd);
1043 1044

    virCommandFree(cmd);
1045
 cleanup:
1046
    VIR_FREE(create_tool);
1047
    return ret;
1048 1049 1050 1051 1052 1053 1054
}

/*
 * Xen removed the fully-functional qemu-img, and replaced it
 * with a partially functional qcow-create. Go figure ??!?
 */
static int
1055
virStorageBackendCreateQcowCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
1056
                                  virStoragePoolObjPtr pool,
1057
                                  virStorageVolDefPtr vol,
1058
                                  virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1059
                                  unsigned int flags)
1060
{
1061
    int ret;
E
Eric Blake 已提交
1062
    char *size;
1063
    virCommandPtr cmd;
1064

1065 1066 1067 1068 1069 1070 1071 1072
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);

    if (flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("metadata preallocation is not supported with "
                         "qcow-create"));
        return -1;
    }
E
Eric Blake 已提交
1073

1074
    if (inputvol) {
1075 1076
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot copy from volume with qcow-create"));
1077 1078 1079
        return -1;
    }

1080
    if (vol->target.format != VIR_STORAGE_FILE_QCOW2) {
1081 1082 1083
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported storage vol type %d"),
                       vol->target.format);
1084 1085
        return -1;
    }
1086
    if (vol->target.backingStore != NULL) {
1087 1088 1089
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("copy-on-write image not supported with "
                         "qcow-create"));
1090 1091
        return -1;
    }
1092
    if (vol->target.encryption != NULL) {
1093 1094 1095
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("encrypted volumes not supported with "
                               "qcow-create"));
1096 1097
        return -1;
    }
1098 1099

    /* Size in MB - yes different units to qemu-img :-( */
1100
    if (virAsprintf(&size, "%llu",
1101
                    VIR_DIV_UP(vol->target.capacity, (1024 * 1024))) < 0)
E
Eric Blake 已提交
1102
        return -1;
1103

1104
    cmd = virCommandNewArgList("qcow-create", size, vol->target.path, NULL);
1105

1106 1107
    ret = virStorageBackendCreateExecCommand(pool, vol, cmd);
    virCommandFree(cmd);
E
Eric Blake 已提交
1108
    VIR_FREE(size);
1109

1110
    return ret;
1111 1112
}

1113
virStorageBackendBuildVolFrom
1114
virStorageBackendFSImageToolTypeToFunc(int tool_type)
1115 1116 1117 1118 1119 1120 1121 1122
{
    switch (tool_type) {
    case TOOL_KVM_IMG:
    case TOOL_QEMU_IMG:
        return virStorageBackendCreateQemuImg;
    case TOOL_QCOW_CREATE:
        return virStorageBackendCreateQcowCreate;
    default:
1123 1124 1125
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown file create tool type '%d'."),
                       tool_type);
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
    }

    return NULL;
}

int
virStorageBackendFindFSImageTool(char **tool)
{
    int tool_type = -1;
    char *tmp = NULL;

    if ((tmp = virFindFileInPath("kvm-img")) != NULL) {
        tool_type = TOOL_KVM_IMG;
    } else if ((tmp = virFindFileInPath("qemu-img")) != NULL) {
        tool_type = TOOL_QEMU_IMG;
    } else if ((tmp = virFindFileInPath("qcow-create")) != NULL) {
        tool_type = TOOL_QCOW_CREATE;
    }

    if (tool)
        *tool = tmp;
    else
        VIR_FREE(tmp);

    return tool_type;
}

1153
virStorageBackendBuildVolFrom
1154
virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol,
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
                                         virStorageVolDefPtr inputvol)
{
    int tool_type;

    if (!inputvol)
        return NULL;

    /* If either volume is a non-raw file vol, we need to use an external
     * tool for converting
     */
    if ((vol->type == VIR_STORAGE_VOL_FILE &&
1166
         vol->target.format != VIR_STORAGE_FILE_RAW) ||
1167
        (inputvol->type == VIR_STORAGE_VOL_FILE &&
1168
         inputvol->target.format != VIR_STORAGE_FILE_RAW)) {
1169

D
Daniel P. Berrange 已提交
1170
        if ((tool_type = virStorageBackendFindFSImageTool(NULL)) < 0) {
1171 1172 1173
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("creation of non-raw file images is "
                             "not supported without qemu-img."));
1174 1175 1176
            return NULL;
        }

1177
        return virStorageBackendFSImageToolTypeToFunc(tool_type);
1178 1179
    }

1180 1181 1182 1183
    if (vol->type == VIR_STORAGE_VOL_BLOCK)
        return virStorageBackendCreateBlockFrom;
    else
        return virStorageBackendCreateRaw;
1184
}
1185

1186

1187
virStorageBackendPtr
1188 1189
virStorageBackendForType(int type)
{
1190
    size_t i;
1191
    for (i = 0; backends[i]; i++)
1192 1193 1194
        if (backends[i]->type == type)
            return backends[i];

1195
    virReportError(VIR_ERR_INTERNAL_ERROR,
1196 1197
                   _("missing backend for pool type %d (%s)"),
                   type, NULLSTR(virStoragePoolTypeToString(type)));
1198 1199 1200 1201
    return NULL;
}


1202
virStorageFileBackendPtr
1203 1204 1205
virStorageFileBackendForTypeInternal(int type,
                                     int protocol,
                                     bool report)
1206 1207 1208 1209 1210
{
    size_t i;

    for (i = 0; fileBackends[i]; i++) {
        if (fileBackends[i]->type == type) {
E
Eric Blake 已提交
1211
            if (type == VIR_STORAGE_TYPE_NETWORK &&
1212 1213 1214 1215 1216 1217 1218
                fileBackends[i]->protocol != protocol)
                continue;

            return fileBackends[i];
        }
    }

1219 1220 1221
    if (!report)
        return NULL;

E
Eric Blake 已提交
1222
    if (type == VIR_STORAGE_TYPE_NETWORK) {
1223 1224 1225
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing storage backend for network files "
                         "using %s protocol"),
1226
                       virStorageNetProtocolTypeToString(protocol));
1227 1228 1229
    } else {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing storage backend for '%s' storage"),
E
Eric Blake 已提交
1230
                       virStorageTypeToString(type));
1231 1232 1233 1234 1235 1236
    }

    return NULL;
}


1237 1238 1239 1240 1241 1242 1243 1244
virStorageFileBackendPtr
virStorageFileBackendForType(int type,
                             int protocol)
{
    return virStorageFileBackendForTypeInternal(type, protocol, true);
}


1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
struct diskType {
    int part_table_type;
    unsigned short offset;
    unsigned short length;
    unsigned long long magic;
};


static struct diskType const disk_types[] = {
    { VIR_STORAGE_POOL_DISK_LVM2, 0x218, 8, 0x31303020324D564CULL },
    { VIR_STORAGE_POOL_DISK_GPT,  0x200, 8, 0x5452415020494645ULL },
    { VIR_STORAGE_POOL_DISK_DVH,  0x0,   4, 0x41A9E50BULL },
    { VIR_STORAGE_POOL_DISK_MAC,  0x0,   2, 0x5245ULL },
    { VIR_STORAGE_POOL_DISK_BSD,  0x40,  4, 0x82564557ULL },
    { VIR_STORAGE_POOL_DISK_SUN,  0x1fc, 2, 0xBEDAULL },
    /*
     * NOTE: pc98 is funky; the actual signature is 0x55AA (just like dos), so
     * we can't use that.  At the moment I'm relying on the "dummy" IPL
     * bootloader data that comes from parted.  Luckily, the chances of running
     * into a pc98 machine running libvirt are approximately nil.
     */
    /*{ 0x1fe, 2, 0xAA55UL },*/
    { VIR_STORAGE_POOL_DISK_PC98, 0x0,   8, 0x314C5049000000CBULL },
    /*
     * NOTE: the order is important here; some other disk types (like GPT and
     * and PC98) also have 0x55AA at this offset.  For that reason, the DOS
     * one must be the last one.
     */
    { VIR_STORAGE_POOL_DISK_DOS,  0x1fe, 2, 0xAA55ULL },
    { -1,                         0x0,   0, 0x0ULL },
};


static int
1279
virStorageBackendDetectBlockVolFormatFD(virStorageSourcePtr target,
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
                                        int fd)
{
    size_t i;
    off_t start;
    unsigned char buffer[1024];
    ssize_t bytes;

    /* make sure to set the target format "unknown" to begin with */
    target->format = VIR_STORAGE_POOL_DISK_UNKNOWN;

    start = lseek(fd, 0, SEEK_SET);
    if (start < 0) {
        virReportSystemError(errno,
                             _("cannot seek to beginning of file '%s'"),
                             target->path);
        return -1;
    }
    bytes = saferead(fd, buffer, sizeof(buffer));
    if (bytes < 0) {
        virReportSystemError(errno,
                             _("cannot read beginning of file '%s'"),
                             target->path);
        return -1;
    }

    for (i = 0; disk_types[i].part_table_type != -1; i++) {
        if (disk_types[i].offset + disk_types[i].length > bytes)
            continue;
        if (memcmp(buffer+disk_types[i].offset, &disk_types[i].magic,
            disk_types[i].length) == 0) {
            target->format = disk_types[i].part_table_type;
            break;
        }
    }

    return 0;
}


1319 1320 1321
/*
 * Allows caller to silently ignore files with improper mode
 *
1322 1323 1324
 * Returns -1 on error. If VIR_STORAGE_VOL_OPEN_NOERROR is passed, we
 * return -2 if file mode is unexpected or the volume is a dangling
 * symbolic link.
1325
 */
1326
int
1327 1328
virStorageBackendVolOpen(const char *path, struct stat *sb,
                         unsigned int flags)
1329
{
1330
    int fd, mode = 0;
1331
    char *base = last_component(path);
1332
    bool noerror = (flags & VIR_STORAGE_VOL_OPEN_NOERROR);
1333

E
Eric Blake 已提交
1334
    if (lstat(path, sb) < 0) {
1335 1336 1337 1338 1339 1340 1341 1342 1343
        if (errno == ENOENT) {
            if (noerror) {
                VIR_WARN("ignoring missing file '%s'", path);
                return -2;
            }
            virReportError(VIR_ERR_NO_STORAGE_VOL,
                           _("no storage vol with matching path '%s'"),
                           path);
            return -1;
1344
        }
1345 1346 1347 1348 1349 1350
        virReportSystemError(errno,
                             _("cannot stat file '%s'"),
                             path);
        return -1;
    }

E
Eric Blake 已提交
1351
    if (S_ISFIFO(sb->st_mode)) {
1352 1353 1354 1355 1356 1357 1358
        if (noerror) {
            VIR_WARN("ignoring FIFO '%s'", path);
            return -2;
        }
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume path '%s' is a FIFO"), path);
        return -1;
E
Eric Blake 已提交
1359
    } else if (S_ISSOCK(sb->st_mode)) {
1360 1361 1362 1363 1364 1365 1366
        if (noerror) {
            VIR_WARN("ignoring socket '%s'", path);
            return -2;
        }
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume path '%s' is a socket"), path);
        return -1;
1367 1368
    }

1369 1370 1371 1372 1373 1374
    /* O_NONBLOCK should only matter during open() for fifos and
     * sockets, which we already filtered; but using it prevents a
     * TOCTTOU race.  However, later on we will want to read() the
     * header from this fd, and virFileRead* routines require a
     * blocking fd, so fix it up after verifying we avoided a
     * race.  */
1375
    if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
1376
        if ((errno == ENOENT || errno == ELOOP) &&
1377
            S_ISLNK(sb->st_mode) && noerror) {
1378 1379
            VIR_WARN("ignoring dangling symlink '%s'", path);
            return -2;
1380
        }
1381
        if (errno == ENOENT && noerror) {
1382 1383
            VIR_WARN("ignoring missing file '%s'", path);
            return -2;
1384 1385
        }

1386
        virReportSystemError(errno, _("cannot open volume '%s'"), path);
1387 1388 1389
        return -1;
    }

E
Eric Blake 已提交
1390
    if (fstat(fd, sb) < 0) {
1391
        virReportSystemError(errno, _("cannot stat file '%s'"), path);
1392 1393 1394 1395
        VIR_FORCE_CLOSE(fd);
        return -1;
    }

1396
    if (S_ISREG(sb->st_mode)) {
1397
        mode = VIR_STORAGE_VOL_OPEN_REG;
1398
    } else if (S_ISCHR(sb->st_mode)) {
1399
        mode = VIR_STORAGE_VOL_OPEN_CHAR;
1400
    } else if (S_ISBLK(sb->st_mode)) {
1401
        mode = VIR_STORAGE_VOL_OPEN_BLOCK;
1402
    } else if (S_ISDIR(sb->st_mode)) {
1403 1404 1405 1406 1407
        mode = VIR_STORAGE_VOL_OPEN_DIR;

        if (STREQ(base, ".") ||
            STREQ(base, "..")) {
            VIR_FORCE_CLOSE(fd);
1408 1409 1410 1411 1412 1413 1414
            if (noerror) {
                VIR_INFO("Skipping special dir '%s'", base);
                return -2;
            }
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cannot use volume path '%s'"), path);
            return -1;
1415
        }
1416 1417
    } else {
        VIR_FORCE_CLOSE(fd);
1418 1419 1420 1421 1422 1423 1424
        if (noerror) {
            VIR_WARN("ignoring unexpected type for file '%s'", path);
            return -2;
        }
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected type for file '%s'"), path);
        return -1;
1425 1426 1427
    }

    if (virSetBlocking(fd, true) < 0) {
1428
        VIR_FORCE_CLOSE(fd);
1429 1430
        virReportSystemError(errno, _("unable to set blocking mode for '%s'"),
                             path);
1431
        return -1;
1432
    }
1433 1434

    if (!(mode & flags)) {
1435
        VIR_FORCE_CLOSE(fd);
1436 1437 1438
        if (noerror) {
            VIR_INFO("Skipping volume '%s'", path);
            return -2;
1439 1440
        }

1441 1442 1443
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected storage mode for '%s'"), path);
        return -1;
1444 1445 1446 1447 1448 1449
    }

    return fd;
}

int
1450
virStorageBackendUpdateVolTargetInfo(virStorageSourcePtr target,
1451
                                     bool updateCapacity,
1452
                                     bool withBlockVolFormat,
1453
                                     unsigned int openflags)
1454
{
1455
    int ret, fd = -1;
E
Eric Blake 已提交
1456
    struct stat sb;
1457

1458
    if ((ret = virStorageBackendVolOpen(target->path, &sb, openflags)) < 0)
1459
        goto cleanup;
1460
    fd = ret;
1461

1462 1463
    if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb,
                                                      updateCapacity)) < 0)
1464 1465 1466 1467 1468 1469 1470
        goto cleanup;

    if (withBlockVolFormat) {
        if ((ret = virStorageBackendDetectBlockVolFormatFD(target, fd)) < 0)
            goto cleanup;
    }

1471
 cleanup:
1472
    VIR_FORCE_CLOSE(fd);
1473 1474 1475 1476

    return ret;
}

1477
int
1478
virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
1479
                               bool updateCapacity,
1480
                               bool withBlockVolFormat,
1481
                               unsigned int openflags)
1482 1483 1484
{
    int ret;

1485
    if ((ret = virStorageBackendUpdateVolTargetInfo(&vol->target,
1486 1487 1488
                                                    updateCapacity,
                                                    withBlockVolFormat,
                                                    openflags)) < 0)
1489 1490
        return ret;

1491 1492
    if (vol->target.backingStore &&
        (ret = virStorageBackendUpdateVolTargetInfo(vol->target.backingStore,
1493 1494
                                                    updateCapacity,
                                                    withBlockVolFormat,
1495 1496
                                                    VIR_STORAGE_VOL_OPEN_DEFAULT |
                                                    VIR_STORAGE_VOL_OPEN_NOERROR) < 0))
1497 1498 1499 1500 1501
        return ret;

    return 0;
}

1502 1503 1504
/*
 * virStorageBackendUpdateVolTargetInfoFD:
 * @target: target definition ptr of volume to update
1505 1506
 * @fd: fd of storage volume to update, via virStorageBackendOpenVol*, or -1
 * @sb: details about file (must match @fd, if that is provided)
1507
 * @updateCapacity: If true, updated capacity info will be stored
1508
 *
1509
 * Returns 0 for success, -1 on a legitimate error condition.
1510
 */
1511
int
1512
virStorageBackendUpdateVolTargetInfoFD(virStorageSourcePtr target,
1513
                                       int fd,
1514 1515
                                       struct stat *sb,
                                       bool updateCapacity)
1516
{
1517
#if WITH_SELINUX
1518 1519 1520
    security_context_t filecon = NULL;
#endif

1521
    if (S_ISREG(sb->st_mode)) {
1522
#ifndef WIN32
1523 1524
        target->allocation = (unsigned long long)sb->st_blocks *
            (unsigned long long)DEV_BSIZE;
D
Daniel P. Berrange 已提交
1525
#else
1526
        target->allocation = sb->st_size;
D
Daniel P. Berrange 已提交
1527
#endif
1528 1529 1530
        /* Regular files may be sparse, so logical size (capacity) is not same
         * as actual allocation above
         */
1531 1532
        if (updateCapacity)
            target->capacity = sb->st_size;
1533 1534
    } else if (S_ISDIR(sb->st_mode)) {
        target->allocation = 0;
1535 1536
        if (updateCapacity)
            target->capacity = 0;
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
    } else if (fd >= 0) {
        off_t end;
        /* XXX this is POSIX compliant, but doesn't work for CHAR files,
         * only BLOCK. There is a Linux specific ioctl() for getting
         * size of both CHAR / BLOCK devices we should check for in
         * configure
         */
        end = lseek(fd, 0, SEEK_END);
        if (end == (off_t)-1) {
            virReportSystemError(errno,
                                 _("cannot seek to end of file '%s'"),
                                 target->path);
            return -1;
1550
        }
1551
        target->allocation = end;
1552 1553
        if (updateCapacity)
            target->capacity = end;
1554 1555
    }

1556 1557 1558 1559 1560
    if (!target->perms && VIR_ALLOC(target->perms) < 0)
        return -1;
    target->perms->mode = sb->st_mode & S_IRWXUGO;
    target->perms->uid = sb->st_uid;
    target->perms->gid = sb->st_gid;
1561

1562
    if (!target->timestamps && VIR_ALLOC(target->timestamps) < 0)
1563
        return -1;
E
Eric Blake 已提交
1564 1565 1566 1567
    target->timestamps->atime = get_stat_atime(sb);
    target->timestamps->btime = get_stat_birthtime(sb);
    target->timestamps->ctime = get_stat_ctime(sb);
    target->timestamps->mtime = get_stat_mtime(sb);
1568

1569
    VIR_FREE(target->perms->label);
1570

1571
#if WITH_SELINUX
1572
    /* XXX: make this a security driver call */
1573 1574 1575 1576 1577 1578 1579 1580
    if (fd >= 0) {
        if (fgetfilecon_raw(fd, &filecon) == -1) {
            if (errno != ENODATA && errno != ENOTSUP) {
                virReportSystemError(errno,
                                     _("cannot get file context of '%s'"),
                                     target->path);
                return -1;
            }
1581
        } else {
1582
            if (VIR_STRDUP(target->perms->label, filecon) < 0) {
1583 1584 1585
                freecon(filecon);
                return -1;
            }
1586
            freecon(filecon);
1587
        }
1588 1589 1590 1591 1592 1593
    }
#endif

    return 0;
}

D
Dave Allan 已提交
1594

1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
/*
 * Given a volume path directly in /dev/XXX, iterate over the
 * entries in the directory pool->def->target.path and find the
 * first symlink pointing to the volume path.
 *
 * If, the target.path is /dev/, then return the original volume
 * path.
 *
 * If no symlink is found, then return the original volume path
 *
 * Typically target.path is one of the /dev/disk/by-XXX dirs
 * with stable paths.
1607
 *
1608
 * If 'loop' is true, we use a timeout loop to give dynamic paths
1609
 * a change to appear.
1610 1611
 */
char *
1612
virStorageBackendStablePath(virStoragePoolObjPtr pool,
1613
                            const char *devpath,
1614
                            bool loop)
1615 1616 1617
{
    DIR *dh;
    struct dirent *dent;
1618
    char *stablepath;
1619
    int opentries = 0;
1620
    int retry = 0;
E
Eric Blake 已提交
1621
    int direrr;
1622 1623 1624 1625 1626

    /* Short circuit if pool has no target, or if its /dev */
    if (pool->def->target.path == NULL ||
        STREQ(pool->def->target.path, "/dev") ||
        STREQ(pool->def->target.path, "/dev/"))
1627
        goto ret_strdup;
1628

1629
    /* Skip whole thing for a pool which isn't in /dev
1630
     * so we don't mess filesystem/dir based pools
1631 1632 1633 1634
     */
    if (!STRPREFIX(pool->def->target.path, "/dev"))
        goto ret_strdup;

1635 1636 1637 1638
    /* Logical pools are under /dev but already have stable paths */
    if (pool->def->type == VIR_STORAGE_POOL_LOGICAL)
        goto ret_strdup;

1639 1640 1641
    /* We loop here because /dev/disk/by-{id,path} may not have existed
     * before we started this operation, so we have to give it some time to
     * get created.
1642
     */
1643
 reopen:
1644
    if ((dh = opendir(pool->def->target.path)) == NULL) {
1645
        opentries++;
1646
        if (loop && errno == ENOENT && opentries < 50) {
1647 1648 1649
            usleep(100 * 1000);
            goto reopen;
        }
1650
        virReportSystemError(errno,
1651 1652
                             _("cannot read dir '%s'"),
                             pool->def->target.path);
1653 1654 1655
        return NULL;
    }

1656 1657 1658
    /* The pool is pointing somewhere like /dev/disk/by-path
     * or /dev/disk/by-id, so we need to check all symlinks in
     * the target directory and figure out which one points
1659 1660
     * to this device node.
     *
1661
     * And it might need some time till the stable path shows
E
Eric Blake 已提交
1662 1663
     * up, so add timeout to retry here.  Ignore readdir failures,
     * since we have a fallback.
1664
     */
1665
 retry:
E
Eric Blake 已提交
1666
    while ((direrr = virDirRead(dh, &dent, NULL)) > 0) {
1667 1668 1669
        if (dent->d_name[0] == '.')
            continue;

1670 1671 1672
        if (virAsprintf(&stablepath, "%s/%s",
                        pool->def->target.path,
                        dent->d_name) == -1) {
1673 1674 1675 1676 1677 1678 1679 1680 1681
            closedir(dh);
            return NULL;
        }

        if (virFileLinkPointsTo(stablepath, devpath)) {
            closedir(dh);
            return stablepath;
        }

1682
        VIR_FREE(stablepath);
1683 1684
    }

E
Eric Blake 已提交
1685
    if (!direrr && loop && ++retry < 100) {
1686 1687 1688 1689
        usleep(100 * 1000);
        goto retry;
    }

1690 1691
    closedir(dh);

1692
 ret_strdup:
1693 1694 1695
    /* Couldn't find any matching stable link so give back
     * the original non-stable dev path
     */
1696

1697
    ignore_value(VIR_STRDUP(stablepath, devpath));
1698 1699

    return stablepath;
1700
}
1701

1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
int
virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                virStorageVolDefPtr vol,
                                virStreamPtr stream,
                                unsigned long long offset,
                                unsigned long long len,
                                unsigned int flags)
{
    virCheckFlags(0, -1);

    /* Not using O_CREAT because the file is required to already exist at
     * this point */
    return virFDStreamOpenFile(stream, vol->target.path, offset, len, O_WRONLY);
}

int
virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                  virStorageVolDefPtr vol,
                                  virStreamPtr stream,
                                  unsigned long long offset,
                                  unsigned long long len,
                                  unsigned int flags)
{
    virCheckFlags(0, -1);

    return virFDStreamOpenFile(stream, vol->target.path, offset, len, O_RDONLY);
}

1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934

/* If the volume we're wiping is already a sparse file, we simply
 * truncate and extend it to its original size, filling it with
 * zeroes.  This behavior is guaranteed by POSIX:
 *
 * http://www.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
 *
 * If fildes refers to a regular file, the ftruncate() function shall
 * cause the size of the file to be truncated to length. If the size
 * of the file previously exceeded length, the extra data shall no
 * longer be available to reads on the file. If the file previously
 * was smaller than this size, ftruncate() shall increase the size of
 * the file. If the file size is increased, the extended area shall
 * appear as if it were zero-filled.
 */
static int
virStorageBackendVolZeroSparseFileLocal(virStorageVolDefPtr vol,
                                        off_t size,
                                        int fd)
{
    int ret = -1;

    ret = ftruncate(fd, 0);
    if (ret == -1) {
        virReportSystemError(errno,
                             _("Failed to truncate volume with "
                               "path '%s' to 0 bytes"),
                             vol->target.path);
        return ret;
    }

    ret = ftruncate(fd, size);
    if (ret == -1) {
        virReportSystemError(errno,
                             _("Failed to truncate volume with "
                               "path '%s' to %ju bytes"),
                             vol->target.path, (uintmax_t)size);
    }

    return ret;
}


static int
virStorageBackendWipeExtentLocal(virStorageVolDefPtr vol,
                                 int fd,
                                 off_t extent_start,
                                 off_t extent_length,
                                 char *writebuf,
                                 size_t writebuf_length,
                                 size_t *bytes_wiped)
{
    int ret = -1, written = 0;
    off_t remaining = 0;
    size_t write_size = 0;

    VIR_DEBUG("extent logical start: %ju len: %ju",
              (uintmax_t)extent_start, (uintmax_t)extent_length);

    if ((ret = lseek(fd, extent_start, SEEK_SET)) < 0) {
        virReportSystemError(errno,
                             _("Failed to seek to position %ju in volume "
                               "with path '%s'"),
                             (uintmax_t)extent_start, vol->target.path);
        goto cleanup;
    }

    remaining = extent_length;
    while (remaining > 0) {

        write_size = (writebuf_length < remaining) ? writebuf_length : remaining;
        written = safewrite(fd, writebuf, write_size);
        if (written < 0) {
            virReportSystemError(errno,
                                 _("Failed to write %zu bytes to "
                                   "storage volume with path '%s'"),
                                 write_size, vol->target.path);

            goto cleanup;
        }

        *bytes_wiped += written;
        remaining -= written;
    }

    if (fdatasync(fd) < 0) {
        ret = -errno;
        virReportSystemError(errno,
                             _("cannot sync data to volume with path '%s'"),
                             vol->target.path);
        goto cleanup;
    }

    VIR_DEBUG("Wrote %zu bytes to volume with path '%s'",
              *bytes_wiped, vol->target.path);

    ret = 0;

 cleanup:
    return ret;
}


int
virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
                              virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                              virStorageVolDefPtr vol,
                              unsigned int algorithm,
                              unsigned int flags)
{
    int ret = -1, fd = -1;
    struct stat st;
    char *writebuf = NULL;
    size_t bytes_wiped = 0;
    virCommandPtr cmd = NULL;

    virCheckFlags(0, -1);

    VIR_DEBUG("Wiping volume with path '%s' and algorithm %u",
              vol->target.path, algorithm);

    fd = open(vol->target.path, O_RDWR);
    if (fd == -1) {
        virReportSystemError(errno,
                             _("Failed to open storage volume with path '%s'"),
                             vol->target.path);
        goto cleanup;
    }

    if (fstat(fd, &st) == -1) {
        virReportSystemError(errno,
                             _("Failed to stat storage volume with path '%s'"),
                             vol->target.path);
        goto cleanup;
    }

    if (algorithm != VIR_STORAGE_VOL_WIPE_ALG_ZERO) {
        const char *alg_char ATTRIBUTE_UNUSED = NULL;
        switch (algorithm) {
        case VIR_STORAGE_VOL_WIPE_ALG_NNSA:
            alg_char = "nnsa";
            break;
        case VIR_STORAGE_VOL_WIPE_ALG_DOD:
            alg_char = "dod";
            break;
        case VIR_STORAGE_VOL_WIPE_ALG_BSI:
            alg_char = "bsi";
            break;
        case VIR_STORAGE_VOL_WIPE_ALG_GUTMANN:
            alg_char = "gutmann";
            break;
        case VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER:
            alg_char = "schneier";
            break;
        case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7:
            alg_char = "pfitzner7";
            break;
        case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33:
            alg_char = "pfitzner33";
            break;
        case VIR_STORAGE_VOL_WIPE_ALG_RANDOM:
            alg_char = "random";
            break;
        default:
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unsupported algorithm %d"),
                           algorithm);
        }
        cmd = virCommandNew(SCRUB);
        virCommandAddArgList(cmd, "-f", "-p", alg_char,
                             vol->target.path, NULL);

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

        ret = 0;
        goto cleanup;
    } else {
        if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) {
            ret = virStorageBackendVolZeroSparseFileLocal(vol, st.st_size, fd);
        } else {

            if (VIR_ALLOC_N(writebuf, st.st_blksize) < 0)
                goto cleanup;

            ret = virStorageBackendWipeExtentLocal(vol,
                                                   fd,
                                                   0,
                                                   vol->target.allocation,
                                                   writebuf,
                                                   st.st_blksize,
                                                   &bytes_wiped);
        }
    }

 cleanup:
    virCommandFree(cmd);
    VIR_FREE(writebuf);
    VIR_FORCE_CLOSE(fd);
    return ret;
}


1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
#ifdef GLUSTER_CLI
int
virStorageBackendFindGlusterPoolSources(const char *host,
                                        int pooltype,
                                        virStoragePoolSourceListPtr list)
{
    char *outbuf = NULL;
    virCommandPtr cmd = NULL;
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr *nodes = NULL;
    virStoragePoolSource *src = NULL;
    size_t i;
    int nnodes;
    int rc;

    int ret = -1;

    cmd = virCommandNewArgList(GLUSTER_CLI,
                               "--xml",
                               "--log-file=/dev/null",
                               "volume", "info", "all", NULL);

    virCommandAddArgFormat(cmd, "--remote-host=%s", host);
    virCommandSetOutputBuffer(cmd, &outbuf);

    if (virCommandRun(cmd, &rc) < 0)
        goto cleanup;

    if (rc != 0) {
        VIR_INFO("failed to query host '%s' for gluster volumes: %s",
                 host, outbuf);
        ret = 0;
        goto cleanup;
    }

    if (!(doc = virXMLParseStringCtxt(outbuf, _("(gluster_cli_output)"),
                                      &ctxt)))
        goto cleanup;

    if ((nnodes = virXPathNodeSet("//volumes/volume", ctxt, &nodes)) <= 0) {
        VIR_INFO("no gluster volumes available on '%s'", host);
        ret = 0;
        goto cleanup;
    }

    for (i = 0; i < nnodes; i++) {
        ctxt->node = nodes[i];

        if (!(src = virStoragePoolSourceListNewSource(list)))
            goto cleanup;

        if (!(src->dir = virXPathString("string(//name)", ctxt))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to extract gluster volume name"));
            goto cleanup;
        }

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

        if (VIR_STRDUP(src->hosts[0].name, host) < 0)
            goto cleanup;

        src->format = pooltype;
    }

    ret = 0;

 cleanup:
    VIR_FREE(nodes);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);
    VIR_FREE(outbuf);
    virCommandFree(cmd);
    return ret;
}
#else /* #ifdef GLUSTER_CLI */
int
virStorageBackendFindGlusterPoolSources(const char *host ATTRIBUTE_UNUSED,
                                        int pooltype ATTRIBUTE_UNUSED,
                                        virStoragePoolSourceListPtr list ATTRIBUTE_UNUSED)
{
    VIR_INFO("gluster cli tool not installed");
    return 0;
}
#endif /* #ifdef GLUSTER_CLI */