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>.");
2314 ("sleep", (RErr, [Int "secs"]), 109, [],
2315 [InitNone, Always, TestRun (
2317 "sleep for some seconds",
2319 Sleep for C<secs> seconds.");
2323 let all_functions = non_daemon_functions @ daemon_functions
2325 (* In some places we want the functions to be displayed sorted
2326 * alphabetically, so this is useful:
2328 let all_functions_sorted =
2329 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2330 compare n1 n2) all_functions
2332 (* Column names and types from LVM PVs/VGs/LVs. *)
2341 "pv_attr", `String (* XXX *);
2342 "pv_pe_count", `Int;
2343 "pv_pe_alloc_count", `Int;
2346 "pv_mda_count", `Int;
2347 "pv_mda_free", `Bytes;
2348 (* Not in Fedora 10:
2349 "pv_mda_size", `Bytes;
2356 "vg_attr", `String (* XXX *);
2359 "vg_sysid", `String;
2360 "vg_extent_size", `Bytes;
2361 "vg_extent_count", `Int;
2362 "vg_free_count", `Int;
2370 "vg_mda_count", `Int;
2371 "vg_mda_free", `Bytes;
2372 (* Not in Fedora 10:
2373 "vg_mda_size", `Bytes;
2379 "lv_attr", `String (* XXX *);
2382 "lv_kernel_major", `Int;
2383 "lv_kernel_minor", `Int;
2387 "snap_percent", `OptPercent;
2388 "copy_percent", `OptPercent;
2391 "mirror_log", `String;
2395 (* Column names and types from stat structures.
2396 * NB. Can't use things like 'st_atime' because glibc header files
2397 * define some of these as macros. Ugh.
2414 let statvfs_cols = [
2428 (* Used for testing language bindings. *)
2430 | CallString of string
2431 | CallOptString of string option
2432 | CallStringList of string list
2436 (* Useful functions.
2437 * Note we don't want to use any external OCaml libraries which
2438 * makes this a bit harder than it should be.
2440 let failwithf fs = ksprintf failwith fs
2442 let replace_char s c1 c2 =
2443 let s2 = String.copy s in
2444 let r = ref false in
2445 for i = 0 to String.length s2 - 1 do
2446 if String.unsafe_get s2 i = c1 then (
2447 String.unsafe_set s2 i c2;
2451 if not !r then s else s2
2455 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2457 let triml ?(test = isspace) str =
2459 let n = ref (String.length str) in
2460 while !n > 0 && test str.[!i]; do
2465 else String.sub str !i !n
2467 let trimr ?(test = isspace) str =
2468 let n = ref (String.length str) in
2469 while !n > 0 && test str.[!n-1]; do
2472 if !n = String.length str then str
2473 else String.sub str 0 !n
2475 let trim ?(test = isspace) str =
2476 trimr ~test (triml ~test str)
2478 let rec find s sub =
2479 let len = String.length s in
2480 let sublen = String.length sub in
2482 if i <= len-sublen then (
2484 if j < sublen then (
2485 if s.[i+j] = sub.[j] then loop2 (j+1)
2491 if r = -1 then loop (i+1) else r
2497 let rec replace_str s s1 s2 =
2498 let len = String.length s in
2499 let sublen = String.length s1 in
2500 let i = find s s1 in
2503 let s' = String.sub s 0 i in
2504 let s'' = String.sub s (i+sublen) (len-i-sublen) in
2505 s' ^ s2 ^ replace_str s'' s1 s2
2508 let rec string_split sep str =
2509 let len = String.length str in
2510 let seplen = String.length sep in
2511 let i = find str sep in
2512 if i = -1 then [str]
2514 let s' = String.sub str 0 i in
2515 let s'' = String.sub str (i+seplen) (len-i-seplen) in
2516 s' :: string_split sep s''
2519 let files_equal n1 n2 =
2520 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
2521 match Sys.command cmd with
2524 | i -> failwithf "%s: failed with error code %d" cmd i
2526 let rec find_map f = function
2527 | [] -> raise Not_found
2531 | None -> find_map f xs
2534 let rec loop i = function
2536 | x :: xs -> f i x; loop (i+1) xs
2541 let rec loop i = function
2543 | x :: xs -> let r = f i x in r :: loop (i+1) xs
2547 let name_of_argt = function
2548 | String n | OptString n | StringList n | Bool n | Int n
2549 | FileIn n | FileOut n -> n
2551 let seq_of_test = function
2552 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
2553 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
2554 | TestOutputLength (s, _) | TestOutputStruct (s, _)
2555 | TestLastFail s -> s
2557 (* Check function names etc. for consistency. *)
2558 let check_functions () =
2559 let contains_uppercase str =
2560 let len = String.length str in
2562 if i >= len then false
2565 if c >= 'A' && c <= 'Z' then true
2572 (* Check function names. *)
2574 fun (name, _, _, _, _, _, _) ->
2575 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
2576 failwithf "function name %s does not need 'guestfs' prefix" name;
2578 failwithf "function name is empty";
2579 if name.[0] < 'a' || name.[0] > 'z' then
2580 failwithf "function name %s must start with lowercase a-z" name;
2581 if String.contains name '-' then
2582 failwithf "function name %s should not contain '-', use '_' instead."
2586 (* Check function parameter/return names. *)
2588 fun (name, style, _, _, _, _, _) ->
2589 let check_arg_ret_name n =
2590 if contains_uppercase n then
2591 failwithf "%s param/ret %s should not contain uppercase chars"
2593 if String.contains n '-' || String.contains n '_' then
2594 failwithf "%s param/ret %s should not contain '-' or '_'"
2597 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;
2598 if n = "int" || n = "char" || n = "short" || n = "long" then
2599 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
2601 failwithf "%s has a param/ret called 'i', which will cause some conflicts in the generated code" name;
2602 if n = "argv" || n = "args" then
2603 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
2606 (match fst style with
2608 | RInt n | RInt64 n | RBool n | RConstString n | RString n
2609 | RStringList n | RPVList n | RVGList n | RLVList n
2610 | RStat n | RStatVFS n
2612 check_arg_ret_name n
2614 check_arg_ret_name n;
2615 check_arg_ret_name m
2617 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
2620 (* Check short descriptions. *)
2622 fun (name, _, _, _, _, shortdesc, _) ->
2623 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
2624 failwithf "short description of %s should begin with lowercase." name;
2625 let c = shortdesc.[String.length shortdesc-1] in
2626 if c = '\n' || c = '.' then
2627 failwithf "short description of %s should not end with . or \\n." name
2630 (* Check long dscriptions. *)
2632 fun (name, _, _, _, _, _, longdesc) ->
2633 if longdesc.[String.length longdesc-1] = '\n' then
2634 failwithf "long description of %s should not end with \\n." name
2637 (* Check proc_nrs. *)
2639 fun (name, _, proc_nr, _, _, _, _) ->
2640 if proc_nr <= 0 then
2641 failwithf "daemon function %s should have proc_nr > 0" name
2645 fun (name, _, proc_nr, _, _, _, _) ->
2646 if proc_nr <> -1 then
2647 failwithf "non-daemon function %s should have proc_nr -1" name
2648 ) non_daemon_functions;
2651 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
2654 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
2655 let rec loop = function
2658 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
2660 | (name1,nr1) :: (name2,nr2) :: _ ->
2661 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
2669 (* Ignore functions that have no tests. We generate a
2670 * warning when the user does 'make check' instead.
2672 | name, _, _, _, [], _, _ -> ()
2673 | name, _, _, _, tests, _, _ ->
2677 match seq_of_test test with
2679 failwithf "%s has a test containing an empty sequence" name
2680 | cmds -> List.map List.hd cmds
2682 let funcs = List.flatten funcs in
2684 let tested = List.mem name funcs in
2687 failwithf "function %s has tests but does not test itself" name
2690 (* 'pr' prints to the current output file. *)
2691 let chan = ref stdout
2692 let pr fs = ksprintf (output_string !chan) fs
2694 (* Generate a header block in a number of standard styles. *)
2695 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
2696 type license = GPLv2 | LGPLv2
2698 let generate_header comment license =
2699 let c = match comment with
2700 | CStyle -> pr "/* "; " *"
2701 | HashStyle -> pr "# "; "#"
2702 | OCamlStyle -> pr "(* "; " *"
2703 | HaskellStyle -> pr "{- "; " " in
2704 pr "libguestfs generated file\n";
2705 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
2706 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
2708 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
2712 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
2713 pr "%s it under the terms of the GNU General Public License as published by\n" c;
2714 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
2715 pr "%s (at your option) any later version.\n" c;
2717 pr "%s This program is distributed in the hope that it will be useful,\n" c;
2718 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2719 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
2720 pr "%s GNU General Public License for more details.\n" c;
2722 pr "%s You should have received a copy of the GNU General Public License along\n" c;
2723 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
2724 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
2727 pr "%s This library is free software; you can redistribute it and/or\n" c;
2728 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
2729 pr "%s License as published by the Free Software Foundation; either\n" c;
2730 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
2732 pr "%s This library is distributed in the hope that it will be useful,\n" c;
2733 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2734 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
2735 pr "%s Lesser General Public License for more details.\n" c;
2737 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
2738 pr "%s License along with this library; if not, write to the Free Software\n" c;
2739 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
2742 | CStyle -> pr " */\n"
2744 | OCamlStyle -> pr " *)\n"
2745 | HaskellStyle -> pr "-}\n"
2749 (* Start of main code generation functions below this line. *)
2751 (* Generate the pod documentation for the C API. *)
2752 let rec generate_actions_pod () =
2754 fun (shortname, style, _, flags, _, _, longdesc) ->
2755 if not (List.mem NotInDocs flags) then (
2756 let name = "guestfs_" ^ shortname in
2757 pr "=head2 %s\n\n" name;
2759 generate_prototype ~extern:false ~handle:"handle" name style;
2761 pr "%s\n\n" longdesc;
2762 (match fst style with
2764 pr "This function returns 0 on success or -1 on error.\n\n"
2766 pr "On error this function returns -1.\n\n"
2768 pr "On error this function returns -1.\n\n"
2770 pr "This function returns a C truth value on success or -1 on error.\n\n"
2772 pr "This function returns a string, or NULL on error.
2773 The string is owned by the guest handle and must I<not> be freed.\n\n"
2775 pr "This function returns a string, or NULL on error.
2776 I<The caller must free the returned string after use>.\n\n"
2778 pr "This function returns a NULL-terminated array of strings
2779 (like L<environ(3)>), or NULL if there was an error.
2780 I<The caller must free the strings and the array after use>.\n\n"
2782 pr "This function returns a C<struct guestfs_int_bool *>,
2783 or NULL if there was an error.
2784 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
2786 pr "This function returns a C<struct guestfs_lvm_pv_list *>
2787 (see E<lt>guestfs-structs.hE<gt>),
2788 or NULL if there was an error.
2789 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
2791 pr "This function returns a C<struct guestfs_lvm_vg_list *>
2792 (see E<lt>guestfs-structs.hE<gt>),
2793 or NULL if there was an error.
2794 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
2796 pr "This function returns a C<struct guestfs_lvm_lv_list *>
2797 (see E<lt>guestfs-structs.hE<gt>),
2798 or NULL if there was an error.
2799 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
2801 pr "This function returns a C<struct guestfs_stat *>
2802 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
2803 or NULL if there was an error.
2804 I<The caller must call C<free> after use>.\n\n"
2806 pr "This function returns a C<struct guestfs_statvfs *>
2807 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
2808 or NULL if there was an error.
2809 I<The caller must call C<free> after use>.\n\n"
2811 pr "This function returns a NULL-terminated array of
2812 strings, or NULL if there was an error.
2813 The array of strings will always have length C<2n+1>, where
2814 C<n> keys and values alternate, followed by the trailing NULL entry.
2815 I<The caller must free the strings and the array after use>.\n\n"
2817 if List.mem ProtocolLimitWarning flags then
2818 pr "%s\n\n" protocol_limit_warning;
2819 if List.mem DangerWillRobinson flags then
2820 pr "%s\n\n" danger_will_robinson
2822 ) all_functions_sorted
2824 and generate_structs_pod () =
2825 (* LVM structs documentation. *)
2828 pr "=head2 guestfs_lvm_%s\n" typ;
2830 pr " struct guestfs_lvm_%s {\n" typ;
2833 | name, `String -> pr " char *%s;\n" name
2835 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
2836 pr " char %s[32];\n" name
2837 | name, `Bytes -> pr " uint64_t %s;\n" name
2838 | name, `Int -> pr " int64_t %s;\n" name
2839 | name, `OptPercent ->
2840 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
2841 pr " float %s;\n" name
2844 pr " struct guestfs_lvm_%s_list {\n" typ;
2845 pr " uint32_t len; /* Number of elements in list. */\n";
2846 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
2849 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
2852 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2854 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
2855 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
2857 * We have to use an underscore instead of a dash because otherwise
2858 * rpcgen generates incorrect code.
2860 * This header is NOT exported to clients, but see also generate_structs_h.
2862 and generate_xdr () =
2863 generate_header CStyle LGPLv2;
2865 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
2866 pr "typedef string str<>;\n";
2869 (* LVM internal structures. *)
2873 pr "struct guestfs_lvm_int_%s {\n" typ;
2875 | name, `String -> pr " string %s<>;\n" name
2876 | name, `UUID -> pr " opaque %s[32];\n" name
2877 | name, `Bytes -> pr " hyper %s;\n" name
2878 | name, `Int -> pr " hyper %s;\n" name
2879 | name, `OptPercent -> pr " float %s;\n" name
2883 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
2885 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2887 (* Stat internal structures. *)
2891 pr "struct guestfs_int_%s {\n" typ;
2893 | name, `Int -> pr " hyper %s;\n" name
2897 ) ["stat", stat_cols; "statvfs", statvfs_cols];
2900 fun (shortname, style, _, _, _, _, _) ->
2901 let name = "guestfs_" ^ shortname in
2903 (match snd style with
2906 pr "struct %s_args {\n" name;
2909 | String n -> pr " string %s<>;\n" n
2910 | OptString n -> pr " str *%s;\n" n
2911 | StringList n -> pr " str %s<>;\n" n
2912 | Bool n -> pr " bool %s;\n" n
2913 | Int n -> pr " int %s;\n" n
2914 | FileIn _ | FileOut _ -> ()
2918 (match fst style with
2921 pr "struct %s_ret {\n" name;
2925 pr "struct %s_ret {\n" name;
2926 pr " hyper %s;\n" n;
2929 pr "struct %s_ret {\n" name;
2933 failwithf "RConstString cannot be returned from a daemon function"
2935 pr "struct %s_ret {\n" name;
2936 pr " string %s<>;\n" n;
2939 pr "struct %s_ret {\n" name;
2940 pr " str %s<>;\n" n;
2943 pr "struct %s_ret {\n" name;
2948 pr "struct %s_ret {\n" name;
2949 pr " guestfs_lvm_int_pv_list %s;\n" n;
2952 pr "struct %s_ret {\n" name;
2953 pr " guestfs_lvm_int_vg_list %s;\n" n;
2956 pr "struct %s_ret {\n" name;
2957 pr " guestfs_lvm_int_lv_list %s;\n" n;
2960 pr "struct %s_ret {\n" name;
2961 pr " guestfs_int_stat %s;\n" n;
2964 pr "struct %s_ret {\n" name;
2965 pr " guestfs_int_statvfs %s;\n" n;
2968 pr "struct %s_ret {\n" name;
2969 pr " str %s<>;\n" n;
2974 (* Table of procedure numbers. *)
2975 pr "enum guestfs_procedure {\n";
2977 fun (shortname, _, proc_nr, _, _, _, _) ->
2978 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
2980 pr " GUESTFS_PROC_NR_PROCS\n";
2984 (* Having to choose a maximum message size is annoying for several
2985 * reasons (it limits what we can do in the API), but it (a) makes
2986 * the protocol a lot simpler, and (b) provides a bound on the size
2987 * of the daemon which operates in limited memory space. For large
2988 * file transfers you should use FTP.
2990 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
2993 (* Message header, etc. *)
2995 /* The communication protocol is now documented in the guestfs(3)
2999 const GUESTFS_PROGRAM = 0x2000F5F5;
3000 const GUESTFS_PROTOCOL_VERSION = 1;
3002 /* These constants must be larger than any possible message length. */
3003 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3004 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3006 enum guestfs_message_direction {
3007 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
3008 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
3011 enum guestfs_message_status {
3012 GUESTFS_STATUS_OK = 0,
3013 GUESTFS_STATUS_ERROR = 1
3016 const GUESTFS_ERROR_LEN = 256;
3018 struct guestfs_message_error {
3019 string error_message<GUESTFS_ERROR_LEN>;
3022 struct guestfs_message_header {
3023 unsigned prog; /* GUESTFS_PROGRAM */
3024 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
3025 guestfs_procedure proc; /* GUESTFS_PROC_x */
3026 guestfs_message_direction direction;
3027 unsigned serial; /* message serial number */
3028 guestfs_message_status status;
3031 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3033 struct guestfs_chunk {
3034 int cancel; /* if non-zero, transfer is cancelled */
3035 /* data size is 0 bytes if the transfer has finished successfully */
3036 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3040 (* Generate the guestfs-structs.h file. *)
3041 and generate_structs_h () =
3042 generate_header CStyle LGPLv2;
3044 (* This is a public exported header file containing various
3045 * structures. The structures are carefully written to have
3046 * exactly the same in-memory format as the XDR structures that
3047 * we use on the wire to the daemon. The reason for creating
3048 * copies of these structures here is just so we don't have to
3049 * export the whole of guestfs_protocol.h (which includes much
3050 * unrelated and XDR-dependent stuff that we don't want to be
3051 * public, or required by clients).
3053 * To reiterate, we will pass these structures to and from the
3054 * client with a simple assignment or memcpy, so the format
3055 * must be identical to what rpcgen / the RFC defines.
3058 (* guestfs_int_bool structure. *)
3059 pr "struct guestfs_int_bool {\n";
3065 (* LVM public structures. *)
3069 pr "struct guestfs_lvm_%s {\n" typ;
3072 | name, `String -> pr " char *%s;\n" name
3073 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3074 | name, `Bytes -> pr " uint64_t %s;\n" name
3075 | name, `Int -> pr " int64_t %s;\n" name
3076 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
3080 pr "struct guestfs_lvm_%s_list {\n" typ;
3081 pr " uint32_t len;\n";
3082 pr " struct guestfs_lvm_%s *val;\n" typ;
3085 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3087 (* Stat structures. *)
3091 pr "struct guestfs_%s {\n" typ;
3094 | name, `Int -> pr " int64_t %s;\n" name
3098 ) ["stat", stat_cols; "statvfs", statvfs_cols]
3100 (* Generate the guestfs-actions.h file. *)
3101 and generate_actions_h () =
3102 generate_header CStyle LGPLv2;
3104 fun (shortname, style, _, _, _, _, _) ->
3105 let name = "guestfs_" ^ shortname in
3106 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3110 (* Generate the client-side dispatch stubs. *)
3111 and generate_client_actions () =
3112 generate_header CStyle LGPLv2;
3118 #include \"guestfs.h\"
3119 #include \"guestfs_protocol.h\"
3121 #define error guestfs_error
3122 #define perrorf guestfs_perrorf
3123 #define safe_malloc guestfs_safe_malloc
3124 #define safe_realloc guestfs_safe_realloc
3125 #define safe_strdup guestfs_safe_strdup
3126 #define safe_memdup guestfs_safe_memdup
3128 /* Check the return message from a call for validity. */
3130 check_reply_header (guestfs_h *g,
3131 const struct guestfs_message_header *hdr,
3132 int proc_nr, int serial)
3134 if (hdr->prog != GUESTFS_PROGRAM) {
3135 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3138 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3139 error (g, \"wrong protocol version (%%d/%%d)\",
3140 hdr->vers, GUESTFS_PROTOCOL_VERSION);
3143 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3144 error (g, \"unexpected message direction (%%d/%%d)\",
3145 hdr->direction, GUESTFS_DIRECTION_REPLY);
3148 if (hdr->proc != proc_nr) {
3149 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3152 if (hdr->serial != serial) {
3153 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3160 /* Check we are in the right state to run a high-level action. */
3162 check_state (guestfs_h *g, const char *caller)
3164 if (!guestfs_is_ready (g)) {
3165 if (guestfs_is_config (g))
3166 error (g, \"%%s: call launch() before using this function\",
3168 else if (guestfs_is_launching (g))
3169 error (g, \"%%s: call wait_ready() before using this function\",
3172 error (g, \"%%s called from the wrong state, %%d != READY\",
3173 caller, guestfs_get_state (g));
3181 (* Client-side stubs for each function. *)
3183 fun (shortname, style, _, _, _, _, _) ->
3184 let name = "guestfs_" ^ shortname in
3186 (* Generate the context struct which stores the high-level
3187 * state between callback functions.
3189 pr "struct %s_ctx {\n" shortname;
3190 pr " /* This flag is set by the callbacks, so we know we've done\n";
3191 pr " * the callbacks as expected, and in the right sequence.\n";
3192 pr " * 0 = not called, 1 = reply_cb called.\n";
3194 pr " int cb_sequence;\n";
3195 pr " struct guestfs_message_header hdr;\n";
3196 pr " struct guestfs_message_error err;\n";
3197 (match fst style with
3200 failwithf "RConstString cannot be returned from a daemon function"
3202 | RBool _ | RString _ | RStringList _
3204 | RPVList _ | RVGList _ | RLVList _
3205 | RStat _ | RStatVFS _
3207 pr " struct %s_ret ret;\n" name
3212 (* Generate the reply callback function. *)
3213 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3215 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3216 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3218 pr " /* This should definitely not happen. */\n";
3219 pr " if (ctx->cb_sequence != 0) {\n";
3220 pr " ctx->cb_sequence = 9999;\n";
3221 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3225 pr " ml->main_loop_quit (ml, g);\n";
3227 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3228 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3231 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3232 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3233 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3240 (match fst style with
3243 failwithf "RConstString cannot be returned from a daemon function"
3245 | RBool _ | RString _ | RStringList _
3247 | RPVList _ | RVGList _ | RLVList _
3248 | RStat _ | RStatVFS _
3250 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3251 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3257 pr " ctx->cb_sequence = 1;\n";
3260 (* Generate the action stub. *)
3261 generate_prototype ~extern:false ~semicolon:false ~newline:true
3262 ~handle:"g" name style;
3265 match fst style with
3266 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3268 failwithf "RConstString cannot be returned from a daemon function"
3269 | RString _ | RStringList _ | RIntBool _
3270 | RPVList _ | RVGList _ | RLVList _
3271 | RStat _ | RStatVFS _
3277 (match snd style with
3279 | _ -> pr " struct %s_args args;\n" name
3282 pr " struct %s_ctx ctx;\n" shortname;
3283 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3284 pr " int serial;\n";
3286 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3287 pr " guestfs_set_busy (g);\n";
3289 pr " memset (&ctx, 0, sizeof ctx);\n";
3292 (* Send the main header and arguments. *)
3293 (match snd style with
3295 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3296 (String.uppercase shortname)
3301 pr " args.%s = (char *) %s;\n" n n
3303 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
3305 pr " args.%s.%s_val = (char **) %s;\n" n n n;
3306 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3308 pr " args.%s = %s;\n" n n
3310 pr " args.%s = %s;\n" n n
3311 | FileIn _ | FileOut _ -> ()
3313 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3314 (String.uppercase shortname);
3315 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3318 pr " if (serial == -1) {\n";
3319 pr " guestfs_end_busy (g);\n";
3320 pr " return %s;\n" error_code;
3324 (* Send any additional files (FileIn) requested. *)
3325 let need_read_reply_label = ref false in
3332 pr " r = guestfs__send_file_sync (g, %s);\n" n;
3333 pr " if (r == -1) {\n";
3334 pr " guestfs_end_busy (g);\n";
3335 pr " return %s;\n" error_code;
3337 pr " if (r == -2) /* daemon cancelled */\n";
3338 pr " goto read_reply;\n";
3339 need_read_reply_label := true;
3345 (* Wait for the reply from the remote end. *)
3346 if !need_read_reply_label then pr " read_reply:\n";
3347 pr " guestfs__switch_to_receiving (g);\n";
3348 pr " ctx.cb_sequence = 0;\n";
3349 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3350 pr " (void) ml->main_loop_run (ml, g);\n";
3351 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
3352 pr " if (ctx.cb_sequence != 1) {\n";
3353 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3354 pr " guestfs_end_busy (g);\n";
3355 pr " return %s;\n" error_code;
3359 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3360 (String.uppercase shortname);
3361 pr " guestfs_end_busy (g);\n";
3362 pr " return %s;\n" error_code;
3366 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3367 pr " error (g, \"%%s\", ctx.err.error_message);\n";
3368 pr " free (ctx.err.error_message);\n";
3369 pr " guestfs_end_busy (g);\n";
3370 pr " return %s;\n" error_code;
3374 (* Expecting to receive further files (FileOut)? *)
3378 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3379 pr " guestfs_end_busy (g);\n";
3380 pr " return %s;\n" error_code;
3386 pr " guestfs_end_busy (g);\n";
3388 (match fst style with
3389 | RErr -> pr " return 0;\n"
3390 | RInt n | RInt64 n | RBool n ->
3391 pr " return ctx.ret.%s;\n" n
3393 failwithf "RConstString cannot be returned from a daemon function"
3395 pr " return ctx.ret.%s; /* caller will free */\n" n
3396 | RStringList n | RHashtable n ->
3397 pr " /* caller will free this, but we need to add a NULL entry */\n";
3398 pr " ctx.ret.%s.%s_val =\n" n n;
3399 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3400 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3402 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3403 pr " return ctx.ret.%s.%s_val;\n" n n
3405 pr " /* caller with free this */\n";
3406 pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3407 | RPVList n | RVGList n | RLVList n
3408 | RStat n | RStatVFS n ->
3409 pr " /* caller will free this */\n";
3410 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3416 (* Generate daemon/actions.h. *)
3417 and generate_daemon_actions_h () =
3418 generate_header CStyle GPLv2;
3420 pr "#include \"../src/guestfs_protocol.h\"\n";
3424 fun (name, style, _, _, _, _, _) ->
3426 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3430 (* Generate the server-side stubs. *)
3431 and generate_daemon_actions () =
3432 generate_header CStyle GPLv2;
3434 pr "#include <config.h>\n";
3436 pr "#include <stdio.h>\n";
3437 pr "#include <stdlib.h>\n";
3438 pr "#include <string.h>\n";
3439 pr "#include <inttypes.h>\n";
3440 pr "#include <ctype.h>\n";
3441 pr "#include <rpc/types.h>\n";
3442 pr "#include <rpc/xdr.h>\n";
3444 pr "#include \"daemon.h\"\n";
3445 pr "#include \"../src/guestfs_protocol.h\"\n";
3446 pr "#include \"actions.h\"\n";
3450 fun (name, style, _, _, _, _, _) ->
3451 (* Generate server-side stubs. *)
3452 pr "static void %s_stub (XDR *xdr_in)\n" name;
3455 match fst style with
3456 | RErr | RInt _ -> pr " int r;\n"; "-1"
3457 | RInt64 _ -> pr " int64_t r;\n"; "-1"
3458 | RBool _ -> pr " int r;\n"; "-1"
3460 failwithf "RConstString cannot be returned from a daemon function"
3461 | RString _ -> pr " char *r;\n"; "NULL"
3462 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
3463 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
3464 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
3465 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
3466 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
3467 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
3468 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
3470 (match snd style with
3473 pr " struct guestfs_%s_args args;\n" name;
3477 | OptString n -> pr " const char *%s;\n" n
3478 | StringList n -> pr " char **%s;\n" n
3479 | Bool n -> pr " int %s;\n" n
3480 | Int n -> pr " int %s;\n" n
3481 | FileIn _ | FileOut _ -> ()
3486 (match snd style with
3489 pr " memset (&args, 0, sizeof args);\n";
3491 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
3492 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
3497 | String n -> pr " %s = args.%s;\n" n n
3498 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
3500 pr " %s = realloc (args.%s.%s_val,\n" n n n;
3501 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
3502 pr " if (%s == NULL) {\n" n;
3503 pr " reply_with_perror (\"realloc\");\n";
3506 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
3507 pr " args.%s.%s_val = %s;\n" n n n;
3508 | Bool n -> pr " %s = args.%s;\n" n n
3509 | Int n -> pr " %s = args.%s;\n" n n
3510 | FileIn _ | FileOut _ -> ()
3515 (* Don't want to call the impl with any FileIn or FileOut
3516 * parameters, since these go "outside" the RPC protocol.
3519 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
3521 pr " r = do_%s " name;
3522 generate_call_args argsnofile;
3525 pr " if (r == %s)\n" error_code;
3526 pr " /* do_%s has already called reply_with_error */\n" name;
3530 (* If there are any FileOut parameters, then the impl must
3531 * send its own reply.
3534 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
3536 pr " /* do_%s has already sent a reply */\n" name
3538 match fst style with
3539 | RErr -> pr " reply (NULL, NULL);\n"
3540 | RInt n | RInt64 n | RBool n ->
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 failwithf "RConstString cannot be returned from a daemon function"
3548 pr " struct guestfs_%s_ret ret;\n" name;
3549 pr " ret.%s = r;\n" n;
3550 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3553 | RStringList n | RHashtable n ->
3554 pr " struct guestfs_%s_ret ret;\n" name;
3555 pr " ret.%s.%s_len = count_strings (r);\n" n n;
3556 pr " ret.%s.%s_val = r;\n" n n;
3557 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3559 pr " free_strings (r);\n"
3561 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
3563 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
3564 | RPVList n | RVGList n | RLVList n
3565 | RStat n | RStatVFS n ->
3566 pr " struct guestfs_%s_ret ret;\n" name;
3567 pr " ret.%s = *r;\n" n;
3568 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3570 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3574 (* Free the args. *)
3575 (match snd style with
3580 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
3587 (* Dispatch function. *)
3588 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
3590 pr " switch (proc_nr) {\n";
3593 fun (name, style, _, _, _, _, _) ->
3594 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
3595 pr " %s_stub (xdr_in);\n" name;
3600 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
3605 (* LVM columns and tokenization functions. *)
3606 (* XXX This generates crap code. We should rethink how we
3612 pr "static const char *lvm_%s_cols = \"%s\";\n"
3613 typ (String.concat "," (List.map fst cols));
3616 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
3618 pr " char *tok, *p, *next;\n";
3622 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
3625 pr " if (!str) {\n";
3626 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
3629 pr " if (!*str || isspace (*str)) {\n";
3630 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
3635 fun (name, coltype) ->
3636 pr " if (!tok) {\n";
3637 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
3640 pr " p = strchrnul (tok, ',');\n";
3641 pr " if (*p) next = p+1; else next = NULL;\n";
3642 pr " *p = '\\0';\n";
3645 pr " r->%s = strdup (tok);\n" name;
3646 pr " if (r->%s == NULL) {\n" name;
3647 pr " perror (\"strdup\");\n";
3651 pr " for (i = j = 0; i < 32; ++j) {\n";
3652 pr " if (tok[j] == '\\0') {\n";
3653 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
3655 pr " } else if (tok[j] != '-')\n";
3656 pr " r->%s[i++] = tok[j];\n" name;
3659 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
3660 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3664 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
3665 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3669 pr " if (tok[0] == '\\0')\n";
3670 pr " r->%s = -1;\n" name;
3671 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
3672 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3676 pr " tok = next;\n";
3679 pr " if (tok != NULL) {\n";
3680 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
3687 pr "guestfs_lvm_int_%s_list *\n" typ;
3688 pr "parse_command_line_%ss (void)\n" typ;
3690 pr " char *out, *err;\n";
3691 pr " char *p, *pend;\n";
3693 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
3694 pr " void *newp;\n";
3696 pr " ret = malloc (sizeof *ret);\n";
3697 pr " if (!ret) {\n";
3698 pr " reply_with_perror (\"malloc\");\n";
3699 pr " return NULL;\n";
3702 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
3703 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
3705 pr " r = command (&out, &err,\n";
3706 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
3707 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
3708 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
3709 pr " if (r == -1) {\n";
3710 pr " reply_with_error (\"%%s\", err);\n";
3711 pr " free (out);\n";
3712 pr " free (err);\n";
3713 pr " free (ret);\n";
3714 pr " return NULL;\n";
3717 pr " free (err);\n";
3719 pr " /* Tokenize each line of the output. */\n";
3722 pr " while (p) {\n";
3723 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
3724 pr " if (pend) {\n";
3725 pr " *pend = '\\0';\n";
3729 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
3732 pr " if (!*p) { /* Empty line? Skip it. */\n";
3737 pr " /* Allocate some space to store this next entry. */\n";
3738 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
3739 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
3740 pr " if (newp == NULL) {\n";
3741 pr " reply_with_perror (\"realloc\");\n";
3742 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3743 pr " free (ret);\n";
3744 pr " free (out);\n";
3745 pr " return NULL;\n";
3747 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
3749 pr " /* Tokenize the next entry. */\n";
3750 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
3751 pr " if (r == -1) {\n";
3752 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
3753 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3754 pr " free (ret);\n";
3755 pr " free (out);\n";
3756 pr " return NULL;\n";
3763 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
3765 pr " free (out);\n";
3766 pr " return ret;\n";
3769 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3771 (* Generate the tests. *)
3772 and generate_tests () =
3773 generate_header CStyle GPLv2;
3780 #include <sys/types.h>
3783 #include \"guestfs.h\"
3785 static guestfs_h *g;
3786 static int suppress_error = 0;
3788 /* This will be 's' or 'h' depending on whether the guest kernel
3789 * names IDE devices /dev/sd* or /dev/hd*.
3791 static char devchar = 's';
3793 static void print_error (guestfs_h *g, void *data, const char *msg)
3795 if (!suppress_error)
3796 fprintf (stderr, \"%%s\\n\", msg);
3799 static void print_strings (char * const * const argv)
3803 for (argc = 0; argv[argc] != NULL; ++argc)
3804 printf (\"\\t%%s\\n\", argv[argc]);
3808 static void print_table (char * const * const argv)
3812 for (i = 0; argv[i] != NULL; i += 2)
3813 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
3817 static void no_test_warnings (void)
3823 | name, _, _, _, [], _, _ ->
3824 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
3825 | name, _, _, _, tests, _, _ -> ()
3831 (* Generate the actual tests. Note that we generate the tests
3832 * in reverse order, deliberately, so that (in general) the
3833 * newest tests run first. This makes it quicker and easier to
3838 fun (name, _, _, _, tests, _, _) ->
3839 mapi (generate_one_test name) tests
3840 ) (List.rev all_functions) in
3841 let test_names = List.concat test_names in
3842 let nr_tests = List.length test_names in
3845 int main (int argc, char *argv[])
3849 const char *filename;
3851 int nr_tests, test_num = 0;
3854 no_test_warnings ();
3856 g = guestfs_create ();
3858 printf (\"guestfs_create FAILED\\n\");
3862 guestfs_set_error_handler (g, print_error, NULL);
3864 guestfs_set_path (g, \"../appliance\");
3866 filename = \"test1.img\";
3867 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3872 if (lseek (fd, %d, SEEK_SET) == -1) {
3878 if (write (fd, &c, 1) == -1) {
3884 if (close (fd) == -1) {
3889 if (guestfs_add_drive (g, filename) == -1) {
3890 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3894 filename = \"test2.img\";
3895 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3900 if (lseek (fd, %d, SEEK_SET) == -1) {
3906 if (write (fd, &c, 1) == -1) {
3912 if (close (fd) == -1) {
3917 if (guestfs_add_drive (g, filename) == -1) {
3918 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3922 filename = \"test3.img\";
3923 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3928 if (lseek (fd, %d, SEEK_SET) == -1) {
3934 if (write (fd, &c, 1) == -1) {
3940 if (close (fd) == -1) {
3945 if (guestfs_add_drive (g, filename) == -1) {
3946 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3950 if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
3951 printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
3955 if (guestfs_launch (g) == -1) {
3956 printf (\"guestfs_launch FAILED\\n\");
3959 if (guestfs_wait_ready (g) == -1) {
3960 printf (\"guestfs_wait_ready FAILED\\n\");
3964 /* Detect if the appliance uses /dev/sd* or /dev/hd* in device
3965 * names. This changed between RHEL 5 and RHEL 6 so we have to
3968 devs = guestfs_list_devices (g);
3969 if (devs == NULL || devs[0] == NULL) {
3970 printf (\"guestfs_list_devices FAILED\\n\");
3973 if (strncmp (devs[0], \"/dev/sd\", 7) == 0)
3975 else if (strncmp (devs[0], \"/dev/hd\", 7) == 0)
3978 printf (\"guestfs_list_devices returned unexpected string '%%s'\\n\",
3982 for (i = 0; devs[i] != NULL; ++i)
3988 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
3992 pr " test_num++;\n";
3993 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
3994 pr " if (%s () == -1) {\n" test_name;
3995 pr " printf (\"%s FAILED\\n\");\n" test_name;
4001 pr " guestfs_close (g);\n";
4002 pr " unlink (\"test1.img\");\n";
4003 pr " unlink (\"test2.img\");\n";
4004 pr " unlink (\"test3.img\");\n";
4007 pr " if (failed > 0) {\n";
4008 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4016 and generate_one_test name i (init, prereq, test) =
4017 let test_name = sprintf "test_%s_%d" name i in
4020 static int %s_skip (void)
4024 str = getenv (\"SKIP_%s\");
4025 if (str && strcmp (str, \"1\") == 0) return 1;
4026 str = getenv (\"SKIP_TEST_%s\");
4027 if (str && strcmp (str, \"1\") == 0) return 1;
4031 " test_name (String.uppercase test_name) (String.uppercase name);
4034 | Disabled | Always -> ()
4035 | If code | Unless code ->
4036 pr "static int %s_prereq (void)\n" test_name;
4044 static int %s (void)
4047 printf (\"%%s skipped (reason: SKIP_TEST_* variable set)\\n\", \"%s\");
4051 " test_name test_name test_name;
4055 pr " printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
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 pr " if (%s_prereq ()) {\n" test_name;
4065 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4069 generate_one_test_body name i test_name init test;
4071 generate_one_test_body name i test_name init test
4079 and generate_one_test_body name i test_name init test =
4083 pr " /* InitNone|InitEmpty for %s */\n" test_name;
4084 List.iter (generate_test_command_call test_name)
4085 [["blockdev_setrw"; "/dev/sda"];
4089 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4090 List.iter (generate_test_command_call test_name)
4091 [["blockdev_setrw"; "/dev/sda"];
4094 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4095 ["mkfs"; "ext2"; "/dev/sda1"];
4096 ["mount"; "/dev/sda1"; "/"]]
4097 | InitBasicFSonLVM ->
4098 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4100 List.iter (generate_test_command_call test_name)
4101 [["blockdev_setrw"; "/dev/sda"];
4104 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4105 ["pvcreate"; "/dev/sda1"];
4106 ["vgcreate"; "VG"; "/dev/sda1"];
4107 ["lvcreate"; "LV"; "VG"; "8"];
4108 ["mkfs"; "ext2"; "/dev/VG/LV"];
4109 ["mount"; "/dev/VG/LV"; "/"]]
4112 let get_seq_last = function
4114 failwithf "%s: you cannot use [] (empty list) when expecting a command"
4117 let seq = List.rev seq in
4118 List.rev (List.tl seq), List.hd seq
4123 pr " /* TestRun for %s (%d) */\n" name i;
4124 List.iter (generate_test_command_call test_name) seq
4125 | TestOutput (seq, expected) ->
4126 pr " /* TestOutput for %s (%d) */\n" name i;
4127 pr " char expected[] = \"%s\";\n" (c_quote expected);
4128 if String.length expected > 7 &&
4129 String.sub expected 0 7 = "/dev/sd" then
4130 pr " expected[5] = devchar;\n";
4131 let seq, last = get_seq_last seq in
4133 pr " if (strcmp (r, expected) != 0) {\n";
4134 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4138 List.iter (generate_test_command_call test_name) seq;
4139 generate_test_command_call ~test test_name last
4140 | TestOutputList (seq, expected) ->
4141 pr " /* TestOutputList for %s (%d) */\n" name i;
4142 let seq, last = get_seq_last seq in
4146 pr " if (!r[%d]) {\n" i;
4147 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4148 pr " print_strings (r);\n";
4152 pr " char expected[] = \"%s\";\n" (c_quote str);
4153 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
4154 pr " expected[5] = devchar;\n";
4155 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4156 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4161 pr " if (r[%d] != NULL) {\n" (List.length expected);
4162 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4164 pr " print_strings (r);\n";
4168 List.iter (generate_test_command_call test_name) seq;
4169 generate_test_command_call ~test test_name last
4170 | TestOutputInt (seq, expected) ->
4171 pr " /* TestOutputInt for %s (%d) */\n" name i;
4172 let seq, last = get_seq_last seq in
4174 pr " if (r != %d) {\n" expected;
4175 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4181 List.iter (generate_test_command_call test_name) seq;
4182 generate_test_command_call ~test test_name last
4183 | TestOutputTrue seq ->
4184 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4185 let seq, last = get_seq_last seq in
4188 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4193 List.iter (generate_test_command_call test_name) seq;
4194 generate_test_command_call ~test test_name last
4195 | TestOutputFalse seq ->
4196 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4197 let seq, last = get_seq_last seq in
4200 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4205 List.iter (generate_test_command_call test_name) seq;
4206 generate_test_command_call ~test test_name last
4207 | TestOutputLength (seq, expected) ->
4208 pr " /* TestOutputLength for %s (%d) */\n" name i;
4209 let seq, last = get_seq_last seq in
4212 pr " for (j = 0; j < %d; ++j)\n" expected;
4213 pr " if (r[j] == NULL) {\n";
4214 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4216 pr " print_strings (r);\n";
4219 pr " if (r[j] != NULL) {\n";
4220 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4222 pr " print_strings (r);\n";
4226 List.iter (generate_test_command_call test_name) seq;
4227 generate_test_command_call ~test test_name last
4228 | TestOutputStruct (seq, checks) ->
4229 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4230 let seq, last = get_seq_last seq in
4234 | CompareWithInt (field, expected) ->
4235 pr " if (r->%s != %d) {\n" field expected;
4236 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4237 test_name field expected;
4238 pr " (int) r->%s);\n" field;
4241 | CompareWithString (field, expected) ->
4242 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4243 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4244 test_name field expected;
4245 pr " r->%s);\n" field;
4248 | CompareFieldsIntEq (field1, field2) ->
4249 pr " if (r->%s != r->%s) {\n" field1 field2;
4250 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4251 test_name field1 field2;
4252 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4255 | CompareFieldsStrEq (field1, field2) ->
4256 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4257 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4258 test_name field1 field2;
4259 pr " r->%s, r->%s);\n" field1 field2;
4264 List.iter (generate_test_command_call test_name) seq;
4265 generate_test_command_call ~test test_name last
4266 | TestLastFail seq ->
4267 pr " /* TestLastFail for %s (%d) */\n" name i;
4268 let seq, last = get_seq_last seq in
4269 List.iter (generate_test_command_call test_name) seq;
4270 generate_test_command_call test_name ~expect_error:true last
4272 (* Generate the code to run a command, leaving the result in 'r'.
4273 * If you expect to get an error then you should set expect_error:true.
4275 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4277 | [] -> assert false
4279 (* Look up the command to find out what args/ret it has. *)
4282 let _, style, _, _, _, _, _ =
4283 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4286 failwithf "%s: in test, command %s was not found" test_name name in
4288 if List.length (snd style) <> List.length args then
4289 failwithf "%s: in test, wrong number of args given to %s"
4296 | OptString n, "NULL" -> ()
4298 | OptString n, arg ->
4299 pr " char %s[] = \"%s\";\n" n (c_quote arg);
4300 if String.length arg > 7 && String.sub arg 0 7 = "/dev/sd" then
4301 pr " %s[5] = devchar;\n" n
4304 | FileIn _, _ | FileOut _, _ -> ()
4305 | StringList n, arg ->
4306 let strs = string_split " " arg in
4309 pr " char %s_%d[] = \"%s\";\n" n i (c_quote str);
4310 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
4311 pr " %s_%d[5] = devchar;\n" n i
4313 pr " char *%s[] = {\n" n;
4315 fun i _ -> pr " %s_%d,\n" n i
4319 ) (List.combine (snd style) args);
4322 match fst style with
4323 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4324 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4325 | RConstString _ -> pr " const char *r;\n"; "NULL"
4326 | RString _ -> pr " char *r;\n"; "NULL"
4327 | RStringList _ | RHashtable _ ->
4332 pr " struct guestfs_int_bool *r;\n"; "NULL"
4334 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4336 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4338 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4340 pr " struct guestfs_stat *r;\n"; "NULL"
4342 pr " struct guestfs_statvfs *r;\n"; "NULL" in
4344 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4345 pr " r = guestfs_%s (g" name;
4347 (* Generate the parameters. *)
4350 | OptString _, "NULL" -> pr ", NULL"
4354 | FileIn _, arg | FileOut _, arg ->
4355 pr ", \"%s\"" (c_quote arg)
4356 | StringList n, _ ->
4360 try int_of_string arg
4361 with Failure "int_of_string" ->
4362 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4365 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4366 ) (List.combine (snd style) args);
4369 if not expect_error then
4370 pr " if (r == %s)\n" error_code
4372 pr " if (r != %s)\n" error_code;
4375 (* Insert the test code. *)
4381 (match fst style with
4382 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4383 | RString _ -> pr " free (r);\n"
4384 | RStringList _ | RHashtable _ ->
4385 pr " for (i = 0; r[i] != NULL; ++i)\n";
4386 pr " free (r[i]);\n";
4389 pr " guestfs_free_int_bool (r);\n"
4391 pr " guestfs_free_lvm_pv_list (r);\n"
4393 pr " guestfs_free_lvm_vg_list (r);\n"
4395 pr " guestfs_free_lvm_lv_list (r);\n"
4396 | RStat _ | RStatVFS _ ->
4403 let str = replace_str str "\r" "\\r" in
4404 let str = replace_str str "\n" "\\n" in
4405 let str = replace_str str "\t" "\\t" in
4406 let str = replace_str str "\000" "\\0" in
4409 (* Generate a lot of different functions for guestfish. *)
4410 and generate_fish_cmds () =
4411 generate_header CStyle GPLv2;
4415 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4417 let all_functions_sorted =
4419 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4420 ) all_functions_sorted in
4422 pr "#include <stdio.h>\n";
4423 pr "#include <stdlib.h>\n";
4424 pr "#include <string.h>\n";
4425 pr "#include <inttypes.h>\n";
4427 pr "#include <guestfs.h>\n";
4428 pr "#include \"fish.h\"\n";
4431 (* list_commands function, which implements guestfish -h *)
4432 pr "void list_commands (void)\n";
4434 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
4435 pr " list_builtin_commands ();\n";
4437 fun (name, _, _, flags, _, shortdesc, _) ->
4438 let name = replace_char name '_' '-' in
4439 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4441 ) all_functions_sorted;
4442 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4446 (* display_command function, which implements guestfish -h cmd *)
4447 pr "void display_command (const char *cmd)\n";
4450 fun (name, style, _, flags, _, shortdesc, longdesc) ->
4451 let name2 = replace_char name '_' '-' in
4453 try find_map (function FishAlias n -> Some n | _ -> None) flags
4454 with Not_found -> name in
4455 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4457 match snd style with
4461 name2 (String.concat "> <" (List.map name_of_argt args)) in
4464 if List.mem ProtocolLimitWarning flags then
4465 ("\n\n" ^ protocol_limit_warning)
4468 (* For DangerWillRobinson commands, we should probably have
4469 * guestfish prompt before allowing you to use them (especially
4470 * in interactive mode). XXX
4474 if List.mem DangerWillRobinson flags then
4475 ("\n\n" ^ danger_will_robinson)
4478 let describe_alias =
4479 if name <> alias then
4480 sprintf "\n\nYou can use '%s' as an alias for this command." alias
4484 pr "strcasecmp (cmd, \"%s\") == 0" name;
4485 if name <> name2 then
4486 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4487 if name <> alias then
4488 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4490 pr " pod2text (\"%s - %s\", %S);\n"
4492 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4495 pr " display_builtin_command (cmd);\n";
4499 (* print_{pv,vg,lv}_list functions *)
4503 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4510 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4512 pr " printf (\"%s: \");\n" name;
4513 pr " for (i = 0; i < 32; ++i)\n";
4514 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
4515 pr " printf (\"\\n\");\n"
4517 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4519 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4520 | name, `OptPercent ->
4521 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4522 typ name name typ name;
4523 pr " else printf (\"%s: \\n\");\n" name
4527 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4532 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4533 pr " print_%s (&%ss->val[i]);\n" typ typ;
4536 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4538 (* print_{stat,statvfs} functions *)
4542 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4547 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4551 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4553 (* run_<action> actions *)
4555 fun (name, style, _, flags, _, _, _) ->
4556 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4558 (match fst style with
4561 | RBool _ -> pr " int r;\n"
4562 | RInt64 _ -> pr " int64_t r;\n"
4563 | RConstString _ -> pr " const char *r;\n"
4564 | RString _ -> pr " char *r;\n"
4565 | RStringList _ | RHashtable _ -> pr " char **r;\n"
4566 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
4567 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
4568 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
4569 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
4570 | RStat _ -> pr " struct guestfs_stat *r;\n"
4571 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
4578 | FileOut n -> pr " const char *%s;\n" n
4579 | StringList n -> pr " char **%s;\n" n
4580 | Bool n -> pr " int %s;\n" n
4581 | Int n -> pr " int %s;\n" n
4584 (* Check and convert parameters. *)
4585 let argc_expected = List.length (snd style) in
4586 pr " if (argc != %d) {\n" argc_expected;
4587 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
4589 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
4595 | String name -> pr " %s = argv[%d];\n" name i
4597 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
4600 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
4603 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
4605 | StringList name ->
4606 pr " %s = parse_string_list (argv[%d]);\n" name i
4608 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
4610 pr " %s = atoi (argv[%d]);\n" name i
4613 (* Call C API function. *)
4615 try find_map (function FishAction n -> Some n | _ -> None) flags
4616 with Not_found -> sprintf "guestfs_%s" name in
4618 generate_call_args ~handle:"g" (snd style);
4621 (* Check return value for errors and display command results. *)
4622 (match fst style with
4623 | RErr -> pr " return r;\n"
4625 pr " if (r == -1) return -1;\n";
4626 pr " printf (\"%%d\\n\", r);\n";
4629 pr " if (r == -1) return -1;\n";
4630 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
4633 pr " if (r == -1) return -1;\n";
4634 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
4637 pr " if (r == NULL) return -1;\n";
4638 pr " printf (\"%%s\\n\", r);\n";
4641 pr " if (r == NULL) return -1;\n";
4642 pr " printf (\"%%s\\n\", r);\n";
4646 pr " if (r == NULL) return -1;\n";
4647 pr " print_strings (r);\n";
4648 pr " free_strings (r);\n";
4651 pr " if (r == NULL) return -1;\n";
4652 pr " printf (\"%%d, %%s\\n\", r->i,\n";
4653 pr " r->b ? \"true\" : \"false\");\n";
4654 pr " guestfs_free_int_bool (r);\n";
4657 pr " if (r == NULL) return -1;\n";
4658 pr " print_pv_list (r);\n";
4659 pr " guestfs_free_lvm_pv_list (r);\n";
4662 pr " if (r == NULL) return -1;\n";
4663 pr " print_vg_list (r);\n";
4664 pr " guestfs_free_lvm_vg_list (r);\n";
4667 pr " if (r == NULL) return -1;\n";
4668 pr " print_lv_list (r);\n";
4669 pr " guestfs_free_lvm_lv_list (r);\n";
4672 pr " if (r == NULL) return -1;\n";
4673 pr " print_stat (r);\n";
4677 pr " if (r == NULL) return -1;\n";
4678 pr " print_statvfs (r);\n";
4682 pr " if (r == NULL) return -1;\n";
4683 pr " print_table (r);\n";
4684 pr " free_strings (r);\n";
4691 (* run_action function *)
4692 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
4695 fun (name, _, _, flags, _, _, _) ->
4696 let name2 = replace_char name '_' '-' in
4698 try find_map (function FishAlias n -> Some n | _ -> None) flags
4699 with Not_found -> name in
4701 pr "strcasecmp (cmd, \"%s\") == 0" name;
4702 if name <> name2 then
4703 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4704 if name <> alias then
4705 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4707 pr " return run_%s (cmd, argc, argv);\n" name;
4711 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
4718 (* Readline completion for guestfish. *)
4719 and generate_fish_completion () =
4720 generate_header CStyle GPLv2;
4724 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4734 #ifdef HAVE_LIBREADLINE
4735 #include <readline/readline.h>
4740 #ifdef HAVE_LIBREADLINE
4742 static const char *const commands[] = {
4743 BUILTIN_COMMANDS_FOR_COMPLETION,
4746 (* Get the commands, including the aliases. They don't need to be
4747 * sorted - the generator() function just does a dumb linear search.
4751 fun (name, _, _, flags, _, _, _) ->
4752 let name2 = replace_char name '_' '-' in
4754 try find_map (function FishAlias n -> Some n | _ -> None) flags
4755 with Not_found -> name in
4757 if name <> alias then [name2; alias] else [name2]
4759 let commands = List.flatten commands in
4761 List.iter (pr " \"%s\",\n") commands;
4767 generator (const char *text, int state)
4769 static int index, len;
4774 len = strlen (text);
4777 while ((name = commands[index]) != NULL) {
4779 if (strncasecmp (name, text, len) == 0)
4780 return strdup (name);
4786 #endif /* HAVE_LIBREADLINE */
4788 char **do_completion (const char *text, int start, int end)
4790 char **matches = NULL;
4792 #ifdef HAVE_LIBREADLINE
4794 matches = rl_completion_matches (text, generator);
4801 (* Generate the POD documentation for guestfish. *)
4802 and generate_fish_actions_pod () =
4803 let all_functions_sorted =
4805 fun (_, _, _, flags, _, _, _) ->
4806 not (List.mem NotInFish flags || List.mem NotInDocs flags)
4807 ) all_functions_sorted in
4809 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
4812 fun (name, style, _, flags, _, _, longdesc) ->
4814 Str.global_substitute rex (
4817 try Str.matched_group 1 s
4819 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
4820 "C<" ^ replace_char sub '_' '-' ^ ">"
4822 let name = replace_char name '_' '-' in
4824 try find_map (function FishAlias n -> Some n | _ -> None) flags
4825 with Not_found -> name in
4827 pr "=head2 %s" name;
4828 if name <> alias then
4835 | String n -> pr " %s" n
4836 | OptString n -> pr " %s" n
4837 | StringList n -> pr " '%s ...'" n
4838 | Bool _ -> pr " true|false"
4839 | Int n -> pr " %s" n
4840 | FileIn n | FileOut n -> pr " (%s|-)" n
4844 pr "%s\n\n" longdesc;
4846 if List.exists (function FileIn _ | FileOut _ -> true
4847 | _ -> false) (snd style) then
4848 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
4850 if List.mem ProtocolLimitWarning flags then
4851 pr "%s\n\n" protocol_limit_warning;
4853 if List.mem DangerWillRobinson flags then
4854 pr "%s\n\n" danger_will_robinson
4855 ) all_functions_sorted
4857 (* Generate a C function prototype. *)
4858 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
4859 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
4861 ?handle name style =
4862 if extern then pr "extern ";
4863 if static then pr "static ";
4864 (match fst style with
4866 | RInt _ -> pr "int "
4867 | RInt64 _ -> pr "int64_t "
4868 | RBool _ -> pr "int "
4869 | RConstString _ -> pr "const char *"
4870 | RString _ -> pr "char *"
4871 | RStringList _ | RHashtable _ -> pr "char **"
4873 if not in_daemon then pr "struct guestfs_int_bool *"
4874 else pr "guestfs_%s_ret *" name
4876 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
4877 else pr "guestfs_lvm_int_pv_list *"
4879 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
4880 else pr "guestfs_lvm_int_vg_list *"
4882 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
4883 else pr "guestfs_lvm_int_lv_list *"
4885 if not in_daemon then pr "struct guestfs_stat *"
4886 else pr "guestfs_int_stat *"
4888 if not in_daemon then pr "struct guestfs_statvfs *"
4889 else pr "guestfs_int_statvfs *"
4891 pr "%s%s (" prefix name;
4892 if handle = None && List.length (snd style) = 0 then
4895 let comma = ref false in
4898 | Some handle -> pr "guestfs_h *%s" handle; comma := true
4902 if single_line then pr ", " else pr ",\n\t\t"
4909 | OptString n -> next (); pr "const char *%s" n
4910 | StringList n -> next (); pr "char * const* const %s" n
4911 | Bool n -> next (); pr "int %s" n
4912 | Int n -> next (); pr "int %s" n
4915 if not in_daemon then (next (); pr "const char *%s" n)
4919 if semicolon then pr ";";
4920 if newline then pr "\n"
4922 (* Generate C call arguments, eg "(handle, foo, bar)" *)
4923 and generate_call_args ?handle args =
4925 let comma = ref false in
4928 | Some handle -> pr "%s" handle; comma := true
4932 if !comma then pr ", ";
4934 pr "%s" (name_of_argt arg)
4938 (* Generate the OCaml bindings interface. *)
4939 and generate_ocaml_mli () =
4940 generate_header OCamlStyle LGPLv2;
4943 (** For API documentation you should refer to the C API
4944 in the guestfs(3) manual page. The OCaml API uses almost
4945 exactly the same calls. *)
4948 (** A [guestfs_h] handle. *)
4950 exception Error of string
4951 (** This exception is raised when there is an error. *)
4953 val create : unit -> t
4955 val close : t -> unit
4956 (** Handles are closed by the garbage collector when they become
4957 unreferenced, but callers can also call this in order to
4958 provide predictable cleanup. *)
4961 generate_ocaml_lvm_structure_decls ();
4963 generate_ocaml_stat_structure_decls ();
4967 fun (name, style, _, _, _, shortdesc, _) ->
4968 generate_ocaml_prototype name style;
4969 pr "(** %s *)\n" shortdesc;
4973 (* Generate the OCaml bindings implementation. *)
4974 and generate_ocaml_ml () =
4975 generate_header OCamlStyle LGPLv2;
4979 exception Error of string
4980 external create : unit -> t = \"ocaml_guestfs_create\"
4981 external close : t -> unit = \"ocaml_guestfs_close\"
4984 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
4988 generate_ocaml_lvm_structure_decls ();
4990 generate_ocaml_stat_structure_decls ();
4994 fun (name, style, _, _, _, shortdesc, _) ->
4995 generate_ocaml_prototype ~is_external:true name style;
4998 (* Generate the OCaml bindings C implementation. *)
4999 and generate_ocaml_c () =
5000 generate_header CStyle LGPLv2;
5007 #include <caml/config.h>
5008 #include <caml/alloc.h>
5009 #include <caml/callback.h>
5010 #include <caml/fail.h>
5011 #include <caml/memory.h>
5012 #include <caml/mlvalues.h>
5013 #include <caml/signals.h>
5015 #include <guestfs.h>
5017 #include \"guestfs_c.h\"
5019 /* Copy a hashtable of string pairs into an assoc-list. We return
5020 * the list in reverse order, but hashtables aren't supposed to be
5023 static CAMLprim value
5024 copy_table (char * const * argv)
5027 CAMLlocal5 (rv, pairv, kv, vv, cons);
5031 for (i = 0; argv[i] != NULL; i += 2) {
5032 kv = caml_copy_string (argv[i]);
5033 vv = caml_copy_string (argv[i+1]);
5034 pairv = caml_alloc (2, 0);
5035 Store_field (pairv, 0, kv);
5036 Store_field (pairv, 1, vv);
5037 cons = caml_alloc (2, 0);
5038 Store_field (cons, 1, rv);
5040 Store_field (cons, 0, pairv);
5048 (* LVM struct copy functions. *)
5051 let has_optpercent_col =
5052 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
5054 pr "static CAMLprim value\n";
5055 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
5057 pr " CAMLparam0 ();\n";
5058 if has_optpercent_col then
5059 pr " CAMLlocal3 (rv, v, v2);\n"
5061 pr " CAMLlocal2 (rv, v);\n";
5063 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5068 pr " v = caml_copy_string (%s->%s);\n" typ name
5070 pr " v = caml_alloc_string (32);\n";
5071 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
5074 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5075 | name, `OptPercent ->
5076 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5077 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
5078 pr " v = caml_alloc (1, 0);\n";
5079 pr " Store_field (v, 0, v2);\n";
5080 pr " } else /* None */\n";
5081 pr " v = Val_int (0);\n";
5083 pr " Store_field (rv, %d, v);\n" i
5085 pr " CAMLreturn (rv);\n";
5089 pr "static CAMLprim value\n";
5090 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
5093 pr " CAMLparam0 ();\n";
5094 pr " CAMLlocal2 (rv, v);\n";
5097 pr " if (%ss->len == 0)\n" typ;
5098 pr " CAMLreturn (Atom (0));\n";
5100 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
5101 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
5102 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
5103 pr " caml_modify (&Field (rv, i), v);\n";
5105 pr " CAMLreturn (rv);\n";
5109 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5111 (* Stat copy functions. *)
5114 pr "static CAMLprim value\n";
5115 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5117 pr " CAMLparam0 ();\n";
5118 pr " CAMLlocal2 (rv, v);\n";
5120 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5125 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5127 pr " Store_field (rv, %d, v);\n" i
5129 pr " CAMLreturn (rv);\n";
5132 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5136 fun (name, style, _, _, _, _, _) ->
5138 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5140 pr "CAMLprim value\n";
5141 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5142 List.iter (pr ", value %s") (List.tl params);
5147 | [p1; p2; p3; p4; p5] ->
5148 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
5149 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5150 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5151 pr " CAMLxparam%d (%s);\n"
5152 (List.length rest) (String.concat ", " rest)
5154 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5156 pr " CAMLlocal1 (rv);\n";
5159 pr " guestfs_h *g = Guestfs_val (gv);\n";
5160 pr " if (g == NULL)\n";
5161 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
5169 pr " const char *%s = String_val (%sv);\n" n n
5171 pr " const char *%s =\n" n;
5172 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5175 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5177 pr " int %s = Bool_val (%sv);\n" n n
5179 pr " int %s = Int_val (%sv);\n" n n
5182 match fst style with
5183 | RErr -> pr " int r;\n"; "-1"
5184 | RInt _ -> pr " int r;\n"; "-1"
5185 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5186 | RBool _ -> pr " int r;\n"; "-1"
5187 | RConstString _ -> pr " const char *r;\n"; "NULL"
5188 | RString _ -> pr " char *r;\n"; "NULL"
5194 pr " struct guestfs_int_bool *r;\n"; "NULL"
5196 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5198 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5200 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5202 pr " struct guestfs_stat *r;\n"; "NULL"
5204 pr " struct guestfs_statvfs *r;\n"; "NULL"
5211 pr " caml_enter_blocking_section ();\n";
5212 pr " r = guestfs_%s " name;
5213 generate_call_args ~handle:"g" (snd style);
5215 pr " caml_leave_blocking_section ();\n";
5220 pr " ocaml_guestfs_free_strings (%s);\n" n;
5221 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5224 pr " if (r == %s)\n" error_code;
5225 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5228 (match fst style with
5229 | RErr -> pr " rv = Val_unit;\n"
5230 | RInt _ -> pr " rv = Val_int (r);\n"
5232 pr " rv = caml_copy_int64 (r);\n"
5233 | RBool _ -> pr " rv = Val_bool (r);\n"
5234 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5236 pr " rv = caml_copy_string (r);\n";
5239 pr " rv = caml_copy_string_array ((const char **) r);\n";
5240 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5243 pr " rv = caml_alloc (2, 0);\n";
5244 pr " Store_field (rv, 0, Val_int (r->i));\n";
5245 pr " Store_field (rv, 1, Val_bool (r->b));\n";
5246 pr " guestfs_free_int_bool (r);\n";
5248 pr " rv = copy_lvm_pv_list (r);\n";
5249 pr " guestfs_free_lvm_pv_list (r);\n";
5251 pr " rv = copy_lvm_vg_list (r);\n";
5252 pr " guestfs_free_lvm_vg_list (r);\n";
5254 pr " rv = copy_lvm_lv_list (r);\n";
5255 pr " guestfs_free_lvm_lv_list (r);\n";
5257 pr " rv = copy_stat (r);\n";
5260 pr " rv = copy_statvfs (r);\n";
5263 pr " rv = copy_table (r);\n";
5264 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5268 pr " CAMLreturn (rv);\n";
5272 if List.length params > 5 then (
5273 pr "CAMLprim value\n";
5274 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5276 pr " return ocaml_guestfs_%s (argv[0]" name;
5277 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5284 and generate_ocaml_lvm_structure_decls () =
5287 pr "type lvm_%s = {\n" typ;
5290 | name, `String -> pr " %s : string;\n" name
5291 | name, `UUID -> pr " %s : string;\n" name
5292 | name, `Bytes -> pr " %s : int64;\n" name
5293 | name, `Int -> pr " %s : int64;\n" name
5294 | name, `OptPercent -> pr " %s : float option;\n" name
5298 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5300 and generate_ocaml_stat_structure_decls () =
5303 pr "type %s = {\n" typ;
5306 | name, `Int -> pr " %s : int64;\n" name
5310 ) ["stat", stat_cols; "statvfs", statvfs_cols]
5312 and generate_ocaml_prototype ?(is_external = false) name style =
5313 if is_external then pr "external " else pr "val ";
5314 pr "%s : t -> " name;
5317 | String _ | FileIn _ | FileOut _ -> pr "string -> "
5318 | OptString _ -> pr "string option -> "
5319 | StringList _ -> pr "string array -> "
5320 | Bool _ -> pr "bool -> "
5321 | Int _ -> pr "int -> "
5323 (match fst style with
5324 | RErr -> pr "unit" (* all errors are turned into exceptions *)
5325 | RInt _ -> pr "int"
5326 | RInt64 _ -> pr "int64"
5327 | RBool _ -> pr "bool"
5328 | RConstString _ -> pr "string"
5329 | RString _ -> pr "string"
5330 | RStringList _ -> pr "string array"
5331 | RIntBool _ -> pr "int * bool"
5332 | RPVList _ -> pr "lvm_pv array"
5333 | RVGList _ -> pr "lvm_vg array"
5334 | RLVList _ -> pr "lvm_lv array"
5335 | RStat _ -> pr "stat"
5336 | RStatVFS _ -> pr "statvfs"
5337 | RHashtable _ -> pr "(string * string) list"
5339 if is_external then (
5341 if List.length (snd style) + 1 > 5 then
5342 pr "\"ocaml_guestfs_%s_byte\" " name;
5343 pr "\"ocaml_guestfs_%s\"" name
5347 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5348 and generate_perl_xs () =
5349 generate_header CStyle LGPLv2;
5352 #include \"EXTERN.h\"
5356 #include <guestfs.h>
5359 #define PRId64 \"lld\"
5363 my_newSVll(long long val) {
5364 #ifdef USE_64_BIT_ALL
5365 return newSViv(val);
5369 len = snprintf(buf, 100, \"%%\" PRId64, val);
5370 return newSVpv(buf, len);
5375 #define PRIu64 \"llu\"
5379 my_newSVull(unsigned long long val) {
5380 #ifdef USE_64_BIT_ALL
5381 return newSVuv(val);
5385 len = snprintf(buf, 100, \"%%\" PRIu64, val);
5386 return newSVpv(buf, len);
5390 /* http://www.perlmonks.org/?node_id=680842 */
5392 XS_unpack_charPtrPtr (SV *arg) {
5397 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5398 croak (\"array reference expected\");
5400 av = (AV *)SvRV (arg);
5401 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5403 croak (\"malloc failed\");
5405 for (i = 0; i <= av_len (av); i++) {
5406 SV **elem = av_fetch (av, i, 0);
5408 if (!elem || !*elem)
5409 croak (\"missing element in list\");
5411 ret[i] = SvPV_nolen (*elem);
5419 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
5426 RETVAL = guestfs_create ();
5428 croak (\"could not create guestfs handle\");
5429 guestfs_set_error_handler (RETVAL, NULL, NULL);
5442 fun (name, style, _, _, _, _, _) ->
5443 (match fst style with
5444 | RErr -> pr "void\n"
5445 | RInt _ -> pr "SV *\n"
5446 | RInt64 _ -> pr "SV *\n"
5447 | RBool _ -> pr "SV *\n"
5448 | RConstString _ -> pr "SV *\n"
5449 | RString _ -> pr "SV *\n"
5452 | RPVList _ | RVGList _ | RLVList _
5453 | RStat _ | RStatVFS _
5455 pr "void\n" (* all lists returned implictly on the stack *)
5457 (* Call and arguments. *)
5459 generate_call_args ~handle:"g" (snd style);
5461 pr " guestfs_h *g;\n";
5465 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
5467 (* http://www.perlmonks.org/?node_id=554277
5468 * Note that the implicit handle argument means we have
5469 * to add 1 to the ST(x) operator.
5471 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
5472 | StringList n -> pr " char **%s;\n" n
5473 | Bool n -> pr " int %s;\n" n
5474 | Int n -> pr " int %s;\n" n
5477 let do_cleanups () =
5480 | String _ | OptString _ | Bool _ | Int _
5481 | FileIn _ | FileOut _ -> ()
5482 | StringList n -> pr " free (%s);\n" n
5487 (match fst style with
5492 pr " r = guestfs_%s " name;
5493 generate_call_args ~handle:"g" (snd style);
5496 pr " if (r == -1)\n";
5497 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5503 pr " %s = guestfs_%s " n name;
5504 generate_call_args ~handle:"g" (snd style);
5507 pr " if (%s == -1)\n" n;
5508 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5509 pr " RETVAL = newSViv (%s);\n" n;
5514 pr " int64_t %s;\n" n;
5516 pr " %s = guestfs_%s " n name;
5517 generate_call_args ~handle:"g" (snd style);
5520 pr " if (%s == -1)\n" n;
5521 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5522 pr " RETVAL = my_newSVll (%s);\n" n;
5527 pr " const char *%s;\n" n;
5529 pr " %s = guestfs_%s " n name;
5530 generate_call_args ~handle:"g" (snd style);
5533 pr " if (%s == NULL)\n" n;
5534 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5535 pr " RETVAL = newSVpv (%s, 0);\n" n;
5540 pr " char *%s;\n" n;
5542 pr " %s = guestfs_%s " n name;
5543 generate_call_args ~handle:"g" (snd style);
5546 pr " if (%s == NULL)\n" n;
5547 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5548 pr " RETVAL = newSVpv (%s, 0);\n" n;
5549 pr " free (%s);\n" n;
5552 | RStringList n | RHashtable n ->
5554 pr " char **%s;\n" n;
5557 pr " %s = guestfs_%s " n name;
5558 generate_call_args ~handle:"g" (snd style);
5561 pr " if (%s == NULL)\n" n;
5562 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5563 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
5564 pr " EXTEND (SP, n);\n";
5565 pr " for (i = 0; i < n; ++i) {\n";
5566 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
5567 pr " free (%s[i]);\n" n;
5569 pr " free (%s);\n" n;
5572 pr " struct guestfs_int_bool *r;\n";
5574 pr " r = guestfs_%s " name;
5575 generate_call_args ~handle:"g" (snd style);
5578 pr " if (r == NULL)\n";
5579 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5580 pr " EXTEND (SP, 2);\n";
5581 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
5582 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
5583 pr " guestfs_free_int_bool (r);\n";
5585 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
5587 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
5589 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
5591 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
5593 generate_perl_stat_code
5594 "statvfs" statvfs_cols name style n do_cleanups
5600 and generate_perl_lvm_code typ cols name style n do_cleanups =
5602 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
5606 pr " %s = guestfs_%s " n name;
5607 generate_call_args ~handle:"g" (snd style);
5610 pr " if (%s == NULL)\n" n;
5611 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5612 pr " EXTEND (SP, %s->len);\n" n;
5613 pr " for (i = 0; i < %s->len; ++i) {\n" n;
5614 pr " hv = newHV ();\n";
5618 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
5619 name (String.length name) n name
5621 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
5622 name (String.length name) n name
5624 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
5625 name (String.length name) n name
5627 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
5628 name (String.length name) n name
5629 | name, `OptPercent ->
5630 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
5631 name (String.length name) n name
5633 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
5635 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
5637 and generate_perl_stat_code typ cols name style n do_cleanups =
5639 pr " struct guestfs_%s *%s;\n" typ n;
5641 pr " %s = guestfs_%s " n name;
5642 generate_call_args ~handle:"g" (snd style);
5645 pr " if (%s == NULL)\n" n;
5646 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5647 pr " EXTEND (SP, %d);\n" (List.length cols);
5651 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
5653 pr " free (%s);\n" n
5655 (* Generate Sys/Guestfs.pm. *)
5656 and generate_perl_pm () =
5657 generate_header HashStyle LGPLv2;
5664 Sys::Guestfs - Perl bindings for libguestfs
5670 my $h = Sys::Guestfs->new ();
5671 $h->add_drive ('guest.img');
5674 $h->mount ('/dev/sda1', '/');
5675 $h->touch ('/hello');
5680 The C<Sys::Guestfs> module provides a Perl XS binding to the
5681 libguestfs API for examining and modifying virtual machine
5684 Amongst the things this is good for: making batch configuration
5685 changes to guests, getting disk used/free statistics (see also:
5686 virt-df), migrating between virtualization systems (see also:
5687 virt-p2v), performing partial backups, performing partial guest
5688 clones, cloning guests and changing registry/UUID/hostname info, and
5691 Libguestfs uses Linux kernel and qemu code, and can access any type of
5692 guest filesystem that Linux and qemu can, including but not limited
5693 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5694 schemes, qcow, qcow2, vmdk.
5696 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5697 LVs, what filesystem is in each LV, etc.). It can also run commands
5698 in the context of the guest. Also you can access filesystems over FTP.
5702 All errors turn into calls to C<croak> (see L<Carp(3)>).
5710 package Sys::Guestfs;
5716 XSLoader::load ('Sys::Guestfs');
5718 =item $h = Sys::Guestfs->new ();
5720 Create a new guestfs handle.
5726 my $class = ref ($proto) || $proto;
5728 my $self = Sys::Guestfs::_create ();
5729 bless $self, $class;
5735 (* Actions. We only need to print documentation for these as
5736 * they are pulled in from the XS code automatically.
5739 fun (name, style, _, flags, _, _, longdesc) ->
5740 if not (List.mem NotInDocs flags) then (
5741 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
5743 generate_perl_prototype name style;
5745 pr "%s\n\n" longdesc;
5746 if List.mem ProtocolLimitWarning flags then
5747 pr "%s\n\n" protocol_limit_warning;
5748 if List.mem DangerWillRobinson flags then
5749 pr "%s\n\n" danger_will_robinson
5751 ) all_functions_sorted;
5763 Copyright (C) 2009 Red Hat Inc.
5767 Please see the file COPYING.LIB for the full license.
5771 L<guestfs(3)>, L<guestfish(1)>.
5776 and generate_perl_prototype name style =
5777 (match fst style with
5783 | RString n -> pr "$%s = " n
5784 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
5788 | RLVList n -> pr "@%s = " n
5791 | RHashtable n -> pr "%%%s = " n
5794 let comma = ref false in
5797 if !comma then pr ", ";
5800 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
5807 (* Generate Python C module. *)
5808 and generate_python_c () =
5809 generate_header CStyle LGPLv2;
5818 #include \"guestfs.h\"
5826 get_handle (PyObject *obj)
5829 assert (obj != Py_None);
5830 return ((Pyguestfs_Object *) obj)->g;
5834 put_handle (guestfs_h *g)
5838 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
5841 /* This list should be freed (but not the strings) after use. */
5842 static const char **
5843 get_string_list (PyObject *obj)
5850 if (!PyList_Check (obj)) {
5851 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
5855 len = PyList_Size (obj);
5856 r = malloc (sizeof (char *) * (len+1));
5858 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
5862 for (i = 0; i < len; ++i)
5863 r[i] = PyString_AsString (PyList_GetItem (obj, i));
5870 put_string_list (char * const * const argv)
5875 for (argc = 0; argv[argc] != NULL; ++argc)
5878 list = PyList_New (argc);
5879 for (i = 0; i < argc; ++i)
5880 PyList_SetItem (list, i, PyString_FromString (argv[i]));
5886 put_table (char * const * const argv)
5888 PyObject *list, *item;
5891 for (argc = 0; argv[argc] != NULL; ++argc)
5894 list = PyList_New (argc >> 1);
5895 for (i = 0; i < argc; i += 2) {
5896 item = PyTuple_New (2);
5897 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
5898 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
5899 PyList_SetItem (list, i >> 1, item);
5906 free_strings (char **argv)
5910 for (argc = 0; argv[argc] != NULL; ++argc)
5916 py_guestfs_create (PyObject *self, PyObject *args)
5920 g = guestfs_create ();
5922 PyErr_SetString (PyExc_RuntimeError,
5923 \"guestfs.create: failed to allocate handle\");
5926 guestfs_set_error_handler (g, NULL, NULL);
5927 return put_handle (g);
5931 py_guestfs_close (PyObject *self, PyObject *args)
5936 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
5938 g = get_handle (py_g);
5942 Py_INCREF (Py_None);
5948 (* LVM structures, turned into Python dictionaries. *)
5951 pr "static PyObject *\n";
5952 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
5954 pr " PyObject *dict;\n";
5956 pr " dict = PyDict_New ();\n";
5960 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5961 pr " PyString_FromString (%s->%s));\n"
5964 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5965 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
5968 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5969 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
5972 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5973 pr " PyLong_FromLongLong (%s->%s));\n"
5975 | name, `OptPercent ->
5976 pr " if (%s->%s >= 0)\n" typ name;
5977 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5978 pr " PyFloat_FromDouble ((double) %s->%s));\n"
5981 pr " Py_INCREF (Py_None);\n";
5982 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
5985 pr " return dict;\n";
5989 pr "static PyObject *\n";
5990 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
5992 pr " PyObject *list;\n";
5995 pr " list = PyList_New (%ss->len);\n" typ;
5996 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
5997 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
5998 pr " return list;\n";
6001 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
6003 (* Stat structures, turned into Python dictionaries. *)
6006 pr "static PyObject *\n";
6007 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6009 pr " PyObject *dict;\n";
6011 pr " dict = PyDict_New ();\n";
6015 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6016 pr " PyLong_FromLongLong (%s->%s));\n"
6019 pr " return dict;\n";
6022 ) ["stat", stat_cols; "statvfs", statvfs_cols];
6024 (* Python wrapper functions. *)
6026 fun (name, style, _, _, _, _, _) ->
6027 pr "static PyObject *\n";
6028 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6031 pr " PyObject *py_g;\n";
6032 pr " guestfs_h *g;\n";
6033 pr " PyObject *py_r;\n";
6036 match fst style with
6037 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6038 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6039 | RConstString _ -> pr " const char *r;\n"; "NULL"
6040 | RString _ -> pr " char *r;\n"; "NULL"
6041 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6042 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6043 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6044 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6045 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6046 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6047 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6051 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
6052 | OptString n -> pr " const char *%s;\n" n
6054 pr " PyObject *py_%s;\n" n;
6055 pr " const char **%s;\n" n
6056 | Bool n -> pr " int %s;\n" n
6057 | Int n -> pr " int %s;\n" n
6062 (* Convert the parameters. *)
6063 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
6066 | String _ | FileIn _ | FileOut _ -> pr "s"
6067 | OptString _ -> pr "z"
6068 | StringList _ -> pr "O"
6069 | Bool _ -> pr "i" (* XXX Python has booleans? *)
6072 pr ":guestfs_%s\",\n" name;
6076 | String n | FileIn n | FileOut n -> pr ", &%s" n
6077 | OptString n -> pr ", &%s" n
6078 | StringList n -> pr ", &py_%s" n
6079 | Bool n -> pr ", &%s" n
6080 | Int n -> pr ", &%s" n
6084 pr " return NULL;\n";
6086 pr " g = get_handle (py_g);\n";
6089 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6091 pr " %s = get_string_list (py_%s);\n" n n;
6092 pr " if (!%s) return NULL;\n" n
6097 pr " r = guestfs_%s " name;
6098 generate_call_args ~handle:"g" (snd style);
6103 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6105 pr " free (%s);\n" n
6108 pr " if (r == %s) {\n" error_code;
6109 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6110 pr " return NULL;\n";
6114 (match fst style with
6116 pr " Py_INCREF (Py_None);\n";
6117 pr " py_r = Py_None;\n"
6119 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
6120 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
6121 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
6123 pr " py_r = PyString_FromString (r);\n";
6126 pr " py_r = put_string_list (r);\n";
6127 pr " free_strings (r);\n"
6129 pr " py_r = PyTuple_New (2);\n";
6130 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
6131 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
6132 pr " guestfs_free_int_bool (r);\n"
6134 pr " py_r = put_lvm_pv_list (r);\n";
6135 pr " guestfs_free_lvm_pv_list (r);\n"
6137 pr " py_r = put_lvm_vg_list (r);\n";
6138 pr " guestfs_free_lvm_vg_list (r);\n"
6140 pr " py_r = put_lvm_lv_list (r);\n";
6141 pr " guestfs_free_lvm_lv_list (r);\n"
6143 pr " py_r = put_stat (r);\n";
6146 pr " py_r = put_statvfs (r);\n";
6149 pr " py_r = put_table (r);\n";
6150 pr " free_strings (r);\n"
6153 pr " return py_r;\n";
6158 (* Table of functions. *)
6159 pr "static PyMethodDef methods[] = {\n";
6160 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6161 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6163 fun (name, _, _, _, _, _, _) ->
6164 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6167 pr " { NULL, NULL, 0, NULL }\n";
6171 (* Init function. *)
6174 initlibguestfsmod (void)
6176 static int initialized = 0;
6178 if (initialized) return;
6179 Py_InitModule ((char *) \"libguestfsmod\", methods);
6184 (* Generate Python module. *)
6185 and generate_python_py () =
6186 generate_header HashStyle LGPLv2;
6189 u\"\"\"Python bindings for libguestfs
6192 g = guestfs.GuestFS ()
6193 g.add_drive (\"guest.img\")
6196 parts = g.list_partitions ()
6198 The guestfs module provides a Python binding to the libguestfs API
6199 for examining and modifying virtual machine disk images.
6201 Amongst the things this is good for: making batch configuration
6202 changes to guests, getting disk used/free statistics (see also:
6203 virt-df), migrating between virtualization systems (see also:
6204 virt-p2v), performing partial backups, performing partial guest
6205 clones, cloning guests and changing registry/UUID/hostname info, and
6208 Libguestfs uses Linux kernel and qemu code, and can access any type of
6209 guest filesystem that Linux and qemu can, including but not limited
6210 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6211 schemes, qcow, qcow2, vmdk.
6213 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6214 LVs, what filesystem is in each LV, etc.). It can also run commands
6215 in the context of the guest. Also you can access filesystems over FTP.
6217 Errors which happen while using the API are turned into Python
6218 RuntimeError exceptions.
6220 To create a guestfs handle you usually have to perform the following
6223 # Create the handle, call add_drive at least once, and possibly
6224 # several times if the guest has multiple block devices:
6225 g = guestfs.GuestFS ()
6226 g.add_drive (\"guest.img\")
6228 # Launch the qemu subprocess and wait for it to become ready:
6232 # Now you can issue commands, for example:
6237 import libguestfsmod
6240 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6242 def __init__ (self):
6243 \"\"\"Create a new libguestfs handle.\"\"\"
6244 self._o = libguestfsmod.create ()
6247 libguestfsmod.close (self._o)
6252 fun (name, style, _, flags, _, _, longdesc) ->
6254 generate_call_args ~handle:"self" (snd style);
6257 if not (List.mem NotInDocs flags) then (
6258 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6260 match fst style with
6261 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6264 doc ^ "\n\nThis function returns a list of strings."
6266 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6268 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
6270 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
6272 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
6274 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6276 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6278 doc ^ "\n\nThis function returns a dictionary." in
6280 if List.mem ProtocolLimitWarning flags then
6281 doc ^ "\n\n" ^ protocol_limit_warning
6284 if List.mem DangerWillRobinson flags then
6285 doc ^ "\n\n" ^ danger_will_robinson
6287 let doc = pod2text ~width:60 name doc in
6288 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6289 let doc = String.concat "\n " doc in
6290 pr " u\"\"\"%s\"\"\"\n" doc;
6292 pr " return libguestfsmod.%s " name;
6293 generate_call_args ~handle:"self._o" (snd style);
6298 (* Useful if you need the longdesc POD text as plain text. Returns a
6301 * This is the slowest thing about autogeneration.
6303 and pod2text ~width name longdesc =
6304 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6305 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6307 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6308 let chan = Unix.open_process_in cmd in
6309 let lines = ref [] in
6311 let line = input_line chan in
6312 if i = 1 then (* discard the first line of output *)
6315 let line = triml line in
6316 lines := line :: !lines;
6319 let lines = try loop 1 with End_of_file -> List.rev !lines in
6320 Unix.unlink filename;
6321 match Unix.close_process_in chan with
6322 | Unix.WEXITED 0 -> lines
6324 failwithf "pod2text: process exited with non-zero status (%d)" i
6325 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6326 failwithf "pod2text: process signalled or stopped by signal %d" i
6328 (* Generate ruby bindings. *)
6329 and generate_ruby_c () =
6330 generate_header CStyle LGPLv2;
6338 #include \"guestfs.h\"
6340 #include \"extconf.h\"
6342 /* For Ruby < 1.9 */
6344 #define RARRAY_LEN(r) (RARRAY((r))->len)
6347 static VALUE m_guestfs; /* guestfs module */
6348 static VALUE c_guestfs; /* guestfs_h handle */
6349 static VALUE e_Error; /* used for all errors */
6351 static void ruby_guestfs_free (void *p)
6354 guestfs_close ((guestfs_h *) p);
6357 static VALUE ruby_guestfs_create (VALUE m)
6361 g = guestfs_create ();
6363 rb_raise (e_Error, \"failed to create guestfs handle\");
6365 /* Don't print error messages to stderr by default. */
6366 guestfs_set_error_handler (g, NULL, NULL);
6368 /* Wrap it, and make sure the close function is called when the
6371 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6374 static VALUE ruby_guestfs_close (VALUE gv)
6377 Data_Get_Struct (gv, guestfs_h, g);
6379 ruby_guestfs_free (g);
6380 DATA_PTR (gv) = NULL;
6388 fun (name, style, _, _, _, _, _) ->
6389 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6390 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6393 pr " guestfs_h *g;\n";
6394 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
6396 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6402 | String n | FileIn n | FileOut n ->
6403 pr " const char *%s = StringValueCStr (%sv);\n" n n;
6405 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6406 pr " \"%s\", \"%s\");\n" n name
6408 pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
6412 pr " int i, len;\n";
6413 pr " len = RARRAY_LEN (%sv);\n" n;
6414 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6416 pr " for (i = 0; i < len; ++i) {\n";
6417 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
6418 pr " %s[i] = StringValueCStr (v);\n" n;
6420 pr " %s[len] = NULL;\n" n;
6423 pr " int %s = RTEST (%sv);\n" n n
6425 pr " int %s = NUM2INT (%sv);\n" n n
6430 match fst style with
6431 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6432 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6433 | RConstString _ -> pr " const char *r;\n"; "NULL"
6434 | RString _ -> pr " char *r;\n"; "NULL"
6435 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6436 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6437 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6438 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6439 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6440 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6441 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6444 pr " r = guestfs_%s " name;
6445 generate_call_args ~handle:"g" (snd style);
6450 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6452 pr " free (%s);\n" n
6455 pr " if (r == %s)\n" error_code;
6456 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6459 (match fst style with
6461 pr " return Qnil;\n"
6462 | RInt _ | RBool _ ->
6463 pr " return INT2NUM (r);\n"
6465 pr " return ULL2NUM (r);\n"
6467 pr " return rb_str_new2 (r);\n";
6469 pr " VALUE rv = rb_str_new2 (r);\n";
6473 pr " int i, len = 0;\n";
6474 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
6475 pr " VALUE rv = rb_ary_new2 (len);\n";
6476 pr " for (i = 0; r[i] != NULL; ++i) {\n";
6477 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6478 pr " free (r[i]);\n";
6483 pr " VALUE rv = rb_ary_new2 (2);\n";
6484 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
6485 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
6486 pr " guestfs_free_int_bool (r);\n";
6489 generate_ruby_lvm_code "pv" pv_cols
6491 generate_ruby_lvm_code "vg" vg_cols
6493 generate_ruby_lvm_code "lv" lv_cols
6495 pr " VALUE rv = rb_hash_new ();\n";
6499 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6504 pr " VALUE rv = rb_hash_new ();\n";
6508 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6513 pr " VALUE rv = rb_hash_new ();\n";
6515 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
6516 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6517 pr " free (r[i]);\n";
6518 pr " free (r[i+1]);\n";
6529 /* Initialize the module. */
6530 void Init__guestfs ()
6532 m_guestfs = rb_define_module (\"Guestfs\");
6533 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6534 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6536 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6537 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6540 (* Define the rest of the methods. *)
6542 fun (name, style, _, _, _, _, _) ->
6543 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
6544 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6549 (* Ruby code to return an LVM struct list. *)
6550 and generate_ruby_lvm_code typ cols =
6551 pr " VALUE rv = rb_ary_new2 (r->len);\n";
6553 pr " for (i = 0; i < r->len; ++i) {\n";
6554 pr " VALUE hv = rb_hash_new ();\n";
6558 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
6560 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
6563 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
6564 | name, `OptPercent ->
6565 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
6567 pr " rb_ary_push (rv, hv);\n";
6569 pr " guestfs_free_lvm_%s_list (r);\n" typ;
6572 (* Generate Java bindings GuestFS.java file. *)
6573 and generate_java_java () =
6574 generate_header CStyle LGPLv2;
6577 package com.redhat.et.libguestfs;
6579 import java.util.HashMap;
6580 import com.redhat.et.libguestfs.LibGuestFSException;
6581 import com.redhat.et.libguestfs.PV;
6582 import com.redhat.et.libguestfs.VG;
6583 import com.redhat.et.libguestfs.LV;
6584 import com.redhat.et.libguestfs.Stat;
6585 import com.redhat.et.libguestfs.StatVFS;
6586 import com.redhat.et.libguestfs.IntBool;
6589 * The GuestFS object is a libguestfs handle.
6593 public class GuestFS {
6594 // Load the native code.
6596 System.loadLibrary (\"guestfs_jni\");
6600 * The native guestfs_h pointer.
6605 * Create a libguestfs handle.
6607 * @throws LibGuestFSException
6609 public GuestFS () throws LibGuestFSException
6613 private native long _create () throws LibGuestFSException;
6616 * Close a libguestfs handle.
6618 * You can also leave handles to be collected by the garbage
6619 * collector, but this method ensures that the resources used
6620 * by the handle are freed up immediately. If you call any
6621 * other methods after closing the handle, you will get an
6624 * @throws LibGuestFSException
6626 public void close () throws LibGuestFSException
6632 private native void _close (long g) throws LibGuestFSException;
6634 public void finalize () throws LibGuestFSException
6642 fun (name, style, _, flags, _, shortdesc, longdesc) ->
6643 if not (List.mem NotInDocs flags); then (
6644 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6646 if List.mem ProtocolLimitWarning flags then
6647 doc ^ "\n\n" ^ protocol_limit_warning
6650 if List.mem DangerWillRobinson flags then
6651 doc ^ "\n\n" ^ danger_will_robinson
6653 let doc = pod2text ~width:60 name doc in
6654 let doc = List.map ( (* RHBZ#501883 *)
6657 | nonempty -> nonempty
6659 let doc = String.concat "\n * " doc in
6662 pr " * %s\n" shortdesc;
6665 pr " * @throws LibGuestFSException\n";
6669 generate_java_prototype ~public:true ~semicolon:false name style;
6672 pr " if (g == 0)\n";
6673 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
6676 if fst style <> RErr then pr "return ";
6678 generate_call_args ~handle:"g" (snd style);
6682 generate_java_prototype ~privat:true ~native:true name style;
6689 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
6690 ?(semicolon=true) name style =
6691 if privat then pr "private ";
6692 if public then pr "public ";
6693 if native then pr "native ";
6696 (match fst style with
6697 | RErr -> pr "void ";
6698 | RInt _ -> pr "int ";
6699 | RInt64 _ -> pr "long ";
6700 | RBool _ -> pr "boolean ";
6701 | RConstString _ | RString _ -> pr "String ";
6702 | RStringList _ -> pr "String[] ";
6703 | RIntBool _ -> pr "IntBool ";
6704 | RPVList _ -> pr "PV[] ";
6705 | RVGList _ -> pr "VG[] ";
6706 | RLVList _ -> pr "LV[] ";
6707 | RStat _ -> pr "Stat ";
6708 | RStatVFS _ -> pr "StatVFS ";
6709 | RHashtable _ -> pr "HashMap<String,String> ";
6712 if native then pr "_%s " name else pr "%s " name;
6714 let needs_comma = ref false in
6723 if !needs_comma then pr ", ";
6724 needs_comma := true;
6741 pr " throws LibGuestFSException";
6742 if semicolon then pr ";"
6744 and generate_java_struct typ cols =
6745 generate_header CStyle LGPLv2;
6748 package com.redhat.et.libguestfs;
6751 * Libguestfs %s structure.
6762 | name, `UUID -> pr " public String %s;\n" name
6764 | name, `Int -> pr " public long %s;\n" name
6765 | name, `OptPercent ->
6766 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
6767 pr " public float %s;\n" name
6772 and generate_java_c () =
6773 generate_header CStyle LGPLv2;
6780 #include \"com_redhat_et_libguestfs_GuestFS.h\"
6781 #include \"guestfs.h\"
6783 /* Note that this function returns. The exception is not thrown
6784 * until after the wrapper function returns.
6787 throw_exception (JNIEnv *env, const char *msg)
6790 cl = (*env)->FindClass (env,
6791 \"com/redhat/et/libguestfs/LibGuestFSException\");
6792 (*env)->ThrowNew (env, cl, msg);
6795 JNIEXPORT jlong JNICALL
6796 Java_com_redhat_et_libguestfs_GuestFS__1create
6797 (JNIEnv *env, jobject obj)
6801 g = guestfs_create ();
6803 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
6806 guestfs_set_error_handler (g, NULL, NULL);
6807 return (jlong) (long) g;
6810 JNIEXPORT void JNICALL
6811 Java_com_redhat_et_libguestfs_GuestFS__1close
6812 (JNIEnv *env, jobject obj, jlong jg)
6814 guestfs_h *g = (guestfs_h *) (long) jg;
6821 fun (name, style, _, _, _, _, _) ->
6823 (match fst style with
6824 | RErr -> pr "void ";
6825 | RInt _ -> pr "jint ";
6826 | RInt64 _ -> pr "jlong ";
6827 | RBool _ -> pr "jboolean ";
6828 | RConstString _ | RString _ -> pr "jstring ";
6829 | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
6831 | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
6835 pr "Java_com_redhat_et_libguestfs_GuestFS_";
6836 pr "%s" (replace_str ("_" ^ name) "_" "_1");
6838 pr " (JNIEnv *env, jobject obj, jlong jg";
6845 pr ", jstring j%s" n
6847 pr ", jobjectArray j%s" n
6849 pr ", jboolean j%s" n
6855 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
6856 let error_code, no_ret =
6857 match fst style with
6858 | RErr -> pr " int r;\n"; "-1", ""
6860 | RInt _ -> pr " int r;\n"; "-1", "0"
6861 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
6862 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
6864 pr " jstring jr;\n";
6865 pr " char *r;\n"; "NULL", "NULL"
6867 pr " jobjectArray jr;\n";
6870 pr " jstring jstr;\n";
6871 pr " char **r;\n"; "NULL", "NULL"
6873 pr " jobject jr;\n";
6875 pr " jfieldID fl;\n";
6876 pr " struct guestfs_int_bool *r;\n"; "NULL", "NULL"
6878 pr " jobject jr;\n";
6880 pr " jfieldID fl;\n";
6881 pr " struct guestfs_stat *r;\n"; "NULL", "NULL"
6883 pr " jobject jr;\n";
6885 pr " jfieldID fl;\n";
6886 pr " struct guestfs_statvfs *r;\n"; "NULL", "NULL"
6888 pr " jobjectArray jr;\n";
6890 pr " jfieldID fl;\n";
6891 pr " jobject jfl;\n";
6892 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
6894 pr " jobjectArray jr;\n";
6896 pr " jfieldID fl;\n";
6897 pr " jobject jfl;\n";
6898 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
6900 pr " jobjectArray jr;\n";
6902 pr " jfieldID fl;\n";
6903 pr " jobject jfl;\n";
6904 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
6905 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
6912 pr " const char *%s;\n" n
6914 pr " int %s_len;\n" n;
6915 pr " const char **%s;\n" n
6922 (match fst style with
6923 | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
6924 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
6925 | RString _ | RIntBool _ | RStat _ | RStatVFS _
6926 | RHashtable _ -> false) ||
6927 List.exists (function StringList _ -> true | _ -> false) (snd style) in
6933 (* Get the parameters. *)
6939 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
6941 (* This is completely undocumented, but Java null becomes
6944 pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
6946 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
6947 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
6948 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6949 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6951 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
6953 pr " %s[%s_len] = NULL;\n" n n;
6956 pr " %s = j%s;\n" n n
6959 (* Make the call. *)
6960 pr " r = guestfs_%s " name;
6961 generate_call_args ~handle:"g" (snd style);
6964 (* Release the parameters. *)
6970 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
6973 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
6975 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6976 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6978 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
6980 pr " free (%s);\n" n
6985 (* Check for errors. *)
6986 pr " if (r == %s) {\n" error_code;
6987 pr " throw_exception (env, guestfs_last_error (g));\n";
6988 pr " return %s;\n" no_ret;
6992 (match fst style with
6994 | RInt _ -> pr " return (jint) r;\n"
6995 | RBool _ -> pr " return (jboolean) r;\n"
6996 | RInt64 _ -> pr " return (jlong) r;\n"
6997 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
6999 pr " jr = (*env)->NewStringUTF (env, r);\n";
7003 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7004 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7005 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
7006 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7007 pr " for (i = 0; i < r_len; ++i) {\n";
7008 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
7009 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7010 pr " free (r[i]);\n";
7015 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
7016 pr " jr = (*env)->AllocObject (env, cl);\n";
7017 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
7018 pr " (*env)->SetIntField (env, jr, fl, r->i);\n";
7019 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
7020 pr " (*env)->SetBooleanField (env, jr, fl, r->b);\n";
7021 pr " guestfs_free_int_bool (r);\n";
7024 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
7025 pr " jr = (*env)->AllocObject (env, cl);\n";
7029 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7031 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7036 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
7037 pr " jr = (*env)->AllocObject (env, cl);\n";
7041 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7043 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7048 generate_java_lvm_return "pv" "PV" pv_cols
7050 generate_java_lvm_return "vg" "VG" vg_cols
7052 generate_java_lvm_return "lv" "LV" lv_cols
7055 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7056 pr " return NULL;\n"
7063 and generate_java_lvm_return typ jtyp cols =
7064 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7065 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7066 pr " for (i = 0; i < r->len; ++i) {\n";
7067 pr " jfl = (*env)->AllocObject (env, cl);\n";
7071 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7072 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7075 pr " char s[33];\n";
7076 pr " memcpy (s, r->val[i].%s, 32);\n" name;
7078 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7079 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7081 | name, (`Bytes|`Int) ->
7082 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7083 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7084 | name, `OptPercent ->
7085 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7086 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7088 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7090 pr " guestfs_free_lvm_%s_list (r);\n" typ;
7093 and generate_haskell_hs () =
7094 generate_header HaskellStyle LGPLv2;
7096 (* XXX We only know how to generate partial FFI for Haskell
7097 * at the moment. Please help out!
7099 let can_generate style =
7100 let check_no_bad_args =
7101 List.for_all (function Bool _ | Int _ -> false | _ -> true)
7104 | RErr, args -> check_no_bad_args args
7117 | RHashtable _, _ -> false in
7120 {-# INCLUDE <guestfs.h> #-}
7121 {-# LANGUAGE ForeignFunctionInterface #-}
7126 (* List out the names of the actions we want to export. *)
7128 fun (name, style, _, _, _, _, _) ->
7129 if can_generate style then pr ",\n %s" name
7137 import Control.Exception
7138 import Data.Typeable
7140 data GuestfsS = GuestfsS -- represents the opaque C struct
7141 type GuestfsP = Ptr GuestfsS -- guestfs_h *
7142 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7144 -- XXX define properly later XXX
7148 data IntBool = IntBool
7150 data StatVFS = StatVFS
7151 data Hashtable = Hashtable
7153 foreign import ccall unsafe \"guestfs_create\" c_create
7155 foreign import ccall unsafe \"&guestfs_close\" c_close
7156 :: FunPtr (GuestfsP -> IO ())
7157 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
7158 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
7160 create :: IO GuestfsH
7163 c_set_error_handler p nullPtr nullPtr
7164 h <- newForeignPtr c_close p
7167 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
7168 :: GuestfsP -> IO CString
7170 -- last_error :: GuestfsH -> IO (Maybe String)
7171 -- last_error h = do
7172 -- str <- withForeignPtr h (\\p -> c_last_error p)
7173 -- maybePeek peekCString str
7175 last_error :: GuestfsH -> IO (String)
7177 str <- withForeignPtr h (\\p -> c_last_error p)
7179 then return \"no error\"
7180 else peekCString str
7184 (* Generate wrappers for each foreign function. *)
7186 fun (name, style, _, _, _, _, _) ->
7187 if can_generate style then (
7188 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7190 generate_haskell_prototype ~handle:"GuestfsP" style;
7194 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7196 pr "%s %s = do\n" name
7197 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7203 | String n -> pr "withCString %s $ \\%s -> " n n
7204 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7205 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7207 (* XXX this doesn't work *)
7209 pr " %s = case %s of\n" n n;
7212 pr " in fromIntegral %s $ \\%s ->\n" n n
7213 | Int n -> pr "fromIntegral %s $ \\%s -> " n n
7215 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7216 (String.concat " " ("p" :: List.map name_of_argt (snd style)));
7217 (match fst style with
7218 | RErr | RInt _ | RInt64 _ | RBool _ ->
7219 pr " if (r == -1)\n";
7221 pr " err <- last_error h\n";
7223 | RConstString _ | RString _ | RStringList _ | RIntBool _
7224 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7226 pr " if (r == nullPtr)\n";
7228 pr " err <- last_error h\n";
7231 (match fst style with
7233 pr " else return ()\n"
7235 pr " else return (fromIntegral r)\n"
7237 pr " else return (fromIntegral r)\n"
7239 pr " else return (toBool r)\n"
7250 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7256 and generate_haskell_prototype ~handle ?(hs = false) style =
7258 let string = if hs then "String" else "CString" in
7259 let int = if hs then "Int" else "CInt" in
7260 let bool = if hs then "Bool" else "CInt" in
7261 let int64 = if hs then "Integer" else "Int64" in
7265 | String _ -> pr "%s" string
7266 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7267 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7268 | Bool _ -> pr "%s" bool
7269 | Int _ -> pr "%s" int
7270 | FileIn _ -> pr "%s" string
7271 | FileOut _ -> pr "%s" string
7276 (match fst style with
7277 | RErr -> if not hs then pr "CInt"
7278 | RInt _ -> pr "%s" int
7279 | RInt64 _ -> pr "%s" int64
7280 | RBool _ -> pr "%s" bool
7281 | RConstString _ -> pr "%s" string
7282 | RString _ -> pr "%s" string
7283 | RStringList _ -> pr "[%s]" string
7284 | RIntBool _ -> pr "IntBool"
7285 | RPVList _ -> pr "[PV]"
7286 | RVGList _ -> pr "[VG]"
7287 | RLVList _ -> pr "[LV]"
7288 | RStat _ -> pr "Stat"
7289 | RStatVFS _ -> pr "StatVFS"
7290 | RHashtable _ -> pr "Hashtable"
7294 and generate_bindtests () =
7295 generate_header CStyle LGPLv2;
7300 #include <inttypes.h>
7303 #include \"guestfs.h\"
7304 #include \"guestfs_protocol.h\"
7306 #define error guestfs_error
7309 print_strings (char * const* const argv)
7314 for (argc = 0; argv[argc] != NULL; ++argc) {
7315 if (argc > 0) printf (\", \");
7316 printf (\"\\\"%%s\\\"\", argv[argc]);
7321 /* The test0 function prints its parameters to stdout. */
7325 match test_functions with
7326 | [] -> assert false
7327 | test0 :: tests -> test0, tests in
7330 let (name, style, _, _, _, _, _) = test0 in
7331 generate_prototype ~extern:false ~semicolon:false ~newline:true
7332 ~handle:"g" ~prefix:"guestfs_" name style;
7338 | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
7339 | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
7340 | StringList n -> pr " print_strings (%s);\n" n
7341 | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
7342 | Int n -> pr " printf (\"%%d\\n\", %s);\n" n
7344 pr " /* Java changes stdout line buffering so we need this: */\n";
7345 pr " fflush (stdout);\n";
7351 fun (name, style, _, _, _, _, _) ->
7352 if String.sub name (String.length name - 3) 3 <> "err" then (
7353 pr "/* Test normal return. */\n";
7354 generate_prototype ~extern:false ~semicolon:false ~newline:true
7355 ~handle:"g" ~prefix:"guestfs_" name style;
7357 (match fst style with
7362 pr " sscanf (val, \"%%d\", &r);\n";
7366 pr " sscanf (val, \"%%\" SCNi64, &r);\n";
7369 pr " return strcmp (val, \"true\") == 0;\n"
7371 (* Can't return the input string here. Return a static
7372 * string so we ensure we get a segfault if the caller
7375 pr " return \"static string\";\n"
7377 pr " return strdup (val);\n"
7379 pr " char **strs;\n";
7381 pr " sscanf (val, \"%%d\", &n);\n";
7382 pr " strs = malloc ((n+1) * sizeof (char *));\n";
7383 pr " for (i = 0; i < n; ++i) {\n";
7384 pr " strs[i] = malloc (16);\n";
7385 pr " snprintf (strs[i], 16, \"%%d\", i);\n";
7387 pr " strs[n] = NULL;\n";
7388 pr " return strs;\n"
7390 pr " struct guestfs_int_bool *r;\n";
7391 pr " r = malloc (sizeof (struct guestfs_int_bool));\n";
7392 pr " sscanf (val, \"%%\" SCNi32, &r->i);\n";
7396 pr " struct guestfs_lvm_pv_list *r;\n";
7398 pr " r = malloc (sizeof (struct guestfs_lvm_pv_list));\n";
7399 pr " sscanf (val, \"%%d\", &r->len);\n";
7400 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_pv));\n";
7401 pr " for (i = 0; i < r->len; ++i) {\n";
7402 pr " r->val[i].pv_name = malloc (16);\n";
7403 pr " snprintf (r->val[i].pv_name, 16, \"%%d\", i);\n";
7407 pr " struct guestfs_lvm_vg_list *r;\n";
7409 pr " r = malloc (sizeof (struct guestfs_lvm_vg_list));\n";
7410 pr " sscanf (val, \"%%d\", &r->len);\n";
7411 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_vg));\n";
7412 pr " for (i = 0; i < r->len; ++i) {\n";
7413 pr " r->val[i].vg_name = malloc (16);\n";
7414 pr " snprintf (r->val[i].vg_name, 16, \"%%d\", i);\n";
7418 pr " struct guestfs_lvm_lv_list *r;\n";
7420 pr " r = malloc (sizeof (struct guestfs_lvm_lv_list));\n";
7421 pr " sscanf (val, \"%%d\", &r->len);\n";
7422 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_lv));\n";
7423 pr " for (i = 0; i < r->len; ++i) {\n";
7424 pr " r->val[i].lv_name = malloc (16);\n";
7425 pr " snprintf (r->val[i].lv_name, 16, \"%%d\", i);\n";
7429 pr " struct guestfs_stat *r;\n";
7430 pr " r = calloc (1, sizeof (*r));\n";
7431 pr " sscanf (val, \"%%\" SCNi64, &r->dev);\n";
7434 pr " struct guestfs_statvfs *r;\n";
7435 pr " r = calloc (1, sizeof (*r));\n";
7436 pr " sscanf (val, \"%%\" SCNi64, &r->bsize);\n";
7439 pr " char **strs;\n";
7441 pr " sscanf (val, \"%%d\", &n);\n";
7442 pr " strs = malloc ((n*2+1) * sizeof (char *));\n";
7443 pr " for (i = 0; i < n; ++i) {\n";
7444 pr " strs[i*2] = malloc (16);\n";
7445 pr " strs[i*2+1] = malloc (16);\n";
7446 pr " snprintf (strs[i*2], 16, \"%%d\", i);\n";
7447 pr " snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
7449 pr " strs[n*2] = NULL;\n";
7450 pr " return strs;\n"
7455 pr "/* Test error return. */\n";
7456 generate_prototype ~extern:false ~semicolon:false ~newline:true
7457 ~handle:"g" ~prefix:"guestfs_" name style;
7459 pr " error (g, \"error\");\n";
7460 (match fst style with
7461 | RErr | RInt _ | RInt64 _ | RBool _ ->
7464 | RString _ | RStringList _ | RIntBool _
7465 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7467 pr " return NULL;\n"
7474 and generate_ocaml_bindtests () =
7475 generate_header OCamlStyle GPLv2;
7479 let g = Guestfs.create () in
7486 | CallString s -> "\"" ^ s ^ "\""
7487 | CallOptString None -> "None"
7488 | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
7489 | CallStringList xs ->
7490 "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
7491 | CallInt i when i >= 0 -> string_of_int i
7492 | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
7493 | CallBool b -> string_of_bool b
7498 generate_lang_bindtests (
7499 fun f args -> pr " Guestfs.%s g %s;\n" f (mkargs args)
7502 pr "print_endline \"EOF\"\n"
7504 and generate_perl_bindtests () =
7505 pr "#!/usr/bin/perl -w\n";
7506 generate_header HashStyle GPLv2;
7513 my $g = Sys::Guestfs->new ();
7517 String.concat ", " (
7520 | CallString s -> "\"" ^ s ^ "\""
7521 | CallOptString None -> "undef"
7522 | CallOptString (Some s) -> sprintf "\"%s\"" s
7523 | CallStringList xs ->
7524 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7525 | CallInt i -> string_of_int i
7526 | CallBool b -> if b then "1" else "0"
7531 generate_lang_bindtests (
7532 fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
7535 pr "print \"EOF\\n\"\n"
7537 and generate_python_bindtests () =
7538 generate_header HashStyle GPLv2;
7543 g = guestfs.GuestFS ()
7547 String.concat ", " (
7550 | CallString s -> "\"" ^ s ^ "\""
7551 | CallOptString None -> "None"
7552 | CallOptString (Some s) -> sprintf "\"%s\"" s
7553 | CallStringList xs ->
7554 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7555 | CallInt i -> string_of_int i
7556 | CallBool b -> if b then "1" else "0"
7561 generate_lang_bindtests (
7562 fun f args -> pr "g.%s (%s)\n" f (mkargs args)
7565 pr "print \"EOF\"\n"
7567 and generate_ruby_bindtests () =
7568 generate_header HashStyle GPLv2;
7573 g = Guestfs::create()
7577 String.concat ", " (
7580 | CallString s -> "\"" ^ s ^ "\""
7581 | CallOptString None -> "nil"
7582 | CallOptString (Some s) -> sprintf "\"%s\"" s
7583 | CallStringList xs ->
7584 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7585 | CallInt i -> string_of_int i
7586 | CallBool b -> string_of_bool b
7591 generate_lang_bindtests (
7592 fun f args -> pr "g.%s(%s)\n" f (mkargs args)
7595 pr "print \"EOF\\n\"\n"
7597 and generate_java_bindtests () =
7598 generate_header CStyle GPLv2;
7601 import com.redhat.et.libguestfs.*;
7603 public class Bindtests {
7604 public static void main (String[] argv)
7607 GuestFS g = new GuestFS ();
7611 String.concat ", " (
7614 | CallString s -> "\"" ^ s ^ "\""
7615 | CallOptString None -> "null"
7616 | CallOptString (Some s) -> sprintf "\"%s\"" s
7617 | CallStringList xs ->
7619 String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
7620 | CallInt i -> string_of_int i
7621 | CallBool b -> string_of_bool b
7626 generate_lang_bindtests (
7627 fun f args -> pr " g.%s (%s);\n" f (mkargs args)
7631 System.out.println (\"EOF\");
7633 catch (Exception exn) {
7634 System.err.println (exn);
7641 and generate_haskell_bindtests () =
7642 () (* XXX Haskell bindings need to be fleshed out. *)
7644 (* Language-independent bindings tests - we do it this way to
7645 * ensure there is parity in testing bindings across all languages.
7647 and generate_lang_bindtests call =
7648 call "test0" [CallString "abc"; CallOptString (Some "def");
7649 CallStringList []; CallBool false;
7650 CallInt 0; CallString "123"; CallString "456"];
7651 call "test0" [CallString "abc"; CallOptString None;
7652 CallStringList []; CallBool false;
7653 CallInt 0; CallString "123"; CallString "456"];
7654 call "test0" [CallString ""; CallOptString (Some "def");
7655 CallStringList []; CallBool false;
7656 CallInt 0; CallString "123"; CallString "456"];
7657 call "test0" [CallString ""; CallOptString (Some "");
7658 CallStringList []; CallBool false;
7659 CallInt 0; CallString "123"; CallString "456"];
7660 call "test0" [CallString "abc"; CallOptString (Some "def");
7661 CallStringList ["1"]; CallBool false;
7662 CallInt 0; CallString "123"; CallString "456"];
7663 call "test0" [CallString "abc"; CallOptString (Some "def");
7664 CallStringList ["1"; "2"]; CallBool false;
7665 CallInt 0; CallString "123"; CallString "456"];
7666 call "test0" [CallString "abc"; CallOptString (Some "def");
7667 CallStringList ["1"]; CallBool true;
7668 CallInt 0; CallString "123"; CallString "456"];
7669 call "test0" [CallString "abc"; CallOptString (Some "def");
7670 CallStringList ["1"]; CallBool false;
7671 CallInt (-1); CallString "123"; CallString "456"];
7672 call "test0" [CallString "abc"; CallOptString (Some "def");
7673 CallStringList ["1"]; CallBool false;
7674 CallInt (-2); CallString "123"; CallString "456"];
7675 call "test0" [CallString "abc"; CallOptString (Some "def");
7676 CallStringList ["1"]; CallBool false;
7677 CallInt 1; CallString "123"; CallString "456"];
7678 call "test0" [CallString "abc"; CallOptString (Some "def");
7679 CallStringList ["1"]; CallBool false;
7680 CallInt 2; CallString "123"; CallString "456"];
7681 call "test0" [CallString "abc"; CallOptString (Some "def");
7682 CallStringList ["1"]; CallBool false;
7683 CallInt 4095; CallString "123"; CallString "456"];
7684 call "test0" [CallString "abc"; CallOptString (Some "def");
7685 CallStringList ["1"]; CallBool false;
7686 CallInt 0; CallString ""; CallString ""]
7688 (* XXX Add here tests of the return and error functions. *)
7690 let output_to filename =
7691 let filename_new = filename ^ ".new" in
7692 chan := open_out filename_new;
7697 (* Is the new file different from the current file? *)
7698 if Sys.file_exists filename && files_equal filename filename_new then
7699 Unix.unlink filename_new (* same, so skip it *)
7701 (* different, overwrite old one *)
7702 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
7703 Unix.rename filename_new filename;
7704 Unix.chmod filename 0o444;
7705 printf "written %s\n%!" filename;
7714 if not (Sys.file_exists "configure.ac") then (
7716 You are probably running this from the wrong directory.
7717 Run it from the top source directory using the command
7723 let close = output_to "src/guestfs_protocol.x" in
7727 let close = output_to "src/guestfs-structs.h" in
7728 generate_structs_h ();
7731 let close = output_to "src/guestfs-actions.h" in
7732 generate_actions_h ();
7735 let close = output_to "src/guestfs-actions.c" in
7736 generate_client_actions ();
7739 let close = output_to "daemon/actions.h" in
7740 generate_daemon_actions_h ();
7743 let close = output_to "daemon/stubs.c" in
7744 generate_daemon_actions ();
7747 let close = output_to "capitests/tests.c" in
7751 let close = output_to "src/guestfs-bindtests.c" in
7752 generate_bindtests ();
7755 let close = output_to "fish/cmds.c" in
7756 generate_fish_cmds ();
7759 let close = output_to "fish/completion.c" in
7760 generate_fish_completion ();
7763 let close = output_to "guestfs-structs.pod" in
7764 generate_structs_pod ();
7767 let close = output_to "guestfs-actions.pod" in
7768 generate_actions_pod ();
7771 let close = output_to "guestfish-actions.pod" in
7772 generate_fish_actions_pod ();
7775 let close = output_to "ocaml/guestfs.mli" in
7776 generate_ocaml_mli ();
7779 let close = output_to "ocaml/guestfs.ml" in
7780 generate_ocaml_ml ();
7783 let close = output_to "ocaml/guestfs_c_actions.c" in
7784 generate_ocaml_c ();
7787 let close = output_to "ocaml/bindtests.ml" in
7788 generate_ocaml_bindtests ();
7791 let close = output_to "perl/Guestfs.xs" in
7792 generate_perl_xs ();
7795 let close = output_to "perl/lib/Sys/Guestfs.pm" in
7796 generate_perl_pm ();
7799 let close = output_to "perl/bindtests.pl" in
7800 generate_perl_bindtests ();
7803 let close = output_to "python/guestfs-py.c" in
7804 generate_python_c ();
7807 let close = output_to "python/guestfs.py" in
7808 generate_python_py ();
7811 let close = output_to "python/bindtests.py" in
7812 generate_python_bindtests ();
7815 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
7819 let close = output_to "ruby/bindtests.rb" in
7820 generate_ruby_bindtests ();
7823 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
7824 generate_java_java ();
7827 let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
7828 generate_java_struct "PV" pv_cols;
7831 let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
7832 generate_java_struct "VG" vg_cols;
7835 let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
7836 generate_java_struct "LV" lv_cols;
7839 let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
7840 generate_java_struct "Stat" stat_cols;
7843 let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
7844 generate_java_struct "StatVFS" statvfs_cols;
7847 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
7851 let close = output_to "java/Bindtests.java" in
7852 generate_java_bindtests ();
7855 let close = output_to "haskell/Guestfs.hs" in
7856 generate_haskell_hs ();
7859 let close = output_to "haskell/bindtests.hs" in
7860 generate_haskell_bindtests ();