[Pkg-libvirt-commits] [libguestfs] 23/61: Add virt-customize standalone tool.
Hilko Bengen
bengen at moszumanska.debian.org
Sat Mar 29 14:36:23 UTC 2014
This is an automated email from the git hooks/post-receive script.
bengen pushed a commit to branch experimental
in repository libguestfs.
commit 2b208d84db080659badbb70044497aae040592e7
Author: Richard W.M. Jones <rjones at redhat.com>
Date: Tue Mar 25 10:46:08 2014 +0000
Add virt-customize standalone tool.
This includes some simple tests and a manual page.
---
.gitignore | 3 +
Makefile.am | 1 +
builder/virt-builder.pod | 1 +
customize/Makefile.am | 41 ++++++--
customize/main.ml | 222 +++++++++++++++++++++++++++++++++++++++
customize/test-virt-customize.sh | 32 ++++++
customize/virt-customize.pod | 156 +++++++++++++++++++++++++++
fish/guestfish.pod | 1 +
po-docs/ja/Makefile.am | 9 ++
po-docs/podfiles | 3 +
po-docs/uk/Makefile.am | 9 ++
src/guestfs.pod | 3 +-
sysprep/virt-sysprep.pod | 1 +
13 files changed, 474 insertions(+), 8 deletions(-)
diff --git a/.gitignore b/.gitignore
index a93eb95..0231a04 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,7 +95,9 @@ Makefile.in
/customize/customize_cmdline.mli
/customize/customize-options.pod
/customize/customize-synopsis.pod
+/customize/stamp-virt-customize.pod
/customize/virt-customize
+/customize/virt-customize.1
/daemon/actions.h
/daemon/errnostring.c
/daemon/errnostring-gperf.c
@@ -236,6 +238,7 @@ Makefile.in
/html/virt-cat.1.html
/html/virt-copy-in.1.html
/html/virt-copy-out.1.html
+/html/virt-customize.1.html
/html/virt-df.1.html
/html/virt-diff.1.html
/html/virt-edit.1.html
diff --git a/Makefile.am b/Makefile.am
index 5b8a82e..ce0f9ad 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -239,6 +239,7 @@ HTMLFILES = \
html/virt-cat.1.html \
html/virt-copy-in.1.html \
html/virt-copy-out.1.html \
+ html/virt-customize.1.html \
html/virt-df.1.html \
html/virt-diff.1.html \
html/virt-edit.1.html \
diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod
index 2429f66..c6e66ff 100644
--- a/builder/virt-builder.pod
+++ b/builder/virt-builder.pod
@@ -1590,6 +1590,7 @@ L<guestfs(3)>,
L<guestfish(1)>,
L<guestmount(1)>,
L<virt-copy-out(1)>,
+L<virt-customize(1)>,
L<virt-install(1)>,
L<virt-rescue(1)>,
L<virt-resize(1)>,
diff --git a/customize/Makefile.am b/customize/Makefile.am
index 889fe1c..2747add 100644
--- a/customize/Makefile.am
+++ b/customize/Makefile.am
@@ -18,9 +18,14 @@
include $(top_srcdir)/subdir-rules.mk
EXTRA_DIST = \
- $(SOURCES)
+ $(SOURCES) \
+ test-virt-customize.sh \
+ virt-customize.pod
-CLEANFILES = *~ *.cmi *.cmo *.cmx *.cmxa *.o
+CLEANFILES = \
+ *~ *.cmi *.cmo *.cmx *.cmxa *.o \
+ stamp-virt-customize.pod \
+ virt-customize virt-customize.1
generator_built = \
customize_cmdline.mli \
@@ -41,6 +46,7 @@ SOURCES = \
firstboot.mli \
hostname.ml \
hostname.mli \
+ main.ml \
password.ml \
password.mli \
perl_edit.ml \
@@ -55,8 +61,12 @@ SOURCES = \
if HAVE_OCAML
deps = \
+ $(top_builddir)/fish/guestfish-uri.o \
$(top_builddir)/mllib/common_gettext.cmx \
$(top_builddir)/mllib/common_utils.cmx \
+ $(top_builddir)/mllib/config.cmx \
+ $(top_builddir)/mllib/uri-c.o \
+ $(top_builddir)/mllib/uRI.cmx \
crypt-c.o
if HAVE_OCAMLOPT
@@ -76,7 +86,8 @@ ocaml_modules = \
random_seed \
timezone \
customize_cmdline \
- customize_run
+ customize_run \
+ main
if HAVE_OCAMLOPT
OBJECTS += $(patsubst %,%.cmx,$(ocaml_modules))
@@ -84,9 +95,7 @@ else
OBJECTS += $(patsubst %,%.cmo,$(ocaml_modules))
endif
-# XXX virt-customize isn't a complete tool yet, so currently this is
-# just a dummy target binary.
-noinst_SCRIPTS = virt-customize
+bin_SCRIPTS = virt-customize
# -I $(top_builddir)/src/.libs is a hack which forces corresponding -L
# option to be passed to gcc, so we don't try linking against an
@@ -144,11 +153,29 @@ DEFAULT_INCLUDES = \
.c.o:
$(CC) $(CFLAGS) $(PROF_CFLAGS) $(DEFAULT_INCLUDES) -c $< -o $@
+# Manual pages and HTML files for the website.
+man_MANS = virt-customize.1
+noinst_DATA = $(top_builddir)/html/virt-customize.1.html
+
+virt-customize.1 $(top_builddir)/html/virt-customize.1.html: stamp-virt-customize.pod
+
+stamp-virt-customize.pod: virt-customize.pod $(top_srcdir)/customize/customize-synopsis.pod $(top_srcdir)/customize/customize-options.pod
+ $(PODWRAPPER) \
+ --man virt-customize.1 \
+ --html $(top_builddir)/html/virt-customize.1.html \
+ --insert $(top_srcdir)/customize/customize-synopsis.pod:__CUSTOMIZE_SYNOPSIS__ \
+ --insert $(top_srcdir)/customize/customize-options.pod:__CUSTOMIZE_OPTIONS__ \
+ --license GPLv2+ \
+ $<
+ touch $@
+
# Tests.
TESTS_ENVIRONMENT = $(top_builddir)/run --test
-TESTS =
+if ENABLE_APPLIANCE
+TESTS = test-virt-customize.sh
+endif
check-valgrind:
$(MAKE) VG="$(top_builddir)/run @VG@" check
diff --git a/customize/main.ml b/customize/main.ml
new file mode 100644
index 0000000..74ecb8e
--- /dev/null
+++ b/customize/main.ml
@@ -0,0 +1,222 @@
+(* virt-customize
+ * 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.
+ *)
+
+open Common_gettext.Gettext
+open Common_utils
+
+open Printf
+
+module G = Guestfs
+
+let () = Random.self_init ()
+
+let prog = Filename.basename Sys.executable_name
+
+let main () =
+ let debug_gc = ref false in
+ let domain = ref None in
+ let dryrun = ref false in
+ let files = ref [] in
+ let format = ref "auto" in
+ let quiet = ref false in
+ let libvirturi = ref "" in
+ let trace = ref false in
+ let verbose = ref false in
+
+ let display_version () =
+ printf "virt-customize %s\n" Config.package_version;
+ exit 0
+ and add_file arg =
+ let uri =
+ try URI.parse_uri arg
+ with Invalid_argument "URI.parse_uri" ->
+ eprintf "Error parsing URI '%s'. Look for error messages printed above.\n" arg;
+ exit 1 in
+ let format = match !format with "auto" -> None | fmt -> Some fmt in
+ files := (uri, format) :: !files
+ and set_domain dom =
+ if !domain <> None then (
+ eprintf (f_"%s: --domain option can only be given once\n") prog;
+ exit 1
+ );
+ domain := Some dom
+ in
+
+ let argspec = [
+ "-a", Arg.String add_file, s_"file" ^ " " ^ s_"Add disk image file";
+ "--add", Arg.String add_file, s_"file" ^ " " ^ s_"Add disk image file";
+ "-c", Arg.Set_string libvirturi, s_"uri" ^ " " ^ s_"Set libvirt URI";
+ "--connect", Arg.Set_string libvirturi, s_"uri" ^ " " ^ s_"Set libvirt URI";
+ "--debug-gc", Arg.Set debug_gc, " " ^ s_"Debug GC and memory allocations (internal)";
+ "-d", Arg.String set_domain, s_"domain" ^ " " ^ s_"Set libvirt guest name";
+ "--domain", Arg.String set_domain, s_"domain" ^ " " ^ s_"Set libvirt guest name";
+ "-n", Arg.Set dryrun, " " ^ s_"Perform a dry run";
+ "--dryrun", Arg.Set dryrun, " " ^ s_"Perform a dry run";
+ "--dry-run", Arg.Set dryrun, " " ^ s_"Perform a dry run";
+ "--format", Arg.Set_string format, s_"format" ^ " " ^ s_"Set format (default: auto)";
+ "--long-options", Arg.Unit display_long_options, " " ^ s_"List long options";
+ "-q", Arg.Set quiet, " " ^ s_"Don't print log messages";
+ "--quiet", Arg.Set quiet, " " ^ s_"Don't print log messages";
+ "-v", Arg.Set verbose, " " ^ s_"Enable debugging messages";
+ "--verbose", Arg.Set verbose, " " ^ s_"Enable debugging messages";
+ "-V", Arg.Unit display_version, " " ^ s_"Display version and exit";
+ "--version", Arg.Unit display_version, " " ^ s_"Display version and exit";
+ "-x", Arg.Set trace, " " ^ s_"Enable tracing of libguestfs calls";
+ ] in
+ let customize_argspec, get_customize_ops =
+ Customize_cmdline.argspec ~prog () in
+ let customize_argspec =
+ List.map (fun (spec, _, _) -> spec) customize_argspec in
+ let argspec = argspec @ customize_argspec in
+ let argspec =
+ let cmp (arg1, _, _) (arg2, _, _) =
+ let arg1 = skip_dashes arg1 and arg2 = skip_dashes arg2 in
+ compare (String.lowercase arg1) (String.lowercase arg2)
+ in
+ List.sort cmp argspec in
+ let argspec = Arg.align argspec in
+ long_options := argspec;
+
+ let anon_fun _ = raise (Arg.Bad (s_"extra parameter on the command line")) in
+ let usage_msg =
+ sprintf (f_"\
+%s: customize a virtual machine
+
+ virt-customize [--options] -d domname
+
+ virt-customize [--options] -a disk.img [-a disk.img ...]
+
+A short summary of the options is given below. For detailed help please
+read the man page virt-customize(1).
+")
+ prog in
+ Arg.parse argspec anon_fun usage_msg;
+
+ (* Check -a and -d options. *)
+ let files = !files in
+ let domain = !domain in
+ let libvirturi = match !libvirturi with "" -> None | s -> Some s in
+ let add =
+ match files, domain with
+ | [], None ->
+ eprintf (f_"%s: you must give either -a or -d options\n") prog;
+ eprintf (f_"Read virt-customize(1) man page for further information.\n");
+ exit 1
+ | [], Some dom ->
+ fun (g : Guestfs.guestfs) readonly ->
+ let allowuuid = true in
+ let readonlydisk = "ignore" (* ignore CDs, data drives *) in
+ let discard = if readonly then None else Some "besteffort" in
+ ignore (g#add_domain
+ ~readonly ?discard
+ ?libvirturi ~allowuuid ~readonlydisk
+ dom)
+ | _, Some _ ->
+ eprintf (f_"%s: you cannot give -a and -d options together\n") prog;
+ eprintf (f_"Read virt-customize(1) man page for further information.\n");
+ exit 1
+ | files, None ->
+ fun g readonly ->
+ List.iter (
+ fun (uri, format) ->
+ let { URI.path = path; protocol = protocol;
+ server = server; username = username } = uri in
+ let discard = if readonly then None else Some "besteffort" in
+ g#add_drive
+ ~readonly ?discard
+ ?format ~protocol ?server ?username
+ path
+ ) files
+ in
+
+ (* Dereference the rest of the args. *)
+ let debug_gc = !debug_gc in
+ let dryrun = !dryrun in
+ let quiet = !quiet in
+ let trace = !trace in
+ let verbose = !verbose in
+
+ let ops = get_customize_ops () in
+
+ let msg fs = make_message_function ~quiet fs in
+
+ msg (f_"Examining the guest ...");
+
+ (* Connect to libguestfs. *)
+ let g = new G.guestfs () in
+ if trace then g#set_trace true;
+ if verbose then g#set_verbose true;
+ add g dryrun;
+ g#launch ();
+
+ (* Inspection. *)
+ (match Array.to_list (g#inspect_os ()) with
+ | [] ->
+ eprintf (f_"%s: no operating systems were found in the guest image\n") prog;
+ exit 1
+ | roots ->
+ List.iter (
+ fun root ->
+ (* Mount up the disks, like guestfish -i.
+ * See [ocaml/examples/inspect_vm.ml].
+ *)
+ let mps = g#inspect_get_mountpoints root in
+ let cmp (a,_) (b,_) = compare (String.length a) (String.length b) in
+ let mps = List.sort cmp mps in
+ List.iter (
+ fun (mp, dev) ->
+ try g#mount dev mp;
+ with Guestfs.Error msg -> eprintf (f_"%s (ignored)\n") msg
+ ) mps;
+
+ (* Do the customization. *)
+ Customize_run.run ~prog ~debug:verbose ~quiet g root ops;
+
+ g#umount_all ();
+ ) roots;
+ );
+
+ g#shutdown ();
+ g#close ();
+
+ if debug_gc then
+ Gc.compact ()
+
+(* Finished. *)
+let () =
+ (try main ()
+ with
+ | Failure msg -> (* from failwith/failwithf *)
+ eprintf (f_"%s: %s\n") prog msg;
+ exit 1
+ | Invalid_argument msg -> (* probably should never happen *)
+ eprintf (f_"%s: internal error: invalid argument: %s\n") prog msg;
+ exit 1
+ | Assert_failure (file, line, char) -> (* should never happen *)
+ eprintf (f_"%s: internal error: assertion failed at %s, line %d, char %d\n")
+ prog file line char;
+ exit 1
+ | Not_found -> (* should never happen *)
+ eprintf (f_"%s: internal error: Not_found exception was thrown\n") prog;
+ exit 1
+ | exn ->
+ eprintf (f_"%s: exception: %s\n") prog (Printexc.to_string exn);
+ exit 1
+ );
+
+ exit 0
diff --git a/customize/test-virt-customize.sh b/customize/test-virt-customize.sh
new file mode 100755
index 0000000..877e8d3
--- /dev/null
+++ b/customize/test-virt-customize.sh
@@ -0,0 +1,32 @@
+#!/bin/bash -
+# libguestfs virt-customize test script
+# 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.
+
+export LANG=C
+set -e
+
+# virt-customize with the -n option doesn't modify the guest. It ought
+# to be able to customize any of our Linux-like test guests.
+
+for f in ../tests/guests/{debian,fedora,ubuntu}.img; do
+ # Ignore zero-sized windows.img if ntfs-3g is not installed.
+ if [ -s "$f" ]; then
+ $VG ./virt-customize -n -a $f \
+ --write /etc/motd:HELLO \
+ --delete /etc/motd
+ fi
+done
diff --git a/customize/virt-customize.pod b/customize/virt-customize.pod
new file mode 100644
index 0000000..9c7f0fd
--- /dev/null
+++ b/customize/virt-customize.pod
@@ -0,0 +1,156 @@
+=head1 NAME
+
+virt-customize - Customize a virtual machine
+
+=head1 SYNOPSIS
+
+ virt-customize [--options] -d domname
+__CUSTOMIZE_SYNOPSIS__
+
+ virt-customize [--options] -a disk.img [-a disk.img ...]
+__CUSTOMIZE_SYNOPSIS__
+
+=head1 DESCRIPTION
+
+Virt-customize can customize a virtual machine (disk image) by
+installing packages, editing configuration files, and so on.
+
+Virt-customize modifies the guest or disk image I<in place>. The
+guest must be shut down. If you want to preserve the existing
+contents of the guest, I<you must snapshot, copy or clone the disk first>.
+
+You do I<not> need to run virt-customize as root. In fact we'd
+generally recommend that you don't.
+
+Related tools include: L<virt-sysprep(1)> and L<virt-builder(1)>.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+Display brief help.
+
+=item B<-a> file
+
+=item B<--add> file
+
+Add I<file> which should be a disk image from a virtual machine.
+
+The format of the disk image is auto-detected. To override this and
+force a particular format use the I<--format> option.
+
+=item B<-a> URI
+
+=item B<--add> URI
+
+Add a remote disk. The URI format is compatible with guestfish.
+See L<guestfish(1)/ADDING REMOTE STORAGE>.
+
+=item B<-c> URI
+
+=item B<--connect> URI
+
+If using libvirt, connect to the given I<URI>. If omitted, then we
+connect to the default libvirt hypervisor.
+
+If you specify guest block devices directly (I<-a>), then libvirt is
+not used at all.
+
+=item B<-d> guest
+
+=item B<--domain> guest
+
+Add all the disks from the named libvirt guest. Domain UUIDs can be
+used instead of names.
+
+=item B<-n>
+
+=item B<--dry-run>
+
+Perform a read-only "dry run" on the guest. This runs the sysprep
+operation, but throws away any changes to the disk at the end.
+
+=item B<--format> raw|qcow2|..
+
+=item B<--format> auto
+
+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 auto> switches back to
+auto-detection for subsequent I<-a> options.
+
+For example:
+
+ virt-customize --format raw -a disk.img
+
+forces raw format (no auto-detection) for C<disk.img>.
+
+ virt-customize --format raw -a disk.img --format auto -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<-q>
+
+=item B<--quiet>
+
+Don't print log messages.
+
+To enable detailed logging of individual file operations, use I<-x>.
+
+=item B<-v>
+
+=item B<--verbose>
+
+Enable verbose messages for debugging.
+
+=item B<-V>
+
+=item B<--version>
+
+Display version number and exit.
+
+=item B<-x>
+
+Enable tracing of libguestfs API calls.
+
+=back
+
+=head2 Customization options
+
+__CUSTOMIZE_OPTIONS__
+
+=head1 EXIT STATUS
+
+This program returns 0 on success, or 1 if there was an error.
+
+=head1 SEE ALSO
+
+L<guestfs(3)>,
+L<guestfish(1)>,
+L<virt-builder(1)>,
+L<virt-clone(1)>,
+L<virt-rescue(1)>,
+L<virt-resize(1)>,
+L<virt-sparsify(1)>,
+L<virt-sysprep(1)>,
+L<virsh(1)>,
+L<lvcreate(8)>,
+L<qemu-img(1)>,
+L<scrub(1)>,
+L<http://libguestfs.org/>,
+L<http://libvirt.org/>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones L<http://people.redhat.com/~rjones/>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2011-2014 Red Hat Inc.
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index a53ef92..25279fb 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -1607,6 +1607,7 @@ L<virt-builder(1)>,
L<virt-cat(1)>,
L<virt-copy-in(1)>,
L<virt-copy-out(1)>,
+L<virt-customize(1)>,
L<virt-df(1)>,
L<virt-diff(1)>,
L<virt-edit(1)>,
diff --git a/po-docs/ja/Makefile.am b/po-docs/ja/Makefile.am
index f17be96..0b9df84 100644
--- a/po-docs/ja/Makefile.am
+++ b/po-docs/ja/Makefile.am
@@ -116,6 +116,15 @@ virt-builder.1: virt-builder.pod customize-synopsis.pod customize-options.pod
--insert $(srcdir)/customize-options.pod:__CUSTOMIZE_OPTIONS__ \
$<
+virt-customize.1: virt-customize.pod customize-synopsis.pod customize-options.pod
+ $(PODWRAPPER) \
+ --no-strict-checks \
+ --man $@ \
+ --license GPLv2+ \
+ --insert $(srcdir)/customize-synopsis.pod:__CUSTOMIZE_SYNOPSIS__ \
+ --insert $(srcdir)/customize-options.pod:__CUSTOMIZE_OPTIONS__ \
+ $<
+
virt-sysprep.1: virt-sysprep.pod sysprep-extra-options.pod sysprep-operations.pod
$(PODWRAPPER) \
--no-strict-checks \
diff --git a/po-docs/podfiles b/po-docs/podfiles
index d863554..2094601 100644
--- a/po-docs/podfiles
+++ b/po-docs/podfiles
@@ -5,6 +5,9 @@
../cat/virt-cat.pod
../cat/virt-filesystems.pod
../cat/virt-ls.pod
+../customize/customize-options.pod
+../customize/customize-synopsis.pod
+../customize/virt-customize.pod
../daemon/guestfsd.pod
../df/virt-df.pod
../diff/virt-diff.pod
diff --git a/po-docs/uk/Makefile.am b/po-docs/uk/Makefile.am
index f17be96..0b9df84 100644
--- a/po-docs/uk/Makefile.am
+++ b/po-docs/uk/Makefile.am
@@ -116,6 +116,15 @@ virt-builder.1: virt-builder.pod customize-synopsis.pod customize-options.pod
--insert $(srcdir)/customize-options.pod:__CUSTOMIZE_OPTIONS__ \
$<
+virt-customize.1: virt-customize.pod customize-synopsis.pod customize-options.pod
+ $(PODWRAPPER) \
+ --no-strict-checks \
+ --man $@ \
+ --license GPLv2+ \
+ --insert $(srcdir)/customize-synopsis.pod:__CUSTOMIZE_SYNOPSIS__ \
+ --insert $(srcdir)/customize-options.pod:__CUSTOMIZE_OPTIONS__ \
+ $<
+
virt-sysprep.1: virt-sysprep.pod sysprep-extra-options.pod sysprep-operations.pod
$(PODWRAPPER) \
--no-strict-checks \
diff --git a/src/guestfs.pod b/src/guestfs.pod
index e6e91f4..a81cc6d 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -4274,7 +4274,7 @@ Outside contributions, experimental parts.
=item C<customize>
-virt-customize mini-library.
+L<virt-customize(1)> command and documentation.
=item C<daemon>
@@ -4735,6 +4735,7 @@ L<virt-builder(1)>,
L<virt-cat(1)>,
L<virt-copy-in(1)>,
L<virt-copy-out(1)>,
+L<virt-customize(1)>,
L<virt-df(1)>,
L<virt-diff(1)>,
L<virt-edit(1)>,
diff --git a/sysprep/virt-sysprep.pod b/sysprep/virt-sysprep.pod
index aa570a5..b59c796 100644
--- a/sysprep/virt-sysprep.pod
+++ b/sysprep/virt-sysprep.pod
@@ -528,6 +528,7 @@ L<guestfs(3)>,
L<guestfish(1)>,
L<virt-builder(1)>,
L<virt-clone(1)>,
+L<virt-customize(1)>,
L<virt-rescue(1)>,
L<virt-resize(1)>,
L<virt-sparsify(1)>,
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-libvirt/libguestfs.git
More information about the Pkg-libvirt-commits
mailing list