Extract the guest kernel/ramdisk extraction from virt-builder into a
separate utility, so it can be used and improved without cluttering
virt-builder.
Currently it does what virt-builder --get-kernel did, adding also the
options for remote disks and libvirt access, much like other libguestfs
tools.
virt-builder --get-kernel now just spawns virt-get-kernel.
---
.gitignore | 5 ++
Makefile.am | 3 +-
builder/Makefile.am | 2 -
builder/builder.ml | 15 +++-
builder/get_kernel.ml | 92 --------------------
builder/get_kernel.mli | 19 -----
configure.ac | 1 +
get-kernel/Makefile.am | 146 ++++++++++++++++++++++++++++++++
get-kernel/get_kernel.ml | 185 +++++++++++++++++++++++++++++++++++++++++
get-kernel/virt-get-kernel.pod | 148 +++++++++++++++++++++++++++++++++
po/POTFILES-ml | 2 +-
run.in | 1 +
12 files changed, 502 insertions(+), 117 deletions(-)
delete mode 100644 builder/get_kernel.ml
delete mode 100644 builder/get_kernel.mli
create mode 100644 get-kernel/Makefile.am
create mode 100644 get-kernel/get_kernel.ml
create mode 100644 get-kernel/virt-get-kernel.pod
diff --git a/.gitignore b/.gitignore
index d1292d9..6f14915 100644
--- a/.gitignore
+++ b/.gitignore
@@ -193,6 +193,10 @@ Makefile.in
/generator/generator
/generator/.pod2text.data*
/generator/stamp-generator
+/get-kernel/.depend
+/get-kernel/stamp-virt-get-kernel.pod
+/get-kernel/virt-get-kernel
+/get-kernel/virt-get-kernel.1
/.gitattributes
/.git-module-status
/gnulib
@@ -245,6 +249,7 @@ Makefile.in
/html/virt-edit.1.html
/html/virt-filesystems.1.html
/html/virt-format.1.html
+/html/virt-get-kernel.1.html
/html/virt-index-validate.1.html
/html/virt-inspector.1.html
/html/virt-list-filesystems.1.html
diff --git a/Makefile.am b/Makefile.am
index 331a34e..ad6d9d3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -133,6 +133,7 @@ SUBDIRS += \
mllib \
customize \
builder builder/website \
+ get-kernel \
resize \
sparsify \
sysprep \
@@ -353,7 +354,7 @@ all-local:
grep -v -E '^python/utils.c$$' | \
LC_ALL=C sort > po/POTFILES
cd $(srcdir); \
- find builder customize mllib resize sparsify sysprep v2v -name '*.ml' | \
+ find builder customize get-kernel mllib resize sparsify sysprep v2v -name '*.ml'
| \
LC_ALL=C sort > po/POTFILES-ml
# Try to stop people using 'make install' without 'DESTDIR'.
diff --git a/builder/Makefile.am b/builder/Makefile.am
index 28b2adf..d69e25f 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -39,7 +39,6 @@ CLEANFILES = *~ *.annot *.cmi *.cmo *.cmx *.cmxa *.o virt-builder
SOURCES_MLI = \
cache.mli \
downloader.mli \
- get_kernel.mli \
index_parser.mli \
ini_reader.mli \
languages.mli \
@@ -56,7 +55,6 @@ SOURCES_ML = \
ini_reader.ml \
paths.ml \
languages.ml \
- get_kernel.ml \
cache.ml \
sources.ml \
downloader.ml \
diff --git a/builder/builder.ml b/builder/builder.ml
index 5ea69c0..1f618ad 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -91,8 +91,19 @@ let main () =
let mode =
match mode with
| `Get_kernel -> (* --get-kernel is really a different program ... *)
- Get_kernel.get_kernel ?format ?output arg;
- exit 0
+ let cmd =
+ sprintf "virt-get-kernel%s%s%s%s --add %s"
+ (if verbose () then " --verbose" else "")
+ (if trace () then " -x" else "")
+ (match format with
+ | None -> ""
+ | Some format -> sprintf " --format %s" (quote format))
+ (match output with
+ | None -> ""
+ | Some output -> sprintf " --output %s" (quote output))
+ (quote arg) in
+ if verbose () then printf "%s\n%!" cmd;
+ exit (Sys.command cmd)
| `Delete_cache -> (* --delete-cache *)
(match cache with
diff --git a/builder/get_kernel.ml b/builder/get_kernel.ml
deleted file mode 100644
index 5cea647..0000000
--- a/builder/get_kernel.ml
+++ /dev/null
@@ -1,92 +0,0 @@
-(* virt-builder
- * Copyright (C) 2013 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 Utils
-
-module G = Guestfs
-
-open Printf
-
-(* Originally:
- *
http://rwmj.wordpress.com/2013/09/13/get-kernel-and-initramfs-from-a-disk...
- *)
-let rec get_kernel ?format ?output disk =
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
- g#add_drive_opts ?format ~readonly:true disk;
- g#launch ();
-
- let roots = g#inspect_os () in
- if Array.length roots = 0 then
- error (f_"get-kernel: no operating system found");
- if Array.length roots > 1 then
- error (f_"get-kernel: dual/multi-boot images are not supported by this
tool");
- let root = roots.(0) in
-
- (* Mount up the disks. *)
- 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_ro dev mp
- with Guestfs.Error msg -> warning (f_"%s (ignored)") msg
- ) mps;
-
- (* Get all kernels and initramfses. *)
- let glob w = Array.to_list (g#glob_expand w) in
- let kernels = glob "/boot/vmlinuz-*" in
- let initrds = glob "/boot/initramfs-*" in
-
- (* Old RHEL: *)
- let initrds = if initrds <> [] then initrds else glob "/boot/initrd-*"
in
-
- (* Debian/Ubuntu: *)
- let initrds = if initrds <> [] then initrds else glob
"/boot/initrd.img-*" in
-
- (* Sort by version to get the latest version as first element. *)
- let kernels = List.rev (List.sort compare_version kernels) in
- let initrds = List.rev (List.sort compare_version initrds) in
-
- if kernels = [] then
- error (f_"no kernel found");
-
- (* Download the latest. *)
- let outputdir =
- match output with
- | None -> Filename.current_dir_name
- | Some dir -> dir in
- let kernel_in = List.hd kernels in
- let kernel_out = outputdir // Filename.basename kernel_in in
- printf "download: %s -> %s\n%!" kernel_in kernel_out;
- g#download kernel_in kernel_out;
-
- if initrds <> [] then (
- let initrd_in = List.hd initrds in
- let initrd_out = outputdir // Filename.basename initrd_in in
- printf "download: %s -> %s\n%!" initrd_in initrd_out;
- g#download initrd_in initrd_out
- );
-
- (* Shutdown. *)
- g#shutdown ();
- g#close ()
diff --git a/builder/get_kernel.mli b/builder/get_kernel.mli
deleted file mode 100644
index 5f47ca1..0000000
--- a/builder/get_kernel.mli
+++ /dev/null
@@ -1,19 +0,0 @@
-(* virt-builder
- * Copyright (C) 2013 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.
- *)
-
-val get_kernel : ?format:string -> ?output:string -> string -> unit
diff --git a/configure.ac b/configure.ac
index 2c82c35..e0da1ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1749,6 +1749,7 @@ AC_CONFIG_FILES([Makefile
format/Makefile
fuse/Makefile
generator/Makefile
+ get-kernel/Makefile
gnulib/lib/Makefile
gnulib/tests/Makefile
gobject/libguestfs-gobject-1.0.pc
diff --git a/get-kernel/Makefile.am b/get-kernel/Makefile.am
new file mode 100644
index 0000000..f217128
--- /dev/null
+++ b/get-kernel/Makefile.am
@@ -0,0 +1,146 @@
+# libguestfs get-kernel tool
+# Copyright (C) 2015 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 = \
+ $(SOURCES_ML) $(SOURCES_C) \
+ virt-get-kernel.pod
+
+CLEANFILES = *~ *.annot *.cmi *.cmo *.cmx *.cmxa *.o virt-get-kernel
+
+SOURCES_ML = \
+ get_kernel.ml
+
+SOURCES_C = \
+ $(top_srcdir)/mllib/uri-c.c \
+ $(top_srcdir)/fish/uri.c
+
+man_MANS =
+noinst_DATA =
+bin_PROGRAMS =
+
+if HAVE_OCAML
+
+bin_PROGRAMS += virt-get-kernel
+
+virt_get_kernel_SOURCES = $(SOURCES_C)
+virt_get_kernel_CPPFLAGS = \
+ -I. \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
+ -I$(shell $(OCAMLC) -where) \
+ -I$(top_srcdir)/gnulib/lib \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/fish
+virt_get_kernel_CFLAGS = \
+ -pthread \
+ $(WARN_CFLAGS) $(WERROR_CFLAGS) \
+ $(LIBXML2_CFLAGS)
+
+BOBJECTS = \
+ $(top_builddir)/mllib/libdir.cmo \
+ $(top_builddir)/mllib/config.cmo \
+ $(top_builddir)/mllib/common_gettext.cmo \
+ $(top_builddir)/mllib/common_utils.cmo \
+ $(top_builddir)/mllib/uRI.cmo \
+ $(SOURCES_ML:.ml=.cmo)
+XOBJECTS = $(BOBJECTS:.cmo=.cmx)
+
+# -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
+# installed copy of libguestfs.
+OCAMLPACKAGES = \
+ -package str,unix \
+ -I $(top_builddir)/src/.libs \
+ -I $(top_builddir)/gnulib/lib/.libs \
+ -I $(top_builddir)/ocaml \
+ -I $(top_builddir)/mllib
+if HAVE_OCAML_PKG_GETTEXT
+OCAMLPACKAGES += -package gettext-stub
+endif
+
+OCAMLCLIBS = \
+ -pthread -lpthread \
+ -lutils \
+ $(LIBXML2_LIBS) \
+ $(LIBINTL) \
+ -lgnu
+
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+
+if !HAVE_OCAMLOPT
+OBJECTS = $(BOBJECTS)
+BEST = c
+OCAMLLINKFLAGS = mlguestfs.cma -custom
+else
+OBJECTS = $(XOBJECTS)
+BEST = opt
+OCAMLLINKFLAGS = mlguestfs.cmxa
+endif
+
+virt_get_kernel_DEPENDENCIES = $(OBJECTS) $(top_srcdir)/ocaml-link.sh
+virt_get_kernel_LINK = \
+ $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \
+ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLPACKAGES) $(OCAMLLINKFLAGS) \
+ $(OBJECTS) -o $@
+
+.mli.cmi:
+ $(OCAMLFIND) ocamlc $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
+.ml.cmo:
+ $(OCAMLFIND) ocamlc $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
+if HAVE_OCAMLOPT
+.ml.cmx:
+ $(OCAMLFIND) ocamlopt $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
+endif
+
+# Manual pages and HTML files for the website.
+
+man_MANS += virt-get-kernel.1
+noinst_DATA += $(top_builddir)/html/virt-get-kernel.1.html
+
+virt-get-kernel.1 $(top_builddir)/html/virt-get-kernel.1.html: stamp-virt-get-kernel.pod
+
+stamp-virt-get-kernel.pod: virt-get-kernel.pod
+ $(PODWRAPPER) \
+ --man virt-get-kernel.1 \
+ --html $(top_builddir)/html/virt-get-kernel.1.html \
+ --license GPLv2+ \
+ $<
+ touch $@
+
+CLEANFILES += stamp-virt-get-kernel.pod
+
+# Dependencies.
+depend: .depend
+
+.depend: $(wildcard $(abs_srcdir)/*.mli) $(wildcard $(abs_srcdir)/*.ml)
+ rm -f $@ $@-t
+ $(OCAMLFIND) ocamldep -I ../ocaml -I $(abs_srcdir) -I $(abs_top_builddir)/mllib $^ | \
+ $(SED) 's/ *$$//' | \
+ $(SED) -e :a -e '/ *\\$$/N; s/ *\\\n */ /; ta' | \
+ $(SED) -e 's,$(abs_srcdir)/,$(builddir)/,g' | \
+ sort > $@-t
+ mv $@-t $@
+
+-include .depend
+
+endif
+
+DISTCLEANFILES = .depend
+
+.PHONY: depend
diff --git a/get-kernel/get_kernel.ml b/get-kernel/get_kernel.ml
new file mode 100644
index 0000000..646a240
--- /dev/null
+++ b/get-kernel/get_kernel.ml
@@ -0,0 +1,185 @@
+(* virt-get-kernel
+ * Copyright (C) 2013-2015 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
+
+module G = Guestfs
+
+open Printf
+
+(* Main program. *)
+let main () =
+ let add, output =
+ let domain = ref None in
+ let file = ref None in
+ let libvirturi = ref "" in
+ let format = ref "" in
+ let output = ref "" in
+ let machine_readable = ref false in
+
+ let set_file arg =
+ if !file <> None then
+ error (f_"--add option can only be given once");
+ let uri =
+ try URI.parse_uri arg
+ with Invalid_argument "URI.parse_uri" ->
+ error (f_"error parsing URI '%s'. Look for error messages printed
above.") arg in
+ file := Some uri
+ and set_domain dom =
+ if !domain <> None then
+ error (f_"--domain option can only be given once");
+ domain := Some dom in
+
+ let ditto = " -\"-" in
+ let argspec = Arg.align [
+ "-a", Arg.String set_file, s_"file" ^ "
" ^ s_"Add disk image file";
+ "--add", Arg.String set_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";
+ "-d", Arg.String set_domain, s_"domain" ^ "
" ^ s_"Set libvirt guest name";
+ "--domain", Arg.String set_domain, s_"domain" ^ "
" ^ s_"Set libvirt guest name";
+ "--format", Arg.Set_string format, s_"format" ^ "
" ^ s_"Format of input disk";
+ "--short-options", Arg.Unit display_short_options, " " ^
s_"List short options";
+ "--long-options", Arg.Unit display_long_options, " " ^
s_"List long options";
+ "--machine-readable", Arg.Set machine_readable, " " ^
s_"Make output machine readable";
+ "-o", Arg.Set_string output, s_"directory" ^ "
" ^ s_"Output directory";
+ "--output", Arg.Set_string output, ditto;
+ "-v", Arg.Unit set_verbose, " " ^ s_"Enable
debugging messages";
+ "--verbose", Arg.Unit set_verbose, ditto;
+ "-V", Arg.Unit print_version_and_exit,
+ " " ^ s_"Display version and
exit";
+ "--version", Arg.Unit print_version_and_exit, ditto;
+ "-x", Arg.Unit set_trace, " " ^ s_"Enable
tracing of libguestfs calls";
+ ] in
+ long_options := argspec;
+ let anon_fun _ = raise (Arg.Bad (s_"extra parameter on the command line"))
in
+ let usage_msg =
+ sprintf (f_"\
+%s: extract kernel and ramdisk from a guest
+
+A short summary of the options is given below. For detailed help please
+read the man page virt-get-kernel(1).
+")
+ prog in
+ Arg.parse argspec anon_fun usage_msg;
+
+ (* Machine-readable mode? Print out some facts about what
+ * this binary supports.
+ *)
+ if !machine_readable then (
+ printf "virt-get-kernel\n";
+ exit 0
+ );
+
+ (* Check -a and -d options. *)
+ let file = !file in
+ let domain = !domain in
+ let libvirturi = match !libvirturi with "" -> None | s -> Some s in
+ let add =
+ match file, domain with
+ | None, None ->
+ error (f_"you must give either -a or -d options. Read virt-get-kernel(1)
man page for further information.")
+ | Some _, Some _ ->
+ error (f_"you cannot give -a and -d options together. Read
virt-get-kernel(1) man page for further information.")
+ | None, Some dom ->
+ fun (g : Guestfs.guestfs) ->
+ let readonlydisk = "ignore" (* ignore CDs, data drives *) in
+ ignore (g#add_domain
+ ~readonly:true ~allowuuid:true ~readonlydisk
+ ?libvirturi dom)
+ | Some uri, None ->
+ fun g ->
+ let { URI.path = path; protocol = protocol;
+ server = server; username = username;
+ password = password } = uri in
+ let format = match !format with "" -> None | s -> Some s in
+ g#add_drive
+ ~readonly:true ?format ~protocol ?server ?username ?secret:password
+ path
+ in
+
+ (* Dereference the rest of the args. *)
+ let output = match !output with "" -> None | str -> Some str in
+
+ add, output in
+
+ (* 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;
+ g#launch ();
+
+ let roots = g#inspect_os () in
+ if Array.length roots = 0 then
+ error (f_"get-kernel: no operating system found");
+ if Array.length roots > 1 then
+ error (f_"get-kernel: dual/multi-boot images are not supported by this
tool");
+ let root = roots.(0) in
+
+ (* Mount up the disks. *)
+ 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_ro dev mp
+ with Guestfs.Error msg -> warning (f_"%s (ignored)") msg
+ ) mps;
+
+ (* Get all kernels and initramfses. *)
+ let glob w = Array.to_list (g#glob_expand w) in
+ let kernels = glob "/boot/vmlinuz-*" in
+ let initrds = glob "/boot/initramfs-*" in
+
+ (* Old RHEL: *)
+ let initrds = if initrds <> [] then initrds else glob "/boot/initrd-*"
in
+
+ (* Debian/Ubuntu: *)
+ let initrds = if initrds <> [] then initrds else glob
"/boot/initrd.img-*" in
+
+ (* Sort by version to get the latest version as first element. *)
+ let kernels = List.rev (List.sort compare_version kernels) in
+ let initrds = List.rev (List.sort compare_version initrds) in
+
+ if kernels = [] then
+ error (f_"no kernel found");
+
+ (* Download the latest. *)
+ let outputdir =
+ match output with
+ | None -> Filename.current_dir_name
+ | Some dir -> dir in
+ let kernel_in = List.hd kernels in
+ let kernel_out = outputdir // Filename.basename kernel_in in
+ printf "download: %s -> %s\n%!" kernel_in kernel_out;
+ g#download kernel_in kernel_out;
+
+ if initrds <> [] then (
+ let initrd_in = List.hd initrds in
+ let initrd_out = outputdir // Filename.basename initrd_in in
+ printf "download: %s -> %s\n%!" initrd_in initrd_out;
+ g#download initrd_in initrd_out
+ );
+
+ (* Shutdown. *)
+ g#shutdown ();
+ g#close ()
+
+let () = run_main_and_handle_errors main
diff --git a/get-kernel/virt-get-kernel.pod b/get-kernel/virt-get-kernel.pod
new file mode 100644
index 0000000..e130b4c
--- /dev/null
+++ b/get-kernel/virt-get-kernel.pod
@@ -0,0 +1,148 @@
+=head1 NAME
+
+virt-get-kernel - Extract kernel and ramdisk from guests
+
+=head1 SYNOPSIS
+
+ virt-get-kernel [--options] -d domname
+
+ virt-get-kernel [--options] -a disk.img
+
+=head1 DESCRIPTION
+
+This option extracts the kernel and initramfs from a guest.
+
+The format of the disk image is automatically detected unless you
+specify it by using the I<--format> option.
+
+In the case where the guest contains multiple kernels, the one with
+the highest version number is chosen. To extract arbitrary kernels
+from the disk image, see L<guestfish(1)>. To extract the entire
+C</boot> directory of a guest, see L<virt-copy-out(1)>.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+Display 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<--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 the I<-a> option
+on the command line.
+
+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<--machine-readable>
+
+This option is used to make the output more machine friendly
+when being parsed by other programs. See
+L</MACHINE READABLE OUTPUT> below.
+
+=item B<-o> directory
+
+=item B<--output> directory
+
+This option specifies the output directory where kernel and initramfs
+from the guest are written.
+
+If not specified, the default output is the current directory.
+
+=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
+
+=head1 MACHINE READABLE OUTPUT
+
+The I<--machine-readable> option can be used to make the output more
+machine friendly, which is useful when calling virt-get-kernel from
+other programs, GUIs etc.
+
+Use the option on its own to query the capabilities of the
+virt-get-kernel binary. Typical output looks like this:
+
+ $ virt-get-kernel --machine-readable
+ virt-get-kernel
+
+A list of features is printed, one per line, and the program exits
+with status 0.
+
+=head1 ENVIRONMENT VARIABLES
+
+For other environment variables which affect all libguestfs programs,
+see L<guestfs(3)/ENVIRONMENT VARIABLES>.
+
+=head1 EXIT STATUS
+
+This program returns 0 if successful, or non-zero if there was an
+error.
+
+=head1 SEE ALSO
+
+L<guestfs(3)>,
+L<guestfish(1)>,
+L<guestmount(1)>,
+L<virt-copy-out(1)>,
+L<http://libguestfs.org/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones
L<http://people.redhat.com/~rjones/>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2013-2015 Red Hat Inc.
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 3fc60e5..8725385 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -2,7 +2,6 @@ builder/builder.ml
builder/cache.ml
builder/cmdline.ml
builder/downloader.ml
-builder/get_kernel.ml
builder/index_parser.ml
builder/ini_reader.ml
builder/languages.ml
@@ -26,6 +25,7 @@ customize/random_seed.ml
customize/ssh_key.ml
customize/timezone.ml
customize/urandom.ml
+get-kernel/get_kernel.ml
mllib/JSON.ml
mllib/JSON_tests.ml
mllib/common_gettext.ml
diff --git a/run.in b/run.in
index 8fdf454..6709cdd 100755
--- a/run.in
+++ b/run.in
@@ -92,6 +92,7 @@ prepend PATH "$b/erlang"
prepend PATH "$b/fish"
prepend PATH "$b/format"
prepend PATH "$b/fuse"
+prepend PATH "$b/get-kernel"
prepend PATH "$b/inspector"
prepend PATH "$b/make-fs"
prepend PATH "$b/p2v"
--
2.1.0