storage_backend.c 49.1 KB
Newer Older
1
/*
2
 * storage_backend.c: internal storage driver backend contract
3
 *
4
 * Copyright (C) 2007-2010 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
 * 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 <string.h>
27
#include <stdio.h>
D
Daniel P. Berrange 已提交
28
#if HAVE_REGEX_H
29
# include <regex.h>
D
Daniel P. Berrange 已提交
30
#endif
31
#include <sys/types.h>
E
Eric Blake 已提交
32
#include <sys/wait.h>
33
#include <unistd.h>
34 35 36
#include <fcntl.h>
#include <stdint.h>
#include <sys/stat.h>
37
#include <sys/param.h>
38 39 40
#include <dirent.h>

#if HAVE_SELINUX
41
# include <selinux/selinux.h>
42
#endif
43

44
#include "datatypes.h"
45
#include "virterror_internal.h"
D
Daniel P. Berrange 已提交
46 47
#include "util.h"
#include "memory.h"
48
#include "internal.h"
49
#include "secret_conf.h"
50
#include "uuid.h"
51
#include "storage_file.h"
D
Daniel P. Berrange 已提交
52
#include "storage_backend.h"
53
#include "logging.h"
54
#include "files.h"
55

56
#if WITH_STORAGE_LVM
57
# include "storage_backend_logical.h"
58 59
#endif
#if WITH_STORAGE_ISCSI
60
# include "storage_backend_iscsi.h"
61
#endif
62
#if WITH_STORAGE_SCSI
63
# include "storage_backend_scsi.h"
64
#endif
D
Dave Allan 已提交
65
#if WITH_STORAGE_MPATH
66
# include "storage_backend_mpath.h"
D
Dave Allan 已提交
67
#endif
68
#if WITH_STORAGE_DISK
69
# include "storage_backend_disk.h"
70 71
#endif
#if WITH_STORAGE_DIR
72
# include "storage_backend_fs.h"
73 74
#endif

75 76
#define VIR_FROM_THIS VIR_FROM_STORAGE

77 78 79 80 81 82 83 84 85 86 87 88 89 90
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
91 92 93
#if WITH_STORAGE_SCSI
    &virStorageBackendSCSI,
#endif
D
Dave Allan 已提交
94 95 96
#if WITH_STORAGE_MPATH
    &virStorageBackendMpath,
#endif
97 98 99 100 101
#if WITH_STORAGE_DISK
    &virStorageBackendDisk,
#endif
    NULL
};
102

103 104 105 106 107 108 109 110
static int track_allocation_progress = 0;

enum {
    TOOL_QEMU_IMG,
    TOOL_KVM_IMG,
    TOOL_QCOW_CREATE,
};

111 112
static int ATTRIBUTE_NONNULL (2)
virStorageBackendCopyToFD(virStorageVolDefPtr vol,
113 114
                          virStorageVolDefPtr inputvol,
                          int fd,
115 116
                          unsigned long long *total,
                          int is_dest_file)
117 118 119
{
    int inputfd = -1;
    int amtread = -1;
120
    int ret = 0;
121 122 123 124 125
    unsigned long long remain;
    size_t bytes = 1024 * 1024;
    char zerobuf[512];
    char *buf = NULL;

126
    if ((inputfd = open(inputvol->target.path, O_RDONLY)) < 0) {
127
        ret = -errno;
128
        virReportSystemError(errno,
129 130 131
                             _("could not open input path '%s'"),
                             inputvol->target.path);
        goto cleanup;
132 133 134 135 136
    }

    bzero(&zerobuf, sizeof(zerobuf));

    if (VIR_ALLOC_N(buf, bytes) < 0) {
137
        ret = -errno;
138
        virReportOOMError();
139 140 141 142 143 144 145 146 147 148 149 150
        goto cleanup;
    }

    remain = *total;

    while (amtread != 0) {
        int amtleft;

        if (remain < bytes)
            bytes = remain;

        if ((amtread = saferead(inputfd, buf, bytes)) < 0) {
151
            ret = -errno;
152
            virReportSystemError(errno,
153 154 155 156 157 158 159 160 161 162 163 164 165
                                 _("failed reading from file '%s'"),
                                 inputvol->target.path);
            goto cleanup;
        }
        remain -= amtread;

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

166
            if (is_dest_file && memcmp(buf+offset, zerobuf, interval) == 0) {
167
                if (lseek(fd, interval, SEEK_CUR) < 0) {
168
                    ret = -errno;
169
                    virReportSystemError(errno,
170 171 172 173 174
                                         _("cannot extend file '%s'"),
                                         vol->target.path);
                    goto cleanup;
                }
            } else if (safewrite(fd, buf+offset, interval) < 0) {
175
                ret = -errno;
176
                virReportSystemError(errno,
177 178 179 180 181 182 183 184
                                     _("failed writing to file '%s'"),
                                     vol->target.path);
                goto cleanup;

            }
        } while ((amtleft -= 512) > 0);
    }

185
    if (VIR_CLOSE(inputfd) < 0) {
186
        ret = -errno;
187
        virReportSystemError(errno,
188 189 190 191 192 193 194 195 196
                             _("cannot close file '%s'"),
                             inputvol->target.path);
        goto cleanup;
    }
    inputfd = -1;

    *total -= remain;

cleanup:
197
    VIR_FORCE_CLOSE(inputfd);
198

199 200
    VIR_FREE(buf);

201 202 203
    return ret;
}

204
static int
205
virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
206
                                 virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
207 208 209 210 211 212 213
                                 virStorageVolDefPtr vol,
                                 virStorageVolDefPtr inputvol,
                                 unsigned int flags ATTRIBUTE_UNUSED)
{
    int fd = -1;
    int ret = -1;
    unsigned long long remain;
214 215 216
    struct stat st;
    gid_t gid;
    uid_t uid;
217 218

    if ((fd = open(vol->target.path, O_RDWR)) < 0) {
219
        virReportSystemError(errno,
220 221 222 223 224 225 226 227
                             _("cannot create path '%s'"),
                             vol->target.path);
        goto cleanup;
    }

    remain = vol->allocation;

    if (inputvol) {
228
        int res = virStorageBackendCopyToFD(vol, inputvol,
229
                                            fd, &remain, 0);
230 231 232 233
        if (res < 0)
            goto cleanup;
    }

234
    if (fstat(fd, &st) == -1) {
235
        virReportSystemError(errno, _("stat of '%s' failed"),
236 237 238 239 240 241
                             vol->target.path);
        goto cleanup;
    }
    uid = (vol->target.perms.uid != st.st_uid) ? vol->target.perms.uid : -1;
    gid = (vol->target.perms.gid != st.st_gid) ? vol->target.perms.gid : -1;
    if (((uid != -1) || (gid != -1))
242
        && (fchown(fd, uid, gid) < 0)) {
243
        virReportSystemError(errno,
244
                             _("cannot chown '%s' to (%u, %u)"),
245
                             vol->target.path, uid, gid);
246 247 248
        goto cleanup;
    }
    if (fchmod(fd, vol->target.perms.mode) < 0) {
249
        virReportSystemError(errno,
250 251 252 253
                             _("cannot set mode of '%s' to %04o"),
                             vol->target.path, vol->target.perms.mode);
        goto cleanup;
    }
254
    if (VIR_CLOSE(fd) < 0) {
255
        virReportSystemError(errno,
256 257 258 259 260 261 262 263
                             _("cannot close file '%s'"),
                             vol->target.path);
        goto cleanup;
    }
    fd = -1;

    ret = 0;
cleanup:
264
    VIR_FORCE_CLOSE(fd);
265 266 267 268

    return ret;
}

269 270 271 272
struct createRawFileOpHookData {
    virStorageVolDefPtr vol;
    virStorageVolDefPtr inputvol;
};
273

274 275 276 277
static int createRawFileOpHook(int fd, void *data) {
    struct createRawFileOpHookData *hdata = data;
    int ret = 0;
    unsigned long long remain;
278

279 280
    /* Seek to the final size, so the capacity is available upfront
     * for progress reporting */
281
    if (ftruncate(fd, hdata->vol->capacity) < 0) {
282
        ret = -errno;
283
        virReportSystemError(errno,
284
                             _("cannot extend file '%s'"),
285
                             hdata->vol->target.path);
286 287 288
        goto cleanup;
    }

289
    remain = hdata->vol->allocation;
290

291
    if (hdata->inputvol) {
292 293 294
        ret = virStorageBackendCopyToFD(hdata->vol, hdata->inputvol,
                                        fd, &remain, 1);
        if (ret < 0) {
295
            goto cleanup;
296
        }
297 298 299 300 301 302 303 304 305 306 307 308 309 310
    }

    if (remain) {
        if (track_allocation_progress) {

            while (remain) {
                /* Allocate in chunks of 512MiB: big-enough chunk
                 * size and takes approx. 9s on ext3. A progress
                 * update every 9s is a fair-enough trade-off
                 */
                unsigned long long bytes = 512 * 1024 * 1024;

                if (bytes > remain)
                    bytes = remain;
311 312
                if (safezero(fd, 0, hdata->vol->allocation - remain,
                             bytes) != 0) {
313
                    ret = -errno;
J
Jiri Denemark 已提交
314
                    virReportSystemError(errno, _("cannot fill file '%s'"),
315
                                         hdata->vol->target.path);
316 317 318 319 320
                    goto cleanup;
                }
                remain -= bytes;
            }
        } else { /* No progress bars to be shown */
321
            if (safezero(fd, 0, 0, remain) != 0) {
322
                ret = -errno;
J
Jiri Denemark 已提交
323
                virReportSystemError(errno, _("cannot fill file '%s'"),
324
                                     hdata->vol->target.path);
325 326 327
                goto cleanup;
            }
        }
328

329 330 331
    }

    if (fsync(fd) < 0) {
332
        ret = -errno;
333 334 335
        virReportSystemError(errno, _("cannot sync data to file '%s'"),
                             hdata->vol->target.path);
        goto cleanup;
336 337
    }

338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
cleanup:
    return ret;
}

int
virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
                           virStoragePoolObjPtr pool,
                           virStorageVolDefPtr vol,
                           virStorageVolDefPtr inputvol,
                           unsigned int flags ATTRIBUTE_UNUSED)
{
    int ret = -1;
    int createstat;
    struct createRawFileOpHookData hdata = { vol, inputvol };

    if (vol->target.encryption != NULL) {
        virStorageReportError(VIR_ERR_NO_SUPPORT,
                              "%s", _("storage pool does not support encrypted "
                                      "volumes"));
357 358
        goto cleanup;
    }
359

360 361 362
    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;

363
    if ((createstat = virFileOperation(vol->target.path,
364
                                       O_RDWR | O_CREAT | O_EXCL,
365
                                       vol->target.perms.mode, uid, gid,
366 367 368 369
                                       createRawFileOpHook, &hdata,
                                       VIR_FILE_OP_FORCE_PERMS |
                                       (pool->def->type == VIR_STORAGE_POOL_NETFS
                                        ? VIR_FILE_OP_AS_UID : 0))) < 0) {
370
    virReportSystemError(-createstat,
371 372 373 374
                         _("cannot create path '%s'"),
                         vol->target.path);
    goto cleanup;
    }
375 376 377 378 379 380

    ret = 0;
cleanup:
    return ret;
}

381 382 383 384 385 386 387 388 389
static int
virStorageGenerateSecretUUID(virConnectPtr conn,
                             unsigned char *uuid)
{
    unsigned attempt;

    for (attempt = 0; attempt < 65536; attempt++) {
        virSecretPtr tmp;
        if (virUUIDGenerate(uuid) < 0) {
390 391
            virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                  _("unable to generate uuid"));
392 393 394 395 396 397 398 399 400
            return -1;
        }
        tmp = conn->secretDriver->lookupByUUID(conn, uuid);
        if (tmp == NULL)
            return 0;

        virSecretFree(tmp);
    }

401 402
    virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                          _("too many conflicts when generating an uuid"));
403 404 405 406

    return -1;
}

407 408 409 410 411 412 413 414 415
static int
virStorageGenerateQcowEncryption(virConnectPtr conn,
                                 virStorageVolDefPtr vol)
{
    virSecretDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    virStorageEncryptionPtr enc;
    virStorageEncryptionSecretPtr enc_secret = NULL;
    virSecretPtr secret = NULL;
416
    char *xml;
417 418 419
    unsigned char value[VIR_STORAGE_QCOW_PASSPHRASE_SIZE];
    int ret = -1;

420 421 422
    if (conn->secretDriver == NULL ||
        conn->secretDriver->lookupByUUID == NULL ||
        conn->secretDriver->defineXML == NULL ||
423
        conn->secretDriver->setValue == NULL) {
424
        virStorageReportError(VIR_ERR_NO_SUPPORT, "%s",
425 426 427 428 429 430
                              _("secret storage not supported"));
        goto cleanup;
    }

    enc = vol->target.encryption;
    if (enc->nsecrets != 0) {
431
        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
432 433 434 435 436 437
                              _("secrets already defined"));
        goto cleanup;
    }

    if (VIR_ALLOC(enc_secret) < 0 || VIR_REALLOC_N(enc->secrets, 1) < 0 ||
        VIR_ALLOC(def) < 0) {
438
        virReportOOMError();
439 440 441 442 443
        goto cleanup;
    }

    def->ephemeral = 0;
    def->private = 0;
444
    if (virStorageGenerateSecretUUID(conn, def->uuid) < 0)
445
        goto cleanup;
446

447 448 449
    def->usage_type = VIR_SECRET_USAGE_TYPE_VOLUME;
    def->usage.volume = strdup(vol->target.path);
    if (def->usage.volume == NULL) {
450
        virReportOOMError();
451 452
        goto cleanup;
    }
453
    xml = virSecretDefFormat(def);
454 455 456 457 458 459 460 461 462 463 464 465
    virSecretDefFree(def);
    def = NULL;
    if (xml == NULL)
        goto cleanup;

    secret = conn->secretDriver->defineXML(conn, xml, 0);
    if (secret == NULL) {
        VIR_FREE(xml);
        goto cleanup;
    }
    VIR_FREE(xml);

466
    if (virStorageGenerateQcowPassphrase(value) < 0)
467 468 469 470 471 472
        goto cleanup;

    if (conn->secretDriver->setValue(secret, value, sizeof(value), 0) < 0)
        goto cleanup;

    enc_secret->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
473
    memcpy(enc_secret->uuid, secret->uuid, VIR_UUID_BUFLEN);
474 475 476 477 478 479 480 481 482
    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;

cleanup:
    if (secret != NULL) {
483 484
        if (ret != 0 &&
            conn->secretDriver->undefine != NULL)
485 486 487
            conn->secretDriver->undefine(secret);
        virSecretFree(secret);
    }
488
    virBufferFreeAndReset(&buf);
489 490 491 492 493
    virSecretDefFree(def);
    VIR_FREE(enc_secret);
    return ret;
}

494 495 496
static int virStorageBuildSetUIDHook(void *data) {
    virStorageVolDefPtr vol = data;

497
    if ((vol->target.perms.gid != -1)
498
        && (setgid(vol->target.perms.gid) != 0)) {
499
        virReportSystemError(errno,
500 501 502 503
                             _("Cannot set gid to %u before creating %s"),
                             vol->target.perms.gid, vol->target.path);
        return -1;
    }
504
    if ((vol->target.perms.uid != -1)
505
        && (setuid(vol->target.perms.uid) != 0)) {
506
        virReportSystemError(errno,
507 508 509 510 511 512 513
                             _("Cannot set uid to %u before creating %s"),
                             vol->target.perms.uid, vol->target.path);
        return -1;
    }
    return 0;
}

514
static int virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
515 516 517 518 519 520 521 522
                                              virStorageVolDefPtr vol,
                                              const char **cmdargv) {
    struct stat st;
    gid_t gid;
    uid_t uid;
    int filecreated = 0;

    if ((pool->def->type == VIR_STORAGE_POOL_NETFS)
523 524 525 526 527
        && (((getuid() == 0)
             && (vol->target.perms.uid != -1)
             && (vol->target.perms.uid != 0))
            || ((vol->target.perms.gid != -1)
                && (vol->target.perms.gid != getgid())))) {
528
        if (virRunWithHook(cmdargv,
529 530 531 532 533 534 535
                           virStorageBuildSetUIDHook, vol, NULL) == 0) {
            /* command was successfully run, check if the file was created */
            if (stat(vol->target.path, &st) >=0)
                filecreated = 1;
        }
    }
    if (!filecreated) {
536
        if (virRun(cmdargv, NULL) < 0) {
537
            virReportSystemError(errno,
538 539 540 541 542
                                 _("Cannot run %s to create %s"),
                                 cmdargv[0], vol->target.path);
            return -1;
        }
        if (stat(vol->target.path, &st) < 0) {
543
            virReportSystemError(errno,
544 545 546 547 548 549 550 551 552 553
                                 _("%s failed to create %s"),
                                 cmdargv[0], vol->target.path);
            return -1;
        }
    }

    uid = (vol->target.perms.uid != st.st_uid) ? vol->target.perms.uid : -1;
    gid = (vol->target.perms.gid != st.st_gid) ? vol->target.perms.gid : -1;
    if (((uid != -1) || (gid != -1))
        && (chown(vol->target.path, uid, gid) < 0)) {
554
        virReportSystemError(errno,
555
                             _("cannot chown %s to (%u, %u)"),
556
                             vol->target.path, uid, gid);
557 558 559
        return -1;
    }
    if (chmod(vol->target.path, vol->target.perms.mode) < 0) {
560
        virReportSystemError(errno,
561 562 563 564 565 566 567
                             _("cannot set mode of '%s' to %04o"),
                             vol->target.path, vol->target.perms.mode);
        return -1;
    }
    return 0;
}

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
enum {
    QEMU_IMG_BACKING_FORMAT_NONE = 0,
    QEMU_IMG_BACKING_FORMAT_FLAG,
    QEMU_IMG_BACKING_FORMAT_OPTIONS,
};

static int virStorageBackendQEMUImgBackingFormat(const char *qemuimg)
{
    const char *const qemuarg[] = { qemuimg, "-h", NULL };
    const char *const qemuenv[] = { "LC_ALL=C", NULL };
    pid_t child = 0;
    int status;
    int newstdout = -1;
    char *help = NULL;
    enum { MAX_HELP_OUTPUT_SIZE = 1024*8 };
    char *start;
    char *end;
    char *tmp;
    int ret = -1;

    if (virExec(qemuarg, qemuenv, NULL,
                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
        goto cleanup;

E
Eric Blake 已提交
592
    if (virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help) < 0) {
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
        virReportSystemError(errno,
                             _("Unable to read '%s -h' output"),
                             qemuimg);
        goto cleanup;
    }

    start = strstr(help, " create ");
    end = strstr(start, "\n");
    if ((tmp = strstr(start, "-F fmt")) && tmp < end)
        ret = QEMU_IMG_BACKING_FORMAT_FLAG;
    else if ((tmp = strstr(start, "[-o options]")) && tmp < end)
        ret = QEMU_IMG_BACKING_FORMAT_OPTIONS;
    else
        ret = QEMU_IMG_BACKING_FORMAT_NONE;

cleanup:
    VIR_FREE(help);
610
    VIR_FORCE_CLOSE(newstdout);
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
rewait:
    if (child) {
        if (waitpid(child, &status, 0) != child) {
            if (errno == EINTR)
                goto rewait;

            VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
                      WEXITSTATUS(status), (unsigned long)child);
        }
        if (WEXITSTATUS(status) != 0) {
            VIR_WARN("Unexpected exit status '%d', qemu probably failed",
                     WEXITSTATUS(status));
        }
    }

    return ret;
}


630 631
static int
virStorageBackendCreateQemuImg(virConnectPtr conn,
632
                               virStoragePoolObjPtr pool,
633
                               virStorageVolDefPtr vol,
634 635
                               virStorageVolDefPtr inputvol,
                               unsigned int flags ATTRIBUTE_UNUSED)
636
{
637
    int ret = -1;
E
Eric Blake 已提交
638
    char *size = NULL;
639 640
    char *create_tool;

641
    const char *type = virStorageFileFormatTypeToString(vol->target.format);
642
    const char *backingType = vol->backingStore.path ?
643
        virStorageFileFormatTypeToString(vol->backingStore.format) : NULL;
644 645 646 647 648 649

    const char *inputBackingPath = (inputvol ? inputvol->backingStore.path
                                             : NULL);
    const char *inputPath = inputvol ? inputvol->target.path : NULL;
    /* Treat input block devices as 'raw' format */
    const char *inputType = inputPath ?
650 651 652 653
        virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ?
                                         VIR_STORAGE_FILE_RAW :
                                         inputvol->target.format) :
        NULL;
654 655

    if (type == NULL) {
656
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
657 658 659 660 661
                              _("unknown storage vol type %d"),
                              vol->target.format);
        return -1;
    }
    if (inputvol && inputType == NULL) {
662
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
663 664 665 666 667 668 669 670 671 672 673 674 675 676
                              _("unknown storage vol type %d"),
                              inputvol->target.format);
        return -1;
    }

    if (vol->backingStore.path) {

        /* 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 &&
            (!inputBackingPath ||
             STRNEQ(inputBackingPath, vol->backingStore.path))) {
677
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
678 679 680 681 682 683
                                  "%s", _("a different backing store can not "
                                          "be specified."));
            return -1;
        }

        if (backingType == NULL) {
684
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
685 686 687 688 689
                                  _("unknown storage vol backing store type %d"),
                                  vol->backingStore.format);
            return -1;
        }
        if (access(vol->backingStore.path, R_OK) != 0) {
690
            virReportSystemError(errno,
691 692 693 694 695 696
                                 _("inaccessible backing store volume %s"),
                                 vol->backingStore.path);
            return -1;
        }
    }

697
    if (vol->target.encryption != NULL) {
698 699
        virStorageEncryptionPtr enc;

700 701
        if (vol->target.format != VIR_STORAGE_FILE_QCOW &&
            vol->target.format != VIR_STORAGE_FILE_QCOW2) {
702
            virStorageReportError(VIR_ERR_NO_SUPPORT,
703 704 705 706
                                  _("qcow volume encryption unsupported with "
                                    "volume format %s"), type);
            return -1;
        }
707 708 709
        enc = vol->target.encryption;
        if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW &&
            enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT) {
710
            virStorageReportError(VIR_ERR_NO_SUPPORT,
711 712 713 714
                                  _("unsupported volume encryption format %d"),
                                  vol->target.encryption->format);
            return -1;
        }
715
        if (enc->nsecrets > 1) {
716
            virStorageReportError(VIR_ERR_INVALID_STORAGE_VOL, "%s",
717 718 719
                                  _("too many secrets for qcow encryption"));
            return -1;
        }
720 721 722 723 724
        if (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT ||
            enc->nsecrets == 0) {
            if (virStorageGenerateQcowEncryption(conn, vol) < 0)
                return -1;
        }
725 726
    }

727
    /* Size in KB */
E
Eric Blake 已提交
728 729 730 731
    if (virAsprintf(&size, "%lluK", vol->capacity / 1024) < 0) {
        virReportOOMError();
        goto cleanup;
    }
732 733 734 735 736 737 738

    /* 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) {
739
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
740
                              "%s", _("unable to find kvm-img or qemu-img"));
741 742 743 744
        return -1;
    }

    if (inputvol) {
745 746 747 748 749 750 751 752 753 754 755
        const char *imgargv[] = {
            create_tool,
            "convert",
            "-f", inputType,
            "-O", type,
            inputPath,
            vol->target.path,
            NULL,
        };

        ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
756
    } else if (vol->backingStore.path) {
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
        const char *imgargv[] = {
            create_tool,
            "create",
            "-f", type,
            "-b", vol->backingStore.path,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL
        };
        int imgformat = virStorageBackendQEMUImgBackingFormat(create_tool);
        char *optflag = NULL;
        if (imgformat < 0)
            goto cleanup;

        switch (imgformat) {
        case QEMU_IMG_BACKING_FORMAT_FLAG:
            imgargv[6] = "-F";
            imgargv[7] = backingType;
            imgargv[8] = vol->target.path;
            imgargv[9] = size;
780
            if (vol->target.encryption != NULL)
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
                imgargv[10] = "-e";
            break;

        case QEMU_IMG_BACKING_FORMAT_OPTIONS:
            if (virAsprintf(&optflag, "backing_fmt=%s", backingType) < 0) {
                virReportOOMError();
                goto cleanup;
            }
            imgargv[6] = "-o";
            imgargv[7] = optflag;
            imgargv[8] = vol->target.path;
            imgargv[9] = size;
            if (vol->target.encryption != NULL)
                imgargv[10] = "-e";
            break;

        default:
            VIR_INFO("Unable to set backing store format for %s with %s",
                     vol->target.path, create_tool);
            imgargv[6] = vol->target.path;
            imgargv[7] = size;
            if (vol->target.encryption != NULL)
                imgargv[8] = "-e";
        }

        ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
        VIR_FREE(optflag);
808
    } else {
809 810 811 812 813 814 815 816 817 818
        /* The extra NULL field is for indicating encryption (-e). */
        const char *imgargv[] = {
            create_tool,
            "create",
            "-f", type,
            vol->target.path,
            size,
            NULL,
            NULL
        };
819 820
        if (vol->target.encryption != NULL)
            imgargv[6] = "-e";
821

822 823
        ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
    }
824

825
    cleanup:
E
Eric Blake 已提交
826
    VIR_FREE(size);
827
    VIR_FREE(create_tool);
828

829
    return ret;
830 831 832 833 834 835 836
}

/*
 * Xen removed the fully-functional qemu-img, and replaced it
 * with a partially functional qcow-create. Go figure ??!?
 */
static int
837
virStorageBackendCreateQcowCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
838
                                  virStoragePoolObjPtr pool,
839
                                  virStorageVolDefPtr vol,
840 841
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags ATTRIBUTE_UNUSED)
842
{
843
    int ret;
E
Eric Blake 已提交
844
    char *size;
845 846 847
    const char *imgargv[4];

    if (inputvol) {
848
        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
849 850 851 852
                              _("cannot copy from volume with qcow-create"));
        return -1;
    }

853
    if (vol->target.format != VIR_STORAGE_FILE_QCOW2) {
854
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
855 856 857 858 859
                              _("unsupported storage vol type %d"),
                              vol->target.format);
        return -1;
    }
    if (vol->backingStore.path != NULL) {
860
        virStorageReportError(VIR_ERR_NO_SUPPORT, "%s",
861
                              _("copy-on-write image not supported with "
862
                                      "qcow-create"));
863 864
        return -1;
    }
865
    if (vol->target.encryption != NULL) {
866
        virStorageReportError(VIR_ERR_NO_SUPPORT,
867 868 869 870
                              "%s", _("encrypted volumes not supported with "
                                      "qcow-create"));
        return -1;
    }
871 872

    /* Size in MB - yes different units to qemu-img :-( */
E
Eric Blake 已提交
873 874 875 876
    if (virAsprintf(&size, "%llu", vol->capacity / 1024 / 1024) < 0) {
        virReportOOMError();
        return -1;
    }
877 878 879 880 881 882

    imgargv[0] = virFindFileInPath("qcow-create");
    imgargv[1] = size;
    imgargv[2] = vol->target.path;
    imgargv[3] = NULL;

883
    ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
884
    VIR_FREE(imgargv[0]);
E
Eric Blake 已提交
885
    VIR_FREE(size);
886

887
    return ret;
888 889
}

890
virStorageBackendBuildVolFrom
891
virStorageBackendFSImageToolTypeToFunc(int tool_type)
892 893 894 895 896 897 898 899
{
    switch (tool_type) {
    case TOOL_KVM_IMG:
    case TOOL_QEMU_IMG:
        return virStorageBackendCreateQemuImg;
    case TOOL_QCOW_CREATE:
        return virStorageBackendCreateQcowCreate;
    default:
900
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
                              _("Unknown file create tool type '%d'."),
                              tool_type);
    }

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

930
virStorageBackendBuildVolFrom
931
virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol,
932 933 934 935 936 937 938 939 940 941 942
                                         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 &&
943
         vol->target.format != VIR_STORAGE_FILE_RAW) ||
944
        (inputvol->type == VIR_STORAGE_VOL_FILE &&
945
         inputvol->target.format != VIR_STORAGE_FILE_RAW)) {
946

D
Daniel P. Berrange 已提交
947
        if ((tool_type = virStorageBackendFindFSImageTool(NULL)) < 0) {
948
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
949 950 951 952 953
                                  "%s", _("creation of non-raw file images is "
                                          "not supported without qemu-img."));
            return NULL;
        }

954
        return virStorageBackendFSImageToolTypeToFunc(tool_type);
955 956
    }

957 958 959 960
    if (vol->type == VIR_STORAGE_VOL_BLOCK)
        return virStorageBackendCreateBlockFrom;
    else
        return virStorageBackendCreateRaw;
961
}
962

963

964 965
virStorageBackendPtr
virStorageBackendForType(int type) {
966
    unsigned int i;
967
    for (i = 0; backends[i]; i++)
968 969 970
        if (backends[i]->type == type)
            return backends[i];

971
    virStorageReportError(VIR_ERR_INTERNAL_ERROR,
972 973 974 975 976
                          _("missing backend for pool type %d"), type);
    return NULL;
}


977 978 979
/*
 * Allows caller to silently ignore files with improper mode
 *
980 981
 * Returns -1 on error, -2 if file mode is unexpected or the
 * volume is a dangling symbolic link.
982
 */
983
int
984
virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags)
985
{
986 987
    int fd, mode = 0;
    struct stat sb;
988

989
    if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
990 991 992 993 994 995
        if ((errno == ENOENT || errno == ELOOP) &&
            lstat(path, &sb) == 0) {
            VIR_WARN("ignoring dangling symlink '%s'", path);
            return -2;
        }

996
        virReportSystemError(errno,
997
                             _("cannot open volume '%s'"),
998
                             path);
999 1000 1001
        return -1;
    }

1002 1003 1004 1005
    if (fstat(fd, &sb) < 0) {
        virReportSystemError(errno,
                             _("cannot stat file '%s'"),
                             path);
1006
        VIR_FORCE_CLOSE(fd);
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
        return -1;
    }

    if (S_ISREG(sb.st_mode))
        mode = VIR_STORAGE_VOL_OPEN_REG;
    else if (S_ISCHR(sb.st_mode))
        mode = VIR_STORAGE_VOL_OPEN_CHAR;
    else if (S_ISBLK(sb.st_mode))
        mode = VIR_STORAGE_VOL_OPEN_BLOCK;

    if (!(mode & flags)) {
1018
        VIR_FORCE_CLOSE(fd);
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048

        if (mode & VIR_STORAGE_VOL_OPEN_ERROR) {
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                  _("unexpected storage mode for '%s'"), path);
            return -1;
        }

        return -2;
    }

    return fd;
}

int virStorageBackendVolOpen(const char *path)
{
    return virStorageBackendVolOpenCheckMode(path,
                                             VIR_STORAGE_VOL_OPEN_DEFAULT);
}

int
virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target,
                                     unsigned long long *allocation,
                                     unsigned long long *capacity)
{
    int ret, fd;

    if ((ret = virStorageBackendVolOpen(target->path)) < 0)
        return ret;

    fd = ret;
1049
    ret = virStorageBackendUpdateVolTargetInfoFD(target,
1050 1051 1052
                                                 fd,
                                                 allocation,
                                                 capacity);
1053

1054
    VIR_FORCE_CLOSE(fd);
1055 1056 1057 1058

    return ret;
}

1059
int
1060
virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
1061 1062 1063 1064
                               int withCapacity)
{
    int ret;

1065
    if ((ret = virStorageBackendUpdateVolTargetInfo(&vol->target,
1066 1067 1068 1069 1070
                                                    &vol->allocation,
                                                    withCapacity ? &vol->capacity : NULL)) < 0)
        return ret;

    if (vol->backingStore.path &&
1071
        (ret = virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
1072 1073 1074 1075 1076 1077
                                                    NULL, NULL)) < 0)
        return ret;

    return 0;
}

1078 1079 1080 1081
/*
 * virStorageBackendUpdateVolTargetInfoFD:
 * @conn: connection to report errors on
 * @target: target definition ptr of volume to update
1082
 * @fd: fd of storage volume to update, via virStorageBackendOpenVol*
1083 1084 1085
 * @allocation: If not NULL, updated allocation information will be stored
 * @capacity: If not NULL, updated capacity info will be stored
 *
1086
 * Returns 0 for success, -1 on a legitimate error condition.
1087
 */
1088
int
1089
virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
1090 1091 1092
                                       int fd,
                                       unsigned long long *allocation,
                                       unsigned long long *capacity)
1093 1094 1095 1096 1097 1098 1099
{
    struct stat sb;
#if HAVE_SELINUX
    security_context_t filecon = NULL;
#endif

    if (fstat(fd, &sb) < 0) {
1100
        virReportSystemError(errno,
1101
                             _("cannot stat file '%s'"),
1102
                             target->path);
1103 1104 1105
        return -1;
    }

1106 1107
    if (allocation) {
        if (S_ISREG(sb.st_mode)) {
1108
#ifndef WIN32
1109
            *allocation = (unsigned long long)sb.st_blocks *
1110
                          (unsigned long long)DEV_BSIZE;
D
Daniel P. Berrange 已提交
1111
#else
1112
            *allocation = sb.st_size;
D
Daniel P. Berrange 已提交
1113
#endif
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
            /* Regular files may be sparse, so logical size (capacity) is not same
             * as actual allocation above
             */
            if (capacity)
                *capacity = sb.st_size;
        } else {
            off_t end;
            /* XXX this is POSIX compliant, but doesn't work for 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) {
1128
                virReportSystemError(errno,
1129 1130 1131 1132 1133 1134 1135
                                     _("cannot seek to end of file '%s'"),
                                     target->path);
                return -1;
            }
            *allocation = end;
            if (capacity)
                *capacity = end;
1136 1137 1138
        }
    }

1139 1140 1141
    target->perms.mode = sb.st_mode & S_IRWXUGO;
    target->perms.uid = sb.st_uid;
    target->perms.gid = sb.st_gid;
1142

1143
    VIR_FREE(target->perms.label);
1144 1145

#if HAVE_SELINUX
1146
    /* XXX: make this a security driver call */
1147
    if (fgetfilecon(fd, &filecon) == -1) {
1148
        if (errno != ENODATA && errno != ENOTSUP) {
1149
            virReportSystemError(errno,
1150
                                 _("cannot get file context of '%s'"),
1151
                                 target->path);
1152 1153
            return -1;
        } else {
1154
            target->perms.label = NULL;
1155 1156
        }
    } else {
1157
        target->perms.label = strdup(filecon);
1158
        freecon(filecon);
1159
        if (target->perms.label == NULL) {
1160
            virReportOOMError();
1161 1162
            return -1;
        }
1163 1164
    }
#else
1165
    target->perms.label = NULL;
1166 1167 1168 1169 1170
#endif

    return 0;
}

D
Dave Allan 已提交
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205

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


int
1206 1207
virStorageBackendDetectBlockVolFormatFD(virStorageVolTargetPtr target,
                                        int fd)
D
Dave Allan 已提交
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
{
    int 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) {
1219
        virReportSystemError(errno,
D
Dave Allan 已提交
1220 1221 1222 1223 1224 1225
                             _("cannot seek to beginning of file '%s'"),
                             target->path);
        return -1;
    }
    bytes = saferead(fd, buffer, sizeof(buffer));
    if (bytes < 0) {
1226
        virReportSystemError(errno,
D
Dave Allan 已提交
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
                             _("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;
}


1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
/*
 * 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.
 */
char *
1260
virStorageBackendStablePath(virStoragePoolObjPtr pool,
1261
                            const char *devpath)
1262 1263 1264
{
    DIR *dh;
    struct dirent *dent;
1265
    char *stablepath;
1266
    int opentries = 0;
1267 1268 1269 1270 1271

    /* 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/"))
1272
        goto ret_strdup;
1273

1274 1275 1276 1277 1278 1279
    /* Skip whole thing for a pool which isn't in /dev
     * so we don't mess will filesystem/dir based pools
     */
    if (!STRPREFIX(pool->def->target.path, "/dev"))
        goto ret_strdup;

1280 1281 1282
    /* 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.
1283
     */
1284
 reopen:
1285
    if ((dh = opendir(pool->def->target.path)) == NULL) {
1286 1287 1288 1289 1290
        opentries++;
        if (errno == ENOENT && opentries < 50) {
            usleep(100 * 1000);
            goto reopen;
        }
1291
        virReportSystemError(errno,
1292 1293
                             _("cannot read dir '%s'"),
                             pool->def->target.path);
1294 1295 1296
        return NULL;
    }

1297 1298 1299 1300 1301
    /* 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
     * to this device node
     */
1302 1303 1304 1305
    while ((dent = readdir(dh)) != NULL) {
        if (dent->d_name[0] == '.')
            continue;

1306 1307 1308
        if (virAsprintf(&stablepath, "%s/%s",
                        pool->def->target.path,
                        dent->d_name) == -1) {
1309
            virReportOOMError();
1310 1311 1312 1313 1314 1315 1316 1317 1318
            closedir(dh);
            return NULL;
        }

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

1319
        VIR_FREE(stablepath);
1320 1321 1322 1323
    }

    closedir(dh);

1324
 ret_strdup:
1325 1326 1327
    /* Couldn't find any matching stable link so give back
     * the original non-stable dev path
     */
1328 1329 1330 1331

    stablepath = strdup(devpath);

    if (stablepath == NULL)
1332
        virReportOOMError();
1333 1334

    return stablepath;
1335 1336
}

D
Daniel P. Berrange 已提交
1337

1338
#ifndef WIN32
1339 1340 1341 1342
/*
 * Run an external program.
 *
 * Read its output and apply a series of regexes to each line
R
Richard W.M. Jones 已提交
1343
 * When the entire set of regexes has matched consecutively
1344 1345 1346
 * then run a callback passing in all the matches
 */
int
1347
virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
1348
                              const char *const*prog,
1349 1350 1351 1352
                              int nregex,
                              const char **regex,
                              int *nvars,
                              virStorageBackendListVolRegexFunc func,
1353 1354
                              void *data,
                              int *outexit)
1355
{
1356 1357
    int fd = -1, exitstatus, err, failed = 1;
    pid_t child = 0;
1358 1359 1360 1361 1362 1363 1364 1365 1366
    FILE *list = NULL;
    regex_t *reg;
    regmatch_t *vars = NULL;
    char line[1024];
    int maxReg = 0, i, j;
    int totgroups = 0, ngroup = 0, maxvars = 0;
    char **groups;

    /* Compile all regular expressions */
1367
    if (VIR_ALLOC_N(reg, nregex) < 0) {
1368
        virReportOOMError();
1369 1370 1371 1372 1373 1374 1375 1376
        return -1;
    }

    for (i = 0 ; i < nregex ; i++) {
        err = regcomp(&reg[i], regex[i], REG_EXTENDED);
        if (err != 0) {
            char error[100];
            regerror(err, &reg[i], error, sizeof(error));
1377
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1378 1379 1380
                                  _("Failed to compile regex %s"), error);
            for (j = 0 ; j <= i ; j++)
                regfree(&reg[j]);
1381
            VIR_FREE(reg);
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
            return -1;
        }

        totgroups += nvars[i];
        if (nvars[i] > maxvars)
            maxvars = nvars[i];

    }

    /* Storage for matched variables */
1392
    if (VIR_ALLOC_N(groups, totgroups) < 0) {
1393
        virReportOOMError();
1394 1395
        goto cleanup;
    }
1396
    if (VIR_ALLOC_N(vars, maxvars+1) < 0) {
1397
        virReportOOMError();
1398 1399 1400 1401 1402
        goto cleanup;
    }


    /* Run the program and capture its output */
1403
    if (virExec(prog, NULL, NULL,
1404
                &child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) {
1405 1406 1407
        goto cleanup;
    }

1408
    if ((list = VIR_FDOPEN(fd, "r")) == NULL) {
1409
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1410
                              "%s", _("cannot read fd"));
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
        goto cleanup;
    }

    while (fgets(line, sizeof(line), list) != NULL) {
        /* Strip trailing newline */
        int len = strlen(line);
        if (len && line[len-1] == '\n')
            line[len-1] = '\0';

        for (i = 0 ; i <= maxReg && i < nregex ; i++) {
            if (regexec(&reg[i], line, nvars[i]+1, vars, 0) == 0) {
                maxReg++;

                if (i == 0)
                    ngroup = 0;

                /* NULL terminate each captured group in the line */
                for (j = 0 ; j < nvars[i] ; j++) {
                    /* NB vars[0] is the full pattern, so we offset j by 1 */
                    line[vars[j+1].rm_eo] = '\0';
                    if ((groups[ngroup++] =
                         strdup(line + vars[j+1].rm_so)) == NULL) {
1433
                        virReportOOMError();
1434 1435 1436 1437 1438 1439
                        goto cleanup;
                    }
                }

                /* We're matching on the last regex, so callback time */
                if (i == (nregex-1)) {
1440
                    if (((*func)(pool, groups, data)) < 0)
1441 1442 1443
                        goto cleanup;

                    /* Release matches & restart to matching the first regex */
1444
                    for (j = 0 ; j < totgroups ; j++)
1445
                        VIR_FREE(groups[j]);
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
                    maxReg = 0;
                    ngroup = 0;
                }
            }
        }
    }

    failed = 0;

 cleanup:
    if (groups) {
        for (j = 0 ; j < totgroups ; j++)
1458 1459
            VIR_FREE(groups[j]);
        VIR_FREE(groups);
1460
    }
1461
    VIR_FREE(vars);
1462 1463 1464 1465

    for (i = 0 ; i < nregex ; i++)
        regfree(&reg[i]);

1466
    VIR_FREE(reg);
1467

1468 1469
    VIR_FORCE_FCLOSE(list);
    VIR_FORCE_CLOSE(fd);
1470 1471 1472 1473 1474 1475 1476 1477

    while ((err = waitpid(child, &exitstatus, 0) == -1) && errno == EINTR);

    /* Don't bother checking exit status if we already failed */
    if (failed)
        return -1;

    if (err == -1) {
1478
        virReportSystemError(errno,
1479 1480
                             _("failed to wait for command '%s'"),
                             prog[0]);
1481 1482 1483
        return -1;
    } else {
        if (WIFEXITED(exitstatus)) {
1484 1485
            if (outexit != NULL)
                *outexit = WEXITSTATUS(exitstatus);
1486
        } else {
1487
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1488
                                  "%s", _("command did not exit cleanly"));
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507
            return -1;
        }
    }

    return 0;
}

/*
 * Run an external program and read from its standard output
 * a stream of tokens from IN_STREAM, applying FUNC to
 * each successive sequence of N_COLUMNS tokens.
 * If FUNC returns < 0, stop processing input and return -1.
 * Return -1 if N_COLUMNS == 0.
 * Return -1 upon memory allocation error.
 * If the number of input tokens is not a multiple of N_COLUMNS,
 * then the final FUNC call will specify a number smaller than N_COLUMNS.
 * If there are no input tokens (empty input), call FUNC with N_COLUMNS == 0.
 */
int
1508
virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
1509 1510 1511 1512 1513 1514
                            const char **prog,
                            size_t n_columns,
                            virStorageBackendListVolNulFunc func,
                            void *data)
{
    size_t n_tok = 0;
1515 1516
    int fd = -1, exitstatus;
    pid_t child = 0;
1517 1518 1519 1520 1521 1522 1523 1524 1525
    FILE *fp = NULL;
    char **v;
    int err = -1;
    int w_err;
    int i;

    if (n_columns == 0)
        return -1;

1526
    if (VIR_ALLOC_N(v, n_columns) < 0) {
1527
        virReportOOMError();
1528 1529 1530 1531 1532 1533
        return -1;
    }
    for (i = 0; i < n_columns; i++)
        v[i] = NULL;

    /* Run the program and capture its output */
1534
    if (virExec(prog, NULL, NULL,
1535
                &child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) {
1536 1537 1538
        goto cleanup;
    }

1539
    if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
1540
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1541
                              "%s", _("cannot open file using fd"));
1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
        goto cleanup;
    }

    while (1) {
        char *buf = NULL;
        size_t buf_len = 0;
        /* Be careful: even when it returns -1,
           this use of getdelim allocates memory.  */
        ssize_t tok_len = getdelim (&buf, &buf_len, 0, fp);
        v[n_tok] = buf;
        if (tok_len < 0) {
            /* Maybe EOF, maybe an error.
               If n_tok > 0, then we know it's an error.  */
1555
            if (n_tok && func (pool, n_tok, v, data) < 0)
1556 1557 1558 1559 1560
                goto cleanup;
            break;
        }
        ++n_tok;
        if (n_tok == n_columns) {
1561
            if (func (pool, n_tok, v, data) < 0)
1562 1563 1564
                goto cleanup;
            n_tok = 0;
            for (i = 0; i < n_columns; i++) {
1565
                VIR_FREE(v[i]);
1566 1567 1568 1569 1570 1571 1572
            }
        }
    }

    if (feof (fp))
        err = 0;
    else
1573
        virReportSystemError(errno,
1574
                             _("read error on pipe to '%s'"), prog[0]);
1575 1576 1577

 cleanup:
    for (i = 0; i < n_columns; i++)
1578 1579
        VIR_FREE(v[i]);
    VIR_FREE(v);
1580

1581 1582
    VIR_FORCE_FCLOSE(fp);
    VIR_FORCE_CLOSE(fd);
1583 1584 1585 1586 1587 1588 1589 1590 1591

    while ((w_err = waitpid (child, &exitstatus, 0) == -1) && errno == EINTR)
        /* empty */ ;

    /* Don't bother checking exit status if we already failed */
    if (err < 0)
        return -1;

    if (w_err == -1) {
1592
        virReportSystemError(errno,
1593 1594
                             _("failed to wait for command '%s'"),
                             prog[0]);
1595 1596 1597 1598
        return -1;
    } else {
        if (WIFEXITED(exitstatus)) {
            if (WEXITSTATUS(exitstatus) != 0) {
1599
                virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1600 1601 1602 1603 1604
                                      _("non-zero exit status from command %d"),
                                      WEXITSTATUS(exitstatus));
                return -1;
            }
        } else {
1605
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1606
                                  "%s", _("command did not exit cleanly"));
1607 1608 1609 1610 1611 1612
            return -1;
        }
    }

    return 0;
}
D
Daniel P. Berrange 已提交
1613

1614
#else /* WIN32 */
D
Daniel P. Berrange 已提交
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626

int
virStorageBackendRunProgRegex(virConnectPtr conn,
                              virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                              const char *const*prog ATTRIBUTE_UNUSED,
                              int nregex ATTRIBUTE_UNUSED,
                              const char **regex ATTRIBUTE_UNUSED,
                              int *nvars ATTRIBUTE_UNUSED,
                              virStorageBackendListVolRegexFunc func ATTRIBUTE_UNUSED,
                              void *data ATTRIBUTE_UNUSED,
                              int *outexit ATTRIBUTE_UNUSED)
{
1627
    virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("%s not implemented on Win32"), __FUNCTION__);
D
Daniel P. Berrange 已提交
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
    return -1;
}

int
virStorageBackendRunProgNul(virConnectPtr conn,
                            virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                            const char **prog ATTRIBUTE_UNUSED,
                            size_t n_columns ATTRIBUTE_UNUSED,
                            virStorageBackendListVolNulFunc func ATTRIBUTE_UNUSED,
                            void *data ATTRIBUTE_UNUSED)
{
1639
    virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("%s not implemented on Win32"), __FUNCTION__);
D
Daniel P. Berrange 已提交
1640 1641
    return -1;
}
1642
#endif /* WIN32 */