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 * If the appliance is running an older Linux kernel (eg. RHEL 5) then
147 * devices are named /dev/hda etc. To cope with this, the test suite
148 * adds some hairly logic to detect this case, and then automagically
149 * replaces all strings which match "/dev/sd.*" with "/dev/hd.*".
150 * When writing test cases you shouldn't have to worry about this
153 * Don't assume anything about the previous contents of the block
154 * devices. Use 'Init*' to create some initial scenarios.
156 * You can add a prerequisite clause to any individual test. This
157 * is a run-time check, which, if it fails, causes the test to be
158 * skipped. Useful if testing a command which might not work on
159 * all variations of libguestfs builds. A test that has prerequisite
160 * of 'Always' is run unconditionally.
162 * In addition, packagers can skip individual tests by setting the
163 * environment variables: eg:
164 * SKIP_TEST_<CMD>_<NUM>=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command)
165 * SKIP_TEST_<CMD>=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests)
167 type tests = (test_init * test_prereq * test) list
169 (* Run the command sequence and just expect nothing to fail. *)
171 (* Run the command sequence and expect the output of the final
172 * command to be the string.
174 | TestOutput of seq * string
175 (* Run the command sequence and expect the output of the final
176 * command to be the list of strings.
178 | TestOutputList of seq * string list
179 (* Run the command sequence and expect the output of the final
180 * command to be the integer.
182 | TestOutputInt of seq * int
183 (* Run the command sequence and expect the output of the final
184 * command to be a true value (!= 0 or != NULL).
186 | TestOutputTrue of seq
187 (* Run the command sequence and expect the output of the final
188 * command to be a false value (== 0 or == NULL, but not an error).
190 | TestOutputFalse of seq
191 (* Run the command sequence and expect the output of the final
192 * command to be a list of the given length (but don't care about
195 | TestOutputLength of seq * int
196 (* Run the command sequence and expect the output of the final
197 * command to be a structure.
199 | TestOutputStruct of seq * test_field_compare list
200 (* Run the command sequence and expect the final command (only)
203 | TestLastFail of seq
205 and test_field_compare =
206 | CompareWithInt of string * int
207 | CompareWithString of string * string
208 | CompareFieldsIntEq of string * string
209 | CompareFieldsStrEq of string * string
211 (* Test prerequisites. *)
213 (* Test always runs. *)
215 (* Test is currently disabled - eg. it fails, or it tests some
216 * unimplemented feature.
219 (* 'string' is some C code (a function body) that should return
220 * true or false. The test will run if the code returns true.
223 (* As for 'If' but the test runs _unless_ the code returns true. *)
226 (* Some initial scenarios for testing. *)
228 (* Do nothing, block devices could contain random stuff including
229 * LVM PVs, and some filesystems might be mounted. This is usually
233 (* Block devices are empty and no filesystems are mounted. *)
235 (* /dev/sda contains a single partition /dev/sda1, which is formatted
236 * as ext2, empty [except for lost+found] and mounted on /.
237 * /dev/sdb and /dev/sdc may have random content.
242 * /dev/sda1 (is a PV):
243 * /dev/VG/LV (size 8MB):
244 * formatted as ext2, empty [except for lost+found], mounted on /
245 * /dev/sdb and /dev/sdc may have random content.
249 (* Sequence of commands for testing. *)
251 and cmd = string list
253 (* Note about long descriptions: When referring to another
254 * action, use the format C<guestfs_other> (ie. the full name of
255 * the C function). This will be replaced as appropriate in other
258 * Apart from that, long descriptions are just perldoc paragraphs.
261 (* These test functions are used in the language binding tests. *)
263 let test_all_args = [
266 StringList "strlist";
273 let test_all_rets = [
274 (* except for RErr, which is tested thoroughly elsewhere *)
275 "test0rint", RInt "valout";
276 "test0rint64", RInt64 "valout";
277 "test0rbool", RBool "valout";
278 "test0rconststring", RConstString "valout";
279 "test0rstring", RString "valout";
280 "test0rstringlist", RStringList "valout";
281 "test0rintbool", RIntBool ("valout", "valout");
282 "test0rpvlist", RPVList "valout";
283 "test0rvglist", RVGList "valout";
284 "test0rlvlist", RLVList "valout";
285 "test0rstat", RStat "valout";
286 "test0rstatvfs", RStatVFS "valout";
287 "test0rhashtable", RHashtable "valout";
290 let test_functions = [
291 ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
293 "internal test function - do not use",
295 This is an internal test function which is used to test whether
296 the automatically generated bindings can handle every possible
297 parameter type correctly.
299 It echos the contents of each parameter to stdout.
301 You probably don't want to call this function.");
305 [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
307 "internal test function - do not use",
309 This is an internal test function which is used to test whether
310 the automatically generated bindings can handle every possible
311 return type correctly.
313 It converts string C<val> to the return type.
315 You probably don't want to call this function.");
316 (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
318 "internal test function - do not use",
320 This is an internal test function which is used to test whether
321 the automatically generated bindings can handle every possible
322 return type correctly.
324 This function always returns an error.
326 You probably don't want to call this function.")]
330 (* non_daemon_functions are any functions which don't get processed
331 * in the daemon, eg. functions for setting and getting local
332 * configuration values.
335 let non_daemon_functions = test_functions @ [
336 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
338 "launch the qemu subprocess",
340 Internally libguestfs is implemented by running a virtual machine
343 You should call this after configuring the handle
344 (eg. adding drives) but before performing any actions.");
346 ("wait_ready", (RErr, []), -1, [NotInFish],
348 "wait until the qemu subprocess launches",
350 Internally libguestfs is implemented by running a virtual machine
353 You should call this after C<guestfs_launch> to wait for the launch
356 ("kill_subprocess", (RErr, []), -1, [],
358 "kill the qemu subprocess",
360 This kills the qemu subprocess. You should never need to call this.");
362 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
364 "add an image to examine or modify",
366 This function adds a virtual machine disk image C<filename> to the
367 guest. The first time you call this function, the disk appears as IDE
368 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
371 You don't necessarily need to be root when using libguestfs. However
372 you obviously do need sufficient permissions to access the filename
373 for whatever operations you want to perform (ie. read access if you
374 just want to read the image or write access if you want to modify the
377 This is equivalent to the qemu parameter C<-drive file=filename>.
379 Note that this call checks for the existence of C<filename>. This
380 stops you from specifying other types of drive which are supported
381 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
382 the general C<guestfs_config> call instead.");
384 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
386 "add a CD-ROM disk image to examine",
388 This function adds a virtual CD-ROM disk image to the guest.
390 This is equivalent to the qemu parameter C<-cdrom filename>.
392 Note that this call checks for the existence of C<filename>. This
393 stops you from specifying other types of drive which are supported
394 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
395 the general C<guestfs_config> call instead.");
397 ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
399 "add a drive in snapshot mode (read-only)",
401 This adds a drive in snapshot mode, making it effectively
404 Note that writes to the device are allowed, and will be seen for
405 the duration of the guestfs handle, but they are written
406 to a temporary file which is discarded as soon as the guestfs
407 handle is closed. We don't currently have any method to enable
408 changes to be committed, although qemu can support this.
410 This is equivalent to the qemu parameter
411 C<-drive file=filename,snapshot=on>.
413 Note that this call checks for the existence of C<filename>. This
414 stops you from specifying other types of drive which are supported
415 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
416 the general C<guestfs_config> call instead.");
418 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
420 "add qemu parameters",
422 This can be used to add arbitrary qemu command line parameters
423 of the form C<-param value>. Actually it's not quite arbitrary - we
424 prevent you from setting some parameters which would interfere with
425 parameters that we use.
427 The first character of C<param> string must be a C<-> (dash).
429 C<value> can be NULL.");
431 ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
433 "set the qemu binary",
435 Set the qemu binary that we will use.
437 The default is chosen when the library was compiled by the
440 You can also override this by setting the C<LIBGUESTFS_QEMU>
441 environment variable.
443 Setting C<qemu> to C<NULL> restores the default qemu binary.");
445 ("get_qemu", (RConstString "qemu", []), -1, [],
447 "get the qemu binary",
449 Return the current qemu binary.
451 This is always non-NULL. If it wasn't set already, then this will
452 return the default qemu binary name.");
454 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
456 "set the search path",
458 Set the path that libguestfs searches for kernel and initrd.img.
460 The default is C<$libdir/guestfs> unless overridden by setting
461 C<LIBGUESTFS_PATH> environment variable.
463 Setting C<path> to C<NULL> restores the default path.");
465 ("get_path", (RConstString "path", []), -1, [],
467 "get the search path",
469 Return the current search path.
471 This is always non-NULL. If it wasn't set already, then this will
472 return the default path.");
474 ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
476 "add options to kernel command line",
478 This function is used to add additional options to the
479 guest kernel command line.
481 The default is C<NULL> unless overridden by setting
482 C<LIBGUESTFS_APPEND> environment variable.
484 Setting C<append> to C<NULL> means I<no> additional options
485 are passed (libguestfs always adds a few of its own).");
487 ("get_append", (RConstString "append", []), -1, [],
489 "get the additional kernel options",
491 Return the additional kernel options which are added to the
492 guest kernel command line.
494 If C<NULL> then no options are added.");
496 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
500 If C<autosync> is true, this enables autosync. Libguestfs will make a
501 best effort attempt to run C<guestfs_umount_all> followed by
502 C<guestfs_sync> when the handle is closed
503 (also if the program exits without closing handles).
505 This is disabled by default (except in guestfish where it is
506 enabled by default).");
508 ("get_autosync", (RBool "autosync", []), -1, [],
512 Get the autosync flag.");
514 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
518 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
520 Verbose messages are disabled unless the environment variable
521 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
523 ("get_verbose", (RBool "verbose", []), -1, [],
527 This returns the verbose messages flag.");
529 ("is_ready", (RBool "ready", []), -1, [],
531 "is ready to accept commands",
533 This returns true iff this handle is ready to accept commands
534 (in the C<READY> state).
536 For more information on states, see L<guestfs(3)>.");
538 ("is_config", (RBool "config", []), -1, [],
540 "is in configuration state",
542 This returns true iff this handle is being configured
543 (in the C<CONFIG> state).
545 For more information on states, see L<guestfs(3)>.");
547 ("is_launching", (RBool "launching", []), -1, [],
549 "is launching subprocess",
551 This returns true iff this handle is launching the subprocess
552 (in the C<LAUNCHING> state).
554 For more information on states, see L<guestfs(3)>.");
556 ("is_busy", (RBool "busy", []), -1, [],
558 "is busy processing a command",
560 This returns true iff this handle is busy processing a command
561 (in the C<BUSY> state).
563 For more information on states, see L<guestfs(3)>.");
565 ("get_state", (RInt "state", []), -1, [],
567 "get the current state",
569 This returns the current state as an opaque integer. This is
570 only useful for printing debug and internal error messages.
572 For more information on states, see L<guestfs(3)>.");
574 ("set_busy", (RErr, []), -1, [NotInFish],
578 This sets the state to C<BUSY>. This is only used when implementing
579 actions using the low-level API.
581 For more information on states, see L<guestfs(3)>.");
583 ("set_ready", (RErr, []), -1, [NotInFish],
585 "set state to ready",
587 This sets the state to C<READY>. This is only used when implementing
588 actions using the low-level API.
590 For more information on states, see L<guestfs(3)>.");
592 ("end_busy", (RErr, []), -1, [NotInFish],
594 "leave the busy state",
596 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
597 state as is. This is only used when implementing
598 actions using the low-level API.
600 For more information on states, see L<guestfs(3)>.");
604 (* daemon_functions are any functions which cause some action
605 * to take place in the daemon.
608 let daemon_functions = [
609 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
610 [InitEmpty, Always, TestOutput (
611 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
612 ["mkfs"; "ext2"; "/dev/sda1"];
613 ["mount"; "/dev/sda1"; "/"];
614 ["write_file"; "/new"; "new file contents"; "0"];
615 ["cat"; "/new"]], "new file contents")],
616 "mount a guest disk at a position in the filesystem",
618 Mount a guest disk at a position in the filesystem. Block devices
619 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
620 the guest. If those block devices contain partitions, they will have
621 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
624 The rules are the same as for L<mount(2)>: A filesystem must
625 first be mounted on C</> before others can be mounted. Other
626 filesystems can only be mounted on directories which already
629 The mounted filesystem is writable, if we have sufficient permissions
630 on the underlying device.
632 The filesystem options C<sync> and C<noatime> are set with this
633 call, in order to improve reliability.");
635 ("sync", (RErr, []), 2, [],
636 [ InitEmpty, Always, TestRun [["sync"]]],
637 "sync disks, writes are flushed through to the disk image",
639 This syncs the disk, so that any writes are flushed through to the
640 underlying disk image.
642 You should always call this if you have modified a disk image, before
643 closing the handle.");
645 ("touch", (RErr, [String "path"]), 3, [],
646 [InitBasicFS, Always, TestOutputTrue (
648 ["exists"; "/new"]])],
649 "update file timestamps or create a new file",
651 Touch acts like the L<touch(1)> command. It can be used to
652 update the timestamps on a file, or, if the file does not exist,
653 to create a new zero-length file.");
655 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
656 [InitBasicFS, Always, TestOutput (
657 [["write_file"; "/new"; "new file contents"; "0"];
658 ["cat"; "/new"]], "new file contents")],
659 "list the contents of a file",
661 Return the contents of the file named C<path>.
663 Note that this function cannot correctly handle binary files
664 (specifically, files containing C<\\0> character which is treated
665 as end of string). For those you need to use the C<guestfs_download>
666 function which has a more complex interface.");
668 ("ll", (RString "listing", [String "directory"]), 5, [],
669 [], (* XXX Tricky to test because it depends on the exact format
670 * of the 'ls -l' command, which changes between F10 and F11.
672 "list the files in a directory (long format)",
674 List the files in C<directory> (relative to the root directory,
675 there is no cwd) in the format of 'ls -la'.
677 This command is mostly useful for interactive sessions. It
678 is I<not> intended that you try to parse the output string.");
680 ("ls", (RStringList "listing", [String "directory"]), 6, [],
681 [InitBasicFS, Always, TestOutputList (
684 ["touch"; "/newest"];
685 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
686 "list the files in a directory",
688 List the files in C<directory> (relative to the root directory,
689 there is no cwd). The '.' and '..' entries are not returned, but
690 hidden files are shown.
692 This command is mostly useful for interactive sessions. Programs
693 should probably use C<guestfs_readdir> instead.");
695 ("list_devices", (RStringList "devices", []), 7, [],
696 [InitEmpty, Always, TestOutputList (
697 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
698 "list the block devices",
700 List all the block devices.
702 The full block device names are returned, eg. C</dev/sda>");
704 ("list_partitions", (RStringList "partitions", []), 8, [],
705 [InitBasicFS, Always, TestOutputList (
706 [["list_partitions"]], ["/dev/sda1"]);
707 InitEmpty, Always, TestOutputList (
708 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
709 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
710 "list the partitions",
712 List all the partitions detected on all block devices.
714 The full partition device names are returned, eg. C</dev/sda1>
716 This does not return logical volumes. For that you will need to
717 call C<guestfs_lvs>.");
719 ("pvs", (RStringList "physvols", []), 9, [],
720 [InitBasicFSonLVM, Always, TestOutputList (
721 [["pvs"]], ["/dev/sda1"]);
722 InitEmpty, Always, TestOutputList (
723 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
724 ["pvcreate"; "/dev/sda1"];
725 ["pvcreate"; "/dev/sda2"];
726 ["pvcreate"; "/dev/sda3"];
727 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
728 "list the LVM physical volumes (PVs)",
730 List all the physical volumes detected. This is the equivalent
731 of the L<pvs(8)> command.
733 This returns a list of just the device names that contain
734 PVs (eg. C</dev/sda2>).
736 See also C<guestfs_pvs_full>.");
738 ("vgs", (RStringList "volgroups", []), 10, [],
739 [InitBasicFSonLVM, Always, TestOutputList (
741 InitEmpty, Always, TestOutputList (
742 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
743 ["pvcreate"; "/dev/sda1"];
744 ["pvcreate"; "/dev/sda2"];
745 ["pvcreate"; "/dev/sda3"];
746 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
747 ["vgcreate"; "VG2"; "/dev/sda3"];
748 ["vgs"]], ["VG1"; "VG2"])],
749 "list the LVM volume groups (VGs)",
751 List all the volumes groups detected. This is the equivalent
752 of the L<vgs(8)> command.
754 This returns a list of just the volume group names that were
755 detected (eg. C<VolGroup00>).
757 See also C<guestfs_vgs_full>.");
759 ("lvs", (RStringList "logvols", []), 11, [],
760 [InitBasicFSonLVM, Always, TestOutputList (
761 [["lvs"]], ["/dev/VG/LV"]);
762 InitEmpty, Always, TestOutputList (
763 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
764 ["pvcreate"; "/dev/sda1"];
765 ["pvcreate"; "/dev/sda2"];
766 ["pvcreate"; "/dev/sda3"];
767 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
768 ["vgcreate"; "VG2"; "/dev/sda3"];
769 ["lvcreate"; "LV1"; "VG1"; "50"];
770 ["lvcreate"; "LV2"; "VG1"; "50"];
771 ["lvcreate"; "LV3"; "VG2"; "50"];
772 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
773 "list the LVM logical volumes (LVs)",
775 List all the logical volumes detected. This is the equivalent
776 of the L<lvs(8)> command.
778 This returns a list of the logical volume device names
779 (eg. C</dev/VolGroup00/LogVol00>).
781 See also C<guestfs_lvs_full>.");
783 ("pvs_full", (RPVList "physvols", []), 12, [],
784 [], (* XXX how to test? *)
785 "list the LVM physical volumes (PVs)",
787 List all the physical volumes detected. This is the equivalent
788 of the L<pvs(8)> command. The \"full\" version includes all fields.");
790 ("vgs_full", (RVGList "volgroups", []), 13, [],
791 [], (* XXX how to test? *)
792 "list the LVM volume groups (VGs)",
794 List all the volumes groups detected. This is the equivalent
795 of the L<vgs(8)> command. The \"full\" version includes all fields.");
797 ("lvs_full", (RLVList "logvols", []), 14, [],
798 [], (* XXX how to test? *)
799 "list the LVM logical volumes (LVs)",
801 List all the logical volumes detected. This is the equivalent
802 of the L<lvs(8)> command. The \"full\" version includes all fields.");
804 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
805 [InitBasicFS, Always, TestOutputList (
806 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
807 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
808 InitBasicFS, Always, TestOutputList (
809 [["write_file"; "/new"; ""; "0"];
810 ["read_lines"; "/new"]], [])],
811 "read file as lines",
813 Return the contents of the file named C<path>.
815 The file contents are returned as a list of lines. Trailing
816 C<LF> and C<CRLF> character sequences are I<not> returned.
818 Note that this function cannot correctly handle binary files
819 (specifically, files containing C<\\0> character which is treated
820 as end of line). For those you need to use the C<guestfs_read_file>
821 function which has a more complex interface.");
823 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
824 [], (* XXX Augeas code needs tests. *)
825 "create a new Augeas handle",
827 Create a new Augeas handle for editing configuration files.
828 If there was any previous Augeas handle associated with this
829 guestfs session, then it is closed.
831 You must call this before using any other C<guestfs_aug_*>
834 C<root> is the filesystem root. C<root> must not be NULL,
837 The flags are the same as the flags defined in
838 E<lt>augeas.hE<gt>, the logical I<or> of the following
843 =item C<AUG_SAVE_BACKUP> = 1
845 Keep the original file with a C<.augsave> extension.
847 =item C<AUG_SAVE_NEWFILE> = 2
849 Save changes into a file with extension C<.augnew>, and
850 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
852 =item C<AUG_TYPE_CHECK> = 4
854 Typecheck lenses (can be expensive).
856 =item C<AUG_NO_STDINC> = 8
858 Do not use standard load path for modules.
860 =item C<AUG_SAVE_NOOP> = 16
862 Make save a no-op, just record what would have been changed.
864 =item C<AUG_NO_LOAD> = 32
866 Do not load the tree in C<guestfs_aug_init>.
870 To close the handle, you can call C<guestfs_aug_close>.
872 To find out more about Augeas, see L<http://augeas.net/>.");
874 ("aug_close", (RErr, []), 26, [],
875 [], (* XXX Augeas code needs tests. *)
876 "close the current Augeas handle",
878 Close the current Augeas handle and free up any resources
879 used by it. After calling this, you have to call
880 C<guestfs_aug_init> again before you can use any other
883 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
884 [], (* XXX Augeas code needs tests. *)
885 "define an Augeas variable",
887 Defines an Augeas variable C<name> whose value is the result
888 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
891 On success this returns the number of nodes in C<expr>, or
892 C<0> if C<expr> evaluates to something which is not a nodeset.");
894 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
895 [], (* XXX Augeas code needs tests. *)
896 "define an Augeas node",
898 Defines a variable C<name> whose value is the result of
901 If C<expr> evaluates to an empty nodeset, a node is created,
902 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
903 C<name> will be the nodeset containing that single node.
905 On success this returns a pair containing the
906 number of nodes in the nodeset, and a boolean flag
907 if a node was created.");
909 ("aug_get", (RString "val", [String "path"]), 19, [],
910 [], (* XXX Augeas code needs tests. *)
911 "look up the value of an Augeas path",
913 Look up the value associated with C<path>. If C<path>
914 matches exactly one node, the C<value> is returned.");
916 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
917 [], (* XXX Augeas code needs tests. *)
918 "set Augeas path to value",
920 Set the value associated with C<path> to C<value>.");
922 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
923 [], (* XXX Augeas code needs tests. *)
924 "insert a sibling Augeas node",
926 Create a new sibling C<label> for C<path>, inserting it into
927 the tree before or after C<path> (depending on the boolean
930 C<path> must match exactly one existing node in the tree, and
931 C<label> must be a label, ie. not contain C</>, C<*> or end
932 with a bracketed index C<[N]>.");
934 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
935 [], (* XXX Augeas code needs tests. *)
936 "remove an Augeas path",
938 Remove C<path> and all of its children.
940 On success this returns the number of entries which were removed.");
942 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
943 [], (* XXX Augeas code needs tests. *)
946 Move the node C<src> to C<dest>. C<src> must match exactly
947 one node. C<dest> is overwritten if it exists.");
949 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
950 [], (* XXX Augeas code needs tests. *)
951 "return Augeas nodes which match path",
953 Returns a list of paths which match the path expression C<path>.
954 The returned paths are sufficiently qualified so that they match
955 exactly one node in the current tree.");
957 ("aug_save", (RErr, []), 25, [],
958 [], (* XXX Augeas code needs tests. *)
959 "write all pending Augeas changes to disk",
961 This writes all pending changes to disk.
963 The flags which were passed to C<guestfs_aug_init> affect exactly
964 how files are saved.");
966 ("aug_load", (RErr, []), 27, [],
967 [], (* XXX Augeas code needs tests. *)
968 "load files into the tree",
970 Load files into the tree.
972 See C<aug_load> in the Augeas documentation for the full gory
975 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
976 [], (* XXX Augeas code needs tests. *)
977 "list Augeas nodes under a path",
979 This is just a shortcut for listing C<guestfs_aug_match>
980 C<path/*> and sorting the resulting nodes into alphabetical order.");
982 ("rm", (RErr, [String "path"]), 29, [],
983 [InitBasicFS, Always, TestRun
986 InitBasicFS, Always, TestLastFail
988 InitBasicFS, Always, TestLastFail
993 Remove the single file C<path>.");
995 ("rmdir", (RErr, [String "path"]), 30, [],
996 [InitBasicFS, Always, TestRun
999 InitBasicFS, Always, TestLastFail
1000 [["rmdir"; "/new"]];
1001 InitBasicFS, Always, TestLastFail
1003 ["rmdir"; "/new"]]],
1004 "remove a directory",
1006 Remove the single directory C<path>.");
1008 ("rm_rf", (RErr, [String "path"]), 31, [],
1009 [InitBasicFS, Always, TestOutputFalse
1011 ["mkdir"; "/new/foo"];
1012 ["touch"; "/new/foo/bar"];
1014 ["exists"; "/new"]]],
1015 "remove a file or directory recursively",
1017 Remove the file or directory C<path>, recursively removing the
1018 contents if its a directory. This is like the C<rm -rf> shell
1021 ("mkdir", (RErr, [String "path"]), 32, [],
1022 [InitBasicFS, Always, TestOutputTrue
1024 ["is_dir"; "/new"]];
1025 InitBasicFS, Always, TestLastFail
1026 [["mkdir"; "/new/foo/bar"]]],
1027 "create a directory",
1029 Create a directory named C<path>.");
1031 ("mkdir_p", (RErr, [String "path"]), 33, [],
1032 [InitBasicFS, Always, TestOutputTrue
1033 [["mkdir_p"; "/new/foo/bar"];
1034 ["is_dir"; "/new/foo/bar"]];
1035 InitBasicFS, Always, TestOutputTrue
1036 [["mkdir_p"; "/new/foo/bar"];
1037 ["is_dir"; "/new/foo"]];
1038 InitBasicFS, Always, TestOutputTrue
1039 [["mkdir_p"; "/new/foo/bar"];
1040 ["is_dir"; "/new"]];
1041 (* Regression tests for RHBZ#503133: *)
1042 InitBasicFS, Always, TestRun
1044 ["mkdir_p"; "/new"]];
1045 InitBasicFS, Always, TestLastFail
1047 ["mkdir_p"; "/new"]]],
1048 "create a directory and parents",
1050 Create a directory named C<path>, creating any parent directories
1051 as necessary. This is like the C<mkdir -p> shell command.");
1053 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1054 [], (* XXX Need stat command to test *)
1057 Change the mode (permissions) of C<path> to C<mode>. Only
1058 numeric modes are supported.");
1060 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1061 [], (* XXX Need stat command to test *)
1062 "change file owner and group",
1064 Change the file owner to C<owner> and group to C<group>.
1066 Only numeric uid and gid are supported. If you want to use
1067 names, you will need to locate and parse the password file
1068 yourself (Augeas support makes this relatively easy).");
1070 ("exists", (RBool "existsflag", [String "path"]), 36, [],
1071 [InitBasicFS, Always, TestOutputTrue (
1073 ["exists"; "/new"]]);
1074 InitBasicFS, Always, TestOutputTrue (
1076 ["exists"; "/new"]])],
1077 "test if file or directory exists",
1079 This returns C<true> if and only if there is a file, directory
1080 (or anything) with the given C<path> name.
1082 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1084 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1085 [InitBasicFS, Always, TestOutputTrue (
1087 ["is_file"; "/new"]]);
1088 InitBasicFS, Always, TestOutputFalse (
1090 ["is_file"; "/new"]])],
1091 "test if file exists",
1093 This returns C<true> if and only if there is a file
1094 with the given C<path> name. Note that it returns false for
1095 other objects like directories.
1097 See also C<guestfs_stat>.");
1099 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1100 [InitBasicFS, Always, TestOutputFalse (
1102 ["is_dir"; "/new"]]);
1103 InitBasicFS, Always, TestOutputTrue (
1105 ["is_dir"; "/new"]])],
1106 "test if file exists",
1108 This returns C<true> if and only if there is a directory
1109 with the given C<path> name. Note that it returns false for
1110 other objects like files.
1112 See also C<guestfs_stat>.");
1114 ("pvcreate", (RErr, [String "device"]), 39, [],
1115 [InitEmpty, Always, TestOutputList (
1116 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1117 ["pvcreate"; "/dev/sda1"];
1118 ["pvcreate"; "/dev/sda2"];
1119 ["pvcreate"; "/dev/sda3"];
1120 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1121 "create an LVM physical volume",
1123 This creates an LVM physical volume on the named C<device>,
1124 where C<device> should usually be a partition name such
1127 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1128 [InitEmpty, Always, TestOutputList (
1129 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1130 ["pvcreate"; "/dev/sda1"];
1131 ["pvcreate"; "/dev/sda2"];
1132 ["pvcreate"; "/dev/sda3"];
1133 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1134 ["vgcreate"; "VG2"; "/dev/sda3"];
1135 ["vgs"]], ["VG1"; "VG2"])],
1136 "create an LVM volume group",
1138 This creates an LVM volume group called C<volgroup>
1139 from the non-empty list of physical volumes C<physvols>.");
1141 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1142 [InitEmpty, Always, TestOutputList (
1143 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1144 ["pvcreate"; "/dev/sda1"];
1145 ["pvcreate"; "/dev/sda2"];
1146 ["pvcreate"; "/dev/sda3"];
1147 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1148 ["vgcreate"; "VG2"; "/dev/sda3"];
1149 ["lvcreate"; "LV1"; "VG1"; "50"];
1150 ["lvcreate"; "LV2"; "VG1"; "50"];
1151 ["lvcreate"; "LV3"; "VG2"; "50"];
1152 ["lvcreate"; "LV4"; "VG2"; "50"];
1153 ["lvcreate"; "LV5"; "VG2"; "50"];
1155 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1156 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1157 "create an LVM volume group",
1159 This creates an LVM volume group called C<logvol>
1160 on the volume group C<volgroup>, with C<size> megabytes.");
1162 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1163 [InitEmpty, Always, TestOutput (
1164 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1165 ["mkfs"; "ext2"; "/dev/sda1"];
1166 ["mount"; "/dev/sda1"; "/"];
1167 ["write_file"; "/new"; "new file contents"; "0"];
1168 ["cat"; "/new"]], "new file contents")],
1169 "make a filesystem",
1171 This creates a filesystem on C<device> (usually a partition
1172 or LVM logical volume). The filesystem type is C<fstype>, for
1175 ("sfdisk", (RErr, [String "device";
1176 Int "cyls"; Int "heads"; Int "sectors";
1177 StringList "lines"]), 43, [DangerWillRobinson],
1179 "create partitions on a block device",
1181 This is a direct interface to the L<sfdisk(8)> program for creating
1182 partitions on block devices.
1184 C<device> should be a block device, for example C</dev/sda>.
1186 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1187 and sectors on the device, which are passed directly to sfdisk as
1188 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
1189 of these, then the corresponding parameter is omitted. Usually for
1190 'large' disks, you can just pass C<0> for these, but for small
1191 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1192 out the right geometry and you will need to tell it.
1194 C<lines> is a list of lines that we feed to C<sfdisk>. For more
1195 information refer to the L<sfdisk(8)> manpage.
1197 To create a single partition occupying the whole disk, you would
1198 pass C<lines> as a single element list, when the single element being
1199 the string C<,> (comma).
1201 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1203 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1204 [InitBasicFS, Always, TestOutput (
1205 [["write_file"; "/new"; "new file contents"; "0"];
1206 ["cat"; "/new"]], "new file contents");
1207 InitBasicFS, Always, TestOutput (
1208 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1209 ["cat"; "/new"]], "\nnew file contents\n");
1210 InitBasicFS, Always, TestOutput (
1211 [["write_file"; "/new"; "\n\n"; "0"];
1212 ["cat"; "/new"]], "\n\n");
1213 InitBasicFS, Always, TestOutput (
1214 [["write_file"; "/new"; ""; "0"];
1215 ["cat"; "/new"]], "");
1216 InitBasicFS, Always, TestOutput (
1217 [["write_file"; "/new"; "\n\n\n"; "0"];
1218 ["cat"; "/new"]], "\n\n\n");
1219 InitBasicFS, Always, TestOutput (
1220 [["write_file"; "/new"; "\n"; "0"];
1221 ["cat"; "/new"]], "\n")],
1224 This call creates a file called C<path>. The contents of the
1225 file is the string C<content> (which can contain any 8 bit data),
1226 with length C<size>.
1228 As a special case, if C<size> is C<0>
1229 then the length is calculated using C<strlen> (so in this case
1230 the content cannot contain embedded ASCII NULs).
1232 I<NB.> Owing to a bug, writing content containing ASCII NUL
1233 characters does I<not> work, even if the length is specified.
1234 We hope to resolve this bug in a future version. In the meantime
1235 use C<guestfs_upload>.");
1237 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1238 [InitEmpty, Always, TestOutputList (
1239 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1240 ["mkfs"; "ext2"; "/dev/sda1"];
1241 ["mount"; "/dev/sda1"; "/"];
1242 ["mounts"]], ["/dev/sda1"]);
1243 InitEmpty, Always, TestOutputList (
1244 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1245 ["mkfs"; "ext2"; "/dev/sda1"];
1246 ["mount"; "/dev/sda1"; "/"];
1249 "unmount a filesystem",
1251 This unmounts the given filesystem. The filesystem may be
1252 specified either by its mountpoint (path) or the device which
1253 contains the filesystem.");
1255 ("mounts", (RStringList "devices", []), 46, [],
1256 [InitBasicFS, Always, TestOutputList (
1257 [["mounts"]], ["/dev/sda1"])],
1258 "show mounted filesystems",
1260 This returns the list of currently mounted filesystems. It returns
1261 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1263 Some internal mounts are not shown.");
1265 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1266 [InitBasicFS, Always, TestOutputList (
1269 (* check that umount_all can unmount nested mounts correctly: *)
1270 InitEmpty, Always, TestOutputList (
1271 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1272 ["mkfs"; "ext2"; "/dev/sda1"];
1273 ["mkfs"; "ext2"; "/dev/sda2"];
1274 ["mkfs"; "ext2"; "/dev/sda3"];
1275 ["mount"; "/dev/sda1"; "/"];
1277 ["mount"; "/dev/sda2"; "/mp1"];
1278 ["mkdir"; "/mp1/mp2"];
1279 ["mount"; "/dev/sda3"; "/mp1/mp2"];
1280 ["mkdir"; "/mp1/mp2/mp3"];
1283 "unmount all filesystems",
1285 This unmounts all mounted filesystems.
1287 Some internal mounts are not unmounted by this call.");
1289 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1291 "remove all LVM LVs, VGs and PVs",
1293 This command removes all LVM logical volumes, volume groups
1294 and physical volumes.");
1296 ("file", (RString "description", [String "path"]), 49, [],
1297 [InitBasicFS, Always, TestOutput (
1299 ["file"; "/new"]], "empty");
1300 InitBasicFS, Always, TestOutput (
1301 [["write_file"; "/new"; "some content\n"; "0"];
1302 ["file"; "/new"]], "ASCII text");
1303 InitBasicFS, Always, TestLastFail (
1304 [["file"; "/nofile"]])],
1305 "determine file type",
1307 This call uses the standard L<file(1)> command to determine
1308 the type or contents of the file. This also works on devices,
1309 for example to find out whether a partition contains a filesystem.
1311 The exact command which runs is C<file -bsL path>. Note in
1312 particular that the filename is not prepended to the output
1313 (the C<-b> option).");
1315 ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1316 [InitBasicFS, Always, TestOutput (
1317 [["upload"; "test-command"; "/test-command"];
1318 ["chmod"; "493"; "/test-command"];
1319 ["command"; "/test-command 1"]], "Result1");
1320 InitBasicFS, Always, TestOutput (
1321 [["upload"; "test-command"; "/test-command"];
1322 ["chmod"; "493"; "/test-command"];
1323 ["command"; "/test-command 2"]], "Result2\n");
1324 InitBasicFS, Always, TestOutput (
1325 [["upload"; "test-command"; "/test-command"];
1326 ["chmod"; "493"; "/test-command"];
1327 ["command"; "/test-command 3"]], "\nResult3");
1328 InitBasicFS, Always, TestOutput (
1329 [["upload"; "test-command"; "/test-command"];
1330 ["chmod"; "493"; "/test-command"];
1331 ["command"; "/test-command 4"]], "\nResult4\n");
1332 InitBasicFS, Always, TestOutput (
1333 [["upload"; "test-command"; "/test-command"];
1334 ["chmod"; "493"; "/test-command"];
1335 ["command"; "/test-command 5"]], "\nResult5\n\n");
1336 InitBasicFS, Always, TestOutput (
1337 [["upload"; "test-command"; "/test-command"];
1338 ["chmod"; "493"; "/test-command"];
1339 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1340 InitBasicFS, Always, TestOutput (
1341 [["upload"; "test-command"; "/test-command"];
1342 ["chmod"; "493"; "/test-command"];
1343 ["command"; "/test-command 7"]], "");
1344 InitBasicFS, Always, TestOutput (
1345 [["upload"; "test-command"; "/test-command"];
1346 ["chmod"; "493"; "/test-command"];
1347 ["command"; "/test-command 8"]], "\n");
1348 InitBasicFS, Always, TestOutput (
1349 [["upload"; "test-command"; "/test-command"];
1350 ["chmod"; "493"; "/test-command"];
1351 ["command"; "/test-command 9"]], "\n\n");
1352 InitBasicFS, Always, TestOutput (
1353 [["upload"; "test-command"; "/test-command"];
1354 ["chmod"; "493"; "/test-command"];
1355 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1356 InitBasicFS, Always, TestOutput (
1357 [["upload"; "test-command"; "/test-command"];
1358 ["chmod"; "493"; "/test-command"];
1359 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1360 InitBasicFS, Always, TestLastFail (
1361 [["upload"; "test-command"; "/test-command"];
1362 ["chmod"; "493"; "/test-command"];
1363 ["command"; "/test-command"]])],
1364 "run a command from the guest filesystem",
1366 This call runs a command from the guest filesystem. The
1367 filesystem must be mounted, and must contain a compatible
1368 operating system (ie. something Linux, with the same
1369 or compatible processor architecture).
1371 The single parameter is an argv-style list of arguments.
1372 The first element is the name of the program to run.
1373 Subsequent elements are parameters. The list must be
1374 non-empty (ie. must contain a program name).
1376 The return value is anything printed to I<stdout> by
1379 If the command returns a non-zero exit status, then
1380 this function returns an error message. The error message
1381 string is the content of I<stderr> from the command.
1383 The C<$PATH> environment variable will contain at least
1384 C</usr/bin> and C</bin>. If you require a program from
1385 another location, you should provide the full path in the
1388 Shared libraries and data files required by the program
1389 must be available on filesystems which are mounted in the
1390 correct places. It is the caller's responsibility to ensure
1391 all filesystems that are needed are mounted at the right
1394 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1395 [InitBasicFS, Always, TestOutputList (
1396 [["upload"; "test-command"; "/test-command"];
1397 ["chmod"; "493"; "/test-command"];
1398 ["command_lines"; "/test-command 1"]], ["Result1"]);
1399 InitBasicFS, Always, TestOutputList (
1400 [["upload"; "test-command"; "/test-command"];
1401 ["chmod"; "493"; "/test-command"];
1402 ["command_lines"; "/test-command 2"]], ["Result2"]);
1403 InitBasicFS, Always, TestOutputList (
1404 [["upload"; "test-command"; "/test-command"];
1405 ["chmod"; "493"; "/test-command"];
1406 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1407 InitBasicFS, Always, TestOutputList (
1408 [["upload"; "test-command"; "/test-command"];
1409 ["chmod"; "493"; "/test-command"];
1410 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1411 InitBasicFS, Always, TestOutputList (
1412 [["upload"; "test-command"; "/test-command"];
1413 ["chmod"; "493"; "/test-command"];
1414 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1415 InitBasicFS, Always, TestOutputList (
1416 [["upload"; "test-command"; "/test-command"];
1417 ["chmod"; "493"; "/test-command"];
1418 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1419 InitBasicFS, Always, TestOutputList (
1420 [["upload"; "test-command"; "/test-command"];
1421 ["chmod"; "493"; "/test-command"];
1422 ["command_lines"; "/test-command 7"]], []);
1423 InitBasicFS, Always, TestOutputList (
1424 [["upload"; "test-command"; "/test-command"];
1425 ["chmod"; "493"; "/test-command"];
1426 ["command_lines"; "/test-command 8"]], [""]);
1427 InitBasicFS, Always, TestOutputList (
1428 [["upload"; "test-command"; "/test-command"];
1429 ["chmod"; "493"; "/test-command"];
1430 ["command_lines"; "/test-command 9"]], ["";""]);
1431 InitBasicFS, Always, TestOutputList (
1432 [["upload"; "test-command"; "/test-command"];
1433 ["chmod"; "493"; "/test-command"];
1434 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1435 InitBasicFS, Always, TestOutputList (
1436 [["upload"; "test-command"; "/test-command"];
1437 ["chmod"; "493"; "/test-command"];
1438 ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1439 "run a command, returning lines",
1441 This is the same as C<guestfs_command>, but splits the
1442 result into a list of lines.");
1444 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1445 [InitBasicFS, Always, TestOutputStruct (
1447 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1448 "get file information",
1450 Returns file information for the given C<path>.
1452 This is the same as the C<stat(2)> system call.");
1454 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1455 [InitBasicFS, Always, TestOutputStruct (
1457 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1458 "get file information for a symbolic link",
1460 Returns file information for the given C<path>.
1462 This is the same as C<guestfs_stat> except that if C<path>
1463 is a symbolic link, then the link is stat-ed, not the file it
1466 This is the same as the C<lstat(2)> system call.");
1468 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1469 [InitBasicFS, Always, TestOutputStruct (
1470 [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1471 CompareWithInt ("blocks", 490020);
1472 CompareWithInt ("bsize", 1024)])],
1473 "get file system statistics",
1475 Returns file system statistics for any mounted file system.
1476 C<path> should be a file or directory in the mounted file system
1477 (typically it is the mount point itself, but it doesn't need to be).
1479 This is the same as the C<statvfs(2)> system call.");
1481 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1483 "get ext2/ext3/ext4 superblock details",
1485 This returns the contents of the ext2, ext3 or ext4 filesystem
1486 superblock on C<device>.
1488 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1489 manpage for more details. The list of fields returned isn't
1490 clearly defined, and depends on both the version of C<tune2fs>
1491 that libguestfs was built against, and the filesystem itself.");
1493 ("blockdev_setro", (RErr, [String "device"]), 56, [],
1494 [InitEmpty, Always, TestOutputTrue (
1495 [["blockdev_setro"; "/dev/sda"];
1496 ["blockdev_getro"; "/dev/sda"]])],
1497 "set block device to read-only",
1499 Sets the block device named C<device> to read-only.
1501 This uses the L<blockdev(8)> command.");
1503 ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1504 [InitEmpty, Always, TestOutputFalse (
1505 [["blockdev_setrw"; "/dev/sda"];
1506 ["blockdev_getro"; "/dev/sda"]])],
1507 "set block device to read-write",
1509 Sets the block device named C<device> to read-write.
1511 This uses the L<blockdev(8)> command.");
1513 ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1514 [InitEmpty, Always, TestOutputTrue (
1515 [["blockdev_setro"; "/dev/sda"];
1516 ["blockdev_getro"; "/dev/sda"]])],
1517 "is block device set to read-only",
1519 Returns a boolean indicating if the block device is read-only
1520 (true if read-only, false if not).
1522 This uses the L<blockdev(8)> command.");
1524 ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1525 [InitEmpty, Always, TestOutputInt (
1526 [["blockdev_getss"; "/dev/sda"]], 512)],
1527 "get sectorsize of block device",
1529 This returns the size of sectors on a block device.
1530 Usually 512, but can be larger for modern devices.
1532 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1535 This uses the L<blockdev(8)> command.");
1537 ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1538 [InitEmpty, Always, TestOutputInt (
1539 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1540 "get blocksize of block device",
1542 This returns the block size of a device.
1544 (Note this is different from both I<size in blocks> and
1545 I<filesystem block size>).
1547 This uses the L<blockdev(8)> command.");
1549 ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1551 "set blocksize of block device",
1553 This sets the block size of a device.
1555 (Note this is different from both I<size in blocks> and
1556 I<filesystem block size>).
1558 This uses the L<blockdev(8)> command.");
1560 ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1561 [InitEmpty, Always, TestOutputInt (
1562 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1563 "get total size of device in 512-byte sectors",
1565 This returns the size of the device in units of 512-byte sectors
1566 (even if the sectorsize isn't 512 bytes ... weird).
1568 See also C<guestfs_blockdev_getss> for the real sector size of
1569 the device, and C<guestfs_blockdev_getsize64> for the more
1570 useful I<size in bytes>.
1572 This uses the L<blockdev(8)> command.");
1574 ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1575 [InitEmpty, Always, TestOutputInt (
1576 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1577 "get total size of device in bytes",
1579 This returns the size of the device in bytes.
1581 See also C<guestfs_blockdev_getsz>.
1583 This uses the L<blockdev(8)> command.");
1585 ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1586 [InitEmpty, Always, TestRun
1587 [["blockdev_flushbufs"; "/dev/sda"]]],
1588 "flush device buffers",
1590 This tells the kernel to flush internal buffers associated
1593 This uses the L<blockdev(8)> command.");
1595 ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1596 [InitEmpty, Always, TestRun
1597 [["blockdev_rereadpt"; "/dev/sda"]]],
1598 "reread partition table",
1600 Reread the partition table on C<device>.
1602 This uses the L<blockdev(8)> command.");
1604 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1605 [InitBasicFS, Always, TestOutput (
1606 (* Pick a file from cwd which isn't likely to change. *)
1607 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1608 ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1609 "upload a file from the local machine",
1611 Upload local file C<filename> to C<remotefilename> on the
1614 C<filename> can also be a named pipe.
1616 See also C<guestfs_download>.");
1618 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1619 [InitBasicFS, Always, TestOutput (
1620 (* Pick a file from cwd which isn't likely to change. *)
1621 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1622 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1623 ["upload"; "testdownload.tmp"; "/upload"];
1624 ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1625 "download a file to the local machine",
1627 Download file C<remotefilename> and save it as C<filename>
1628 on the local machine.
1630 C<filename> can also be a named pipe.
1632 See also C<guestfs_upload>, C<guestfs_cat>.");
1634 ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1635 [InitBasicFS, Always, TestOutput (
1636 [["write_file"; "/new"; "test\n"; "0"];
1637 ["checksum"; "crc"; "/new"]], "935282863");
1638 InitBasicFS, Always, TestLastFail (
1639 [["checksum"; "crc"; "/new"]]);
1640 InitBasicFS, Always, TestOutput (
1641 [["write_file"; "/new"; "test\n"; "0"];
1642 ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1643 InitBasicFS, Always, TestOutput (
1644 [["write_file"; "/new"; "test\n"; "0"];
1645 ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1646 InitBasicFS, Always, TestOutput (
1647 [["write_file"; "/new"; "test\n"; "0"];
1648 ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1649 InitBasicFS, Always, TestOutput (
1650 [["write_file"; "/new"; "test\n"; "0"];
1651 ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1652 InitBasicFS, Always, TestOutput (
1653 [["write_file"; "/new"; "test\n"; "0"];
1654 ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1655 InitBasicFS, Always, TestOutput (
1656 [["write_file"; "/new"; "test\n"; "0"];
1657 ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
1658 InitBasicFS, Always, TestOutput (
1659 [["mount"; "/dev/sdd"; "/"];
1660 ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
1661 "compute MD5, SHAx or CRC checksum of file",
1663 This call computes the MD5, SHAx or CRC checksum of the
1666 The type of checksum to compute is given by the C<csumtype>
1667 parameter which must have one of the following values:
1673 Compute the cyclic redundancy check (CRC) specified by POSIX
1674 for the C<cksum> command.
1678 Compute the MD5 hash (using the C<md5sum> program).
1682 Compute the SHA1 hash (using the C<sha1sum> program).
1686 Compute the SHA224 hash (using the C<sha224sum> program).
1690 Compute the SHA256 hash (using the C<sha256sum> program).
1694 Compute the SHA384 hash (using the C<sha384sum> program).
1698 Compute the SHA512 hash (using the C<sha512sum> program).
1702 The checksum is returned as a printable string.");
1704 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1705 [InitBasicFS, Always, TestOutput (
1706 [["tar_in"; "../images/helloworld.tar"; "/"];
1707 ["cat"; "/hello"]], "hello\n")],
1708 "unpack tarfile to directory",
1710 This command uploads and unpacks local file C<tarfile> (an
1711 I<uncompressed> tar file) into C<directory>.
1713 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1715 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1717 "pack directory into tarfile",
1719 This command packs the contents of C<directory> and downloads
1720 it to local file C<tarfile>.
1722 To download a compressed tarball, use C<guestfs_tgz_out>.");
1724 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1725 [InitBasicFS, Always, TestOutput (
1726 [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1727 ["cat"; "/hello"]], "hello\n")],
1728 "unpack compressed tarball to directory",
1730 This command uploads and unpacks local file C<tarball> (a
1731 I<gzip compressed> tar file) into C<directory>.
1733 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1735 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1737 "pack directory into compressed tarball",
1739 This command packs the contents of C<directory> and downloads
1740 it to local file C<tarball>.
1742 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1744 ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1745 [InitBasicFS, Always, TestLastFail (
1747 ["mount_ro"; "/dev/sda1"; "/"];
1748 ["touch"; "/new"]]);
1749 InitBasicFS, Always, TestOutput (
1750 [["write_file"; "/new"; "data"; "0"];
1752 ["mount_ro"; "/dev/sda1"; "/"];
1753 ["cat"; "/new"]], "data")],
1754 "mount a guest disk, read-only",
1756 This is the same as the C<guestfs_mount> command, but it
1757 mounts the filesystem with the read-only (I<-o ro>) flag.");
1759 ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1761 "mount a guest disk with mount options",
1763 This is the same as the C<guestfs_mount> command, but it
1764 allows you to set the mount options as for the
1765 L<mount(8)> I<-o> flag.");
1767 ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1769 "mount a guest disk with mount options and vfstype",
1771 This is the same as the C<guestfs_mount> command, but it
1772 allows you to set both the mount options and the vfstype
1773 as for the L<mount(8)> I<-o> and I<-t> flags.");
1775 ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1777 "debugging and internals",
1779 The C<guestfs_debug> command exposes some internals of
1780 C<guestfsd> (the guestfs daemon) that runs inside the
1783 There is no comprehensive help for this command. You have
1784 to look at the file C<daemon/debug.c> in the libguestfs source
1785 to find out what you can do.");
1787 ("lvremove", (RErr, [String "device"]), 77, [],
1788 [InitEmpty, Always, TestOutputList (
1789 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1790 ["pvcreate"; "/dev/sda1"];
1791 ["vgcreate"; "VG"; "/dev/sda1"];
1792 ["lvcreate"; "LV1"; "VG"; "50"];
1793 ["lvcreate"; "LV2"; "VG"; "50"];
1794 ["lvremove"; "/dev/VG/LV1"];
1795 ["lvs"]], ["/dev/VG/LV2"]);
1796 InitEmpty, Always, TestOutputList (
1797 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1798 ["pvcreate"; "/dev/sda1"];
1799 ["vgcreate"; "VG"; "/dev/sda1"];
1800 ["lvcreate"; "LV1"; "VG"; "50"];
1801 ["lvcreate"; "LV2"; "VG"; "50"];
1802 ["lvremove"; "/dev/VG"];
1804 InitEmpty, Always, TestOutputList (
1805 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1806 ["pvcreate"; "/dev/sda1"];
1807 ["vgcreate"; "VG"; "/dev/sda1"];
1808 ["lvcreate"; "LV1"; "VG"; "50"];
1809 ["lvcreate"; "LV2"; "VG"; "50"];
1810 ["lvremove"; "/dev/VG"];
1812 "remove an LVM logical volume",
1814 Remove an LVM logical volume C<device>, where C<device> is
1815 the path to the LV, such as C</dev/VG/LV>.
1817 You can also remove all LVs in a volume group by specifying
1818 the VG name, C</dev/VG>.");
1820 ("vgremove", (RErr, [String "vgname"]), 78, [],
1821 [InitEmpty, Always, TestOutputList (
1822 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1823 ["pvcreate"; "/dev/sda1"];
1824 ["vgcreate"; "VG"; "/dev/sda1"];
1825 ["lvcreate"; "LV1"; "VG"; "50"];
1826 ["lvcreate"; "LV2"; "VG"; "50"];
1829 InitEmpty, Always, TestOutputList (
1830 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1831 ["pvcreate"; "/dev/sda1"];
1832 ["vgcreate"; "VG"; "/dev/sda1"];
1833 ["lvcreate"; "LV1"; "VG"; "50"];
1834 ["lvcreate"; "LV2"; "VG"; "50"];
1837 "remove an LVM volume group",
1839 Remove an LVM volume group C<vgname>, (for example C<VG>).
1841 This also forcibly removes all logical volumes in the volume
1844 ("pvremove", (RErr, [String "device"]), 79, [],
1845 [InitEmpty, Always, TestOutputList (
1846 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1847 ["pvcreate"; "/dev/sda1"];
1848 ["vgcreate"; "VG"; "/dev/sda1"];
1849 ["lvcreate"; "LV1"; "VG"; "50"];
1850 ["lvcreate"; "LV2"; "VG"; "50"];
1852 ["pvremove"; "/dev/sda1"];
1854 InitEmpty, Always, TestOutputList (
1855 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1856 ["pvcreate"; "/dev/sda1"];
1857 ["vgcreate"; "VG"; "/dev/sda1"];
1858 ["lvcreate"; "LV1"; "VG"; "50"];
1859 ["lvcreate"; "LV2"; "VG"; "50"];
1861 ["pvremove"; "/dev/sda1"];
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"];
1870 ["pvremove"; "/dev/sda1"];
1872 "remove an LVM physical volume",
1874 This wipes a physical volume C<device> so that LVM will no longer
1877 The implementation uses the C<pvremove> command which refuses to
1878 wipe physical volumes that contain any volume groups, so you have
1879 to remove those first.");
1881 ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
1882 [InitBasicFS, Always, TestOutput (
1883 [["set_e2label"; "/dev/sda1"; "testlabel"];
1884 ["get_e2label"; "/dev/sda1"]], "testlabel")],
1885 "set the ext2/3/4 filesystem label",
1887 This sets the ext2/3/4 filesystem label of the filesystem on
1888 C<device> to C<label>. Filesystem labels are limited to
1891 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
1892 to return the existing label on a filesystem.");
1894 ("get_e2label", (RString "label", [String "device"]), 81, [],
1896 "get the ext2/3/4 filesystem label",
1898 This returns the ext2/3/4 filesystem label of the filesystem on
1901 ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
1902 [InitBasicFS, Always, TestOutput (
1903 [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
1904 ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
1905 InitBasicFS, Always, TestOutput (
1906 [["set_e2uuid"; "/dev/sda1"; "clear"];
1907 ["get_e2uuid"; "/dev/sda1"]], "");
1908 (* We can't predict what UUIDs will be, so just check the commands run. *)
1909 InitBasicFS, Always, TestRun (
1910 [["set_e2uuid"; "/dev/sda1"; "random"]]);
1911 InitBasicFS, Always, TestRun (
1912 [["set_e2uuid"; "/dev/sda1"; "time"]])],
1913 "set the ext2/3/4 filesystem UUID",
1915 This sets the ext2/3/4 filesystem UUID of the filesystem on
1916 C<device> to C<uuid>. The format of the UUID and alternatives
1917 such as C<clear>, C<random> and C<time> are described in the
1918 L<tune2fs(8)> manpage.
1920 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
1921 to return the existing UUID of a filesystem.");
1923 ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
1925 "get the ext2/3/4 filesystem UUID",
1927 This returns the ext2/3/4 filesystem UUID of the filesystem on
1930 ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
1931 [InitBasicFS, Always, TestOutputInt (
1932 [["umount"; "/dev/sda1"];
1933 ["fsck"; "ext2"; "/dev/sda1"]], 0);
1934 InitBasicFS, Always, TestOutputInt (
1935 [["umount"; "/dev/sda1"];
1936 ["zero"; "/dev/sda1"];
1937 ["fsck"; "ext2"; "/dev/sda1"]], 8)],
1938 "run the filesystem checker",
1940 This runs the filesystem checker (fsck) on C<device> which
1941 should have filesystem type C<fstype>.
1943 The returned integer is the status. See L<fsck(8)> for the
1944 list of status codes from C<fsck>.
1952 Multiple status codes can be summed together.
1956 A non-zero return code can mean \"success\", for example if
1957 errors have been corrected on the filesystem.
1961 Checking or repairing NTFS volumes is not supported
1966 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
1968 ("zero", (RErr, [String "device"]), 85, [],
1969 [InitBasicFS, Always, TestOutput (
1970 [["umount"; "/dev/sda1"];
1971 ["zero"; "/dev/sda1"];
1972 ["file"; "/dev/sda1"]], "data")],
1973 "write zeroes to the device",
1975 This command writes zeroes over the first few blocks of C<device>.
1977 How many blocks are zeroed isn't specified (but it's I<not> enough
1978 to securely wipe the device). It should be sufficient to remove
1979 any partition tables, filesystem superblocks and so on.");
1981 ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
1982 [InitBasicFS, Always, TestOutputTrue (
1983 [["grub_install"; "/"; "/dev/sda1"];
1984 ["is_dir"; "/boot"]])],
1987 This command installs GRUB (the Grand Unified Bootloader) on
1988 C<device>, with the root directory being C<root>.");
1990 ("cp", (RErr, [String "src"; String "dest"]), 87, [],
1991 [InitBasicFS, Always, TestOutput (
1992 [["write_file"; "/old"; "file content"; "0"];
1993 ["cp"; "/old"; "/new"];
1994 ["cat"; "/new"]], "file content");
1995 InitBasicFS, Always, TestOutputTrue (
1996 [["write_file"; "/old"; "file content"; "0"];
1997 ["cp"; "/old"; "/new"];
1998 ["is_file"; "/old"]]);
1999 InitBasicFS, Always, TestOutput (
2000 [["write_file"; "/old"; "file content"; "0"];
2002 ["cp"; "/old"; "/dir/new"];
2003 ["cat"; "/dir/new"]], "file content")],
2006 This copies a file from C<src> to C<dest> where C<dest> is
2007 either a destination filename or destination directory.");
2009 ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2010 [InitBasicFS, Always, TestOutput (
2011 [["mkdir"; "/olddir"];
2012 ["mkdir"; "/newdir"];
2013 ["write_file"; "/olddir/file"; "file content"; "0"];
2014 ["cp_a"; "/olddir"; "/newdir"];
2015 ["cat"; "/newdir/olddir/file"]], "file content")],
2016 "copy a file or directory recursively",
2018 This copies a file or directory from C<src> to C<dest>
2019 recursively using the C<cp -a> command.");
2021 ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2022 [InitBasicFS, Always, TestOutput (
2023 [["write_file"; "/old"; "file content"; "0"];
2024 ["mv"; "/old"; "/new"];
2025 ["cat"; "/new"]], "file content");
2026 InitBasicFS, Always, TestOutputFalse (
2027 [["write_file"; "/old"; "file content"; "0"];
2028 ["mv"; "/old"; "/new"];
2029 ["is_file"; "/old"]])],
2032 This moves a file from C<src> to C<dest> where C<dest> is
2033 either a destination filename or destination directory.");
2035 ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2036 [InitEmpty, Always, TestRun (
2037 [["drop_caches"; "3"]])],
2038 "drop kernel page cache, dentries and inodes",
2040 This instructs the guest kernel to drop its page cache,
2041 and/or dentries and inode caches. The parameter C<whattodrop>
2042 tells the kernel what precisely to drop, see
2043 L<http://linux-mm.org/Drop_Caches>
2045 Setting C<whattodrop> to 3 should drop everything.
2047 This automatically calls L<sync(2)> before the operation,
2048 so that the maximum guest memory is freed.");
2050 ("dmesg", (RString "kmsgs", []), 91, [],
2051 [InitEmpty, Always, TestRun (
2053 "return kernel messages",
2055 This returns the kernel messages (C<dmesg> output) from
2056 the guest kernel. This is sometimes useful for extended
2057 debugging of problems.
2059 Another way to get the same information is to enable
2060 verbose messages with C<guestfs_set_verbose> or by setting
2061 the environment variable C<LIBGUESTFS_DEBUG=1> before
2062 running the program.");
2064 ("ping_daemon", (RErr, []), 92, [],
2065 [InitEmpty, Always, TestRun (
2066 [["ping_daemon"]])],
2067 "ping the guest daemon",
2069 This is a test probe into the guestfs daemon running inside
2070 the qemu subprocess. Calling this function checks that the
2071 daemon responds to the ping message, without affecting the daemon
2072 or attached block device(s) in any other way.");
2074 ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2075 [InitBasicFS, Always, TestOutputTrue (
2076 [["write_file"; "/file1"; "contents of a file"; "0"];
2077 ["cp"; "/file1"; "/file2"];
2078 ["equal"; "/file1"; "/file2"]]);
2079 InitBasicFS, Always, TestOutputFalse (
2080 [["write_file"; "/file1"; "contents of a file"; "0"];
2081 ["write_file"; "/file2"; "contents of another file"; "0"];
2082 ["equal"; "/file1"; "/file2"]]);
2083 InitBasicFS, Always, TestLastFail (
2084 [["equal"; "/file1"; "/file2"]])],
2085 "test if two files have equal contents",
2087 This compares the two files C<file1> and C<file2> and returns
2088 true if their content is exactly equal, or false otherwise.
2090 The external L<cmp(1)> program is used for the comparison.");
2092 ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2093 [InitBasicFS, Always, TestOutputList (
2094 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2095 ["strings"; "/new"]], ["hello"; "world"]);
2096 InitBasicFS, Always, TestOutputList (
2098 ["strings"; "/new"]], [])],
2099 "print the printable strings in a file",
2101 This runs the L<strings(1)> command on a file and returns
2102 the list of printable strings found.");
2104 ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2105 [InitBasicFS, Always, TestOutputList (
2106 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2107 ["strings_e"; "b"; "/new"]], []);
2108 InitBasicFS, Disabled, TestOutputList (
2109 [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2110 ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2111 "print the printable strings in a file",
2113 This is like the C<guestfs_strings> command, but allows you to
2114 specify the encoding.
2116 See the L<strings(1)> manpage for the full list of encodings.
2118 Commonly useful encodings are C<l> (lower case L) which will
2119 show strings inside Windows/x86 files.
2121 The returned strings are transcoded to UTF-8.");
2123 ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2124 [InitBasicFS, Always, TestOutput (
2125 [["write_file"; "/new"; "hello\nworld\n"; "12"];
2126 ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n")],
2127 "dump a file in hexadecimal",
2129 This runs C<hexdump -C> on the given C<path>. The result is
2130 the human-readable, canonical hex dump of the file.");
2132 ("zerofree", (RErr, [String "device"]), 97, [],
2133 [InitNone, Always, TestOutput (
2134 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2135 ["mkfs"; "ext3"; "/dev/sda1"];
2136 ["mount"; "/dev/sda1"; "/"];
2137 ["write_file"; "/new"; "test file"; "0"];
2138 ["umount"; "/dev/sda1"];
2139 ["zerofree"; "/dev/sda1"];
2140 ["mount"; "/dev/sda1"; "/"];
2141 ["cat"; "/new"]], "test file")],
2142 "zero unused inodes and disk blocks on ext2/3 filesystem",
2144 This runs the I<zerofree> program on C<device>. This program
2145 claims to zero unused inodes and disk blocks on an ext2/3
2146 filesystem, thus making it possible to compress the filesystem
2149 You should B<not> run this program if the filesystem is
2152 It is possible that using this program can damage the filesystem
2153 or data on the filesystem.");
2155 ("pvresize", (RErr, [String "device"]), 98, [],
2157 "resize an LVM physical volume",
2159 This resizes (expands or shrinks) an existing LVM physical
2160 volume to match the new size of the underlying device.");
2162 ("sfdisk_N", (RErr, [String "device"; Int "n";
2163 Int "cyls"; Int "heads"; Int "sectors";
2164 String "line"]), 99, [DangerWillRobinson],
2166 "modify a single partition on a block device",
2168 This runs L<sfdisk(8)> option to modify just the single
2169 partition C<n> (note: C<n> counts from 1).
2171 For other parameters, see C<guestfs_sfdisk>. You should usually
2172 pass C<0> for the cyls/heads/sectors parameters.");
2174 ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2176 "display the partition table",
2178 This displays the partition table on C<device>, in the
2179 human-readable output of the L<sfdisk(8)> command. It is
2180 not intended to be parsed.");
2182 ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2184 "display the kernel geometry",
2186 This displays the kernel's idea of the geometry of C<device>.
2188 The result is in human-readable format, and not designed to
2191 ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2193 "display the disk geometry from the partition table",
2195 This displays the disk geometry of C<device> read from the
2196 partition table. Especially in the case where the underlying
2197 block device has been resized, this can be different from the
2198 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2200 The result is in human-readable format, and not designed to
2203 ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2205 "activate or deactivate all volume groups",
2207 This command activates or (if C<activate> is false) deactivates
2208 all logical volumes in all volume groups.
2209 If activated, then they are made known to the
2210 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2211 then those devices disappear.
2213 This command is the same as running C<vgchange -a y|n>");
2215 ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2217 "activate or deactivate some volume groups",
2219 This command activates or (if C<activate> is false) deactivates
2220 all logical volumes in the listed volume groups C<volgroups>.
2221 If activated, then they are made known to the
2222 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2223 then those devices disappear.
2225 This command is the same as running C<vgchange -a y|n volgroups...>
2227 Note that if C<volgroups> is an empty list then B<all> volume groups
2228 are activated or deactivated.");
2230 ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2231 [InitNone, Always, TestOutput (
2232 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2233 ["pvcreate"; "/dev/sda1"];
2234 ["vgcreate"; "VG"; "/dev/sda1"];
2235 ["lvcreate"; "LV"; "VG"; "10"];
2236 ["mkfs"; "ext2"; "/dev/VG/LV"];
2237 ["mount"; "/dev/VG/LV"; "/"];
2238 ["write_file"; "/new"; "test content"; "0"];
2240 ["lvresize"; "/dev/VG/LV"; "20"];
2241 ["e2fsck_f"; "/dev/VG/LV"];
2242 ["resize2fs"; "/dev/VG/LV"];
2243 ["mount"; "/dev/VG/LV"; "/"];
2244 ["cat"; "/new"]], "test content")],
2245 "resize an LVM logical volume",
2247 This resizes (expands or shrinks) an existing LVM logical
2248 volume to C<mbytes>. When reducing, data in the reduced part
2251 ("resize2fs", (RErr, [String "device"]), 106, [],
2252 [], (* lvresize tests this *)
2253 "resize an ext2/ext3 filesystem",
2255 This resizes an ext2 or ext3 filesystem to match the size of
2256 the underlying device.
2258 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2259 on the C<device> before calling this command. For unknown reasons
2260 C<resize2fs> sometimes gives an error about this and sometimes not.
2261 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2262 calling this function.");
2264 ("find", (RStringList "names", [String "directory"]), 107, [],
2265 [InitBasicFS, Always, TestOutputList (
2266 [["find"; "/"]], ["lost+found"]);
2267 InitBasicFS, Always, TestOutputList (
2271 ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2272 InitBasicFS, Always, TestOutputList (
2273 [["mkdir_p"; "/a/b/c"];
2274 ["touch"; "/a/b/c/d"];
2275 ["find"; "/a/b/"]], ["c"; "c/d"])],
2276 "find all files and directories",
2278 This command lists out all files and directories, recursively,
2279 starting at C<directory>. It is essentially equivalent to
2280 running the shell command C<find directory -print> but some
2281 post-processing happens on the output, described below.
2283 This returns a list of strings I<without any prefix>. Thus
2284 if the directory structure was:
2290 then the returned list from C<guestfs_find> C</tmp> would be
2298 If C<directory> is not a directory, then this command returns
2301 The returned list is sorted.");
2303 ("e2fsck_f", (RErr, [String "device"]), 108, [],
2304 [], (* lvresize tests this *)
2305 "check an ext2/ext3 filesystem",
2307 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2308 filesystem checker on C<device>, noninteractively (C<-p>),
2309 even if the filesystem appears to be clean (C<-f>).
2311 This command is only needed because of C<guestfs_resize2fs>
2312 (q.v.). Normally you should use C<guestfs_fsck>.");
2316 let all_functions = non_daemon_functions @ daemon_functions
2318 (* In some places we want the functions to be displayed sorted
2319 * alphabetically, so this is useful:
2321 let all_functions_sorted =
2322 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2323 compare n1 n2) all_functions
2325 (* Column names and types from LVM PVs/VGs/LVs. *)
2334 "pv_attr", `String (* XXX *);
2335 "pv_pe_count", `Int;
2336 "pv_pe_alloc_count", `Int;
2339 "pv_mda_count", `Int;
2340 "pv_mda_free", `Bytes;
2341 (* Not in Fedora 10:
2342 "pv_mda_size", `Bytes;
2349 "vg_attr", `String (* XXX *);
2352 "vg_sysid", `String;
2353 "vg_extent_size", `Bytes;
2354 "vg_extent_count", `Int;
2355 "vg_free_count", `Int;
2363 "vg_mda_count", `Int;
2364 "vg_mda_free", `Bytes;
2365 (* Not in Fedora 10:
2366 "vg_mda_size", `Bytes;
2372 "lv_attr", `String (* XXX *);
2375 "lv_kernel_major", `Int;
2376 "lv_kernel_minor", `Int;
2380 "snap_percent", `OptPercent;
2381 "copy_percent", `OptPercent;
2384 "mirror_log", `String;
2388 (* Column names and types from stat structures.
2389 * NB. Can't use things like 'st_atime' because glibc header files
2390 * define some of these as macros. Ugh.
2407 let statvfs_cols = [
2421 (* Used for testing language bindings. *)
2423 | CallString of string
2424 | CallOptString of string option
2425 | CallStringList of string list
2429 (* Useful functions.
2430 * Note we don't want to use any external OCaml libraries which
2431 * makes this a bit harder than it should be.
2433 let failwithf fs = ksprintf failwith fs
2435 let replace_char s c1 c2 =
2436 let s2 = String.copy s in
2437 let r = ref false in
2438 for i = 0 to String.length s2 - 1 do
2439 if String.unsafe_get s2 i = c1 then (
2440 String.unsafe_set s2 i c2;
2444 if not !r then s else s2
2448 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2450 let triml ?(test = isspace) str =
2452 let n = ref (String.length str) in
2453 while !n > 0 && test str.[!i]; do
2458 else String.sub str !i !n
2460 let trimr ?(test = isspace) str =
2461 let n = ref (String.length str) in
2462 while !n > 0 && test str.[!n-1]; do
2465 if !n = String.length str then str
2466 else String.sub str 0 !n
2468 let trim ?(test = isspace) str =
2469 trimr ~test (triml ~test str)
2471 let rec find s sub =
2472 let len = String.length s in
2473 let sublen = String.length sub in
2475 if i <= len-sublen then (
2477 if j < sublen then (
2478 if s.[i+j] = sub.[j] then loop2 (j+1)
2484 if r = -1 then loop (i+1) else r
2490 let rec replace_str s s1 s2 =
2491 let len = String.length s in
2492 let sublen = String.length s1 in
2493 let i = find s s1 in
2496 let s' = String.sub s 0 i in
2497 let s'' = String.sub s (i+sublen) (len-i-sublen) in
2498 s' ^ s2 ^ replace_str s'' s1 s2
2501 let rec string_split sep str =
2502 let len = String.length str in
2503 let seplen = String.length sep in
2504 let i = find str sep in
2505 if i = -1 then [str]
2507 let s' = String.sub str 0 i in
2508 let s'' = String.sub str (i+seplen) (len-i-seplen) in
2509 s' :: string_split sep s''
2512 let files_equal n1 n2 =
2513 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
2514 match Sys.command cmd with
2517 | i -> failwithf "%s: failed with error code %d" cmd i
2519 let rec find_map f = function
2520 | [] -> raise Not_found
2524 | None -> find_map f xs
2527 let rec loop i = function
2529 | x :: xs -> f i x; loop (i+1) xs
2534 let rec loop i = function
2536 | x :: xs -> let r = f i x in r :: loop (i+1) xs
2540 let name_of_argt = function
2541 | String n | OptString n | StringList n | Bool n | Int n
2542 | FileIn n | FileOut n -> n
2544 let seq_of_test = function
2545 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
2546 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
2547 | TestOutputLength (s, _) | TestOutputStruct (s, _)
2548 | TestLastFail s -> s
2550 (* Check function names etc. for consistency. *)
2551 let check_functions () =
2552 let contains_uppercase str =
2553 let len = String.length str in
2555 if i >= len then false
2558 if c >= 'A' && c <= 'Z' then true
2565 (* Check function names. *)
2567 fun (name, _, _, _, _, _, _) ->
2568 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
2569 failwithf "function name %s does not need 'guestfs' prefix" name;
2571 failwithf "function name is empty";
2572 if name.[0] < 'a' || name.[0] > 'z' then
2573 failwithf "function name %s must start with lowercase a-z" name;
2574 if String.contains name '-' then
2575 failwithf "function name %s should not contain '-', use '_' instead."
2579 (* Check function parameter/return names. *)
2581 fun (name, style, _, _, _, _, _) ->
2582 let check_arg_ret_name n =
2583 if contains_uppercase n then
2584 failwithf "%s param/ret %s should not contain uppercase chars"
2586 if String.contains n '-' || String.contains n '_' then
2587 failwithf "%s param/ret %s should not contain '-' or '_'"
2590 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;
2591 if n = "int" || n = "char" || n = "short" || n = "long" then
2592 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
2594 failwithf "%s has a param/ret called 'i', which will cause some conflicts in the generated code" name;
2595 if n = "argv" || n = "args" then
2596 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
2599 (match fst style with
2601 | RInt n | RInt64 n | RBool n | RConstString n | RString n
2602 | RStringList n | RPVList n | RVGList n | RLVList n
2603 | RStat n | RStatVFS n
2605 check_arg_ret_name n
2607 check_arg_ret_name n;
2608 check_arg_ret_name m
2610 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
2613 (* Check short descriptions. *)
2615 fun (name, _, _, _, _, shortdesc, _) ->
2616 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
2617 failwithf "short description of %s should begin with lowercase." name;
2618 let c = shortdesc.[String.length shortdesc-1] in
2619 if c = '\n' || c = '.' then
2620 failwithf "short description of %s should not end with . or \\n." name
2623 (* Check long dscriptions. *)
2625 fun (name, _, _, _, _, _, longdesc) ->
2626 if longdesc.[String.length longdesc-1] = '\n' then
2627 failwithf "long description of %s should not end with \\n." name
2630 (* Check proc_nrs. *)
2632 fun (name, _, proc_nr, _, _, _, _) ->
2633 if proc_nr <= 0 then
2634 failwithf "daemon function %s should have proc_nr > 0" name
2638 fun (name, _, proc_nr, _, _, _, _) ->
2639 if proc_nr <> -1 then
2640 failwithf "non-daemon function %s should have proc_nr -1" name
2641 ) non_daemon_functions;
2644 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
2647 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
2648 let rec loop = function
2651 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
2653 | (name1,nr1) :: (name2,nr2) :: _ ->
2654 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
2662 (* Ignore functions that have no tests. We generate a
2663 * warning when the user does 'make check' instead.
2665 | name, _, _, _, [], _, _ -> ()
2666 | name, _, _, _, tests, _, _ ->
2670 match seq_of_test test with
2672 failwithf "%s has a test containing an empty sequence" name
2673 | cmds -> List.map List.hd cmds
2675 let funcs = List.flatten funcs in
2677 let tested = List.mem name funcs in
2680 failwithf "function %s has tests but does not test itself" name
2683 (* 'pr' prints to the current output file. *)
2684 let chan = ref stdout
2685 let pr fs = ksprintf (output_string !chan) fs
2687 (* Generate a header block in a number of standard styles. *)
2688 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
2689 type license = GPLv2 | LGPLv2
2691 let generate_header comment license =
2692 let c = match comment with
2693 | CStyle -> pr "/* "; " *"
2694 | HashStyle -> pr "# "; "#"
2695 | OCamlStyle -> pr "(* "; " *"
2696 | HaskellStyle -> pr "{- "; " " in
2697 pr "libguestfs generated file\n";
2698 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
2699 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
2701 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
2705 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
2706 pr "%s it under the terms of the GNU General Public License as published by\n" c;
2707 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
2708 pr "%s (at your option) any later version.\n" c;
2710 pr "%s This program is distributed in the hope that it will be useful,\n" c;
2711 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2712 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
2713 pr "%s GNU General Public License for more details.\n" c;
2715 pr "%s You should have received a copy of the GNU General Public License along\n" c;
2716 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
2717 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
2720 pr "%s This library is free software; you can redistribute it and/or\n" c;
2721 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
2722 pr "%s License as published by the Free Software Foundation; either\n" c;
2723 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
2725 pr "%s This library is distributed in the hope that it will be useful,\n" c;
2726 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2727 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
2728 pr "%s Lesser General Public License for more details.\n" c;
2730 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
2731 pr "%s License along with this library; if not, write to the Free Software\n" c;
2732 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
2735 | CStyle -> pr " */\n"
2737 | OCamlStyle -> pr " *)\n"
2738 | HaskellStyle -> pr "-}\n"
2742 (* Start of main code generation functions below this line. *)
2744 (* Generate the pod documentation for the C API. *)
2745 let rec generate_actions_pod () =
2747 fun (shortname, style, _, flags, _, _, longdesc) ->
2748 if not (List.mem NotInDocs flags) then (
2749 let name = "guestfs_" ^ shortname in
2750 pr "=head2 %s\n\n" name;
2752 generate_prototype ~extern:false ~handle:"handle" name style;
2754 pr "%s\n\n" longdesc;
2755 (match fst style with
2757 pr "This function returns 0 on success or -1 on error.\n\n"
2759 pr "On error this function returns -1.\n\n"
2761 pr "On error this function returns -1.\n\n"
2763 pr "This function returns a C truth value on success or -1 on error.\n\n"
2765 pr "This function returns a string, or NULL on error.
2766 The string is owned by the guest handle and must I<not> be freed.\n\n"
2768 pr "This function returns a string, or NULL on error.
2769 I<The caller must free the returned string after use>.\n\n"
2771 pr "This function returns a NULL-terminated array of strings
2772 (like L<environ(3)>), or NULL if there was an error.
2773 I<The caller must free the strings and the array after use>.\n\n"
2775 pr "This function returns a C<struct guestfs_int_bool *>,
2776 or NULL if there was an error.
2777 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
2779 pr "This function returns a C<struct guestfs_lvm_pv_list *>
2780 (see E<lt>guestfs-structs.hE<gt>),
2781 or NULL if there was an error.
2782 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
2784 pr "This function returns a C<struct guestfs_lvm_vg_list *>
2785 (see E<lt>guestfs-structs.hE<gt>),
2786 or NULL if there was an error.
2787 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
2789 pr "This function returns a C<struct guestfs_lvm_lv_list *>
2790 (see E<lt>guestfs-structs.hE<gt>),
2791 or NULL if there was an error.
2792 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
2794 pr "This function returns a C<struct guestfs_stat *>
2795 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
2796 or NULL if there was an error.
2797 I<The caller must call C<free> after use>.\n\n"
2799 pr "This function returns a C<struct guestfs_statvfs *>
2800 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
2801 or NULL if there was an error.
2802 I<The caller must call C<free> after use>.\n\n"
2804 pr "This function returns a NULL-terminated array of
2805 strings, or NULL if there was an error.
2806 The array of strings will always have length C<2n+1>, where
2807 C<n> keys and values alternate, followed by the trailing NULL entry.
2808 I<The caller must free the strings and the array after use>.\n\n"
2810 if List.mem ProtocolLimitWarning flags then
2811 pr "%s\n\n" protocol_limit_warning;
2812 if List.mem DangerWillRobinson flags then
2813 pr "%s\n\n" danger_will_robinson
2815 ) all_functions_sorted
2817 and generate_structs_pod () =
2818 (* LVM structs documentation. *)
2821 pr "=head2 guestfs_lvm_%s\n" typ;
2823 pr " struct guestfs_lvm_%s {\n" typ;
2826 | name, `String -> pr " char *%s;\n" name
2828 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
2829 pr " char %s[32];\n" name
2830 | name, `Bytes -> pr " uint64_t %s;\n" name
2831 | name, `Int -> pr " int64_t %s;\n" name
2832 | name, `OptPercent ->
2833 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
2834 pr " float %s;\n" name
2837 pr " struct guestfs_lvm_%s_list {\n" typ;
2838 pr " uint32_t len; /* Number of elements in list. */\n";
2839 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
2842 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
2845 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2847 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
2848 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
2850 * We have to use an underscore instead of a dash because otherwise
2851 * rpcgen generates incorrect code.
2853 * This header is NOT exported to clients, but see also generate_structs_h.
2855 and generate_xdr () =
2856 generate_header CStyle LGPLv2;
2858 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
2859 pr "typedef string str<>;\n";
2862 (* LVM internal structures. *)
2866 pr "struct guestfs_lvm_int_%s {\n" typ;
2868 | name, `String -> pr " string %s<>;\n" name
2869 | name, `UUID -> pr " opaque %s[32];\n" name
2870 | name, `Bytes -> pr " hyper %s;\n" name
2871 | name, `Int -> pr " hyper %s;\n" name
2872 | name, `OptPercent -> pr " float %s;\n" name
2876 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
2878 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2880 (* Stat internal structures. *)
2884 pr "struct guestfs_int_%s {\n" typ;
2886 | name, `Int -> pr " hyper %s;\n" name
2890 ) ["stat", stat_cols; "statvfs", statvfs_cols];
2893 fun (shortname, style, _, _, _, _, _) ->
2894 let name = "guestfs_" ^ shortname in
2896 (match snd style with
2899 pr "struct %s_args {\n" name;
2902 | String n -> pr " string %s<>;\n" n
2903 | OptString n -> pr " str *%s;\n" n
2904 | StringList n -> pr " str %s<>;\n" n
2905 | Bool n -> pr " bool %s;\n" n
2906 | Int n -> pr " int %s;\n" n
2907 | FileIn _ | FileOut _ -> ()
2911 (match fst style with
2914 pr "struct %s_ret {\n" name;
2918 pr "struct %s_ret {\n" name;
2919 pr " hyper %s;\n" n;
2922 pr "struct %s_ret {\n" name;
2926 failwithf "RConstString cannot be returned from a daemon function"
2928 pr "struct %s_ret {\n" name;
2929 pr " string %s<>;\n" n;
2932 pr "struct %s_ret {\n" name;
2933 pr " str %s<>;\n" n;
2936 pr "struct %s_ret {\n" name;
2941 pr "struct %s_ret {\n" name;
2942 pr " guestfs_lvm_int_pv_list %s;\n" n;
2945 pr "struct %s_ret {\n" name;
2946 pr " guestfs_lvm_int_vg_list %s;\n" n;
2949 pr "struct %s_ret {\n" name;
2950 pr " guestfs_lvm_int_lv_list %s;\n" n;
2953 pr "struct %s_ret {\n" name;
2954 pr " guestfs_int_stat %s;\n" n;
2957 pr "struct %s_ret {\n" name;
2958 pr " guestfs_int_statvfs %s;\n" n;
2961 pr "struct %s_ret {\n" name;
2962 pr " str %s<>;\n" n;
2967 (* Table of procedure numbers. *)
2968 pr "enum guestfs_procedure {\n";
2970 fun (shortname, _, proc_nr, _, _, _, _) ->
2971 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
2973 pr " GUESTFS_PROC_NR_PROCS\n";
2977 (* Having to choose a maximum message size is annoying for several
2978 * reasons (it limits what we can do in the API), but it (a) makes
2979 * the protocol a lot simpler, and (b) provides a bound on the size
2980 * of the daemon which operates in limited memory space. For large
2981 * file transfers you should use FTP.
2983 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
2986 (* Message header, etc. *)
2988 /* The communication protocol is now documented in the guestfs(3)
2992 const GUESTFS_PROGRAM = 0x2000F5F5;
2993 const GUESTFS_PROTOCOL_VERSION = 1;
2995 /* These constants must be larger than any possible message length. */
2996 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
2997 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
2999 enum guestfs_message_direction {
3000 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
3001 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
3004 enum guestfs_message_status {
3005 GUESTFS_STATUS_OK = 0,
3006 GUESTFS_STATUS_ERROR = 1
3009 const GUESTFS_ERROR_LEN = 256;
3011 struct guestfs_message_error {
3012 string error_message<GUESTFS_ERROR_LEN>;
3015 struct guestfs_message_header {
3016 unsigned prog; /* GUESTFS_PROGRAM */
3017 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
3018 guestfs_procedure proc; /* GUESTFS_PROC_x */
3019 guestfs_message_direction direction;
3020 unsigned serial; /* message serial number */
3021 guestfs_message_status status;
3024 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3026 struct guestfs_chunk {
3027 int cancel; /* if non-zero, transfer is cancelled */
3028 /* data size is 0 bytes if the transfer has finished successfully */
3029 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3033 (* Generate the guestfs-structs.h file. *)
3034 and generate_structs_h () =
3035 generate_header CStyle LGPLv2;
3037 (* This is a public exported header file containing various
3038 * structures. The structures are carefully written to have
3039 * exactly the same in-memory format as the XDR structures that
3040 * we use on the wire to the daemon. The reason for creating
3041 * copies of these structures here is just so we don't have to
3042 * export the whole of guestfs_protocol.h (which includes much
3043 * unrelated and XDR-dependent stuff that we don't want to be
3044 * public, or required by clients).
3046 * To reiterate, we will pass these structures to and from the
3047 * client with a simple assignment or memcpy, so the format
3048 * must be identical to what rpcgen / the RFC defines.
3051 (* guestfs_int_bool structure. *)
3052 pr "struct guestfs_int_bool {\n";
3058 (* LVM public structures. *)
3062 pr "struct guestfs_lvm_%s {\n" typ;
3065 | name, `String -> pr " char *%s;\n" name
3066 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3067 | name, `Bytes -> pr " uint64_t %s;\n" name
3068 | name, `Int -> pr " int64_t %s;\n" name
3069 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
3073 pr "struct guestfs_lvm_%s_list {\n" typ;
3074 pr " uint32_t len;\n";
3075 pr " struct guestfs_lvm_%s *val;\n" typ;
3078 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3080 (* Stat structures. *)
3084 pr "struct guestfs_%s {\n" typ;
3087 | name, `Int -> pr " int64_t %s;\n" name
3091 ) ["stat", stat_cols; "statvfs", statvfs_cols]
3093 (* Generate the guestfs-actions.h file. *)
3094 and generate_actions_h () =
3095 generate_header CStyle LGPLv2;
3097 fun (shortname, style, _, _, _, _, _) ->
3098 let name = "guestfs_" ^ shortname in
3099 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3103 (* Generate the client-side dispatch stubs. *)
3104 and generate_client_actions () =
3105 generate_header CStyle LGPLv2;
3111 #include \"guestfs.h\"
3112 #include \"guestfs_protocol.h\"
3114 #define error guestfs_error
3115 #define perrorf guestfs_perrorf
3116 #define safe_malloc guestfs_safe_malloc
3117 #define safe_realloc guestfs_safe_realloc
3118 #define safe_strdup guestfs_safe_strdup
3119 #define safe_memdup guestfs_safe_memdup
3121 /* Check the return message from a call for validity. */
3123 check_reply_header (guestfs_h *g,
3124 const struct guestfs_message_header *hdr,
3125 int proc_nr, int serial)
3127 if (hdr->prog != GUESTFS_PROGRAM) {
3128 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3131 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3132 error (g, \"wrong protocol version (%%d/%%d)\",
3133 hdr->vers, GUESTFS_PROTOCOL_VERSION);
3136 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3137 error (g, \"unexpected message direction (%%d/%%d)\",
3138 hdr->direction, GUESTFS_DIRECTION_REPLY);
3141 if (hdr->proc != proc_nr) {
3142 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3145 if (hdr->serial != serial) {
3146 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3153 /* Check we are in the right state to run a high-level action. */
3155 check_state (guestfs_h *g, const char *caller)
3157 if (!guestfs_is_ready (g)) {
3158 if (guestfs_is_config (g))
3159 error (g, \"%%s: call launch() before using this function\",
3161 else if (guestfs_is_launching (g))
3162 error (g, \"%%s: call wait_ready() before using this function\",
3165 error (g, \"%%s called from the wrong state, %%d != READY\",
3166 caller, guestfs_get_state (g));
3174 (* Client-side stubs for each function. *)
3176 fun (shortname, style, _, _, _, _, _) ->
3177 let name = "guestfs_" ^ shortname in
3179 (* Generate the context struct which stores the high-level
3180 * state between callback functions.
3182 pr "struct %s_ctx {\n" shortname;
3183 pr " /* This flag is set by the callbacks, so we know we've done\n";
3184 pr " * the callbacks as expected, and in the right sequence.\n";
3185 pr " * 0 = not called, 1 = reply_cb called.\n";
3187 pr " int cb_sequence;\n";
3188 pr " struct guestfs_message_header hdr;\n";
3189 pr " struct guestfs_message_error err;\n";
3190 (match fst style with
3193 failwithf "RConstString cannot be returned from a daemon function"
3195 | RBool _ | RString _ | RStringList _
3197 | RPVList _ | RVGList _ | RLVList _
3198 | RStat _ | RStatVFS _
3200 pr " struct %s_ret ret;\n" name
3205 (* Generate the reply callback function. *)
3206 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3208 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3209 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3211 pr " /* This should definitely not happen. */\n";
3212 pr " if (ctx->cb_sequence != 0) {\n";
3213 pr " ctx->cb_sequence = 9999;\n";
3214 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3218 pr " ml->main_loop_quit (ml, g);\n";
3220 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3221 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3224 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3225 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3226 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3233 (match fst style with
3236 failwithf "RConstString cannot be returned from a daemon function"
3238 | RBool _ | RString _ | RStringList _
3240 | RPVList _ | RVGList _ | RLVList _
3241 | RStat _ | RStatVFS _
3243 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3244 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3250 pr " ctx->cb_sequence = 1;\n";
3253 (* Generate the action stub. *)
3254 generate_prototype ~extern:false ~semicolon:false ~newline:true
3255 ~handle:"g" name style;
3258 match fst style with
3259 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3261 failwithf "RConstString cannot be returned from a daemon function"
3262 | RString _ | RStringList _ | RIntBool _
3263 | RPVList _ | RVGList _ | RLVList _
3264 | RStat _ | RStatVFS _
3270 (match snd style with
3272 | _ -> pr " struct %s_args args;\n" name
3275 pr " struct %s_ctx ctx;\n" shortname;
3276 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3277 pr " int serial;\n";
3279 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3280 pr " guestfs_set_busy (g);\n";
3282 pr " memset (&ctx, 0, sizeof ctx);\n";
3285 (* Send the main header and arguments. *)
3286 (match snd style with
3288 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3289 (String.uppercase shortname)
3294 pr " args.%s = (char *) %s;\n" n n
3296 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
3298 pr " args.%s.%s_val = (char **) %s;\n" n n n;
3299 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3301 pr " args.%s = %s;\n" n n
3303 pr " args.%s = %s;\n" n n
3304 | FileIn _ | FileOut _ -> ()
3306 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3307 (String.uppercase shortname);
3308 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3311 pr " if (serial == -1) {\n";
3312 pr " guestfs_end_busy (g);\n";
3313 pr " return %s;\n" error_code;
3317 (* Send any additional files (FileIn) requested. *)
3318 let need_read_reply_label = ref false in
3325 pr " r = guestfs__send_file_sync (g, %s);\n" n;
3326 pr " if (r == -1) {\n";
3327 pr " guestfs_end_busy (g);\n";
3328 pr " return %s;\n" error_code;
3330 pr " if (r == -2) /* daemon cancelled */\n";
3331 pr " goto read_reply;\n";
3332 need_read_reply_label := true;
3338 (* Wait for the reply from the remote end. *)
3339 if !need_read_reply_label then pr " read_reply:\n";
3340 pr " guestfs__switch_to_receiving (g);\n";
3341 pr " ctx.cb_sequence = 0;\n";
3342 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3343 pr " (void) ml->main_loop_run (ml, g);\n";
3344 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
3345 pr " if (ctx.cb_sequence != 1) {\n";
3346 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3347 pr " guestfs_end_busy (g);\n";
3348 pr " return %s;\n" error_code;
3352 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3353 (String.uppercase shortname);
3354 pr " guestfs_end_busy (g);\n";
3355 pr " return %s;\n" error_code;
3359 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3360 pr " error (g, \"%%s\", ctx.err.error_message);\n";
3361 pr " free (ctx.err.error_message);\n";
3362 pr " guestfs_end_busy (g);\n";
3363 pr " return %s;\n" error_code;
3367 (* Expecting to receive further files (FileOut)? *)
3371 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3372 pr " guestfs_end_busy (g);\n";
3373 pr " return %s;\n" error_code;
3379 pr " guestfs_end_busy (g);\n";
3381 (match fst style with
3382 | RErr -> pr " return 0;\n"
3383 | RInt n | RInt64 n | RBool n ->
3384 pr " return ctx.ret.%s;\n" n
3386 failwithf "RConstString cannot be returned from a daemon function"
3388 pr " return ctx.ret.%s; /* caller will free */\n" n
3389 | RStringList n | RHashtable n ->
3390 pr " /* caller will free this, but we need to add a NULL entry */\n";
3391 pr " ctx.ret.%s.%s_val =\n" n n;
3392 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3393 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3395 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3396 pr " return ctx.ret.%s.%s_val;\n" n n
3398 pr " /* caller with free this */\n";
3399 pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3400 | RPVList n | RVGList n | RLVList n
3401 | RStat n | RStatVFS n ->
3402 pr " /* caller will free this */\n";
3403 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3409 (* Generate daemon/actions.h. *)
3410 and generate_daemon_actions_h () =
3411 generate_header CStyle GPLv2;
3413 pr "#include \"../src/guestfs_protocol.h\"\n";
3417 fun (name, style, _, _, _, _, _) ->
3419 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3423 (* Generate the server-side stubs. *)
3424 and generate_daemon_actions () =
3425 generate_header CStyle GPLv2;
3427 pr "#include <config.h>\n";
3429 pr "#include <stdio.h>\n";
3430 pr "#include <stdlib.h>\n";
3431 pr "#include <string.h>\n";
3432 pr "#include <inttypes.h>\n";
3433 pr "#include <ctype.h>\n";
3434 pr "#include <rpc/types.h>\n";
3435 pr "#include <rpc/xdr.h>\n";
3437 pr "#include \"daemon.h\"\n";
3438 pr "#include \"../src/guestfs_protocol.h\"\n";
3439 pr "#include \"actions.h\"\n";
3443 fun (name, style, _, _, _, _, _) ->
3444 (* Generate server-side stubs. *)
3445 pr "static void %s_stub (XDR *xdr_in)\n" name;
3448 match fst style with
3449 | RErr | RInt _ -> pr " int r;\n"; "-1"
3450 | RInt64 _ -> pr " int64_t r;\n"; "-1"
3451 | RBool _ -> pr " int r;\n"; "-1"
3453 failwithf "RConstString cannot be returned from a daemon function"
3454 | RString _ -> pr " char *r;\n"; "NULL"
3455 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
3456 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
3457 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
3458 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
3459 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
3460 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
3461 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
3463 (match snd style with
3466 pr " struct guestfs_%s_args args;\n" name;
3470 | OptString n -> pr " const char *%s;\n" n
3471 | StringList n -> pr " char **%s;\n" n
3472 | Bool n -> pr " int %s;\n" n
3473 | Int n -> pr " int %s;\n" n
3474 | FileIn _ | FileOut _ -> ()
3479 (match snd style with
3482 pr " memset (&args, 0, sizeof args);\n";
3484 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
3485 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
3490 | String n -> pr " %s = args.%s;\n" n n
3491 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
3493 pr " %s = realloc (args.%s.%s_val,\n" n n n;
3494 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
3495 pr " if (%s == NULL) {\n" n;
3496 pr " reply_with_perror (\"realloc\");\n";
3499 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
3500 pr " args.%s.%s_val = %s;\n" n n n;
3501 | Bool n -> pr " %s = args.%s;\n" n n
3502 | Int n -> pr " %s = args.%s;\n" n n
3503 | FileIn _ | FileOut _ -> ()
3508 (* Don't want to call the impl with any FileIn or FileOut
3509 * parameters, since these go "outside" the RPC protocol.
3512 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
3514 pr " r = do_%s " name;
3515 generate_call_args argsnofile;
3518 pr " if (r == %s)\n" error_code;
3519 pr " /* do_%s has already called reply_with_error */\n" name;
3523 (* If there are any FileOut parameters, then the impl must
3524 * send its own reply.
3527 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
3529 pr " /* do_%s has already sent a reply */\n" name
3531 match fst style with
3532 | RErr -> pr " reply (NULL, NULL);\n"
3533 | RInt n | RInt64 n | RBool n ->
3534 pr " struct guestfs_%s_ret ret;\n" name;
3535 pr " ret.%s = r;\n" n;
3536 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3539 failwithf "RConstString cannot be returned from a daemon function"
3541 pr " struct guestfs_%s_ret ret;\n" name;
3542 pr " ret.%s = r;\n" n;
3543 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3546 | RStringList n | RHashtable n ->
3547 pr " struct guestfs_%s_ret ret;\n" name;
3548 pr " ret.%s.%s_len = count_strings (r);\n" n n;
3549 pr " ret.%s.%s_val = r;\n" n n;
3550 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3552 pr " free_strings (r);\n"
3554 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
3556 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
3557 | RPVList n | RVGList n | RLVList n
3558 | RStat n | RStatVFS n ->
3559 pr " struct guestfs_%s_ret ret;\n" name;
3560 pr " ret.%s = *r;\n" n;
3561 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3563 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3567 (* Free the args. *)
3568 (match snd style with
3573 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
3580 (* Dispatch function. *)
3581 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
3583 pr " switch (proc_nr) {\n";
3586 fun (name, style, _, _, _, _, _) ->
3587 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
3588 pr " %s_stub (xdr_in);\n" name;
3593 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
3598 (* LVM columns and tokenization functions. *)
3599 (* XXX This generates crap code. We should rethink how we
3605 pr "static const char *lvm_%s_cols = \"%s\";\n"
3606 typ (String.concat "," (List.map fst cols));
3609 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
3611 pr " char *tok, *p, *next;\n";
3615 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
3618 pr " if (!str) {\n";
3619 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
3622 pr " if (!*str || isspace (*str)) {\n";
3623 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
3628 fun (name, coltype) ->
3629 pr " if (!tok) {\n";
3630 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
3633 pr " p = strchrnul (tok, ',');\n";
3634 pr " if (*p) next = p+1; else next = NULL;\n";
3635 pr " *p = '\\0';\n";
3638 pr " r->%s = strdup (tok);\n" name;
3639 pr " if (r->%s == NULL) {\n" name;
3640 pr " perror (\"strdup\");\n";
3644 pr " for (i = j = 0; i < 32; ++j) {\n";
3645 pr " if (tok[j] == '\\0') {\n";
3646 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
3648 pr " } else if (tok[j] != '-')\n";
3649 pr " r->%s[i++] = tok[j];\n" name;
3652 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
3653 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3657 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
3658 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3662 pr " if (tok[0] == '\\0')\n";
3663 pr " r->%s = -1;\n" name;
3664 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
3665 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3669 pr " tok = next;\n";
3672 pr " if (tok != NULL) {\n";
3673 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
3680 pr "guestfs_lvm_int_%s_list *\n" typ;
3681 pr "parse_command_line_%ss (void)\n" typ;
3683 pr " char *out, *err;\n";
3684 pr " char *p, *pend;\n";
3686 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
3687 pr " void *newp;\n";
3689 pr " ret = malloc (sizeof *ret);\n";
3690 pr " if (!ret) {\n";
3691 pr " reply_with_perror (\"malloc\");\n";
3692 pr " return NULL;\n";
3695 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
3696 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
3698 pr " r = command (&out, &err,\n";
3699 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
3700 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
3701 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
3702 pr " if (r == -1) {\n";
3703 pr " reply_with_error (\"%%s\", err);\n";
3704 pr " free (out);\n";
3705 pr " free (err);\n";
3706 pr " free (ret);\n";
3707 pr " return NULL;\n";
3710 pr " free (err);\n";
3712 pr " /* Tokenize each line of the output. */\n";
3715 pr " while (p) {\n";
3716 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
3717 pr " if (pend) {\n";
3718 pr " *pend = '\\0';\n";
3722 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
3725 pr " if (!*p) { /* Empty line? Skip it. */\n";
3730 pr " /* Allocate some space to store this next entry. */\n";
3731 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
3732 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
3733 pr " if (newp == NULL) {\n";
3734 pr " reply_with_perror (\"realloc\");\n";
3735 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3736 pr " free (ret);\n";
3737 pr " free (out);\n";
3738 pr " return NULL;\n";
3740 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
3742 pr " /* Tokenize the next entry. */\n";
3743 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
3744 pr " if (r == -1) {\n";
3745 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
3746 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3747 pr " free (ret);\n";
3748 pr " free (out);\n";
3749 pr " return NULL;\n";
3756 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
3758 pr " free (out);\n";
3759 pr " return ret;\n";
3762 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3764 (* Generate the tests. *)
3765 and generate_tests () =
3766 generate_header CStyle GPLv2;
3773 #include <sys/types.h>
3776 #include \"guestfs.h\"
3778 static guestfs_h *g;
3779 static int suppress_error = 0;
3781 /* This will be 's' or 'h' depending on whether the guest kernel
3782 * names IDE devices /dev/sd* or /dev/hd*.
3784 static char devchar = 's';
3786 static void print_error (guestfs_h *g, void *data, const char *msg)
3788 if (!suppress_error)
3789 fprintf (stderr, \"%%s\\n\", msg);
3792 static void print_strings (char * const * const argv)
3796 for (argc = 0; argv[argc] != NULL; ++argc)
3797 printf (\"\\t%%s\\n\", argv[argc]);
3801 static void print_table (char * const * const argv)
3805 for (i = 0; argv[i] != NULL; i += 2)
3806 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
3810 static void no_test_warnings (void)
3816 | name, _, _, _, [], _, _ ->
3817 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
3818 | name, _, _, _, tests, _, _ -> ()
3824 (* Generate the actual tests. Note that we generate the tests
3825 * in reverse order, deliberately, so that (in general) the
3826 * newest tests run first. This makes it quicker and easier to
3831 fun (name, _, _, _, tests, _, _) ->
3832 mapi (generate_one_test name) tests
3833 ) (List.rev all_functions) in
3834 let test_names = List.concat test_names in
3835 let nr_tests = List.length test_names in
3838 int main (int argc, char *argv[])
3842 const char *filename;
3844 int nr_tests, test_num = 0;
3847 no_test_warnings ();
3849 g = guestfs_create ();
3851 printf (\"guestfs_create FAILED\\n\");
3855 guestfs_set_error_handler (g, print_error, NULL);
3857 guestfs_set_path (g, \"../appliance\");
3859 filename = \"test1.img\";
3860 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3865 if (lseek (fd, %d, SEEK_SET) == -1) {
3871 if (write (fd, &c, 1) == -1) {
3877 if (close (fd) == -1) {
3882 if (guestfs_add_drive (g, filename) == -1) {
3883 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3887 filename = \"test2.img\";
3888 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3893 if (lseek (fd, %d, SEEK_SET) == -1) {
3899 if (write (fd, &c, 1) == -1) {
3905 if (close (fd) == -1) {
3910 if (guestfs_add_drive (g, filename) == -1) {
3911 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3915 filename = \"test3.img\";
3916 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3921 if (lseek (fd, %d, SEEK_SET) == -1) {
3927 if (write (fd, &c, 1) == -1) {
3933 if (close (fd) == -1) {
3938 if (guestfs_add_drive (g, filename) == -1) {
3939 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3943 if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
3944 printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
3948 if (guestfs_launch (g) == -1) {
3949 printf (\"guestfs_launch FAILED\\n\");
3952 if (guestfs_wait_ready (g) == -1) {
3953 printf (\"guestfs_wait_ready FAILED\\n\");
3957 /* Detect if the appliance uses /dev/sd* or /dev/hd* in device
3958 * names. This changed between RHEL 5 and RHEL 6 so we have to
3961 devs = guestfs_list_devices (g);
3962 if (devs == NULL || devs[0] == NULL) {
3963 printf (\"guestfs_list_devices FAILED\\n\");
3966 if (strncmp (devs[0], \"/dev/sd\", 7) == 0)
3968 else if (strncmp (devs[0], \"/dev/hd\", 7) == 0)
3971 printf (\"guestfs_list_devices returned unexpected string '%%s'\\n\",
3975 for (i = 0; devs[i] != NULL; ++i)
3981 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
3985 pr " test_num++;\n";
3986 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
3987 pr " if (%s () == -1) {\n" test_name;
3988 pr " printf (\"%s FAILED\\n\");\n" test_name;
3994 pr " guestfs_close (g);\n";
3995 pr " unlink (\"test1.img\");\n";
3996 pr " unlink (\"test2.img\");\n";
3997 pr " unlink (\"test3.img\");\n";
4000 pr " if (failed > 0) {\n";
4001 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4009 and generate_one_test name i (init, prereq, test) =
4010 let test_name = sprintf "test_%s_%d" name i in
4013 static int %s_skip (void)
4017 str = getenv (\"SKIP_%s\");
4018 if (str && strcmp (str, \"1\") == 0) return 1;
4019 str = getenv (\"SKIP_TEST_%s\");
4020 if (str && strcmp (str, \"1\") == 0) return 1;
4024 " test_name (String.uppercase test_name) (String.uppercase name);
4027 | Disabled | Always -> ()
4028 | If code | Unless code ->
4029 pr "static int %s_prereq (void)\n" test_name;
4037 static int %s (void)
4040 printf (\"%%s skipped (reason: SKIP_TEST_* variable set)\\n\", \"%s\");
4044 " test_name test_name test_name;
4048 pr " printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4050 pr " if (! %s_prereq ()) {\n" test_name;
4051 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4055 generate_one_test_body name i test_name init test;
4057 pr " if (%s_prereq ()) {\n" test_name;
4058 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4062 generate_one_test_body name i test_name init test;
4064 generate_one_test_body name i test_name init test
4072 and generate_one_test_body name i test_name init test =
4076 pr " /* InitNone|InitEmpty for %s */\n" test_name;
4077 List.iter (generate_test_command_call test_name)
4078 [["blockdev_setrw"; "/dev/sda"];
4082 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4083 List.iter (generate_test_command_call test_name)
4084 [["blockdev_setrw"; "/dev/sda"];
4087 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4088 ["mkfs"; "ext2"; "/dev/sda1"];
4089 ["mount"; "/dev/sda1"; "/"]]
4090 | InitBasicFSonLVM ->
4091 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4093 List.iter (generate_test_command_call test_name)
4094 [["blockdev_setrw"; "/dev/sda"];
4097 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4098 ["pvcreate"; "/dev/sda1"];
4099 ["vgcreate"; "VG"; "/dev/sda1"];
4100 ["lvcreate"; "LV"; "VG"; "8"];
4101 ["mkfs"; "ext2"; "/dev/VG/LV"];
4102 ["mount"; "/dev/VG/LV"; "/"]]
4105 let get_seq_last = function
4107 failwithf "%s: you cannot use [] (empty list) when expecting a command"
4110 let seq = List.rev seq in
4111 List.rev (List.tl seq), List.hd seq
4116 pr " /* TestRun for %s (%d) */\n" name i;
4117 List.iter (generate_test_command_call test_name) seq
4118 | TestOutput (seq, expected) ->
4119 pr " /* TestOutput for %s (%d) */\n" name i;
4120 pr " char expected[] = \"%s\";\n" (c_quote expected);
4121 if String.length expected > 7 &&
4122 String.sub expected 0 7 = "/dev/sd" then
4123 pr " expected[5] = devchar;\n";
4124 let seq, last = get_seq_last seq in
4126 pr " if (strcmp (r, expected) != 0) {\n";
4127 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4131 List.iter (generate_test_command_call test_name) seq;
4132 generate_test_command_call ~test test_name last
4133 | TestOutputList (seq, expected) ->
4134 pr " /* TestOutputList for %s (%d) */\n" name i;
4135 let seq, last = get_seq_last seq in
4139 pr " if (!r[%d]) {\n" i;
4140 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4141 pr " print_strings (r);\n";
4145 pr " char expected[] = \"%s\";\n" (c_quote str);
4146 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
4147 pr " expected[5] = devchar;\n";
4148 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4149 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4154 pr " if (r[%d] != NULL) {\n" (List.length expected);
4155 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4157 pr " print_strings (r);\n";
4161 List.iter (generate_test_command_call test_name) seq;
4162 generate_test_command_call ~test test_name last
4163 | TestOutputInt (seq, expected) ->
4164 pr " /* TestOutputInt for %s (%d) */\n" name i;
4165 let seq, last = get_seq_last seq in
4167 pr " if (r != %d) {\n" expected;
4168 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4174 List.iter (generate_test_command_call test_name) seq;
4175 generate_test_command_call ~test test_name last
4176 | TestOutputTrue seq ->
4177 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4178 let seq, last = get_seq_last seq in
4181 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4186 List.iter (generate_test_command_call test_name) seq;
4187 generate_test_command_call ~test test_name last
4188 | TestOutputFalse seq ->
4189 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4190 let seq, last = get_seq_last seq in
4193 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4198 List.iter (generate_test_command_call test_name) seq;
4199 generate_test_command_call ~test test_name last
4200 | TestOutputLength (seq, expected) ->
4201 pr " /* TestOutputLength for %s (%d) */\n" name i;
4202 let seq, last = get_seq_last seq in
4205 pr " for (j = 0; j < %d; ++j)\n" expected;
4206 pr " if (r[j] == NULL) {\n";
4207 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4209 pr " print_strings (r);\n";
4212 pr " if (r[j] != NULL) {\n";
4213 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4215 pr " print_strings (r);\n";
4219 List.iter (generate_test_command_call test_name) seq;
4220 generate_test_command_call ~test test_name last
4221 | TestOutputStruct (seq, checks) ->
4222 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4223 let seq, last = get_seq_last seq in
4227 | CompareWithInt (field, expected) ->
4228 pr " if (r->%s != %d) {\n" field expected;
4229 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4230 test_name field expected;
4231 pr " (int) r->%s);\n" field;
4234 | CompareWithString (field, expected) ->
4235 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4236 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4237 test_name field expected;
4238 pr " r->%s);\n" field;
4241 | CompareFieldsIntEq (field1, field2) ->
4242 pr " if (r->%s != r->%s) {\n" field1 field2;
4243 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4244 test_name field1 field2;
4245 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4248 | CompareFieldsStrEq (field1, field2) ->
4249 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4250 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4251 test_name field1 field2;
4252 pr " r->%s, r->%s);\n" field1 field2;
4257 List.iter (generate_test_command_call test_name) seq;
4258 generate_test_command_call ~test test_name last
4259 | TestLastFail seq ->
4260 pr " /* TestLastFail for %s (%d) */\n" name i;
4261 let seq, last = get_seq_last seq in
4262 List.iter (generate_test_command_call test_name) seq;
4263 generate_test_command_call test_name ~expect_error:true last
4265 (* Generate the code to run a command, leaving the result in 'r'.
4266 * If you expect to get an error then you should set expect_error:true.
4268 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4270 | [] -> assert false
4272 (* Look up the command to find out what args/ret it has. *)
4275 let _, style, _, _, _, _, _ =
4276 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4279 failwithf "%s: in test, command %s was not found" test_name name in
4281 if List.length (snd style) <> List.length args then
4282 failwithf "%s: in test, wrong number of args given to %s"
4289 | OptString n, "NULL" -> ()
4291 | OptString n, arg ->
4292 pr " char %s[] = \"%s\";\n" n (c_quote arg);
4293 if String.length arg > 7 && String.sub arg 0 7 = "/dev/sd" then
4294 pr " %s[5] = devchar;\n" n
4297 | FileIn _, _ | FileOut _, _ -> ()
4298 | StringList n, arg ->
4299 let strs = string_split " " arg in
4302 pr " char %s_%d[] = \"%s\";\n" n i (c_quote str);
4303 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
4304 pr " %s_%d[5] = devchar;\n" n i
4306 pr " char *%s[] = {\n" n;
4308 fun i _ -> pr " %s_%d,\n" n i
4312 ) (List.combine (snd style) args);
4315 match fst style with
4316 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4317 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4318 | RConstString _ -> pr " const char *r;\n"; "NULL"
4319 | RString _ -> pr " char *r;\n"; "NULL"
4320 | RStringList _ | RHashtable _ ->
4325 pr " struct guestfs_int_bool *r;\n"; "NULL"
4327 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4329 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4331 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4333 pr " struct guestfs_stat *r;\n"; "NULL"
4335 pr " struct guestfs_statvfs *r;\n"; "NULL" in
4337 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4338 pr " r = guestfs_%s (g" name;
4340 (* Generate the parameters. *)
4343 | OptString _, "NULL" -> pr ", NULL"
4347 | FileIn _, arg | FileOut _, arg ->
4348 pr ", \"%s\"" (c_quote arg)
4349 | StringList n, _ ->
4353 try int_of_string arg
4354 with Failure "int_of_string" ->
4355 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4358 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4359 ) (List.combine (snd style) args);
4362 if not expect_error then
4363 pr " if (r == %s)\n" error_code
4365 pr " if (r != %s)\n" error_code;
4368 (* Insert the test code. *)
4374 (match fst style with
4375 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4376 | RString _ -> pr " free (r);\n"
4377 | RStringList _ | RHashtable _ ->
4378 pr " for (i = 0; r[i] != NULL; ++i)\n";
4379 pr " free (r[i]);\n";
4382 pr " guestfs_free_int_bool (r);\n"
4384 pr " guestfs_free_lvm_pv_list (r);\n"
4386 pr " guestfs_free_lvm_vg_list (r);\n"
4388 pr " guestfs_free_lvm_lv_list (r);\n"
4389 | RStat _ | RStatVFS _ ->
4396 let str = replace_str str "\r" "\\r" in
4397 let str = replace_str str "\n" "\\n" in
4398 let str = replace_str str "\t" "\\t" in
4399 let str = replace_str str "\000" "\\0" in
4402 (* Generate a lot of different functions for guestfish. *)
4403 and generate_fish_cmds () =
4404 generate_header CStyle GPLv2;
4408 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4410 let all_functions_sorted =
4412 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4413 ) all_functions_sorted in
4415 pr "#include <stdio.h>\n";
4416 pr "#include <stdlib.h>\n";
4417 pr "#include <string.h>\n";
4418 pr "#include <inttypes.h>\n";
4420 pr "#include <guestfs.h>\n";
4421 pr "#include \"fish.h\"\n";
4424 (* list_commands function, which implements guestfish -h *)
4425 pr "void list_commands (void)\n";
4427 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
4428 pr " list_builtin_commands ();\n";
4430 fun (name, _, _, flags, _, shortdesc, _) ->
4431 let name = replace_char name '_' '-' in
4432 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4434 ) all_functions_sorted;
4435 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4439 (* display_command function, which implements guestfish -h cmd *)
4440 pr "void display_command (const char *cmd)\n";
4443 fun (name, style, _, flags, _, shortdesc, longdesc) ->
4444 let name2 = replace_char name '_' '-' in
4446 try find_map (function FishAlias n -> Some n | _ -> None) flags
4447 with Not_found -> name in
4448 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4450 match snd style with
4454 name2 (String.concat "> <" (List.map name_of_argt args)) in
4457 if List.mem ProtocolLimitWarning flags then
4458 ("\n\n" ^ protocol_limit_warning)
4461 (* For DangerWillRobinson commands, we should probably have
4462 * guestfish prompt before allowing you to use them (especially
4463 * in interactive mode). XXX
4467 if List.mem DangerWillRobinson flags then
4468 ("\n\n" ^ danger_will_robinson)
4471 let describe_alias =
4472 if name <> alias then
4473 sprintf "\n\nYou can use '%s' as an alias for this command." alias
4477 pr "strcasecmp (cmd, \"%s\") == 0" name;
4478 if name <> name2 then
4479 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4480 if name <> alias then
4481 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4483 pr " pod2text (\"%s - %s\", %S);\n"
4485 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4488 pr " display_builtin_command (cmd);\n";
4492 (* print_{pv,vg,lv}_list functions *)
4496 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4503 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4505 pr " printf (\"%s: \");\n" name;
4506 pr " for (i = 0; i < 32; ++i)\n";
4507 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
4508 pr " printf (\"\\n\");\n"
4510 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4512 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4513 | name, `OptPercent ->
4514 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4515 typ name name typ name;
4516 pr " else printf (\"%s: \\n\");\n" name
4520 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4525 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4526 pr " print_%s (&%ss->val[i]);\n" typ typ;
4529 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4531 (* print_{stat,statvfs} functions *)
4535 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4540 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4544 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4546 (* run_<action> actions *)
4548 fun (name, style, _, flags, _, _, _) ->
4549 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4551 (match fst style with
4554 | RBool _ -> pr " int r;\n"
4555 | RInt64 _ -> pr " int64_t r;\n"
4556 | RConstString _ -> pr " const char *r;\n"
4557 | RString _ -> pr " char *r;\n"
4558 | RStringList _ | RHashtable _ -> pr " char **r;\n"
4559 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
4560 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
4561 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
4562 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
4563 | RStat _ -> pr " struct guestfs_stat *r;\n"
4564 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
4571 | FileOut n -> pr " const char *%s;\n" n
4572 | StringList n -> pr " char **%s;\n" n
4573 | Bool n -> pr " int %s;\n" n
4574 | Int n -> pr " int %s;\n" n
4577 (* Check and convert parameters. *)
4578 let argc_expected = List.length (snd style) in
4579 pr " if (argc != %d) {\n" argc_expected;
4580 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
4582 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
4588 | String name -> pr " %s = argv[%d];\n" name i
4590 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
4593 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
4596 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
4598 | StringList name ->
4599 pr " %s = parse_string_list (argv[%d]);\n" name i
4601 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
4603 pr " %s = atoi (argv[%d]);\n" name i
4606 (* Call C API function. *)
4608 try find_map (function FishAction n -> Some n | _ -> None) flags
4609 with Not_found -> sprintf "guestfs_%s" name in
4611 generate_call_args ~handle:"g" (snd style);
4614 (* Check return value for errors and display command results. *)
4615 (match fst style with
4616 | RErr -> pr " return r;\n"
4618 pr " if (r == -1) return -1;\n";
4619 pr " printf (\"%%d\\n\", r);\n";
4622 pr " if (r == -1) return -1;\n";
4623 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
4626 pr " if (r == -1) return -1;\n";
4627 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
4630 pr " if (r == NULL) return -1;\n";
4631 pr " printf (\"%%s\\n\", r);\n";
4634 pr " if (r == NULL) return -1;\n";
4635 pr " printf (\"%%s\\n\", r);\n";
4639 pr " if (r == NULL) return -1;\n";
4640 pr " print_strings (r);\n";
4641 pr " free_strings (r);\n";
4644 pr " if (r == NULL) return -1;\n";
4645 pr " printf (\"%%d, %%s\\n\", r->i,\n";
4646 pr " r->b ? \"true\" : \"false\");\n";
4647 pr " guestfs_free_int_bool (r);\n";
4650 pr " if (r == NULL) return -1;\n";
4651 pr " print_pv_list (r);\n";
4652 pr " guestfs_free_lvm_pv_list (r);\n";
4655 pr " if (r == NULL) return -1;\n";
4656 pr " print_vg_list (r);\n";
4657 pr " guestfs_free_lvm_vg_list (r);\n";
4660 pr " if (r == NULL) return -1;\n";
4661 pr " print_lv_list (r);\n";
4662 pr " guestfs_free_lvm_lv_list (r);\n";
4665 pr " if (r == NULL) return -1;\n";
4666 pr " print_stat (r);\n";
4670 pr " if (r == NULL) return -1;\n";
4671 pr " print_statvfs (r);\n";
4675 pr " if (r == NULL) return -1;\n";
4676 pr " print_table (r);\n";
4677 pr " free_strings (r);\n";
4684 (* run_action function *)
4685 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
4688 fun (name, _, _, flags, _, _, _) ->
4689 let name2 = replace_char name '_' '-' in
4691 try find_map (function FishAlias n -> Some n | _ -> None) flags
4692 with Not_found -> name in
4694 pr "strcasecmp (cmd, \"%s\") == 0" name;
4695 if name <> name2 then
4696 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4697 if name <> alias then
4698 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4700 pr " return run_%s (cmd, argc, argv);\n" name;
4704 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
4711 (* Readline completion for guestfish. *)
4712 and generate_fish_completion () =
4713 generate_header CStyle GPLv2;
4717 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4727 #ifdef HAVE_LIBREADLINE
4728 #include <readline/readline.h>
4733 #ifdef HAVE_LIBREADLINE
4735 static const char *const commands[] = {
4736 BUILTIN_COMMANDS_FOR_COMPLETION,
4739 (* Get the commands, including the aliases. They don't need to be
4740 * sorted - the generator() function just does a dumb linear search.
4744 fun (name, _, _, flags, _, _, _) ->
4745 let name2 = replace_char name '_' '-' in
4747 try find_map (function FishAlias n -> Some n | _ -> None) flags
4748 with Not_found -> name in
4750 if name <> alias then [name2; alias] else [name2]
4752 let commands = List.flatten commands in
4754 List.iter (pr " \"%s\",\n") commands;
4760 generator (const char *text, int state)
4762 static int index, len;
4767 len = strlen (text);
4770 while ((name = commands[index]) != NULL) {
4772 if (strncasecmp (name, text, len) == 0)
4773 return strdup (name);
4779 #endif /* HAVE_LIBREADLINE */
4781 char **do_completion (const char *text, int start, int end)
4783 char **matches = NULL;
4785 #ifdef HAVE_LIBREADLINE
4787 matches = rl_completion_matches (text, generator);
4794 (* Generate the POD documentation for guestfish. *)
4795 and generate_fish_actions_pod () =
4796 let all_functions_sorted =
4798 fun (_, _, _, flags, _, _, _) ->
4799 not (List.mem NotInFish flags || List.mem NotInDocs flags)
4800 ) all_functions_sorted in
4802 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
4805 fun (name, style, _, flags, _, _, longdesc) ->
4807 Str.global_substitute rex (
4810 try Str.matched_group 1 s
4812 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
4813 "C<" ^ replace_char sub '_' '-' ^ ">"
4815 let name = replace_char name '_' '-' in
4817 try find_map (function FishAlias n -> Some n | _ -> None) flags
4818 with Not_found -> name in
4820 pr "=head2 %s" name;
4821 if name <> alias then
4828 | String n -> pr " %s" n
4829 | OptString n -> pr " %s" n
4830 | StringList n -> pr " '%s ...'" n
4831 | Bool _ -> pr " true|false"
4832 | Int n -> pr " %s" n
4833 | FileIn n | FileOut n -> pr " (%s|-)" n
4837 pr "%s\n\n" longdesc;
4839 if List.exists (function FileIn _ | FileOut _ -> true
4840 | _ -> false) (snd style) then
4841 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
4843 if List.mem ProtocolLimitWarning flags then
4844 pr "%s\n\n" protocol_limit_warning;
4846 if List.mem DangerWillRobinson flags then
4847 pr "%s\n\n" danger_will_robinson
4848 ) all_functions_sorted
4850 (* Generate a C function prototype. *)
4851 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
4852 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
4854 ?handle name style =
4855 if extern then pr "extern ";
4856 if static then pr "static ";
4857 (match fst style with
4859 | RInt _ -> pr "int "
4860 | RInt64 _ -> pr "int64_t "
4861 | RBool _ -> pr "int "
4862 | RConstString _ -> pr "const char *"
4863 | RString _ -> pr "char *"
4864 | RStringList _ | RHashtable _ -> pr "char **"
4866 if not in_daemon then pr "struct guestfs_int_bool *"
4867 else pr "guestfs_%s_ret *" name
4869 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
4870 else pr "guestfs_lvm_int_pv_list *"
4872 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
4873 else pr "guestfs_lvm_int_vg_list *"
4875 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
4876 else pr "guestfs_lvm_int_lv_list *"
4878 if not in_daemon then pr "struct guestfs_stat *"
4879 else pr "guestfs_int_stat *"
4881 if not in_daemon then pr "struct guestfs_statvfs *"
4882 else pr "guestfs_int_statvfs *"
4884 pr "%s%s (" prefix name;
4885 if handle = None && List.length (snd style) = 0 then
4888 let comma = ref false in
4891 | Some handle -> pr "guestfs_h *%s" handle; comma := true
4895 if single_line then pr ", " else pr ",\n\t\t"
4902 | OptString n -> next (); pr "const char *%s" n
4903 | StringList n -> next (); pr "char * const* const %s" n
4904 | Bool n -> next (); pr "int %s" n
4905 | Int n -> next (); pr "int %s" n
4908 if not in_daemon then (next (); pr "const char *%s" n)
4912 if semicolon then pr ";";
4913 if newline then pr "\n"
4915 (* Generate C call arguments, eg "(handle, foo, bar)" *)
4916 and generate_call_args ?handle args =
4918 let comma = ref false in
4921 | Some handle -> pr "%s" handle; comma := true
4925 if !comma then pr ", ";
4927 pr "%s" (name_of_argt arg)
4931 (* Generate the OCaml bindings interface. *)
4932 and generate_ocaml_mli () =
4933 generate_header OCamlStyle LGPLv2;
4936 (** For API documentation you should refer to the C API
4937 in the guestfs(3) manual page. The OCaml API uses almost
4938 exactly the same calls. *)
4941 (** A [guestfs_h] handle. *)
4943 exception Error of string
4944 (** This exception is raised when there is an error. *)
4946 val create : unit -> t
4948 val close : t -> unit
4949 (** Handles are closed by the garbage collector when they become
4950 unreferenced, but callers can also call this in order to
4951 provide predictable cleanup. *)
4954 generate_ocaml_lvm_structure_decls ();
4956 generate_ocaml_stat_structure_decls ();
4960 fun (name, style, _, _, _, shortdesc, _) ->
4961 generate_ocaml_prototype name style;
4962 pr "(** %s *)\n" shortdesc;
4966 (* Generate the OCaml bindings implementation. *)
4967 and generate_ocaml_ml () =
4968 generate_header OCamlStyle LGPLv2;
4972 exception Error of string
4973 external create : unit -> t = \"ocaml_guestfs_create\"
4974 external close : t -> unit = \"ocaml_guestfs_close\"
4977 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
4981 generate_ocaml_lvm_structure_decls ();
4983 generate_ocaml_stat_structure_decls ();
4987 fun (name, style, _, _, _, shortdesc, _) ->
4988 generate_ocaml_prototype ~is_external:true name style;
4991 (* Generate the OCaml bindings C implementation. *)
4992 and generate_ocaml_c () =
4993 generate_header CStyle LGPLv2;
5000 #include <caml/config.h>
5001 #include <caml/alloc.h>
5002 #include <caml/callback.h>
5003 #include <caml/fail.h>
5004 #include <caml/memory.h>
5005 #include <caml/mlvalues.h>
5006 #include <caml/signals.h>
5008 #include <guestfs.h>
5010 #include \"guestfs_c.h\"
5012 /* Copy a hashtable of string pairs into an assoc-list. We return
5013 * the list in reverse order, but hashtables aren't supposed to be
5016 static CAMLprim value
5017 copy_table (char * const * argv)
5020 CAMLlocal5 (rv, pairv, kv, vv, cons);
5024 for (i = 0; argv[i] != NULL; i += 2) {
5025 kv = caml_copy_string (argv[i]);
5026 vv = caml_copy_string (argv[i+1]);
5027 pairv = caml_alloc (2, 0);
5028 Store_field (pairv, 0, kv);
5029 Store_field (pairv, 1, vv);
5030 cons = caml_alloc (2, 0);
5031 Store_field (cons, 1, rv);
5033 Store_field (cons, 0, pairv);
5041 (* LVM struct copy functions. *)
5044 let has_optpercent_col =
5045 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
5047 pr "static CAMLprim value\n";
5048 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
5050 pr " CAMLparam0 ();\n";
5051 if has_optpercent_col then
5052 pr " CAMLlocal3 (rv, v, v2);\n"
5054 pr " CAMLlocal2 (rv, v);\n";
5056 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5061 pr " v = caml_copy_string (%s->%s);\n" typ name
5063 pr " v = caml_alloc_string (32);\n";
5064 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
5067 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5068 | name, `OptPercent ->
5069 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5070 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
5071 pr " v = caml_alloc (1, 0);\n";
5072 pr " Store_field (v, 0, v2);\n";
5073 pr " } else /* None */\n";
5074 pr " v = Val_int (0);\n";
5076 pr " Store_field (rv, %d, v);\n" i
5078 pr " CAMLreturn (rv);\n";
5082 pr "static CAMLprim value\n";
5083 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
5086 pr " CAMLparam0 ();\n";
5087 pr " CAMLlocal2 (rv, v);\n";
5090 pr " if (%ss->len == 0)\n" typ;
5091 pr " CAMLreturn (Atom (0));\n";
5093 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
5094 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
5095 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
5096 pr " caml_modify (&Field (rv, i), v);\n";
5098 pr " CAMLreturn (rv);\n";
5102 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5104 (* Stat copy functions. *)
5107 pr "static CAMLprim value\n";
5108 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5110 pr " CAMLparam0 ();\n";
5111 pr " CAMLlocal2 (rv, v);\n";
5113 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5118 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5120 pr " Store_field (rv, %d, v);\n" i
5122 pr " CAMLreturn (rv);\n";
5125 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5129 fun (name, style, _, _, _, _, _) ->
5131 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5133 pr "CAMLprim value\n";
5134 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5135 List.iter (pr ", value %s") (List.tl params);
5140 | [p1; p2; p3; p4; p5] ->
5141 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
5142 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5143 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5144 pr " CAMLxparam%d (%s);\n"
5145 (List.length rest) (String.concat ", " rest)
5147 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5149 pr " CAMLlocal1 (rv);\n";
5152 pr " guestfs_h *g = Guestfs_val (gv);\n";
5153 pr " if (g == NULL)\n";
5154 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
5162 pr " const char *%s = String_val (%sv);\n" n n
5164 pr " const char *%s =\n" n;
5165 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5168 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5170 pr " int %s = Bool_val (%sv);\n" n n
5172 pr " int %s = Int_val (%sv);\n" n n
5175 match fst style with
5176 | RErr -> pr " int r;\n"; "-1"
5177 | RInt _ -> pr " int r;\n"; "-1"
5178 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5179 | RBool _ -> pr " int r;\n"; "-1"
5180 | RConstString _ -> pr " const char *r;\n"; "NULL"
5181 | RString _ -> pr " char *r;\n"; "NULL"
5187 pr " struct guestfs_int_bool *r;\n"; "NULL"
5189 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5191 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5193 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5195 pr " struct guestfs_stat *r;\n"; "NULL"
5197 pr " struct guestfs_statvfs *r;\n"; "NULL"
5204 pr " caml_enter_blocking_section ();\n";
5205 pr " r = guestfs_%s " name;
5206 generate_call_args ~handle:"g" (snd style);
5208 pr " caml_leave_blocking_section ();\n";
5213 pr " ocaml_guestfs_free_strings (%s);\n" n;
5214 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5217 pr " if (r == %s)\n" error_code;
5218 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5221 (match fst style with
5222 | RErr -> pr " rv = Val_unit;\n"
5223 | RInt _ -> pr " rv = Val_int (r);\n"
5225 pr " rv = caml_copy_int64 (r);\n"
5226 | RBool _ -> pr " rv = Val_bool (r);\n"
5227 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5229 pr " rv = caml_copy_string (r);\n";
5232 pr " rv = caml_copy_string_array ((const char **) r);\n";
5233 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5236 pr " rv = caml_alloc (2, 0);\n";
5237 pr " Store_field (rv, 0, Val_int (r->i));\n";
5238 pr " Store_field (rv, 1, Val_bool (r->b));\n";
5239 pr " guestfs_free_int_bool (r);\n";
5241 pr " rv = copy_lvm_pv_list (r);\n";
5242 pr " guestfs_free_lvm_pv_list (r);\n";
5244 pr " rv = copy_lvm_vg_list (r);\n";
5245 pr " guestfs_free_lvm_vg_list (r);\n";
5247 pr " rv = copy_lvm_lv_list (r);\n";
5248 pr " guestfs_free_lvm_lv_list (r);\n";
5250 pr " rv = copy_stat (r);\n";
5253 pr " rv = copy_statvfs (r);\n";
5256 pr " rv = copy_table (r);\n";
5257 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5261 pr " CAMLreturn (rv);\n";
5265 if List.length params > 5 then (
5266 pr "CAMLprim value\n";
5267 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5269 pr " return ocaml_guestfs_%s (argv[0]" name;
5270 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5277 and generate_ocaml_lvm_structure_decls () =
5280 pr "type lvm_%s = {\n" typ;
5283 | name, `String -> pr " %s : string;\n" name
5284 | name, `UUID -> pr " %s : string;\n" name
5285 | name, `Bytes -> pr " %s : int64;\n" name
5286 | name, `Int -> pr " %s : int64;\n" name
5287 | name, `OptPercent -> pr " %s : float option;\n" name
5291 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5293 and generate_ocaml_stat_structure_decls () =
5296 pr "type %s = {\n" typ;
5299 | name, `Int -> pr " %s : int64;\n" name
5303 ) ["stat", stat_cols; "statvfs", statvfs_cols]
5305 and generate_ocaml_prototype ?(is_external = false) name style =
5306 if is_external then pr "external " else pr "val ";
5307 pr "%s : t -> " name;
5310 | String _ | FileIn _ | FileOut _ -> pr "string -> "
5311 | OptString _ -> pr "string option -> "
5312 | StringList _ -> pr "string array -> "
5313 | Bool _ -> pr "bool -> "
5314 | Int _ -> pr "int -> "
5316 (match fst style with
5317 | RErr -> pr "unit" (* all errors are turned into exceptions *)
5318 | RInt _ -> pr "int"
5319 | RInt64 _ -> pr "int64"
5320 | RBool _ -> pr "bool"
5321 | RConstString _ -> pr "string"
5322 | RString _ -> pr "string"
5323 | RStringList _ -> pr "string array"
5324 | RIntBool _ -> pr "int * bool"
5325 | RPVList _ -> pr "lvm_pv array"
5326 | RVGList _ -> pr "lvm_vg array"
5327 | RLVList _ -> pr "lvm_lv array"
5328 | RStat _ -> pr "stat"
5329 | RStatVFS _ -> pr "statvfs"
5330 | RHashtable _ -> pr "(string * string) list"
5332 if is_external then (
5334 if List.length (snd style) + 1 > 5 then
5335 pr "\"ocaml_guestfs_%s_byte\" " name;
5336 pr "\"ocaml_guestfs_%s\"" name
5340 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5341 and generate_perl_xs () =
5342 generate_header CStyle LGPLv2;
5345 #include \"EXTERN.h\"
5349 #include <guestfs.h>
5352 #define PRId64 \"lld\"
5356 my_newSVll(long long val) {
5357 #ifdef USE_64_BIT_ALL
5358 return newSViv(val);
5362 len = snprintf(buf, 100, \"%%\" PRId64, val);
5363 return newSVpv(buf, len);
5368 #define PRIu64 \"llu\"
5372 my_newSVull(unsigned long long val) {
5373 #ifdef USE_64_BIT_ALL
5374 return newSVuv(val);
5378 len = snprintf(buf, 100, \"%%\" PRIu64, val);
5379 return newSVpv(buf, len);
5383 /* http://www.perlmonks.org/?node_id=680842 */
5385 XS_unpack_charPtrPtr (SV *arg) {
5390 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5391 croak (\"array reference expected\");
5393 av = (AV *)SvRV (arg);
5394 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5396 croak (\"malloc failed\");
5398 for (i = 0; i <= av_len (av); i++) {
5399 SV **elem = av_fetch (av, i, 0);
5401 if (!elem || !*elem)
5402 croak (\"missing element in list\");
5404 ret[i] = SvPV_nolen (*elem);
5412 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
5419 RETVAL = guestfs_create ();
5421 croak (\"could not create guestfs handle\");
5422 guestfs_set_error_handler (RETVAL, NULL, NULL);
5435 fun (name, style, _, _, _, _, _) ->
5436 (match fst style with
5437 | RErr -> pr "void\n"
5438 | RInt _ -> pr "SV *\n"
5439 | RInt64 _ -> pr "SV *\n"
5440 | RBool _ -> pr "SV *\n"
5441 | RConstString _ -> pr "SV *\n"
5442 | RString _ -> pr "SV *\n"
5445 | RPVList _ | RVGList _ | RLVList _
5446 | RStat _ | RStatVFS _
5448 pr "void\n" (* all lists returned implictly on the stack *)
5450 (* Call and arguments. *)
5452 generate_call_args ~handle:"g" (snd style);
5454 pr " guestfs_h *g;\n";
5458 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
5460 (* http://www.perlmonks.org/?node_id=554277
5461 * Note that the implicit handle argument means we have
5462 * to add 1 to the ST(x) operator.
5464 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
5465 | StringList n -> pr " char **%s;\n" n
5466 | Bool n -> pr " int %s;\n" n
5467 | Int n -> pr " int %s;\n" n
5470 let do_cleanups () =
5473 | String _ | OptString _ | Bool _ | Int _
5474 | FileIn _ | FileOut _ -> ()
5475 | StringList n -> pr " free (%s);\n" n
5480 (match fst style with
5485 pr " r = guestfs_%s " name;
5486 generate_call_args ~handle:"g" (snd style);
5489 pr " if (r == -1)\n";
5490 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5496 pr " %s = guestfs_%s " n name;
5497 generate_call_args ~handle:"g" (snd style);
5500 pr " if (%s == -1)\n" n;
5501 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5502 pr " RETVAL = newSViv (%s);\n" n;
5507 pr " int64_t %s;\n" n;
5509 pr " %s = guestfs_%s " n name;
5510 generate_call_args ~handle:"g" (snd style);
5513 pr " if (%s == -1)\n" n;
5514 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5515 pr " RETVAL = my_newSVll (%s);\n" n;
5520 pr " const char *%s;\n" n;
5522 pr " %s = guestfs_%s " n name;
5523 generate_call_args ~handle:"g" (snd style);
5526 pr " if (%s == NULL)\n" n;
5527 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5528 pr " RETVAL = newSVpv (%s, 0);\n" n;
5533 pr " char *%s;\n" n;
5535 pr " %s = guestfs_%s " n name;
5536 generate_call_args ~handle:"g" (snd style);
5539 pr " if (%s == NULL)\n" n;
5540 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5541 pr " RETVAL = newSVpv (%s, 0);\n" n;
5542 pr " free (%s);\n" n;
5545 | RStringList n | RHashtable n ->
5547 pr " char **%s;\n" n;
5550 pr " %s = guestfs_%s " n name;
5551 generate_call_args ~handle:"g" (snd style);
5554 pr " if (%s == NULL)\n" n;
5555 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5556 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
5557 pr " EXTEND (SP, n);\n";
5558 pr " for (i = 0; i < n; ++i) {\n";
5559 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
5560 pr " free (%s[i]);\n" n;
5562 pr " free (%s);\n" n;
5565 pr " struct guestfs_int_bool *r;\n";
5567 pr " r = guestfs_%s " name;
5568 generate_call_args ~handle:"g" (snd style);
5571 pr " if (r == NULL)\n";
5572 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5573 pr " EXTEND (SP, 2);\n";
5574 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
5575 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
5576 pr " guestfs_free_int_bool (r);\n";
5578 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
5580 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
5582 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
5584 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
5586 generate_perl_stat_code
5587 "statvfs" statvfs_cols name style n do_cleanups
5593 and generate_perl_lvm_code typ cols name style n do_cleanups =
5595 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
5599 pr " %s = guestfs_%s " n name;
5600 generate_call_args ~handle:"g" (snd style);
5603 pr " if (%s == NULL)\n" n;
5604 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5605 pr " EXTEND (SP, %s->len);\n" n;
5606 pr " for (i = 0; i < %s->len; ++i) {\n" n;
5607 pr " hv = newHV ();\n";
5611 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
5612 name (String.length name) n name
5614 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
5615 name (String.length name) n name
5617 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
5618 name (String.length name) n name
5620 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
5621 name (String.length name) n name
5622 | name, `OptPercent ->
5623 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
5624 name (String.length name) n name
5626 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
5628 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
5630 and generate_perl_stat_code typ cols name style n do_cleanups =
5632 pr " struct guestfs_%s *%s;\n" typ n;
5634 pr " %s = guestfs_%s " n name;
5635 generate_call_args ~handle:"g" (snd style);
5638 pr " if (%s == NULL)\n" n;
5639 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5640 pr " EXTEND (SP, %d);\n" (List.length cols);
5644 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
5646 pr " free (%s);\n" n
5648 (* Generate Sys/Guestfs.pm. *)
5649 and generate_perl_pm () =
5650 generate_header HashStyle LGPLv2;
5657 Sys::Guestfs - Perl bindings for libguestfs
5663 my $h = Sys::Guestfs->new ();
5664 $h->add_drive ('guest.img');
5667 $h->mount ('/dev/sda1', '/');
5668 $h->touch ('/hello');
5673 The C<Sys::Guestfs> module provides a Perl XS binding to the
5674 libguestfs API for examining and modifying virtual machine
5677 Amongst the things this is good for: making batch configuration
5678 changes to guests, getting disk used/free statistics (see also:
5679 virt-df), migrating between virtualization systems (see also:
5680 virt-p2v), performing partial backups, performing partial guest
5681 clones, cloning guests and changing registry/UUID/hostname info, and
5684 Libguestfs uses Linux kernel and qemu code, and can access any type of
5685 guest filesystem that Linux and qemu can, including but not limited
5686 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5687 schemes, qcow, qcow2, vmdk.
5689 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5690 LVs, what filesystem is in each LV, etc.). It can also run commands
5691 in the context of the guest. Also you can access filesystems over FTP.
5695 All errors turn into calls to C<croak> (see L<Carp(3)>).
5703 package Sys::Guestfs;
5709 XSLoader::load ('Sys::Guestfs');
5711 =item $h = Sys::Guestfs->new ();
5713 Create a new guestfs handle.
5719 my $class = ref ($proto) || $proto;
5721 my $self = Sys::Guestfs::_create ();
5722 bless $self, $class;
5728 (* Actions. We only need to print documentation for these as
5729 * they are pulled in from the XS code automatically.
5732 fun (name, style, _, flags, _, _, longdesc) ->
5733 if not (List.mem NotInDocs flags) then (
5734 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
5736 generate_perl_prototype name style;
5738 pr "%s\n\n" longdesc;
5739 if List.mem ProtocolLimitWarning flags then
5740 pr "%s\n\n" protocol_limit_warning;
5741 if List.mem DangerWillRobinson flags then
5742 pr "%s\n\n" danger_will_robinson
5744 ) all_functions_sorted;
5756 Copyright (C) 2009 Red Hat Inc.
5760 Please see the file COPYING.LIB for the full license.
5764 L<guestfs(3)>, L<guestfish(1)>.
5769 and generate_perl_prototype name style =
5770 (match fst style with
5776 | RString n -> pr "$%s = " n
5777 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
5781 | RLVList n -> pr "@%s = " n
5784 | RHashtable n -> pr "%%%s = " n
5787 let comma = ref false in
5790 if !comma then pr ", ";
5793 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
5800 (* Generate Python C module. *)
5801 and generate_python_c () =
5802 generate_header CStyle LGPLv2;
5811 #include \"guestfs.h\"
5819 get_handle (PyObject *obj)
5822 assert (obj != Py_None);
5823 return ((Pyguestfs_Object *) obj)->g;
5827 put_handle (guestfs_h *g)
5831 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
5834 /* This list should be freed (but not the strings) after use. */
5835 static const char **
5836 get_string_list (PyObject *obj)
5843 if (!PyList_Check (obj)) {
5844 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
5848 len = PyList_Size (obj);
5849 r = malloc (sizeof (char *) * (len+1));
5851 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
5855 for (i = 0; i < len; ++i)
5856 r[i] = PyString_AsString (PyList_GetItem (obj, i));
5863 put_string_list (char * const * const argv)
5868 for (argc = 0; argv[argc] != NULL; ++argc)
5871 list = PyList_New (argc);
5872 for (i = 0; i < argc; ++i)
5873 PyList_SetItem (list, i, PyString_FromString (argv[i]));
5879 put_table (char * const * const argv)
5881 PyObject *list, *item;
5884 for (argc = 0; argv[argc] != NULL; ++argc)
5887 list = PyList_New (argc >> 1);
5888 for (i = 0; i < argc; i += 2) {
5889 item = PyTuple_New (2);
5890 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
5891 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
5892 PyList_SetItem (list, i >> 1, item);
5899 free_strings (char **argv)
5903 for (argc = 0; argv[argc] != NULL; ++argc)
5909 py_guestfs_create (PyObject *self, PyObject *args)
5913 g = guestfs_create ();
5915 PyErr_SetString (PyExc_RuntimeError,
5916 \"guestfs.create: failed to allocate handle\");
5919 guestfs_set_error_handler (g, NULL, NULL);
5920 return put_handle (g);
5924 py_guestfs_close (PyObject *self, PyObject *args)
5929 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
5931 g = get_handle (py_g);
5935 Py_INCREF (Py_None);
5941 (* LVM structures, turned into Python dictionaries. *)
5944 pr "static PyObject *\n";
5945 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
5947 pr " PyObject *dict;\n";
5949 pr " dict = PyDict_New ();\n";
5953 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5954 pr " PyString_FromString (%s->%s));\n"
5957 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5958 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
5961 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5962 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
5965 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5966 pr " PyLong_FromLongLong (%s->%s));\n"
5968 | name, `OptPercent ->
5969 pr " if (%s->%s >= 0)\n" typ name;
5970 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5971 pr " PyFloat_FromDouble ((double) %s->%s));\n"
5974 pr " Py_INCREF (Py_None);\n";
5975 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
5978 pr " return dict;\n";
5982 pr "static PyObject *\n";
5983 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
5985 pr " PyObject *list;\n";
5988 pr " list = PyList_New (%ss->len);\n" typ;
5989 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
5990 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
5991 pr " return list;\n";
5994 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5996 (* Stat structures, turned into Python dictionaries. *)
5999 pr "static PyObject *\n";
6000 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6002 pr " PyObject *dict;\n";
6004 pr " dict = PyDict_New ();\n";
6008 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6009 pr " PyLong_FromLongLong (%s->%s));\n"
6012 pr " return dict;\n";
6015 ) ["stat", stat_cols; "statvfs", statvfs_cols];
6017 (* Python wrapper functions. *)
6019 fun (name, style, _, _, _, _, _) ->
6020 pr "static PyObject *\n";
6021 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6024 pr " PyObject *py_g;\n";
6025 pr " guestfs_h *g;\n";
6026 pr " PyObject *py_r;\n";
6029 match fst style with
6030 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6031 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6032 | RConstString _ -> pr " const char *r;\n"; "NULL"
6033 | RString _ -> pr " char *r;\n"; "NULL"
6034 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6035 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6036 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6037 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6038 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6039 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6040 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6044 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
6045 | OptString n -> pr " const char *%s;\n" n
6047 pr " PyObject *py_%s;\n" n;
6048 pr " const char **%s;\n" n
6049 | Bool n -> pr " int %s;\n" n
6050 | Int n -> pr " int %s;\n" n
6055 (* Convert the parameters. *)
6056 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
6059 | String _ | FileIn _ | FileOut _ -> pr "s"
6060 | OptString _ -> pr "z"
6061 | StringList _ -> pr "O"
6062 | Bool _ -> pr "i" (* XXX Python has booleans? *)
6065 pr ":guestfs_%s\",\n" name;
6069 | String n | FileIn n | FileOut n -> pr ", &%s" n
6070 | OptString n -> pr ", &%s" n
6071 | StringList n -> pr ", &py_%s" n
6072 | Bool n -> pr ", &%s" n
6073 | Int n -> pr ", &%s" n
6077 pr " return NULL;\n";
6079 pr " g = get_handle (py_g);\n";
6082 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6084 pr " %s = get_string_list (py_%s);\n" n n;
6085 pr " if (!%s) return NULL;\n" n
6090 pr " r = guestfs_%s " name;
6091 generate_call_args ~handle:"g" (snd style);
6096 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6098 pr " free (%s);\n" n
6101 pr " if (r == %s) {\n" error_code;
6102 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6103 pr " return NULL;\n";
6107 (match fst style with
6109 pr " Py_INCREF (Py_None);\n";
6110 pr " py_r = Py_None;\n"
6112 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
6113 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
6114 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
6116 pr " py_r = PyString_FromString (r);\n";
6119 pr " py_r = put_string_list (r);\n";
6120 pr " free_strings (r);\n"
6122 pr " py_r = PyTuple_New (2);\n";
6123 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
6124 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
6125 pr " guestfs_free_int_bool (r);\n"
6127 pr " py_r = put_lvm_pv_list (r);\n";
6128 pr " guestfs_free_lvm_pv_list (r);\n"
6130 pr " py_r = put_lvm_vg_list (r);\n";
6131 pr " guestfs_free_lvm_vg_list (r);\n"
6133 pr " py_r = put_lvm_lv_list (r);\n";
6134 pr " guestfs_free_lvm_lv_list (r);\n"
6136 pr " py_r = put_stat (r);\n";
6139 pr " py_r = put_statvfs (r);\n";
6142 pr " py_r = put_table (r);\n";
6143 pr " free_strings (r);\n"
6146 pr " return py_r;\n";
6151 (* Table of functions. *)
6152 pr "static PyMethodDef methods[] = {\n";
6153 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6154 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6156 fun (name, _, _, _, _, _, _) ->
6157 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6160 pr " { NULL, NULL, 0, NULL }\n";
6164 (* Init function. *)
6167 initlibguestfsmod (void)
6169 static int initialized = 0;
6171 if (initialized) return;
6172 Py_InitModule ((char *) \"libguestfsmod\", methods);
6177 (* Generate Python module. *)
6178 and generate_python_py () =
6179 generate_header HashStyle LGPLv2;
6182 u\"\"\"Python bindings for libguestfs
6185 g = guestfs.GuestFS ()
6186 g.add_drive (\"guest.img\")
6189 parts = g.list_partitions ()
6191 The guestfs module provides a Python binding to the libguestfs API
6192 for examining and modifying virtual machine disk images.
6194 Amongst the things this is good for: making batch configuration
6195 changes to guests, getting disk used/free statistics (see also:
6196 virt-df), migrating between virtualization systems (see also:
6197 virt-p2v), performing partial backups, performing partial guest
6198 clones, cloning guests and changing registry/UUID/hostname info, and
6201 Libguestfs uses Linux kernel and qemu code, and can access any type of
6202 guest filesystem that Linux and qemu can, including but not limited
6203 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6204 schemes, qcow, qcow2, vmdk.
6206 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6207 LVs, what filesystem is in each LV, etc.). It can also run commands
6208 in the context of the guest. Also you can access filesystems over FTP.
6210 Errors which happen while using the API are turned into Python
6211 RuntimeError exceptions.
6213 To create a guestfs handle you usually have to perform the following
6216 # Create the handle, call add_drive at least once, and possibly
6217 # several times if the guest has multiple block devices:
6218 g = guestfs.GuestFS ()
6219 g.add_drive (\"guest.img\")
6221 # Launch the qemu subprocess and wait for it to become ready:
6225 # Now you can issue commands, for example:
6230 import libguestfsmod
6233 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6235 def __init__ (self):
6236 \"\"\"Create a new libguestfs handle.\"\"\"
6237 self._o = libguestfsmod.create ()
6240 libguestfsmod.close (self._o)
6245 fun (name, style, _, flags, _, _, longdesc) ->
6247 generate_call_args ~handle:"self" (snd style);
6250 if not (List.mem NotInDocs flags) then (
6251 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6253 match fst style with
6254 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6257 doc ^ "\n\nThis function returns a list of strings."
6259 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6261 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
6263 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
6265 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
6267 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6269 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6271 doc ^ "\n\nThis function returns a dictionary." in
6273 if List.mem ProtocolLimitWarning flags then
6274 doc ^ "\n\n" ^ protocol_limit_warning
6277 if List.mem DangerWillRobinson flags then
6278 doc ^ "\n\n" ^ danger_will_robinson
6280 let doc = pod2text ~width:60 name doc in
6281 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6282 let doc = String.concat "\n " doc in
6283 pr " u\"\"\"%s\"\"\"\n" doc;
6285 pr " return libguestfsmod.%s " name;
6286 generate_call_args ~handle:"self._o" (snd style);
6291 (* Useful if you need the longdesc POD text as plain text. Returns a
6294 * This is the slowest thing about autogeneration.
6296 and pod2text ~width name longdesc =
6297 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6298 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6300 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6301 let chan = Unix.open_process_in cmd in
6302 let lines = ref [] in
6304 let line = input_line chan in
6305 if i = 1 then (* discard the first line of output *)
6308 let line = triml line in
6309 lines := line :: !lines;
6312 let lines = try loop 1 with End_of_file -> List.rev !lines in
6313 Unix.unlink filename;
6314 match Unix.close_process_in chan with
6315 | Unix.WEXITED 0 -> lines
6317 failwithf "pod2text: process exited with non-zero status (%d)" i
6318 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6319 failwithf "pod2text: process signalled or stopped by signal %d" i
6321 (* Generate ruby bindings. *)
6322 and generate_ruby_c () =
6323 generate_header CStyle LGPLv2;
6331 #include \"guestfs.h\"
6333 #include \"extconf.h\"
6335 /* For Ruby < 1.9 */
6337 #define RARRAY_LEN(r) (RARRAY((r))->len)
6340 static VALUE m_guestfs; /* guestfs module */
6341 static VALUE c_guestfs; /* guestfs_h handle */
6342 static VALUE e_Error; /* used for all errors */
6344 static void ruby_guestfs_free (void *p)
6347 guestfs_close ((guestfs_h *) p);
6350 static VALUE ruby_guestfs_create (VALUE m)
6354 g = guestfs_create ();
6356 rb_raise (e_Error, \"failed to create guestfs handle\");
6358 /* Don't print error messages to stderr by default. */
6359 guestfs_set_error_handler (g, NULL, NULL);
6361 /* Wrap it, and make sure the close function is called when the
6364 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6367 static VALUE ruby_guestfs_close (VALUE gv)
6370 Data_Get_Struct (gv, guestfs_h, g);
6372 ruby_guestfs_free (g);
6373 DATA_PTR (gv) = NULL;
6381 fun (name, style, _, _, _, _, _) ->
6382 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6383 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6386 pr " guestfs_h *g;\n";
6387 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
6389 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6395 | String n | FileIn n | FileOut n ->
6396 pr " const char *%s = StringValueCStr (%sv);\n" n n;
6398 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6399 pr " \"%s\", \"%s\");\n" n name
6401 pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
6405 pr " int i, len;\n";
6406 pr " len = RARRAY_LEN (%sv);\n" n;
6407 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6409 pr " for (i = 0; i < len; ++i) {\n";
6410 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
6411 pr " %s[i] = StringValueCStr (v);\n" n;
6413 pr " %s[len] = NULL;\n" n;
6416 pr " int %s = RTEST (%sv);\n" n n
6418 pr " int %s = NUM2INT (%sv);\n" n n
6423 match fst style with
6424 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6425 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6426 | RConstString _ -> pr " const char *r;\n"; "NULL"
6427 | RString _ -> pr " char *r;\n"; "NULL"
6428 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6429 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6430 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6431 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6432 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6433 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6434 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6437 pr " r = guestfs_%s " name;
6438 generate_call_args ~handle:"g" (snd style);
6443 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6445 pr " free (%s);\n" n
6448 pr " if (r == %s)\n" error_code;
6449 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6452 (match fst style with
6454 pr " return Qnil;\n"
6455 | RInt _ | RBool _ ->
6456 pr " return INT2NUM (r);\n"
6458 pr " return ULL2NUM (r);\n"
6460 pr " return rb_str_new2 (r);\n";
6462 pr " VALUE rv = rb_str_new2 (r);\n";
6466 pr " int i, len = 0;\n";
6467 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
6468 pr " VALUE rv = rb_ary_new2 (len);\n";
6469 pr " for (i = 0; r[i] != NULL; ++i) {\n";
6470 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6471 pr " free (r[i]);\n";
6476 pr " VALUE rv = rb_ary_new2 (2);\n";
6477 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
6478 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
6479 pr " guestfs_free_int_bool (r);\n";
6482 generate_ruby_lvm_code "pv" pv_cols
6484 generate_ruby_lvm_code "vg" vg_cols
6486 generate_ruby_lvm_code "lv" lv_cols
6488 pr " VALUE rv = rb_hash_new ();\n";
6492 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6497 pr " VALUE rv = rb_hash_new ();\n";
6501 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6506 pr " VALUE rv = rb_hash_new ();\n";
6508 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
6509 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6510 pr " free (r[i]);\n";
6511 pr " free (r[i+1]);\n";
6522 /* Initialize the module. */
6523 void Init__guestfs ()
6525 m_guestfs = rb_define_module (\"Guestfs\");
6526 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6527 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6529 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6530 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6533 (* Define the rest of the methods. *)
6535 fun (name, style, _, _, _, _, _) ->
6536 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
6537 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6542 (* Ruby code to return an LVM struct list. *)
6543 and generate_ruby_lvm_code typ cols =
6544 pr " VALUE rv = rb_ary_new2 (r->len);\n";
6546 pr " for (i = 0; i < r->len; ++i) {\n";
6547 pr " VALUE hv = rb_hash_new ();\n";
6551 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
6553 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
6556 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
6557 | name, `OptPercent ->
6558 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
6560 pr " rb_ary_push (rv, hv);\n";
6562 pr " guestfs_free_lvm_%s_list (r);\n" typ;
6565 (* Generate Java bindings GuestFS.java file. *)
6566 and generate_java_java () =
6567 generate_header CStyle LGPLv2;
6570 package com.redhat.et.libguestfs;
6572 import java.util.HashMap;
6573 import com.redhat.et.libguestfs.LibGuestFSException;
6574 import com.redhat.et.libguestfs.PV;
6575 import com.redhat.et.libguestfs.VG;
6576 import com.redhat.et.libguestfs.LV;
6577 import com.redhat.et.libguestfs.Stat;
6578 import com.redhat.et.libguestfs.StatVFS;
6579 import com.redhat.et.libguestfs.IntBool;
6582 * The GuestFS object is a libguestfs handle.
6586 public class GuestFS {
6587 // Load the native code.
6589 System.loadLibrary (\"guestfs_jni\");
6593 * The native guestfs_h pointer.
6598 * Create a libguestfs handle.
6600 * @throws LibGuestFSException
6602 public GuestFS () throws LibGuestFSException
6606 private native long _create () throws LibGuestFSException;
6609 * Close a libguestfs handle.
6611 * You can also leave handles to be collected by the garbage
6612 * collector, but this method ensures that the resources used
6613 * by the handle are freed up immediately. If you call any
6614 * other methods after closing the handle, you will get an
6617 * @throws LibGuestFSException
6619 public void close () throws LibGuestFSException
6625 private native void _close (long g) throws LibGuestFSException;
6627 public void finalize () throws LibGuestFSException
6635 fun (name, style, _, flags, _, shortdesc, longdesc) ->
6636 if not (List.mem NotInDocs flags); then (
6637 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6639 if List.mem ProtocolLimitWarning flags then
6640 doc ^ "\n\n" ^ protocol_limit_warning
6643 if List.mem DangerWillRobinson flags then
6644 doc ^ "\n\n" ^ danger_will_robinson
6646 let doc = pod2text ~width:60 name doc in
6647 let doc = List.map ( (* RHBZ#501883 *)
6650 | nonempty -> nonempty
6652 let doc = String.concat "\n * " doc in
6655 pr " * %s\n" shortdesc;
6658 pr " * @throws LibGuestFSException\n";
6662 generate_java_prototype ~public:true ~semicolon:false name style;
6665 pr " if (g == 0)\n";
6666 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
6669 if fst style <> RErr then pr "return ";
6671 generate_call_args ~handle:"g" (snd style);
6675 generate_java_prototype ~privat:true ~native:true name style;
6682 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
6683 ?(semicolon=true) name style =
6684 if privat then pr "private ";
6685 if public then pr "public ";
6686 if native then pr "native ";
6689 (match fst style with
6690 | RErr -> pr "void ";
6691 | RInt _ -> pr "int ";
6692 | RInt64 _ -> pr "long ";
6693 | RBool _ -> pr "boolean ";
6694 | RConstString _ | RString _ -> pr "String ";
6695 | RStringList _ -> pr "String[] ";
6696 | RIntBool _ -> pr "IntBool ";
6697 | RPVList _ -> pr "PV[] ";
6698 | RVGList _ -> pr "VG[] ";
6699 | RLVList _ -> pr "LV[] ";
6700 | RStat _ -> pr "Stat ";
6701 | RStatVFS _ -> pr "StatVFS ";
6702 | RHashtable _ -> pr "HashMap<String,String> ";
6705 if native then pr "_%s " name else pr "%s " name;
6707 let needs_comma = ref false in
6716 if !needs_comma then pr ", ";
6717 needs_comma := true;
6734 pr " throws LibGuestFSException";
6735 if semicolon then pr ";"
6737 and generate_java_struct typ cols =
6738 generate_header CStyle LGPLv2;
6741 package com.redhat.et.libguestfs;
6744 * Libguestfs %s structure.
6755 | name, `UUID -> pr " public String %s;\n" name
6757 | name, `Int -> pr " public long %s;\n" name
6758 | name, `OptPercent ->
6759 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
6760 pr " public float %s;\n" name
6765 and generate_java_c () =
6766 generate_header CStyle LGPLv2;
6773 #include \"com_redhat_et_libguestfs_GuestFS.h\"
6774 #include \"guestfs.h\"
6776 /* Note that this function returns. The exception is not thrown
6777 * until after the wrapper function returns.
6780 throw_exception (JNIEnv *env, const char *msg)
6783 cl = (*env)->FindClass (env,
6784 \"com/redhat/et/libguestfs/LibGuestFSException\");
6785 (*env)->ThrowNew (env, cl, msg);
6788 JNIEXPORT jlong JNICALL
6789 Java_com_redhat_et_libguestfs_GuestFS__1create
6790 (JNIEnv *env, jobject obj)
6794 g = guestfs_create ();
6796 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
6799 guestfs_set_error_handler (g, NULL, NULL);
6800 return (jlong) (long) g;
6803 JNIEXPORT void JNICALL
6804 Java_com_redhat_et_libguestfs_GuestFS__1close
6805 (JNIEnv *env, jobject obj, jlong jg)
6807 guestfs_h *g = (guestfs_h *) (long) jg;
6814 fun (name, style, _, _, _, _, _) ->
6816 (match fst style with
6817 | RErr -> pr "void ";
6818 | RInt _ -> pr "jint ";
6819 | RInt64 _ -> pr "jlong ";
6820 | RBool _ -> pr "jboolean ";
6821 | RConstString _ | RString _ -> pr "jstring ";
6822 | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
6824 | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
6828 pr "Java_com_redhat_et_libguestfs_GuestFS_";
6829 pr "%s" (replace_str ("_" ^ name) "_" "_1");
6831 pr " (JNIEnv *env, jobject obj, jlong jg";
6838 pr ", jstring j%s" n
6840 pr ", jobjectArray j%s" n
6842 pr ", jboolean j%s" n
6848 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
6849 let error_code, no_ret =
6850 match fst style with
6851 | RErr -> pr " int r;\n"; "-1", ""
6853 | RInt _ -> pr " int r;\n"; "-1", "0"
6854 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
6855 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
6857 pr " jstring jr;\n";
6858 pr " char *r;\n"; "NULL", "NULL"
6860 pr " jobjectArray jr;\n";
6863 pr " jstring jstr;\n";
6864 pr " char **r;\n"; "NULL", "NULL"
6866 pr " jobject jr;\n";
6868 pr " jfieldID fl;\n";
6869 pr " struct guestfs_int_bool *r;\n"; "NULL", "NULL"
6871 pr " jobject jr;\n";
6873 pr " jfieldID fl;\n";
6874 pr " struct guestfs_stat *r;\n"; "NULL", "NULL"
6876 pr " jobject jr;\n";
6878 pr " jfieldID fl;\n";
6879 pr " struct guestfs_statvfs *r;\n"; "NULL", "NULL"
6881 pr " jobjectArray jr;\n";
6883 pr " jfieldID fl;\n";
6884 pr " jobject jfl;\n";
6885 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
6887 pr " jobjectArray jr;\n";
6889 pr " jfieldID fl;\n";
6890 pr " jobject jfl;\n";
6891 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
6893 pr " jobjectArray jr;\n";
6895 pr " jfieldID fl;\n";
6896 pr " jobject jfl;\n";
6897 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
6898 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
6905 pr " const char *%s;\n" n
6907 pr " int %s_len;\n" n;
6908 pr " const char **%s;\n" n
6915 (match fst style with
6916 | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
6917 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
6918 | RString _ | RIntBool _ | RStat _ | RStatVFS _
6919 | RHashtable _ -> false) ||
6920 List.exists (function StringList _ -> true | _ -> false) (snd style) in
6926 (* Get the parameters. *)
6932 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
6934 (* This is completely undocumented, but Java null becomes
6937 pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
6939 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
6940 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
6941 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6942 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6944 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
6946 pr " %s[%s_len] = NULL;\n" n n;
6949 pr " %s = j%s;\n" n n
6952 (* Make the call. *)
6953 pr " r = guestfs_%s " name;
6954 generate_call_args ~handle:"g" (snd style);
6957 (* Release the parameters. *)
6963 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
6966 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
6968 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6969 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6971 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
6973 pr " free (%s);\n" n
6978 (* Check for errors. *)
6979 pr " if (r == %s) {\n" error_code;
6980 pr " throw_exception (env, guestfs_last_error (g));\n";
6981 pr " return %s;\n" no_ret;
6985 (match fst style with
6987 | RInt _ -> pr " return (jint) r;\n"
6988 | RBool _ -> pr " return (jboolean) r;\n"
6989 | RInt64 _ -> pr " return (jlong) r;\n"
6990 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
6992 pr " jr = (*env)->NewStringUTF (env, r);\n";
6996 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
6997 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
6998 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
6999 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7000 pr " for (i = 0; i < r_len; ++i) {\n";
7001 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
7002 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7003 pr " free (r[i]);\n";
7008 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
7009 pr " jr = (*env)->AllocObject (env, cl);\n";
7010 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
7011 pr " (*env)->SetIntField (env, jr, fl, r->i);\n";
7012 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
7013 pr " (*env)->SetBooleanField (env, jr, fl, r->b);\n";
7014 pr " guestfs_free_int_bool (r);\n";
7017 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
7018 pr " jr = (*env)->AllocObject (env, cl);\n";
7022 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7024 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7029 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
7030 pr " jr = (*env)->AllocObject (env, cl);\n";
7034 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7036 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7041 generate_java_lvm_return "pv" "PV" pv_cols
7043 generate_java_lvm_return "vg" "VG" vg_cols
7045 generate_java_lvm_return "lv" "LV" lv_cols
7048 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7049 pr " return NULL;\n"
7056 and generate_java_lvm_return typ jtyp cols =
7057 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7058 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7059 pr " for (i = 0; i < r->len; ++i) {\n";
7060 pr " jfl = (*env)->AllocObject (env, cl);\n";
7064 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7065 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7068 pr " char s[33];\n";
7069 pr " memcpy (s, r->val[i].%s, 32);\n" name;
7071 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7072 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7074 | name, (`Bytes|`Int) ->
7075 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7076 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7077 | name, `OptPercent ->
7078 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7079 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7081 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7083 pr " guestfs_free_lvm_%s_list (r);\n" typ;
7086 and generate_haskell_hs () =
7087 generate_header HaskellStyle LGPLv2;
7089 (* XXX We only know how to generate partial FFI for Haskell
7090 * at the moment. Please help out!
7092 let can_generate style =
7093 let check_no_bad_args =
7094 List.for_all (function Bool _ | Int _ -> false | _ -> true)
7097 | RErr, args -> check_no_bad_args args
7110 | RHashtable _, _ -> false in
7113 {-# INCLUDE <guestfs.h> #-}
7114 {-# LANGUAGE ForeignFunctionInterface #-}
7119 (* List out the names of the actions we want to export. *)
7121 fun (name, style, _, _, _, _, _) ->
7122 if can_generate style then pr ",\n %s" name
7130 import Control.Exception
7131 import Data.Typeable
7133 data GuestfsS = GuestfsS -- represents the opaque C struct
7134 type GuestfsP = Ptr GuestfsS -- guestfs_h *
7135 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7137 -- XXX define properly later XXX
7141 data IntBool = IntBool
7143 data StatVFS = StatVFS
7144 data Hashtable = Hashtable
7146 foreign import ccall unsafe \"guestfs_create\" c_create
7148 foreign import ccall unsafe \"&guestfs_close\" c_close
7149 :: FunPtr (GuestfsP -> IO ())
7150 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
7151 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
7153 create :: IO GuestfsH
7156 c_set_error_handler p nullPtr nullPtr
7157 h <- newForeignPtr c_close p
7160 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
7161 :: GuestfsP -> IO CString
7163 -- last_error :: GuestfsH -> IO (Maybe String)
7164 -- last_error h = do
7165 -- str <- withForeignPtr h (\\p -> c_last_error p)
7166 -- maybePeek peekCString str
7168 last_error :: GuestfsH -> IO (String)
7170 str <- withForeignPtr h (\\p -> c_last_error p)
7172 then return \"no error\"
7173 else peekCString str
7177 (* Generate wrappers for each foreign function. *)
7179 fun (name, style, _, _, _, _, _) ->
7180 if can_generate style then (
7181 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7183 generate_haskell_prototype ~handle:"GuestfsP" style;
7187 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7189 pr "%s %s = do\n" name
7190 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7196 | String n -> pr "withCString %s $ \\%s -> " n n
7197 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7198 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7200 (* XXX this doesn't work *)
7202 pr " %s = case %s of\n" n n;
7205 pr " in fromIntegral %s $ \\%s ->\n" n n
7206 | Int n -> pr "fromIntegral %s $ \\%s -> " n n
7208 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7209 (String.concat " " ("p" :: List.map name_of_argt (snd style)));
7210 (match fst style with
7211 | RErr | RInt _ | RInt64 _ | RBool _ ->
7212 pr " if (r == -1)\n";
7214 pr " err <- last_error h\n";
7216 | RConstString _ | RString _ | RStringList _ | RIntBool _
7217 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7219 pr " if (r == nullPtr)\n";
7221 pr " err <- last_error h\n";
7224 (match fst style with
7226 pr " else return ()\n"
7228 pr " else return (fromIntegral r)\n"
7230 pr " else return (fromIntegral r)\n"
7232 pr " else return (toBool r)\n"
7243 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7249 and generate_haskell_prototype ~handle ?(hs = false) style =
7251 let string = if hs then "String" else "CString" in
7252 let int = if hs then "Int" else "CInt" in
7253 let bool = if hs then "Bool" else "CInt" in
7254 let int64 = if hs then "Integer" else "Int64" in
7258 | String _ -> pr "%s" string
7259 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7260 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7261 | Bool _ -> pr "%s" bool
7262 | Int _ -> pr "%s" int
7263 | FileIn _ -> pr "%s" string
7264 | FileOut _ -> pr "%s" string
7269 (match fst style with
7270 | RErr -> if not hs then pr "CInt"
7271 | RInt _ -> pr "%s" int
7272 | RInt64 _ -> pr "%s" int64
7273 | RBool _ -> pr "%s" bool
7274 | RConstString _ -> pr "%s" string
7275 | RString _ -> pr "%s" string
7276 | RStringList _ -> pr "[%s]" string
7277 | RIntBool _ -> pr "IntBool"
7278 | RPVList _ -> pr "[PV]"
7279 | RVGList _ -> pr "[VG]"
7280 | RLVList _ -> pr "[LV]"
7281 | RStat _ -> pr "Stat"
7282 | RStatVFS _ -> pr "StatVFS"
7283 | RHashtable _ -> pr "Hashtable"
7287 and generate_bindtests () =
7288 generate_header CStyle LGPLv2;
7293 #include <inttypes.h>
7296 #include \"guestfs.h\"
7297 #include \"guestfs_protocol.h\"
7299 #define error guestfs_error
7302 print_strings (char * const* const argv)
7307 for (argc = 0; argv[argc] != NULL; ++argc) {
7308 if (argc > 0) printf (\", \");
7309 printf (\"\\\"%%s\\\"\", argv[argc]);
7314 /* The test0 function prints its parameters to stdout. */
7318 match test_functions with
7319 | [] -> assert false
7320 | test0 :: tests -> test0, tests in
7323 let (name, style, _, _, _, _, _) = test0 in
7324 generate_prototype ~extern:false ~semicolon:false ~newline:true
7325 ~handle:"g" ~prefix:"guestfs_" name style;
7331 | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
7332 | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
7333 | StringList n -> pr " print_strings (%s);\n" n
7334 | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
7335 | Int n -> pr " printf (\"%%d\\n\", %s);\n" n
7337 pr " /* Java changes stdout line buffering so we need this: */\n";
7338 pr " fflush (stdout);\n";
7344 fun (name, style, _, _, _, _, _) ->
7345 if String.sub name (String.length name - 3) 3 <> "err" then (
7346 pr "/* Test normal return. */\n";
7347 generate_prototype ~extern:false ~semicolon:false ~newline:true
7348 ~handle:"g" ~prefix:"guestfs_" name style;
7350 (match fst style with
7355 pr " sscanf (val, \"%%d\", &r);\n";
7359 pr " sscanf (val, \"%%\" SCNi64, &r);\n";
7362 pr " return strcmp (val, \"true\") == 0;\n"
7364 (* Can't return the input string here. Return a static
7365 * string so we ensure we get a segfault if the caller
7368 pr " return \"static string\";\n"
7370 pr " return strdup (val);\n"
7372 pr " char **strs;\n";
7374 pr " sscanf (val, \"%%d\", &n);\n";
7375 pr " strs = malloc ((n+1) * sizeof (char *));\n";
7376 pr " for (i = 0; i < n; ++i) {\n";
7377 pr " strs[i] = malloc (16);\n";
7378 pr " snprintf (strs[i], 16, \"%%d\", i);\n";
7380 pr " strs[n] = NULL;\n";
7381 pr " return strs;\n"
7383 pr " struct guestfs_int_bool *r;\n";
7384 pr " r = malloc (sizeof (struct guestfs_int_bool));\n";
7385 pr " sscanf (val, \"%%\" SCNi32, &r->i);\n";
7389 pr " struct guestfs_lvm_pv_list *r;\n";
7391 pr " r = malloc (sizeof (struct guestfs_lvm_pv_list));\n";
7392 pr " sscanf (val, \"%%d\", &r->len);\n";
7393 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_pv));\n";
7394 pr " for (i = 0; i < r->len; ++i) {\n";
7395 pr " r->val[i].pv_name = malloc (16);\n";
7396 pr " snprintf (r->val[i].pv_name, 16, \"%%d\", i);\n";
7400 pr " struct guestfs_lvm_vg_list *r;\n";
7402 pr " r = malloc (sizeof (struct guestfs_lvm_vg_list));\n";
7403 pr " sscanf (val, \"%%d\", &r->len);\n";
7404 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_vg));\n";
7405 pr " for (i = 0; i < r->len; ++i) {\n";
7406 pr " r->val[i].vg_name = malloc (16);\n";
7407 pr " snprintf (r->val[i].vg_name, 16, \"%%d\", i);\n";
7411 pr " struct guestfs_lvm_lv_list *r;\n";
7413 pr " r = malloc (sizeof (struct guestfs_lvm_lv_list));\n";
7414 pr " sscanf (val, \"%%d\", &r->len);\n";
7415 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_lv));\n";
7416 pr " for (i = 0; i < r->len; ++i) {\n";
7417 pr " r->val[i].lv_name = malloc (16);\n";
7418 pr " snprintf (r->val[i].lv_name, 16, \"%%d\", i);\n";
7422 pr " struct guestfs_stat *r;\n";
7423 pr " r = calloc (1, sizeof (*r));\n";
7424 pr " sscanf (val, \"%%\" SCNi64, &r->dev);\n";
7427 pr " struct guestfs_statvfs *r;\n";
7428 pr " r = calloc (1, sizeof (*r));\n";
7429 pr " sscanf (val, \"%%\" SCNi64, &r->bsize);\n";
7432 pr " char **strs;\n";
7434 pr " sscanf (val, \"%%d\", &n);\n";
7435 pr " strs = malloc ((n*2+1) * sizeof (char *));\n";
7436 pr " for (i = 0; i < n; ++i) {\n";
7437 pr " strs[i*2] = malloc (16);\n";
7438 pr " strs[i*2+1] = malloc (16);\n";
7439 pr " snprintf (strs[i*2], 16, \"%%d\", i);\n";
7440 pr " snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
7442 pr " strs[n*2] = NULL;\n";
7443 pr " return strs;\n"
7448 pr "/* Test error return. */\n";
7449 generate_prototype ~extern:false ~semicolon:false ~newline:true
7450 ~handle:"g" ~prefix:"guestfs_" name style;
7452 pr " error (g, \"error\");\n";
7453 (match fst style with
7454 | RErr | RInt _ | RInt64 _ | RBool _ ->
7457 | RString _ | RStringList _ | RIntBool _
7458 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7460 pr " return NULL;\n"
7467 and generate_ocaml_bindtests () =
7468 generate_header OCamlStyle GPLv2;
7472 let g = Guestfs.create () in
7479 | CallString s -> "\"" ^ s ^ "\""
7480 | CallOptString None -> "None"
7481 | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
7482 | CallStringList xs ->
7483 "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
7484 | CallInt i when i >= 0 -> string_of_int i
7485 | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
7486 | CallBool b -> string_of_bool b
7491 generate_lang_bindtests (
7492 fun f args -> pr " Guestfs.%s g %s;\n" f (mkargs args)
7495 pr "print_endline \"EOF\"\n"
7497 and generate_perl_bindtests () =
7498 pr "#!/usr/bin/perl -w\n";
7499 generate_header HashStyle GPLv2;
7506 my $g = Sys::Guestfs->new ();
7510 String.concat ", " (
7513 | CallString s -> "\"" ^ s ^ "\""
7514 | CallOptString None -> "undef"
7515 | CallOptString (Some s) -> sprintf "\"%s\"" s
7516 | CallStringList xs ->
7517 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7518 | CallInt i -> string_of_int i
7519 | CallBool b -> if b then "1" else "0"
7524 generate_lang_bindtests (
7525 fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
7528 pr "print \"EOF\\n\"\n"
7530 and generate_python_bindtests () =
7531 generate_header HashStyle GPLv2;
7536 g = guestfs.GuestFS ()
7540 String.concat ", " (
7543 | CallString s -> "\"" ^ s ^ "\""
7544 | CallOptString None -> "None"
7545 | CallOptString (Some s) -> sprintf "\"%s\"" s
7546 | CallStringList xs ->
7547 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7548 | CallInt i -> string_of_int i
7549 | CallBool b -> if b then "1" else "0"
7554 generate_lang_bindtests (
7555 fun f args -> pr "g.%s (%s)\n" f (mkargs args)
7558 pr "print \"EOF\"\n"
7560 and generate_ruby_bindtests () =
7561 generate_header HashStyle GPLv2;
7566 g = Guestfs::create()
7570 String.concat ", " (
7573 | CallString s -> "\"" ^ s ^ "\""
7574 | CallOptString None -> "nil"
7575 | CallOptString (Some s) -> sprintf "\"%s\"" s
7576 | CallStringList xs ->
7577 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7578 | CallInt i -> string_of_int i
7579 | CallBool b -> string_of_bool b
7584 generate_lang_bindtests (
7585 fun f args -> pr "g.%s(%s)\n" f (mkargs args)
7588 pr "print \"EOF\\n\"\n"
7590 and generate_java_bindtests () =
7591 generate_header CStyle GPLv2;
7594 import com.redhat.et.libguestfs.*;
7596 public class Bindtests {
7597 public static void main (String[] argv)
7600 GuestFS g = new GuestFS ();
7604 String.concat ", " (
7607 | CallString s -> "\"" ^ s ^ "\""
7608 | CallOptString None -> "null"
7609 | CallOptString (Some s) -> sprintf "\"%s\"" s
7610 | CallStringList xs ->
7612 String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
7613 | CallInt i -> string_of_int i
7614 | CallBool b -> string_of_bool b
7619 generate_lang_bindtests (
7620 fun f args -> pr " g.%s (%s);\n" f (mkargs args)
7624 System.out.println (\"EOF\");
7626 catch (Exception exn) {
7627 System.err.println (exn);
7634 and generate_haskell_bindtests () =
7635 () (* XXX Haskell bindings need to be fleshed out. *)
7637 (* Language-independent bindings tests - we do it this way to
7638 * ensure there is parity in testing bindings across all languages.
7640 and generate_lang_bindtests call =
7641 call "test0" [CallString "abc"; CallOptString (Some "def");
7642 CallStringList []; CallBool false;
7643 CallInt 0; CallString "123"; CallString "456"];
7644 call "test0" [CallString "abc"; CallOptString None;
7645 CallStringList []; CallBool false;
7646 CallInt 0; CallString "123"; CallString "456"];
7647 call "test0" [CallString ""; CallOptString (Some "def");
7648 CallStringList []; CallBool false;
7649 CallInt 0; CallString "123"; CallString "456"];
7650 call "test0" [CallString ""; CallOptString (Some "");
7651 CallStringList []; CallBool false;
7652 CallInt 0; CallString "123"; CallString "456"];
7653 call "test0" [CallString "abc"; CallOptString (Some "def");
7654 CallStringList ["1"]; CallBool false;
7655 CallInt 0; CallString "123"; CallString "456"];
7656 call "test0" [CallString "abc"; CallOptString (Some "def");
7657 CallStringList ["1"; "2"]; CallBool false;
7658 CallInt 0; CallString "123"; CallString "456"];
7659 call "test0" [CallString "abc"; CallOptString (Some "def");
7660 CallStringList ["1"]; CallBool true;
7661 CallInt 0; CallString "123"; CallString "456"];
7662 call "test0" [CallString "abc"; CallOptString (Some "def");
7663 CallStringList ["1"]; CallBool false;
7664 CallInt (-1); CallString "123"; CallString "456"];
7665 call "test0" [CallString "abc"; CallOptString (Some "def");
7666 CallStringList ["1"]; CallBool false;
7667 CallInt (-2); CallString "123"; CallString "456"];
7668 call "test0" [CallString "abc"; CallOptString (Some "def");
7669 CallStringList ["1"]; CallBool false;
7670 CallInt 1; CallString "123"; CallString "456"];
7671 call "test0" [CallString "abc"; CallOptString (Some "def");
7672 CallStringList ["1"]; CallBool false;
7673 CallInt 2; CallString "123"; CallString "456"];
7674 call "test0" [CallString "abc"; CallOptString (Some "def");
7675 CallStringList ["1"]; CallBool false;
7676 CallInt 4095; CallString "123"; CallString "456"];
7677 call "test0" [CallString "abc"; CallOptString (Some "def");
7678 CallStringList ["1"]; CallBool false;
7679 CallInt 0; CallString ""; CallString ""]
7681 (* XXX Add here tests of the return and error functions. *)
7683 let output_to filename =
7684 let filename_new = filename ^ ".new" in
7685 chan := open_out filename_new;
7690 (* Is the new file different from the current file? *)
7691 if Sys.file_exists filename && files_equal filename filename_new then
7692 Unix.unlink filename_new (* same, so skip it *)
7694 (* different, overwrite old one *)
7695 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
7696 Unix.rename filename_new filename;
7697 Unix.chmod filename 0o444;
7698 printf "written %s\n%!" filename;
7707 if not (Sys.file_exists "configure.ac") then (
7709 You are probably running this from the wrong directory.
7710 Run it from the top source directory using the command
7716 let close = output_to "src/guestfs_protocol.x" in
7720 let close = output_to "src/guestfs-structs.h" in
7721 generate_structs_h ();
7724 let close = output_to "src/guestfs-actions.h" in
7725 generate_actions_h ();
7728 let close = output_to "src/guestfs-actions.c" in
7729 generate_client_actions ();
7732 let close = output_to "daemon/actions.h" in
7733 generate_daemon_actions_h ();
7736 let close = output_to "daemon/stubs.c" in
7737 generate_daemon_actions ();
7740 let close = output_to "capitests/tests.c" in
7744 let close = output_to "src/guestfs-bindtests.c" in
7745 generate_bindtests ();
7748 let close = output_to "fish/cmds.c" in
7749 generate_fish_cmds ();
7752 let close = output_to "fish/completion.c" in
7753 generate_fish_completion ();
7756 let close = output_to "guestfs-structs.pod" in
7757 generate_structs_pod ();
7760 let close = output_to "guestfs-actions.pod" in
7761 generate_actions_pod ();
7764 let close = output_to "guestfish-actions.pod" in
7765 generate_fish_actions_pod ();
7768 let close = output_to "ocaml/guestfs.mli" in
7769 generate_ocaml_mli ();
7772 let close = output_to "ocaml/guestfs.ml" in
7773 generate_ocaml_ml ();
7776 let close = output_to "ocaml/guestfs_c_actions.c" in
7777 generate_ocaml_c ();
7780 let close = output_to "ocaml/bindtests.ml" in
7781 generate_ocaml_bindtests ();
7784 let close = output_to "perl/Guestfs.xs" in
7785 generate_perl_xs ();
7788 let close = output_to "perl/lib/Sys/Guestfs.pm" in
7789 generate_perl_pm ();
7792 let close = output_to "perl/bindtests.pl" in
7793 generate_perl_bindtests ();
7796 let close = output_to "python/guestfs-py.c" in
7797 generate_python_c ();
7800 let close = output_to "python/guestfs.py" in
7801 generate_python_py ();
7804 let close = output_to "python/bindtests.py" in
7805 generate_python_bindtests ();
7808 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
7812 let close = output_to "ruby/bindtests.rb" in
7813 generate_ruby_bindtests ();
7816 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
7817 generate_java_java ();
7820 let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
7821 generate_java_struct "PV" pv_cols;
7824 let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
7825 generate_java_struct "VG" vg_cols;
7828 let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
7829 generate_java_struct "LV" lv_cols;
7832 let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
7833 generate_java_struct "Stat" stat_cols;
7836 let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
7837 generate_java_struct "StatVFS" statvfs_cols;
7840 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
7844 let close = output_to "java/Bindtests.java" in
7845 generate_java_bindtests ();
7848 let close = output_to "haskell/Guestfs.hs" in
7849 generate_haskell_hs ();
7852 let close = output_to "haskell/bindtests.hs" in
7853 generate_haskell_bindtests ();