From: "Richard W.M. Jones" <rjones(a)redhat.com>
This tool allows you to easily reformat a disk, creating a blank disk
with optional partition, LVM and empty filesystem.
---
.gitignore | 4 +
Makefile.am | 3 +-
configure.ac | 1 +
format/Makefile.am | 78 ++++++++
format/format.c | 450 +++++++++++++++++++++++++++++++++++++++++++++++
format/virt-format.pod | 207 ++++++++++++++++++++++
po/POTFILES.in | 1 +
src/guestfs.pod | 5 +
tests/extra/Makefile.am | 1 +
tools/virt-make-fs | 3 +
10 files changed, 752 insertions(+), 1 deletions(-)
create mode 100644 format/Makefile.am
create mode 100644 format/format.c
create mode 100755 format/virt-format.pod
diff --git a/.gitignore b/.gitignore
index 0611975..36411aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -105,6 +105,9 @@ fish/virt-copy-in.1
fish/virt-copy-out.1
fish/virt-tar-in.1
fish/virt-tar-out.1
+format/stamp-virt-format.pod
+format/virt-format
+format/virt-format.1
fuse/guestmount
fuse/guestmount.1
fuse/stamp-guestmount.pod
@@ -145,6 +148,7 @@ html/virt-copy-out.1.html
html/virt-df.1.html
html/virt-edit.1.html
html/virt-filesystems.1.html
+html/virt-format.1.html
html/virt-inspector.1.html
html/virt-list-filesystems.1.html
html/virt-list-partitions.1.html
diff --git a/Makefile.am b/Makefile.am
index d14cc12..22ae04e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,7 +52,7 @@ SUBDIRS += test-tool
SUBDIRS += fish
# virt-tools in C.
-SUBDIRS += align cat df edit inspector rescue
+SUBDIRS += align cat df edit format inspector rescue
# Language bindings.
if HAVE_PERL
@@ -187,6 +187,7 @@ HTMLFILES = \
html/virt-df.1.html \
html/virt-edit.1.html \
html/virt-filesystems.1.html \
+ html/virt-format.1.html \
html/virt-inspector.1.html \
html/virt-list-filesystems.1.html \
html/virt-list-partitions.1.html \
diff --git a/configure.ac b/configure.ac
index d8abf71..fa97479 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1018,6 +1018,7 @@ AC_CONFIG_FILES([Makefile
erlang/examples/Makefile
examples/Makefile
fish/Makefile
+ format/Makefile
fuse/Makefile
generator/Makefile
gnulib/lib/Makefile
diff --git a/format/Makefile.am b/format/Makefile.am
new file mode 100644
index 0000000..b3ff216
--- /dev/null
+++ b/format/Makefile.am
@@ -0,0 +1,78 @@
+# libguestfs virt format tool
+# Copyright (C) 2012 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
+
+EXTRA_DIST = \
+ virt-format.pod
+
+CLEANFILES = stamp-virt-format.pod
+
+bin_PROGRAMS = virt-format
+
+SHARED_SOURCE_FILES = \
+ ../fish/config.c \
+ ../fish/inspect.c \
+ ../fish/keys.c \
+ ../fish/options.h \
+ ../fish/options.c \
+ ../fish/virt.c
+
+virt_format_SOURCES = \
+ $(SHARED_SOURCE_FILES) \
+ format.c
+
+virt_format_CFLAGS = \
+ -DGUESTFS_WARN_DEPRECATED=1 \
+ -I$(top_srcdir)/src -I$(top_builddir)/src \
+ -I$(top_srcdir)/fish \
+ -I$(srcdir)/../gnulib/lib -I../gnulib/lib \
+ -DLOCALEBASEDIR=\""$(datadir)/locale"\" \
+ $(WARN_CFLAGS) $(WERROR_CFLAGS) \
+ $(LIBCONFIG_CFLAGS) \
+ $(LIBVIRT_CFLAGS)
+
+virt_format_LDADD = \
+ $(LIBCONFIG_LIBS) \
+ $(top_builddir)/src/libguestfs.la \
+ ../gnulib/lib/libgnu.la \
+ $(LIBVIRT_LIBS)
+
+# Manual pages and HTML files for the website.
+man_MANS = virt-format.1
+noinst_DATA = $(top_builddir)/html/virt-format.1.html
+
+virt-format.1 $(top_builddir)/html/virt-format.1.html: stamp-virt-format.pod
+
+stamp-virt-format.pod: virt-format.pod
+ $(top_builddir)/podwrapper.sh \
+ --man virt-format.1 \
+ --html $(top_builddir)/html/virt-format.1.html \
+ $<
+ touch $@
+
+# Tests.
+
+# random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' <
/dev/null)
+
+# TESTS_ENVIRONMENT = \
+# MALLOC_PERTURB_=$(random_val) \
+# LD_LIBRARY_PATH=$(top_builddir)/src/.libs \
+# LIBGUESTFS_PATH=$(top_builddir)/appliance \
+# TMPDIR=$(top_builddir)
+
+# TESTS = test-virt-format.sh
diff --git a/format/format.c b/format/format.c
new file mode 100644
index 0000000..c701bf7
--- /dev/null
+++ b/format/format.c
@@ -0,0 +1,450 @@
+/* virt-format
+ * Copyright (C) 2012 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <locale.h>
+#include <assert.h>
+#include <libintl.h>
+
+#include "progname.h"
+#include "c-ctype.h"
+
+#include "guestfs.h"
+#include "options.h"
+
+/* These globals are shared with options.c. */
+guestfs_h *g;
+
+int read_only = 0;
+int live = 0;
+int verbose = 0;
+int keys_from_stdin = 0;
+int echo_keys = 0;
+int inspector = 0;
+const char *libvirt_uri = NULL;
+
+static const char *filesystem = NULL;
+static const char *vg = NULL, *lv = NULL;
+static const char *partition = "DEFAULT";
+static int wipe = 0;
+
+static void parse_vg_lv (const char *lvm);
+static int do_format (void);
+static int do_rescan (char **devices);
+
+static inline char *
+bad_cast (char const *s)
+{
+ return (char *) s;
+}
+
+static void __attribute__((noreturn))
+usage (int status)
+{
+ char *warning =
+ _("IMPORTANT NOTE: This program ERASES ALL DATA on disks.");
+
+ if (status != EXIT_SUCCESS)
+ fprintf (stderr, _("Try `%s --help' for more information.\n%s\n"),
+ program_name, warning);
+ else {
+ fprintf (stdout,
+ _("%s: erase and make a blank disk\n"
+ "Copyright (C) 2012 Red Hat Inc.\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Usage:\n"
+ " %s [--options] -a disk.img [-a disk.img ...]\n"
+ "Options:\n"
+ " -a|--add image Add image\n"
+ " --filesystem=.. Create empty filesystem\n"
+ " --format[=raw|..] Force disk format for -a option\n"
+ " --help Display brief help\n"
+ " --lvm=.. Create Linux LVM2 logical volume\n"
+ " --partition=.. Create / set partition type\n"
+ " -v|--verbose Verbose messages\n"
+ " -V|--version Display version and exit\n"
+ " --wipe Write zeroes over whole disk\n"
+ " -x Trace libguestfs API calls\n"
+ "For more information, see the manpage %s(1).\n"
+ "\n"
+ "%s\n\n"),
+ program_name, warning, program_name, program_name,
+ warning);
+ }
+ exit (status);
+}
+
+int
+main (int argc, char *argv[])
+{
+ /* Set global program name that is not polluted with libtool artifacts. */
+ set_program_name (argv[0]);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEBASEDIR);
+ textdomain (PACKAGE);
+
+ enum { HELP_OPTION = CHAR_MAX + 1 };
+
+ static const char *options = "a:c:d:qvVx";
+ static const struct option long_options[] = {
+ { "add", 1, 0, 'a' },
+ { "filesystem", 1, 0, 0 },
+ { "format", 2, 0, 0 },
+ { "help", 0, 0, HELP_OPTION },
+ { "lvm", 2, 0, 0 },
+ { "partition", 2, 0, 0 },
+ { "verbose", 0, 0, 'v' },
+ { "version", 0, 0, 'V' },
+ { "wipe", 0, 0, 0 },
+ { 0, 0, 0, 0 }
+ };
+ struct drv *drvs = NULL;
+ struct drv *drv;
+ const char *format = NULL;
+ int c;
+ int option_index;
+ int retry, retries;
+
+ g = guestfs_create ();
+ if (g == NULL) {
+ fprintf (stderr, _("guestfs_create: failed to create handle\n"));
+ exit (EXIT_FAILURE);
+ }
+
+ argv[0] = bad_cast (program_name);
+
+ for (;;) {
+ c = getopt_long (argc, argv, options, long_options, &option_index);
+ if (c == -1) break;
+
+ switch (c) {
+ case 0: /* options which are long only */
+ if (STREQ (long_options[option_index].name, "format")) {
+ if (!optarg || STREQ (optarg, ""))
+ format = NULL;
+ else
+ format = optarg;
+ } else if (STREQ (long_options[option_index].name, "filesystem")) {
+ if (STREQ (optarg, "none"))
+ filesystem = NULL;
+ else if (optarg[0] == '-') { /* eg: --filesystem --lvm */
+ fprintf (stderr, _("%s: no filesystem was specified\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ } else
+ filesystem = optarg;
+ } else if (STREQ (long_options[option_index].name, "lvm")) {
+ if (vg || lv) {
+ fprintf (stderr,
+ _("%s: --lvm option cannot be given multiple times\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+ if (optarg == NULL) {
+ vg = strdup ("VG");
+ lv = strdup ("LV");
+ if (!vg || !lv) { perror ("strdup"); exit (EXIT_FAILURE); }
+ }
+ else if (STREQ (optarg, "none"))
+ vg = lv = NULL;
+ else
+ parse_vg_lv (optarg);
+ } else if (STREQ (long_options[option_index].name, "partition")) {
+ if (optarg == NULL)
+ partition = "DEFAULT";
+ else if (STREQ (optarg, "none"))
+ partition = NULL;
+ else
+ partition = optarg;
+ } else if (STREQ (long_options[option_index].name, "wipe")) {
+ wipe = 1;
+ } else {
+ fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
+ program_name, long_options[option_index].name, option_index);
+ exit (EXIT_FAILURE);
+ }
+ break;
+
+ case 'a':
+ OPTION_a;
+ break;
+
+ case 'v':
+ OPTION_v;
+ break;
+
+ case 'V':
+ OPTION_V;
+ break;
+
+ case 'x':
+ OPTION_x;
+ break;
+
+ case HELP_OPTION:
+ usage (EXIT_SUCCESS);
+
+ default:
+ usage (EXIT_FAILURE);
+ }
+ }
+
+ /* These are really constants, but they have to be variables for the
+ * options parsing code. Assert here that they have known-good
+ * values.
+ */
+ assert (read_only == 0);
+ assert (inspector == 0);
+ assert (live == 0);
+
+ /* Must be no extra arguments on the command line. */
+ if (optind != argc)
+ usage (EXIT_FAILURE);
+
+ /* The user didn't specify any drives to format. */
+ if (drvs == NULL)
+ usage (EXIT_FAILURE);
+
+ /* Because the libguestfs kernel can get stuck rereading the
+ * partition table after things have been erased, we sometimes need
+ * to completely restart the guest. Hence this complex retry logic.
+ */
+ for (retries = 0; retries <= 1; ++retries) {
+ /* Add domains/drives from the command line (for a single guest). */
+ add_drives (drvs, 'a');
+
+ if (guestfs_launch (g) == -1)
+ exit (EXIT_FAILURE);
+
+ /* Perform the format. */
+ retry = do_format ();
+ if (!retry)
+ break;
+
+ if (retries == 0) {
+ /* We're going to silently retry, after reopening the connection. */
+ guestfs_h *g2;
+
+ g2 = guestfs_create ();
+ guestfs_set_verbose (g2, guestfs_get_verbose (g));
+ guestfs_set_trace (g2, guestfs_get_trace (g));
+
+ guestfs_close (g);
+ g = g2;
+ }
+ else {
+ /* Failed. */
+ fprintf (stderr,
+ _("%s: failed to rescan the disks after two attempts. This\n"
+ "may mean there is some sort of partition table or disk\n"
+ "data which we are unable to remove. If you think this\n"
+ "is a bug, please file a bug at
http://libguestfs.org/\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ /* Free up data structures. */
+ free_drives (drvs);
+
+ guestfs_close (g);
+
+ exit (EXIT_SUCCESS);
+}
+
+/* Parse lvm string of the form "/dev/VG/LV" or "VG/LV".
+ * This sets the global variables 'vg' and 'lv', or exits on failure.
+ */
+static void
+parse_vg_lv (const char *lvm)
+{
+ size_t i;
+
+ if (STRPREFIX (lvm, "/dev/"))
+ lvm += 5;
+
+ i = strcspn (lvm, "/");
+ if (lvm[i]) {
+ vg = strndup (lvm, i);
+ lv = strdup (lvm + i + 1);
+
+ if (!vg || !lv) {
+ perror ("strdup");
+ exit (EXIT_FAILURE);
+ }
+ } else {
+ cannot_parse:
+ fprintf (stderr, _("%s: cannot parse --lvm option (%s)\n"),
+ program_name, lvm);
+ exit (EXIT_FAILURE);
+ }
+
+ if (strchr (vg, '/') || strchr (lv, '/'))
+ goto cannot_parse;
+}
+
+/* Returns 0 on success, 1 if we need to retry. */
+static int
+do_format (void)
+{
+ char **devices;
+ size_t i, pass;
+
+ devices = guestfs_list_devices (g);
+ if (devices == NULL)
+ exit (EXIT_FAILURE);
+
+ /* Erase the disks. */
+ if (!wipe) {
+ char **parts;
+
+ /* No wipe, but get rid of LVM metadata by erasing each partition. */
+ parts = guestfs_list_partitions (g);
+ if (parts == NULL)
+ exit (EXIT_FAILURE);
+
+ for (i = 0; parts[i] != NULL; ++i) {
+ if (guestfs_zero (g, parts[i]) == -1)
+ exit (EXIT_FAILURE);
+ free (parts[i]);
+ }
+ free (parts);
+
+ /* Then erase the partition table on each device. */
+ for (i = 0; devices[i] != NULL; ++i) {
+ if (guestfs_zero (g, devices[i]) == -1)
+ exit (EXIT_FAILURE);
+ }
+ }
+ else /* wipe */ {
+ for (i = 0; devices[i] != NULL; ++i) {
+ if (guestfs_zero_device (g, devices[i]) == -1)
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (do_rescan (devices))
+ return 1; /* which means, reopen the handle and retry */
+
+ /* Format each disk. */
+ for (i = 0; devices[i] != NULL; ++i) {
+ char *dev = devices[i];
+ int free_dev = 0;
+
+ if (partition) {
+ const char *ptype = partition;
+ int64_t dev_size;
+
+ /* If partition has the magic value "DEFAULT", choose either MBR or
GPT.*/
+ if (STREQ (partition, "DEFAULT")) {
+ dev_size = guestfs_blockdev_getsize64 (g, devices[i]);
+ if (dev_size == -1)
+ exit (EXIT_FAILURE);
+ ptype = dev_size < INT64_C(2)*1024*1024*1024*1024 ? "mbr" :
"gpt";
+ }
+
+ if (guestfs_part_disk (g, devices[i], ptype) == -1)
+ exit (EXIT_FAILURE);
+ if (asprintf (&dev, "%s1", devices[i]) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+ free_dev = 1;
+ }
+
+ if (vg && lv) {
+ char *devs[2] = { dev, NULL };
+
+ if (guestfs_pvcreate (g, dev) == -1)
+ exit (EXIT_FAILURE);
+
+ if (guestfs_vgcreate (g, vg, devs) == -1)
+ exit (EXIT_FAILURE);
+
+ if (guestfs_lvcreate (g, lv, vg, 32) == -1) /* 32 MB is smallest LV */
+ exit (EXIT_FAILURE);
+
+ if (free_dev)
+ free (dev);
+ if (asprintf (&dev, "/dev/%s/%s", vg, lv) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+ free_dev = 1;
+
+ if (guestfs_lvresize_free (g, dev, 100) == -1)
+ exit (EXIT_FAILURE);
+ }
+
+ if (filesystem) {
+ if (guestfs_mkfs_opts (g, filesystem, dev, -1) == -1)
+ exit (EXIT_FAILURE);
+ }
+
+ if (free_dev)
+ free (dev);
+ }
+
+ if (guestfs_sync (g) == -1)
+ exit (EXIT_FAILURE);
+
+ /* Free device list. */
+ for (i = 0; devices[i] != NULL; ++i)
+ free (devices[i]);
+ free (devices);
+
+ return 0;
+}
+
+/* Rescan everything so the kernel knows that there are no partition
+ * tables, VGs etc. Returns 0 on success, 1 if we need to retry.
+ */
+static int
+do_rescan (char **devices)
+{
+ size_t i;
+ int errors = 0;
+ guestfs_error_handler_cb old_error_cb;
+ void *old_error_data;
+
+ old_error_cb = guestfs_get_error_handler (g, &old_error_data);
+ guestfs_set_error_handler (g, NULL, NULL);
+
+ for (i = 0; devices[i] != NULL; ++i) {
+ if (guestfs_blockdev_rereadpt (g, devices[i]) == -1)
+ errors++;
+ }
+
+ if (guestfs_vgscan (g) == -1)
+ errors++;
+
+ guestfs_set_error_handler (g, old_error_cb, old_error_data);
+
+ return errors ? 1 : 0;
+}
diff --git a/format/virt-format.pod b/format/virt-format.pod
new file mode 100755
index 0000000..0b9c52b
--- /dev/null
+++ b/format/virt-format.pod
@@ -0,0 +1,207 @@
+=encoding utf8
+
+=head1 NAME
+
+virt-format - Erase and make a blank disk
+
+=head1 SYNOPSIS
+
+ virt-format [--options] -a disk.img [-a disk.img ...]
+
+=head1 DESCRIPTION
+
+Virt-format takes an existing disk file (or it can be a host
+partition, LV etc), B<erases all data on it>, and formats it as a
+blank disk. It can optionally create partition tables, empty
+filesystems, logical volumes and more.
+
+To create a disk containing data, you may be better to use
+L<virt-make-fs(1)>. If you are creating a blank disk to use in
+L<guestfish(1)>, you should instead use the guestfish I<-N> option.
+
+Normal usage would be something like this:
+
+ virt-format -a disk.qcow
+
+or this:
+
+ virt-format -a /dev/VG/LV
+
+C<disk.qcow> or C</dev/VG/LV> must exist already. B<Any data on these
+disks will be erased by these commands>. These commands will create a
+single empty partition covering the whole disk, with no filesystem
+inside it.
+
+Additional parameters can be used to control the creation of
+partitions, filesystems, etc. The most commonly used options are:
+
+=over 4
+
+=item I<--filesystem=[ext3|ntfs|vfat|...]>
+
+Create an empty filesystem (C<ext3>, C<ntfs> etc) inside the partition.
+
+=item I<--lvm[=/dev/VG/LV]>
+
+Create a Linux LVM2 logical volume on the disk. When used with
+I<--filesystem>, the filesystem is created inside the LV.
+
+=back
+
+For more information about these and other options, see
+L</OPTIONS> below.
+
+The format of the disk is normally auto-detected, but you can also
+force it by using the I<--format> option (q.v.). In situations where
+you do not trust the existing content of the disk, then it is
+advisable to use this option to avoid possible exploits.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+Display brief help.
+
+=item B<-a> file
+
+=item B<--add> file
+
+Add I<file>, a disk image, host partition, LV, external USB disk, etc.
+
+The format of the disk image is auto-detected. To override this and
+force a particular format use the I<--format=..> option.
+
+B<Any existing data on the disk is erased.>
+
+=item B<--filesystem=ext3|ntfs|vfat|...>
+
+Create an empty filesystem of the specified type. Many filesystem
+types are supported by libguestfs.
+
+=item B<--filesystem=none>
+
+Create no filesystem. This is the default.
+
+=item B<--format=raw|qcow2|..>
+
+=item B<--format>
+
+The default for the I<-a> option is to auto-detect the format of the
+disk image. Using this forces the disk format for I<-a> options which
+follow on the command line. Using I<--format> with no argument
+switches back to auto-detection for subsequent I<-a> options.
+
+For example:
+
+ virt-format --format=raw -a disk.img
+
+forces raw format (no auto-detection) for C<disk.img>.
+
+ virt-format --format=raw -a disk.img --format -a another.img
+
+forces raw format (no auto-detection) for C<disk.img> and reverts to
+auto-detection for C<another.img>.
+
+If you have untrusted raw-format guest disk images, you should use
+this option to specify the disk format. This avoids a possible
+security problem with malicious guests (CVE-2010-3851).
+
+=item B<--lvm=/dev/I<VG>/I<LV>>
+
+Create a Linux LVM2 logical volume called C</dev/I<VG>/I<LV>>. You
+can change the name of the volume group and logical volume.
+
+=item B<--lvm>
+
+Create a Linux LVM2 logical volume with the default name
+(C</dev/VG/LV>).
+
+=item B<--lvm=none>
+
+Create no logical volume. This is the default.
+
+=item B<--partition>
+
+Create either an MBR or GPT partition covering the whole disk. MBR is
+chosen if the disk size is E<lt> 2 TB, GPT if E<ge> 2 TB.
+
+This is the default.
+
+=item B<--partition=gpt>
+
+Create a GPT partition.
+
+=item B<--partition=mbr>
+
+Create an MBR partition.
+
+=item B<--partition=none>
+
+Create no partition table. Note that Windows may not be able to see
+these disks.
+
+=item B<-v>
+
+=item B<--verbose>
+
+Enable verbose messages for debugging.
+
+=item B<-V>
+
+=item B<--version>
+
+Display version number and exit.
+
+=item B<--wipe>
+
+Normally virt-format does not wipe data from the disk (because that
+takes a long time). Thus if there is data on the disk, it is only
+hidden and partially overwritten by virt-format, and it might be
+recovered by disk editing tools.
+
+If you use this option, virt-format writes zeroes over the whole disk
+so that previous data is not recoverable.
+
+=item B<-x>
+
+Enable tracing of libguestfs API calls.
+
+=back
+
+=head1 EXIT STATUS
+
+This program returns C<0> on success, or C<1> on failure.
+
+=head1 SEE ALSO
+
+L<guestfs(3)>,
+L<guestfish(1)>,
+L<virt-filesystems(1)>,
+L<virt-make-fs(1)>,
+L<virt-rescue(1)>,
+L<virt-resize(1)>,
+L<http://libguestfs.org/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones
L<http://people.redhat.com/~rjones/>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2012 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.
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 380a3c7..84972db 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -124,6 +124,7 @@ fish/supported.c
fish/tilde.c
fish/time.c
fish/virt.c
+format/format.c
fuse/dircache.c
fuse/guestmount.c
inspector/virt-inspector.c
diff --git a/src/guestfs.pod b/src/guestfs.pod
index f7740b6..55f6e7f 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -2955,6 +2955,10 @@ L<guestfish(1)>, the command-line shell, and various shell
scripts
built on top such as L<virt-copy-in(1)>, L<virt-copy-out(1)>,
L<virt-tar-in(1)>, L<virt-tar-out(1)>.
+=item C<format>
+
+L<virt-format(1)> command and documentation.
+
=item C<fuse>
L<guestmount(1)>, FUSE (userspace filesystem) built on top of libguestfs.
@@ -3271,6 +3275,7 @@ L<virt-copy-out(1)>,
L<virt-df(1)>,
L<virt-edit(1)>,
L<virt-filesystems(1)>,
+L<virt-format(1)>,
L<virt-inspector(1)>,
L<virt-list-filesystems(1)>,
L<virt-list-partitions(1)>,
diff --git a/tests/extra/Makefile.am b/tests/extra/Makefile.am
index 8f34958..83abc65 100644
--- a/tests/extra/Makefile.am
+++ b/tests/extra/Makefile.am
@@ -102,6 +102,7 @@ test-prerequisites:
test-tools-null:
$(RUN_VG) ../../fish/guestfish -N part exit
$(RUN_VG) ../../align/virt-alignment-scan -a test1.img >/dev/null
+ $(RUN_VG) ../../format/virt-format -a test1.img >/dev/null
rm test1.img
$(RUN_VG) ../../cat/virt-filesystems -a /dev/null >/dev/null
$(RUN_VG) ../../cat/virt-filesystems -a /dev/null --all --long -h --uuid >/dev/null
diff --git a/tools/virt-make-fs b/tools/virt-make-fs
index d4e231b..3afbb43 100755
--- a/tools/virt-make-fs
+++ b/tools/virt-make-fs
@@ -54,6 +54,8 @@ which can be useful if you want to attach these filesystems to
existing virtual machines (eg. to import large amounts of read-only
data to a VM).
+To create blank disks, use L<virt-format(1)>.
+
Basic usage is:
virt-make-fs input output.img
@@ -557,6 +559,7 @@ manual page L<sh(1)> for details.
=head1 SEE ALSO
L<guestfish(1)>,
+L<virt-format(1)>,
L<virt-resize(1)>,
L<virt-tar-in(1)>,
L<mkisofs(1)>,
--
1.7.6