From: Richard Jones Date: Sat, 11 Sep 2010 08:25:12 +0000 (+0100) Subject: Split generator into separate source files. X-Git-Tag: 1.5.12~6 X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=commitdiff_plain;h=04d8209077d2227eb1d42695ba71147f78987050 Split generator into separate source files. 'src/generator.ml' is no more. Instead the generator is logically split up over many different source files. Read generator/README for help and tips. We compile the generator down to bytecode, not native code. This means it will run more slowly, but is done for maximum portability. --- diff --git a/.gitignore b/.gitignore index 55bd91b..e7c35f5 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,9 @@ fish/rc_protocol.h fuse/guestmount fuse/guestmount.1 fuse/guestmount.static +generator/.pod2text.data +generator/generator +generator/stamp-generator guestfish.1 guestfish-actions.pod guestfs.3 @@ -248,8 +251,6 @@ src/guestfs_protocol.x src/guestfs-structs.h src/.libs/libguestfs.so src/libguestfs.syms -src/.pod2text.data -src/stamp-generator stamp-h1 test1.img test-tool/libguestfs-test-tool diff --git a/HACKING b/HACKING index 3d60737..9ae20a6 100644 --- a/HACKING +++ b/HACKING @@ -7,8 +7,8 @@ Adding a new action All action functions are generated automatically, so there are only two files you need to edit: -(1) src/generator.ml: Add your new action, parameters, description, -etc. to the big list called 'functions' at the top of this file. +(1) generator/generator_actions.ml: Add your new action, parameters, +description, etc. to the big list at the top of this file. (2) Edit/create a C file in daemon/ subdirectory which implements your 'do_action' function. Take a look at one of the numerous examples @@ -89,6 +89,11 @@ fish/ fuse/ FUSE (userspace filesystem) built on top of libguestfs. +generator/ + The crucially important generator, used to automatically + generate large amounts of boilerplate C code for things like + RPC and bindings. + haskell/ Haskell bindings. @@ -144,7 +149,6 @@ tools/ src/ Source code to the C library. - Also contains the crucial generator program. test-tool/ Interactive qemu/kernel test tool. diff --git a/Makefile.am b/Makefile.am index a9c1478..6c68dc1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ include $(top_srcdir)/subdir-rules.mk ACLOCAL_AMFLAGS = -I m4 # Basic source for the library. -SUBDIRS = gnulib/lib images src examples po +SUBDIRS = gnulib/lib images generator src examples po if ENABLE_DAEMON SUBDIRS += daemon diff --git a/configure.ac b/configure.ac index 96e6f53..11126f6 100644 --- a/configure.ac +++ b/configure.ac @@ -792,6 +792,7 @@ dnl http://www.mail-archive.com/automake@gnu.org/msg10204.html AC_CONFIG_FILES([appliance/update.sh], [chmod +x appliance/update.sh]) AC_CONFIG_FILES([Makefile + generator/Makefile src/Makefile fish/Makefile po/Makefile.in examples/Makefile appliance/Makefile appliance/debian/debirf.conf diff --git a/daemon/Makefile.am b/daemon/Makefile.am index dc58134..0e2ac6e 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -1,5 +1,5 @@ # libguestfs-daemon -# Copyright (C) 2009 Red Hat Inc. +# Copyright (C) 2010 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 @@ -20,6 +20,7 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = lib tests . libsrcdir = $(top_builddir)/../src +generatorsrcdir = $(top_builddir)/../generator generator_built = \ actions.h \ @@ -28,9 +29,9 @@ generator_built = \ .PHONY: force -$(generator_built): $(libsrcdir)/stamp-generator -$(libsrcdir)/stamp-generator: force - $(MAKE) -C $(libsrcdir) stamp-generator +$(generator_built): $(generatorsrcdir)/stamp-generator +$(generatorsrcdir)/stamp-generator: force + $(MAKE) -C $(generatorsrcdir) stamp-generator BUILT_SOURCES = \ $(generator_built) \ diff --git a/generator/.depend b/generator/.depend new file mode 100644 index 0000000..ff9263e --- /dev/null +++ b/generator/.depend @@ -0,0 +1,129 @@ +generator_types.cmo: +generator_types.cmx: +generator_utils.cmi: generator_types.cmo +generator_utils.cmo: generator_types.cmo generator_utils.cmi +generator_utils.cmx: generator_types.cmx generator_utils.cmi +generator_actions.cmi: generator_types.cmo +generator_actions.cmo: generator_utils.cmi generator_types.cmo \ + generator_actions.cmi +generator_actions.cmx: generator_utils.cmx generator_types.cmx \ + generator_actions.cmi +generator_structs.cmi: generator_types.cmo +generator_structs.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi +generator_structs.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmi +generator_optgroups.cmo: generator_types.cmo generator_actions.cmi +generator_optgroups.cmx: generator_types.cmx generator_actions.cmx +generator_prepopts.cmi: +generator_prepopts.cmo: generator_prepopts.cmi +generator_prepopts.cmx: generator_prepopts.cmi +generator_pr.cmi: +generator_pr.cmo: generator_utils.cmi generator_pr.cmi +generator_pr.cmx: generator_utils.cmx generator_pr.cmi +generator_docstrings.cmo: generator_utils.cmi generator_types.cmo \ + generator_pr.cmi +generator_docstrings.cmx: generator_utils.cmx generator_types.cmx \ + generator_pr.cmx +generator_checks.cmo: generator_utils.cmi generator_types.cmo \ + generator_actions.cmi +generator_checks.cmx: generator_utils.cmx generator_types.cmx \ + generator_actions.cmx +generator_c.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_actions.cmi +generator_c.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_actions.cmx +generator_xdr.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_actions.cmi +generator_xdr.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_actions.cmx +generator_daemon.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_daemon.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_capitests.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_actions.cmi +generator_capitests.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_actions.cmx +generator_fish.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_prepopts.cmi generator_pr.cmi \ + generator_optgroups.cmo generator_docstrings.cmo generator_c.cmo \ + generator_actions.cmi +generator_fish.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_prepopts.cmx generator_pr.cmx \ + generator_optgroups.cmx generator_docstrings.cmx generator_c.cmx \ + generator_actions.cmx +generator_ocaml.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_ocaml.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_perl.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_perl.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_python.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_python.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_ruby.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_ruby.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_java.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_java.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_haskell.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_actions.cmi +generator_haskell.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_actions.cmx +generator_csharp.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_actions.cmi +generator_csharp.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_actions.cmx +generator_php.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_php.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_bindtests.cmo: generator_utils.cmi generator_types.cmo \ + generator_structs.cmi generator_pr.cmi generator_optgroups.cmo \ + generator_docstrings.cmo generator_c.cmo generator_actions.cmi +generator_bindtests.cmx: generator_utils.cmx generator_types.cmx \ + generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \ + generator_docstrings.cmx generator_c.cmx generator_actions.cmx +generator_main.cmo: generator_xdr.cmo generator_structs.cmi \ + generator_ruby.cmo generator_python.cmo generator_pr.cmi \ + generator_php.cmo generator_perl.cmo generator_ocaml.cmo \ + generator_java.cmo generator_haskell.cmo generator_fish.cmo \ + generator_daemon.cmo generator_csharp.cmo generator_capitests.cmo \ + generator_c.cmo generator_bindtests.cmo +generator_main.cmx: generator_xdr.cmx generator_structs.cmx \ + generator_ruby.cmx generator_python.cmx generator_pr.cmx \ + generator_php.cmx generator_perl.cmx generator_ocaml.cmx \ + generator_java.cmx generator_haskell.cmx generator_fish.cmx \ + generator_daemon.cmx generator_csharp.cmx generator_capitests.cmx \ + generator_c.cmx generator_bindtests.cmx diff --git a/generator/Makefile.am b/generator/Makefile.am new file mode 100644 index 0000000..7ef5d9d --- /dev/null +++ b/generator/Makefile.am @@ -0,0 +1,95 @@ +# libguestfs +# Copyright (C) 2010 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +SOURCES = \ + generator_types.ml \ + generator_utils.mli \ + generator_utils.ml \ + generator_actions.mli \ + generator_actions.ml \ + generator_structs.mli \ + generator_structs.ml \ + generator_optgroups.ml \ + generator_prepopts.mli \ + generator_prepopts.ml \ + generator_pr.mli \ + generator_pr.ml \ + generator_docstrings.ml \ + generator_checks.ml \ + generator_c.ml \ + generator_xdr.ml \ + generator_daemon.ml \ + generator_capitests.ml \ + generator_fish.ml \ + generator_ocaml.ml \ + generator_perl.ml \ + generator_python.ml \ + generator_ruby.ml \ + generator_java.ml \ + generator_haskell.ml \ + generator_csharp.ml \ + generator_php.ml \ + generator_bindtests.ml \ + generator_main.ml + +SOURCES_ML = $(filter %.ml,$(SOURCES)) +OBJECTS = $(SOURCES_ML:.ml=.cmo) + +EXTRA_DIST = $(SOURCES) + +OCAMLCFLAGS = -I +xml-light -I +../pkg-lib/xml-light +OCAMLCLIBS = xml-light.cma unix.cma str.cma + +noinst_PROGRAM = generator + +generator: $(OBJECTS) ../images/test.iso + $(OCAMLC) -o generator $(OCAMLCFLAGS) $(OCAMLCLIBS) $(OBJECTS) + +.ml.cmo: + $(OCAMLC) $(OCAMLCFLAGS) -c $< -o $@ + +.mli.cmi: + $(OCAMLC) $(OCAMLCFLAGS) -c $< -o $@ + +depend: .depend + +.depend: $(SOURCES) + rm -f $@ $@-t + $(OCAMLDEP) $^ | sed 's/ *$$//' > $@-t + mv $@-t $@ + +include .depend + +noinst_DATA = stamp-generator + +# Run the generator. +# Git removes empty directories, so in cases where the +# generator is creating the sole file in a directory, we +# have to create the directory first. +stamp-generator: generator + mkdir -p $(top_srcdir)/perl/lib/Sys + mkdir -p $(top_srcdir)/ruby/ext/guestfs + mkdir -p $(top_srcdir)/java/com/redhat/et/libguestfs + mkdir -p $(top_srcdir)/csharp + cd $(top_srcdir) && generator/generator + +../images/test.iso: + make -C ../images test.iso + +CLEANFILES = $(noinst_DATA) $(noinst_PROGRAM) *.cmi *.cmo *~ + +SUFFIXES = .cmo .cmi .cmx .ml .mli .mll .mly diff --git a/generator/README b/generator/README new file mode 100644 index 0000000..dfbd160 --- /dev/null +++ b/generator/README @@ -0,0 +1,34 @@ +This program generates a large amount of code and documentation for +all the daemon actions. + +To add a new action there are only two files you need to change, +'generator_actions.ml' to describe the interface, and +daemon/.c to write the implementation. + +After editing these files, build it (make -C generator) to regenerate +all the output files. 'make' will rerun this automatically when +necessary. + +IMPORTANT: This program should NOT print any warnings at compile time +or run time. If it prints warnings, you should treat them as errors. + +OCaml tips: + +(1) In emacs, install tuareg-mode to display and format OCaml code +correctly. 'vim' comes with a good OCaml editing mode by default. + +(2) Read the resources at http://ocaml-tutorial.org/ + +(3) A module called 'Generator_foo' is defined in one or two files +called 'generator_foo.mli' and 'generator_foo.ml' (NB: lowercase first +letter). The *.mli file, if present, defines the public interface for +the module. The *.ml file is the implementation. If the *.mli file +is missing then everything is exported. + +Some notable files in this directory: + +generator_actions.ml The libguestfs API. +generator_structs.ml Structures returned by the API. +generator_c.ml Generate C API. +generator_.ml Generate bindings for . +generator_main.ml The main generator program. diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml new file mode 100644 index 0000000..bde9e6c --- /dev/null +++ b/generator/generator_actions.ml @@ -0,0 +1,5086 @@ +(* libguestfs + * Copyright (C) 2009-2010 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 + *) + +(* Please read generator/README first. *) + +(* Note about long descriptions: When referring to another + * action, use the format C (ie. the full name of + * the C function). This will be replaced as appropriate in other + * language bindings. + * + * Apart from that, long descriptions are just perldoc paragraphs. + *) + +open Generator_types +open Generator_utils + +(* These test functions are used in the language binding tests. *) + +let test_all_args = [ + String "str"; + OptString "optstr"; + StringList "strlist"; + Bool "b"; + Int "integer"; + Int64 "integer64"; + FileIn "filein"; + FileOut "fileout"; + BufferIn "bufferin"; +] + +let test_all_rets = [ + (* except for RErr, which is tested thoroughly elsewhere *) + "test0rint", RInt "valout"; + "test0rint64", RInt64 "valout"; + "test0rbool", RBool "valout"; + "test0rconststring", RConstString "valout"; + "test0rconstoptstring", RConstOptString "valout"; + "test0rstring", RString "valout"; + "test0rstringlist", RStringList "valout"; + "test0rstruct", RStruct ("valout", "lvm_pv"); + "test0rstructlist", RStructList ("valout", "lvm_pv"); + "test0rhashtable", RHashtable "valout"; +] + +let test_functions = [ + ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs], + [], + "internal test function - do not use", + "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +parameter type correctly. + +It echos the contents of each parameter to stdout. + +You probably don't want to call this function."); +] @ List.flatten ( + List.map ( + fun (name, ret) -> + [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs], + [], + "internal test function - do not use", + "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +return type correctly. + +It converts string C to the return type. + +You probably don't want to call this function."); + (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs], + [], + "internal test function - do not use", + "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +return type correctly. + +This function always returns an error. + +You probably don't want to call this function.")] + ) test_all_rets +) + +(* non_daemon_functions are any functions which don't get processed + * in the daemon, eg. functions for setting and getting local + * configuration values. + *) + +let non_daemon_functions = test_functions @ [ + ("launch", (RErr, []), -1, [FishAlias "run"], + [], + "launch the qemu subprocess", + "\ +Internally libguestfs is implemented by running a virtual machine +using L. + +You should call this after configuring the handle +(eg. adding drives) but before performing any actions."); + + ("wait_ready", (RErr, []), -1, [NotInFish], + [], + "wait until the qemu subprocess launches (no op)", + "\ +This function is a no op. + +In versions of the API E 1.0.71 you had to call this function +just after calling C to wait for the launch +to complete. However this is no longer necessary because +C now does the waiting. + +If you see any calls to this function in code then you can just +remove them, unless you want to retain compatibility with older +versions of the API."); + + ("kill_subprocess", (RErr, []), -1, [], + [], + "kill the qemu subprocess", + "\ +This kills the qemu subprocess. You should never need to call this."); + + ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"], + [], + "add an image to examine or modify", + "\ +This function adds a virtual machine disk image C to the +guest. The first time you call this function, the disk appears as IDE +disk 0 (C) in the guest, the second time as C, and +so on. + +You don't necessarily need to be root when using libguestfs. However +you obviously do need sufficient permissions to access the filename +for whatever operations you want to perform (ie. read access if you +just want to read the image or write access if you want to modify the +image). + +This is equivalent to the qemu parameter +C<-drive file=filename,cache=off,if=...>. + +C is omitted in cases where it is not supported by +the underlying filesystem. + +C is set at compile time by the configuration option +C<./configure --with-drive-if=...>. In the rare case where you +might need to change this at run time, use C +or C. + +Note that this call checks for the existence of C. This +stops you from specifying other types of drive which are supported +by qemu such as C and C URLs. To specify those, use +the general C call instead."); + + ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"], + [], + "add a CD-ROM disk image to examine", + "\ +This function adds a virtual CD-ROM disk image to the guest. + +This is equivalent to the qemu parameter C<-cdrom filename>. + +Notes: + +=over 4 + +=item * + +This call checks for the existence of C. This +stops you from specifying other types of drive which are supported +by qemu such as C and C URLs. To specify those, use +the general C call instead. + +=item * + +If you just want to add an ISO file (often you use this as an +efficient way to transfer large files into the guest), then you +should probably use C instead. + +=back"); + + ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"], + [], + "add a drive in snapshot mode (read-only)", + "\ +This adds a drive in snapshot mode, making it effectively +read-only. + +Note that writes to the device are allowed, and will be seen for +the duration of the guestfs handle, but they are written +to a temporary file which is discarded as soon as the guestfs +handle is closed. We don't currently have any method to enable +changes to be committed, although qemu can support this. + +This is equivalent to the qemu parameter +C<-drive file=filename,snapshot=on,if=...>. + +C is set at compile time by the configuration option +C<./configure --with-drive-if=...>. In the rare case where you +might need to change this at run time, use C +or C. + +Note that this call checks for the existence of C. This +stops you from specifying other types of drive which are supported +by qemu such as C and C URLs. To specify those, use +the general C call instead."); + + ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [], + [], + "add qemu parameters", + "\ +This can be used to add arbitrary qemu command line parameters +of the form C<-param value>. Actually it's not quite arbitrary - we +prevent you from setting some parameters which would interfere with +parameters that we use. + +The first character of C string must be a C<-> (dash). + +C can be NULL."); + + ("set_qemu", (RErr, [OptString "qemu"]), -1, [FishAlias "qemu"], + [], + "set the qemu binary", + "\ +Set the qemu binary that we will use. + +The default is chosen when the library was compiled by the +configure script. + +You can also override this by setting the C +environment variable. + +Setting C to C restores the default qemu binary. + +Note that you should call this function as early as possible +after creating the handle. This is because some pre-launch +operations depend on testing qemu features (by running C). +If the qemu binary changes, we don't retest features, and +so you might see inconsistent results. Using the environment +variable C is safest of all since that picks +the qemu binary at the same time as the handle is created."); + + ("get_qemu", (RConstString "qemu", []), -1, [], + [InitNone, Always, TestRun ( + [["get_qemu"]])], + "get the qemu binary", + "\ +Return the current qemu binary. + +This is always non-NULL. If it wasn't set already, then this will +return the default qemu binary name."); + + ("set_path", (RErr, [OptString "searchpath"]), -1, [FishAlias "path"], + [], + "set the search path", + "\ +Set the path that libguestfs searches for kernel and initrd.img. + +The default is C<$libdir/guestfs> unless overridden by setting +C environment variable. + +Setting C to C restores the default path."); + + ("get_path", (RConstString "path", []), -1, [], + [InitNone, Always, TestRun ( + [["get_path"]])], + "get the search path", + "\ +Return the current search path. + +This is always non-NULL. If it wasn't set already, then this will +return the default path."); + + ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"], + [], + "add options to kernel command line", + "\ +This function is used to add additional options to the +guest kernel command line. + +The default is C unless overridden by setting +C environment variable. + +Setting C to C means I additional options +are passed (libguestfs always adds a few of its own)."); + + ("get_append", (RConstOptString "append", []), -1, [], + (* This cannot be tested with the current framework. The + * function can return NULL in normal operations, which the + * test framework interprets as an error. + *) + [], + "get the additional kernel options", + "\ +Return the additional kernel options which are added to the +guest kernel command line. + +If C then no options are added."); + + ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"], + [], + "set autosync mode", + "\ +If C is true, this enables autosync. Libguestfs will make a +best effort attempt to run C followed by +C when the handle is closed +(also if the program exits without closing handles). + +This is disabled by default (except in guestfish where it is +enabled by default)."); + + ("get_autosync", (RBool "autosync", []), -1, [], + [InitNone, Always, TestRun ( + [["get_autosync"]])], + "get autosync mode", + "\ +Get the autosync flag."); + + ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"], + [], + "set verbose mode", + "\ +If C is true, this turns on verbose messages (to C). + +Verbose messages are disabled unless the environment variable +C is defined and set to C<1>."); + + ("get_verbose", (RBool "verbose", []), -1, [], + [], + "get verbose mode", + "\ +This returns the verbose messages flag."); + + ("is_ready", (RBool "ready", []), -1, [], + [InitNone, Always, TestOutputTrue ( + [["is_ready"]])], + "is ready to accept commands", + "\ +This returns true iff this handle is ready to accept commands +(in the C state). + +For more information on states, see L."); + + ("is_config", (RBool "config", []), -1, [], + [InitNone, Always, TestOutputFalse ( + [["is_config"]])], + "is in configuration state", + "\ +This returns true iff this handle is being configured +(in the C state). + +For more information on states, see L."); + + ("is_launching", (RBool "launching", []), -1, [], + [InitNone, Always, TestOutputFalse ( + [["is_launching"]])], + "is launching subprocess", + "\ +This returns true iff this handle is launching the subprocess +(in the C state). + +For more information on states, see L."); + + ("is_busy", (RBool "busy", []), -1, [], + [InitNone, Always, TestOutputFalse ( + [["is_busy"]])], + "is busy processing a command", + "\ +This returns true iff this handle is busy processing a command +(in the C state). + +For more information on states, see L."); + + ("get_state", (RInt "state", []), -1, [], + [], + "get the current state", + "\ +This returns the current state as an opaque integer. This is +only useful for printing debug and internal error messages. + +For more information on states, see L."); + + ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"], + [InitNone, Always, TestOutputInt ( + [["set_memsize"; "500"]; + ["get_memsize"]], 500)], + "set memory allocated to the qemu subprocess", + "\ +This sets the memory size in megabytes allocated to the +qemu subprocess. This only has any effect if called before +C. + +You can also change this by setting the environment +variable C before the handle is +created. + +For more information on the architecture of libguestfs, +see L."); + + ("get_memsize", (RInt "memsize", []), -1, [], + [InitNone, Always, TestOutputIntOp ( + [["get_memsize"]], ">=", 256)], + "get memory allocated to the qemu subprocess", + "\ +This gets the memory size in megabytes allocated to the +qemu subprocess. + +If C was not called +on this handle, and if C was not set, +then this returns the compiled-in default value for memsize. + +For more information on the architecture of libguestfs, +see L."); + + ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"], + [InitNone, Always, TestOutputIntOp ( + [["get_pid"]], ">=", 1)], + "get PID of qemu subprocess", + "\ +Return the process ID of the qemu subprocess. If there is no +qemu subprocess, then this will return an error. + +This is an internal call used for debugging and testing."); + + ("version", (RStruct ("version", "version"), []), -1, [], + [InitNone, Always, TestOutputStruct ( + [["version"]], [CompareWithInt ("major", 1)])], + "get the library version number", + "\ +Return the libguestfs version number that the program is linked +against. + +Note that because of dynamic linking this is not necessarily +the version of libguestfs that you compiled against. You can +compile the program, and then at runtime dynamically link +against a completely different C library. + +This call was added in version C<1.0.58>. In previous +versions of libguestfs there was no way to get the version +number. From C code you can use dynamic linker functions +to find out if this symbol exists (if it doesn't, then +it's an earlier version). + +The call returns a structure with four elements. The first +three (C, C and C) are numbers and +correspond to the usual version triplet. The fourth element +(C) is a string and is normally empty, but may be +used for distro-specific information. + +To construct the original version string: +C<$major.$minor.$release$extra> + +See also: L. + +I Don't use this call to test for availability +of features. In enterprise distributions we backport +features from later versions into earlier versions, +making this an unreliable way to test for features. +Use C instead."); + + ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"], + [InitNone, Always, TestOutputTrue ( + [["set_selinux"; "true"]; + ["get_selinux"]])], + "set SELinux enabled or disabled at appliance boot", + "\ +This sets the selinux flag that is passed to the appliance +at boot time. The default is C (disabled). + +Note that if SELinux is enabled, it is always in +Permissive mode (C). + +For more information on the architecture of libguestfs, +see L."); + + ("get_selinux", (RBool "selinux", []), -1, [], + [], + "get SELinux enabled flag", + "\ +This returns the current setting of the selinux flag which +is passed to the appliance at boot time. See C. + +For more information on the architecture of libguestfs, +see L."); + + ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"], + [InitNone, Always, TestOutputFalse ( + [["set_trace"; "false"]; + ["get_trace"]])], + "enable or disable command traces", + "\ +If the command trace flag is set to 1, then commands are +printed on stderr before they are executed in a format +which is very similar to the one used by guestfish. In +other words, you can run a program with this enabled, and +you will get out a script which you can feed to guestfish +to perform the same set of actions. + +If you want to trace C API calls into libguestfs (and +other libraries) then possibly a better way is to use +the external ltrace(1) command. + +Command traces are disabled unless the environment variable +C is defined and set to C<1>."); + + ("get_trace", (RBool "trace", []), -1, [], + [], + "get command trace enabled flag", + "\ +Return the command trace flag."); + + ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"], + [InitNone, Always, TestOutputFalse ( + [["set_direct"; "false"]; + ["get_direct"]])], + "enable or disable direct appliance mode", + "\ +If the direct appliance mode flag is enabled, then stdin and +stdout are passed directly through to the appliance once it +is launched. + +One consequence of this is that log messages aren't caught +by the library and handled by C, +but go straight to stdout. + +You probably don't want to use this unless you know what you +are doing. + +The default is disabled."); + + ("get_direct", (RBool "direct", []), -1, [], + [], + "get direct appliance mode flag", + "\ +Return the direct appliance mode flag."); + + ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"], + [InitNone, Always, TestOutputTrue ( + [["set_recovery_proc"; "true"]; + ["get_recovery_proc"]])], + "enable or disable the recovery process", + "\ +If this is called with the parameter C then +C does not create a recovery process. The +purpose of the recovery process is to stop runaway qemu +processes in the case where the main program aborts abruptly. + +This only has any effect if called before C, +and the default is true. + +About the only time when you would want to disable this is +if the main process will fork itself into the background +(\"daemonize\" itself). In this case the recovery process +thinks that the main program has disappeared and so kills +qemu, which is not very helpful."); + + ("get_recovery_proc", (RBool "recoveryproc", []), -1, [], + [], + "get recovery process enabled flag", + "\ +Return the recovery process enabled flag."); + + ("add_drive_with_if", (RErr, [String "filename"; String "iface"]), -1, [], + [], + "add a drive specifying the QEMU block emulation to use", + "\ +This is the same as C but it allows you +to specify the QEMU interface emulation to use at run time."); + + ("add_drive_ro_with_if", (RErr, [String "filename"; String "iface"]), -1, [], + [], + "add a drive read-only specifying the QEMU block emulation to use", + "\ +This is the same as C but it allows you +to specify the QEMU interface emulation to use at run time."); + + ("file_architecture", (RString "arch", [Pathname "filename"]), -1, [], + [InitISOFS, Always, TestOutput ( + [["file_architecture"; "/bin-i586-dynamic"]], "i386"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/bin-sparc-dynamic"]], "sparc"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/bin-win32.exe"]], "i386"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/bin-win64.exe"]], "x86_64"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/bin-x86_64-dynamic"]], "x86_64"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/lib-i586.so"]], "i386"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/lib-sparc.so"]], "sparc"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/lib-win32.dll"]], "i386"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/lib-win64.dll"]], "x86_64"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/lib-x86_64.so"]], "x86_64"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/initrd-x86_64.img"]], "x86_64"); + InitISOFS, Always, TestOutput ( + [["file_architecture"; "/initrd-x86_64.img.gz"]], "x86_64");], + "detect the architecture of a binary file", + "\ +This detects the architecture of the binary C, +and returns it if known. + +Currently defined architectures are: + +=over 4 + +=item \"i386\" + +This string is returned for all 32 bit i386, i486, i586, i686 binaries +irrespective of the precise processor requirements of the binary. + +=item \"x86_64\" + +64 bit x86-64. + +=item \"sparc\" + +32 bit SPARC. + +=item \"sparc64\" + +64 bit SPARC V9 and above. + +=item \"ia64\" + +Intel Itanium. + +=item \"ppc\" + +32 bit Power PC. + +=item \"ppc64\" + +64 bit Power PC. + +=back + +Libguestfs may return other architecture strings in future. + +The function works on at least the following types of files: + +=over 4 + +=item * + +many types of Un*x and Linux binary + +=item * + +many types of Un*x and Linux shared library + +=item * + +Windows Win32 and Win64 binaries + +=item * + +Windows Win32 and Win64 DLLs + +Win32 binaries and DLLs return C. + +Win64 binaries and DLLs return C. + +=item * + +Linux kernel modules + +=item * + +Linux new-style initrd images + +=item * + +some non-x86 Linux vmlinuz kernels + +=back + +What it can't do currently: + +=over 4 + +=item * + +static libraries (libfoo.a) + +=item * + +Linux old-style initrd as compressed ext2 filesystem (RHEL 3) + +=item * + +x86 Linux vmlinuz kernels + +x86 vmlinuz images (bzImage format) consist of a mix of 16-, 32- and +compressed code, and are horribly hard to unpack. If you want to find +the architecture of a kernel, use the architecture of the associated +initrd or kernel module(s) instead. + +=back"); + + ("inspect_os", (RStringList "roots", []), -1, [], + [], + "inspect disk and return list of operating systems found", + "\ +This function uses other libguestfs functions and certain +heuristics to inspect the disk(s) (usually disks belonging to +a virtual machine), looking for operating systems. + +The list returned is empty if no operating systems were found. + +If one operating system was found, then this returns a list with +a single element, which is the name of the root filesystem of +this operating system. It is also possible for this function +to return a list containing more than one element, indicating +a dual-boot or multi-boot virtual machine, with each element being +the root filesystem of one of the operating systems. + +You can pass the root string(s) returned to other +C functions in order to query further +information about each operating system, such as the name +and version. + +This function uses other libguestfs features such as +C and C in order to mount +and unmount filesystems and look at the contents. This should +be called with no disks currently mounted. The function may also +use Augeas, so any existing Augeas handle will be closed. + +This function cannot decrypt encrypted disks. The caller +must do that first (supplying the necessary keys) if the +disk is encrypted. + +Please read L for more details."); + + ("inspect_get_type", (RString "name", [Device "root"]), -1, [], + [], + "get type of inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns the type of the inspected operating system. +Currently defined types are: + +=over 4 + +=item \"linux\" + +Any Linux-based operating system. + +=item \"windows\" + +Any Microsoft Windows operating system. + +=item \"unknown\" + +The operating system type could not be determined. + +=back + +Future versions of libguestfs may return other strings here. +The caller should be prepared to handle any string. + +Please read L for more details."); + + ("inspect_get_arch", (RString "arch", [Device "root"]), -1, [], + [], + "get architecture of inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns the architecture of the inspected operating system. +The possible return values are listed under +C. + +If the architecture could not be determined, then the +string C is returned. + +Please read L for more details."); + + ("inspect_get_distro", (RString "distro", [Device "root"]), -1, [], + [], + "get distro of inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns the distro (distribution) of the inspected operating +system. + +Currently defined distros are: + +=over 4 + +=item \"debian\" + +Debian or a Debian-derived distro such as Ubuntu. + +=item \"fedora\" + +Fedora. + +=item \"redhat-based\" + +Some Red Hat-derived distro. + +=item \"rhel\" + +Red Hat Enterprise Linux and some derivatives. + +=item \"windows\" + +Windows does not have distributions. This string is +returned if the OS type is Windows. + +=item \"unknown\" + +The distro could not be determined. + +=back + +Future versions of libguestfs may return other strings here. +The caller should be prepared to handle any string. + +Please read L for more details."); + + ("inspect_get_major_version", (RInt "major", [Device "root"]), -1, [], + [], + "get major version of inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns the major version number of the inspected operating +system. + +Windows uses a consistent versioning scheme which is I +reflected in the popular public names used by the operating system. +Notably the operating system known as \"Windows 7\" is really +version 6.1 (ie. major = 6, minor = 1). You can find out the +real versions corresponding to releases of Windows by consulting +Wikipedia or MSDN. + +If the version could not be determined, then C<0> is returned. + +Please read L for more details."); + + ("inspect_get_minor_version", (RInt "minor", [Device "root"]), -1, [], + [], + "get minor version of inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns the minor version number of the inspected operating +system. + +If the version could not be determined, then C<0> is returned. + +Please read L for more details. +See also C."); + + ("inspect_get_product_name", (RString "product", [Device "root"]), -1, [], + [], + "get product name of inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns the product name of the inspected operating +system. The product name is generally some freeform string +which can be displayed to the user, but should not be +parsed by programs. + +If the product name could not be determined, then the +string C is returned. + +Please read L for more details."); + + ("inspect_get_mountpoints", (RHashtable "mountpoints", [Device "root"]), -1, [], + [], + "get mountpoints of inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns a hash of where we think the filesystems +associated with this operating system should be mounted. +Callers should note that this is at best an educated guess +made by reading configuration files such as C. + +Each element in the returned hashtable has a key which +is the path of the mountpoint (eg. C) and a value +which is the filesystem that would be mounted there +(eg. C). + +Non-mounted devices such as swap devices are I +returned in this list. + +Please read L for more details. +See also C."); + + ("inspect_get_filesystems", (RStringList "filesystems", [Device "root"]), -1, [], + [], + "get filesystems associated with inspected operating system", + "\ +This function should only be called with a root device string +as returned by C. + +This returns a list of all the filesystems that we think +are associated with this operating system. This includes +the root filesystem, other ordinary filesystems, and +non-mounted devices like swap partitions. + +In the case of a multi-boot virtual machine, it is possible +for a filesystem to be shared between operating systems. + +Please read L for more details. +See also C."); + + ("set_network", (RErr, [Bool "network"]), -1, [FishAlias "network"], + [], + "set enable network flag", + "\ +If C is true, then the network is enabled in the +libguestfs appliance. The default is false. + +This affects whether commands are able to access the network +(see L). + +You must call this before calling C, otherwise +it has no effect."); + + ("get_network", (RBool "network", []), -1, [], + [], + "get enable network flag", + "\ +This returns the enable network flag."); + +] + +(* daemon_functions are any functions which cause some action + * to take place in the daemon. + *) + +let daemon_functions = [ + ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [], + [InitEmpty, Always, TestOutput ( + [["part_disk"; "/dev/sda"; "mbr"]; + ["mkfs"; "ext2"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]; + ["write"; "/new"; "new file contents"]; + ["cat"; "/new"]], "new file contents")], + "mount a guest disk at a position in the filesystem", + "\ +Mount a guest disk at a position in the filesystem. Block devices +are named C, C and so on, as they were added to +the guest. If those block devices contain partitions, they will have +the usual names (eg. C). Also LVM C-style +names can be used. + +The rules are the same as for L: A filesystem must +first be mounted on C before others can be mounted. Other +filesystems can only be mounted on directories which already +exist. + +The mounted filesystem is writable, if we have sufficient permissions +on the underlying device. + +B +When you use this call, the filesystem options C and C +are set implicitly. This was originally done because we thought it +would improve reliability, but it turns out that I<-o sync> has a +very large negative performance impact and negligible effect on +reliability. Therefore we recommend that you avoid using +C in any code that needs performance, and instead +use C (use an empty string for the first +parameter if you don't want any options)."); + + ("sync", (RErr, []), 2, [], + [ InitEmpty, Always, TestRun [["sync"]]], + "sync disks, writes are flushed through to the disk image", + "\ +This syncs the disk, so that any writes are flushed through to the +underlying disk image. + +You should always call this if you have modified a disk image, before +closing the handle."); + + ("touch", (RErr, [Pathname "path"]), 3, [], + [InitBasicFS, Always, TestOutputTrue ( + [["touch"; "/new"]; + ["exists"; "/new"]])], + "update file timestamps or create a new file", + "\ +Touch acts like the L command. It can be used to +update the timestamps on a file, or, if the file does not exist, +to create a new zero-length file. + +This command only works on regular files, and will fail on other +file types such as directories, symbolic links, block special etc."); + + ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning], + [InitISOFS, Always, TestOutput ( + [["cat"; "/known-2"]], "abcdef\n")], + "list the contents of a file", + "\ +Return the contents of the file named C. + +Note that this function cannot correctly handle binary files +(specifically, files containing C<\\0> character which is treated +as end of string). For those you need to use the C +or C functions which have a more complex interface."); + + ("ll", (RString "listing", [Pathname "directory"]), 5, [], + [], (* XXX Tricky to test because it depends on the exact format + * of the 'ls -l' command, which changes between F10 and F11. + *) + "list the files in a directory (long format)", + "\ +List the files in C (relative to the root directory, +there is no cwd) in the format of 'ls -la'. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string."); + + ("ls", (RStringList "listing", [Pathname "directory"]), 6, [], + [InitBasicFS, Always, TestOutputList ( + [["touch"; "/new"]; + ["touch"; "/newer"]; + ["touch"; "/newest"]; + ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])], + "list the files in a directory", + "\ +List the files in C (relative to the root directory, +there is no cwd). The '.' and '..' entries are not returned, but +hidden files are shown. + +This command is mostly useful for interactive sessions. Programs +should probably use C instead."); + + ("list_devices", (RStringList "devices", []), 7, [], + [InitEmpty, Always, TestOutputListOfDevices ( + [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])], + "list the block devices", + "\ +List all the block devices. + +The full block device names are returned, eg. C"); + + ("list_partitions", (RStringList "partitions", []), 8, [], + [InitBasicFS, Always, TestOutputListOfDevices ( + [["list_partitions"]], ["/dev/sda1"]); + InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; + ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])], + "list the partitions", + "\ +List all the partitions detected on all block devices. + +The full partition device names are returned, eg. C + +This does not return logical volumes. For that you will need to +call C."); + + ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"], + [InitBasicFSonLVM, Always, TestOutputListOfDevices ( + [["pvs"]], ["/dev/sda1"]); + InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; + ["pvcreate"; "/dev/sda1"]; + ["pvcreate"; "/dev/sda2"]; + ["pvcreate"; "/dev/sda3"]; + ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])], + "list the LVM physical volumes (PVs)", + "\ +List all the physical volumes detected. This is the equivalent +of the L command. + +This returns a list of just the device names that contain +PVs (eg. C). + +See also C."); + + ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"], + [InitBasicFSonLVM, Always, TestOutputList ( + [["vgs"]], ["VG"]); + InitEmpty, Always, TestOutputList ( + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; + ["pvcreate"; "/dev/sda1"]; + ["pvcreate"; "/dev/sda2"]; + ["pvcreate"; "/dev/sda3"]; + ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"]; + ["vgcreate"; "VG2"; "/dev/sda3"]; + ["vgs"]], ["VG1"; "VG2"])], + "list the LVM volume groups (VGs)", + "\ +List all the volumes groups detected. This is the equivalent +of the L command. + +This returns a list of just the volume group names that were +detected (eg. C). + +See also C."); + + ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"], + [InitBasicFSonLVM, Always, TestOutputList ( + [["lvs"]], ["/dev/VG/LV"]); + InitEmpty, Always, TestOutputList ( + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; + ["pvcreate"; "/dev/sda1"]; + ["pvcreate"; "/dev/sda2"]; + ["pvcreate"; "/dev/sda3"]; + ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"]; + ["vgcreate"; "VG2"; "/dev/sda3"]; + ["lvcreate"; "LV1"; "VG1"; "50"]; + ["lvcreate"; "LV2"; "VG1"; "50"]; + ["lvcreate"; "LV3"; "VG2"; "50"]; + ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])], + "list the LVM logical volumes (LVs)", + "\ +List all the logical volumes detected. This is the equivalent +of the L command. + +This returns a list of the logical volume device names +(eg. C). + +See also C."); + + ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"], + [], (* XXX how to test? *) + "list the LVM physical volumes (PVs)", + "\ +List all the physical volumes detected. This is the equivalent +of the L command. The \"full\" version includes all fields."); + + ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"], + [], (* XXX how to test? *) + "list the LVM volume groups (VGs)", + "\ +List all the volumes groups detected. This is the equivalent +of the L command. The \"full\" version includes all fields."); + + ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"], + [], (* XXX how to test? *) + "list the LVM logical volumes (LVs)", + "\ +List all the logical volumes detected. This is the equivalent +of the L command. The \"full\" version includes all fields."); + + ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [], + [InitISOFS, Always, TestOutputList ( + [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]); + InitISOFS, Always, TestOutputList ( + [["read_lines"; "/empty"]], [])], + "read file as lines", + "\ +Return the contents of the file named C. + +The file contents are returned as a list of lines. Trailing +C and C character sequences are I returned. + +Note that this function cannot correctly handle binary files +(specifically, files containing C<\\0> character which is treated +as end of line). For those you need to use the C +function which has a more complex interface."); + + ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "create a new Augeas handle", + "\ +Create a new Augeas handle for editing configuration files. +If there was any previous Augeas handle associated with this +guestfs session, then it is closed. + +You must call this before using any other C +commands. + +C is the filesystem root. C must not be NULL, +use C instead. + +The flags are the same as the flags defined in +Eaugeas.hE, the logical I of the following +integers: + +=over 4 + +=item C = 1 + +Keep the original file with a C<.augsave> extension. + +=item C = 2 + +Save changes into a file with extension C<.augnew>, and +do not overwrite original. Overrides C. + +=item C = 4 + +Typecheck lenses (can be expensive). + +=item C = 8 + +Do not use standard load path for modules. + +=item C = 16 + +Make save a no-op, just record what would have been changed. + +=item C = 32 + +Do not load the tree in C. + +=back + +To close the handle, you can call C. + +To find out more about Augeas, see L."); + + ("aug_close", (RErr, []), 26, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "close the current Augeas handle", + "\ +Close the current Augeas handle and free up any resources +used by it. After calling this, you have to call +C again before you can use any other +Augeas functions."); + + ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "define an Augeas variable", + "\ +Defines an Augeas variable C whose value is the result +of evaluating C. If C is NULL, then C is +undefined. + +On success this returns the number of nodes in C, or +C<0> if C evaluates to something which is not a nodeset."); + + ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "define an Augeas node", + "\ +Defines a variable C whose value is the result of +evaluating C. + +If C evaluates to an empty nodeset, a node is created, +equivalent to calling C C, C. +C will be the nodeset containing that single node. + +On success this returns a pair containing the +number of nodes in the nodeset, and a boolean flag +if a node was created."); + + ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "look up the value of an Augeas path", + "\ +Look up the value associated with C. If C +matches exactly one node, the C is returned."); + + ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "set Augeas path to value", + "\ +Set the value associated with C to C. + +In the Augeas API, it is possible to clear a node by setting +the value to NULL. Due to an oversight in the libguestfs API +you cannot do that with this call. Instead you must use the +C call."); + + ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "insert a sibling Augeas node", + "\ +Create a new sibling C