Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 00/10] New API: disk-create for creating blank disks.
A lot of code runs 'qemu-img create' or 'truncate' to create blank disk images. In the past I resisted adding an API to do this, since it essentially duplicates what you can already do using other tools (ie. qemu-img). However this does simplify calling code quite a lot since qemu-img is somewhat error-prone to use (eg: don't try to create a disk called "foo:bar") and it's generally hard to safely construct and run external commands from C. This is in preparation for finishing off the virt-make-fs rewrite (patch coming later). Rich.
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 01/10] src/Makefile.am: Reorder SOURCES into alphabetical order.
--- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index f5c8d2d..ba02061 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,8 +87,8 @@ libguestfs_la_SOURCES = \ alloc.c \ appliance.c \ bindtests.c \ - command.c \ canonical-name.c \ + command.c \ conn-socket.c \ dbdump.c \ drives.c \ -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 02/10] New API: disk-create for creating blank disks.
This is a wrapper around either 'qemu-img create' or calls to open, truncate and posix_fallocate which litter and complicate existing code. --- Makefile.am | 1 + configure.ac | 1 + generator/actions.ml | 52 ++++++- gobject/Makefile.inc | 2 + po/POTFILES | 2 + src/Makefile.am | 1 + src/create.c | 319 +++++++++++++++++++++++++++++++++++++++ tests/create/Makefile.am | 27 ++++ tests/create/test-disk-create.sh | 48 ++++++ 9 files changed, 451 insertions(+), 2 deletions(-) create mode 100644 src/create.c create mode 100644 tests/create/Makefile.am create mode 100755 tests/create/test-disk-create.sh diff --git a/Makefile.am b/Makefile.am index e39d11f..5b8f109 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,7 @@ SUBDIRS += tests/tmpdirs SUBDIRS += tests/protocol SUBDIRS += tests/events SUBDIRS += tests/parallel +SUBDIRS += tests/create SUBDIRS += tests/disks SUBDIRS += tests/mountable SUBDIRS += tests/network diff --git a/configure.ac b/configure.ac index c07462e..df8e962 100644 --- a/configure.ac +++ b/configure.ac @@ -1745,6 +1745,7 @@ AC_CONFIG_FILES([Makefile tests/btrfs/Makefile tests/c-api/Makefile tests/charsets/Makefile + tests/create/Makefile tests/data/Makefile tests/disks/Makefile tests/disks/test-qemu-drive-libvirt.xml diff --git a/generator/actions.ml b/generator/actions.ml index fa1a2c5..3637da0 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -3093,6 +3093,54 @@ Return the current backend settings. See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." }; + { defaults with + name = "disk_create"; + style = RErr, [String "filename"; String "format"; Int64 "size"], [OString "backingfile"; OString "backingformat"; OString "preallocation"; OString "compat"; OInt "clustersize"]; + test_excuse = "tests in tests/create subdirectory"; + shortdesc = "create a blank disk image"; + longdesc = "\ +Create a blank disk image called C<filename> (a host file or device) +with format C<format> (usually C<raw> or C<qcow2>, but other formats +are possible). The size is C<size> bytes. + +If used with the optional C<backingfile> parameter, then a snapshot +is created on top of the backing file. In this case, C<size> must +be passed as C<-1>. The size of the snapshot is the same as the +size of the backing file, which is discovered automatically. You +are encouraged to also pass C<backingformat> to describe the format +of C<backingfile>. + +The other optional parameters are: + +=over 4 + +=item C<preallocation> + +If format is C<raw>, then this can be either C<sparse> or C<full> +to create a sparse or fully allocated file respectively. The default +is C<sparse>. + +If format is C<qcow2>, then this can be either C<off> or +C<metadata>. Preallocating metadata can be faster when doing lots +of writes, but uses more space. + +=item C<compat> + +C<qcow2> only: +Pass the string C<1.1> to use the advanced qcow2 format supported +by qemu E<ge> 1.1. + +=item C<clustersize> + +C<qcow2> only: +Change the qcow2 cluster size. The default is 65536 (bytes) and +this settig may be any power of two between 512 and 2097152. + +=back + +Note that this call does not add the new disk to the handle. You +may need to call C<guestfs_add_drive_opts> separately." }; + ] (* daemon_functions are any functions which cause some action @@ -11739,7 +11787,7 @@ let fish_commands = [ This creates an empty (zeroed) file of the given size, and then adds so it can be further examined. -For more advanced image creation, see L<qemu-img(1)> utility. +For more advanced image creation, see L</disk-create>. Size can be specified using standard suffixes, eg. C<1M>. @@ -11983,7 +12031,7 @@ not assigned to the file until they are needed. Sparse disk files only use space when written to, but they are slower and there is a danger you could run out of real disk space during a write operation. -For more advanced image creation, see L<qemu-img(1)> utility. +For more advanced image creation, see L</disk-create>. Size can be specified using standard suffixes, eg. C<1M>. diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index 7024754..7a8493a 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -52,6 +52,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-mount_local.h \ include/guestfs-gobject/optargs-umount_local.h \ include/guestfs-gobject/optargs-add_drive_scratch.h \ + include/guestfs-gobject/optargs-disk_create.h \ include/guestfs-gobject/optargs-is_file.h \ include/guestfs-gobject/optargs-is_dir.h \ include/guestfs-gobject/optargs-umount.h \ @@ -127,6 +128,7 @@ guestfs_gobject_sources= \ src/optargs-mount_local.c \ src/optargs-umount_local.c \ src/optargs-add_drive_scratch.c \ + src/optargs-disk_create.c \ src/optargs-is_file.c \ src/optargs-is_dir.c \ src/optargs-umount.c \ diff --git a/po/POTFILES b/po/POTFILES index c6277e9..76d1b1d 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -170,6 +170,7 @@ gobject/src/optargs-copy_device_to_device.c gobject/src/optargs-copy_device_to_file.c gobject/src/optargs-copy_file_to_device.c gobject/src/optargs-copy_file_to_file.c +gobject/src/optargs-disk_create.c gobject/src/optargs-e2fsck.c gobject/src/optargs-fstrim.c gobject/src/optargs-grep.c @@ -267,6 +268,7 @@ src/canonical-name.c src/cleanup.c src/command.c src/conn-socket.c +src/create.c src/dbdump.c src/drives.c src/errnostring-gperf.c diff --git a/src/Makefile.am b/src/Makefile.am index ba02061..4475281 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -90,6 +90,7 @@ libguestfs_la_SOURCES = \ canonical-name.c \ command.c \ conn-socket.c \ + create.c \ dbdump.c \ drives.c \ errors.c \ diff --git a/src/create.c b/src/create.c new file mode 100644 index 0000000..18c4402 --- /dev/null +++ b/src/create.c @@ -0,0 +1,319 @@ +/* libguestfs + * Copyright (C) 2012 Red Hat Inc. + * + * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <errno.h> + +#include "guestfs.h" +#include "guestfs-internal.h" +#include "guestfs-internal-actions.h" +#include "guestfs_protocol.h" + +static int disk_create_raw (guestfs_h *g, const char *filename, int64_t size, const struct guestfs_disk_create_argv *optargs); +static int disk_create_qcow2 (guestfs_h *g, const char *filename, int64_t size, const char *backingfile, const struct guestfs_disk_create_argv *optargs); +static char *qemu_escape_param (guestfs_h *g, const char *param); + +int +guestfs__disk_create (guestfs_h *g, const char *filename, + const char *format, int64_t size, + const struct guestfs_disk_create_argv *optargs) +{ + const char *backingfile; + + backingfile = optargs->bitmask & GUESTFS_DISK_CREATE_BACKINGFILE_BITMASK ? + optargs->backingfile : NULL; + + /* Ensure size is valid. */ + if (backingfile) { + if (size != -1) { + error (g, _("if using a backing file, size must be passed as -1")); + return -1; + } + } else { + /* XXX Actually size == 0 could be valid, although not useful and + * it causes qemu to break. + */ + if (size <= 0) { + error (g, _("invalid size: %" PRIi64), size); + return -1; + } + } + + /* Now the format-specific code. */ + if (STREQ (format, "raw")) { + if (backingfile) { + error (g, _("backingfile cannot be used for raw format disks")); + return -1; + } + if (disk_create_raw (g, filename, size, optargs) == -1) + return -1; + } + else if (STREQ (format, "qcow2")) { + if (disk_create_qcow2 (g, filename, size, backingfile, optargs) == -1) + return -1; + } + else { + /* Be conservative about what formats we support, since we don't + * want to make unlimited promises through the API. We can always + * add more later. + */ + error (g, _("unsupported format '%s'"), format); + return -1; + } + + return 0; +} + +static int +disk_create_raw (guestfs_h *g, const char *filename, int64_t size, + const struct guestfs_disk_create_argv *optargs) +{ + int allocated = 0; + int fd; + struct stat statbuf; + + /* backingfile parameter not present checked above */ + + if (optargs->bitmask & GUESTFS_DISK_CREATE_BACKINGFORMAT_BITMASK) { + error (g, _("backingformat parameter cannot be used with raw format")); + return -1; + } + if (optargs->bitmask & GUESTFS_DISK_CREATE_PREALLOCATION_BITMASK) { + if (STREQ (optargs->preallocation, "sparse")) + allocated = 0; + else if (STREQ (optargs->preallocation, "full")) + allocated = 1; + else { + error (g, _("invalid value for preallocation parameter '%s'"), + optargs->preallocation); + return -1; + } + } + if (optargs->bitmask & GUESTFS_DISK_CREATE_COMPAT_BITMASK) { + error (g, _("compat parameter cannot be used with raw format")); + return -1; + } + if (optargs->bitmask & GUESTFS_DISK_CREATE_CLUSTERSIZE_BITMASK) { + error (g, _("clustersize parameter cannot be used with raw format")); + return -1; + } + + /* This version refuses the overwrite block devices or char devices. + * XXX It would be possible to make it work with block devices. + */ + if (stat (filename, &statbuf) == 0) { + if (S_ISBLK (statbuf.st_mode)) { + error (g, _("refusing to overwrite block device '%s'"), filename); + return -1; + } + if (S_ISCHR (statbuf.st_mode)) { + error (g, _("refusing to overwrite char device '%s'"), filename); + return -1; + } + } + + fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC|O_CLOEXEC, 0666); + if (fd == -1) { + perrorf (g, _("cannot create raw file: %s"), filename); + return -1; + } + + if (!allocated) { /* Sparse file. */ + if (ftruncate (fd, size) == -1) { + perrorf (g, _("%s: truncate"), filename); + close (fd); + unlink (filename); + return -1; + } + } + else { /* Allocated file. */ +#ifdef HAVE_POSIX_FALLOCATE + int err; + + err = posix_fallocate (fd, 0, size); + if (err != 0) { + errno = err; + perrorf (g, _("%s: fallocate"), filename); + close (fd); + unlink (filename); + return -1; + } +#else + /* Slow emulation of posix_fallocate on platforms which don't have it. */ + char buffer[BUFSIZ]; + size_t remaining = size; + size_t n; + ssize_t r; + + memset (buffer, 0, sizeof buffer); + + while (remaining > 0) { + n = remaining > sizeof buffer ? sizeof buffer : remaining; + r = write (fd, buffer, n); + if (r == -1) { + perrorf (g, _("%s: write"), filename); + close (fd); + unlink (filename); + return -1; + } + remaining -= r; + } +#endif + } + + if (close (fd) == -1) { + perrorf (g, _("%s: close"), filename); + unlink (filename); + return -1; + } + + return 0; +} + +/* http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 */ +static int +is_power_of_2 (unsigned v) +{ + return v && ((v & (v - 1)) == 0); +} + +static int +disk_create_qcow2 (guestfs_h *g, const char *orig_filename, int64_t size, + const char *backingfile, + const struct guestfs_disk_create_argv *optargs) +{ + CLEANUP_FREE char *filename = NULL; + const char *backingformat = NULL; + const char *preallocation = NULL; + const char *compat = NULL; + int clustersize = -1; + CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (optionsv); + CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g); + int r; + + /* If the filename is something like "file:foo" then qemu-img will + * try to interpret that as "foo" in the file:/// protocol. To + * avoid that, if the path is relative prefix it with "./" since + * qemu-img won't try to interpret such a path. + */ + if (orig_filename[0] != '/') + filename = safe_asprintf (g, "./%s", orig_filename); + else + filename = safe_strdup (g, orig_filename); + + if (optargs->bitmask & GUESTFS_DISK_CREATE_BACKINGFORMAT_BITMASK) { + backingformat = optargs->backingformat; + if (STRNEQ (backingformat, "raw") && STRNEQ (backingformat, "qcow2")) { + error (g, _("invalid value for backingformat parameter '%s'"), + backingformat); + return -1; + } + } + if (optargs->bitmask & GUESTFS_DISK_CREATE_PREALLOCATION_BITMASK) { + preallocation = optargs->preallocation; + if (STRNEQ (preallocation, "off") && STRNEQ (preallocation, "metadata")) { + error (g, _("invalid value for preallocation parameter '%s'"), + preallocation); + return -1; + } + } + if (optargs->bitmask & GUESTFS_DISK_CREATE_COMPAT_BITMASK) { + compat = optargs->compat; + if (STRNEQ (compat, "0.10") && STRNEQ (compat, "1.1")) { + error (g, _("invalid value for compat parameter '%s'"), compat); + return -1; + } + } + if (optargs->bitmask & GUESTFS_DISK_CREATE_CLUSTERSIZE_BITMASK) { + clustersize = optargs->clustersize; + if (clustersize < 512 || clustersize > 2097152 || + !is_power_of_2 ((unsigned) clustersize)) { + error (g, _("invalid value for clustersize parameter '%d'"), + clustersize); + return -1; + } + } + + /* Assemble the qemu-img command line. */ + guestfs___cmd_add_arg (cmd, "qemu-img"); + guestfs___cmd_add_arg (cmd, "create"); + guestfs___cmd_add_arg (cmd, "-f"); + guestfs___cmd_add_arg (cmd, "qcow2"); + + /* -o parameter. */ + if (backingfile) { + CLEANUP_FREE char *p = qemu_escape_param (g, backingfile); + guestfs___add_sprintf (g, &optionsv, "backing_file=%s", p); + } + if (backingformat) + guestfs___add_sprintf (g, &optionsv, "backing_fmt=%s", backingformat); + if (preallocation) + guestfs___add_sprintf (g, &optionsv, "preallocation=%s", preallocation); + if (compat) + guestfs___add_sprintf (g, &optionsv, "compat=%s", compat); + if (clustersize >= 0) + guestfs___add_sprintf (g, &optionsv, "cluster_size=%d", clustersize); + guestfs___end_stringsbuf (g, &optionsv); + + if (optionsv.size > 1) { + CLEANUP_FREE char *options = guestfs___join_strings (",", optionsv.argv); + guestfs___cmd_add_arg (cmd, "-o"); + guestfs___cmd_add_arg (cmd, options); + } + + /* Complete the command line. */ + guestfs___cmd_add_arg (cmd, filename); + if (size >= 0) + guestfs___cmd_add_arg_format (cmd, "%" PRIi64, size); + + r = guestfs___cmd_run (cmd); + if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { + guestfs___external_command_failed (g, r, "qemu-img", orig_filename); + return -1; + } + + return 0; +} + +/* XXX Duplicated in launch-direct.c. */ +static char * +qemu_escape_param (guestfs_h *g, const char *param) +{ + size_t i, len = strlen (param); + char *p, *ret; + + ret = p = safe_malloc (g, len*2 + 1); /* max length of escaped name*/ + for (i = 0; i < len; ++i) { + *p++ = param[i]; + if (param[i] == ',') + *p++ = ','; + } + *p = '\0'; + + return ret; +} diff --git a/tests/create/Makefile.am b/tests/create/Makefile.am new file mode 100644 index 0000000..cdcecd2 --- /dev/null +++ b/tests/create/Makefile.am @@ -0,0 +1,27 @@ +# libguestfs +# Copyright (C) 2014 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +include $(top_srcdir)/subdir-rules.mk + +TESTS = \ + test-disk-create.sh + +TESTS_ENVIRONMENT = \ + $(top_builddir)/run --test + +EXTRA_DIST = \ + $(TESTS) diff --git a/tests/create/test-disk-create.sh b/tests/create/test-disk-create.sh new file mode 100755 index 0000000..b287233 --- /dev/null +++ b/tests/create/test-disk-create.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# Copyright (C) 2014 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Test the disk-create API. + +export LANG=C + +set -e + +rm -f disk*.img file:*.img + +# XXX We should also test failure paths. + +../../fish/guestfish <<EOF + disk-create disk1.img raw 256K + disk-create disk2.img raw 256K preallocation:sparse + disk-create disk3.img raw 256K preallocation:full + disk-create disk4.img qcow2 256K + disk-create disk5.img qcow2 256K preallocation:off + disk-create disk6.img qcow2 256K preallocation:metadata + disk-create disk7.img qcow2 256K compat:1.1 + disk-create disk8.img qcow2 256K clustersize:128K + disk-create disk9.img qcow2 -1 backingfile:disk1.img compat:1.1 + disk-create disk10.img qcow2 -1 backingfile:disk2.img backingformat:raw + disk-create disk11.img qcow2 -1 backingfile:disk4.img backingformat:qcow2 + + # Some annoying corner-cases in qemu-img. + disk-create disk:0.img qcow2 256K + disk-create file:0.img qcow2 256K + disk-create disk,0.img qcow2 256K + disk-create disk,,0.img qcow2 256K +EOF + +rm disk*.img file:*.img -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 03/10] lib: Use disk-create API instead of qemu-img/truncate inside the library.
--- src/drives.c | 35 ++++------------------------------- src/launch-direct.c | 37 ++++++++++++------------------------- src/launch-libvirt.c | 38 +++++++++++--------------------------- 3 files changed, 27 insertions(+), 83 deletions(-) diff --git a/src/drives.c b/src/drives.c index dd2b96c..733a6c4 100644 --- a/src/drives.c +++ b/src/drives.c @@ -509,7 +509,6 @@ create_drive_dev_null (guestfs_h *g, bool readonly, const char *format, const char *disk_label) { CLEANUP_FREE char *tmpfile = NULL; - int fd = -1; if (format && STRNEQ (format, "raw")) { error (g, _("for device '/dev/null', format must be 'raw'")); @@ -525,20 +524,9 @@ create_drive_dev_null (guestfs_h *g, bool readonly, const char *format, readonly = false; tmpfile = safe_asprintf (g, "%s/devnull%d", g->tmpdir, ++g->unique); - fd = open (tmpfile, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0600); - if (fd == -1) { - perrorf (g, "open: %s", tmpfile); + + if (guestfs_disk_create (g, tmpfile, "raw", 4096, -1) == -1) return NULL; - } - if (ftruncate (fd, 4096) == -1) { - perrorf (g, "truncate: %s", tmpfile); - close (fd); - return NULL; - } - if (close (fd) == -1) { - perrorf (g, "close: %s", tmpfile); - return NULL; - } return create_drive_file (g, tmpfile, readonly, format, iface, name, disk_label, 0); @@ -1083,11 +1071,10 @@ guestfs__add_drive_ro_with_if (guestfs_h *g, const char *filename, int guestfs__add_drive_scratch (guestfs_h *g, int64_t size, - const struct guestfs_add_drive_scratch_argv *optargs) + const struct guestfs_add_drive_scratch_argv *optargs) { struct guestfs_add_drive_opts_argv add_drive_optargs = { .bitmask = 0 }; CLEANUP_FREE char *filename = NULL; - int fd; /* Some parameters we always set. */ add_drive_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK; @@ -1114,22 +1101,8 @@ guestfs__add_drive_scratch (guestfs_h *g, int64_t size, filename = safe_asprintf (g, "%s/scratch.%d", g->tmpdir, ++g->unique); /* Create a raw format temporary disk. */ - fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0600); - if (fd == -1) { - perrorf (g, "open: %s", filename); + if (guestfs_disk_create (g, filename, "raw", size, -1) == -1) return -1; - } - - if (ftruncate (fd, size) == -1) { - perrorf (g, "ftruncate: %s", filename); - close (fd); - return -1; - } - - if (close (fd) == -1) { - perrorf (g, "close: %s", filename); - return -1; - } /* Call guestfs_add_drive_opts to add the drive. */ return guestfs_add_drive_opts_argv (g, filename, &add_drive_optargs); diff --git a/src/launch-direct.c b/src/launch-direct.c index 2b22ed0..964a507 100644 --- a/src/launch-direct.c +++ b/src/launch-direct.c @@ -107,48 +107,35 @@ static char *qemu_escape_param (guestfs_h *g, const char *param); static char * create_cow_overlay_direct (guestfs_h *g, void *datav, struct drive *drv) { - char *overlay = NULL; + char *overlay; CLEANUP_FREE char *backing_drive = NULL; - CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g); - int r; + struct guestfs_disk_create_argv optargs; backing_drive = guestfs___drive_source_qemu_param (g, &drv->src); if (!backing_drive) - goto error; + return NULL; if (guestfs___lazy_make_tmpdir (g) == -1) - goto error; + return NULL; overlay = safe_asprintf (g, "%s/overlay%d", g->tmpdir, ++g->unique); - guestfs___cmd_add_arg (cmd, "qemu-img"); - guestfs___cmd_add_arg (cmd, "create"); - guestfs___cmd_add_arg (cmd, "-f"); - guestfs___cmd_add_arg (cmd, "qcow2"); - guestfs___cmd_add_arg (cmd, "-b"); - guestfs___cmd_add_arg (cmd, backing_drive); + optargs.bitmask = GUESTFS_DISK_CREATE_BACKINGFILE_BITMASK; + optargs.backingfile = backing_drive; if (drv->src.format) { - guestfs___cmd_add_arg (cmd, "-o"); - guestfs___cmd_add_arg_format (cmd, "backing_fmt=%s", drv->src.format); + optargs.bitmask |= GUESTFS_DISK_CREATE_BACKINGFORMAT_BITMASK; + optargs.backingformat = drv->src.format; } - guestfs___cmd_add_arg (cmd, overlay); - r = guestfs___cmd_run (cmd); - if (r == -1) - goto error; - if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { - guestfs___external_command_failed (g, r, "qemu-img create", backing_drive); - goto error; + + if (guestfs_disk_create_argv (g, overlay, "qcow2", -1, &optargs) == -1) { + free (overlay); + return NULL; } /* Caller sets g->overlay in the handle to this, and then manages * the memory. */ return overlay; - - error: - free (overlay); - - return NULL; } #ifdef QEMU_OPTIONS diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c index 8cc261d..60213fd 100644 --- a/src/launch-libvirt.c +++ b/src/launch-libvirt.c @@ -145,33 +145,22 @@ static char * make_qcow2_overlay (guestfs_h *g, const char *backing_drive, const char *format) { - CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g); - char *overlay = NULL; - int r; + char *overlay; + struct guestfs_disk_create_argv optargs; if (guestfs___lazy_make_tmpdir (g) == -1) return NULL; overlay = safe_asprintf (g, "%s/overlay%d", g->tmpdir, ++g->unique); - guestfs___cmd_add_arg (cmd, "qemu-img"); - guestfs___cmd_add_arg (cmd, "create"); - guestfs___cmd_add_arg (cmd, "-f"); - guestfs___cmd_add_arg (cmd, "qcow2"); - guestfs___cmd_add_arg (cmd, "-b"); - guestfs___cmd_add_arg (cmd, backing_drive); + optargs.bitmask = GUESTFS_DISK_CREATE_BACKINGFILE_BITMASK; + optargs.backingfile = backing_drive; if (format) { - guestfs___cmd_add_arg (cmd, "-o"); - guestfs___cmd_add_arg_format (cmd, "backing_fmt=%s", format); + optargs.bitmask |= GUESTFS_DISK_CREATE_BACKINGFORMAT_BITMASK; + optargs.backingformat = format; } - guestfs___cmd_add_arg (cmd, overlay); - r = guestfs___cmd_run (cmd); - if (r == -1) { - free (overlay); - return NULL; - } - if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { - guestfs___external_command_failed (g, r, "qemu-img create", backing_drive); + + if (guestfs_disk_create_argv (g, overlay, "qcow2", -1, &optargs) == -1) { free (overlay); return NULL; } @@ -184,15 +173,15 @@ create_cow_overlay_libvirt (guestfs_h *g, void *datav, struct drive *drv) { struct backend_libvirt_data *data = datav; CLEANUP_FREE char *backing_drive = NULL; - char *overlay = NULL; + char *overlay; backing_drive = guestfs___drive_source_qemu_param (g, &drv->src); if (!backing_drive) - goto error; + return NULL; overlay = make_qcow2_overlay (g, backing_drive, drv->src.format); if (!overlay) - goto error; + return NULL; #if HAVE_LIBSELINUX if (data->selinux_imagelabel) { @@ -208,11 +197,6 @@ create_cow_overlay_libvirt (guestfs_h *g, void *datav, struct drive *drv) * the memory. */ return overlay; - - error: - free (overlay); - - return NULL; } static int -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 04/10] fish: Use disk-create API to implement guestfish 'alloc' and 'sparse' commands.
--- fish/Makefile.am | 1 + fish/alloc.c | 60 ++++-------------------------------------------------- fish/test-alloc.sh | 47 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 56 deletions(-) create mode 100755 fish/test-alloc.sh diff --git a/fish/Makefile.am b/fish/Makefile.am index 54ba875..c39c968 100644 --- a/fish/Makefile.am +++ b/fish/Makefile.am @@ -301,6 +301,7 @@ EXTRA_DIST += \ test-a.sh \ test-add-domain.sh \ test-add-uri.sh \ + test-alloc.sh \ test-copy.sh \ test-d.sh \ test-edit.sh \ diff --git a/fish/alloc.c b/fish/alloc.c index 18597f7..06dd8cf 100644 --- a/fish/alloc.c +++ b/fish/alloc.c @@ -66,67 +66,15 @@ int alloc_disk (const char *filename, const char *size_str, int add, int sparse) { off_t size; - int fd; - char c = 0; + const char *prealloc = sparse ? "sparse" : "full"; if (parse_size (size_str, &size) == -1) return -1; - fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC|O_CLOEXEC, 0666); - if (fd == -1) { - perror (filename); + if (guestfs_disk_create (g, filename, "raw", (int64_t) size, + GUESTFS_DISK_CREATE_PREALLOCATION, prealloc, + -1) == -1) return -1; - } - - if (!sparse) { /* Not sparse */ -#ifdef HAVE_POSIX_FALLOCATE - int err = posix_fallocate (fd, 0, size); - if (err != 0) { - errno = err; - perror ("fallocate"); - close (fd); - unlink (filename); - return -1; - } -#else - /* Slow emulation of posix_fallocate on platforms which don't have it. */ - char buffer[BUFSIZ]; - memset (buffer, 0, sizeof buffer); - - size_t remaining = size; - while (remaining > 0) { - size_t n = remaining > sizeof buffer ? sizeof buffer : remaining; - ssize_t r = write (fd, buffer, n); - if (r == -1) { - perror ("write"); - close (fd); - unlink (filename); - return -1; - } - remaining -= r; - } -#endif - } else { /* Sparse */ - if (lseek (fd, size-1, SEEK_SET) == (off_t) -1) { - perror ("lseek"); - close (fd); - unlink (filename); - return -1; - } - - if (write (fd, &c, 1) != 1) { - perror ("write"); - close (fd); - unlink (filename); - return -1; - } - } - - if (close (fd) == -1) { - perror (filename); - unlink (filename); - return -1; - } if (add) { if (guestfs_add_drive_opts (g, filename, diff --git a/fish/test-alloc.sh b/fish/test-alloc.sh new file mode 100755 index 0000000..3f46f8b --- /dev/null +++ b/fish/test-alloc.sh @@ -0,0 +1,47 @@ +#!/bin/bash - +# libguestfs +# Copyright (C) 2014 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Test guestfish alloc and sparse commands. + +set -e + +rm -f test-alloc.img + +$VG ./guestfish alloc test-alloc.img 200000 +if [ "$(stat -c '%s' test-alloc.img)" -ne 200000 ]; then + echo "$0: alloc command failed to create file of the correct size" + exit 1 +fi + +if [ "$(stat -c '%b' test-alloc.img)" -eq 0 ]; then + echo "$0: alloc command failed to create a fully allocated file" + exit 1 +fi + +$VG ./guestfish sparse test-alloc.img 100000 +if [ "$(stat -c '%s' test-alloc.img)" -ne 100000 ]; then + echo "$0: sparse command failed to create file of the correct size" + exit 1 +fi + +if [ "$(stat -c '%b' test-alloc.img)" -ne 0 ]; then + echo "$0: sparse command failed to create a sparse file" + exit 1 +fi + +rm test-alloc.img -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 05/10] examples: Update various examples to use new disk-create API.
--- examples/create-disk.c | 20 +++++--------------- examples/mount-local.c | 22 +++++----------------- golang/examples/create-disk.go | 12 ++---------- ocaml/examples/create_disk.ml | 4 +--- perl/examples/create_disk.pl | 4 +--- python/examples/create_disk.py | 5 +---- ruby/examples/create_disk.rb | 4 +--- 7 files changed, 16 insertions(+), 55 deletions(-) diff --git a/examples/create-disk.c b/examples/create-disk.c index 620efed..4326a45 100644 --- a/examples/create-disk.c +++ b/examples/create-disk.c @@ -17,26 +17,16 @@ main (int argc, char *argv[]) if (g == NULL) { perror ("failed to create libguestfs handle"); exit (EXIT_FAILURE); - } - - /* Create a raw-format sparse disk image, 512 MB in size. */ - int fd = open ("disk.img", O_CREAT|O_WRONLY|O_TRUNC|O_NOCTTY, 0666); - if (fd == -1) { - perror ("disk.img"); - exit (EXIT_FAILURE); - } - if (ftruncate (fd, 512 * 1024 * 1024) == -1) { - perror ("disk.img: truncate"); - exit (EXIT_FAILURE); - } - if (close (fd) == -1) { - perror ("disk.img: close"); - exit (EXIT_FAILURE); } /* Set the trace flag so that we can see each libguestfs call. */ guestfs_set_trace (g, 1); + /* Create a raw-format sparse disk image, 512 MB in size. */ + if (guestfs_disk_create (g, "disk.img", "raw", UINT64_C(512)*1024*1024, + -1) == -1) + exit (EXIT_FAILURE); + /* Add the disk image to libguestfs. */ if (guestfs_add_drive_opts (g, "disk.img", GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", /* raw format */ diff --git a/examples/mount-local.c b/examples/mount-local.c index 18970d0..291cb26 100644 --- a/examples/mount-local.c +++ b/examples/mount-local.c @@ -43,7 +43,7 @@ int main (int argc, char *argv[]) { guestfs_h *g; - int fd, r; + int r; char tempdir[] = "/tmp/mlXXXXXX"; pid_t pid; char *shell, *p; @@ -65,22 +65,6 @@ main (int argc, char *argv[]) "Creating and formatting the disk image, please wait a moment ...\n"); fflush (stdout); - /* Create the output disk image: raw sparse. */ - fd = open (argv[1], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644); - if (fd == -1) { - perror (argv[1]); - exit (EXIT_FAILURE); - } - if (ftruncate (fd, SIZE_MB * 1024 * 1024) == -1) { - perror ("truncate"); - close (fd); - exit (EXIT_FAILURE); - } - if (close (fd) == -1) { - perror ("close"); - exit (EXIT_FAILURE); - } - /* Guestfs handle. */ g = guestfs_create (); if (g == NULL) { @@ -88,6 +72,10 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); } + /* Create the output disk image: raw sparse. */ + if (guestfs_disk_create (g, argv[1], "raw", SIZE_MB * 1024 * 1024, -1) == -1) + exit (EXIT_FAILURE); + /* Create the disk image and format it with a partition and a filesystem. */ if (guestfs_add_drive_opts (g, argv[1], GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", diff --git a/golang/examples/create-disk.go b/golang/examples/create-disk.go index 336fd6c..a59d3f4 100644 --- a/golang/examples/create-disk.go +++ b/golang/examples/create-disk.go @@ -4,7 +4,6 @@ package main import ( "fmt" - "os" "libguestfs.org/guestfs" ) @@ -18,15 +17,8 @@ func main() { defer g.Close () /* Create a raw-format sparse disk image, 512 MB in size. */ - f, ferr := os.Create (output) - if ferr != nil { - panic (fmt.Sprintf ("could not create file: %s: %s", - output, ferr)) - } - defer f.Close () - - if ferr := f.Truncate (512 * 1024 * 1024); ferr != nil { - panic (fmt.Sprintf ("could not truncate file: %s", ferr)) + if err := g.Disk_create (output, "raw", 512 * 1024 * 1024); err != nil { + panic (err) } /* Set the trace flag so that we can see each libguestfs call. */ diff --git a/ocaml/examples/create_disk.ml b/ocaml/examples/create_disk.ml index 73d51e3..5083d39 100644 --- a/ocaml/examples/create_disk.ml +++ b/ocaml/examples/create_disk.ml @@ -9,9 +9,7 @@ let () let g = new Guestfs.guestfs () in (* Create a raw-format sparse disk image, 512 MB in size. *) - let fd = openfile output [O_WRONLY;O_CREAT;O_TRUNC;O_NOCTTY] 0o666 in - ftruncate fd (512 * 1024 * 1024); - close fd; + g#disk_create output "raw" 536870912L; (* Set the trace flag so that we can see each libguestfs call. *) g#set_trace true; diff --git a/perl/examples/create_disk.pl b/perl/examples/create_disk.pl index 2186ce7..0b9fa8d 100755 --- a/perl/examples/create_disk.pl +++ b/perl/examples/create_disk.pl @@ -10,9 +10,7 @@ my $output = "disk.img"; my $g = new Sys::Guestfs (); # Create a raw-format sparse disk image, 512 MB in size. -open FILE, ">$output" or die "$output: $!"; -truncate FILE, 512 * 1024 * 1024 or die "$output: truncate: $!"; -close FILE or die "$output: $!"; +$g->disk_create ($output, "raw", 512 * 1024 * 1024); # Set the trace flag so that we can see each libguestfs call. $g->set_trace (1); diff --git a/python/examples/create_disk.py b/python/examples/create_disk.py index 2f57f3f..ed42e70 100644 --- a/python/examples/create_disk.py +++ b/python/examples/create_disk.py @@ -1,6 +1,5 @@ # Example showing how to create a disk image. -import os import guestfs output = "disk.img" @@ -12,9 +11,7 @@ output = "disk.img" g = guestfs.GuestFS (python_return_dict=True) # Create a raw-format sparse disk image, 512 MB in size. -f = open (output, "w") -f.truncate (512 * 1024 * 1024) -f.close () +g.disk_create (output, "raw", 512 * 1024 * 1024); # Set the trace flag so that we can see each libguestfs call. g.set_trace (1) diff --git a/ruby/examples/create_disk.rb b/ruby/examples/create_disk.rb index fba85ff..00310de 100644 --- a/ruby/examples/create_disk.rb +++ b/ruby/examples/create_disk.rb @@ -7,9 +7,7 @@ output = "disk.img" g = Guestfs::Guestfs.new() # Create a raw-format sparse disk image, 512 MB in size. -File.open(output, "w") { - |f| f.truncate(512 * 1024 * 1024) -} +g.disk_create (output, "raw", 512 * 1024 * 1024) # Set the trace flag so that we can see each libguestfs call. g.set_trace(1) -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 06/10] builder: Use disk-create API instead of calling qemu-img create.
--- builder/builder.ml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/builder/builder.ml b/builder/builder.ml index 3c45fa5..b01f4eb 100644 --- a/builder/builder.ml +++ b/builder/builder.ml @@ -513,14 +513,8 @@ let main () let { Index_parser.expand = expand; lvexpand = lvexpand } = entry in msg (f_"Resizing (using virt-resize) to expand the disk to %s") (human_size osize); - let cmd - sprintf "qemu-img create -f %s%s %s %Ld%s" - (quote oformat) - (if oformat = "qcow2" then " -o preallocation=metadata" else "") - (quote ofile) osize - (if debug then "" else " >/dev/null 2>&1") in - if debug then eprintf "%s\n%!" cmd; - if Sys.command cmd <> 0 then exit 1; + let preallocation = if oformat = "qcow2" then Some "metadata" else None in + (new G.guestfs ())#disk_create ?preallocation ofile oformat osize; let cmd sprintf "virt-resize%s%s%s --output-format %s%s%s %s %s" (if debug then " --verbose" else " --quiet") -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 07/10] tests: Update miscellaneous tests to use disk-create API.
Instead of calling out to qemu-img / truncate. --- diff/test-virt-diff.sh | 4 +++- edit/test-virt-edit.sh | 4 +++- fish/test-a.sh | 2 +- fish/test-add-domain.sh | 2 +- fish/test-d.sh | 2 +- fuse/test-fuse-umount-race.sh | 4 +++- python/t/810-rhbz811650.py | 6 ++---- resize/test-virt-resize.sh | 4 +++- sysprep/test-virt-sysprep-passwords.sh | 4 +++- tests/guests/guest-aux/make-fedora-img.pl | 15 ++++----------- tests/hotplug/test-hot-add.pl | 13 ++++--------- tests/hotplug/test-hot-remove.pl | 13 ++++--------- tests/hotplug/test-hotplug-repeated.pl | 7 +------ tests/md/test-inspect-fstab.sh | 4 +++- tests/mountable/test-mountable-inspect.sh | 4 +++- tests/qemu/qemu-snapshot-isolation.sh | 3 ++- tests/syslinux/test-syslinux.pl | 10 ++++------ 17 files changed, 45 insertions(+), 56 deletions(-) diff --git a/diff/test-virt-diff.sh b/diff/test-virt-diff.sh index 95778d8..3a3a1aa 100755 --- a/diff/test-virt-diff.sh +++ b/diff/test-virt-diff.sh @@ -32,7 +32,9 @@ fi rm -f fedora.qcow2 # Modify a copy of the image. -qemu-img create -f qcow2 -b ../tests/guests/fedora.img fedora.qcow2 +../fish/guestfish -- \ + disk-create fedora.qcow2 qcow2 -1 \ + backingfile:../tests/guests/fedora.img backingformat:raw ../fish/guestfish -a fedora.qcow2 -i <<EOF touch /diff diff --git a/edit/test-virt-edit.sh b/edit/test-virt-edit.sh index 572ad22..99c2e7c 100755 --- a/edit/test-virt-edit.sh +++ b/edit/test-virt-edit.sh @@ -28,7 +28,9 @@ rm -f test.qcow2 # Make a copy of the Fedora image so we can write to it then # discard it. -qemu-img create -F raw -b ../tests/guests/fedora.img -f qcow2 test.qcow2 +../fish/guestfish -- \ + disk-create test.qcow2 qcow2 -1 \ + backingfile:../tests/guests/fedora.img backingformat:raw # Edit interactively. We have to simulate this by setting $EDITOR. # The command will be: echo newline >> /tmp/file diff --git a/fish/test-a.sh b/fish/test-a.sh index df892fe..52194c2 100755 --- a/fish/test-a.sh +++ b/fish/test-a.sh @@ -30,7 +30,7 @@ $VG ./guestfish -x -a test-a.img </dev/null >test-a.out 2>&1 ! grep -sq 'add_drive.*format' test-a.out rm test-a.img -qemu-img create -f qcow2 test-a.img 100M +$VG ./guestfish disk-create test-a.img qcow2 100M $VG ./guestfish -x --format=qcow2 -a test-a.img </dev/null >test-a.out 2>&1 diff --git a/fish/test-add-domain.sh b/fish/test-add-domain.sh index 419c5cf..a6b0e10 100755 --- a/fish/test-add-domain.sh +++ b/fish/test-add-domain.sh @@ -27,7 +27,7 @@ cwd="$(pwd)" $VG ./guestfish sparse test-add-domain-1.img 1M $VG ./guestfish sparse test-add-domain-2.img 1M -qemu-img create -f qcow2 test-add-domain-3.img 1M +$VG ./guestfish disk-create test-add-domain-3.img qcow2 1M $VG ./guestfish sparse test-add-domain-4.img 1M # Libvirt test XML, see libvirt.git/examples/xml/test/testnode.xml diff --git a/fish/test-d.sh b/fish/test-d.sh index b891505..1e16bdc 100755 --- a/fish/test-d.sh +++ b/fish/test-d.sh @@ -27,7 +27,7 @@ cwd="$(pwd)" $VG ./guestfish sparse test-d-1.img 1M $VG ./guestfish sparse test-d-2.img 1M -qemu-img create -f qcow2 test-d-3.img 1M +$VG ./guestfish disk-create test-d-3.img qcow2 1M $VG ./guestfish sparse test-d-4.img 1M # Libvirt test XML, see libvirt.git/examples/xml/test/testnode.xml diff --git a/fuse/test-fuse-umount-race.sh b/fuse/test-fuse-umount-race.sh index 67dbac9..7624219 100755 --- a/fuse/test-fuse-umount-race.sh +++ b/fuse/test-fuse-umount-race.sh @@ -42,7 +42,9 @@ rm -f test.qcow2 test-copy.qcow2 test.pid rm -rf mp # Make a copy of the Fedora image so we can write to it then discard it. -qemu-img create -F raw -b ../tests/guests/fedora.img -f qcow2 test.qcow2 +../fish/guestfish -- \ + disk-create test.qcow2 qcow2 -1 \ + backingfile:../tests/guests/fedora.img backingformat:raw mkdir mp ./guestmount -a test.qcow2 -m /dev/VG/Root --pid-file test.pid mp diff --git a/python/t/810-rhbz811650.py b/python/t/810-rhbz811650.py index 128f3b5..56d8062 100644 --- a/python/t/810-rhbz811650.py +++ b/python/t/810-rhbz811650.py @@ -18,12 +18,10 @@ import os import guestfs -f = open ("rhbz811650.img", "w") -f.truncate (500 * 1024 * 1024) -f.close () - g = guestfs.GuestFS (python_return_dict=True) +g.disk_create ("rhbz811650.img", "raw", 500 * 1024 * 1024) + # Deliberate error: the disk format is supposed to be raw. g.add_drive ("rhbz811650.img", format="qcow2"); diff --git a/resize/test-virt-resize.sh b/resize/test-virt-resize.sh index 944301c..29c1e4c 100755 --- a/resize/test-virt-resize.sh +++ b/resize/test-virt-resize.sh @@ -32,7 +32,9 @@ fi $VG ../fish/guestfish \ -N test-virt-resize-1.img=bootrootlv:/dev/VG/LV:ext2:ext4:400M:32M:gpt </dev/null -qemu-img create -f qcow2 -o preallocation=metadata test-virt-resize-2.img 500M +$VG ../fish/guestfish \ + disk-create test-virt-resize-2.img qcow2 500M preallocation:metadata + $VG ./virt-resize -d --debug-gc \ --expand /dev/sda2 \ --lv-expand /dev/VG/LV \ diff --git a/sysprep/test-virt-sysprep-passwords.sh b/sysprep/test-virt-sysprep-passwords.sh index f606501..488187c 100755 --- a/sysprep/test-virt-sysprep-passwords.sh +++ b/sysprep/test-virt-sysprep-passwords.sh @@ -35,7 +35,9 @@ fi # so we fake that now. rm -f passwords.qcow2 password -qemu-img create -F raw -b ../tests/guests/fedora.img -f qcow2 passwords.qcow2 +../fish/guestfish -- \ + disk-create passwords.qcow2 qcow2 -1 \ + backingfile:../tests/guests/fedora.img backingformat:raw ../fish/guestfish -a passwords.qcow2 -i <<'EOF' write-append /etc/shadow "test01::15677:0:99999:7:::\n" diff --git a/tests/guests/guest-aux/make-fedora-img.pl b/tests/guests/guest-aux/make-fedora-img.pl index 0537bd2..4eb08b5 100755 --- a/tests/guests/guest-aux/make-fedora-img.pl +++ b/tests/guests/guest-aux/make-fedora-img.pl @@ -60,9 +60,7 @@ EOF $bootdev = '/dev/sda1'; - open (my $img, '>', "fedora.img.tmp.$$") or die; - truncate ($img, $IMAGE_SIZE) or die; - close ($img) or die; + $g->disk_create ("fedora.img.tmp.$$", "raw", $IMAGE_SIZE); $g->add_drive ("fedora.img.tmp.$$"); $g->launch (); @@ -88,11 +86,8 @@ EOF $bootdev = '/dev/md/boot'; foreach my $img (@images) { - open (my $fh, '>', $img) or die; - truncate ($fh, $IMAGE_SIZE) or die; - close ($fh) or die; - - $g->add_drive ($img); + $g->disk_create ($img, "raw", $IMAGE_SIZE); + $g->add_drive ($img); } $g->launch (); @@ -140,9 +135,7 @@ EOF $bootdev = '/dev/sda1'; - open (my $img, '>', "fedora-btrfs.img.tmp.$$") or die; - truncate ($img, $IMAGE_SIZE) or die; - close ($img) or die; + $g->disk_create ("fedora-btrfs.img.tmp.$$", "raw", $IMAGE_SIZE); $g->add_drive ("fedora-btrfs.img.tmp.$$"); $g->launch (); diff --git a/tests/hotplug/test-hot-add.pl b/tests/hotplug/test-hot-add.pl index 310440e..2496e08 100755 --- a/tests/hotplug/test-hot-add.pl +++ b/tests/hotplug/test-hot-add.pl @@ -36,15 +36,10 @@ unless ($backend eq "libvirt" || $backend =~ /^libvirt:/) { $g->launch (); # Create some temporary disks. -open FILE, ">test-hot-add-1.img" or die "test-hot-add-1.img: $!"; -truncate FILE, 512 * 1024 * 1024 or die "test-hot-add-1.img: truncate: $!"; -close FILE; - -open FILE, ">test-hot-add-2.img" or die "test-hot-add-2.img: $!"; -truncate FILE, 512 * 1024 * 1024 or die "test-hot-add-2.img: truncate: $!"; -close FILE; - -die unless system ("qemu-img create -f qcow2 -o preallocation=metadata test-hot-add-3.img 1G") == 0; +$g->disk_create ("test-hot-add-1.img", "raw", 512 * 1024 * 1024); +$g->disk_create ("test-hot-add-2.img", "raw", 512 * 1024 * 1024); +$g->disk_create ("test-hot-add-3.img", "qcow2", 1024 * 1024 * 1024, + preallocation => "metadata"); # Hot-add them. Labels are required. $g->add_drive ("test-hot-add-1.img", label => "a"); # autodetect format diff --git a/tests/hotplug/test-hot-remove.pl b/tests/hotplug/test-hot-remove.pl index c9e4146..aa6ab93 100755 --- a/tests/hotplug/test-hot-remove.pl +++ b/tests/hotplug/test-hot-remove.pl @@ -33,15 +33,10 @@ unless ($backend eq "libvirt" || $backend =~ /^libvirt:/) { } # Create some temporary disks. -open FILE, ">test-hot-remove-1.img" or die "test-hot-remove-1.img: $!"; -truncate FILE, 512 * 1024 * 1024 or die "test-hot-remove-1.img: truncate: $!"; -close FILE; - -open FILE, ">test-hot-remove-2.img" or die "test-hot-remove-2.img: $!"; -truncate FILE, 512 * 1024 * 1024 or die "test-hot-remove-2.img: truncate: $!"; -close FILE; - -die unless system ("qemu-img create -f qcow2 -o preallocation=metadata test-hot-remove-3.img 1G") == 0; +$g->disk_create ("test-hot-remove-1.img", "raw", 512 * 1024 * 1024); +$g->disk_create ("test-hot-remove-2.img", "raw", 512 * 1024 * 1024); +$g->disk_create ("test-hot-remove-3.img", "qcow2", 1024 * 1024 * 1024, + preallocation => "metadata"); # Hot-add them. Labels are required. $g->add_drive ("test-hot-remove-1.img", label => "a"); # autodetect format diff --git a/tests/hotplug/test-hotplug-repeated.pl b/tests/hotplug/test-hotplug-repeated.pl index 635bf41..306bceb 100755 --- a/tests/hotplug/test-hotplug-repeated.pl +++ b/tests/hotplug/test-hotplug-repeated.pl @@ -35,12 +35,7 @@ unless ($backend eq "libvirt" || $backend =~ /^libvirt:/) { $g->launch (); # Create a temporary disk. -open FILE, ">test-hotplug-repeated.img" or - die "test-hotplug-repeated.img: $!"; -truncate FILE, 512 * 1024 * 1024 or - die "test-hotplug-repeated.img: truncate: $!"; -close FILE or - die "test-hotplug-repeated.img: close: $!"; +$g->disk_create ("test-hotplug-repeated.img", "raw", 512 * 1024 * 1024); my $start_t = time (); while (time () - $start_t <= 60) { diff --git a/tests/md/test-inspect-fstab.sh b/tests/md/test-inspect-fstab.sh index 635c06c..04ee9d1 100755 --- a/tests/md/test-inspect-fstab.sh +++ b/tests/md/test-inspect-fstab.sh @@ -34,7 +34,9 @@ rm -f inspect-fstab-1.qcow2 inspect-fstab.fstab inspect-fstab.output # Start with the regular (good) fedora image, modify /etc/fstab # and then inspect it. -qemu-img create -F raw -b ../guests/fedora.img -f qcow2 inspect-fstab-1.qcow2 +$guestfish -- \ + disk-create inspect-fstab-1.qcow2 qcow2 -1 \ + backingfile:../guests/fedora.img backingformat:raw cat <<'EOF' > inspect-fstab.fstab /dev/VG/Root / ext2 default 0 0 diff --git a/tests/mountable/test-mountable-inspect.sh b/tests/mountable/test-mountable-inspect.sh index 10d1e9f..b248b01 100755 --- a/tests/mountable/test-mountable-inspect.sh +++ b/tests/mountable/test-mountable-inspect.sh @@ -43,7 +43,9 @@ rm -f root.tmp test.qcow2 test.output # Start with the regular (good) fedora image, modify /etc/fstab # and then inspect it. -qemu-img create -F raw -b ../guests/fedora-btrfs.img -f qcow2 test.qcow2 +$guestfish -- \ + disk-create test.qcow2 qcow2 -1 \ + backingfile:../guests/fedora-btrfs.img backingformat:raw # Test that basic inspection works and the expected filesystems are # found diff --git a/tests/qemu/qemu-snapshot-isolation.sh b/tests/qemu/qemu-snapshot-isolation.sh index 360e999..82b3892 100755 --- a/tests/qemu/qemu-snapshot-isolation.sh +++ b/tests/qemu/qemu-snapshot-isolation.sh @@ -38,7 +38,8 @@ isolation1_md5sum="$(md5sum isolation1.img | awk '{print $1}')" isolation2_md5sum="$(md5sum isolation2.img | awk '{print $1}')" if [ "$supports_qcow2" = "yes" ]; then - qemu-img create -f qcow2 -o preallocation=metadata isolation3.img 100M + ../../fish/guestfish \ + disk-create isolation3.img qcow2 100M preallocation:metadata isolation3_md5sum="$(md5sum isolation3.img | awk '{print $1}')" add3="add-drive-opts isolation3.img format:qcow2 readonly:true" cmds3=" diff --git a/tests/syslinux/test-syslinux.pl b/tests/syslinux/test-syslinux.pl index 9844883..d86c095 100755 --- a/tests/syslinux/test-syslinux.pl +++ b/tests/syslinux/test-syslinux.pl @@ -55,13 +55,11 @@ unless ($kernel) { } print "kernel: $kernel\n"; -# Create the disk. -unlink "$disk"; -open DISK, ">$disk" or die "$disk: $!"; -truncate DISK, 100*1024*1024; -close DISK; - my $g = Sys::Guestfs->new (); + +# Create the disk. +$g->disk_create ($disk, "raw", 100*1024*1024); + $g->add_drive ($disk, format => "raw"); $g->launch (); -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 08/10] rescue: Note that we're not using add-drive-scratch here, and maybe we should be.
--- rescue/rescue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rescue/rescue.c b/rescue/rescue.c index 0442711..b46dad6 100644 --- a/rescue/rescue.c +++ b/rescue/rescue.c @@ -533,6 +533,8 @@ add_scratch_disk (struct drv **drvs) struct scratch_disk *sd; struct drv *drv; + /* XXX Is there a reason we're not using guestfs_add_drive_scratch here? */ + /* Create a temporary file, raw sparse format. */ fd = mkstemp (filename_s); if (fd == -1) { -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 09/10] sparsify: Use new disk-create API instead of calling qemu-img.
disk-create doesn't support the lazy_refcounts option. --- sparsify/sparsify.ml | 71 ++++++---------------------------------------------- 1 file changed, 7 insertions(+), 64 deletions(-) diff --git a/sparsify/sparsify.ml b/sparsify/sparsify.ml index 3e544db..212a23f 100644 --- a/sparsify/sparsify.ml +++ b/sparsify/sparsify.ml @@ -157,16 +157,6 @@ read the man page virt-sparsify(1). else Sys.getcwd () // indisk in - let contains_colon filename - try ignore (String.index filename ':'); true with Not_found -> false in - - (* Check filenames don't contain a colon (limitation of qemu-img). *) - if contains_colon indisk then - error (f_"input filename '%s' contains a colon (':'); qemu-img command line syntax prevents us from using such an image") indisk; - - if contains_colon outdisk then - error (f_"output filename '%s' contains a colon (':'); qemu-img command line syntax prevents us from using such an image") outdisk; - (* Check the output is not a block or char special (RHBZ#1056290). *) if is_block_device outdisk then error (f_"output '%s' cannot be a block device, it must be a regular file") @@ -190,34 +180,6 @@ let () let do_sigint _ = exit 1 in Sys.set_signal Sys.sigint (Sys.Signal_handle do_sigint) -(* Try to determine which flag options qemu-img supports for qcow2. - * We do this by creating and disposing of a few test images. This - * also detects if qemu-img is completely broken. - *) -let qemu_img_supports_compat11, qemu_img_supports_lazy_refcounts - let test options - let tmp = Filename.temp_file "test" ".qcow2" in - unlink_on_exit tmp; - let cmd = "qemu-img create -f qcow2" ^ - (match options with None -> "" | Some opts -> " -o " ^ opts) ^ - " " ^ tmp ^ " 128K > /dev/null" in - if verbose then printf "testing if '%s' works ... %!" cmd; - let r = Sys.command cmd = 0 in - if verbose then printf "%b\n" r; - r - in - if not (test None) then ( - eprintf (f_"\ -'qemu-img create' cannot create qcow2 files. Check the 'qemu-img' -program is installed and working, and that it matches the version\ -of qemu installed.\n"); - exit 1 - ); - let supports_compat11 = test (Some "compat=1.1") in - let supports_lazy_refcounts - test (Some "compat=1.1,lazy_refcounts") in - supports_compat11, supports_lazy_refcounts - (* What should the output format be? If the user specified an * input format, use that, else detect it from the source image. *) @@ -298,32 +260,13 @@ let overlaydisk unlink_on_exit tmp; (* Create it with the indisk as the backing file. *) - let cmd - let options - let backing_file_option - [sprintf "backing_file=%s" (replace_str indisk "," ",,")] in - let backing_fmt_option - match format with - | None -> [] - | Some fmt -> [sprintf "backing_fmt=%s" fmt] in - let compat11 - if qemu_img_supports_compat11 then ["compat=1.1"] else [] in - let lazy_refcounts - if qemu_img_supports_lazy_refcounts then - ["lazy_refcounts"] - else [] in - String.concat "," ( - backing_file_option @ - backing_fmt_option @ - compat11 @ - lazy_refcounts - ) in - sprintf "qemu-img create -f qcow2 -o %s %s > /dev/null" - (Filename.quote options) (Filename.quote tmp) in - if verbose then - printf "%s\n%!" cmd; - if Sys.command cmd <> 0 then - error (f_"external command failed: %s") cmd; + (* XXX Old code used to: + * - detect if compat=1.1 was supported + * - add lazy_refcounts option + *) + (new G.guestfs ())#disk_create + ~backingfile:indisk ?backingformat:format ~compat:"1.1" + tmp "qcow2" Int64.minus_one; tmp -- 1.8.4.2
Richard W.M. Jones
2014-Jan-28 16:24 UTC
[Libguestfs] [PATCH 10/10] virt-make-fs: Use disk-create API instead of calling qemu-img create.
Strictly speaking this reduces the number of formats that virt-make-fs can output to, but it's likely that no one cares and if they do we can add new formats in future. --- tools/virt-make-fs | 44 ++++++-------------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/tools/virt-make-fs b/tools/virt-make-fs index 605d067..f1cc09d 100755 --- a/tools/virt-make-fs +++ b/tools/virt-make-fs @@ -231,9 +231,6 @@ Choose the output disk image format. The default is C<raw> (raw sparse disk image). -For other choices, see the L<qemu-img(1)> manpage. The only other -choice that would really make sense here is C<qcow2>. - =cut my $type = "ext2"; @@ -425,46 +422,17 @@ if (!defined $size) { $size = int ($size); -# Create the output disk. -# -# Use qemu-img so we can control the output format, but capture any -# output temporarily and only display it if the command fails. - -my @options = (); -@options = ("-o", "preallocation=metadata") if $format eq "qcow2"; - -my @cmd = ("qemu-img", "create", "-f", $format, @options, $output, $size); -if ($debug) { - print STDERR ("running: ", join (" ", @cmd), "\n"); -} - -{ - my $tmpfh = tempfile (); - my ($r, $oldout, $olderr); - - open $oldout, ">&STDOUT" or die __"cannot dup STDOUT"; - open $olderr, ">&STDERR" or die __"cannot dup STDERR"; - close STDOUT; - close STDERR; - open STDOUT, ">&", \$tmpfh or die __"cannot redirect STDOUT"; - open STDERR, ">&", \$tmpfh or die __"cannot redirect STDERR"; - $r = system (@cmd); - open STDOUT, ">&", $oldout or die __"cannot restore STDOUT"; - open STDERR, ">&", $olderr or die __"cannot restore STDERR"; - - unless ($r == 0) { - print STDERR __"qemu-img create: failed to create disk image:\n"; - seek $tmpfh, 0, SEEK_SET; - print STDERR $_ while <$tmpfh>; - die "\n"; - } -} - eval { print STDERR "starting libguestfs ...\n" if $debug; # Run libguestfs. my $g = Sys::Guestfs->new (); + + # Create the output disk. + my %options = (); + $options{preallocation} = "metadata" if $format eq "qcow2"; + $g->disk_create ($output, $format, $size, %options); + $g->add_drive ($output, format => $format); $g->launch (); -- 1.8.4.2
Pino Toscano
2014-Jan-28 16:53 UTC
Re: [Libguestfs] [PATCH 05/10] examples: Update various examples to use new disk-create API.
On Tuesday 28 January 2014 16:24:52 Richard W.M. Jones wrote:> --- a/ocaml/examples/create_disk.ml > +++ b/ocaml/examples/create_disk.ml > @@ -9,9 +9,7 @@ let () > let g = new Guestfs.guestfs () in > > (* Create a raw-format sparse disk image, 512 MB in size. *) > - let fd = openfile output [O_WRONLY;O_CREAT;O_TRUNC;O_NOCTTY] 0o666 in > - ftruncate fd (512 * 1024 * 1024); > - close fd; > + g#disk_create output "raw" 536870912L;Minor niptick: I'd leave the multiplication, as it was before and as the other examples do (easier to spot and to change). -- Pino Toscano
Apparently Analagous Threads
- [PATCH 00/10] New API: disk-create for creating blank disks.
- Re: [PATCH 05/10] examples: Update various examples to use new disk-create API.
- [PATCH] builder: handle -v and -x flags like in other tools (RHBZ#1196100)
- [PATCH] OCaml tools: use open_guestfs everywhere
- Re: [PATCH] v2v: use open_guestfs everywhere