3 * Copyright (C) 2009 Red Hat Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 (* This script generates a large amount of code and documentation for
21 * all the daemon actions.
23 * To add a new action there are only two files you need to change,
24 * this one to describe the interface (see the big table below), and
25 * daemon/<somefile>.c to write the implementation.
27 * After editing this file, run it (./src/generator.ml) to regenerate
28 * all the output files.
30 * IMPORTANT: This script should NOT print any warnings. If it prints
31 * warnings, you should treat them as errors.
32 * [Need to add -warn-error to ocaml command line]
40 type style = ret * args
42 (* "RErr" as a return value means an int used as a simple error
43 * indication, ie. 0 or -1.
46 (* "RInt" as a return value means an int which is -1 for error
47 * or any value >= 0 on success. Only use this for smallish
48 * positive ints (0 <= i < 2^30).
51 (* "RInt64" is the same as RInt, but is guaranteed to be able
52 * to return a full 64 bit value, _except_ that -1 means error
53 * (so -1 cannot be a valid, non-error return value).
56 (* "RBool" is a bool return value which can be true/false or
60 (* "RConstString" is a string that refers to a constant value.
61 * Try to avoid using this. In particular you cannot use this
62 * for values returned from the daemon, because there is no
63 * thread-safe way to return them in the C API.
65 | RConstString of string
66 (* "RString" and "RStringList" are caller-frees. *)
68 | RStringList of string
69 (* Some limited tuples are possible: *)
70 | RIntBool of string * string
71 (* LVM PVs, VGs and LVs. *)
78 (* Key-value pairs of untyped strings. Turns into a hashtable or
79 * dictionary in languages which support it. DON'T use this as a
80 * general "bucket" for results. Prefer a stronger typed return
81 * value if one is available, or write a custom struct. Don't use
82 * this if the list could potentially be very long, since it is
83 * inefficient. Keys should be unique. NULLs are not permitted.
85 | RHashtable of string
87 and args = argt list (* Function parameters, guestfs handle is implicit. *)
89 (* Note in future we should allow a "variable args" parameter as
90 * the final parameter, to allow commands like
91 * chmod mode file [file(s)...]
92 * This is not implemented yet, but many commands (such as chmod)
93 * are currently defined with the argument order keeping this future
94 * possibility in mind.
97 | String of string (* const char *name, cannot be NULL *)
98 | OptString of string (* const char *name, may be NULL *)
99 | StringList of string(* list of strings (each string cannot be NULL) *)
100 | Bool of string (* boolean *)
101 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
102 (* These are treated as filenames (simple string parameters) in
103 * the C API and bindings. But in the RPC protocol, we transfer
104 * the actual file content up to or down from the daemon.
105 * FileIn: local machine -> daemon (in request)
106 * FileOut: daemon -> local machine (in reply)
107 * In guestfish (only), the special name "-" means read from
108 * stdin or write to stdout.
114 | ProtocolLimitWarning (* display warning about protocol size limits *)
115 | DangerWillRobinson (* flags particularly dangerous commands *)
116 | FishAlias of string (* provide an alias for this cmd in guestfish *)
117 | FishAction of string (* call this function in guestfish *)
118 | NotInFish (* do not export via guestfish *)
119 | NotInDocs (* do not add this function to documentation *)
121 let protocol_limit_warning =
122 "Because of the message protocol, there is a transfer limit
123 of somewhere between 2MB and 4MB. To transfer large files you should use
126 let danger_will_robinson =
127 "B<This command is dangerous. Without careful use you
128 can easily destroy all your data>."
130 (* You can supply zero or as many tests as you want per API call.
132 * Note that the test environment has 3 block devices, of size 500MB,
133 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
134 * a fourth squashfs block device with some known files on it (/dev/sdd).
136 * Note for partitioning purposes, the 500MB device has 63 cylinders.
138 * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
140 * To be able to run the tests in a reasonable amount of time,
141 * the virtual machine and block devices are reused between tests.
142 * So don't try testing kill_subprocess :-x
144 * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
146 * Don't assume anything about the previous contents of the block
147 * devices. Use 'Init*' to create some initial scenarios.
149 * You can add a prerequisite clause to any individual test. This
150 * is a run-time check, which, if it fails, causes the test to be
151 * skipped. Useful if testing a command which might not work on
152 * all variations of libguestfs builds. A test that has prerequisite
153 * of 'Always' is run unconditionally.
155 * In addition, packagers can skip individual tests by setting the
156 * environment variables: eg:
157 * SKIP_TEST_<CMD>_<NUM>=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command)
158 * SKIP_TEST_<CMD>=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests)
160 type tests = (test_init * test_prereq * test) list
162 (* Run the command sequence and just expect nothing to fail. *)
164 (* Run the command sequence and expect the output of the final
165 * command to be the string.
167 | TestOutput of seq * string
168 (* Run the command sequence and expect the output of the final
169 * command to be the list of strings.
171 | TestOutputList of seq * string list
172 (* Run the command sequence and expect the output of the final
173 * command to be the list of block devices (could be either
174 * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
175 * character of each string).
177 | TestOutputListOfDevices of seq * string list
178 (* Run the command sequence and expect the output of the final
179 * command to be the integer.
181 | TestOutputInt of seq * int
182 (* Run the command sequence and expect the output of the final
183 * command to be a true value (!= 0 or != NULL).
185 | TestOutputTrue of seq
186 (* Run the command sequence and expect the output of the final
187 * command to be a false value (== 0 or == NULL, but not an error).
189 | TestOutputFalse of seq
190 (* Run the command sequence and expect the output of the final
191 * command to be a list of the given length (but don't care about
194 | TestOutputLength of seq * int
195 (* Run the command sequence and expect the output of the final
196 * command to be a structure.
198 | TestOutputStruct of seq * test_field_compare list
199 (* Run the command sequence and expect the final command (only)
202 | TestLastFail of seq
204 and test_field_compare =
205 | CompareWithInt of string * int
206 | CompareWithString of string * string
207 | CompareFieldsIntEq of string * string
208 | CompareFieldsStrEq of string * string
210 (* Test prerequisites. *)
212 (* Test always runs. *)
214 (* Test is currently disabled - eg. it fails, or it tests some
215 * unimplemented feature.
218 (* 'string' is some C code (a function body) that should return
219 * true or false. The test will run if the code returns true.
222 (* As for 'If' but the test runs _unless_ the code returns true. *)
225 (* Some initial scenarios for testing. *)
227 (* Do nothing, block devices could contain random stuff including
228 * LVM PVs, and some filesystems might be mounted. This is usually
232 (* Block devices are empty and no filesystems are mounted. *)
234 (* /dev/sda contains a single partition /dev/sda1, which is formatted
235 * as ext2, empty [except for lost+found] and mounted on /.
236 * /dev/sdb and /dev/sdc may have random content.
241 * /dev/sda1 (is a PV):
242 * /dev/VG/LV (size 8MB):
243 * formatted as ext2, empty [except for lost+found], mounted on /
244 * /dev/sdb and /dev/sdc may have random content.
248 (* Sequence of commands for testing. *)
250 and cmd = string list
252 (* Note about long descriptions: When referring to another
253 * action, use the format C<guestfs_other> (ie. the full name of
254 * the C function). This will be replaced as appropriate in other
257 * Apart from that, long descriptions are just perldoc paragraphs.
260 (* These test functions are used in the language binding tests. *)
262 let test_all_args = [
265 StringList "strlist";
272 let test_all_rets = [
273 (* except for RErr, which is tested thoroughly elsewhere *)
274 "test0rint", RInt "valout";
275 "test0rint64", RInt64 "valout";
276 "test0rbool", RBool "valout";
277 "test0rconststring", RConstString "valout";
278 "test0rstring", RString "valout";
279 "test0rstringlist", RStringList "valout";
280 "test0rintbool", RIntBool ("valout", "valout");
281 "test0rpvlist", RPVList "valout";
282 "test0rvglist", RVGList "valout";
283 "test0rlvlist", RLVList "valout";
284 "test0rstat", RStat "valout";
285 "test0rstatvfs", RStatVFS "valout";
286 "test0rhashtable", RHashtable "valout";
289 let test_functions = [
290 ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
292 "internal test function - do not use",
294 This is an internal test function which is used to test whether
295 the automatically generated bindings can handle every possible
296 parameter type correctly.
298 It echos the contents of each parameter to stdout.
300 You probably don't want to call this function.");
304 [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
306 "internal test function - do not use",
308 This is an internal test function which is used to test whether
309 the automatically generated bindings can handle every possible
310 return type correctly.
312 It converts string C<val> to the return type.
314 You probably don't want to call this function.");
315 (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
317 "internal test function - do not use",
319 This is an internal test function which is used to test whether
320 the automatically generated bindings can handle every possible
321 return type correctly.
323 This function always returns an error.
325 You probably don't want to call this function.")]
329 (* non_daemon_functions are any functions which don't get processed
330 * in the daemon, eg. functions for setting and getting local
331 * configuration values.
334 let non_daemon_functions = test_functions @ [
335 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
337 "launch the qemu subprocess",
339 Internally libguestfs is implemented by running a virtual machine
342 You should call this after configuring the handle
343 (eg. adding drives) but before performing any actions.");
345 ("wait_ready", (RErr, []), -1, [NotInFish],
347 "wait until the qemu subprocess launches",
349 Internally libguestfs is implemented by running a virtual machine
352 You should call this after C<guestfs_launch> to wait for the launch
355 ("kill_subprocess", (RErr, []), -1, [],
357 "kill the qemu subprocess",
359 This kills the qemu subprocess. You should never need to call this.");
361 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
363 "add an image to examine or modify",
365 This function adds a virtual machine disk image C<filename> to the
366 guest. The first time you call this function, the disk appears as IDE
367 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
370 You don't necessarily need to be root when using libguestfs. However
371 you obviously do need sufficient permissions to access the filename
372 for whatever operations you want to perform (ie. read access if you
373 just want to read the image or write access if you want to modify the
376 This is equivalent to the qemu parameter C<-drive file=filename,cache=off>.
378 Note that this call checks for the existence of C<filename>. This
379 stops you from specifying other types of drive which are supported
380 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
381 the general C<guestfs_config> call instead.");
383 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
385 "add a CD-ROM disk image to examine",
387 This function adds a virtual CD-ROM disk image to the guest.
389 This is equivalent to the qemu parameter C<-cdrom filename>.
391 Note that this call checks for the existence of C<filename>. This
392 stops you from specifying other types of drive which are supported
393 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
394 the general C<guestfs_config> call instead.");
396 ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
398 "add a drive in snapshot mode (read-only)",
400 This adds a drive in snapshot mode, making it effectively
403 Note that writes to the device are allowed, and will be seen for
404 the duration of the guestfs handle, but they are written
405 to a temporary file which is discarded as soon as the guestfs
406 handle is closed. We don't currently have any method to enable
407 changes to be committed, although qemu can support this.
409 This is equivalent to the qemu parameter
410 C<-drive file=filename,snapshot=on>.
412 Note that this call checks for the existence of C<filename>. This
413 stops you from specifying other types of drive which are supported
414 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
415 the general C<guestfs_config> call instead.");
417 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
419 "add qemu parameters",
421 This can be used to add arbitrary qemu command line parameters
422 of the form C<-param value>. Actually it's not quite arbitrary - we
423 prevent you from setting some parameters which would interfere with
424 parameters that we use.
426 The first character of C<param> string must be a C<-> (dash).
428 C<value> can be NULL.");
430 ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
432 "set the qemu binary",
434 Set the qemu binary that we will use.
436 The default is chosen when the library was compiled by the
439 You can also override this by setting the C<LIBGUESTFS_QEMU>
440 environment variable.
442 Setting C<qemu> to C<NULL> restores the default qemu binary.");
444 ("get_qemu", (RConstString "qemu", []), -1, [],
446 "get the qemu binary",
448 Return the current qemu binary.
450 This is always non-NULL. If it wasn't set already, then this will
451 return the default qemu binary name.");
453 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
455 "set the search path",
457 Set the path that libguestfs searches for kernel and initrd.img.
459 The default is C<$libdir/guestfs> unless overridden by setting
460 C<LIBGUESTFS_PATH> environment variable.
462 Setting C<path> to C<NULL> restores the default path.");
464 ("get_path", (RConstString "path", []), -1, [],
466 "get the search path",
468 Return the current search path.
470 This is always non-NULL. If it wasn't set already, then this will
471 return the default path.");
473 ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
475 "add options to kernel command line",
477 This function is used to add additional options to the
478 guest kernel command line.
480 The default is C<NULL> unless overridden by setting
481 C<LIBGUESTFS_APPEND> environment variable.
483 Setting C<append> to C<NULL> means I<no> additional options
484 are passed (libguestfs always adds a few of its own).");
486 ("get_append", (RConstString "append", []), -1, [],
488 "get the additional kernel options",
490 Return the additional kernel options which are added to the
491 guest kernel command line.
493 If C<NULL> then no options are added.");
495 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
499 If C<autosync> is true, this enables autosync. Libguestfs will make a
500 best effort attempt to run C<guestfs_umount_all> followed by
501 C<guestfs_sync> when the handle is closed
502 (also if the program exits without closing handles).
504 This is disabled by default (except in guestfish where it is
505 enabled by default).");
507 ("get_autosync", (RBool "autosync", []), -1, [],
511 Get the autosync flag.");
513 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
517 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
519 Verbose messages are disabled unless the environment variable
520 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
522 ("get_verbose", (RBool "verbose", []), -1, [],
526 This returns the verbose messages flag.");
528 ("is_ready", (RBool "ready", []), -1, [],
530 "is ready to accept commands",
532 This returns true iff this handle is ready to accept commands
533 (in the C<READY> state).
535 For more information on states, see L<guestfs(3)>.");
537 ("is_config", (RBool "config", []), -1, [],
539 "is in configuration state",
541 This returns true iff this handle is being configured
542 (in the C<CONFIG> state).
544 For more information on states, see L<guestfs(3)>.");
546 ("is_launching", (RBool "launching", []), -1, [],
548 "is launching subprocess",
550 This returns true iff this handle is launching the subprocess
551 (in the C<LAUNCHING> state).
553 For more information on states, see L<guestfs(3)>.");
555 ("is_busy", (RBool "busy", []), -1, [],
557 "is busy processing a command",
559 This returns true iff this handle is busy processing a command
560 (in the C<BUSY> state).
562 For more information on states, see L<guestfs(3)>.");
564 ("get_state", (RInt "state", []), -1, [],
566 "get the current state",
568 This returns the current state as an opaque integer. This is
569 only useful for printing debug and internal error messages.
571 For more information on states, see L<guestfs(3)>.");
573 ("set_busy", (RErr, []), -1, [NotInFish],
577 This sets the state to C<BUSY>. This is only used when implementing
578 actions using the low-level API.
580 For more information on states, see L<guestfs(3)>.");
582 ("set_ready", (RErr, []), -1, [NotInFish],
584 "set state to ready",
586 This sets the state to C<READY>. This is only used when implementing
587 actions using the low-level API.
589 For more information on states, see L<guestfs(3)>.");
591 ("end_busy", (RErr, []), -1, [NotInFish],
593 "leave the busy state",
595 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
596 state as is. This is only used when implementing
597 actions using the low-level API.
599 For more information on states, see L<guestfs(3)>.");
601 ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
603 "set memory allocated to the qemu subprocess",
605 This sets the memory size in megabytes allocated to the
606 qemu subprocess. This only has any effect if called before
609 You can also change this by setting the environment
610 variable C<LIBGUESTFS_MEMSIZE> before the handle is
613 For more information on the architecture of libguestfs,
614 see L<guestfs(3)>.");
616 ("get_memsize", (RInt "memsize", []), -1, [],
618 "get memory allocated to the qemu subprocess",
620 This gets the memory size in megabytes allocated to the
623 If C<guestfs_set_memsize> was not called
624 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
625 then this returns the compiled-in default value for memsize.
627 For more information on the architecture of libguestfs,
628 see L<guestfs(3)>.");
632 (* daemon_functions are any functions which cause some action
633 * to take place in the daemon.
636 let daemon_functions = [
637 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
638 [InitEmpty, Always, TestOutput (
639 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
640 ["mkfs"; "ext2"; "/dev/sda1"];
641 ["mount"; "/dev/sda1"; "/"];
642 ["write_file"; "/new"; "new file contents"; "0"];
643 ["cat"; "/new"]], "new file contents")],
644 "mount a guest disk at a position in the filesystem",
646 Mount a guest disk at a position in the filesystem. Block devices
647 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
648 the guest. If those block devices contain partitions, they will have
649 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
652 The rules are the same as for L<mount(2)>: A filesystem must
653 first be mounted on C</> before others can be mounted. Other
654 filesystems can only be mounted on directories which already
657 The mounted filesystem is writable, if we have sufficient permissions
658 on the underlying device.
660 The filesystem options C<sync> and C<noatime> are set with this
661 call, in order to improve reliability.");
663 ("sync", (RErr, []), 2, [],
664 [ InitEmpty, Always, TestRun [["sync"]]],
665 "sync disks, writes are flushed through to the disk image",
667 This syncs the disk, so that any writes are flushed through to the
668 underlying disk image.
670 You should always call this if you have modified a disk image, before
671 closing the handle.");
673 ("touch", (RErr, [String "path"]), 3, [],
674 [InitBasicFS, Always, TestOutputTrue (
676 ["exists"; "/new"]])],
677 "update file timestamps or create a new file",
679 Touch acts like the L<touch(1)> command. It can be used to
680 update the timestamps on a file, or, if the file does not exist,
681 to create a new zero-length file.");
683 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
684 [InitBasicFS, Always, TestOutput (
685 [["write_file"; "/new"; "new file contents"; "0"];
686 ["cat"; "/new"]], "new file contents")],
687 "list the contents of a file",
689 Return the contents of the file named C<path>.
691 Note that this function cannot correctly handle binary files
692 (specifically, files containing C<\\0> character which is treated
693 as end of string). For those you need to use the C<guestfs_download>
694 function which has a more complex interface.");
696 ("ll", (RString "listing", [String "directory"]), 5, [],
697 [], (* XXX Tricky to test because it depends on the exact format
698 * of the 'ls -l' command, which changes between F10 and F11.
700 "list the files in a directory (long format)",
702 List the files in C<directory> (relative to the root directory,
703 there is no cwd) in the format of 'ls -la'.
705 This command is mostly useful for interactive sessions. It
706 is I<not> intended that you try to parse the output string.");
708 ("ls", (RStringList "listing", [String "directory"]), 6, [],
709 [InitBasicFS, Always, TestOutputList (
712 ["touch"; "/newest"];
713 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
714 "list the files in a directory",
716 List the files in C<directory> (relative to the root directory,
717 there is no cwd). The '.' and '..' entries are not returned, but
718 hidden files are shown.
720 This command is mostly useful for interactive sessions. Programs
721 should probably use C<guestfs_readdir> instead.");
723 ("list_devices", (RStringList "devices", []), 7, [],
724 [InitEmpty, Always, TestOutputListOfDevices (
725 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
726 "list the block devices",
728 List all the block devices.
730 The full block device names are returned, eg. C</dev/sda>");
732 ("list_partitions", (RStringList "partitions", []), 8, [],
733 [InitBasicFS, Always, TestOutputListOfDevices (
734 [["list_partitions"]], ["/dev/sda1"]);
735 InitEmpty, Always, TestOutputListOfDevices (
736 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
737 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
738 "list the partitions",
740 List all the partitions detected on all block devices.
742 The full partition device names are returned, eg. C</dev/sda1>
744 This does not return logical volumes. For that you will need to
745 call C<guestfs_lvs>.");
747 ("pvs", (RStringList "physvols", []), 9, [],
748 [InitBasicFSonLVM, Always, TestOutputListOfDevices (
749 [["pvs"]], ["/dev/sda1"]);
750 InitEmpty, Always, TestOutputListOfDevices (
751 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
752 ["pvcreate"; "/dev/sda1"];
753 ["pvcreate"; "/dev/sda2"];
754 ["pvcreate"; "/dev/sda3"];
755 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
756 "list the LVM physical volumes (PVs)",
758 List all the physical volumes detected. This is the equivalent
759 of the L<pvs(8)> command.
761 This returns a list of just the device names that contain
762 PVs (eg. C</dev/sda2>).
764 See also C<guestfs_pvs_full>.");
766 ("vgs", (RStringList "volgroups", []), 10, [],
767 [InitBasicFSonLVM, Always, TestOutputList (
769 InitEmpty, Always, TestOutputList (
770 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
771 ["pvcreate"; "/dev/sda1"];
772 ["pvcreate"; "/dev/sda2"];
773 ["pvcreate"; "/dev/sda3"];
774 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
775 ["vgcreate"; "VG2"; "/dev/sda3"];
776 ["vgs"]], ["VG1"; "VG2"])],
777 "list the LVM volume groups (VGs)",
779 List all the volumes groups detected. This is the equivalent
780 of the L<vgs(8)> command.
782 This returns a list of just the volume group names that were
783 detected (eg. C<VolGroup00>).
785 See also C<guestfs_vgs_full>.");
787 ("lvs", (RStringList "logvols", []), 11, [],
788 [InitBasicFSonLVM, Always, TestOutputList (
789 [["lvs"]], ["/dev/VG/LV"]);
790 InitEmpty, Always, TestOutputList (
791 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
792 ["pvcreate"; "/dev/sda1"];
793 ["pvcreate"; "/dev/sda2"];
794 ["pvcreate"; "/dev/sda3"];
795 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
796 ["vgcreate"; "VG2"; "/dev/sda3"];
797 ["lvcreate"; "LV1"; "VG1"; "50"];
798 ["lvcreate"; "LV2"; "VG1"; "50"];
799 ["lvcreate"; "LV3"; "VG2"; "50"];
800 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
801 "list the LVM logical volumes (LVs)",
803 List all the logical volumes detected. This is the equivalent
804 of the L<lvs(8)> command.
806 This returns a list of the logical volume device names
807 (eg. C</dev/VolGroup00/LogVol00>).
809 See also C<guestfs_lvs_full>.");
811 ("pvs_full", (RPVList "physvols", []), 12, [],
812 [], (* XXX how to test? *)
813 "list the LVM physical volumes (PVs)",
815 List all the physical volumes detected. This is the equivalent
816 of the L<pvs(8)> command. The \"full\" version includes all fields.");
818 ("vgs_full", (RVGList "volgroups", []), 13, [],
819 [], (* XXX how to test? *)
820 "list the LVM volume groups (VGs)",
822 List all the volumes groups detected. This is the equivalent
823 of the L<vgs(8)> command. The \"full\" version includes all fields.");
825 ("lvs_full", (RLVList "logvols", []), 14, [],
826 [], (* XXX how to test? *)
827 "list the LVM logical volumes (LVs)",
829 List all the logical volumes detected. This is the equivalent
830 of the L<lvs(8)> command. The \"full\" version includes all fields.");
832 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
833 [InitBasicFS, Always, TestOutputList (
834 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
835 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
836 InitBasicFS, Always, TestOutputList (
837 [["write_file"; "/new"; ""; "0"];
838 ["read_lines"; "/new"]], [])],
839 "read file as lines",
841 Return the contents of the file named C<path>.
843 The file contents are returned as a list of lines. Trailing
844 C<LF> and C<CRLF> character sequences are I<not> returned.
846 Note that this function cannot correctly handle binary files
847 (specifically, files containing C<\\0> character which is treated
848 as end of line). For those you need to use the C<guestfs_read_file>
849 function which has a more complex interface.");
851 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
852 [], (* XXX Augeas code needs tests. *)
853 "create a new Augeas handle",
855 Create a new Augeas handle for editing configuration files.
856 If there was any previous Augeas handle associated with this
857 guestfs session, then it is closed.
859 You must call this before using any other C<guestfs_aug_*>
862 C<root> is the filesystem root. C<root> must not be NULL,
865 The flags are the same as the flags defined in
866 E<lt>augeas.hE<gt>, the logical I<or> of the following
871 =item C<AUG_SAVE_BACKUP> = 1
873 Keep the original file with a C<.augsave> extension.
875 =item C<AUG_SAVE_NEWFILE> = 2
877 Save changes into a file with extension C<.augnew>, and
878 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
880 =item C<AUG_TYPE_CHECK> = 4
882 Typecheck lenses (can be expensive).
884 =item C<AUG_NO_STDINC> = 8
886 Do not use standard load path for modules.
888 =item C<AUG_SAVE_NOOP> = 16
890 Make save a no-op, just record what would have been changed.
892 =item C<AUG_NO_LOAD> = 32
894 Do not load the tree in C<guestfs_aug_init>.
898 To close the handle, you can call C<guestfs_aug_close>.
900 To find out more about Augeas, see L<http://augeas.net/>.");
902 ("aug_close", (RErr, []), 26, [],
903 [], (* XXX Augeas code needs tests. *)
904 "close the current Augeas handle",
906 Close the current Augeas handle and free up any resources
907 used by it. After calling this, you have to call
908 C<guestfs_aug_init> again before you can use any other
911 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
912 [], (* XXX Augeas code needs tests. *)
913 "define an Augeas variable",
915 Defines an Augeas variable C<name> whose value is the result
916 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
919 On success this returns the number of nodes in C<expr>, or
920 C<0> if C<expr> evaluates to something which is not a nodeset.");
922 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
923 [], (* XXX Augeas code needs tests. *)
924 "define an Augeas node",
926 Defines a variable C<name> whose value is the result of
929 If C<expr> evaluates to an empty nodeset, a node is created,
930 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
931 C<name> will be the nodeset containing that single node.
933 On success this returns a pair containing the
934 number of nodes in the nodeset, and a boolean flag
935 if a node was created.");
937 ("aug_get", (RString "val", [String "path"]), 19, [],
938 [], (* XXX Augeas code needs tests. *)
939 "look up the value of an Augeas path",
941 Look up the value associated with C<path>. If C<path>
942 matches exactly one node, the C<value> is returned.");
944 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
945 [], (* XXX Augeas code needs tests. *)
946 "set Augeas path to value",
948 Set the value associated with C<path> to C<value>.");
950 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
951 [], (* XXX Augeas code needs tests. *)
952 "insert a sibling Augeas node",
954 Create a new sibling C<label> for C<path>, inserting it into
955 the tree before or after C<path> (depending on the boolean
958 C<path> must match exactly one existing node in the tree, and
959 C<label> must be a label, ie. not contain C</>, C<*> or end
960 with a bracketed index C<[N]>.");
962 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
963 [], (* XXX Augeas code needs tests. *)
964 "remove an Augeas path",
966 Remove C<path> and all of its children.
968 On success this returns the number of entries which were removed.");
970 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
971 [], (* XXX Augeas code needs tests. *)
974 Move the node C<src> to C<dest>. C<src> must match exactly
975 one node. C<dest> is overwritten if it exists.");
977 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
978 [], (* XXX Augeas code needs tests. *)
979 "return Augeas nodes which match path",
981 Returns a list of paths which match the path expression C<path>.
982 The returned paths are sufficiently qualified so that they match
983 exactly one node in the current tree.");
985 ("aug_save", (RErr, []), 25, [],
986 [], (* XXX Augeas code needs tests. *)
987 "write all pending Augeas changes to disk",
989 This writes all pending changes to disk.
991 The flags which were passed to C<guestfs_aug_init> affect exactly
992 how files are saved.");
994 ("aug_load", (RErr, []), 27, [],
995 [], (* XXX Augeas code needs tests. *)
996 "load files into the tree",
998 Load files into the tree.
1000 See C<aug_load> in the Augeas documentation for the full gory
1003 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
1004 [], (* XXX Augeas code needs tests. *)
1005 "list Augeas nodes under a path",
1007 This is just a shortcut for listing C<guestfs_aug_match>
1008 C<path/*> and sorting the resulting nodes into alphabetical order.");
1010 ("rm", (RErr, [String "path"]), 29, [],
1011 [InitBasicFS, Always, TestRun
1014 InitBasicFS, Always, TestLastFail
1016 InitBasicFS, Always, TestLastFail
1021 Remove the single file C<path>.");
1023 ("rmdir", (RErr, [String "path"]), 30, [],
1024 [InitBasicFS, Always, TestRun
1027 InitBasicFS, Always, TestLastFail
1028 [["rmdir"; "/new"]];
1029 InitBasicFS, Always, TestLastFail
1031 ["rmdir"; "/new"]]],
1032 "remove a directory",
1034 Remove the single directory C<path>.");
1036 ("rm_rf", (RErr, [String "path"]), 31, [],
1037 [InitBasicFS, Always, TestOutputFalse
1039 ["mkdir"; "/new/foo"];
1040 ["touch"; "/new/foo/bar"];
1042 ["exists"; "/new"]]],
1043 "remove a file or directory recursively",
1045 Remove the file or directory C<path>, recursively removing the
1046 contents if its a directory. This is like the C<rm -rf> shell
1049 ("mkdir", (RErr, [String "path"]), 32, [],
1050 [InitBasicFS, Always, TestOutputTrue
1052 ["is_dir"; "/new"]];
1053 InitBasicFS, Always, TestLastFail
1054 [["mkdir"; "/new/foo/bar"]]],
1055 "create a directory",
1057 Create a directory named C<path>.");
1059 ("mkdir_p", (RErr, [String "path"]), 33, [],
1060 [InitBasicFS, Always, TestOutputTrue
1061 [["mkdir_p"; "/new/foo/bar"];
1062 ["is_dir"; "/new/foo/bar"]];
1063 InitBasicFS, Always, TestOutputTrue
1064 [["mkdir_p"; "/new/foo/bar"];
1065 ["is_dir"; "/new/foo"]];
1066 InitBasicFS, Always, TestOutputTrue
1067 [["mkdir_p"; "/new/foo/bar"];
1068 ["is_dir"; "/new"]];
1069 (* Regression tests for RHBZ#503133: *)
1070 InitBasicFS, Always, TestRun
1072 ["mkdir_p"; "/new"]];
1073 InitBasicFS, Always, TestLastFail
1075 ["mkdir_p"; "/new"]]],
1076 "create a directory and parents",
1078 Create a directory named C<path>, creating any parent directories
1079 as necessary. This is like the C<mkdir -p> shell command.");
1081 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1082 [], (* XXX Need stat command to test *)
1085 Change the mode (permissions) of C<path> to C<mode>. Only
1086 numeric modes are supported.");
1088 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1089 [], (* XXX Need stat command to test *)
1090 "change file owner and group",
1092 Change the file owner to C<owner> and group to C<group>.
1094 Only numeric uid and gid are supported. If you want to use
1095 names, you will need to locate and parse the password file
1096 yourself (Augeas support makes this relatively easy).");
1098 ("exists", (RBool "existsflag", [String "path"]), 36, [],
1099 [InitBasicFS, Always, TestOutputTrue (
1101 ["exists"; "/new"]]);
1102 InitBasicFS, Always, TestOutputTrue (
1104 ["exists"; "/new"]])],
1105 "test if file or directory exists",
1107 This returns C<true> if and only if there is a file, directory
1108 (or anything) with the given C<path> name.
1110 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1112 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1113 [InitBasicFS, Always, TestOutputTrue (
1115 ["is_file"; "/new"]]);
1116 InitBasicFS, Always, TestOutputFalse (
1118 ["is_file"; "/new"]])],
1119 "test if file exists",
1121 This returns C<true> if and only if there is a file
1122 with the given C<path> name. Note that it returns false for
1123 other objects like directories.
1125 See also C<guestfs_stat>.");
1127 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1128 [InitBasicFS, Always, TestOutputFalse (
1130 ["is_dir"; "/new"]]);
1131 InitBasicFS, Always, TestOutputTrue (
1133 ["is_dir"; "/new"]])],
1134 "test if file exists",
1136 This returns C<true> if and only if there is a directory
1137 with the given C<path> name. Note that it returns false for
1138 other objects like files.
1140 See also C<guestfs_stat>.");
1142 ("pvcreate", (RErr, [String "device"]), 39, [],
1143 [InitEmpty, Always, TestOutputListOfDevices (
1144 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1145 ["pvcreate"; "/dev/sda1"];
1146 ["pvcreate"; "/dev/sda2"];
1147 ["pvcreate"; "/dev/sda3"];
1148 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1149 "create an LVM physical volume",
1151 This creates an LVM physical volume on the named C<device>,
1152 where C<device> should usually be a partition name such
1155 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1156 [InitEmpty, Always, TestOutputList (
1157 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1158 ["pvcreate"; "/dev/sda1"];
1159 ["pvcreate"; "/dev/sda2"];
1160 ["pvcreate"; "/dev/sda3"];
1161 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1162 ["vgcreate"; "VG2"; "/dev/sda3"];
1163 ["vgs"]], ["VG1"; "VG2"])],
1164 "create an LVM volume group",
1166 This creates an LVM volume group called C<volgroup>
1167 from the non-empty list of physical volumes C<physvols>.");
1169 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1170 [InitEmpty, Always, TestOutputList (
1171 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1172 ["pvcreate"; "/dev/sda1"];
1173 ["pvcreate"; "/dev/sda2"];
1174 ["pvcreate"; "/dev/sda3"];
1175 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1176 ["vgcreate"; "VG2"; "/dev/sda3"];
1177 ["lvcreate"; "LV1"; "VG1"; "50"];
1178 ["lvcreate"; "LV2"; "VG1"; "50"];
1179 ["lvcreate"; "LV3"; "VG2"; "50"];
1180 ["lvcreate"; "LV4"; "VG2"; "50"];
1181 ["lvcreate"; "LV5"; "VG2"; "50"];
1183 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1184 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1185 "create an LVM volume group",
1187 This creates an LVM volume group called C<logvol>
1188 on the volume group C<volgroup>, with C<size> megabytes.");
1190 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1191 [InitEmpty, Always, TestOutput (
1192 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1193 ["mkfs"; "ext2"; "/dev/sda1"];
1194 ["mount"; "/dev/sda1"; "/"];
1195 ["write_file"; "/new"; "new file contents"; "0"];
1196 ["cat"; "/new"]], "new file contents")],
1197 "make a filesystem",
1199 This creates a filesystem on C<device> (usually a partition
1200 or LVM logical volume). The filesystem type is C<fstype>, for
1203 ("sfdisk", (RErr, [String "device";
1204 Int "cyls"; Int "heads"; Int "sectors";
1205 StringList "lines"]), 43, [DangerWillRobinson],
1207 "create partitions on a block device",
1209 This is a direct interface to the L<sfdisk(8)> program for creating
1210 partitions on block devices.
1212 C<device> should be a block device, for example C</dev/sda>.
1214 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1215 and sectors on the device, which are passed directly to sfdisk as
1216 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
1217 of these, then the corresponding parameter is omitted. Usually for
1218 'large' disks, you can just pass C<0> for these, but for small
1219 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1220 out the right geometry and you will need to tell it.
1222 C<lines> is a list of lines that we feed to C<sfdisk>. For more
1223 information refer to the L<sfdisk(8)> manpage.
1225 To create a single partition occupying the whole disk, you would
1226 pass C<lines> as a single element list, when the single element being
1227 the string C<,> (comma).
1229 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1231 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1232 [InitBasicFS, Always, TestOutput (
1233 [["write_file"; "/new"; "new file contents"; "0"];
1234 ["cat"; "/new"]], "new file contents");
1235 InitBasicFS, Always, TestOutput (
1236 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1237 ["cat"; "/new"]], "\nnew file contents\n");
1238 InitBasicFS, Always, TestOutput (
1239 [["write_file"; "/new"; "\n\n"; "0"];
1240 ["cat"; "/new"]], "\n\n");
1241 InitBasicFS, Always, TestOutput (
1242 [["write_file"; "/new"; ""; "0"];
1243 ["cat"; "/new"]], "");
1244 InitBasicFS, Always, TestOutput (
1245 [["write_file"; "/new"; "\n\n\n"; "0"];
1246 ["cat"; "/new"]], "\n\n\n");
1247 InitBasicFS, Always, TestOutput (
1248 [["write_file"; "/new"; "\n"; "0"];
1249 ["cat"; "/new"]], "\n")],
1252 This call creates a file called C<path>. The contents of the
1253 file is the string C<content> (which can contain any 8 bit data),
1254 with length C<size>.
1256 As a special case, if C<size> is C<0>
1257 then the length is calculated using C<strlen> (so in this case
1258 the content cannot contain embedded ASCII NULs).
1260 I<NB.> Owing to a bug, writing content containing ASCII NUL
1261 characters does I<not> work, even if the length is specified.
1262 We hope to resolve this bug in a future version. In the meantime
1263 use C<guestfs_upload>.");
1265 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1266 [InitEmpty, Always, TestOutputListOfDevices (
1267 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1268 ["mkfs"; "ext2"; "/dev/sda1"];
1269 ["mount"; "/dev/sda1"; "/"];
1270 ["mounts"]], ["/dev/sda1"]);
1271 InitEmpty, Always, TestOutputList (
1272 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1273 ["mkfs"; "ext2"; "/dev/sda1"];
1274 ["mount"; "/dev/sda1"; "/"];
1277 "unmount a filesystem",
1279 This unmounts the given filesystem. The filesystem may be
1280 specified either by its mountpoint (path) or the device which
1281 contains the filesystem.");
1283 ("mounts", (RStringList "devices", []), 46, [],
1284 [InitBasicFS, Always, TestOutputListOfDevices (
1285 [["mounts"]], ["/dev/sda1"])],
1286 "show mounted filesystems",
1288 This returns the list of currently mounted filesystems. It returns
1289 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1291 Some internal mounts are not shown.");
1293 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1294 [InitBasicFS, Always, TestOutputList (
1297 (* check that umount_all can unmount nested mounts correctly: *)
1298 InitEmpty, Always, TestOutputList (
1299 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1300 ["mkfs"; "ext2"; "/dev/sda1"];
1301 ["mkfs"; "ext2"; "/dev/sda2"];
1302 ["mkfs"; "ext2"; "/dev/sda3"];
1303 ["mount"; "/dev/sda1"; "/"];
1305 ["mount"; "/dev/sda2"; "/mp1"];
1306 ["mkdir"; "/mp1/mp2"];
1307 ["mount"; "/dev/sda3"; "/mp1/mp2"];
1308 ["mkdir"; "/mp1/mp2/mp3"];
1311 "unmount all filesystems",
1313 This unmounts all mounted filesystems.
1315 Some internal mounts are not unmounted by this call.");
1317 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1319 "remove all LVM LVs, VGs and PVs",
1321 This command removes all LVM logical volumes, volume groups
1322 and physical volumes.");
1324 ("file", (RString "description", [String "path"]), 49, [],
1325 [InitBasicFS, Always, TestOutput (
1327 ["file"; "/new"]], "empty");
1328 InitBasicFS, Always, TestOutput (
1329 [["write_file"; "/new"; "some content\n"; "0"];
1330 ["file"; "/new"]], "ASCII text");
1331 InitBasicFS, Always, TestLastFail (
1332 [["file"; "/nofile"]])],
1333 "determine file type",
1335 This call uses the standard L<file(1)> command to determine
1336 the type or contents of the file. This also works on devices,
1337 for example to find out whether a partition contains a filesystem.
1339 The exact command which runs is C<file -bsL path>. Note in
1340 particular that the filename is not prepended to the output
1341 (the C<-b> option).");
1343 ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1344 [InitBasicFS, Always, TestOutput (
1345 [["upload"; "test-command"; "/test-command"];
1346 ["chmod"; "0o755"; "/test-command"];
1347 ["command"; "/test-command 1"]], "Result1");
1348 InitBasicFS, Always, TestOutput (
1349 [["upload"; "test-command"; "/test-command"];
1350 ["chmod"; "0o755"; "/test-command"];
1351 ["command"; "/test-command 2"]], "Result2\n");
1352 InitBasicFS, Always, TestOutput (
1353 [["upload"; "test-command"; "/test-command"];
1354 ["chmod"; "0o755"; "/test-command"];
1355 ["command"; "/test-command 3"]], "\nResult3");
1356 InitBasicFS, Always, TestOutput (
1357 [["upload"; "test-command"; "/test-command"];
1358 ["chmod"; "0o755"; "/test-command"];
1359 ["command"; "/test-command 4"]], "\nResult4\n");
1360 InitBasicFS, Always, TestOutput (
1361 [["upload"; "test-command"; "/test-command"];
1362 ["chmod"; "0o755"; "/test-command"];
1363 ["command"; "/test-command 5"]], "\nResult5\n\n");
1364 InitBasicFS, Always, TestOutput (
1365 [["upload"; "test-command"; "/test-command"];
1366 ["chmod"; "0o755"; "/test-command"];
1367 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1368 InitBasicFS, Always, TestOutput (
1369 [["upload"; "test-command"; "/test-command"];
1370 ["chmod"; "0o755"; "/test-command"];
1371 ["command"; "/test-command 7"]], "");
1372 InitBasicFS, Always, TestOutput (
1373 [["upload"; "test-command"; "/test-command"];
1374 ["chmod"; "0o755"; "/test-command"];
1375 ["command"; "/test-command 8"]], "\n");
1376 InitBasicFS, Always, TestOutput (
1377 [["upload"; "test-command"; "/test-command"];
1378 ["chmod"; "0o755"; "/test-command"];
1379 ["command"; "/test-command 9"]], "\n\n");
1380 InitBasicFS, Always, TestOutput (
1381 [["upload"; "test-command"; "/test-command"];
1382 ["chmod"; "0o755"; "/test-command"];
1383 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1384 InitBasicFS, Always, TestOutput (
1385 [["upload"; "test-command"; "/test-command"];
1386 ["chmod"; "0o755"; "/test-command"];
1387 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1388 InitBasicFS, Always, TestLastFail (
1389 [["upload"; "test-command"; "/test-command"];
1390 ["chmod"; "0o755"; "/test-command"];
1391 ["command"; "/test-command"]])],
1392 "run a command from the guest filesystem",
1394 This call runs a command from the guest filesystem. The
1395 filesystem must be mounted, and must contain a compatible
1396 operating system (ie. something Linux, with the same
1397 or compatible processor architecture).
1399 The single parameter is an argv-style list of arguments.
1400 The first element is the name of the program to run.
1401 Subsequent elements are parameters. The list must be
1402 non-empty (ie. must contain a program name). Note that
1403 the command runs directly, and is I<not> invoked via
1404 the shell (see C<guestfs_sh>).
1406 The return value is anything printed to I<stdout> by
1409 If the command returns a non-zero exit status, then
1410 this function returns an error message. The error message
1411 string is the content of I<stderr> from the command.
1413 The C<$PATH> environment variable will contain at least
1414 C</usr/bin> and C</bin>. If you require a program from
1415 another location, you should provide the full path in the
1418 Shared libraries and data files required by the program
1419 must be available on filesystems which are mounted in the
1420 correct places. It is the caller's responsibility to ensure
1421 all filesystems that are needed are mounted at the right
1424 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1425 [InitBasicFS, Always, TestOutputList (
1426 [["upload"; "test-command"; "/test-command"];
1427 ["chmod"; "0o755"; "/test-command"];
1428 ["command_lines"; "/test-command 1"]], ["Result1"]);
1429 InitBasicFS, Always, TestOutputList (
1430 [["upload"; "test-command"; "/test-command"];
1431 ["chmod"; "0o755"; "/test-command"];
1432 ["command_lines"; "/test-command 2"]], ["Result2"]);
1433 InitBasicFS, Always, TestOutputList (
1434 [["upload"; "test-command"; "/test-command"];
1435 ["chmod"; "0o755"; "/test-command"];
1436 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1437 InitBasicFS, Always, TestOutputList (
1438 [["upload"; "test-command"; "/test-command"];
1439 ["chmod"; "0o755"; "/test-command"];
1440 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1441 InitBasicFS, Always, TestOutputList (
1442 [["upload"; "test-command"; "/test-command"];
1443 ["chmod"; "0o755"; "/test-command"];
1444 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1445 InitBasicFS, Always, TestOutputList (
1446 [["upload"; "test-command"; "/test-command"];
1447 ["chmod"; "0o755"; "/test-command"];
1448 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1449 InitBasicFS, Always, TestOutputList (
1450 [["upload"; "test-command"; "/test-command"];
1451 ["chmod"; "0o755"; "/test-command"];
1452 ["command_lines"; "/test-command 7"]], []);
1453 InitBasicFS, Always, TestOutputList (
1454 [["upload"; "test-command"; "/test-command"];
1455 ["chmod"; "0o755"; "/test-command"];
1456 ["command_lines"; "/test-command 8"]], [""]);
1457 InitBasicFS, Always, TestOutputList (
1458 [["upload"; "test-command"; "/test-command"];
1459 ["chmod"; "0o755"; "/test-command"];
1460 ["command_lines"; "/test-command 9"]], ["";""]);
1461 InitBasicFS, Always, TestOutputList (
1462 [["upload"; "test-command"; "/test-command"];
1463 ["chmod"; "0o755"; "/test-command"];
1464 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1465 InitBasicFS, Always, TestOutputList (
1466 [["upload"; "test-command"; "/test-command"];
1467 ["chmod"; "0o755"; "/test-command"];
1468 ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1469 "run a command, returning lines",
1471 This is the same as C<guestfs_command>, but splits the
1472 result into a list of lines.
1474 See also: C<guestfs_sh_lines>");
1476 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1477 [InitBasicFS, Always, TestOutputStruct (
1479 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1480 "get file information",
1482 Returns file information for the given C<path>.
1484 This is the same as the C<stat(2)> system call.");
1486 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1487 [InitBasicFS, Always, TestOutputStruct (
1489 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1490 "get file information for a symbolic link",
1492 Returns file information for the given C<path>.
1494 This is the same as C<guestfs_stat> except that if C<path>
1495 is a symbolic link, then the link is stat-ed, not the file it
1498 This is the same as the C<lstat(2)> system call.");
1500 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1501 [InitBasicFS, Always, TestOutputStruct (
1502 [["statvfs"; "/"]], [CompareWithInt ("namemax", 255);
1503 CompareWithInt ("bsize", 1024)])],
1504 "get file system statistics",
1506 Returns file system statistics for any mounted file system.
1507 C<path> should be a file or directory in the mounted file system
1508 (typically it is the mount point itself, but it doesn't need to be).
1510 This is the same as the C<statvfs(2)> system call.");
1512 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1514 "get ext2/ext3/ext4 superblock details",
1516 This returns the contents of the ext2, ext3 or ext4 filesystem
1517 superblock on C<device>.
1519 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1520 manpage for more details. The list of fields returned isn't
1521 clearly defined, and depends on both the version of C<tune2fs>
1522 that libguestfs was built against, and the filesystem itself.");
1524 ("blockdev_setro", (RErr, [String "device"]), 56, [],
1525 [InitEmpty, Always, TestOutputTrue (
1526 [["blockdev_setro"; "/dev/sda"];
1527 ["blockdev_getro"; "/dev/sda"]])],
1528 "set block device to read-only",
1530 Sets the block device named C<device> to read-only.
1532 This uses the L<blockdev(8)> command.");
1534 ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1535 [InitEmpty, Always, TestOutputFalse (
1536 [["blockdev_setrw"; "/dev/sda"];
1537 ["blockdev_getro"; "/dev/sda"]])],
1538 "set block device to read-write",
1540 Sets the block device named C<device> to read-write.
1542 This uses the L<blockdev(8)> command.");
1544 ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1545 [InitEmpty, Always, TestOutputTrue (
1546 [["blockdev_setro"; "/dev/sda"];
1547 ["blockdev_getro"; "/dev/sda"]])],
1548 "is block device set to read-only",
1550 Returns a boolean indicating if the block device is read-only
1551 (true if read-only, false if not).
1553 This uses the L<blockdev(8)> command.");
1555 ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1556 [InitEmpty, Always, TestOutputInt (
1557 [["blockdev_getss"; "/dev/sda"]], 512)],
1558 "get sectorsize of block device",
1560 This returns the size of sectors on a block device.
1561 Usually 512, but can be larger for modern devices.
1563 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1566 This uses the L<blockdev(8)> command.");
1568 ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1569 [InitEmpty, Always, TestOutputInt (
1570 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1571 "get blocksize of block device",
1573 This returns the block size of a device.
1575 (Note this is different from both I<size in blocks> and
1576 I<filesystem block size>).
1578 This uses the L<blockdev(8)> command.");
1580 ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1582 "set blocksize of block device",
1584 This sets the block size of a device.
1586 (Note this is different from both I<size in blocks> and
1587 I<filesystem block size>).
1589 This uses the L<blockdev(8)> command.");
1591 ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1592 [InitEmpty, Always, TestOutputInt (
1593 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1594 "get total size of device in 512-byte sectors",
1596 This returns the size of the device in units of 512-byte sectors
1597 (even if the sectorsize isn't 512 bytes ... weird).
1599 See also C<guestfs_blockdev_getss> for the real sector size of
1600 the device, and C<guestfs_blockdev_getsize64> for the more
1601 useful I<size in bytes>.
1603 This uses the L<blockdev(8)> command.");
1605 ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1606 [InitEmpty, Always, TestOutputInt (
1607 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1608 "get total size of device in bytes",
1610 This returns the size of the device in bytes.
1612 See also C<guestfs_blockdev_getsz>.
1614 This uses the L<blockdev(8)> command.");
1616 ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1617 [InitEmpty, Always, TestRun
1618 [["blockdev_flushbufs"; "/dev/sda"]]],
1619 "flush device buffers",
1621 This tells the kernel to flush internal buffers associated
1624 This uses the L<blockdev(8)> command.");
1626 ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1627 [InitEmpty, Always, TestRun
1628 [["blockdev_rereadpt"; "/dev/sda"]]],
1629 "reread partition table",
1631 Reread the partition table on C<device>.
1633 This uses the L<blockdev(8)> command.");
1635 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1636 [InitBasicFS, Always, TestOutput (
1637 (* Pick a file from cwd which isn't likely to change. *)
1638 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1639 ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1640 "upload a file from the local machine",
1642 Upload local file C<filename> to C<remotefilename> on the
1645 C<filename> can also be a named pipe.
1647 See also C<guestfs_download>.");
1649 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1650 [InitBasicFS, Always, TestOutput (
1651 (* Pick a file from cwd which isn't likely to change. *)
1652 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1653 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1654 ["upload"; "testdownload.tmp"; "/upload"];
1655 ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1656 "download a file to the local machine",
1658 Download file C<remotefilename> and save it as C<filename>
1659 on the local machine.
1661 C<filename> can also be a named pipe.
1663 See also C<guestfs_upload>, C<guestfs_cat>.");
1665 ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1666 [InitBasicFS, Always, TestOutput (
1667 [["write_file"; "/new"; "test\n"; "0"];
1668 ["checksum"; "crc"; "/new"]], "935282863");
1669 InitBasicFS, Always, TestLastFail (
1670 [["checksum"; "crc"; "/new"]]);
1671 InitBasicFS, Always, TestOutput (
1672 [["write_file"; "/new"; "test\n"; "0"];
1673 ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1674 InitBasicFS, Always, TestOutput (
1675 [["write_file"; "/new"; "test\n"; "0"];
1676 ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1677 InitBasicFS, Always, TestOutput (
1678 [["write_file"; "/new"; "test\n"; "0"];
1679 ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1680 InitBasicFS, Always, TestOutput (
1681 [["write_file"; "/new"; "test\n"; "0"];
1682 ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1683 InitBasicFS, Always, TestOutput (
1684 [["write_file"; "/new"; "test\n"; "0"];
1685 ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1686 InitBasicFS, Always, TestOutput (
1687 [["write_file"; "/new"; "test\n"; "0"];
1688 ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
1689 InitBasicFS, Always, TestOutput (
1690 (* RHEL 5 thinks this is an HFS+ filesystem unless we give
1691 * the type explicitly.
1693 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
1694 ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
1695 "compute MD5, SHAx or CRC checksum of file",
1697 This call computes the MD5, SHAx or CRC checksum of the
1700 The type of checksum to compute is given by the C<csumtype>
1701 parameter which must have one of the following values:
1707 Compute the cyclic redundancy check (CRC) specified by POSIX
1708 for the C<cksum> command.
1712 Compute the MD5 hash (using the C<md5sum> program).
1716 Compute the SHA1 hash (using the C<sha1sum> program).
1720 Compute the SHA224 hash (using the C<sha224sum> program).
1724 Compute the SHA256 hash (using the C<sha256sum> program).
1728 Compute the SHA384 hash (using the C<sha384sum> program).
1732 Compute the SHA512 hash (using the C<sha512sum> program).
1736 The checksum is returned as a printable string.");
1738 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1739 [InitBasicFS, Always, TestOutput (
1740 [["tar_in"; "../images/helloworld.tar"; "/"];
1741 ["cat"; "/hello"]], "hello\n")],
1742 "unpack tarfile to directory",
1744 This command uploads and unpacks local file C<tarfile> (an
1745 I<uncompressed> tar file) into C<directory>.
1747 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1749 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1751 "pack directory into tarfile",
1753 This command packs the contents of C<directory> and downloads
1754 it to local file C<tarfile>.
1756 To download a compressed tarball, use C<guestfs_tgz_out>.");
1758 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1759 [InitBasicFS, Always, TestOutput (
1760 [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1761 ["cat"; "/hello"]], "hello\n")],
1762 "unpack compressed tarball to directory",
1764 This command uploads and unpacks local file C<tarball> (a
1765 I<gzip compressed> tar file) into C<directory>.
1767 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1769 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1771 "pack directory into compressed tarball",
1773 This command packs the contents of C<directory> and downloads
1774 it to local file C<tarball>.
1776 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1778 ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1779 [InitBasicFS, Always, TestLastFail (
1781 ["mount_ro"; "/dev/sda1"; "/"];
1782 ["touch"; "/new"]]);
1783 InitBasicFS, Always, TestOutput (
1784 [["write_file"; "/new"; "data"; "0"];
1786 ["mount_ro"; "/dev/sda1"; "/"];
1787 ["cat"; "/new"]], "data")],
1788 "mount a guest disk, read-only",
1790 This is the same as the C<guestfs_mount> command, but it
1791 mounts the filesystem with the read-only (I<-o ro>) flag.");
1793 ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1795 "mount a guest disk with mount options",
1797 This is the same as the C<guestfs_mount> command, but it
1798 allows you to set the mount options as for the
1799 L<mount(8)> I<-o> flag.");
1801 ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1803 "mount a guest disk with mount options and vfstype",
1805 This is the same as the C<guestfs_mount> command, but it
1806 allows you to set both the mount options and the vfstype
1807 as for the L<mount(8)> I<-o> and I<-t> flags.");
1809 ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1811 "debugging and internals",
1813 The C<guestfs_debug> command exposes some internals of
1814 C<guestfsd> (the guestfs daemon) that runs inside the
1817 There is no comprehensive help for this command. You have
1818 to look at the file C<daemon/debug.c> in the libguestfs source
1819 to find out what you can do.");
1821 ("lvremove", (RErr, [String "device"]), 77, [],
1822 [InitEmpty, Always, TestOutputList (
1823 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1824 ["pvcreate"; "/dev/sda1"];
1825 ["vgcreate"; "VG"; "/dev/sda1"];
1826 ["lvcreate"; "LV1"; "VG"; "50"];
1827 ["lvcreate"; "LV2"; "VG"; "50"];
1828 ["lvremove"; "/dev/VG/LV1"];
1829 ["lvs"]], ["/dev/VG/LV2"]);
1830 InitEmpty, Always, TestOutputList (
1831 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1832 ["pvcreate"; "/dev/sda1"];
1833 ["vgcreate"; "VG"; "/dev/sda1"];
1834 ["lvcreate"; "LV1"; "VG"; "50"];
1835 ["lvcreate"; "LV2"; "VG"; "50"];
1836 ["lvremove"; "/dev/VG"];
1838 InitEmpty, Always, TestOutputList (
1839 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1840 ["pvcreate"; "/dev/sda1"];
1841 ["vgcreate"; "VG"; "/dev/sda1"];
1842 ["lvcreate"; "LV1"; "VG"; "50"];
1843 ["lvcreate"; "LV2"; "VG"; "50"];
1844 ["lvremove"; "/dev/VG"];
1846 "remove an LVM logical volume",
1848 Remove an LVM logical volume C<device>, where C<device> is
1849 the path to the LV, such as C</dev/VG/LV>.
1851 You can also remove all LVs in a volume group by specifying
1852 the VG name, C</dev/VG>.");
1854 ("vgremove", (RErr, [String "vgname"]), 78, [],
1855 [InitEmpty, Always, TestOutputList (
1856 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1857 ["pvcreate"; "/dev/sda1"];
1858 ["vgcreate"; "VG"; "/dev/sda1"];
1859 ["lvcreate"; "LV1"; "VG"; "50"];
1860 ["lvcreate"; "LV2"; "VG"; "50"];
1863 InitEmpty, Always, TestOutputList (
1864 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1865 ["pvcreate"; "/dev/sda1"];
1866 ["vgcreate"; "VG"; "/dev/sda1"];
1867 ["lvcreate"; "LV1"; "VG"; "50"];
1868 ["lvcreate"; "LV2"; "VG"; "50"];
1871 "remove an LVM volume group",
1873 Remove an LVM volume group C<vgname>, (for example C<VG>).
1875 This also forcibly removes all logical volumes in the volume
1878 ("pvremove", (RErr, [String "device"]), 79, [],
1879 [InitEmpty, Always, TestOutputListOfDevices (
1880 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1881 ["pvcreate"; "/dev/sda1"];
1882 ["vgcreate"; "VG"; "/dev/sda1"];
1883 ["lvcreate"; "LV1"; "VG"; "50"];
1884 ["lvcreate"; "LV2"; "VG"; "50"];
1886 ["pvremove"; "/dev/sda1"];
1888 InitEmpty, Always, TestOutputListOfDevices (
1889 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1890 ["pvcreate"; "/dev/sda1"];
1891 ["vgcreate"; "VG"; "/dev/sda1"];
1892 ["lvcreate"; "LV1"; "VG"; "50"];
1893 ["lvcreate"; "LV2"; "VG"; "50"];
1895 ["pvremove"; "/dev/sda1"];
1897 InitEmpty, Always, TestOutputListOfDevices (
1898 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1899 ["pvcreate"; "/dev/sda1"];
1900 ["vgcreate"; "VG"; "/dev/sda1"];
1901 ["lvcreate"; "LV1"; "VG"; "50"];
1902 ["lvcreate"; "LV2"; "VG"; "50"];
1904 ["pvremove"; "/dev/sda1"];
1906 "remove an LVM physical volume",
1908 This wipes a physical volume C<device> so that LVM will no longer
1911 The implementation uses the C<pvremove> command which refuses to
1912 wipe physical volumes that contain any volume groups, so you have
1913 to remove those first.");
1915 ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
1916 [InitBasicFS, Always, TestOutput (
1917 [["set_e2label"; "/dev/sda1"; "testlabel"];
1918 ["get_e2label"; "/dev/sda1"]], "testlabel")],
1919 "set the ext2/3/4 filesystem label",
1921 This sets the ext2/3/4 filesystem label of the filesystem on
1922 C<device> to C<label>. Filesystem labels are limited to
1925 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
1926 to return the existing label on a filesystem.");
1928 ("get_e2label", (RString "label", [String "device"]), 81, [],
1930 "get the ext2/3/4 filesystem label",
1932 This returns the ext2/3/4 filesystem label of the filesystem on
1935 ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
1936 [InitBasicFS, Always, TestOutput (
1937 [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
1938 ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
1939 InitBasicFS, Always, TestOutput (
1940 [["set_e2uuid"; "/dev/sda1"; "clear"];
1941 ["get_e2uuid"; "/dev/sda1"]], "");
1942 (* We can't predict what UUIDs will be, so just check the commands run. *)
1943 InitBasicFS, Always, TestRun (
1944 [["set_e2uuid"; "/dev/sda1"; "random"]]);
1945 InitBasicFS, Always, TestRun (
1946 [["set_e2uuid"; "/dev/sda1"; "time"]])],
1947 "set the ext2/3/4 filesystem UUID",
1949 This sets the ext2/3/4 filesystem UUID of the filesystem on
1950 C<device> to C<uuid>. The format of the UUID and alternatives
1951 such as C<clear>, C<random> and C<time> are described in the
1952 L<tune2fs(8)> manpage.
1954 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
1955 to return the existing UUID of a filesystem.");
1957 ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
1959 "get the ext2/3/4 filesystem UUID",
1961 This returns the ext2/3/4 filesystem UUID of the filesystem on
1964 ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
1965 [InitBasicFS, Always, TestOutputInt (
1966 [["umount"; "/dev/sda1"];
1967 ["fsck"; "ext2"; "/dev/sda1"]], 0);
1968 InitBasicFS, Always, TestOutputInt (
1969 [["umount"; "/dev/sda1"];
1970 ["zero"; "/dev/sda1"];
1971 ["fsck"; "ext2"; "/dev/sda1"]], 8)],
1972 "run the filesystem checker",
1974 This runs the filesystem checker (fsck) on C<device> which
1975 should have filesystem type C<fstype>.
1977 The returned integer is the status. See L<fsck(8)> for the
1978 list of status codes from C<fsck>.
1986 Multiple status codes can be summed together.
1990 A non-zero return code can mean \"success\", for example if
1991 errors have been corrected on the filesystem.
1995 Checking or repairing NTFS volumes is not supported
2000 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2002 ("zero", (RErr, [String "device"]), 85, [],
2003 [InitBasicFS, Always, TestOutput (
2004 [["umount"; "/dev/sda1"];
2005 ["zero"; "/dev/sda1"];
2006 ["file"; "/dev/sda1"]], "data")],
2007 "write zeroes to the device",
2009 This command writes zeroes over the first few blocks of C<device>.
2011 How many blocks are zeroed isn't specified (but it's I<not> enough
2012 to securely wipe the device). It should be sufficient to remove
2013 any partition tables, filesystem superblocks and so on.
2015 See also: C<guestfs_scrub_device>.");
2017 ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
2018 [InitBasicFS, Always, TestOutputTrue (
2019 [["grub_install"; "/"; "/dev/sda1"];
2020 ["is_dir"; "/boot"]])],
2023 This command installs GRUB (the Grand Unified Bootloader) on
2024 C<device>, with the root directory being C<root>.");
2026 ("cp", (RErr, [String "src"; String "dest"]), 87, [],
2027 [InitBasicFS, Always, TestOutput (
2028 [["write_file"; "/old"; "file content"; "0"];
2029 ["cp"; "/old"; "/new"];
2030 ["cat"; "/new"]], "file content");
2031 InitBasicFS, Always, TestOutputTrue (
2032 [["write_file"; "/old"; "file content"; "0"];
2033 ["cp"; "/old"; "/new"];
2034 ["is_file"; "/old"]]);
2035 InitBasicFS, Always, TestOutput (
2036 [["write_file"; "/old"; "file content"; "0"];
2038 ["cp"; "/old"; "/dir/new"];
2039 ["cat"; "/dir/new"]], "file content")],
2042 This copies a file from C<src> to C<dest> where C<dest> is
2043 either a destination filename or destination directory.");
2045 ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2046 [InitBasicFS, Always, TestOutput (
2047 [["mkdir"; "/olddir"];
2048 ["mkdir"; "/newdir"];
2049 ["write_file"; "/olddir/file"; "file content"; "0"];
2050 ["cp_a"; "/olddir"; "/newdir"];
2051 ["cat"; "/newdir/olddir/file"]], "file content")],
2052 "copy a file or directory recursively",
2054 This copies a file or directory from C<src> to C<dest>
2055 recursively using the C<cp -a> command.");
2057 ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2058 [InitBasicFS, Always, TestOutput (
2059 [["write_file"; "/old"; "file content"; "0"];
2060 ["mv"; "/old"; "/new"];
2061 ["cat"; "/new"]], "file content");
2062 InitBasicFS, Always, TestOutputFalse (
2063 [["write_file"; "/old"; "file content"; "0"];
2064 ["mv"; "/old"; "/new"];
2065 ["is_file"; "/old"]])],
2068 This moves a file from C<src> to C<dest> where C<dest> is
2069 either a destination filename or destination directory.");
2071 ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2072 [InitEmpty, Always, TestRun (
2073 [["drop_caches"; "3"]])],
2074 "drop kernel page cache, dentries and inodes",
2076 This instructs the guest kernel to drop its page cache,
2077 and/or dentries and inode caches. The parameter C<whattodrop>
2078 tells the kernel what precisely to drop, see
2079 L<http://linux-mm.org/Drop_Caches>
2081 Setting C<whattodrop> to 3 should drop everything.
2083 This automatically calls L<sync(2)> before the operation,
2084 so that the maximum guest memory is freed.");
2086 ("dmesg", (RString "kmsgs", []), 91, [],
2087 [InitEmpty, Always, TestRun (
2089 "return kernel messages",
2091 This returns the kernel messages (C<dmesg> output) from
2092 the guest kernel. This is sometimes useful for extended
2093 debugging of problems.
2095 Another way to get the same information is to enable
2096 verbose messages with C<guestfs_set_verbose> or by setting
2097 the environment variable C<LIBGUESTFS_DEBUG=1> before
2098 running the program.");
2100 ("ping_daemon", (RErr, []), 92, [],
2101 [InitEmpty, Always, TestRun (
2102 [["ping_daemon"]])],
2103 "ping the guest daemon",
2105 This is a test probe into the guestfs daemon running inside
2106 the qemu subprocess. Calling this function checks that the
2107 daemon responds to the ping message, without affecting the daemon
2108 or attached block device(s) in any other way.");
2110 ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2111 [InitBasicFS, Always, TestOutputTrue (
2112 [["write_file"; "/file1"; "contents of a file"; "0"];
2113 ["cp"; "/file1"; "/file2"];
2114 ["equal"; "/file1"; "/file2"]]);
2115 InitBasicFS, Always, TestOutputFalse (
2116 [["write_file"; "/file1"; "contents of a file"; "0"];
2117 ["write_file"; "/file2"; "contents of another file"; "0"];
2118 ["equal"; "/file1"; "/file2"]]);
2119 InitBasicFS, Always, TestLastFail (
2120 [["equal"; "/file1"; "/file2"]])],
2121 "test if two files have equal contents",
2123 This compares the two files C<file1> and C<file2> and returns
2124 true if their content is exactly equal, or false otherwise.
2126 The external L<cmp(1)> program is used for the comparison.");
2128 ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2129 [InitBasicFS, Always, TestOutputList (
2130 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2131 ["strings"; "/new"]], ["hello"; "world"]);
2132 InitBasicFS, Always, TestOutputList (
2134 ["strings"; "/new"]], [])],
2135 "print the printable strings in a file",
2137 This runs the L<strings(1)> command on a file and returns
2138 the list of printable strings found.");
2140 ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2141 [InitBasicFS, Always, TestOutputList (
2142 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2143 ["strings_e"; "b"; "/new"]], []);
2144 InitBasicFS, Disabled, TestOutputList (
2145 [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2146 ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2147 "print the printable strings in a file",
2149 This is like the C<guestfs_strings> command, but allows you to
2150 specify the encoding.
2152 See the L<strings(1)> manpage for the full list of encodings.
2154 Commonly useful encodings are C<l> (lower case L) which will
2155 show strings inside Windows/x86 files.
2157 The returned strings are transcoded to UTF-8.");
2159 ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2160 [InitBasicFS, Always, TestOutput (
2161 [["write_file"; "/new"; "hello\nworld\n"; "12"];
2162 ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n");
2163 (* Test for RHBZ#501888c2 regression which caused large hexdump
2164 * commands to segfault.
2166 InitBasicFS, Always, TestRun (
2167 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2168 ["hexdump"; "/100krandom"]])],
2169 "dump a file in hexadecimal",
2171 This runs C<hexdump -C> on the given C<path>. The result is
2172 the human-readable, canonical hex dump of the file.");
2174 ("zerofree", (RErr, [String "device"]), 97, [],
2175 [InitNone, Always, TestOutput (
2176 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2177 ["mkfs"; "ext3"; "/dev/sda1"];
2178 ["mount"; "/dev/sda1"; "/"];
2179 ["write_file"; "/new"; "test file"; "0"];
2180 ["umount"; "/dev/sda1"];
2181 ["zerofree"; "/dev/sda1"];
2182 ["mount"; "/dev/sda1"; "/"];
2183 ["cat"; "/new"]], "test file")],
2184 "zero unused inodes and disk blocks on ext2/3 filesystem",
2186 This runs the I<zerofree> program on C<device>. This program
2187 claims to zero unused inodes and disk blocks on an ext2/3
2188 filesystem, thus making it possible to compress the filesystem
2191 You should B<not> run this program if the filesystem is
2194 It is possible that using this program can damage the filesystem
2195 or data on the filesystem.");
2197 ("pvresize", (RErr, [String "device"]), 98, [],
2199 "resize an LVM physical volume",
2201 This resizes (expands or shrinks) an existing LVM physical
2202 volume to match the new size of the underlying device.");
2204 ("sfdisk_N", (RErr, [String "device"; Int "partnum";
2205 Int "cyls"; Int "heads"; Int "sectors";
2206 String "line"]), 99, [DangerWillRobinson],
2208 "modify a single partition on a block device",
2210 This runs L<sfdisk(8)> option to modify just the single
2211 partition C<n> (note: C<n> counts from 1).
2213 For other parameters, see C<guestfs_sfdisk>. You should usually
2214 pass C<0> for the cyls/heads/sectors parameters.");
2216 ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2218 "display the partition table",
2220 This displays the partition table on C<device>, in the
2221 human-readable output of the L<sfdisk(8)> command. It is
2222 not intended to be parsed.");
2224 ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2226 "display the kernel geometry",
2228 This displays the kernel's idea of the geometry of C<device>.
2230 The result is in human-readable format, and not designed to
2233 ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2235 "display the disk geometry from the partition table",
2237 This displays the disk geometry of C<device> read from the
2238 partition table. Especially in the case where the underlying
2239 block device has been resized, this can be different from the
2240 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2242 The result is in human-readable format, and not designed to
2245 ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2247 "activate or deactivate all volume groups",
2249 This command activates or (if C<activate> is false) deactivates
2250 all logical volumes in all volume groups.
2251 If activated, then they are made known to the
2252 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2253 then those devices disappear.
2255 This command is the same as running C<vgchange -a y|n>");
2257 ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2259 "activate or deactivate some volume groups",
2261 This command activates or (if C<activate> is false) deactivates
2262 all logical volumes in the listed volume groups C<volgroups>.
2263 If activated, then they are made known to the
2264 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2265 then those devices disappear.
2267 This command is the same as running C<vgchange -a y|n volgroups...>
2269 Note that if C<volgroups> is an empty list then B<all> volume groups
2270 are activated or deactivated.");
2272 ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2273 [InitNone, Always, TestOutput (
2274 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2275 ["pvcreate"; "/dev/sda1"];
2276 ["vgcreate"; "VG"; "/dev/sda1"];
2277 ["lvcreate"; "LV"; "VG"; "10"];
2278 ["mkfs"; "ext2"; "/dev/VG/LV"];
2279 ["mount"; "/dev/VG/LV"; "/"];
2280 ["write_file"; "/new"; "test content"; "0"];
2282 ["lvresize"; "/dev/VG/LV"; "20"];
2283 ["e2fsck_f"; "/dev/VG/LV"];
2284 ["resize2fs"; "/dev/VG/LV"];
2285 ["mount"; "/dev/VG/LV"; "/"];
2286 ["cat"; "/new"]], "test content")],
2287 "resize an LVM logical volume",
2289 This resizes (expands or shrinks) an existing LVM logical
2290 volume to C<mbytes>. When reducing, data in the reduced part
2293 ("resize2fs", (RErr, [String "device"]), 106, [],
2294 [], (* lvresize tests this *)
2295 "resize an ext2/ext3 filesystem",
2297 This resizes an ext2 or ext3 filesystem to match the size of
2298 the underlying device.
2300 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2301 on the C<device> before calling this command. For unknown reasons
2302 C<resize2fs> sometimes gives an error about this and sometimes not.
2303 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2304 calling this function.");
2306 ("find", (RStringList "names", [String "directory"]), 107, [],
2307 [InitBasicFS, Always, TestOutputList (
2308 [["find"; "/"]], ["lost+found"]);
2309 InitBasicFS, Always, TestOutputList (
2313 ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2314 InitBasicFS, Always, TestOutputList (
2315 [["mkdir_p"; "/a/b/c"];
2316 ["touch"; "/a/b/c/d"];
2317 ["find"; "/a/b/"]], ["c"; "c/d"])],
2318 "find all files and directories",
2320 This command lists out all files and directories, recursively,
2321 starting at C<directory>. It is essentially equivalent to
2322 running the shell command C<find directory -print> but some
2323 post-processing happens on the output, described below.
2325 This returns a list of strings I<without any prefix>. Thus
2326 if the directory structure was:
2332 then the returned list from C<guestfs_find> C</tmp> would be
2340 If C<directory> is not a directory, then this command returns
2343 The returned list is sorted.");
2345 ("e2fsck_f", (RErr, [String "device"]), 108, [],
2346 [], (* lvresize tests this *)
2347 "check an ext2/ext3 filesystem",
2349 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2350 filesystem checker on C<device>, noninteractively (C<-p>),
2351 even if the filesystem appears to be clean (C<-f>).
2353 This command is only needed because of C<guestfs_resize2fs>
2354 (q.v.). Normally you should use C<guestfs_fsck>.");
2356 ("sleep", (RErr, [Int "secs"]), 109, [],
2357 [InitNone, Always, TestRun (
2359 "sleep for some seconds",
2361 Sleep for C<secs> seconds.");
2363 ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [],
2364 [InitNone, Always, TestOutputInt (
2365 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2366 ["mkfs"; "ntfs"; "/dev/sda1"];
2367 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2368 InitNone, Always, TestOutputInt (
2369 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2370 ["mkfs"; "ext2"; "/dev/sda1"];
2371 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2372 "probe NTFS volume",
2374 This command runs the L<ntfs-3g.probe(8)> command which probes
2375 an NTFS C<device> for mountability. (Not all NTFS volumes can
2376 be mounted read-write, and some cannot be mounted at all).
2378 C<rw> is a boolean flag. Set it to true if you want to test
2379 if the volume can be mounted read-write. Set it to false if
2380 you want to test if the volume can be mounted read-only.
2382 The return value is an integer which C<0> if the operation
2383 would succeed, or some non-zero value documented in the
2384 L<ntfs-3g.probe(8)> manual page.");
2386 ("sh", (RString "output", [String "command"]), 111, [],
2387 [], (* XXX needs tests *)
2388 "run a command via the shell",
2390 This call runs a command from the guest filesystem via the
2393 This is like C<guestfs_command>, but passes the command to:
2395 /bin/sh -c \"command\"
2397 Depending on the guest's shell, this usually results in
2398 wildcards being expanded, shell expressions being interpolated
2401 All the provisos about C<guestfs_command> apply to this call.");
2403 ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2404 [], (* XXX needs tests *)
2405 "run a command via the shell returning lines",
2407 This is the same as C<guestfs_sh>, but splits the result
2408 into a list of lines.
2410 See also: C<guestfs_command_lines>");
2412 ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [],
2413 [InitBasicFS, Always, TestOutputList (
2414 [["mkdir_p"; "/a/b/c"];
2415 ["touch"; "/a/b/c/d"];
2416 ["touch"; "/a/b/c/e"];
2417 ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2418 InitBasicFS, Always, TestOutputList (
2419 [["mkdir_p"; "/a/b/c"];
2420 ["touch"; "/a/b/c/d"];
2421 ["touch"; "/a/b/c/e"];
2422 ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2423 InitBasicFS, Always, TestOutputList (
2424 [["mkdir_p"; "/a/b/c"];
2425 ["touch"; "/a/b/c/d"];
2426 ["touch"; "/a/b/c/e"];
2427 ["glob_expand"; "/a/*/x/*"]], [])],
2428 "expand a wildcard path",
2430 This command searches for all the pathnames matching
2431 C<pattern> according to the wildcard expansion rules
2434 If no paths match, then this returns an empty list
2435 (note: not an error).
2437 It is just a wrapper around the C L<glob(3)> function
2438 with flags C<GLOB_MARK|GLOB_BRACE>.
2439 See that manual page for more details.");
2441 ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson],
2442 [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2443 [["scrub_device"; "/dev/sdc"]])],
2444 "scrub (securely wipe) a device",
2446 This command writes patterns over C<device> to make data retrieval
2449 It is an interface to the L<scrub(1)> program. See that
2450 manual page for more details.");
2452 ("scrub_file", (RErr, [String "file"]), 115, [],
2453 [InitBasicFS, Always, TestRun (
2454 [["write_file"; "/file"; "content"; "0"];
2455 ["scrub_file"; "/file"]])],
2456 "scrub (securely wipe) a file",
2458 This command writes patterns over a file to make data retrieval
2461 The file is I<removed> after scrubbing.
2463 It is an interface to the L<scrub(1)> program. See that
2464 manual page for more details.");
2466 ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2467 [], (* XXX needs testing *)
2468 "scrub (securely wipe) free space",
2470 This command creates the directory C<dir> and then fills it
2471 with files until the filesystem is full, and scrubs the files
2472 as for C<guestfs_scrub_file>, and deletes them.
2473 The intention is to scrub any free space on the partition
2476 It is an interface to the L<scrub(1)> program. See that
2477 manual page for more details.");
2479 ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2480 [InitBasicFS, Always, TestRun (
2482 ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2483 "create a temporary directory",
2485 This command creates a temporary directory. The
2486 C<template> parameter should be a full pathname for the
2487 temporary directory name with the final six characters being
2490 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2491 the second one being suitable for Windows filesystems.
2493 The name of the temporary directory that was created
2496 The temporary directory is created with mode 0700
2497 and is owned by root.
2499 The caller is responsible for deleting the temporary
2500 directory and its contents after use.
2502 See also: L<mkdtemp(3)>");
2504 ("wc_l", (RInt "lines", [String "path"]), 118, [],
2505 [InitBasicFS, Always, TestOutputInt (
2506 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2507 ["wc_l"; "/10klines"]], 10000)],
2508 "count lines in a file",
2510 This command counts the lines in a file, using the
2511 C<wc -l> external command.");
2513 ("wc_w", (RInt "words", [String "path"]), 119, [],
2514 [InitBasicFS, Always, TestOutputInt (
2515 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2516 ["wc_w"; "/10klines"]], 10000)],
2517 "count words in a file",
2519 This command counts the words in a file, using the
2520 C<wc -w> external command.");
2522 ("wc_c", (RInt "chars", [String "path"]), 120, [],
2523 [InitBasicFS, Always, TestOutputInt (
2524 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2525 ["wc_c"; "/100kallspaces"]], 102400)],
2526 "count characters in a file",
2528 This command counts the characters in a file, using the
2529 C<wc -c> external command.");
2531 ("head", (RStringList "lines", [String "path"]), 121, [ProtocolLimitWarning],
2532 [InitBasicFS, Always, TestOutputList (
2533 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2534 ["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2535 "return first 10 lines of a file",
2537 This command returns up to the first 10 lines of a file as
2538 a list of strings.");
2540 ("head_n", (RStringList "lines", [Int "nrlines"; String "path"]), 122, [ProtocolLimitWarning],
2541 [InitBasicFS, Always, TestOutputList (
2542 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2543 ["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2544 InitBasicFS, Always, TestOutputList (
2545 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2546 ["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2547 InitBasicFS, Always, TestOutputList (
2548 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2549 ["head_n"; "0"; "/10klines"]], [])],
2550 "return first N lines of a file",
2552 If the parameter C<nrlines> is a positive number, this returns the first
2553 C<nrlines> lines of the file C<path>.
2555 If the parameter C<nrlines> is a negative number, this returns lines
2556 from the file C<path>, excluding the last C<nrlines> lines.
2558 If the parameter C<nrlines> is zero, this returns an empty list.");
2560 ("tail", (RStringList "lines", [String "path"]), 123, [ProtocolLimitWarning],
2561 [InitBasicFS, Always, TestOutputList (
2562 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2563 ["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2564 "return last 10 lines of a file",
2566 This command returns up to the last 10 lines of a file as
2567 a list of strings.");
2569 ("tail_n", (RStringList "lines", [Int "nrlines"; String "path"]), 124, [ProtocolLimitWarning],
2570 [InitBasicFS, Always, TestOutputList (
2571 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2572 ["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2573 InitBasicFS, Always, TestOutputList (
2574 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2575 ["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2576 InitBasicFS, Always, TestOutputList (
2577 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2578 ["tail_n"; "0"; "/10klines"]], [])],
2579 "return last N lines of a file",
2581 If the parameter C<nrlines> is a positive number, this returns the last
2582 C<nrlines> lines of the file C<path>.
2584 If the parameter C<nrlines> is a negative number, this returns lines
2585 from the file C<path>, starting with the C<-nrlines>th line.
2587 If the parameter C<nrlines> is zero, this returns an empty list.");
2589 ("df", (RString "output", []), 125, [],
2590 [], (* XXX Tricky to test because it depends on the exact format
2591 * of the 'df' command and other imponderables.
2593 "report file system disk space usage",
2595 This command runs the C<df> command to report disk space used.
2597 This command is mostly useful for interactive sessions. It
2598 is I<not> intended that you try to parse the output string.
2599 Use C<statvfs> from programs.");
2601 ("df_h", (RString "output", []), 126, [],
2602 [], (* XXX Tricky to test because it depends on the exact format
2603 * of the 'df' command and other imponderables.
2605 "report file system disk space usage (human readable)",
2607 This command runs the C<df -h> command to report disk space used
2608 in human-readable format.
2610 This command is mostly useful for interactive sessions. It
2611 is I<not> intended that you try to parse the output string.
2612 Use C<statvfs> from programs.");
2614 ("du", (RInt64 "sizekb", [String "path"]), 127, [],
2615 [InitBasicFS, Always, TestOutputInt (
2617 ["du"; "/p"]], 1 (* ie. 1 block, so depends on ext3 blocksize *))],
2618 "estimate file space usage",
2620 This command runs the C<du -s> command to estimate file space
2623 C<path> can be a file or a directory. If C<path> is a directory
2624 then the estimate includes the contents of the directory and all
2625 subdirectories (recursively).
2627 The result is the estimated size in I<kilobytes>
2628 (ie. units of 1024 bytes).");
2630 ("initrd_list", (RStringList "filenames", [String "path"]), 128, [],
2631 [InitBasicFS, Always, TestOutputList (
2632 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2633 ["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3"])],
2634 "list files in an initrd",
2636 This command lists out files contained in an initrd.
2638 The files are listed without any initial C</> character. The
2639 files are listed in the order they appear (not necessarily
2640 alphabetical). Directory names are listed as separate items.
2642 Old Linux kernels (2.4 and earlier) used a compressed ext2
2643 filesystem as initrd. We I<only> support the newer initramfs
2644 format (compressed cpio files).");
2646 ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
2648 "mount a file using the loop device",
2650 This command lets you mount C<file> (a filesystem image
2651 in a file) on a mount point. It is entirely equivalent to
2652 the command C<mount -o loop file mountpoint>.");
2654 ("mkswap", (RErr, [String "device"]), 130, [],
2655 [InitEmpty, Always, TestRun (
2656 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2657 ["mkswap"; "/dev/sda1"]])],
2658 "create a swap partition",
2660 Create a swap partition on C<device>.");
2662 ("mkswap_L", (RErr, [String "label"; String "device"]), 131, [],
2663 [InitEmpty, Always, TestRun (
2664 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2665 ["mkswap_L"; "hello"; "/dev/sda1"]])],
2666 "create a swap partition with a label",
2668 Create a swap partition on C<device> with label C<label>.");
2670 ("mkswap_U", (RErr, [String "uuid"; String "device"]), 132, [],
2671 [InitEmpty, Always, TestRun (
2672 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2673 ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
2674 "create a swap partition with an explicit UUID",
2676 Create a swap partition on C<device> with UUID C<uuid>.");
2678 ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 133, [],
2679 [InitBasicFS, Always, TestOutputStruct (
2680 [["mknod"; "0o10777"; "0"; "0"; "/node"];
2681 (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2682 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2683 InitBasicFS, Always, TestOutputStruct (
2684 [["mknod"; "0o60777"; "66"; "99"; "/node"];
2685 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2686 "make block, character or FIFO devices",
2688 This call creates block or character special devices, or
2689 named pipes (FIFOs).
2691 The C<mode> parameter should be the mode, using the standard
2692 constants. C<devmajor> and C<devminor> are the
2693 device major and minor numbers, only used when creating block
2694 and character special devices.");
2696 ("mkfifo", (RErr, [Int "mode"; String "path"]), 134, [],
2697 [InitBasicFS, Always, TestOutputStruct (
2698 [["mkfifo"; "0o777"; "/node"];
2699 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2700 "make FIFO (named pipe)",
2702 This call creates a FIFO (named pipe) called C<path> with
2703 mode C<mode>. It is just a convenient wrapper around
2704 C<guestfs_mknod>.");
2706 ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 135, [],
2707 [InitBasicFS, Always, TestOutputStruct (
2708 [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2709 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2710 "make block device node",
2712 This call creates a block device node called C<path> with
2713 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2714 It is just a convenient wrapper around C<guestfs_mknod>.");
2716 ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 136, [],
2717 [InitBasicFS, Always, TestOutputStruct (
2718 [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2719 ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2720 "make char device node",
2722 This call creates a char device node called C<path> with
2723 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2724 It is just a convenient wrapper around C<guestfs_mknod>.");
2726 ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2727 [], (* XXX umask is one of those stateful things that we should
2728 * reset between each test.
2730 "set file mode creation mask (umask)",
2732 This function sets the mask used for creating new files and
2733 device nodes to C<mask & 0777>.
2735 Typical umask values would be C<022> which creates new files
2736 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2737 C<002> which creates new files with permissions like
2738 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2740 The default umask is C<022>. This is important because it
2741 means that directories and device nodes will be created with
2742 C<0644> or C<0755> mode even if you specify C<0777>.
2744 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2746 This call returns the previous umask.");
2750 let all_functions = non_daemon_functions @ daemon_functions
2752 (* In some places we want the functions to be displayed sorted
2753 * alphabetically, so this is useful:
2755 let all_functions_sorted =
2756 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2757 compare n1 n2) all_functions
2759 (* Column names and types from LVM PVs/VGs/LVs. *)
2768 "pv_attr", `String (* XXX *);
2769 "pv_pe_count", `Int;
2770 "pv_pe_alloc_count", `Int;
2773 "pv_mda_count", `Int;
2774 "pv_mda_free", `Bytes;
2775 (* Not in Fedora 10:
2776 "pv_mda_size", `Bytes;
2783 "vg_attr", `String (* XXX *);
2786 "vg_sysid", `String;
2787 "vg_extent_size", `Bytes;
2788 "vg_extent_count", `Int;
2789 "vg_free_count", `Int;
2797 "vg_mda_count", `Int;
2798 "vg_mda_free", `Bytes;
2799 (* Not in Fedora 10:
2800 "vg_mda_size", `Bytes;
2806 "lv_attr", `String (* XXX *);
2809 "lv_kernel_major", `Int;
2810 "lv_kernel_minor", `Int;
2814 "snap_percent", `OptPercent;
2815 "copy_percent", `OptPercent;
2818 "mirror_log", `String;
2822 (* Column names and types from stat structures.
2823 * NB. Can't use things like 'st_atime' because glibc header files
2824 * define some of these as macros. Ugh.
2841 let statvfs_cols = [
2855 (* Used for testing language bindings. *)
2857 | CallString of string
2858 | CallOptString of string option
2859 | CallStringList of string list
2863 (* Useful functions.
2864 * Note we don't want to use any external OCaml libraries which
2865 * makes this a bit harder than it should be.
2867 let failwithf fs = ksprintf failwith fs
2869 let replace_char s c1 c2 =
2870 let s2 = String.copy s in
2871 let r = ref false in
2872 for i = 0 to String.length s2 - 1 do
2873 if String.unsafe_get s2 i = c1 then (
2874 String.unsafe_set s2 i c2;
2878 if not !r then s else s2
2882 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2884 let triml ?(test = isspace) str =
2886 let n = ref (String.length str) in
2887 while !n > 0 && test str.[!i]; do
2892 else String.sub str !i !n
2894 let trimr ?(test = isspace) str =
2895 let n = ref (String.length str) in
2896 while !n > 0 && test str.[!n-1]; do
2899 if !n = String.length str then str
2900 else String.sub str 0 !n
2902 let trim ?(test = isspace) str =
2903 trimr ~test (triml ~test str)
2905 let rec find s sub =
2906 let len = String.length s in
2907 let sublen = String.length sub in
2909 if i <= len-sublen then (
2911 if j < sublen then (
2912 if s.[i+j] = sub.[j] then loop2 (j+1)
2918 if r = -1 then loop (i+1) else r
2924 let rec replace_str s s1 s2 =
2925 let len = String.length s in
2926 let sublen = String.length s1 in
2927 let i = find s s1 in
2930 let s' = String.sub s 0 i in
2931 let s'' = String.sub s (i+sublen) (len-i-sublen) in
2932 s' ^ s2 ^ replace_str s'' s1 s2
2935 let rec string_split sep str =
2936 let len = String.length str in
2937 let seplen = String.length sep in
2938 let i = find str sep in
2939 if i = -1 then [str]
2941 let s' = String.sub str 0 i in
2942 let s'' = String.sub str (i+seplen) (len-i-seplen) in
2943 s' :: string_split sep s''
2946 let files_equal n1 n2 =
2947 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
2948 match Sys.command cmd with
2951 | i -> failwithf "%s: failed with error code %d" cmd i
2953 let rec find_map f = function
2954 | [] -> raise Not_found
2958 | None -> find_map f xs
2961 let rec loop i = function
2963 | x :: xs -> f i x; loop (i+1) xs
2968 let rec loop i = function
2970 | x :: xs -> let r = f i x in r :: loop (i+1) xs
2974 let name_of_argt = function
2975 | String n | OptString n | StringList n | Bool n | Int n
2976 | FileIn n | FileOut n -> n
2978 let seq_of_test = function
2979 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
2980 | TestOutputListOfDevices (s, _)
2981 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
2982 | TestOutputLength (s, _) | TestOutputStruct (s, _)
2983 | TestLastFail s -> s
2985 (* Check function names etc. for consistency. *)
2986 let check_functions () =
2987 let contains_uppercase str =
2988 let len = String.length str in
2990 if i >= len then false
2993 if c >= 'A' && c <= 'Z' then true
3000 (* Check function names. *)
3002 fun (name, _, _, _, _, _, _) ->
3003 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
3004 failwithf "function name %s does not need 'guestfs' prefix" name;
3006 failwithf "function name is empty";
3007 if name.[0] < 'a' || name.[0] > 'z' then
3008 failwithf "function name %s must start with lowercase a-z" name;
3009 if String.contains name '-' then
3010 failwithf "function name %s should not contain '-', use '_' instead."
3014 (* Check function parameter/return names. *)
3016 fun (name, style, _, _, _, _, _) ->
3017 let check_arg_ret_name n =
3018 if contains_uppercase n then
3019 failwithf "%s param/ret %s should not contain uppercase chars"
3021 if String.contains n '-' || String.contains n '_' then
3022 failwithf "%s param/ret %s should not contain '-' or '_'"
3025 failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" name;
3026 if n = "int" || n = "char" || n = "short" || n = "long" then
3027 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
3028 if n = "i" || n = "n" then
3029 failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
3030 if n = "argv" || n = "args" then
3031 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
3034 (match fst style with
3036 | RInt n | RInt64 n | RBool n | RConstString n | RString n
3037 | RStringList n | RPVList n | RVGList n | RLVList n
3038 | RStat n | RStatVFS n
3040 check_arg_ret_name n
3042 check_arg_ret_name n;
3043 check_arg_ret_name m
3045 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
3048 (* Check short descriptions. *)
3050 fun (name, _, _, _, _, shortdesc, _) ->
3051 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
3052 failwithf "short description of %s should begin with lowercase." name;
3053 let c = shortdesc.[String.length shortdesc-1] in
3054 if c = '\n' || c = '.' then
3055 failwithf "short description of %s should not end with . or \\n." name
3058 (* Check long dscriptions. *)
3060 fun (name, _, _, _, _, _, longdesc) ->
3061 if longdesc.[String.length longdesc-1] = '\n' then
3062 failwithf "long description of %s should not end with \\n." name
3065 (* Check proc_nrs. *)
3067 fun (name, _, proc_nr, _, _, _, _) ->
3068 if proc_nr <= 0 then
3069 failwithf "daemon function %s should have proc_nr > 0" name
3073 fun (name, _, proc_nr, _, _, _, _) ->
3074 if proc_nr <> -1 then
3075 failwithf "non-daemon function %s should have proc_nr -1" name
3076 ) non_daemon_functions;
3079 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
3082 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
3083 let rec loop = function
3086 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
3088 | (name1,nr1) :: (name2,nr2) :: _ ->
3089 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
3097 (* Ignore functions that have no tests. We generate a
3098 * warning when the user does 'make check' instead.
3100 | name, _, _, _, [], _, _ -> ()
3101 | name, _, _, _, tests, _, _ ->
3105 match seq_of_test test with
3107 failwithf "%s has a test containing an empty sequence" name
3108 | cmds -> List.map List.hd cmds
3110 let funcs = List.flatten funcs in
3112 let tested = List.mem name funcs in
3115 failwithf "function %s has tests but does not test itself" name
3118 (* 'pr' prints to the current output file. *)
3119 let chan = ref stdout
3120 let pr fs = ksprintf (output_string !chan) fs
3122 (* Generate a header block in a number of standard styles. *)
3123 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
3124 type license = GPLv2 | LGPLv2
3126 let generate_header comment license =
3127 let c = match comment with
3128 | CStyle -> pr "/* "; " *"
3129 | HashStyle -> pr "# "; "#"
3130 | OCamlStyle -> pr "(* "; " *"
3131 | HaskellStyle -> pr "{- "; " " in
3132 pr "libguestfs generated file\n";
3133 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
3134 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
3136 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
3140 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
3141 pr "%s it under the terms of the GNU General Public License as published by\n" c;
3142 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
3143 pr "%s (at your option) any later version.\n" c;
3145 pr "%s This program is distributed in the hope that it will be useful,\n" c;
3146 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3147 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
3148 pr "%s GNU General Public License for more details.\n" c;
3150 pr "%s You should have received a copy of the GNU General Public License along\n" c;
3151 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
3152 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
3155 pr "%s This library is free software; you can redistribute it and/or\n" c;
3156 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
3157 pr "%s License as published by the Free Software Foundation; either\n" c;
3158 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
3160 pr "%s This library is distributed in the hope that it will be useful,\n" c;
3161 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3162 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
3163 pr "%s Lesser General Public License for more details.\n" c;
3165 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
3166 pr "%s License along with this library; if not, write to the Free Software\n" c;
3167 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
3170 | CStyle -> pr " */\n"
3172 | OCamlStyle -> pr " *)\n"
3173 | HaskellStyle -> pr "-}\n"
3177 (* Start of main code generation functions below this line. *)
3179 (* Generate the pod documentation for the C API. *)
3180 let rec generate_actions_pod () =
3182 fun (shortname, style, _, flags, _, _, longdesc) ->
3183 if not (List.mem NotInDocs flags) then (
3184 let name = "guestfs_" ^ shortname in
3185 pr "=head2 %s\n\n" name;
3187 generate_prototype ~extern:false ~handle:"handle" name style;
3189 pr "%s\n\n" longdesc;
3190 (match fst style with
3192 pr "This function returns 0 on success or -1 on error.\n\n"
3194 pr "On error this function returns -1.\n\n"
3196 pr "On error this function returns -1.\n\n"
3198 pr "This function returns a C truth value on success or -1 on error.\n\n"
3200 pr "This function returns a string, or NULL on error.
3201 The string is owned by the guest handle and must I<not> be freed.\n\n"
3203 pr "This function returns a string, or NULL on error.
3204 I<The caller must free the returned string after use>.\n\n"
3206 pr "This function returns a NULL-terminated array of strings
3207 (like L<environ(3)>), or NULL if there was an error.
3208 I<The caller must free the strings and the array after use>.\n\n"
3210 pr "This function returns a C<struct guestfs_int_bool *>,
3211 or NULL if there was an error.
3212 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
3214 pr "This function returns a C<struct guestfs_lvm_pv_list *>
3215 (see E<lt>guestfs-structs.hE<gt>),
3216 or NULL if there was an error.
3217 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
3219 pr "This function returns a C<struct guestfs_lvm_vg_list *>
3220 (see E<lt>guestfs-structs.hE<gt>),
3221 or NULL if there was an error.
3222 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
3224 pr "This function returns a C<struct guestfs_lvm_lv_list *>
3225 (see E<lt>guestfs-structs.hE<gt>),
3226 or NULL if there was an error.
3227 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
3229 pr "This function returns a C<struct guestfs_stat *>
3230 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
3231 or NULL if there was an error.
3232 I<The caller must call C<free> after use>.\n\n"
3234 pr "This function returns a C<struct guestfs_statvfs *>
3235 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
3236 or NULL if there was an error.
3237 I<The caller must call C<free> after use>.\n\n"
3239 pr "This function returns a NULL-terminated array of
3240 strings, or NULL if there was an error.
3241 The array of strings will always have length C<2n+1>, where
3242 C<n> keys and values alternate, followed by the trailing NULL entry.
3243 I<The caller must free the strings and the array after use>.\n\n"
3245 if List.mem ProtocolLimitWarning flags then
3246 pr "%s\n\n" protocol_limit_warning;
3247 if List.mem DangerWillRobinson flags then
3248 pr "%s\n\n" danger_will_robinson
3250 ) all_functions_sorted
3252 and generate_structs_pod () =
3253 (* LVM structs documentation. *)
3256 pr "=head2 guestfs_lvm_%s\n" typ;
3258 pr " struct guestfs_lvm_%s {\n" typ;
3261 | name, `String -> pr " char *%s;\n" name
3263 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
3264 pr " char %s[32];\n" name
3265 | name, `Bytes -> pr " uint64_t %s;\n" name
3266 | name, `Int -> pr " int64_t %s;\n" name
3267 | name, `OptPercent ->
3268 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
3269 pr " float %s;\n" name
3272 pr " struct guestfs_lvm_%s_list {\n" typ;
3273 pr " uint32_t len; /* Number of elements in list. */\n";
3274 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
3277 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
3280 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3282 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3283 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3285 * We have to use an underscore instead of a dash because otherwise
3286 * rpcgen generates incorrect code.
3288 * This header is NOT exported to clients, but see also generate_structs_h.
3290 and generate_xdr () =
3291 generate_header CStyle LGPLv2;
3293 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3294 pr "typedef string str<>;\n";
3297 (* LVM internal structures. *)
3301 pr "struct guestfs_lvm_int_%s {\n" typ;
3303 | name, `String -> pr " string %s<>;\n" name
3304 | name, `UUID -> pr " opaque %s[32];\n" name
3305 | name, `Bytes -> pr " hyper %s;\n" name
3306 | name, `Int -> pr " hyper %s;\n" name
3307 | name, `OptPercent -> pr " float %s;\n" name
3311 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
3313 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3315 (* Stat internal structures. *)
3319 pr "struct guestfs_int_%s {\n" typ;
3321 | name, `Int -> pr " hyper %s;\n" name
3325 ) ["stat", stat_cols; "statvfs", statvfs_cols];
3328 fun (shortname, style, _, _, _, _, _) ->
3329 let name = "guestfs_" ^ shortname in
3331 (match snd style with
3334 pr "struct %s_args {\n" name;
3337 | String n -> pr " string %s<>;\n" n
3338 | OptString n -> pr " str *%s;\n" n
3339 | StringList n -> pr " str %s<>;\n" n
3340 | Bool n -> pr " bool %s;\n" n
3341 | Int n -> pr " int %s;\n" n
3342 | FileIn _ | FileOut _ -> ()
3346 (match fst style with
3349 pr "struct %s_ret {\n" name;
3353 pr "struct %s_ret {\n" name;
3354 pr " hyper %s;\n" n;
3357 pr "struct %s_ret {\n" name;
3361 failwithf "RConstString cannot be returned from a daemon function"
3363 pr "struct %s_ret {\n" name;
3364 pr " string %s<>;\n" n;
3367 pr "struct %s_ret {\n" name;
3368 pr " str %s<>;\n" n;
3371 pr "struct %s_ret {\n" name;
3376 pr "struct %s_ret {\n" name;
3377 pr " guestfs_lvm_int_pv_list %s;\n" n;
3380 pr "struct %s_ret {\n" name;
3381 pr " guestfs_lvm_int_vg_list %s;\n" n;
3384 pr "struct %s_ret {\n" name;
3385 pr " guestfs_lvm_int_lv_list %s;\n" n;
3388 pr "struct %s_ret {\n" name;
3389 pr " guestfs_int_stat %s;\n" n;
3392 pr "struct %s_ret {\n" name;
3393 pr " guestfs_int_statvfs %s;\n" n;
3396 pr "struct %s_ret {\n" name;
3397 pr " str %s<>;\n" n;
3402 (* Table of procedure numbers. *)
3403 pr "enum guestfs_procedure {\n";
3405 fun (shortname, _, proc_nr, _, _, _, _) ->
3406 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3408 pr " GUESTFS_PROC_NR_PROCS\n";
3412 (* Having to choose a maximum message size is annoying for several
3413 * reasons (it limits what we can do in the API), but it (a) makes
3414 * the protocol a lot simpler, and (b) provides a bound on the size
3415 * of the daemon which operates in limited memory space. For large
3416 * file transfers you should use FTP.
3418 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3421 (* Message header, etc. *)
3423 /* The communication protocol is now documented in the guestfs(3)
3427 const GUESTFS_PROGRAM = 0x2000F5F5;
3428 const GUESTFS_PROTOCOL_VERSION = 1;
3430 /* These constants must be larger than any possible message length. */
3431 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3432 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3434 enum guestfs_message_direction {
3435 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
3436 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
3439 enum guestfs_message_status {
3440 GUESTFS_STATUS_OK = 0,
3441 GUESTFS_STATUS_ERROR = 1
3444 const GUESTFS_ERROR_LEN = 256;
3446 struct guestfs_message_error {
3447 string error_message<GUESTFS_ERROR_LEN>;
3450 struct guestfs_message_header {
3451 unsigned prog; /* GUESTFS_PROGRAM */
3452 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
3453 guestfs_procedure proc; /* GUESTFS_PROC_x */
3454 guestfs_message_direction direction;
3455 unsigned serial; /* message serial number */
3456 guestfs_message_status status;
3459 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3461 struct guestfs_chunk {
3462 int cancel; /* if non-zero, transfer is cancelled */
3463 /* data size is 0 bytes if the transfer has finished successfully */
3464 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3468 (* Generate the guestfs-structs.h file. *)
3469 and generate_structs_h () =
3470 generate_header CStyle LGPLv2;
3472 (* This is a public exported header file containing various
3473 * structures. The structures are carefully written to have
3474 * exactly the same in-memory format as the XDR structures that
3475 * we use on the wire to the daemon. The reason for creating
3476 * copies of these structures here is just so we don't have to
3477 * export the whole of guestfs_protocol.h (which includes much
3478 * unrelated and XDR-dependent stuff that we don't want to be
3479 * public, or required by clients).
3481 * To reiterate, we will pass these structures to and from the
3482 * client with a simple assignment or memcpy, so the format
3483 * must be identical to what rpcgen / the RFC defines.
3486 (* guestfs_int_bool structure. *)
3487 pr "struct guestfs_int_bool {\n";
3493 (* LVM public structures. *)
3497 pr "struct guestfs_lvm_%s {\n" typ;
3500 | name, `String -> pr " char *%s;\n" name
3501 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3502 | name, `Bytes -> pr " uint64_t %s;\n" name
3503 | name, `Int -> pr " int64_t %s;\n" name
3504 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
3508 pr "struct guestfs_lvm_%s_list {\n" typ;
3509 pr " uint32_t len;\n";
3510 pr " struct guestfs_lvm_%s *val;\n" typ;
3513 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3515 (* Stat structures. *)
3519 pr "struct guestfs_%s {\n" typ;
3522 | name, `Int -> pr " int64_t %s;\n" name
3526 ) ["stat", stat_cols; "statvfs", statvfs_cols]
3528 (* Generate the guestfs-actions.h file. *)
3529 and generate_actions_h () =
3530 generate_header CStyle LGPLv2;
3532 fun (shortname, style, _, _, _, _, _) ->
3533 let name = "guestfs_" ^ shortname in
3534 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3538 (* Generate the client-side dispatch stubs. *)
3539 and generate_client_actions () =
3540 generate_header CStyle LGPLv2;
3546 #include \"guestfs.h\"
3547 #include \"guestfs_protocol.h\"
3549 #define error guestfs_error
3550 #define perrorf guestfs_perrorf
3551 #define safe_malloc guestfs_safe_malloc
3552 #define safe_realloc guestfs_safe_realloc
3553 #define safe_strdup guestfs_safe_strdup
3554 #define safe_memdup guestfs_safe_memdup
3556 /* Check the return message from a call for validity. */
3558 check_reply_header (guestfs_h *g,
3559 const struct guestfs_message_header *hdr,
3560 int proc_nr, int serial)
3562 if (hdr->prog != GUESTFS_PROGRAM) {
3563 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3566 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3567 error (g, \"wrong protocol version (%%d/%%d)\",
3568 hdr->vers, GUESTFS_PROTOCOL_VERSION);
3571 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3572 error (g, \"unexpected message direction (%%d/%%d)\",
3573 hdr->direction, GUESTFS_DIRECTION_REPLY);
3576 if (hdr->proc != proc_nr) {
3577 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3580 if (hdr->serial != serial) {
3581 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3588 /* Check we are in the right state to run a high-level action. */
3590 check_state (guestfs_h *g, const char *caller)
3592 if (!guestfs_is_ready (g)) {
3593 if (guestfs_is_config (g))
3594 error (g, \"%%s: call launch() before using this function\",
3596 else if (guestfs_is_launching (g))
3597 error (g, \"%%s: call wait_ready() before using this function\",
3600 error (g, \"%%s called from the wrong state, %%d != READY\",
3601 caller, guestfs_get_state (g));
3609 (* Client-side stubs for each function. *)
3611 fun (shortname, style, _, _, _, _, _) ->
3612 let name = "guestfs_" ^ shortname in
3614 (* Generate the context struct which stores the high-level
3615 * state between callback functions.
3617 pr "struct %s_ctx {\n" shortname;
3618 pr " /* This flag is set by the callbacks, so we know we've done\n";
3619 pr " * the callbacks as expected, and in the right sequence.\n";
3620 pr " * 0 = not called, 1 = reply_cb called.\n";
3622 pr " int cb_sequence;\n";
3623 pr " struct guestfs_message_header hdr;\n";
3624 pr " struct guestfs_message_error err;\n";
3625 (match fst style with
3628 failwithf "RConstString cannot be returned from a daemon function"
3630 | RBool _ | RString _ | RStringList _
3632 | RPVList _ | RVGList _ | RLVList _
3633 | RStat _ | RStatVFS _
3635 pr " struct %s_ret ret;\n" name
3640 (* Generate the reply callback function. *)
3641 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3643 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3644 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3646 pr " /* This should definitely not happen. */\n";
3647 pr " if (ctx->cb_sequence != 0) {\n";
3648 pr " ctx->cb_sequence = 9999;\n";
3649 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3653 pr " ml->main_loop_quit (ml, g);\n";
3655 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3656 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3659 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3660 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3661 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3668 (match fst style with
3671 failwithf "RConstString cannot be returned from a daemon function"
3673 | RBool _ | RString _ | RStringList _
3675 | RPVList _ | RVGList _ | RLVList _
3676 | RStat _ | RStatVFS _
3678 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3679 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3685 pr " ctx->cb_sequence = 1;\n";
3688 (* Generate the action stub. *)
3689 generate_prototype ~extern:false ~semicolon:false ~newline:true
3690 ~handle:"g" name style;
3693 match fst style with
3694 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3696 failwithf "RConstString cannot be returned from a daemon function"
3697 | RString _ | RStringList _ | RIntBool _
3698 | RPVList _ | RVGList _ | RLVList _
3699 | RStat _ | RStatVFS _
3705 (match snd style with
3707 | _ -> pr " struct %s_args args;\n" name
3710 pr " struct %s_ctx ctx;\n" shortname;
3711 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3712 pr " int serial;\n";
3714 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3715 pr " guestfs_set_busy (g);\n";
3717 pr " memset (&ctx, 0, sizeof ctx);\n";
3720 (* Send the main header and arguments. *)
3721 (match snd style with
3723 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3724 (String.uppercase shortname)
3729 pr " args.%s = (char *) %s;\n" n n
3731 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
3733 pr " args.%s.%s_val = (char **) %s;\n" n n n;
3734 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3736 pr " args.%s = %s;\n" n n
3738 pr " args.%s = %s;\n" n n
3739 | FileIn _ | FileOut _ -> ()
3741 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3742 (String.uppercase shortname);
3743 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3746 pr " if (serial == -1) {\n";
3747 pr " guestfs_end_busy (g);\n";
3748 pr " return %s;\n" error_code;
3752 (* Send any additional files (FileIn) requested. *)
3753 let need_read_reply_label = ref false in
3760 pr " r = guestfs__send_file_sync (g, %s);\n" n;
3761 pr " if (r == -1) {\n";
3762 pr " guestfs_end_busy (g);\n";
3763 pr " return %s;\n" error_code;
3765 pr " if (r == -2) /* daemon cancelled */\n";
3766 pr " goto read_reply;\n";
3767 need_read_reply_label := true;
3773 (* Wait for the reply from the remote end. *)
3774 if !need_read_reply_label then pr " read_reply:\n";
3775 pr " guestfs__switch_to_receiving (g);\n";
3776 pr " ctx.cb_sequence = 0;\n";
3777 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3778 pr " (void) ml->main_loop_run (ml, g);\n";
3779 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
3780 pr " if (ctx.cb_sequence != 1) {\n";
3781 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3782 pr " guestfs_end_busy (g);\n";
3783 pr " return %s;\n" error_code;
3787 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3788 (String.uppercase shortname);
3789 pr " guestfs_end_busy (g);\n";
3790 pr " return %s;\n" error_code;
3794 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3795 pr " error (g, \"%%s\", ctx.err.error_message);\n";
3796 pr " free (ctx.err.error_message);\n";
3797 pr " guestfs_end_busy (g);\n";
3798 pr " return %s;\n" error_code;
3802 (* Expecting to receive further files (FileOut)? *)
3806 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3807 pr " guestfs_end_busy (g);\n";
3808 pr " return %s;\n" error_code;
3814 pr " guestfs_end_busy (g);\n";
3816 (match fst style with
3817 | RErr -> pr " return 0;\n"
3818 | RInt n | RInt64 n | RBool n ->
3819 pr " return ctx.ret.%s;\n" n
3821 failwithf "RConstString cannot be returned from a daemon function"
3823 pr " return ctx.ret.%s; /* caller will free */\n" n
3824 | RStringList n | RHashtable n ->
3825 pr " /* caller will free this, but we need to add a NULL entry */\n";
3826 pr " ctx.ret.%s.%s_val =\n" n n;
3827 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3828 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3830 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3831 pr " return ctx.ret.%s.%s_val;\n" n n
3833 pr " /* caller with free this */\n";
3834 pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3835 | RPVList n | RVGList n | RLVList n
3836 | RStat n | RStatVFS n ->
3837 pr " /* caller will free this */\n";
3838 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3844 (* Generate daemon/actions.h. *)
3845 and generate_daemon_actions_h () =
3846 generate_header CStyle GPLv2;
3848 pr "#include \"../src/guestfs_protocol.h\"\n";
3852 fun (name, style, _, _, _, _, _) ->
3854 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3858 (* Generate the server-side stubs. *)
3859 and generate_daemon_actions () =
3860 generate_header CStyle GPLv2;
3862 pr "#include <config.h>\n";
3864 pr "#include <stdio.h>\n";
3865 pr "#include <stdlib.h>\n";
3866 pr "#include <string.h>\n";
3867 pr "#include <inttypes.h>\n";
3868 pr "#include <ctype.h>\n";
3869 pr "#include <rpc/types.h>\n";
3870 pr "#include <rpc/xdr.h>\n";
3872 pr "#include \"daemon.h\"\n";
3873 pr "#include \"../src/guestfs_protocol.h\"\n";
3874 pr "#include \"actions.h\"\n";
3878 fun (name, style, _, _, _, _, _) ->
3879 (* Generate server-side stubs. *)
3880 pr "static void %s_stub (XDR *xdr_in)\n" name;
3883 match fst style with
3884 | RErr | RInt _ -> pr " int r;\n"; "-1"
3885 | RInt64 _ -> pr " int64_t r;\n"; "-1"
3886 | RBool _ -> pr " int r;\n"; "-1"
3888 failwithf "RConstString cannot be returned from a daemon function"
3889 | RString _ -> pr " char *r;\n"; "NULL"
3890 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
3891 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
3892 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
3893 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
3894 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
3895 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
3896 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
3898 (match snd style with
3901 pr " struct guestfs_%s_args args;\n" name;
3904 (* Note we allow the string to be writable, in order to
3905 * allow device name translation. This is safe because
3906 * we can modify the string (passed from RPC).
3909 | OptString n -> pr " char *%s;\n" n
3910 | StringList n -> pr " char **%s;\n" n
3911 | Bool n -> pr " int %s;\n" n
3912 | Int n -> pr " int %s;\n" n
3913 | FileIn _ | FileOut _ -> ()
3918 (match snd style with
3921 pr " memset (&args, 0, sizeof args);\n";
3923 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
3924 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
3929 | String n -> pr " %s = args.%s;\n" n n
3930 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
3932 pr " %s = realloc (args.%s.%s_val,\n" n n n;
3933 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
3934 pr " if (%s == NULL) {\n" n;
3935 pr " reply_with_perror (\"realloc\");\n";
3938 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
3939 pr " args.%s.%s_val = %s;\n" n n n;
3940 | Bool n -> pr " %s = args.%s;\n" n n
3941 | Int n -> pr " %s = args.%s;\n" n n
3942 | FileIn _ | FileOut _ -> ()
3947 (* Don't want to call the impl with any FileIn or FileOut
3948 * parameters, since these go "outside" the RPC protocol.
3951 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
3953 pr " r = do_%s " name;
3954 generate_call_args argsnofile;
3957 pr " if (r == %s)\n" error_code;
3958 pr " /* do_%s has already called reply_with_error */\n" name;
3962 (* If there are any FileOut parameters, then the impl must
3963 * send its own reply.
3966 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
3968 pr " /* do_%s has already sent a reply */\n" name
3970 match fst style with
3971 | RErr -> pr " reply (NULL, NULL);\n"
3972 | RInt n | RInt64 n | RBool n ->
3973 pr " struct guestfs_%s_ret ret;\n" name;
3974 pr " ret.%s = r;\n" n;
3975 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3978 failwithf "RConstString cannot be returned from a daemon function"
3980 pr " struct guestfs_%s_ret ret;\n" name;
3981 pr " ret.%s = r;\n" n;
3982 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3985 | RStringList n | RHashtable n ->
3986 pr " struct guestfs_%s_ret ret;\n" name;
3987 pr " ret.%s.%s_len = count_strings (r);\n" n n;
3988 pr " ret.%s.%s_val = r;\n" n n;
3989 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3991 pr " free_strings (r);\n"
3993 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
3995 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
3996 | RPVList n | RVGList n | RLVList n
3997 | RStat n | RStatVFS n ->
3998 pr " struct guestfs_%s_ret ret;\n" name;
3999 pr " ret.%s = *r;\n" n;
4000 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4002 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4006 (* Free the args. *)
4007 (match snd style with
4012 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4019 (* Dispatch function. *)
4020 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4022 pr " switch (proc_nr) {\n";
4025 fun (name, style, _, _, _, _, _) ->
4026 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
4027 pr " %s_stub (xdr_in);\n" name;
4032 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d, set LIBGUESTFS_PATH to point to the matching libguestfs appliance directory\", proc_nr);\n";
4037 (* LVM columns and tokenization functions. *)
4038 (* XXX This generates crap code. We should rethink how we
4044 pr "static const char *lvm_%s_cols = \"%s\";\n"
4045 typ (String.concat "," (List.map fst cols));
4048 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
4050 pr " char *tok, *p, *next;\n";
4054 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4057 pr " if (!str) {\n";
4058 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4061 pr " if (!*str || isspace (*str)) {\n";
4062 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4067 fun (name, coltype) ->
4068 pr " if (!tok) {\n";
4069 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4072 pr " p = strchrnul (tok, ',');\n";
4073 pr " if (*p) next = p+1; else next = NULL;\n";
4074 pr " *p = '\\0';\n";
4077 pr " r->%s = strdup (tok);\n" name;
4078 pr " if (r->%s == NULL) {\n" name;
4079 pr " perror (\"strdup\");\n";
4083 pr " for (i = j = 0; i < 32; ++j) {\n";
4084 pr " if (tok[j] == '\\0') {\n";
4085 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4087 pr " } else if (tok[j] != '-')\n";
4088 pr " r->%s[i++] = tok[j];\n" name;
4091 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4092 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4096 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4097 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4101 pr " if (tok[0] == '\\0')\n";
4102 pr " r->%s = -1;\n" name;
4103 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4104 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4108 pr " tok = next;\n";
4111 pr " if (tok != NULL) {\n";
4112 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4119 pr "guestfs_lvm_int_%s_list *\n" typ;
4120 pr "parse_command_line_%ss (void)\n" typ;
4122 pr " char *out, *err;\n";
4123 pr " char *p, *pend;\n";
4125 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
4126 pr " void *newp;\n";
4128 pr " ret = malloc (sizeof *ret);\n";
4129 pr " if (!ret) {\n";
4130 pr " reply_with_perror (\"malloc\");\n";
4131 pr " return NULL;\n";
4134 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
4135 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
4137 pr " r = command (&out, &err,\n";
4138 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
4139 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4140 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4141 pr " if (r == -1) {\n";
4142 pr " reply_with_error (\"%%s\", err);\n";
4143 pr " free (out);\n";
4144 pr " free (err);\n";
4145 pr " free (ret);\n";
4146 pr " return NULL;\n";
4149 pr " free (err);\n";
4151 pr " /* Tokenize each line of the output. */\n";
4154 pr " while (p) {\n";
4155 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
4156 pr " if (pend) {\n";
4157 pr " *pend = '\\0';\n";
4161 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
4164 pr " if (!*p) { /* Empty line? Skip it. */\n";
4169 pr " /* Allocate some space to store this next entry. */\n";
4170 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
4171 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
4172 pr " if (newp == NULL) {\n";
4173 pr " reply_with_perror (\"realloc\");\n";
4174 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
4175 pr " free (ret);\n";
4176 pr " free (out);\n";
4177 pr " return NULL;\n";
4179 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
4181 pr " /* Tokenize the next entry. */\n";
4182 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
4183 pr " if (r == -1) {\n";
4184 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
4185 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
4186 pr " free (ret);\n";
4187 pr " free (out);\n";
4188 pr " return NULL;\n";
4195 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
4197 pr " free (out);\n";
4198 pr " return ret;\n";
4201 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4203 (* Generate the tests. *)
4204 and generate_tests () =
4205 generate_header CStyle GPLv2;
4212 #include <sys/types.h>
4215 #include \"guestfs.h\"
4217 static guestfs_h *g;
4218 static int suppress_error = 0;
4220 static void print_error (guestfs_h *g, void *data, const char *msg)
4222 if (!suppress_error)
4223 fprintf (stderr, \"%%s\\n\", msg);
4226 static void print_strings (char * const * const argv)
4230 for (argc = 0; argv[argc] != NULL; ++argc)
4231 printf (\"\\t%%s\\n\", argv[argc]);
4235 static void print_table (char * const * const argv)
4239 for (i = 0; argv[i] != NULL; i += 2)
4240 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
4244 static void no_test_warnings (void)
4250 | name, _, _, _, [], _, _ ->
4251 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
4252 | name, _, _, _, tests, _, _ -> ()
4258 (* Generate the actual tests. Note that we generate the tests
4259 * in reverse order, deliberately, so that (in general) the
4260 * newest tests run first. This makes it quicker and easier to
4265 fun (name, _, _, _, tests, _, _) ->
4266 mapi (generate_one_test name) tests
4267 ) (List.rev all_functions) in
4268 let test_names = List.concat test_names in
4269 let nr_tests = List.length test_names in
4272 int main (int argc, char *argv[])
4276 const char *filename;
4278 int nr_tests, test_num = 0;
4280 setbuf (stdout, NULL);
4282 no_test_warnings ();
4284 g = guestfs_create ();
4286 printf (\"guestfs_create FAILED\\n\");
4290 guestfs_set_error_handler (g, print_error, NULL);
4292 guestfs_set_path (g, \"../appliance\");
4294 filename = \"test1.img\";
4295 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4300 if (lseek (fd, %d, SEEK_SET) == -1) {
4306 if (write (fd, &c, 1) == -1) {
4312 if (close (fd) == -1) {
4317 if (guestfs_add_drive (g, filename) == -1) {
4318 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4322 filename = \"test2.img\";
4323 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4328 if (lseek (fd, %d, SEEK_SET) == -1) {
4334 if (write (fd, &c, 1) == -1) {
4340 if (close (fd) == -1) {
4345 if (guestfs_add_drive (g, filename) == -1) {
4346 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4350 filename = \"test3.img\";
4351 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4356 if (lseek (fd, %d, SEEK_SET) == -1) {
4362 if (write (fd, &c, 1) == -1) {
4368 if (close (fd) == -1) {
4373 if (guestfs_add_drive (g, filename) == -1) {
4374 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4378 if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4379 printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4383 if (guestfs_launch (g) == -1) {
4384 printf (\"guestfs_launch FAILED\\n\");
4388 /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4391 if (guestfs_wait_ready (g) == -1) {
4392 printf (\"guestfs_wait_ready FAILED\\n\");
4396 /* Cancel previous alarm. */
4401 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4405 pr " test_num++;\n";
4406 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4407 pr " if (%s () == -1) {\n" test_name;
4408 pr " printf (\"%s FAILED\\n\");\n" test_name;
4414 pr " guestfs_close (g);\n";
4415 pr " unlink (\"test1.img\");\n";
4416 pr " unlink (\"test2.img\");\n";
4417 pr " unlink (\"test3.img\");\n";
4420 pr " if (failed > 0) {\n";
4421 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4429 and generate_one_test name i (init, prereq, test) =
4430 let test_name = sprintf "test_%s_%d" name i in
4433 static int %s_skip (void)
4437 str = getenv (\"TEST_ONLY\");
4439 return strstr (str, \"%s\") == NULL;
4440 str = getenv (\"SKIP_%s\");
4441 if (str && strcmp (str, \"1\") == 0) return 1;
4442 str = getenv (\"SKIP_TEST_%s\");
4443 if (str && strcmp (str, \"1\") == 0) return 1;
4447 " test_name name (String.uppercase test_name) (String.uppercase name);
4450 | Disabled | Always -> ()
4451 | If code | Unless code ->
4452 pr "static int %s_prereq (void)\n" test_name;
4460 static int %s (void)
4463 printf (\" %%s skipped (reason: environment variable set)\\n\", \"%s\");
4467 " test_name test_name test_name;
4471 pr " printf (\" %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4473 pr " if (! %s_prereq ()) {\n" test_name;
4474 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4478 generate_one_test_body name i test_name init test;
4480 pr " if (%s_prereq ()) {\n" test_name;
4481 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4485 generate_one_test_body name i test_name init test;
4487 generate_one_test_body name i test_name init test
4495 and generate_one_test_body name i test_name init test =
4499 pr " /* InitNone|InitEmpty for %s */\n" test_name;
4500 List.iter (generate_test_command_call test_name)
4501 [["blockdev_setrw"; "/dev/sda"];
4505 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4506 List.iter (generate_test_command_call test_name)
4507 [["blockdev_setrw"; "/dev/sda"];
4510 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4511 ["mkfs"; "ext2"; "/dev/sda1"];
4512 ["mount"; "/dev/sda1"; "/"]]
4513 | InitBasicFSonLVM ->
4514 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4516 List.iter (generate_test_command_call test_name)
4517 [["blockdev_setrw"; "/dev/sda"];
4520 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4521 ["pvcreate"; "/dev/sda1"];
4522 ["vgcreate"; "VG"; "/dev/sda1"];
4523 ["lvcreate"; "LV"; "VG"; "8"];
4524 ["mkfs"; "ext2"; "/dev/VG/LV"];
4525 ["mount"; "/dev/VG/LV"; "/"]]
4528 let get_seq_last = function
4530 failwithf "%s: you cannot use [] (empty list) when expecting a command"
4533 let seq = List.rev seq in
4534 List.rev (List.tl seq), List.hd seq
4539 pr " /* TestRun for %s (%d) */\n" name i;
4540 List.iter (generate_test_command_call test_name) seq
4541 | TestOutput (seq, expected) ->
4542 pr " /* TestOutput for %s (%d) */\n" name i;
4543 pr " char expected[] = \"%s\";\n" (c_quote expected);
4544 let seq, last = get_seq_last seq in
4546 pr " if (strcmp (r, expected) != 0) {\n";
4547 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4551 List.iter (generate_test_command_call test_name) seq;
4552 generate_test_command_call ~test test_name last
4553 | TestOutputList (seq, expected) ->
4554 pr " /* TestOutputList for %s (%d) */\n" name i;
4555 let seq, last = get_seq_last seq in
4559 pr " if (!r[%d]) {\n" i;
4560 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4561 pr " print_strings (r);\n";
4565 pr " char expected[] = \"%s\";\n" (c_quote str);
4566 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4567 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4572 pr " if (r[%d] != NULL) {\n" (List.length expected);
4573 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4575 pr " print_strings (r);\n";
4579 List.iter (generate_test_command_call test_name) seq;
4580 generate_test_command_call ~test test_name last
4581 | TestOutputListOfDevices (seq, expected) ->
4582 pr " /* TestOutputListOfDevices for %s (%d) */\n" name i;
4583 let seq, last = get_seq_last seq in
4587 pr " if (!r[%d]) {\n" i;
4588 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4589 pr " print_strings (r);\n";
4593 pr " char expected[] = \"%s\";\n" (c_quote str);
4594 pr " r[%d][5] = 's';\n" i;
4595 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4596 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4601 pr " if (r[%d] != NULL) {\n" (List.length expected);
4602 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4604 pr " print_strings (r);\n";
4608 List.iter (generate_test_command_call test_name) seq;
4609 generate_test_command_call ~test test_name last
4610 | TestOutputInt (seq, expected) ->
4611 pr " /* TestOutputInt for %s (%d) */\n" name i;
4612 let seq, last = get_seq_last seq in
4614 pr " if (r != %d) {\n" expected;
4615 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4621 List.iter (generate_test_command_call test_name) seq;
4622 generate_test_command_call ~test test_name last
4623 | TestOutputTrue seq ->
4624 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4625 let seq, last = get_seq_last seq in
4628 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4633 List.iter (generate_test_command_call test_name) seq;
4634 generate_test_command_call ~test test_name last
4635 | TestOutputFalse seq ->
4636 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4637 let seq, last = get_seq_last seq in
4640 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4645 List.iter (generate_test_command_call test_name) seq;
4646 generate_test_command_call ~test test_name last
4647 | TestOutputLength (seq, expected) ->
4648 pr " /* TestOutputLength for %s (%d) */\n" name i;
4649 let seq, last = get_seq_last seq in
4652 pr " for (j = 0; j < %d; ++j)\n" expected;
4653 pr " if (r[j] == NULL) {\n";
4654 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4656 pr " print_strings (r);\n";
4659 pr " if (r[j] != NULL) {\n";
4660 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4662 pr " print_strings (r);\n";
4666 List.iter (generate_test_command_call test_name) seq;
4667 generate_test_command_call ~test test_name last
4668 | TestOutputStruct (seq, checks) ->
4669 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4670 let seq, last = get_seq_last seq in
4674 | CompareWithInt (field, expected) ->
4675 pr " if (r->%s != %d) {\n" field expected;
4676 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4677 test_name field expected;
4678 pr " (int) r->%s);\n" field;
4681 | CompareWithString (field, expected) ->
4682 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4683 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4684 test_name field expected;
4685 pr " r->%s);\n" field;
4688 | CompareFieldsIntEq (field1, field2) ->
4689 pr " if (r->%s != r->%s) {\n" field1 field2;
4690 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4691 test_name field1 field2;
4692 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4695 | CompareFieldsStrEq (field1, field2) ->
4696 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4697 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4698 test_name field1 field2;
4699 pr " r->%s, r->%s);\n" field1 field2;
4704 List.iter (generate_test_command_call test_name) seq;
4705 generate_test_command_call ~test test_name last
4706 | TestLastFail seq ->
4707 pr " /* TestLastFail for %s (%d) */\n" name i;
4708 let seq, last = get_seq_last seq in
4709 List.iter (generate_test_command_call test_name) seq;
4710 generate_test_command_call test_name ~expect_error:true last
4712 (* Generate the code to run a command, leaving the result in 'r'.
4713 * If you expect to get an error then you should set expect_error:true.
4715 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4717 | [] -> assert false
4719 (* Look up the command to find out what args/ret it has. *)
4722 let _, style, _, _, _, _, _ =
4723 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4726 failwithf "%s: in test, command %s was not found" test_name name in
4728 if List.length (snd style) <> List.length args then
4729 failwithf "%s: in test, wrong number of args given to %s"
4736 | OptString n, "NULL" -> ()
4738 | OptString n, arg ->
4739 pr " char %s[] = \"%s\";\n" n (c_quote arg);
4742 | FileIn _, _ | FileOut _, _ -> ()
4743 | StringList n, arg ->
4744 let strs = string_split " " arg in
4747 pr " char %s_%d[] = \"%s\";\n" n i (c_quote str);
4749 pr " char *%s[] = {\n" n;
4751 fun i _ -> pr " %s_%d,\n" n i
4755 ) (List.combine (snd style) args);
4758 match fst style with
4759 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4760 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4761 | RConstString _ -> pr " const char *r;\n"; "NULL"
4762 | RString _ -> pr " char *r;\n"; "NULL"
4763 | RStringList _ | RHashtable _ ->
4768 pr " struct guestfs_int_bool *r;\n"; "NULL"
4770 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4772 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4774 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4776 pr " struct guestfs_stat *r;\n"; "NULL"
4778 pr " struct guestfs_statvfs *r;\n"; "NULL" in
4780 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4781 pr " r = guestfs_%s (g" name;
4783 (* Generate the parameters. *)
4786 | OptString _, "NULL" -> pr ", NULL"
4790 | FileIn _, arg | FileOut _, arg ->
4791 pr ", \"%s\"" (c_quote arg)
4792 | StringList n, _ ->
4796 try int_of_string arg
4797 with Failure "int_of_string" ->
4798 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4801 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4802 ) (List.combine (snd style) args);
4805 if not expect_error then
4806 pr " if (r == %s)\n" error_code
4808 pr " if (r != %s)\n" error_code;
4811 (* Insert the test code. *)
4817 (match fst style with
4818 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4819 | RString _ -> pr " free (r);\n"
4820 | RStringList _ | RHashtable _ ->
4821 pr " for (i = 0; r[i] != NULL; ++i)\n";
4822 pr " free (r[i]);\n";
4825 pr " guestfs_free_int_bool (r);\n"
4827 pr " guestfs_free_lvm_pv_list (r);\n"
4829 pr " guestfs_free_lvm_vg_list (r);\n"
4831 pr " guestfs_free_lvm_lv_list (r);\n"
4832 | RStat _ | RStatVFS _ ->
4839 let str = replace_str str "\r" "\\r" in
4840 let str = replace_str str "\n" "\\n" in
4841 let str = replace_str str "\t" "\\t" in
4842 let str = replace_str str "\000" "\\0" in
4845 (* Generate a lot of different functions for guestfish. *)
4846 and generate_fish_cmds () =
4847 generate_header CStyle GPLv2;
4851 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4853 let all_functions_sorted =
4855 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4856 ) all_functions_sorted in
4858 pr "#include <stdio.h>\n";
4859 pr "#include <stdlib.h>\n";
4860 pr "#include <string.h>\n";
4861 pr "#include <inttypes.h>\n";
4863 pr "#include <guestfs.h>\n";
4864 pr "#include \"fish.h\"\n";
4867 (* list_commands function, which implements guestfish -h *)
4868 pr "void list_commands (void)\n";
4870 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
4871 pr " list_builtin_commands ();\n";
4873 fun (name, _, _, flags, _, shortdesc, _) ->
4874 let name = replace_char name '_' '-' in
4875 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4877 ) all_functions_sorted;
4878 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4882 (* display_command function, which implements guestfish -h cmd *)
4883 pr "void display_command (const char *cmd)\n";
4886 fun (name, style, _, flags, _, shortdesc, longdesc) ->
4887 let name2 = replace_char name '_' '-' in
4889 try find_map (function FishAlias n -> Some n | _ -> None) flags
4890 with Not_found -> name in
4891 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4893 match snd style with
4897 name2 (String.concat "> <" (List.map name_of_argt args)) in
4900 if List.mem ProtocolLimitWarning flags then
4901 ("\n\n" ^ protocol_limit_warning)
4904 (* For DangerWillRobinson commands, we should probably have
4905 * guestfish prompt before allowing you to use them (especially
4906 * in interactive mode). XXX
4910 if List.mem DangerWillRobinson flags then
4911 ("\n\n" ^ danger_will_robinson)
4914 let describe_alias =
4915 if name <> alias then
4916 sprintf "\n\nYou can use '%s' as an alias for this command." alias
4920 pr "strcasecmp (cmd, \"%s\") == 0" name;
4921 if name <> name2 then
4922 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4923 if name <> alias then
4924 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4926 pr " pod2text (\"%s - %s\", %S);\n"
4928 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4931 pr " display_builtin_command (cmd);\n";
4935 (* print_{pv,vg,lv}_list functions *)
4939 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4946 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4948 pr " printf (\"%s: \");\n" name;
4949 pr " for (i = 0; i < 32; ++i)\n";
4950 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
4951 pr " printf (\"\\n\");\n"
4953 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4955 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4956 | name, `OptPercent ->
4957 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4958 typ name name typ name;
4959 pr " else printf (\"%s: \\n\");\n" name
4963 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4968 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4969 pr " print_%s (&%ss->val[i]);\n" typ typ;
4972 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4974 (* print_{stat,statvfs} functions *)
4978 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4983 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4987 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4989 (* run_<action> actions *)
4991 fun (name, style, _, flags, _, _, _) ->
4992 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4994 (match fst style with
4997 | RBool _ -> pr " int r;\n"
4998 | RInt64 _ -> pr " int64_t r;\n"
4999 | RConstString _ -> pr " const char *r;\n"
5000 | RString _ -> pr " char *r;\n"
5001 | RStringList _ | RHashtable _ -> pr " char **r;\n"
5002 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
5003 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
5004 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
5005 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
5006 | RStat _ -> pr " struct guestfs_stat *r;\n"
5007 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
5014 | FileOut n -> pr " const char *%s;\n" n
5015 | StringList n -> pr " char **%s;\n" n
5016 | Bool n -> pr " int %s;\n" n
5017 | Int n -> pr " int %s;\n" n
5020 (* Check and convert parameters. *)
5021 let argc_expected = List.length (snd style) in
5022 pr " if (argc != %d) {\n" argc_expected;
5023 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
5025 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
5031 | String name -> pr " %s = argv[%d];\n" name i
5033 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5036 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5039 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5041 | StringList name ->
5042 pr " %s = parse_string_list (argv[%d]);\n" name i
5044 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5046 pr " %s = atoi (argv[%d]);\n" name i
5049 (* Call C API function. *)
5051 try find_map (function FishAction n -> Some n | _ -> None) flags
5052 with Not_found -> sprintf "guestfs_%s" name in
5054 generate_call_args ~handle:"g" (snd style);
5057 (* Check return value for errors and display command results. *)
5058 (match fst style with
5059 | RErr -> pr " return r;\n"
5061 pr " if (r == -1) return -1;\n";
5062 pr " printf (\"%%d\\n\", r);\n";
5065 pr " if (r == -1) return -1;\n";
5066 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
5069 pr " if (r == -1) return -1;\n";
5070 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
5073 pr " if (r == NULL) return -1;\n";
5074 pr " printf (\"%%s\\n\", r);\n";
5077 pr " if (r == NULL) return -1;\n";
5078 pr " printf (\"%%s\\n\", r);\n";
5082 pr " if (r == NULL) return -1;\n";
5083 pr " print_strings (r);\n";
5084 pr " free_strings (r);\n";
5087 pr " if (r == NULL) return -1;\n";
5088 pr " printf (\"%%d, %%s\\n\", r->i,\n";
5089 pr " r->b ? \"true\" : \"false\");\n";
5090 pr " guestfs_free_int_bool (r);\n";
5093 pr " if (r == NULL) return -1;\n";
5094 pr " print_pv_list (r);\n";
5095 pr " guestfs_free_lvm_pv_list (r);\n";
5098 pr " if (r == NULL) return -1;\n";
5099 pr " print_vg_list (r);\n";
5100 pr " guestfs_free_lvm_vg_list (r);\n";
5103 pr " if (r == NULL) return -1;\n";
5104 pr " print_lv_list (r);\n";
5105 pr " guestfs_free_lvm_lv_list (r);\n";
5108 pr " if (r == NULL) return -1;\n";
5109 pr " print_stat (r);\n";
5113 pr " if (r == NULL) return -1;\n";
5114 pr " print_statvfs (r);\n";
5118 pr " if (r == NULL) return -1;\n";
5119 pr " print_table (r);\n";
5120 pr " free_strings (r);\n";
5127 (* run_action function *)
5128 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
5131 fun (name, _, _, flags, _, _, _) ->
5132 let name2 = replace_char name '_' '-' in
5134 try find_map (function FishAlias n -> Some n | _ -> None) flags
5135 with Not_found -> name in
5137 pr "strcasecmp (cmd, \"%s\") == 0" name;
5138 if name <> name2 then
5139 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5140 if name <> alias then
5141 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5143 pr " return run_%s (cmd, argc, argv);\n" name;
5147 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
5154 (* Readline completion for guestfish. *)
5155 and generate_fish_completion () =
5156 generate_header CStyle GPLv2;
5160 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5170 #ifdef HAVE_LIBREADLINE
5171 #include <readline/readline.h>
5176 #ifdef HAVE_LIBREADLINE
5178 static const char *const commands[] = {
5179 BUILTIN_COMMANDS_FOR_COMPLETION,
5182 (* Get the commands, including the aliases. They don't need to be
5183 * sorted - the generator() function just does a dumb linear search.
5187 fun (name, _, _, flags, _, _, _) ->
5188 let name2 = replace_char name '_' '-' in
5190 try find_map (function FishAlias n -> Some n | _ -> None) flags
5191 with Not_found -> name in
5193 if name <> alias then [name2; alias] else [name2]
5195 let commands = List.flatten commands in
5197 List.iter (pr " \"%s\",\n") commands;
5203 generator (const char *text, int state)
5205 static int index, len;
5210 len = strlen (text);
5213 rl_attempted_completion_over = 1;
5215 while ((name = commands[index]) != NULL) {
5217 if (strncasecmp (name, text, len) == 0)
5218 return strdup (name);
5224 #endif /* HAVE_LIBREADLINE */
5226 char **do_completion (const char *text, int start, int end)
5228 char **matches = NULL;
5230 #ifdef HAVE_LIBREADLINE
5231 rl_completion_append_character = ' ';
5234 matches = rl_completion_matches (text, generator);
5235 else if (complete_dest_paths)
5236 matches = rl_completion_matches (text, complete_dest_paths_generator);
5243 (* Generate the POD documentation for guestfish. *)
5244 and generate_fish_actions_pod () =
5245 let all_functions_sorted =
5247 fun (_, _, _, flags, _, _, _) ->
5248 not (List.mem NotInFish flags || List.mem NotInDocs flags)
5249 ) all_functions_sorted in
5251 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
5254 fun (name, style, _, flags, _, _, longdesc) ->
5256 Str.global_substitute rex (
5259 try Str.matched_group 1 s
5261 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
5262 "C<" ^ replace_char sub '_' '-' ^ ">"
5264 let name = replace_char name '_' '-' in
5266 try find_map (function FishAlias n -> Some n | _ -> None) flags
5267 with Not_found -> name in
5269 pr "=head2 %s" name;
5270 if name <> alias then
5277 | String n -> pr " %s" n
5278 | OptString n -> pr " %s" n
5279 | StringList n -> pr " '%s ...'" n
5280 | Bool _ -> pr " true|false"
5281 | Int n -> pr " %s" n
5282 | FileIn n | FileOut n -> pr " (%s|-)" n
5286 pr "%s\n\n" longdesc;
5288 if List.exists (function FileIn _ | FileOut _ -> true
5289 | _ -> false) (snd style) then
5290 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5292 if List.mem ProtocolLimitWarning flags then
5293 pr "%s\n\n" protocol_limit_warning;
5295 if List.mem DangerWillRobinson flags then
5296 pr "%s\n\n" danger_will_robinson
5297 ) all_functions_sorted
5299 (* Generate a C function prototype. *)
5300 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5301 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5303 ?handle name style =
5304 if extern then pr "extern ";
5305 if static then pr "static ";
5306 (match fst style with
5308 | RInt _ -> pr "int "
5309 | RInt64 _ -> pr "int64_t "
5310 | RBool _ -> pr "int "
5311 | RConstString _ -> pr "const char *"
5312 | RString _ -> pr "char *"
5313 | RStringList _ | RHashtable _ -> pr "char **"
5315 if not in_daemon then pr "struct guestfs_int_bool *"
5316 else pr "guestfs_%s_ret *" name
5318 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
5319 else pr "guestfs_lvm_int_pv_list *"
5321 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
5322 else pr "guestfs_lvm_int_vg_list *"
5324 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
5325 else pr "guestfs_lvm_int_lv_list *"
5327 if not in_daemon then pr "struct guestfs_stat *"
5328 else pr "guestfs_int_stat *"
5330 if not in_daemon then pr "struct guestfs_statvfs *"
5331 else pr "guestfs_int_statvfs *"
5333 pr "%s%s (" prefix name;
5334 if handle = None && List.length (snd style) = 0 then
5337 let comma = ref false in
5340 | Some handle -> pr "guestfs_h *%s" handle; comma := true
5344 if single_line then pr ", " else pr ",\n\t\t"
5353 if not in_daemon then pr "const char *%s" n
5354 else pr "char *%s" n
5357 if not in_daemon then pr "char * const* const %s" n
5358 else pr "char **%s" n
5359 | Bool n -> next (); pr "int %s" n
5360 | Int n -> next (); pr "int %s" n
5363 if not in_daemon then (next (); pr "const char *%s" n)
5367 if semicolon then pr ";";
5368 if newline then pr "\n"
5370 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5371 and generate_call_args ?handle args =
5373 let comma = ref false in
5376 | Some handle -> pr "%s" handle; comma := true
5380 if !comma then pr ", ";
5382 pr "%s" (name_of_argt arg)
5386 (* Generate the OCaml bindings interface. *)
5387 and generate_ocaml_mli () =
5388 generate_header OCamlStyle LGPLv2;
5391 (** For API documentation you should refer to the C API
5392 in the guestfs(3) manual page. The OCaml API uses almost
5393 exactly the same calls. *)
5396 (** A [guestfs_h] handle. *)
5398 exception Error of string
5399 (** This exception is raised when there is an error. *)
5401 val create : unit -> t
5403 val close : t -> unit
5404 (** Handles are closed by the garbage collector when they become
5405 unreferenced, but callers can also call this in order to
5406 provide predictable cleanup. *)
5409 generate_ocaml_lvm_structure_decls ();
5411 generate_ocaml_stat_structure_decls ();
5415 fun (name, style, _, _, _, shortdesc, _) ->
5416 generate_ocaml_prototype name style;
5417 pr "(** %s *)\n" shortdesc;
5421 (* Generate the OCaml bindings implementation. *)
5422 and generate_ocaml_ml () =
5423 generate_header OCamlStyle LGPLv2;
5427 exception Error of string
5428 external create : unit -> t = \"ocaml_guestfs_create\"
5429 external close : t -> unit = \"ocaml_guestfs_close\"
5432 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
5436 generate_ocaml_lvm_structure_decls ();
5438 generate_ocaml_stat_structure_decls ();
5442 fun (name, style, _, _, _, shortdesc, _) ->
5443 generate_ocaml_prototype ~is_external:true name style;
5446 (* Generate the OCaml bindings C implementation. *)
5447 and generate_ocaml_c () =
5448 generate_header CStyle LGPLv2;
5455 #include <caml/config.h>
5456 #include <caml/alloc.h>
5457 #include <caml/callback.h>
5458 #include <caml/fail.h>
5459 #include <caml/memory.h>
5460 #include <caml/mlvalues.h>
5461 #include <caml/signals.h>
5463 #include <guestfs.h>
5465 #include \"guestfs_c.h\"
5467 /* Copy a hashtable of string pairs into an assoc-list. We return
5468 * the list in reverse order, but hashtables aren't supposed to be
5471 static CAMLprim value
5472 copy_table (char * const * argv)
5475 CAMLlocal5 (rv, pairv, kv, vv, cons);
5479 for (i = 0; argv[i] != NULL; i += 2) {
5480 kv = caml_copy_string (argv[i]);
5481 vv = caml_copy_string (argv[i+1]);
5482 pairv = caml_alloc (2, 0);
5483 Store_field (pairv, 0, kv);
5484 Store_field (pairv, 1, vv);
5485 cons = caml_alloc (2, 0);
5486 Store_field (cons, 1, rv);
5488 Store_field (cons, 0, pairv);
5496 (* LVM struct copy functions. *)
5499 let has_optpercent_col =
5500 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
5502 pr "static CAMLprim value\n";
5503 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
5505 pr " CAMLparam0 ();\n";
5506 if has_optpercent_col then
5507 pr " CAMLlocal3 (rv, v, v2);\n"
5509 pr " CAMLlocal2 (rv, v);\n";
5511 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5516 pr " v = caml_copy_string (%s->%s);\n" typ name
5518 pr " v = caml_alloc_string (32);\n";
5519 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
5522 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5523 | name, `OptPercent ->
5524 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5525 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
5526 pr " v = caml_alloc (1, 0);\n";
5527 pr " Store_field (v, 0, v2);\n";
5528 pr " } else /* None */\n";
5529 pr " v = Val_int (0);\n";
5531 pr " Store_field (rv, %d, v);\n" i
5533 pr " CAMLreturn (rv);\n";
5537 pr "static CAMLprim value\n";
5538 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
5541 pr " CAMLparam0 ();\n";
5542 pr " CAMLlocal2 (rv, v);\n";
5545 pr " if (%ss->len == 0)\n" typ;
5546 pr " CAMLreturn (Atom (0));\n";
5548 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
5549 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
5550 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
5551 pr " caml_modify (&Field (rv, i), v);\n";
5553 pr " CAMLreturn (rv);\n";
5557 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5559 (* Stat copy functions. *)
5562 pr "static CAMLprim value\n";
5563 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5565 pr " CAMLparam0 ();\n";
5566 pr " CAMLlocal2 (rv, v);\n";
5568 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5573 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5575 pr " Store_field (rv, %d, v);\n" i
5577 pr " CAMLreturn (rv);\n";
5580 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5584 fun (name, style, _, _, _, _, _) ->
5586 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5588 pr "CAMLprim value\n";
5589 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5590 List.iter (pr ", value %s") (List.tl params);
5595 | [p1; p2; p3; p4; p5] ->
5596 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
5597 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5598 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5599 pr " CAMLxparam%d (%s);\n"
5600 (List.length rest) (String.concat ", " rest)
5602 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5604 pr " CAMLlocal1 (rv);\n";
5607 pr " guestfs_h *g = Guestfs_val (gv);\n";
5608 pr " if (g == NULL)\n";
5609 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
5617 pr " const char *%s = String_val (%sv);\n" n n
5619 pr " const char *%s =\n" n;
5620 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5623 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5625 pr " int %s = Bool_val (%sv);\n" n n
5627 pr " int %s = Int_val (%sv);\n" n n
5630 match fst style with
5631 | RErr -> pr " int r;\n"; "-1"
5632 | RInt _ -> pr " int r;\n"; "-1"
5633 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5634 | RBool _ -> pr " int r;\n"; "-1"
5635 | RConstString _ -> pr " const char *r;\n"; "NULL"
5636 | RString _ -> pr " char *r;\n"; "NULL"
5642 pr " struct guestfs_int_bool *r;\n"; "NULL"
5644 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5646 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5648 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5650 pr " struct guestfs_stat *r;\n"; "NULL"
5652 pr " struct guestfs_statvfs *r;\n"; "NULL"
5659 pr " caml_enter_blocking_section ();\n";
5660 pr " r = guestfs_%s " name;
5661 generate_call_args ~handle:"g" (snd style);
5663 pr " caml_leave_blocking_section ();\n";
5668 pr " ocaml_guestfs_free_strings (%s);\n" n;
5669 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5672 pr " if (r == %s)\n" error_code;
5673 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5676 (match fst style with
5677 | RErr -> pr " rv = Val_unit;\n"
5678 | RInt _ -> pr " rv = Val_int (r);\n"
5680 pr " rv = caml_copy_int64 (r);\n"
5681 | RBool _ -> pr " rv = Val_bool (r);\n"
5682 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5684 pr " rv = caml_copy_string (r);\n";
5687 pr " rv = caml_copy_string_array ((const char **) r);\n";
5688 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5691 pr " rv = caml_alloc (2, 0);\n";
5692 pr " Store_field (rv, 0, Val_int (r->i));\n";
5693 pr " Store_field (rv, 1, Val_bool (r->b));\n";
5694 pr " guestfs_free_int_bool (r);\n";
5696 pr " rv = copy_lvm_pv_list (r);\n";
5697 pr " guestfs_free_lvm_pv_list (r);\n";
5699 pr " rv = copy_lvm_vg_list (r);\n";
5700 pr " guestfs_free_lvm_vg_list (r);\n";
5702 pr " rv = copy_lvm_lv_list (r);\n";
5703 pr " guestfs_free_lvm_lv_list (r);\n";
5705 pr " rv = copy_stat (r);\n";
5708 pr " rv = copy_statvfs (r);\n";
5711 pr " rv = copy_table (r);\n";
5712 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5716 pr " CAMLreturn (rv);\n";
5720 if List.length params > 5 then (
5721 pr "CAMLprim value\n";
5722 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5724 pr " return ocaml_guestfs_%s (argv[0]" name;
5725 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5732 and generate_ocaml_lvm_structure_decls () =
5735 pr "type lvm_%s = {\n" typ;
5738 | name, `String -> pr " %s : string;\n" name
5739 | name, `UUID -> pr " %s : string;\n" name
5740 | name, `Bytes -> pr " %s : int64;\n" name
5741 | name, `Int -> pr " %s : int64;\n" name
5742 | name, `OptPercent -> pr " %s : float option;\n" name
5746 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5748 and generate_ocaml_stat_structure_decls () =
5751 pr "type %s = {\n" typ;
5754 | name, `Int -> pr " %s : int64;\n" name
5758 ) ["stat", stat_cols; "statvfs", statvfs_cols]
5760 and generate_ocaml_prototype ?(is_external = false) name style =
5761 if is_external then pr "external " else pr "val ";
5762 pr "%s : t -> " name;
5765 | String _ | FileIn _ | FileOut _ -> pr "string -> "
5766 | OptString _ -> pr "string option -> "
5767 | StringList _ -> pr "string array -> "
5768 | Bool _ -> pr "bool -> "
5769 | Int _ -> pr "int -> "
5771 (match fst style with
5772 | RErr -> pr "unit" (* all errors are turned into exceptions *)
5773 | RInt _ -> pr "int"
5774 | RInt64 _ -> pr "int64"
5775 | RBool _ -> pr "bool"
5776 | RConstString _ -> pr "string"
5777 | RString _ -> pr "string"
5778 | RStringList _ -> pr "string array"
5779 | RIntBool _ -> pr "int * bool"
5780 | RPVList _ -> pr "lvm_pv array"
5781 | RVGList _ -> pr "lvm_vg array"
5782 | RLVList _ -> pr "lvm_lv array"
5783 | RStat _ -> pr "stat"
5784 | RStatVFS _ -> pr "statvfs"
5785 | RHashtable _ -> pr "(string * string) list"
5787 if is_external then (
5789 if List.length (snd style) + 1 > 5 then
5790 pr "\"ocaml_guestfs_%s_byte\" " name;
5791 pr "\"ocaml_guestfs_%s\"" name
5795 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5796 and generate_perl_xs () =
5797 generate_header CStyle LGPLv2;
5800 #include \"EXTERN.h\"
5804 #include <guestfs.h>
5807 #define PRId64 \"lld\"
5811 my_newSVll(long long val) {
5812 #ifdef USE_64_BIT_ALL
5813 return newSViv(val);
5817 len = snprintf(buf, 100, \"%%\" PRId64, val);
5818 return newSVpv(buf, len);
5823 #define PRIu64 \"llu\"
5827 my_newSVull(unsigned long long val) {
5828 #ifdef USE_64_BIT_ALL
5829 return newSVuv(val);
5833 len = snprintf(buf, 100, \"%%\" PRIu64, val);
5834 return newSVpv(buf, len);
5838 /* http://www.perlmonks.org/?node_id=680842 */
5840 XS_unpack_charPtrPtr (SV *arg) {
5845 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5846 croak (\"array reference expected\");
5848 av = (AV *)SvRV (arg);
5849 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5851 croak (\"malloc failed\");
5853 for (i = 0; i <= av_len (av); i++) {
5854 SV **elem = av_fetch (av, i, 0);
5856 if (!elem || !*elem)
5857 croak (\"missing element in list\");
5859 ret[i] = SvPV_nolen (*elem);
5867 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
5874 RETVAL = guestfs_create ();
5876 croak (\"could not create guestfs handle\");
5877 guestfs_set_error_handler (RETVAL, NULL, NULL);
5890 fun (name, style, _, _, _, _, _) ->
5891 (match fst style with
5892 | RErr -> pr "void\n"
5893 | RInt _ -> pr "SV *\n"
5894 | RInt64 _ -> pr "SV *\n"
5895 | RBool _ -> pr "SV *\n"
5896 | RConstString _ -> pr "SV *\n"
5897 | RString _ -> pr "SV *\n"
5900 | RPVList _ | RVGList _ | RLVList _
5901 | RStat _ | RStatVFS _
5903 pr "void\n" (* all lists returned implictly on the stack *)
5905 (* Call and arguments. *)
5907 generate_call_args ~handle:"g" (snd style);
5909 pr " guestfs_h *g;\n";
5913 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
5915 (* http://www.perlmonks.org/?node_id=554277
5916 * Note that the implicit handle argument means we have
5917 * to add 1 to the ST(x) operator.
5919 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
5920 | StringList n -> pr " char **%s;\n" n
5921 | Bool n -> pr " int %s;\n" n
5922 | Int n -> pr " int %s;\n" n
5925 let do_cleanups () =
5928 | String _ | OptString _ | Bool _ | Int _
5929 | FileIn _ | FileOut _ -> ()
5930 | StringList n -> pr " free (%s);\n" n
5935 (match fst style with
5940 pr " r = guestfs_%s " name;
5941 generate_call_args ~handle:"g" (snd style);
5944 pr " if (r == -1)\n";
5945 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5951 pr " %s = guestfs_%s " n name;
5952 generate_call_args ~handle:"g" (snd style);
5955 pr " if (%s == -1)\n" n;
5956 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5957 pr " RETVAL = newSViv (%s);\n" n;
5962 pr " int64_t %s;\n" n;
5964 pr " %s = guestfs_%s " n name;
5965 generate_call_args ~handle:"g" (snd style);
5968 pr " if (%s == -1)\n" n;
5969 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5970 pr " RETVAL = my_newSVll (%s);\n" n;
5975 pr " const char *%s;\n" n;
5977 pr " %s = guestfs_%s " n name;
5978 generate_call_args ~handle:"g" (snd style);
5981 pr " if (%s == NULL)\n" n;
5982 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5983 pr " RETVAL = newSVpv (%s, 0);\n" n;
5988 pr " char *%s;\n" n;
5990 pr " %s = guestfs_%s " n name;
5991 generate_call_args ~handle:"g" (snd style);
5994 pr " if (%s == NULL)\n" n;
5995 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5996 pr " RETVAL = newSVpv (%s, 0);\n" n;
5997 pr " free (%s);\n" n;
6000 | RStringList n | RHashtable n ->
6002 pr " char **%s;\n" n;
6005 pr " %s = guestfs_%s " n name;
6006 generate_call_args ~handle:"g" (snd style);
6009 pr " if (%s == NULL)\n" n;
6010 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6011 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6012 pr " EXTEND (SP, n);\n";
6013 pr " for (i = 0; i < n; ++i) {\n";
6014 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6015 pr " free (%s[i]);\n" n;
6017 pr " free (%s);\n" n;
6020 pr " struct guestfs_int_bool *r;\n";
6022 pr " r = guestfs_%s " name;
6023 generate_call_args ~handle:"g" (snd style);
6026 pr " if (r == NULL)\n";
6027 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6028 pr " EXTEND (SP, 2);\n";
6029 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
6030 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
6031 pr " guestfs_free_int_bool (r);\n";
6033 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
6035 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
6037 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
6039 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
6041 generate_perl_stat_code
6042 "statvfs" statvfs_cols name style n do_cleanups
6048 and generate_perl_lvm_code typ cols name style n do_cleanups =
6050 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
6054 pr " %s = guestfs_%s " n name;
6055 generate_call_args ~handle:"g" (snd style);
6058 pr " if (%s == NULL)\n" n;
6059 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6060 pr " EXTEND (SP, %s->len);\n" n;
6061 pr " for (i = 0; i < %s->len; ++i) {\n" n;
6062 pr " hv = newHV ();\n";
6066 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6067 name (String.length name) n name
6069 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
6070 name (String.length name) n name
6072 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6073 name (String.length name) n name
6075 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
6076 name (String.length name) n name
6077 | name, `OptPercent ->
6078 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6079 name (String.length name) n name
6081 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
6083 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
6085 and generate_perl_stat_code typ cols name style n do_cleanups =
6087 pr " struct guestfs_%s *%s;\n" typ n;
6089 pr " %s = guestfs_%s " n name;
6090 generate_call_args ~handle:"g" (snd style);
6093 pr " if (%s == NULL)\n" n;
6094 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6095 pr " EXTEND (SP, %d);\n" (List.length cols);
6099 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
6101 pr " free (%s);\n" n
6103 (* Generate Sys/Guestfs.pm. *)
6104 and generate_perl_pm () =
6105 generate_header HashStyle LGPLv2;
6112 Sys::Guestfs - Perl bindings for libguestfs
6118 my $h = Sys::Guestfs->new ();
6119 $h->add_drive ('guest.img');
6122 $h->mount ('/dev/sda1', '/');
6123 $h->touch ('/hello');
6128 The C<Sys::Guestfs> module provides a Perl XS binding to the
6129 libguestfs API for examining and modifying virtual machine
6132 Amongst the things this is good for: making batch configuration
6133 changes to guests, getting disk used/free statistics (see also:
6134 virt-df), migrating between virtualization systems (see also:
6135 virt-p2v), performing partial backups, performing partial guest
6136 clones, cloning guests and changing registry/UUID/hostname info, and
6139 Libguestfs uses Linux kernel and qemu code, and can access any type of
6140 guest filesystem that Linux and qemu can, including but not limited
6141 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6142 schemes, qcow, qcow2, vmdk.
6144 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6145 LVs, what filesystem is in each LV, etc.). It can also run commands
6146 in the context of the guest. Also you can access filesystems over FTP.
6150 All errors turn into calls to C<croak> (see L<Carp(3)>).
6158 package Sys::Guestfs;
6164 XSLoader::load ('Sys::Guestfs');
6166 =item $h = Sys::Guestfs->new ();
6168 Create a new guestfs handle.
6174 my $class = ref ($proto) || $proto;
6176 my $self = Sys::Guestfs::_create ();
6177 bless $self, $class;
6183 (* Actions. We only need to print documentation for these as
6184 * they are pulled in from the XS code automatically.
6187 fun (name, style, _, flags, _, _, longdesc) ->
6188 if not (List.mem NotInDocs flags) then (
6189 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
6191 generate_perl_prototype name style;
6193 pr "%s\n\n" longdesc;
6194 if List.mem ProtocolLimitWarning flags then
6195 pr "%s\n\n" protocol_limit_warning;
6196 if List.mem DangerWillRobinson flags then
6197 pr "%s\n\n" danger_will_robinson
6199 ) all_functions_sorted;
6211 Copyright (C) 2009 Red Hat Inc.
6215 Please see the file COPYING.LIB for the full license.
6219 L<guestfs(3)>, L<guestfish(1)>.
6224 and generate_perl_prototype name style =
6225 (match fst style with
6231 | RString n -> pr "$%s = " n
6232 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
6236 | RLVList n -> pr "@%s = " n
6239 | RHashtable n -> pr "%%%s = " n
6242 let comma = ref false in
6245 if !comma then pr ", ";
6248 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
6255 (* Generate Python C module. *)
6256 and generate_python_c () =
6257 generate_header CStyle LGPLv2;
6266 #include \"guestfs.h\"
6274 get_handle (PyObject *obj)
6277 assert (obj != Py_None);
6278 return ((Pyguestfs_Object *) obj)->g;
6282 put_handle (guestfs_h *g)
6286 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6289 /* This list should be freed (but not the strings) after use. */
6290 static const char **
6291 get_string_list (PyObject *obj)
6298 if (!PyList_Check (obj)) {
6299 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6303 len = PyList_Size (obj);
6304 r = malloc (sizeof (char *) * (len+1));
6306 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6310 for (i = 0; i < len; ++i)
6311 r[i] = PyString_AsString (PyList_GetItem (obj, i));
6318 put_string_list (char * const * const argv)
6323 for (argc = 0; argv[argc] != NULL; ++argc)
6326 list = PyList_New (argc);
6327 for (i = 0; i < argc; ++i)
6328 PyList_SetItem (list, i, PyString_FromString (argv[i]));
6334 put_table (char * const * const argv)
6336 PyObject *list, *item;
6339 for (argc = 0; argv[argc] != NULL; ++argc)
6342 list = PyList_New (argc >> 1);
6343 for (i = 0; i < argc; i += 2) {
6344 item = PyTuple_New (2);
6345 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
6346 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
6347 PyList_SetItem (list, i >> 1, item);
6354 free_strings (char **argv)
6358 for (argc = 0; argv[argc] != NULL; ++argc)
6364 py_guestfs_create (PyObject *self, PyObject *args)
6368 g = guestfs_create ();
6370 PyErr_SetString (PyExc_RuntimeError,
6371 \"guestfs.create: failed to allocate handle\");
6374 guestfs_set_error_handler (g, NULL, NULL);
6375 return put_handle (g);
6379 py_guestfs_close (PyObject *self, PyObject *args)
6384 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
6386 g = get_handle (py_g);
6390 Py_INCREF (Py_None);
6396 (* LVM structures, turned into Python dictionaries. *)
6399 pr "static PyObject *\n";
6400 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
6402 pr " PyObject *dict;\n";
6404 pr " dict = PyDict_New ();\n";
6408 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6409 pr " PyString_FromString (%s->%s));\n"
6412 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6413 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
6416 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6417 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
6420 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6421 pr " PyLong_FromLongLong (%s->%s));\n"
6423 | name, `OptPercent ->
6424 pr " if (%s->%s >= 0)\n" typ name;
6425 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6426 pr " PyFloat_FromDouble ((double) %s->%s));\n"
6429 pr " Py_INCREF (Py_None);\n";
6430 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
6433 pr " return dict;\n";
6437 pr "static PyObject *\n";
6438 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
6440 pr " PyObject *list;\n";
6443 pr " list = PyList_New (%ss->len);\n" typ;
6444 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
6445 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
6446 pr " return list;\n";
6449 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
6451 (* Stat structures, turned into Python dictionaries. *)
6454 pr "static PyObject *\n";
6455 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6457 pr " PyObject *dict;\n";
6459 pr " dict = PyDict_New ();\n";
6463 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6464 pr " PyLong_FromLongLong (%s->%s));\n"
6467 pr " return dict;\n";
6470 ) ["stat", stat_cols; "statvfs", statvfs_cols];
6472 (* Python wrapper functions. *)
6474 fun (name, style, _, _, _, _, _) ->
6475 pr "static PyObject *\n";
6476 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6479 pr " PyObject *py_g;\n";
6480 pr " guestfs_h *g;\n";
6481 pr " PyObject *py_r;\n";
6484 match fst style with
6485 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6486 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6487 | RConstString _ -> pr " const char *r;\n"; "NULL"
6488 | RString _ -> pr " char *r;\n"; "NULL"
6489 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6490 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6491 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6492 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6493 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6494 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6495 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6499 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
6500 | OptString n -> pr " const char *%s;\n" n
6502 pr " PyObject *py_%s;\n" n;
6503 pr " const char **%s;\n" n
6504 | Bool n -> pr " int %s;\n" n
6505 | Int n -> pr " int %s;\n" n
6510 (* Convert the parameters. *)
6511 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
6514 | String _ | FileIn _ | FileOut _ -> pr "s"
6515 | OptString _ -> pr "z"
6516 | StringList _ -> pr "O"
6517 | Bool _ -> pr "i" (* XXX Python has booleans? *)
6520 pr ":guestfs_%s\",\n" name;
6524 | String n | FileIn n | FileOut n -> pr ", &%s" n
6525 | OptString n -> pr ", &%s" n
6526 | StringList n -> pr ", &py_%s" n
6527 | Bool n -> pr ", &%s" n
6528 | Int n -> pr ", &%s" n
6532 pr " return NULL;\n";
6534 pr " g = get_handle (py_g);\n";
6537 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6539 pr " %s = get_string_list (py_%s);\n" n n;
6540 pr " if (!%s) return NULL;\n" n
6545 pr " r = guestfs_%s " name;
6546 generate_call_args ~handle:"g" (snd style);
6551 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6553 pr " free (%s);\n" n
6556 pr " if (r == %s) {\n" error_code;
6557 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6558 pr " return NULL;\n";
6562 (match fst style with
6564 pr " Py_INCREF (Py_None);\n";
6565 pr " py_r = Py_None;\n"
6567 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
6568 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
6569 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
6571 pr " py_r = PyString_FromString (r);\n";
6574 pr " py_r = put_string_list (r);\n";
6575 pr " free_strings (r);\n"
6577 pr " py_r = PyTuple_New (2);\n";
6578 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
6579 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
6580 pr " guestfs_free_int_bool (r);\n"
6582 pr " py_r = put_lvm_pv_list (r);\n";
6583 pr " guestfs_free_lvm_pv_list (r);\n"
6585 pr " py_r = put_lvm_vg_list (r);\n";
6586 pr " guestfs_free_lvm_vg_list (r);\n"
6588 pr " py_r = put_lvm_lv_list (r);\n";
6589 pr " guestfs_free_lvm_lv_list (r);\n"
6591 pr " py_r = put_stat (r);\n";
6594 pr " py_r = put_statvfs (r);\n";
6597 pr " py_r = put_table (r);\n";
6598 pr " free_strings (r);\n"
6601 pr " return py_r;\n";
6606 (* Table of functions. *)
6607 pr "static PyMethodDef methods[] = {\n";
6608 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6609 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6611 fun (name, _, _, _, _, _, _) ->
6612 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6615 pr " { NULL, NULL, 0, NULL }\n";
6619 (* Init function. *)
6622 initlibguestfsmod (void)
6624 static int initialized = 0;
6626 if (initialized) return;
6627 Py_InitModule ((char *) \"libguestfsmod\", methods);
6632 (* Generate Python module. *)
6633 and generate_python_py () =
6634 generate_header HashStyle LGPLv2;
6637 u\"\"\"Python bindings for libguestfs
6640 g = guestfs.GuestFS ()
6641 g.add_drive (\"guest.img\")
6644 parts = g.list_partitions ()
6646 The guestfs module provides a Python binding to the libguestfs API
6647 for examining and modifying virtual machine disk images.
6649 Amongst the things this is good for: making batch configuration
6650 changes to guests, getting disk used/free statistics (see also:
6651 virt-df), migrating between virtualization systems (see also:
6652 virt-p2v), performing partial backups, performing partial guest
6653 clones, cloning guests and changing registry/UUID/hostname info, and
6656 Libguestfs uses Linux kernel and qemu code, and can access any type of
6657 guest filesystem that Linux and qemu can, including but not limited
6658 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6659 schemes, qcow, qcow2, vmdk.
6661 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6662 LVs, what filesystem is in each LV, etc.). It can also run commands
6663 in the context of the guest. Also you can access filesystems over FTP.
6665 Errors which happen while using the API are turned into Python
6666 RuntimeError exceptions.
6668 To create a guestfs handle you usually have to perform the following
6671 # Create the handle, call add_drive at least once, and possibly
6672 # several times if the guest has multiple block devices:
6673 g = guestfs.GuestFS ()
6674 g.add_drive (\"guest.img\")
6676 # Launch the qemu subprocess and wait for it to become ready:
6680 # Now you can issue commands, for example:
6685 import libguestfsmod
6688 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6690 def __init__ (self):
6691 \"\"\"Create a new libguestfs handle.\"\"\"
6692 self._o = libguestfsmod.create ()
6695 libguestfsmod.close (self._o)
6700 fun (name, style, _, flags, _, _, longdesc) ->
6702 generate_call_args ~handle:"self" (snd style);
6705 if not (List.mem NotInDocs flags) then (
6706 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6708 match fst style with
6709 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6712 doc ^ "\n\nThis function returns a list of strings."
6714 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6716 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
6718 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
6720 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
6722 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6724 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6726 doc ^ "\n\nThis function returns a dictionary." in
6728 if List.mem ProtocolLimitWarning flags then
6729 doc ^ "\n\n" ^ protocol_limit_warning
6732 if List.mem DangerWillRobinson flags then
6733 doc ^ "\n\n" ^ danger_will_robinson
6735 let doc = pod2text ~width:60 name doc in
6736 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6737 let doc = String.concat "\n " doc in
6738 pr " u\"\"\"%s\"\"\"\n" doc;
6740 pr " return libguestfsmod.%s " name;
6741 generate_call_args ~handle:"self._o" (snd style);
6746 (* Useful if you need the longdesc POD text as plain text. Returns a
6749 * This is the slowest thing about autogeneration.
6751 and pod2text ~width name longdesc =
6752 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6753 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6755 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6756 let chan = Unix.open_process_in cmd in
6757 let lines = ref [] in
6759 let line = input_line chan in
6760 if i = 1 then (* discard the first line of output *)
6763 let line = triml line in
6764 lines := line :: !lines;
6767 let lines = try loop 1 with End_of_file -> List.rev !lines in
6768 Unix.unlink filename;
6769 match Unix.close_process_in chan with
6770 | Unix.WEXITED 0 -> lines
6772 failwithf "pod2text: process exited with non-zero status (%d)" i
6773 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6774 failwithf "pod2text: process signalled or stopped by signal %d" i
6776 (* Generate ruby bindings. *)
6777 and generate_ruby_c () =
6778 generate_header CStyle LGPLv2;
6786 #include \"guestfs.h\"
6788 #include \"extconf.h\"
6790 /* For Ruby < 1.9 */
6792 #define RARRAY_LEN(r) (RARRAY((r))->len)
6795 static VALUE m_guestfs; /* guestfs module */
6796 static VALUE c_guestfs; /* guestfs_h handle */
6797 static VALUE e_Error; /* used for all errors */
6799 static void ruby_guestfs_free (void *p)
6802 guestfs_close ((guestfs_h *) p);
6805 static VALUE ruby_guestfs_create (VALUE m)
6809 g = guestfs_create ();
6811 rb_raise (e_Error, \"failed to create guestfs handle\");
6813 /* Don't print error messages to stderr by default. */
6814 guestfs_set_error_handler (g, NULL, NULL);
6816 /* Wrap it, and make sure the close function is called when the
6819 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6822 static VALUE ruby_guestfs_close (VALUE gv)
6825 Data_Get_Struct (gv, guestfs_h, g);
6827 ruby_guestfs_free (g);
6828 DATA_PTR (gv) = NULL;
6836 fun (name, style, _, _, _, _, _) ->
6837 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6838 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6841 pr " guestfs_h *g;\n";
6842 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
6844 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6850 | String n | FileIn n | FileOut n ->
6851 pr " Check_Type (%sv, T_STRING);\n" n;
6852 pr " const char *%s = StringValueCStr (%sv);\n" n n;
6854 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6855 pr " \"%s\", \"%s\");\n" n name
6857 pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
6859 pr " char **%s;\n" n;
6860 pr " Check_Type (%sv, T_ARRAY);\n" n;
6862 pr " int i, len;\n";
6863 pr " len = RARRAY_LEN (%sv);\n" n;
6864 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6866 pr " for (i = 0; i < len; ++i) {\n";
6867 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
6868 pr " %s[i] = StringValueCStr (v);\n" n;
6870 pr " %s[len] = NULL;\n" n;
6873 pr " int %s = RTEST (%sv);\n" n n
6875 pr " int %s = NUM2INT (%sv);\n" n n
6880 match fst style with
6881 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6882 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6883 | RConstString _ -> pr " const char *r;\n"; "NULL"
6884 | RString _ -> pr " char *r;\n"; "NULL"
6885 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6886 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6887 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6888 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6889 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6890 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6891 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6894 pr " r = guestfs_%s " name;
6895 generate_call_args ~handle:"g" (snd style);
6900 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6902 pr " free (%s);\n" n
6905 pr " if (r == %s)\n" error_code;
6906 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6909 (match fst style with
6911 pr " return Qnil;\n"
6912 | RInt _ | RBool _ ->
6913 pr " return INT2NUM (r);\n"
6915 pr " return ULL2NUM (r);\n"
6917 pr " return rb_str_new2 (r);\n";
6919 pr " VALUE rv = rb_str_new2 (r);\n";
6923 pr " int i, len = 0;\n";
6924 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
6925 pr " VALUE rv = rb_ary_new2 (len);\n";
6926 pr " for (i = 0; r[i] != NULL; ++i) {\n";
6927 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6928 pr " free (r[i]);\n";
6933 pr " VALUE rv = rb_ary_new2 (2);\n";
6934 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
6935 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
6936 pr " guestfs_free_int_bool (r);\n";
6939 generate_ruby_lvm_code "pv" pv_cols
6941 generate_ruby_lvm_code "vg" vg_cols
6943 generate_ruby_lvm_code "lv" lv_cols
6945 pr " VALUE rv = rb_hash_new ();\n";
6949 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6954 pr " VALUE rv = rb_hash_new ();\n";
6958 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6963 pr " VALUE rv = rb_hash_new ();\n";
6965 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
6966 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6967 pr " free (r[i]);\n";
6968 pr " free (r[i+1]);\n";
6979 /* Initialize the module. */
6980 void Init__guestfs ()
6982 m_guestfs = rb_define_module (\"Guestfs\");
6983 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6984 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6986 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6987 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6990 (* Define the rest of the methods. *)
6992 fun (name, style, _, _, _, _, _) ->
6993 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
6994 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6999 (* Ruby code to return an LVM struct list. *)
7000 and generate_ruby_lvm_code typ cols =
7001 pr " VALUE rv = rb_ary_new2 (r->len);\n";
7003 pr " for (i = 0; i < r->len; ++i) {\n";
7004 pr " VALUE hv = rb_hash_new ();\n";
7008 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7010 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
7013 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7014 | name, `OptPercent ->
7015 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
7017 pr " rb_ary_push (rv, hv);\n";
7019 pr " guestfs_free_lvm_%s_list (r);\n" typ;
7022 (* Generate Java bindings GuestFS.java file. *)
7023 and generate_java_java () =
7024 generate_header CStyle LGPLv2;
7027 package com.redhat.et.libguestfs;
7029 import java.util.HashMap;
7030 import com.redhat.et.libguestfs.LibGuestFSException;
7031 import com.redhat.et.libguestfs.PV;
7032 import com.redhat.et.libguestfs.VG;
7033 import com.redhat.et.libguestfs.LV;
7034 import com.redhat.et.libguestfs.Stat;
7035 import com.redhat.et.libguestfs.StatVFS;
7036 import com.redhat.et.libguestfs.IntBool;
7039 * The GuestFS object is a libguestfs handle.
7043 public class GuestFS {
7044 // Load the native code.
7046 System.loadLibrary (\"guestfs_jni\");
7050 * The native guestfs_h pointer.
7055 * Create a libguestfs handle.
7057 * @throws LibGuestFSException
7059 public GuestFS () throws LibGuestFSException
7063 private native long _create () throws LibGuestFSException;
7066 * Close a libguestfs handle.
7068 * You can also leave handles to be collected by the garbage
7069 * collector, but this method ensures that the resources used
7070 * by the handle are freed up immediately. If you call any
7071 * other methods after closing the handle, you will get an
7074 * @throws LibGuestFSException
7076 public void close () throws LibGuestFSException
7082 private native void _close (long g) throws LibGuestFSException;
7084 public void finalize () throws LibGuestFSException
7092 fun (name, style, _, flags, _, shortdesc, longdesc) ->
7093 if not (List.mem NotInDocs flags); then (
7094 let doc = replace_str longdesc "C<guestfs_" "C<g." in
7096 if List.mem ProtocolLimitWarning flags then
7097 doc ^ "\n\n" ^ protocol_limit_warning
7100 if List.mem DangerWillRobinson flags then
7101 doc ^ "\n\n" ^ danger_will_robinson
7103 let doc = pod2text ~width:60 name doc in
7104 let doc = List.map ( (* RHBZ#501883 *)
7107 | nonempty -> nonempty
7109 let doc = String.concat "\n * " doc in
7112 pr " * %s\n" shortdesc;
7115 pr " * @throws LibGuestFSException\n";
7119 generate_java_prototype ~public:true ~semicolon:false name style;
7122 pr " if (g == 0)\n";
7123 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
7126 if fst style <> RErr then pr "return ";
7128 generate_call_args ~handle:"g" (snd style);
7132 generate_java_prototype ~privat:true ~native:true name style;
7139 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
7140 ?(semicolon=true) name style =
7141 if privat then pr "private ";
7142 if public then pr "public ";
7143 if native then pr "native ";
7146 (match fst style with
7147 | RErr -> pr "void ";
7148 | RInt _ -> pr "int ";
7149 | RInt64 _ -> pr "long ";
7150 | RBool _ -> pr "boolean ";
7151 | RConstString _ | RString _ -> pr "String ";
7152 | RStringList _ -> pr "String[] ";
7153 | RIntBool _ -> pr "IntBool ";
7154 | RPVList _ -> pr "PV[] ";
7155 | RVGList _ -> pr "VG[] ";
7156 | RLVList _ -> pr "LV[] ";
7157 | RStat _ -> pr "Stat ";
7158 | RStatVFS _ -> pr "StatVFS ";
7159 | RHashtable _ -> pr "HashMap<String,String> ";
7162 if native then pr "_%s " name else pr "%s " name;
7164 let needs_comma = ref false in
7173 if !needs_comma then pr ", ";
7174 needs_comma := true;
7191 pr " throws LibGuestFSException";
7192 if semicolon then pr ";"
7194 and generate_java_struct typ cols =
7195 generate_header CStyle LGPLv2;
7198 package com.redhat.et.libguestfs;
7201 * Libguestfs %s structure.
7212 | name, `UUID -> pr " public String %s;\n" name
7214 | name, `Int -> pr " public long %s;\n" name
7215 | name, `OptPercent ->
7216 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
7217 pr " public float %s;\n" name
7222 and generate_java_c () =
7223 generate_header CStyle LGPLv2;
7230 #include \"com_redhat_et_libguestfs_GuestFS.h\"
7231 #include \"guestfs.h\"
7233 /* Note that this function returns. The exception is not thrown
7234 * until after the wrapper function returns.
7237 throw_exception (JNIEnv *env, const char *msg)
7240 cl = (*env)->FindClass (env,
7241 \"com/redhat/et/libguestfs/LibGuestFSException\");
7242 (*env)->ThrowNew (env, cl, msg);
7245 JNIEXPORT jlong JNICALL
7246 Java_com_redhat_et_libguestfs_GuestFS__1create
7247 (JNIEnv *env, jobject obj)
7251 g = guestfs_create ();
7253 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
7256 guestfs_set_error_handler (g, NULL, NULL);
7257 return (jlong) (long) g;
7260 JNIEXPORT void JNICALL
7261 Java_com_redhat_et_libguestfs_GuestFS__1close
7262 (JNIEnv *env, jobject obj, jlong jg)
7264 guestfs_h *g = (guestfs_h *) (long) jg;
7271 fun (name, style, _, _, _, _, _) ->
7273 (match fst style with
7274 | RErr -> pr "void ";
7275 | RInt _ -> pr "jint ";
7276 | RInt64 _ -> pr "jlong ";
7277 | RBool _ -> pr "jboolean ";
7278 | RConstString _ | RString _ -> pr "jstring ";
7279 | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
7281 | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
7285 pr "Java_com_redhat_et_libguestfs_GuestFS_";
7286 pr "%s" (replace_str ("_" ^ name) "_" "_1");
7288 pr " (JNIEnv *env, jobject obj, jlong jg";
7295 pr ", jstring j%s" n
7297 pr ", jobjectArray j%s" n
7299 pr ", jboolean j%s" n
7305 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
7306 let error_code, no_ret =
7307 match fst style with
7308 | RErr -> pr " int r;\n"; "-1", ""
7310 | RInt _ -> pr " int r;\n"; "-1", "0"
7311 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
7312 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
7314 pr " jstring jr;\n";
7315 pr " char *r;\n"; "NULL", "NULL"
7317 pr " jobjectArray jr;\n";
7320 pr " jstring jstr;\n";
7321 pr " char **r;\n"; "NULL", "NULL"
7323 pr " jobject jr;\n";
7325 pr " jfieldID fl;\n";
7326 pr " struct guestfs_int_bool *r;\n"; "NULL", "NULL"
7328 pr " jobject jr;\n";
7330 pr " jfieldID fl;\n";
7331 pr " struct guestfs_stat *r;\n"; "NULL", "NULL"
7333 pr " jobject jr;\n";
7335 pr " jfieldID fl;\n";
7336 pr " struct guestfs_statvfs *r;\n"; "NULL", "NULL"
7338 pr " jobjectArray jr;\n";
7340 pr " jfieldID fl;\n";
7341 pr " jobject jfl;\n";
7342 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
7344 pr " jobjectArray jr;\n";
7346 pr " jfieldID fl;\n";
7347 pr " jobject jfl;\n";
7348 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
7350 pr " jobjectArray jr;\n";
7352 pr " jfieldID fl;\n";
7353 pr " jobject jfl;\n";
7354 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
7355 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
7362 pr " const char *%s;\n" n
7364 pr " int %s_len;\n" n;
7365 pr " const char **%s;\n" n
7372 (match fst style with
7373 | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
7374 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
7375 | RString _ | RIntBool _ | RStat _ | RStatVFS _
7376 | RHashtable _ -> false) ||
7377 List.exists (function StringList _ -> true | _ -> false) (snd style) in
7383 (* Get the parameters. *)
7389 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
7391 (* This is completely undocumented, but Java null becomes
7394 pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
7396 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
7397 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
7398 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7399 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7401 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
7403 pr " %s[%s_len] = NULL;\n" n n;
7406 pr " %s = j%s;\n" n n
7409 (* Make the call. *)
7410 pr " r = guestfs_%s " name;
7411 generate_call_args ~handle:"g" (snd style);
7414 (* Release the parameters. *)
7420 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7423 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7425 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7426 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7428 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
7430 pr " free (%s);\n" n
7435 (* Check for errors. *)
7436 pr " if (r == %s) {\n" error_code;
7437 pr " throw_exception (env, guestfs_last_error (g));\n";
7438 pr " return %s;\n" no_ret;
7442 (match fst style with
7444 | RInt _ -> pr " return (jint) r;\n"
7445 | RBool _ -> pr " return (jboolean) r;\n"
7446 | RInt64 _ -> pr " return (jlong) r;\n"
7447 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
7449 pr " jr = (*env)->NewStringUTF (env, r);\n";
7453 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7454 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7455 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
7456 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7457 pr " for (i = 0; i < r_len; ++i) {\n";
7458 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
7459 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7460 pr " free (r[i]);\n";
7465 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
7466 pr " jr = (*env)->AllocObject (env, cl);\n";
7467 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
7468 pr " (*env)->SetIntField (env, jr, fl, r->i);\n";
7469 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
7470 pr " (*env)->SetBooleanField (env, jr, fl, r->b);\n";
7471 pr " guestfs_free_int_bool (r);\n";
7474 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
7475 pr " jr = (*env)->AllocObject (env, cl);\n";
7479 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7481 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7486 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
7487 pr " jr = (*env)->AllocObject (env, cl);\n";
7491 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7493 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7498 generate_java_lvm_return "pv" "PV" pv_cols
7500 generate_java_lvm_return "vg" "VG" vg_cols
7502 generate_java_lvm_return "lv" "LV" lv_cols
7505 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7506 pr " return NULL;\n"
7513 and generate_java_lvm_return typ jtyp cols =
7514 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7515 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7516 pr " for (i = 0; i < r->len; ++i) {\n";
7517 pr " jfl = (*env)->AllocObject (env, cl);\n";
7521 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7522 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7525 pr " char s[33];\n";
7526 pr " memcpy (s, r->val[i].%s, 32);\n" name;
7528 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7529 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7531 | name, (`Bytes|`Int) ->
7532 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7533 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7534 | name, `OptPercent ->
7535 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7536 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7538 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7540 pr " guestfs_free_lvm_%s_list (r);\n" typ;
7543 and generate_haskell_hs () =
7544 generate_header HaskellStyle LGPLv2;
7546 (* XXX We only know how to generate partial FFI for Haskell
7547 * at the moment. Please help out!
7549 let can_generate style =
7553 | RInt64 _, _ -> true
7564 | RHashtable _, _ -> false in
7567 {-# INCLUDE <guestfs.h> #-}
7568 {-# LANGUAGE ForeignFunctionInterface #-}
7573 (* List out the names of the actions we want to export. *)
7575 fun (name, style, _, _, _, _, _) ->
7576 if can_generate style then pr ",\n %s" name
7583 import Foreign.C.Types
7585 import Control.Exception
7586 import Data.Typeable
7588 data GuestfsS = GuestfsS -- represents the opaque C struct
7589 type GuestfsP = Ptr GuestfsS -- guestfs_h *
7590 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7592 -- XXX define properly later XXX
7596 data IntBool = IntBool
7598 data StatVFS = StatVFS
7599 data Hashtable = Hashtable
7601 foreign import ccall unsafe \"guestfs_create\" c_create
7603 foreign import ccall unsafe \"&guestfs_close\" c_close
7604 :: FunPtr (GuestfsP -> IO ())
7605 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
7606 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
7608 create :: IO GuestfsH
7611 c_set_error_handler p nullPtr nullPtr
7612 h <- newForeignPtr c_close p
7615 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
7616 :: GuestfsP -> IO CString
7618 -- last_error :: GuestfsH -> IO (Maybe String)
7619 -- last_error h = do
7620 -- str <- withForeignPtr h (\\p -> c_last_error p)
7621 -- maybePeek peekCString str
7623 last_error :: GuestfsH -> IO (String)
7625 str <- withForeignPtr h (\\p -> c_last_error p)
7627 then return \"no error\"
7628 else peekCString str
7632 (* Generate wrappers for each foreign function. *)
7634 fun (name, style, _, _, _, _, _) ->
7635 if can_generate style then (
7636 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7638 generate_haskell_prototype ~handle:"GuestfsP" style;
7642 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7644 pr "%s %s = do\n" name
7645 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7647 (* Convert pointer arguments using with* functions. *)
7652 | String n -> pr "withCString %s $ \\%s -> " n n
7653 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7654 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7655 | Bool _ | Int _ -> ()
7657 (* Convert integer arguments. *)
7661 | Bool n -> sprintf "(fromBool %s)" n
7662 | Int n -> sprintf "(fromIntegral %s)" n
7663 | FileIn n | FileOut n | String n | OptString n | StringList n -> n
7665 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7666 (String.concat " " ("p" :: args));
7667 (match fst style with
7668 | RErr | RInt _ | RInt64 _ | RBool _ ->
7669 pr " if (r == -1)\n";
7671 pr " err <- last_error h\n";
7673 | RConstString _ | RString _ | RStringList _ | RIntBool _
7674 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7676 pr " if (r == nullPtr)\n";
7678 pr " err <- last_error h\n";
7681 (match fst style with
7683 pr " else return ()\n"
7685 pr " else return (fromIntegral r)\n"
7687 pr " else return (fromIntegral r)\n"
7689 pr " else return (toBool r)\n"
7700 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7706 and generate_haskell_prototype ~handle ?(hs = false) style =
7708 let string = if hs then "String" else "CString" in
7709 let int = if hs then "Int" else "CInt" in
7710 let bool = if hs then "Bool" else "CInt" in
7711 let int64 = if hs then "Integer" else "Int64" in
7715 | String _ -> pr "%s" string
7716 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7717 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7718 | Bool _ -> pr "%s" bool
7719 | Int _ -> pr "%s" int
7720 | FileIn _ -> pr "%s" string
7721 | FileOut _ -> pr "%s" string
7726 (match fst style with
7727 | RErr -> if not hs then pr "CInt"
7728 | RInt _ -> pr "%s" int
7729 | RInt64 _ -> pr "%s" int64
7730 | RBool _ -> pr "%s" bool
7731 | RConstString _ -> pr "%s" string
7732 | RString _ -> pr "%s" string
7733 | RStringList _ -> pr "[%s]" string
7734 | RIntBool _ -> pr "IntBool"
7735 | RPVList _ -> pr "[PV]"
7736 | RVGList _ -> pr "[VG]"
7737 | RLVList _ -> pr "[LV]"
7738 | RStat _ -> pr "Stat"
7739 | RStatVFS _ -> pr "StatVFS"
7740 | RHashtable _ -> pr "Hashtable"
7744 and generate_bindtests () =
7745 generate_header CStyle LGPLv2;
7750 #include <inttypes.h>
7753 #include \"guestfs.h\"
7754 #include \"guestfs_protocol.h\"
7756 #define error guestfs_error
7759 print_strings (char * const* const argv)
7764 for (argc = 0; argv[argc] != NULL; ++argc) {
7765 if (argc > 0) printf (\", \");
7766 printf (\"\\\"%%s\\\"\", argv[argc]);
7771 /* The test0 function prints its parameters to stdout. */
7775 match test_functions with
7776 | [] -> assert false
7777 | test0 :: tests -> test0, tests in
7780 let (name, style, _, _, _, _, _) = test0 in
7781 generate_prototype ~extern:false ~semicolon:false ~newline:true
7782 ~handle:"g" ~prefix:"guestfs_" name style;
7788 | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
7789 | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
7790 | StringList n -> pr " print_strings (%s);\n" n
7791 | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
7792 | Int n -> pr " printf (\"%%d\\n\", %s);\n" n
7794 pr " /* Java changes stdout line buffering so we need this: */\n";
7795 pr " fflush (stdout);\n";
7801 fun (name, style, _, _, _, _, _) ->
7802 if String.sub name (String.length name - 3) 3 <> "err" then (
7803 pr "/* Test normal return. */\n";
7804 generate_prototype ~extern:false ~semicolon:false ~newline:true
7805 ~handle:"g" ~prefix:"guestfs_" name style;
7807 (match fst style with
7812 pr " sscanf (val, \"%%d\", &r);\n";
7816 pr " sscanf (val, \"%%\" SCNi64, &r);\n";
7819 pr " return strcmp (val, \"true\") == 0;\n"
7821 (* Can't return the input string here. Return a static
7822 * string so we ensure we get a segfault if the caller
7825 pr " return \"static string\";\n"
7827 pr " return strdup (val);\n"
7829 pr " char **strs;\n";
7831 pr " sscanf (val, \"%%d\", &n);\n";
7832 pr " strs = malloc ((n+1) * sizeof (char *));\n";
7833 pr " for (i = 0; i < n; ++i) {\n";
7834 pr " strs[i] = malloc (16);\n";
7835 pr " snprintf (strs[i], 16, \"%%d\", i);\n";
7837 pr " strs[n] = NULL;\n";
7838 pr " return strs;\n"
7840 pr " struct guestfs_int_bool *r;\n";
7841 pr " r = malloc (sizeof (struct guestfs_int_bool));\n";
7842 pr " sscanf (val, \"%%\" SCNi32, &r->i);\n";
7846 pr " struct guestfs_lvm_pv_list *r;\n";
7848 pr " r = malloc (sizeof (struct guestfs_lvm_pv_list));\n";
7849 pr " sscanf (val, \"%%d\", &r->len);\n";
7850 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_pv));\n";
7851 pr " for (i = 0; i < r->len; ++i) {\n";
7852 pr " r->val[i].pv_name = malloc (16);\n";
7853 pr " snprintf (r->val[i].pv_name, 16, \"%%d\", i);\n";
7857 pr " struct guestfs_lvm_vg_list *r;\n";
7859 pr " r = malloc (sizeof (struct guestfs_lvm_vg_list));\n";
7860 pr " sscanf (val, \"%%d\", &r->len);\n";
7861 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_vg));\n";
7862 pr " for (i = 0; i < r->len; ++i) {\n";
7863 pr " r->val[i].vg_name = malloc (16);\n";
7864 pr " snprintf (r->val[i].vg_name, 16, \"%%d\", i);\n";
7868 pr " struct guestfs_lvm_lv_list *r;\n";
7870 pr " r = malloc (sizeof (struct guestfs_lvm_lv_list));\n";
7871 pr " sscanf (val, \"%%d\", &r->len);\n";
7872 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_lv));\n";
7873 pr " for (i = 0; i < r->len; ++i) {\n";
7874 pr " r->val[i].lv_name = malloc (16);\n";
7875 pr " snprintf (r->val[i].lv_name, 16, \"%%d\", i);\n";
7879 pr " struct guestfs_stat *r;\n";
7880 pr " r = calloc (1, sizeof (*r));\n";
7881 pr " sscanf (val, \"%%\" SCNi64, &r->dev);\n";
7884 pr " struct guestfs_statvfs *r;\n";
7885 pr " r = calloc (1, sizeof (*r));\n";
7886 pr " sscanf (val, \"%%\" SCNi64, &r->bsize);\n";
7889 pr " char **strs;\n";
7891 pr " sscanf (val, \"%%d\", &n);\n";
7892 pr " strs = malloc ((n*2+1) * sizeof (char *));\n";
7893 pr " for (i = 0; i < n; ++i) {\n";
7894 pr " strs[i*2] = malloc (16);\n";
7895 pr " strs[i*2+1] = malloc (16);\n";
7896 pr " snprintf (strs[i*2], 16, \"%%d\", i);\n";
7897 pr " snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
7899 pr " strs[n*2] = NULL;\n";
7900 pr " return strs;\n"
7905 pr "/* Test error return. */\n";
7906 generate_prototype ~extern:false ~semicolon:false ~newline:true
7907 ~handle:"g" ~prefix:"guestfs_" name style;
7909 pr " error (g, \"error\");\n";
7910 (match fst style with
7911 | RErr | RInt _ | RInt64 _ | RBool _ ->
7914 | RString _ | RStringList _ | RIntBool _
7915 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7917 pr " return NULL;\n"
7924 and generate_ocaml_bindtests () =
7925 generate_header OCamlStyle GPLv2;
7929 let g = Guestfs.create () in
7936 | CallString s -> "\"" ^ s ^ "\""
7937 | CallOptString None -> "None"
7938 | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
7939 | CallStringList xs ->
7940 "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
7941 | CallInt i when i >= 0 -> string_of_int i
7942 | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
7943 | CallBool b -> string_of_bool b
7948 generate_lang_bindtests (
7949 fun f args -> pr " Guestfs.%s g %s;\n" f (mkargs args)
7952 pr "print_endline \"EOF\"\n"
7954 and generate_perl_bindtests () =
7955 pr "#!/usr/bin/perl -w\n";
7956 generate_header HashStyle GPLv2;
7963 my $g = Sys::Guestfs->new ();
7967 String.concat ", " (
7970 | CallString s -> "\"" ^ s ^ "\""
7971 | CallOptString None -> "undef"
7972 | CallOptString (Some s) -> sprintf "\"%s\"" s
7973 | CallStringList xs ->
7974 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7975 | CallInt i -> string_of_int i
7976 | CallBool b -> if b then "1" else "0"
7981 generate_lang_bindtests (
7982 fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
7985 pr "print \"EOF\\n\"\n"
7987 and generate_python_bindtests () =
7988 generate_header HashStyle GPLv2;
7993 g = guestfs.GuestFS ()
7997 String.concat ", " (
8000 | CallString s -> "\"" ^ s ^ "\""
8001 | CallOptString None -> "None"
8002 | CallOptString (Some s) -> sprintf "\"%s\"" s
8003 | CallStringList xs ->
8004 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8005 | CallInt i -> string_of_int i
8006 | CallBool b -> if b then "1" else "0"
8011 generate_lang_bindtests (
8012 fun f args -> pr "g.%s (%s)\n" f (mkargs args)
8015 pr "print \"EOF\"\n"
8017 and generate_ruby_bindtests () =
8018 generate_header HashStyle GPLv2;
8023 g = Guestfs::create()
8027 String.concat ", " (
8030 | CallString s -> "\"" ^ s ^ "\""
8031 | CallOptString None -> "nil"
8032 | CallOptString (Some s) -> sprintf "\"%s\"" s
8033 | CallStringList xs ->
8034 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8035 | CallInt i -> string_of_int i
8036 | CallBool b -> string_of_bool b
8041 generate_lang_bindtests (
8042 fun f args -> pr "g.%s(%s)\n" f (mkargs args)
8045 pr "print \"EOF\\n\"\n"
8047 and generate_java_bindtests () =
8048 generate_header CStyle GPLv2;
8051 import com.redhat.et.libguestfs.*;
8053 public class Bindtests {
8054 public static void main (String[] argv)
8057 GuestFS g = new GuestFS ();
8061 String.concat ", " (
8064 | CallString s -> "\"" ^ s ^ "\""
8065 | CallOptString None -> "null"
8066 | CallOptString (Some s) -> sprintf "\"%s\"" s
8067 | CallStringList xs ->
8069 String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
8070 | CallInt i -> string_of_int i
8071 | CallBool b -> string_of_bool b
8076 generate_lang_bindtests (
8077 fun f args -> pr " g.%s (%s);\n" f (mkargs args)
8081 System.out.println (\"EOF\");
8083 catch (Exception exn) {
8084 System.err.println (exn);
8091 and generate_haskell_bindtests () =
8092 generate_header HaskellStyle GPLv2;
8095 module Bindtests where
8096 import qualified Guestfs
8106 | CallString s -> "\"" ^ s ^ "\""
8107 | CallOptString None -> "Nothing"
8108 | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
8109 | CallStringList xs ->
8110 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8111 | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
8112 | CallInt i -> string_of_int i
8113 | CallBool true -> "True"
8114 | CallBool false -> "False"
8119 generate_lang_bindtests (
8120 fun f args -> pr " Guestfs.%s g %s\n" f (mkargs args)
8123 pr " putStrLn \"EOF\"\n"
8125 (* Language-independent bindings tests - we do it this way to
8126 * ensure there is parity in testing bindings across all languages.
8128 and generate_lang_bindtests call =
8129 call "test0" [CallString "abc"; CallOptString (Some "def");
8130 CallStringList []; CallBool false;
8131 CallInt 0; CallString "123"; CallString "456"];
8132 call "test0" [CallString "abc"; CallOptString None;
8133 CallStringList []; CallBool false;
8134 CallInt 0; CallString "123"; CallString "456"];
8135 call "test0" [CallString ""; CallOptString (Some "def");
8136 CallStringList []; CallBool false;
8137 CallInt 0; CallString "123"; CallString "456"];
8138 call "test0" [CallString ""; CallOptString (Some "");
8139 CallStringList []; CallBool false;
8140 CallInt 0; CallString "123"; CallString "456"];
8141 call "test0" [CallString "abc"; CallOptString (Some "def");
8142 CallStringList ["1"]; CallBool false;
8143 CallInt 0; CallString "123"; CallString "456"];
8144 call "test0" [CallString "abc"; CallOptString (Some "def");
8145 CallStringList ["1"; "2"]; CallBool false;
8146 CallInt 0; CallString "123"; CallString "456"];
8147 call "test0" [CallString "abc"; CallOptString (Some "def");
8148 CallStringList ["1"]; CallBool true;
8149 CallInt 0; CallString "123"; CallString "456"];
8150 call "test0" [CallString "abc"; CallOptString (Some "def");
8151 CallStringList ["1"]; CallBool false;
8152 CallInt (-1); CallString "123"; CallString "456"];
8153 call "test0" [CallString "abc"; CallOptString (Some "def");
8154 CallStringList ["1"]; CallBool false;
8155 CallInt (-2); CallString "123"; CallString "456"];
8156 call "test0" [CallString "abc"; CallOptString (Some "def");
8157 CallStringList ["1"]; CallBool false;
8158 CallInt 1; CallString "123"; CallString "456"];
8159 call "test0" [CallString "abc"; CallOptString (Some "def");
8160 CallStringList ["1"]; CallBool false;
8161 CallInt 2; CallString "123"; CallString "456"];
8162 call "test0" [CallString "abc"; CallOptString (Some "def");
8163 CallStringList ["1"]; CallBool false;
8164 CallInt 4095; CallString "123"; CallString "456"];
8165 call "test0" [CallString "abc"; CallOptString (Some "def");
8166 CallStringList ["1"]; CallBool false;
8167 CallInt 0; CallString ""; CallString ""]
8169 (* XXX Add here tests of the return and error functions. *)
8171 (* This is used to generate the src/MAX_PROC_NR file which
8172 * contains the maximum procedure number, a surrogate for the
8173 * ABI version number. See src/Makefile.am for the details.
8175 and generate_max_proc_nr () =
8176 let proc_nrs = List.map (
8177 fun (_, _, proc_nr, _, _, _, _) -> proc_nr
8178 ) daemon_functions in
8180 let max_proc_nr = List.fold_left max 0 proc_nrs in
8182 pr "%d\n" max_proc_nr
8184 let output_to filename =
8185 let filename_new = filename ^ ".new" in
8186 chan := open_out filename_new;
8191 (* Is the new file different from the current file? *)
8192 if Sys.file_exists filename && files_equal filename filename_new then
8193 Unix.unlink filename_new (* same, so skip it *)
8195 (* different, overwrite old one *)
8196 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
8197 Unix.rename filename_new filename;
8198 Unix.chmod filename 0o444;
8199 printf "written %s\n%!" filename;
8208 if not (Sys.file_exists "configure.ac") then (
8210 You are probably running this from the wrong directory.
8211 Run it from the top source directory using the command
8217 let close = output_to "src/guestfs_protocol.x" in
8221 let close = output_to "src/guestfs-structs.h" in
8222 generate_structs_h ();
8225 let close = output_to "src/guestfs-actions.h" in
8226 generate_actions_h ();
8229 let close = output_to "src/guestfs-actions.c" in
8230 generate_client_actions ();
8233 let close = output_to "daemon/actions.h" in
8234 generate_daemon_actions_h ();
8237 let close = output_to "daemon/stubs.c" in
8238 generate_daemon_actions ();
8241 let close = output_to "capitests/tests.c" in
8245 let close = output_to "src/guestfs-bindtests.c" in
8246 generate_bindtests ();
8249 let close = output_to "fish/cmds.c" in
8250 generate_fish_cmds ();
8253 let close = output_to "fish/completion.c" in
8254 generate_fish_completion ();
8257 let close = output_to "guestfs-structs.pod" in
8258 generate_structs_pod ();
8261 let close = output_to "guestfs-actions.pod" in
8262 generate_actions_pod ();
8265 let close = output_to "guestfish-actions.pod" in
8266 generate_fish_actions_pod ();
8269 let close = output_to "ocaml/guestfs.mli" in
8270 generate_ocaml_mli ();
8273 let close = output_to "ocaml/guestfs.ml" in
8274 generate_ocaml_ml ();
8277 let close = output_to "ocaml/guestfs_c_actions.c" in
8278 generate_ocaml_c ();
8281 let close = output_to "ocaml/bindtests.ml" in
8282 generate_ocaml_bindtests ();
8285 let close = output_to "perl/Guestfs.xs" in
8286 generate_perl_xs ();
8289 let close = output_to "perl/lib/Sys/Guestfs.pm" in
8290 generate_perl_pm ();
8293 let close = output_to "perl/bindtests.pl" in
8294 generate_perl_bindtests ();
8297 let close = output_to "python/guestfs-py.c" in
8298 generate_python_c ();
8301 let close = output_to "python/guestfs.py" in
8302 generate_python_py ();
8305 let close = output_to "python/bindtests.py" in
8306 generate_python_bindtests ();
8309 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
8313 let close = output_to "ruby/bindtests.rb" in
8314 generate_ruby_bindtests ();
8317 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
8318 generate_java_java ();
8321 let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
8322 generate_java_struct "PV" pv_cols;
8325 let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
8326 generate_java_struct "VG" vg_cols;
8329 let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
8330 generate_java_struct "LV" lv_cols;
8333 let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
8334 generate_java_struct "Stat" stat_cols;
8337 let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
8338 generate_java_struct "StatVFS" statvfs_cols;
8341 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
8345 let close = output_to "java/Bindtests.java" in
8346 generate_java_bindtests ();
8349 let close = output_to "haskell/Guestfs.hs" in
8350 generate_haskell_hs ();
8353 let close = output_to "haskell/Bindtests.hs" in
8354 generate_haskell_bindtests ();
8357 let close = output_to "src/MAX_PROC_NR" in
8358 generate_max_proc_nr ();