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 (* "RStruct" is a function which returns a single named structure
70 * or an error indication (in C, a struct, and in other languages
71 * with varying representations, but usually very efficient). See
72 * after the function list below for the structures.
74 | RStruct of string * string (* name of retval, name of struct *)
75 (* "RStructList" is a function which returns either a list/array
76 * of structures (could be zero-length), or an error indication.
78 | RStructList of string * string (* name of retval, name of struct *)
79 (* Key-value pairs of untyped strings. Turns into a hashtable or
80 * dictionary in languages which support it. DON'T use this as a
81 * general "bucket" for results. Prefer a stronger typed return
82 * value if one is available, or write a custom struct. Don't use
83 * this if the list could potentially be very long, since it is
84 * inefficient. Keys should be unique. NULLs are not permitted.
86 | RHashtable of string
88 (* "RBufferOut" is handled almost exactly like RString, but
89 * it allows the string to contain arbitrary 8 bit data including
90 * ASCII NUL. In the C API this causes an implicit extra parameter
91 * to be added of type <size_t *size_r>. Other programming languages
92 * support strings with arbitrary 8 bit data. At the RPC layer
93 * we have to use the opaque<> type instead of string<>.
95 | RBufferOut of string
98 and args = argt list (* Function parameters, guestfs handle is implicit. *)
100 (* Note in future we should allow a "variable args" parameter as
101 * the final parameter, to allow commands like
102 * chmod mode file [file(s)...]
103 * This is not implemented yet, but many commands (such as chmod)
104 * are currently defined with the argument order keeping this future
105 * possibility in mind.
108 | String of string (* const char *name, cannot be NULL *)
109 | OptString of string (* const char *name, may be NULL *)
110 | StringList of string(* list of strings (each string cannot be NULL) *)
111 | Bool of string (* boolean *)
112 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
113 (* These are treated as filenames (simple string parameters) in
114 * the C API and bindings. But in the RPC protocol, we transfer
115 * the actual file content up to or down from the daemon.
116 * FileIn: local machine -> daemon (in request)
117 * FileOut: daemon -> local machine (in reply)
118 * In guestfish (only), the special name "-" means read from
119 * stdin or write to stdout.
124 (* Opaque buffer which can contain arbitrary 8 bit data.
125 * In the C API, this is expressed as <char *, int> pair.
126 * Most other languages have a string type which can contain
127 * ASCII NUL. We use whatever type is appropriate for each
129 * Buffers are limited by the total message size. To transfer
130 * large blocks of data, use FileIn/FileOut parameters instead.
131 * To return an arbitrary buffer, use RBufferOut.
137 | ProtocolLimitWarning (* display warning about protocol size limits *)
138 | DangerWillRobinson (* flags particularly dangerous commands *)
139 | FishAlias of string (* provide an alias for this cmd in guestfish *)
140 | FishAction of string (* call this function in guestfish *)
141 | NotInFish (* do not export via guestfish *)
142 | NotInDocs (* do not add this function to documentation *)
144 let protocol_limit_warning =
145 "Because of the message protocol, there is a transfer limit
146 of somewhere between 2MB and 4MB. To transfer large files you should use
149 let danger_will_robinson =
150 "B<This command is dangerous. Without careful use you
151 can easily destroy all your data>."
153 (* You can supply zero or as many tests as you want per API call.
155 * Note that the test environment has 3 block devices, of size 500MB,
156 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
157 * a fourth squashfs block device with some known files on it (/dev/sdd).
159 * Note for partitioning purposes, the 500MB device has 1015 cylinders.
160 * Number of cylinders was 63 for IDE emulated disks with precisely
161 * the same size. How exactly this is calculated is a mystery.
163 * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
165 * To be able to run the tests in a reasonable amount of time,
166 * the virtual machine and block devices are reused between tests.
167 * So don't try testing kill_subprocess :-x
169 * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
171 * Don't assume anything about the previous contents of the block
172 * devices. Use 'Init*' to create some initial scenarios.
174 * You can add a prerequisite clause to any individual test. This
175 * is a run-time check, which, if it fails, causes the test to be
176 * skipped. Useful if testing a command which might not work on
177 * all variations of libguestfs builds. A test that has prerequisite
178 * of 'Always' is run unconditionally.
180 * In addition, packagers can skip individual tests by setting the
181 * environment variables: eg:
182 * SKIP_TEST_<CMD>_<NUM>=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command)
183 * SKIP_TEST_<CMD>=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests)
185 type tests = (test_init * test_prereq * test) list
187 (* Run the command sequence and just expect nothing to fail. *)
189 (* Run the command sequence and expect the output of the final
190 * command to be the string.
192 | TestOutput of seq * string
193 (* Run the command sequence and expect the output of the final
194 * command to be the list of strings.
196 | TestOutputList of seq * string list
197 (* Run the command sequence and expect the output of the final
198 * command to be the list of block devices (could be either
199 * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
200 * character of each string).
202 | TestOutputListOfDevices of seq * string list
203 (* Run the command sequence and expect the output of the final
204 * command to be the integer.
206 | TestOutputInt of seq * int
207 (* Run the command sequence and expect the output of the final
208 * command to be a true value (!= 0 or != NULL).
210 | TestOutputTrue of seq
211 (* Run the command sequence and expect the output of the final
212 * command to be a false value (== 0 or == NULL, but not an error).
214 | TestOutputFalse of seq
215 (* Run the command sequence and expect the output of the final
216 * command to be a list of the given length (but don't care about
219 | TestOutputLength of seq * int
220 (* Run the command sequence and expect the output of the final
221 * command to be a structure.
223 | TestOutputStruct of seq * test_field_compare list
224 (* Run the command sequence and expect the final command (only)
227 | TestLastFail of seq
229 and test_field_compare =
230 | CompareWithInt of string * int
231 | CompareWithString of string * string
232 | CompareFieldsIntEq of string * string
233 | CompareFieldsStrEq of string * string
235 (* Test prerequisites. *)
237 (* Test always runs. *)
239 (* Test is currently disabled - eg. it fails, or it tests some
240 * unimplemented feature.
243 (* 'string' is some C code (a function body) that should return
244 * true or false. The test will run if the code returns true.
247 (* As for 'If' but the test runs _unless_ the code returns true. *)
250 (* Some initial scenarios for testing. *)
252 (* Do nothing, block devices could contain random stuff including
253 * LVM PVs, and some filesystems might be mounted. This is usually
257 (* Block devices are empty and no filesystems are mounted. *)
259 (* /dev/sda contains a single partition /dev/sda1, which is formatted
260 * as ext2, empty [except for lost+found] and mounted on /.
261 * /dev/sdb and /dev/sdc may have random content.
266 * /dev/sda1 (is a PV):
267 * /dev/VG/LV (size 8MB):
268 * formatted as ext2, empty [except for lost+found], mounted on /
269 * /dev/sdb and /dev/sdc may have random content.
273 (* Sequence of commands for testing. *)
275 and cmd = string list
277 (* Note about long descriptions: When referring to another
278 * action, use the format C<guestfs_other> (ie. the full name of
279 * the C function). This will be replaced as appropriate in other
282 * Apart from that, long descriptions are just perldoc paragraphs.
285 (* These test functions are used in the language binding tests. *)
287 let test_all_args = [
290 StringList "strlist";
297 let test_all_rets = [
298 (* except for RErr, which is tested thoroughly elsewhere *)
299 "test0rint", RInt "valout";
300 "test0rint64", RInt64 "valout";
301 "test0rbool", RBool "valout";
302 "test0rconststring", RConstString "valout";
303 "test0rstring", RString "valout";
304 "test0rstringlist", RStringList "valout";
305 "test0rstruct", RStruct ("valout", "lvm_pv");
306 "test0rstructlist", RStructList ("valout", "lvm_pv");
307 "test0rhashtable", RHashtable "valout";
310 let test_functions = [
311 ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
313 "internal test function - do not use",
315 This is an internal test function which is used to test whether
316 the automatically generated bindings can handle every possible
317 parameter type correctly.
319 It echos the contents of each parameter to stdout.
321 You probably don't want to call this function.");
325 [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
327 "internal test function - do not use",
329 This is an internal test function which is used to test whether
330 the automatically generated bindings can handle every possible
331 return type correctly.
333 It converts string C<val> to the return type.
335 You probably don't want to call this function.");
336 (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
338 "internal test function - do not use",
340 This is an internal test function which is used to test whether
341 the automatically generated bindings can handle every possible
342 return type correctly.
344 This function always returns an error.
346 You probably don't want to call this function.")]
350 (* non_daemon_functions are any functions which don't get processed
351 * in the daemon, eg. functions for setting and getting local
352 * configuration values.
355 let non_daemon_functions = test_functions @ [
356 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
358 "launch the qemu subprocess",
360 Internally libguestfs is implemented by running a virtual machine
363 You should call this after configuring the handle
364 (eg. adding drives) but before performing any actions.");
366 ("wait_ready", (RErr, []), -1, [NotInFish],
368 "wait until the qemu subprocess launches",
370 Internally libguestfs is implemented by running a virtual machine
373 You should call this after C<guestfs_launch> to wait for the launch
376 ("kill_subprocess", (RErr, []), -1, [],
378 "kill the qemu subprocess",
380 This kills the qemu subprocess. You should never need to call this.");
382 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
384 "add an image to examine or modify",
386 This function adds a virtual machine disk image C<filename> to the
387 guest. The first time you call this function, the disk appears as IDE
388 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
391 You don't necessarily need to be root when using libguestfs. However
392 you obviously do need sufficient permissions to access the filename
393 for whatever operations you want to perform (ie. read access if you
394 just want to read the image or write access if you want to modify the
397 This is equivalent to the qemu parameter
398 C<-drive file=filename,cache=off,if=...>.
400 Note that this call checks for the existence of C<filename>. This
401 stops you from specifying other types of drive which are supported
402 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
403 the general C<guestfs_config> call instead.");
405 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
407 "add a CD-ROM disk image to examine",
409 This function adds a virtual CD-ROM disk image to the guest.
411 This is equivalent to the qemu parameter C<-cdrom filename>.
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 ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
420 "add a drive in snapshot mode (read-only)",
422 This adds a drive in snapshot mode, making it effectively
425 Note that writes to the device are allowed, and will be seen for
426 the duration of the guestfs handle, but they are written
427 to a temporary file which is discarded as soon as the guestfs
428 handle is closed. We don't currently have any method to enable
429 changes to be committed, although qemu can support this.
431 This is equivalent to the qemu parameter
432 C<-drive file=filename,snapshot=on,if=...>.
434 Note that this call checks for the existence of C<filename>. This
435 stops you from specifying other types of drive which are supported
436 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
437 the general C<guestfs_config> call instead.");
439 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
441 "add qemu parameters",
443 This can be used to add arbitrary qemu command line parameters
444 of the form C<-param value>. Actually it's not quite arbitrary - we
445 prevent you from setting some parameters which would interfere with
446 parameters that we use.
448 The first character of C<param> string must be a C<-> (dash).
450 C<value> can be NULL.");
452 ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
454 "set the qemu binary",
456 Set the qemu binary that we will use.
458 The default is chosen when the library was compiled by the
461 You can also override this by setting the C<LIBGUESTFS_QEMU>
462 environment variable.
464 Setting C<qemu> to C<NULL> restores the default qemu binary.");
466 ("get_qemu", (RConstString "qemu", []), -1, [],
468 "get the qemu binary",
470 Return the current qemu binary.
472 This is always non-NULL. If it wasn't set already, then this will
473 return the default qemu binary name.");
475 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
477 "set the search path",
479 Set the path that libguestfs searches for kernel and initrd.img.
481 The default is C<$libdir/guestfs> unless overridden by setting
482 C<LIBGUESTFS_PATH> environment variable.
484 Setting C<path> to C<NULL> restores the default path.");
486 ("get_path", (RConstString "path", []), -1, [],
488 "get the search path",
490 Return the current search path.
492 This is always non-NULL. If it wasn't set already, then this will
493 return the default path.");
495 ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
497 "add options to kernel command line",
499 This function is used to add additional options to the
500 guest kernel command line.
502 The default is C<NULL> unless overridden by setting
503 C<LIBGUESTFS_APPEND> environment variable.
505 Setting C<append> to C<NULL> means I<no> additional options
506 are passed (libguestfs always adds a few of its own).");
508 ("get_append", (RConstString "append", []), -1, [],
510 "get the additional kernel options",
512 Return the additional kernel options which are added to the
513 guest kernel command line.
515 If C<NULL> then no options are added.");
517 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
521 If C<autosync> is true, this enables autosync. Libguestfs will make a
522 best effort attempt to run C<guestfs_umount_all> followed by
523 C<guestfs_sync> when the handle is closed
524 (also if the program exits without closing handles).
526 This is disabled by default (except in guestfish where it is
527 enabled by default).");
529 ("get_autosync", (RBool "autosync", []), -1, [],
533 Get the autosync flag.");
535 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
539 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
541 Verbose messages are disabled unless the environment variable
542 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
544 ("get_verbose", (RBool "verbose", []), -1, [],
548 This returns the verbose messages flag.");
550 ("is_ready", (RBool "ready", []), -1, [],
552 "is ready to accept commands",
554 This returns true iff this handle is ready to accept commands
555 (in the C<READY> state).
557 For more information on states, see L<guestfs(3)>.");
559 ("is_config", (RBool "config", []), -1, [],
561 "is in configuration state",
563 This returns true iff this handle is being configured
564 (in the C<CONFIG> state).
566 For more information on states, see L<guestfs(3)>.");
568 ("is_launching", (RBool "launching", []), -1, [],
570 "is launching subprocess",
572 This returns true iff this handle is launching the subprocess
573 (in the C<LAUNCHING> state).
575 For more information on states, see L<guestfs(3)>.");
577 ("is_busy", (RBool "busy", []), -1, [],
579 "is busy processing a command",
581 This returns true iff this handle is busy processing a command
582 (in the C<BUSY> state).
584 For more information on states, see L<guestfs(3)>.");
586 ("get_state", (RInt "state", []), -1, [],
588 "get the current state",
590 This returns the current state as an opaque integer. This is
591 only useful for printing debug and internal error messages.
593 For more information on states, see L<guestfs(3)>.");
595 ("set_busy", (RErr, []), -1, [NotInFish],
599 This sets the state to C<BUSY>. This is only used when implementing
600 actions using the low-level API.
602 For more information on states, see L<guestfs(3)>.");
604 ("set_ready", (RErr, []), -1, [NotInFish],
606 "set state to ready",
608 This sets the state to C<READY>. This is only used when implementing
609 actions using the low-level API.
611 For more information on states, see L<guestfs(3)>.");
613 ("end_busy", (RErr, []), -1, [NotInFish],
615 "leave the busy state",
617 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
618 state as is. This is only used when implementing
619 actions using the low-level API.
621 For more information on states, see L<guestfs(3)>.");
623 ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
625 "set memory allocated to the qemu subprocess",
627 This sets the memory size in megabytes allocated to the
628 qemu subprocess. This only has any effect if called before
631 You can also change this by setting the environment
632 variable C<LIBGUESTFS_MEMSIZE> before the handle is
635 For more information on the architecture of libguestfs,
636 see L<guestfs(3)>.");
638 ("get_memsize", (RInt "memsize", []), -1, [],
640 "get memory allocated to the qemu subprocess",
642 This gets the memory size in megabytes allocated to the
645 If C<guestfs_set_memsize> was not called
646 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
647 then this returns the compiled-in default value for memsize.
649 For more information on the architecture of libguestfs,
650 see L<guestfs(3)>.");
652 ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
654 "get PID of qemu subprocess",
656 Return the process ID of the qemu subprocess. If there is no
657 qemu subprocess, then this will return an error.
659 This is an internal call used for debugging and testing.");
661 ("version", (RStruct ("version", "version"), []), -1, [],
662 [InitNone, Always, TestOutputStruct (
663 [["version"]], [CompareWithInt ("major", 1)])],
664 "get the library version number",
666 Return the libguestfs version number that the program is linked
669 Note that because of dynamic linking this is not necessarily
670 the version of libguestfs that you compiled against. You can
671 compile the program, and then at runtime dynamically link
672 against a completely different C<libguestfs.so> library.
674 This call was added in version C<1.0.58>. In previous
675 versions of libguestfs there was no way to get the version
676 number. From C code you can use ELF weak linking tricks to find out if
677 this symbol exists (if it doesn't, then it's an earlier version).
679 The call returns a structure with four elements. The first
680 three (C<major>, C<minor> and C<release>) are numbers and
681 correspond to the usual version triplet. The fourth element
682 (C<extra>) is a string and is normally empty, but may be
683 used for distro-specific information.
685 To construct the original version string:
686 C<$major.$minor.$release$extra>
688 I<Note:> Don't use this call to test for availability
689 of features. Distro backports makes this unreliable.");
693 (* daemon_functions are any functions which cause some action
694 * to take place in the daemon.
697 let daemon_functions = [
698 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
699 [InitEmpty, Always, TestOutput (
700 [["sfdiskM"; "/dev/sda"; ","];
701 ["mkfs"; "ext2"; "/dev/sda1"];
702 ["mount"; "/dev/sda1"; "/"];
703 ["write_file"; "/new"; "new file contents"; "0"];
704 ["cat"; "/new"]], "new file contents")],
705 "mount a guest disk at a position in the filesystem",
707 Mount a guest disk at a position in the filesystem. Block devices
708 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
709 the guest. If those block devices contain partitions, they will have
710 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
713 The rules are the same as for L<mount(2)>: A filesystem must
714 first be mounted on C</> before others can be mounted. Other
715 filesystems can only be mounted on directories which already
718 The mounted filesystem is writable, if we have sufficient permissions
719 on the underlying device.
721 The filesystem options C<sync> and C<noatime> are set with this
722 call, in order to improve reliability.");
724 ("sync", (RErr, []), 2, [],
725 [ InitEmpty, Always, TestRun [["sync"]]],
726 "sync disks, writes are flushed through to the disk image",
728 This syncs the disk, so that any writes are flushed through to the
729 underlying disk image.
731 You should always call this if you have modified a disk image, before
732 closing the handle.");
734 ("touch", (RErr, [String "path"]), 3, [],
735 [InitBasicFS, Always, TestOutputTrue (
737 ["exists"; "/new"]])],
738 "update file timestamps or create a new file",
740 Touch acts like the L<touch(1)> command. It can be used to
741 update the timestamps on a file, or, if the file does not exist,
742 to create a new zero-length file.");
744 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
745 [InitBasicFS, Always, TestOutput (
746 [["write_file"; "/new"; "new file contents"; "0"];
747 ["cat"; "/new"]], "new file contents")],
748 "list the contents of a file",
750 Return the contents of the file named C<path>.
752 Note that this function cannot correctly handle binary files
753 (specifically, files containing C<\\0> character which is treated
754 as end of string). For those you need to use the C<guestfs_download>
755 function which has a more complex interface.");
757 ("ll", (RString "listing", [String "directory"]), 5, [],
758 [], (* XXX Tricky to test because it depends on the exact format
759 * of the 'ls -l' command, which changes between F10 and F11.
761 "list the files in a directory (long format)",
763 List the files in C<directory> (relative to the root directory,
764 there is no cwd) in the format of 'ls -la'.
766 This command is mostly useful for interactive sessions. It
767 is I<not> intended that you try to parse the output string.");
769 ("ls", (RStringList "listing", [String "directory"]), 6, [],
770 [InitBasicFS, Always, TestOutputList (
773 ["touch"; "/newest"];
774 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
775 "list the files in a directory",
777 List the files in C<directory> (relative to the root directory,
778 there is no cwd). The '.' and '..' entries are not returned, but
779 hidden files are shown.
781 This command is mostly useful for interactive sessions. Programs
782 should probably use C<guestfs_readdir> instead.");
784 ("list_devices", (RStringList "devices", []), 7, [],
785 [InitEmpty, Always, TestOutputListOfDevices (
786 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
787 "list the block devices",
789 List all the block devices.
791 The full block device names are returned, eg. C</dev/sda>");
793 ("list_partitions", (RStringList "partitions", []), 8, [],
794 [InitBasicFS, Always, TestOutputListOfDevices (
795 [["list_partitions"]], ["/dev/sda1"]);
796 InitEmpty, Always, TestOutputListOfDevices (
797 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
798 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
799 "list the partitions",
801 List all the partitions detected on all block devices.
803 The full partition device names are returned, eg. C</dev/sda1>
805 This does not return logical volumes. For that you will need to
806 call C<guestfs_lvs>.");
808 ("pvs", (RStringList "physvols", []), 9, [],
809 [InitBasicFSonLVM, Always, TestOutputListOfDevices (
810 [["pvs"]], ["/dev/sda1"]);
811 InitEmpty, Always, TestOutputListOfDevices (
812 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
813 ["pvcreate"; "/dev/sda1"];
814 ["pvcreate"; "/dev/sda2"];
815 ["pvcreate"; "/dev/sda3"];
816 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
817 "list the LVM physical volumes (PVs)",
819 List all the physical volumes detected. This is the equivalent
820 of the L<pvs(8)> command.
822 This returns a list of just the device names that contain
823 PVs (eg. C</dev/sda2>).
825 See also C<guestfs_pvs_full>.");
827 ("vgs", (RStringList "volgroups", []), 10, [],
828 [InitBasicFSonLVM, Always, TestOutputList (
830 InitEmpty, Always, TestOutputList (
831 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
832 ["pvcreate"; "/dev/sda1"];
833 ["pvcreate"; "/dev/sda2"];
834 ["pvcreate"; "/dev/sda3"];
835 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
836 ["vgcreate"; "VG2"; "/dev/sda3"];
837 ["vgs"]], ["VG1"; "VG2"])],
838 "list the LVM volume groups (VGs)",
840 List all the volumes groups detected. This is the equivalent
841 of the L<vgs(8)> command.
843 This returns a list of just the volume group names that were
844 detected (eg. C<VolGroup00>).
846 See also C<guestfs_vgs_full>.");
848 ("lvs", (RStringList "logvols", []), 11, [],
849 [InitBasicFSonLVM, Always, TestOutputList (
850 [["lvs"]], ["/dev/VG/LV"]);
851 InitEmpty, Always, TestOutputList (
852 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
853 ["pvcreate"; "/dev/sda1"];
854 ["pvcreate"; "/dev/sda2"];
855 ["pvcreate"; "/dev/sda3"];
856 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
857 ["vgcreate"; "VG2"; "/dev/sda3"];
858 ["lvcreate"; "LV1"; "VG1"; "50"];
859 ["lvcreate"; "LV2"; "VG1"; "50"];
860 ["lvcreate"; "LV3"; "VG2"; "50"];
861 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
862 "list the LVM logical volumes (LVs)",
864 List all the logical volumes detected. This is the equivalent
865 of the L<lvs(8)> command.
867 This returns a list of the logical volume device names
868 (eg. C</dev/VolGroup00/LogVol00>).
870 See also C<guestfs_lvs_full>.");
872 ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [],
873 [], (* XXX how to test? *)
874 "list the LVM physical volumes (PVs)",
876 List all the physical volumes detected. This is the equivalent
877 of the L<pvs(8)> command. The \"full\" version includes all fields.");
879 ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [],
880 [], (* XXX how to test? *)
881 "list the LVM volume groups (VGs)",
883 List all the volumes groups detected. This is the equivalent
884 of the L<vgs(8)> command. The \"full\" version includes all fields.");
886 ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [],
887 [], (* XXX how to test? *)
888 "list the LVM logical volumes (LVs)",
890 List all the logical volumes detected. This is the equivalent
891 of the L<lvs(8)> command. The \"full\" version includes all fields.");
893 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
894 [InitBasicFS, Always, TestOutputList (
895 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
896 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
897 InitBasicFS, Always, TestOutputList (
898 [["write_file"; "/new"; ""; "0"];
899 ["read_lines"; "/new"]], [])],
900 "read file as lines",
902 Return the contents of the file named C<path>.
904 The file contents are returned as a list of lines. Trailing
905 C<LF> and C<CRLF> character sequences are I<not> returned.
907 Note that this function cannot correctly handle binary files
908 (specifically, files containing C<\\0> character which is treated
909 as end of line). For those you need to use the C<guestfs_read_file>
910 function which has a more complex interface.");
912 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
913 [], (* XXX Augeas code needs tests. *)
914 "create a new Augeas handle",
916 Create a new Augeas handle for editing configuration files.
917 If there was any previous Augeas handle associated with this
918 guestfs session, then it is closed.
920 You must call this before using any other C<guestfs_aug_*>
923 C<root> is the filesystem root. C<root> must not be NULL,
926 The flags are the same as the flags defined in
927 E<lt>augeas.hE<gt>, the logical I<or> of the following
932 =item C<AUG_SAVE_BACKUP> = 1
934 Keep the original file with a C<.augsave> extension.
936 =item C<AUG_SAVE_NEWFILE> = 2
938 Save changes into a file with extension C<.augnew>, and
939 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
941 =item C<AUG_TYPE_CHECK> = 4
943 Typecheck lenses (can be expensive).
945 =item C<AUG_NO_STDINC> = 8
947 Do not use standard load path for modules.
949 =item C<AUG_SAVE_NOOP> = 16
951 Make save a no-op, just record what would have been changed.
953 =item C<AUG_NO_LOAD> = 32
955 Do not load the tree in C<guestfs_aug_init>.
959 To close the handle, you can call C<guestfs_aug_close>.
961 To find out more about Augeas, see L<http://augeas.net/>.");
963 ("aug_close", (RErr, []), 26, [],
964 [], (* XXX Augeas code needs tests. *)
965 "close the current Augeas handle",
967 Close the current Augeas handle and free up any resources
968 used by it. After calling this, you have to call
969 C<guestfs_aug_init> again before you can use any other
972 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
973 [], (* XXX Augeas code needs tests. *)
974 "define an Augeas variable",
976 Defines an Augeas variable C<name> whose value is the result
977 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
980 On success this returns the number of nodes in C<expr>, or
981 C<0> if C<expr> evaluates to something which is not a nodeset.");
983 ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [],
984 [], (* XXX Augeas code needs tests. *)
985 "define an Augeas node",
987 Defines a variable C<name> whose value is the result of
990 If C<expr> evaluates to an empty nodeset, a node is created,
991 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
992 C<name> will be the nodeset containing that single node.
994 On success this returns a pair containing the
995 number of nodes in the nodeset, and a boolean flag
996 if a node was created.");
998 ("aug_get", (RString "val", [String "path"]), 19, [],
999 [], (* XXX Augeas code needs tests. *)
1000 "look up the value of an Augeas path",
1002 Look up the value associated with C<path>. If C<path>
1003 matches exactly one node, the C<value> is returned.");
1005 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
1006 [], (* XXX Augeas code needs tests. *)
1007 "set Augeas path to value",
1009 Set the value associated with C<path> to C<value>.");
1011 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
1012 [], (* XXX Augeas code needs tests. *)
1013 "insert a sibling Augeas node",
1015 Create a new sibling C<label> for C<path>, inserting it into
1016 the tree before or after C<path> (depending on the boolean
1019 C<path> must match exactly one existing node in the tree, and
1020 C<label> must be a label, ie. not contain C</>, C<*> or end
1021 with a bracketed index C<[N]>.");
1023 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
1024 [], (* XXX Augeas code needs tests. *)
1025 "remove an Augeas path",
1027 Remove C<path> and all of its children.
1029 On success this returns the number of entries which were removed.");
1031 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
1032 [], (* XXX Augeas code needs tests. *)
1035 Move the node C<src> to C<dest>. C<src> must match exactly
1036 one node. C<dest> is overwritten if it exists.");
1038 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
1039 [], (* XXX Augeas code needs tests. *)
1040 "return Augeas nodes which match path",
1042 Returns a list of paths which match the path expression C<path>.
1043 The returned paths are sufficiently qualified so that they match
1044 exactly one node in the current tree.");
1046 ("aug_save", (RErr, []), 25, [],
1047 [], (* XXX Augeas code needs tests. *)
1048 "write all pending Augeas changes to disk",
1050 This writes all pending changes to disk.
1052 The flags which were passed to C<guestfs_aug_init> affect exactly
1053 how files are saved.");
1055 ("aug_load", (RErr, []), 27, [],
1056 [], (* XXX Augeas code needs tests. *)
1057 "load files into the tree",
1059 Load files into the tree.
1061 See C<aug_load> in the Augeas documentation for the full gory
1064 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
1065 [], (* XXX Augeas code needs tests. *)
1066 "list Augeas nodes under a path",
1068 This is just a shortcut for listing C<guestfs_aug_match>
1069 C<path/*> and sorting the resulting nodes into alphabetical order.");
1071 ("rm", (RErr, [String "path"]), 29, [],
1072 [InitBasicFS, Always, TestRun
1075 InitBasicFS, Always, TestLastFail
1077 InitBasicFS, Always, TestLastFail
1082 Remove the single file C<path>.");
1084 ("rmdir", (RErr, [String "path"]), 30, [],
1085 [InitBasicFS, Always, TestRun
1088 InitBasicFS, Always, TestLastFail
1089 [["rmdir"; "/new"]];
1090 InitBasicFS, Always, TestLastFail
1092 ["rmdir"; "/new"]]],
1093 "remove a directory",
1095 Remove the single directory C<path>.");
1097 ("rm_rf", (RErr, [String "path"]), 31, [],
1098 [InitBasicFS, Always, TestOutputFalse
1100 ["mkdir"; "/new/foo"];
1101 ["touch"; "/new/foo/bar"];
1103 ["exists"; "/new"]]],
1104 "remove a file or directory recursively",
1106 Remove the file or directory C<path>, recursively removing the
1107 contents if its a directory. This is like the C<rm -rf> shell
1110 ("mkdir", (RErr, [String "path"]), 32, [],
1111 [InitBasicFS, Always, TestOutputTrue
1113 ["is_dir"; "/new"]];
1114 InitBasicFS, Always, TestLastFail
1115 [["mkdir"; "/new/foo/bar"]]],
1116 "create a directory",
1118 Create a directory named C<path>.");
1120 ("mkdir_p", (RErr, [String "path"]), 33, [],
1121 [InitBasicFS, Always, TestOutputTrue
1122 [["mkdir_p"; "/new/foo/bar"];
1123 ["is_dir"; "/new/foo/bar"]];
1124 InitBasicFS, Always, TestOutputTrue
1125 [["mkdir_p"; "/new/foo/bar"];
1126 ["is_dir"; "/new/foo"]];
1127 InitBasicFS, Always, TestOutputTrue
1128 [["mkdir_p"; "/new/foo/bar"];
1129 ["is_dir"; "/new"]];
1130 (* Regression tests for RHBZ#503133: *)
1131 InitBasicFS, Always, TestRun
1133 ["mkdir_p"; "/new"]];
1134 InitBasicFS, Always, TestLastFail
1136 ["mkdir_p"; "/new"]]],
1137 "create a directory and parents",
1139 Create a directory named C<path>, creating any parent directories
1140 as necessary. This is like the C<mkdir -p> shell command.");
1142 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1143 [], (* XXX Need stat command to test *)
1146 Change the mode (permissions) of C<path> to C<mode>. Only
1147 numeric modes are supported.");
1149 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1150 [], (* XXX Need stat command to test *)
1151 "change file owner and group",
1153 Change the file owner to C<owner> and group to C<group>.
1155 Only numeric uid and gid are supported. If you want to use
1156 names, you will need to locate and parse the password file
1157 yourself (Augeas support makes this relatively easy).");
1159 ("exists", (RBool "existsflag", [String "path"]), 36, [],
1160 [InitBasicFS, Always, TestOutputTrue (
1162 ["exists"; "/new"]]);
1163 InitBasicFS, Always, TestOutputTrue (
1165 ["exists"; "/new"]])],
1166 "test if file or directory exists",
1168 This returns C<true> if and only if there is a file, directory
1169 (or anything) with the given C<path> name.
1171 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1173 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1174 [InitBasicFS, Always, TestOutputTrue (
1176 ["is_file"; "/new"]]);
1177 InitBasicFS, Always, TestOutputFalse (
1179 ["is_file"; "/new"]])],
1180 "test if file exists",
1182 This returns C<true> if and only if there is a file
1183 with the given C<path> name. Note that it returns false for
1184 other objects like directories.
1186 See also C<guestfs_stat>.");
1188 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1189 [InitBasicFS, Always, TestOutputFalse (
1191 ["is_dir"; "/new"]]);
1192 InitBasicFS, Always, TestOutputTrue (
1194 ["is_dir"; "/new"]])],
1195 "test if file exists",
1197 This returns C<true> if and only if there is a directory
1198 with the given C<path> name. Note that it returns false for
1199 other objects like files.
1201 See also C<guestfs_stat>.");
1203 ("pvcreate", (RErr, [String "device"]), 39, [],
1204 [InitEmpty, Always, TestOutputListOfDevices (
1205 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1206 ["pvcreate"; "/dev/sda1"];
1207 ["pvcreate"; "/dev/sda2"];
1208 ["pvcreate"; "/dev/sda3"];
1209 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1210 "create an LVM physical volume",
1212 This creates an LVM physical volume on the named C<device>,
1213 where C<device> should usually be a partition name such
1216 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1217 [InitEmpty, Always, TestOutputList (
1218 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1219 ["pvcreate"; "/dev/sda1"];
1220 ["pvcreate"; "/dev/sda2"];
1221 ["pvcreate"; "/dev/sda3"];
1222 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1223 ["vgcreate"; "VG2"; "/dev/sda3"];
1224 ["vgs"]], ["VG1"; "VG2"])],
1225 "create an LVM volume group",
1227 This creates an LVM volume group called C<volgroup>
1228 from the non-empty list of physical volumes C<physvols>.");
1230 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1231 [InitEmpty, Always, TestOutputList (
1232 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1233 ["pvcreate"; "/dev/sda1"];
1234 ["pvcreate"; "/dev/sda2"];
1235 ["pvcreate"; "/dev/sda3"];
1236 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1237 ["vgcreate"; "VG2"; "/dev/sda3"];
1238 ["lvcreate"; "LV1"; "VG1"; "50"];
1239 ["lvcreate"; "LV2"; "VG1"; "50"];
1240 ["lvcreate"; "LV3"; "VG2"; "50"];
1241 ["lvcreate"; "LV4"; "VG2"; "50"];
1242 ["lvcreate"; "LV5"; "VG2"; "50"];
1244 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1245 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1246 "create an LVM volume group",
1248 This creates an LVM volume group called C<logvol>
1249 on the volume group C<volgroup>, with C<size> megabytes.");
1251 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1252 [InitEmpty, Always, TestOutput (
1253 [["sfdiskM"; "/dev/sda"; ","];
1254 ["mkfs"; "ext2"; "/dev/sda1"];
1255 ["mount"; "/dev/sda1"; "/"];
1256 ["write_file"; "/new"; "new file contents"; "0"];
1257 ["cat"; "/new"]], "new file contents")],
1258 "make a filesystem",
1260 This creates a filesystem on C<device> (usually a partition
1261 or LVM logical volume). The filesystem type is C<fstype>, for
1264 ("sfdisk", (RErr, [String "device";
1265 Int "cyls"; Int "heads"; Int "sectors";
1266 StringList "lines"]), 43, [DangerWillRobinson],
1268 "create partitions on a block device",
1270 This is a direct interface to the L<sfdisk(8)> program for creating
1271 partitions on block devices.
1273 C<device> should be a block device, for example C</dev/sda>.
1275 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1276 and sectors on the device, which are passed directly to sfdisk as
1277 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
1278 of these, then the corresponding parameter is omitted. Usually for
1279 'large' disks, you can just pass C<0> for these, but for small
1280 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1281 out the right geometry and you will need to tell it.
1283 C<lines> is a list of lines that we feed to C<sfdisk>. For more
1284 information refer to the L<sfdisk(8)> manpage.
1286 To create a single partition occupying the whole disk, you would
1287 pass C<lines> as a single element list, when the single element being
1288 the string C<,> (comma).
1290 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1292 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1293 [InitBasicFS, Always, TestOutput (
1294 [["write_file"; "/new"; "new file contents"; "0"];
1295 ["cat"; "/new"]], "new file contents");
1296 InitBasicFS, Always, TestOutput (
1297 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1298 ["cat"; "/new"]], "\nnew file contents\n");
1299 InitBasicFS, Always, TestOutput (
1300 [["write_file"; "/new"; "\n\n"; "0"];
1301 ["cat"; "/new"]], "\n\n");
1302 InitBasicFS, Always, TestOutput (
1303 [["write_file"; "/new"; ""; "0"];
1304 ["cat"; "/new"]], "");
1305 InitBasicFS, Always, TestOutput (
1306 [["write_file"; "/new"; "\n\n\n"; "0"];
1307 ["cat"; "/new"]], "\n\n\n");
1308 InitBasicFS, Always, TestOutput (
1309 [["write_file"; "/new"; "\n"; "0"];
1310 ["cat"; "/new"]], "\n")],
1313 This call creates a file called C<path>. The contents of the
1314 file is the string C<content> (which can contain any 8 bit data),
1315 with length C<size>.
1317 As a special case, if C<size> is C<0>
1318 then the length is calculated using C<strlen> (so in this case
1319 the content cannot contain embedded ASCII NULs).
1321 I<NB.> Owing to a bug, writing content containing ASCII NUL
1322 characters does I<not> work, even if the length is specified.
1323 We hope to resolve this bug in a future version. In the meantime
1324 use C<guestfs_upload>.");
1326 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1327 [InitEmpty, Always, TestOutputListOfDevices (
1328 [["sfdiskM"; "/dev/sda"; ","];
1329 ["mkfs"; "ext2"; "/dev/sda1"];
1330 ["mount"; "/dev/sda1"; "/"];
1331 ["mounts"]], ["/dev/sda1"]);
1332 InitEmpty, Always, TestOutputList (
1333 [["sfdiskM"; "/dev/sda"; ","];
1334 ["mkfs"; "ext2"; "/dev/sda1"];
1335 ["mount"; "/dev/sda1"; "/"];
1338 "unmount a filesystem",
1340 This unmounts the given filesystem. The filesystem may be
1341 specified either by its mountpoint (path) or the device which
1342 contains the filesystem.");
1344 ("mounts", (RStringList "devices", []), 46, [],
1345 [InitBasicFS, Always, TestOutputListOfDevices (
1346 [["mounts"]], ["/dev/sda1"])],
1347 "show mounted filesystems",
1349 This returns the list of currently mounted filesystems. It returns
1350 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1352 Some internal mounts are not shown.");
1354 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1355 [InitBasicFS, Always, TestOutputList (
1358 (* check that umount_all can unmount nested mounts correctly: *)
1359 InitEmpty, Always, TestOutputList (
1360 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1361 ["mkfs"; "ext2"; "/dev/sda1"];
1362 ["mkfs"; "ext2"; "/dev/sda2"];
1363 ["mkfs"; "ext2"; "/dev/sda3"];
1364 ["mount"; "/dev/sda1"; "/"];
1366 ["mount"; "/dev/sda2"; "/mp1"];
1367 ["mkdir"; "/mp1/mp2"];
1368 ["mount"; "/dev/sda3"; "/mp1/mp2"];
1369 ["mkdir"; "/mp1/mp2/mp3"];
1372 "unmount all filesystems",
1374 This unmounts all mounted filesystems.
1376 Some internal mounts are not unmounted by this call.");
1378 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1380 "remove all LVM LVs, VGs and PVs",
1382 This command removes all LVM logical volumes, volume groups
1383 and physical volumes.");
1385 ("file", (RString "description", [String "path"]), 49, [],
1386 [InitBasicFS, Always, TestOutput (
1388 ["file"; "/new"]], "empty");
1389 InitBasicFS, Always, TestOutput (
1390 [["write_file"; "/new"; "some content\n"; "0"];
1391 ["file"; "/new"]], "ASCII text");
1392 InitBasicFS, Always, TestLastFail (
1393 [["file"; "/nofile"]])],
1394 "determine file type",
1396 This call uses the standard L<file(1)> command to determine
1397 the type or contents of the file. This also works on devices,
1398 for example to find out whether a partition contains a filesystem.
1400 The exact command which runs is C<file -bsL path>. Note in
1401 particular that the filename is not prepended to the output
1402 (the C<-b> option).");
1404 ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1405 [InitBasicFS, Always, TestOutput (
1406 [["upload"; "test-command"; "/test-command"];
1407 ["chmod"; "0o755"; "/test-command"];
1408 ["command"; "/test-command 1"]], "Result1");
1409 InitBasicFS, Always, TestOutput (
1410 [["upload"; "test-command"; "/test-command"];
1411 ["chmod"; "0o755"; "/test-command"];
1412 ["command"; "/test-command 2"]], "Result2\n");
1413 InitBasicFS, Always, TestOutput (
1414 [["upload"; "test-command"; "/test-command"];
1415 ["chmod"; "0o755"; "/test-command"];
1416 ["command"; "/test-command 3"]], "\nResult3");
1417 InitBasicFS, Always, TestOutput (
1418 [["upload"; "test-command"; "/test-command"];
1419 ["chmod"; "0o755"; "/test-command"];
1420 ["command"; "/test-command 4"]], "\nResult4\n");
1421 InitBasicFS, Always, TestOutput (
1422 [["upload"; "test-command"; "/test-command"];
1423 ["chmod"; "0o755"; "/test-command"];
1424 ["command"; "/test-command 5"]], "\nResult5\n\n");
1425 InitBasicFS, Always, TestOutput (
1426 [["upload"; "test-command"; "/test-command"];
1427 ["chmod"; "0o755"; "/test-command"];
1428 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1429 InitBasicFS, Always, TestOutput (
1430 [["upload"; "test-command"; "/test-command"];
1431 ["chmod"; "0o755"; "/test-command"];
1432 ["command"; "/test-command 7"]], "");
1433 InitBasicFS, Always, TestOutput (
1434 [["upload"; "test-command"; "/test-command"];
1435 ["chmod"; "0o755"; "/test-command"];
1436 ["command"; "/test-command 8"]], "\n");
1437 InitBasicFS, Always, TestOutput (
1438 [["upload"; "test-command"; "/test-command"];
1439 ["chmod"; "0o755"; "/test-command"];
1440 ["command"; "/test-command 9"]], "\n\n");
1441 InitBasicFS, Always, TestOutput (
1442 [["upload"; "test-command"; "/test-command"];
1443 ["chmod"; "0o755"; "/test-command"];
1444 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1445 InitBasicFS, Always, TestOutput (
1446 [["upload"; "test-command"; "/test-command"];
1447 ["chmod"; "0o755"; "/test-command"];
1448 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1449 InitBasicFS, Always, TestLastFail (
1450 [["upload"; "test-command"; "/test-command"];
1451 ["chmod"; "0o755"; "/test-command"];
1452 ["command"; "/test-command"]])],
1453 "run a command from the guest filesystem",
1455 This call runs a command from the guest filesystem. The
1456 filesystem must be mounted, and must contain a compatible
1457 operating system (ie. something Linux, with the same
1458 or compatible processor architecture).
1460 The single parameter is an argv-style list of arguments.
1461 The first element is the name of the program to run.
1462 Subsequent elements are parameters. The list must be
1463 non-empty (ie. must contain a program name). Note that
1464 the command runs directly, and is I<not> invoked via
1465 the shell (see C<guestfs_sh>).
1467 The return value is anything printed to I<stdout> by
1470 If the command returns a non-zero exit status, then
1471 this function returns an error message. The error message
1472 string is the content of I<stderr> from the command.
1474 The C<$PATH> environment variable will contain at least
1475 C</usr/bin> and C</bin>. If you require a program from
1476 another location, you should provide the full path in the
1479 Shared libraries and data files required by the program
1480 must be available on filesystems which are mounted in the
1481 correct places. It is the caller's responsibility to ensure
1482 all filesystems that are needed are mounted at the right
1485 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1486 [InitBasicFS, Always, TestOutputList (
1487 [["upload"; "test-command"; "/test-command"];
1488 ["chmod"; "0o755"; "/test-command"];
1489 ["command_lines"; "/test-command 1"]], ["Result1"]);
1490 InitBasicFS, Always, TestOutputList (
1491 [["upload"; "test-command"; "/test-command"];
1492 ["chmod"; "0o755"; "/test-command"];
1493 ["command_lines"; "/test-command 2"]], ["Result2"]);
1494 InitBasicFS, Always, TestOutputList (
1495 [["upload"; "test-command"; "/test-command"];
1496 ["chmod"; "0o755"; "/test-command"];
1497 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1498 InitBasicFS, Always, TestOutputList (
1499 [["upload"; "test-command"; "/test-command"];
1500 ["chmod"; "0o755"; "/test-command"];
1501 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1502 InitBasicFS, Always, TestOutputList (
1503 [["upload"; "test-command"; "/test-command"];
1504 ["chmod"; "0o755"; "/test-command"];
1505 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1506 InitBasicFS, Always, TestOutputList (
1507 [["upload"; "test-command"; "/test-command"];
1508 ["chmod"; "0o755"; "/test-command"];
1509 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1510 InitBasicFS, Always, TestOutputList (
1511 [["upload"; "test-command"; "/test-command"];
1512 ["chmod"; "0o755"; "/test-command"];
1513 ["command_lines"; "/test-command 7"]], []);
1514 InitBasicFS, Always, TestOutputList (
1515 [["upload"; "test-command"; "/test-command"];
1516 ["chmod"; "0o755"; "/test-command"];
1517 ["command_lines"; "/test-command 8"]], [""]);
1518 InitBasicFS, Always, TestOutputList (
1519 [["upload"; "test-command"; "/test-command"];
1520 ["chmod"; "0o755"; "/test-command"];
1521 ["command_lines"; "/test-command 9"]], ["";""]);
1522 InitBasicFS, Always, TestOutputList (
1523 [["upload"; "test-command"; "/test-command"];
1524 ["chmod"; "0o755"; "/test-command"];
1525 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1526 InitBasicFS, Always, TestOutputList (
1527 [["upload"; "test-command"; "/test-command"];
1528 ["chmod"; "0o755"; "/test-command"];
1529 ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1530 "run a command, returning lines",
1532 This is the same as C<guestfs_command>, but splits the
1533 result into a list of lines.
1535 See also: C<guestfs_sh_lines>");
1537 ("stat", (RStruct ("statbuf", "stat"), [String "path"]), 52, [],
1538 [InitBasicFS, Always, TestOutputStruct (
1540 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1541 "get file information",
1543 Returns file information for the given C<path>.
1545 This is the same as the C<stat(2)> system call.");
1547 ("lstat", (RStruct ("statbuf", "stat"), [String "path"]), 53, [],
1548 [InitBasicFS, Always, TestOutputStruct (
1550 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1551 "get file information for a symbolic link",
1553 Returns file information for the given C<path>.
1555 This is the same as C<guestfs_stat> except that if C<path>
1556 is a symbolic link, then the link is stat-ed, not the file it
1559 This is the same as the C<lstat(2)> system call.");
1561 ("statvfs", (RStruct ("statbuf", "statvfs"), [String "path"]), 54, [],
1562 [InitBasicFS, Always, TestOutputStruct (
1563 [["statvfs"; "/"]], [CompareWithInt ("namemax", 255);
1564 CompareWithInt ("bsize", 1024)])],
1565 "get file system statistics",
1567 Returns file system statistics for any mounted file system.
1568 C<path> should be a file or directory in the mounted file system
1569 (typically it is the mount point itself, but it doesn't need to be).
1571 This is the same as the C<statvfs(2)> system call.");
1573 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1575 "get ext2/ext3/ext4 superblock details",
1577 This returns the contents of the ext2, ext3 or ext4 filesystem
1578 superblock on C<device>.
1580 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1581 manpage for more details. The list of fields returned isn't
1582 clearly defined, and depends on both the version of C<tune2fs>
1583 that libguestfs was built against, and the filesystem itself.");
1585 ("blockdev_setro", (RErr, [String "device"]), 56, [],
1586 [InitEmpty, Always, TestOutputTrue (
1587 [["blockdev_setro"; "/dev/sda"];
1588 ["blockdev_getro"; "/dev/sda"]])],
1589 "set block device to read-only",
1591 Sets the block device named C<device> to read-only.
1593 This uses the L<blockdev(8)> command.");
1595 ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1596 [InitEmpty, Always, TestOutputFalse (
1597 [["blockdev_setrw"; "/dev/sda"];
1598 ["blockdev_getro"; "/dev/sda"]])],
1599 "set block device to read-write",
1601 Sets the block device named C<device> to read-write.
1603 This uses the L<blockdev(8)> command.");
1605 ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1606 [InitEmpty, Always, TestOutputTrue (
1607 [["blockdev_setro"; "/dev/sda"];
1608 ["blockdev_getro"; "/dev/sda"]])],
1609 "is block device set to read-only",
1611 Returns a boolean indicating if the block device is read-only
1612 (true if read-only, false if not).
1614 This uses the L<blockdev(8)> command.");
1616 ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1617 [InitEmpty, Always, TestOutputInt (
1618 [["blockdev_getss"; "/dev/sda"]], 512)],
1619 "get sectorsize of block device",
1621 This returns the size of sectors on a block device.
1622 Usually 512, but can be larger for modern devices.
1624 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1627 This uses the L<blockdev(8)> command.");
1629 ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1630 [InitEmpty, Always, TestOutputInt (
1631 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1632 "get blocksize of block device",
1634 This returns the block size of a device.
1636 (Note this is different from both I<size in blocks> and
1637 I<filesystem block size>).
1639 This uses the L<blockdev(8)> command.");
1641 ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1643 "set blocksize of block device",
1645 This sets the block size of a device.
1647 (Note this is different from both I<size in blocks> and
1648 I<filesystem block size>).
1650 This uses the L<blockdev(8)> command.");
1652 ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1653 [InitEmpty, Always, TestOutputInt (
1654 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1655 "get total size of device in 512-byte sectors",
1657 This returns the size of the device in units of 512-byte sectors
1658 (even if the sectorsize isn't 512 bytes ... weird).
1660 See also C<guestfs_blockdev_getss> for the real sector size of
1661 the device, and C<guestfs_blockdev_getsize64> for the more
1662 useful I<size in bytes>.
1664 This uses the L<blockdev(8)> command.");
1666 ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1667 [InitEmpty, Always, TestOutputInt (
1668 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1669 "get total size of device in bytes",
1671 This returns the size of the device in bytes.
1673 See also C<guestfs_blockdev_getsz>.
1675 This uses the L<blockdev(8)> command.");
1677 ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1678 [InitEmpty, Always, TestRun
1679 [["blockdev_flushbufs"; "/dev/sda"]]],
1680 "flush device buffers",
1682 This tells the kernel to flush internal buffers associated
1685 This uses the L<blockdev(8)> command.");
1687 ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1688 [InitEmpty, Always, TestRun
1689 [["blockdev_rereadpt"; "/dev/sda"]]],
1690 "reread partition table",
1692 Reread the partition table on C<device>.
1694 This uses the L<blockdev(8)> command.");
1696 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1697 [InitBasicFS, Always, TestOutput (
1698 (* Pick a file from cwd which isn't likely to change. *)
1699 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1700 ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1701 "upload a file from the local machine",
1703 Upload local file C<filename> to C<remotefilename> on the
1706 C<filename> can also be a named pipe.
1708 See also C<guestfs_download>.");
1710 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1711 [InitBasicFS, Always, TestOutput (
1712 (* Pick a file from cwd which isn't likely to change. *)
1713 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1714 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1715 ["upload"; "testdownload.tmp"; "/upload"];
1716 ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1717 "download a file to the local machine",
1719 Download file C<remotefilename> and save it as C<filename>
1720 on the local machine.
1722 C<filename> can also be a named pipe.
1724 See also C<guestfs_upload>, C<guestfs_cat>.");
1726 ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1727 [InitBasicFS, Always, TestOutput (
1728 [["write_file"; "/new"; "test\n"; "0"];
1729 ["checksum"; "crc"; "/new"]], "935282863");
1730 InitBasicFS, Always, TestLastFail (
1731 [["checksum"; "crc"; "/new"]]);
1732 InitBasicFS, Always, TestOutput (
1733 [["write_file"; "/new"; "test\n"; "0"];
1734 ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1735 InitBasicFS, Always, TestOutput (
1736 [["write_file"; "/new"; "test\n"; "0"];
1737 ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1738 InitBasicFS, Always, TestOutput (
1739 [["write_file"; "/new"; "test\n"; "0"];
1740 ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1741 InitBasicFS, Always, TestOutput (
1742 [["write_file"; "/new"; "test\n"; "0"];
1743 ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1744 InitBasicFS, Always, TestOutput (
1745 [["write_file"; "/new"; "test\n"; "0"];
1746 ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1747 InitBasicFS, Always, TestOutput (
1748 [["write_file"; "/new"; "test\n"; "0"];
1749 ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
1750 InitBasicFS, Always, TestOutput (
1751 (* RHEL 5 thinks this is an HFS+ filesystem unless we give
1752 * the type explicitly.
1754 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
1755 ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
1756 "compute MD5, SHAx or CRC checksum of file",
1758 This call computes the MD5, SHAx or CRC checksum of the
1761 The type of checksum to compute is given by the C<csumtype>
1762 parameter which must have one of the following values:
1768 Compute the cyclic redundancy check (CRC) specified by POSIX
1769 for the C<cksum> command.
1773 Compute the MD5 hash (using the C<md5sum> program).
1777 Compute the SHA1 hash (using the C<sha1sum> program).
1781 Compute the SHA224 hash (using the C<sha224sum> program).
1785 Compute the SHA256 hash (using the C<sha256sum> program).
1789 Compute the SHA384 hash (using the C<sha384sum> program).
1793 Compute the SHA512 hash (using the C<sha512sum> program).
1797 The checksum is returned as a printable string.");
1799 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1800 [InitBasicFS, Always, TestOutput (
1801 [["tar_in"; "../images/helloworld.tar"; "/"];
1802 ["cat"; "/hello"]], "hello\n")],
1803 "unpack tarfile to directory",
1805 This command uploads and unpacks local file C<tarfile> (an
1806 I<uncompressed> tar file) into C<directory>.
1808 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1810 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1812 "pack directory into tarfile",
1814 This command packs the contents of C<directory> and downloads
1815 it to local file C<tarfile>.
1817 To download a compressed tarball, use C<guestfs_tgz_out>.");
1819 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1820 [InitBasicFS, Always, TestOutput (
1821 [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1822 ["cat"; "/hello"]], "hello\n")],
1823 "unpack compressed tarball to directory",
1825 This command uploads and unpacks local file C<tarball> (a
1826 I<gzip compressed> tar file) into C<directory>.
1828 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1830 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1832 "pack directory into compressed tarball",
1834 This command packs the contents of C<directory> and downloads
1835 it to local file C<tarball>.
1837 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1839 ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1840 [InitBasicFS, Always, TestLastFail (
1842 ["mount_ro"; "/dev/sda1"; "/"];
1843 ["touch"; "/new"]]);
1844 InitBasicFS, Always, TestOutput (
1845 [["write_file"; "/new"; "data"; "0"];
1847 ["mount_ro"; "/dev/sda1"; "/"];
1848 ["cat"; "/new"]], "data")],
1849 "mount a guest disk, read-only",
1851 This is the same as the C<guestfs_mount> command, but it
1852 mounts the filesystem with the read-only (I<-o ro>) flag.");
1854 ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1856 "mount a guest disk with mount options",
1858 This is the same as the C<guestfs_mount> command, but it
1859 allows you to set the mount options as for the
1860 L<mount(8)> I<-o> flag.");
1862 ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1864 "mount a guest disk with mount options and vfstype",
1866 This is the same as the C<guestfs_mount> command, but it
1867 allows you to set both the mount options and the vfstype
1868 as for the L<mount(8)> I<-o> and I<-t> flags.");
1870 ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1872 "debugging and internals",
1874 The C<guestfs_debug> command exposes some internals of
1875 C<guestfsd> (the guestfs daemon) that runs inside the
1878 There is no comprehensive help for this command. You have
1879 to look at the file C<daemon/debug.c> in the libguestfs source
1880 to find out what you can do.");
1882 ("lvremove", (RErr, [String "device"]), 77, [],
1883 [InitEmpty, Always, TestOutputList (
1884 [["sfdiskM"; "/dev/sda"; ","];
1885 ["pvcreate"; "/dev/sda1"];
1886 ["vgcreate"; "VG"; "/dev/sda1"];
1887 ["lvcreate"; "LV1"; "VG"; "50"];
1888 ["lvcreate"; "LV2"; "VG"; "50"];
1889 ["lvremove"; "/dev/VG/LV1"];
1890 ["lvs"]], ["/dev/VG/LV2"]);
1891 InitEmpty, Always, TestOutputList (
1892 [["sfdiskM"; "/dev/sda"; ","];
1893 ["pvcreate"; "/dev/sda1"];
1894 ["vgcreate"; "VG"; "/dev/sda1"];
1895 ["lvcreate"; "LV1"; "VG"; "50"];
1896 ["lvcreate"; "LV2"; "VG"; "50"];
1897 ["lvremove"; "/dev/VG"];
1899 InitEmpty, Always, TestOutputList (
1900 [["sfdiskM"; "/dev/sda"; ","];
1901 ["pvcreate"; "/dev/sda1"];
1902 ["vgcreate"; "VG"; "/dev/sda1"];
1903 ["lvcreate"; "LV1"; "VG"; "50"];
1904 ["lvcreate"; "LV2"; "VG"; "50"];
1905 ["lvremove"; "/dev/VG"];
1907 "remove an LVM logical volume",
1909 Remove an LVM logical volume C<device>, where C<device> is
1910 the path to the LV, such as C</dev/VG/LV>.
1912 You can also remove all LVs in a volume group by specifying
1913 the VG name, C</dev/VG>.");
1915 ("vgremove", (RErr, [String "vgname"]), 78, [],
1916 [InitEmpty, Always, TestOutputList (
1917 [["sfdiskM"; "/dev/sda"; ","];
1918 ["pvcreate"; "/dev/sda1"];
1919 ["vgcreate"; "VG"; "/dev/sda1"];
1920 ["lvcreate"; "LV1"; "VG"; "50"];
1921 ["lvcreate"; "LV2"; "VG"; "50"];
1924 InitEmpty, Always, TestOutputList (
1925 [["sfdiskM"; "/dev/sda"; ","];
1926 ["pvcreate"; "/dev/sda1"];
1927 ["vgcreate"; "VG"; "/dev/sda1"];
1928 ["lvcreate"; "LV1"; "VG"; "50"];
1929 ["lvcreate"; "LV2"; "VG"; "50"];
1932 "remove an LVM volume group",
1934 Remove an LVM volume group C<vgname>, (for example C<VG>).
1936 This also forcibly removes all logical volumes in the volume
1939 ("pvremove", (RErr, [String "device"]), 79, [],
1940 [InitEmpty, Always, TestOutputListOfDevices (
1941 [["sfdiskM"; "/dev/sda"; ","];
1942 ["pvcreate"; "/dev/sda1"];
1943 ["vgcreate"; "VG"; "/dev/sda1"];
1944 ["lvcreate"; "LV1"; "VG"; "50"];
1945 ["lvcreate"; "LV2"; "VG"; "50"];
1947 ["pvremove"; "/dev/sda1"];
1949 InitEmpty, Always, TestOutputListOfDevices (
1950 [["sfdiskM"; "/dev/sda"; ","];
1951 ["pvcreate"; "/dev/sda1"];
1952 ["vgcreate"; "VG"; "/dev/sda1"];
1953 ["lvcreate"; "LV1"; "VG"; "50"];
1954 ["lvcreate"; "LV2"; "VG"; "50"];
1956 ["pvremove"; "/dev/sda1"];
1958 InitEmpty, Always, TestOutputListOfDevices (
1959 [["sfdiskM"; "/dev/sda"; ","];
1960 ["pvcreate"; "/dev/sda1"];
1961 ["vgcreate"; "VG"; "/dev/sda1"];
1962 ["lvcreate"; "LV1"; "VG"; "50"];
1963 ["lvcreate"; "LV2"; "VG"; "50"];
1965 ["pvremove"; "/dev/sda1"];
1967 "remove an LVM physical volume",
1969 This wipes a physical volume C<device> so that LVM will no longer
1972 The implementation uses the C<pvremove> command which refuses to
1973 wipe physical volumes that contain any volume groups, so you have
1974 to remove those first.");
1976 ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
1977 [InitBasicFS, Always, TestOutput (
1978 [["set_e2label"; "/dev/sda1"; "testlabel"];
1979 ["get_e2label"; "/dev/sda1"]], "testlabel")],
1980 "set the ext2/3/4 filesystem label",
1982 This sets the ext2/3/4 filesystem label of the filesystem on
1983 C<device> to C<label>. Filesystem labels are limited to
1986 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
1987 to return the existing label on a filesystem.");
1989 ("get_e2label", (RString "label", [String "device"]), 81, [],
1991 "get the ext2/3/4 filesystem label",
1993 This returns the ext2/3/4 filesystem label of the filesystem on
1996 ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
1997 [InitBasicFS, Always, TestOutput (
1998 [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
1999 ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
2000 InitBasicFS, Always, TestOutput (
2001 [["set_e2uuid"; "/dev/sda1"; "clear"];
2002 ["get_e2uuid"; "/dev/sda1"]], "");
2003 (* We can't predict what UUIDs will be, so just check the commands run. *)
2004 InitBasicFS, Always, TestRun (
2005 [["set_e2uuid"; "/dev/sda1"; "random"]]);
2006 InitBasicFS, Always, TestRun (
2007 [["set_e2uuid"; "/dev/sda1"; "time"]])],
2008 "set the ext2/3/4 filesystem UUID",
2010 This sets the ext2/3/4 filesystem UUID of the filesystem on
2011 C<device> to C<uuid>. The format of the UUID and alternatives
2012 such as C<clear>, C<random> and C<time> are described in the
2013 L<tune2fs(8)> manpage.
2015 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2016 to return the existing UUID of a filesystem.");
2018 ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
2020 "get the ext2/3/4 filesystem UUID",
2022 This returns the ext2/3/4 filesystem UUID of the filesystem on
2025 ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
2026 [InitBasicFS, Always, TestOutputInt (
2027 [["umount"; "/dev/sda1"];
2028 ["fsck"; "ext2"; "/dev/sda1"]], 0);
2029 InitBasicFS, Always, TestOutputInt (
2030 [["umount"; "/dev/sda1"];
2031 ["zero"; "/dev/sda1"];
2032 ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2033 "run the filesystem checker",
2035 This runs the filesystem checker (fsck) on C<device> which
2036 should have filesystem type C<fstype>.
2038 The returned integer is the status. See L<fsck(8)> for the
2039 list of status codes from C<fsck>.
2047 Multiple status codes can be summed together.
2051 A non-zero return code can mean \"success\", for example if
2052 errors have been corrected on the filesystem.
2056 Checking or repairing NTFS volumes is not supported
2061 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2063 ("zero", (RErr, [String "device"]), 85, [],
2064 [InitBasicFS, Always, TestOutput (
2065 [["umount"; "/dev/sda1"];
2066 ["zero"; "/dev/sda1"];
2067 ["file"; "/dev/sda1"]], "data")],
2068 "write zeroes to the device",
2070 This command writes zeroes over the first few blocks of C<device>.
2072 How many blocks are zeroed isn't specified (but it's I<not> enough
2073 to securely wipe the device). It should be sufficient to remove
2074 any partition tables, filesystem superblocks and so on.
2076 See also: C<guestfs_scrub_device>.");
2078 ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
2079 (* Test disabled because grub-install incompatible with virtio-blk driver.
2080 * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2082 [InitBasicFS, Disabled, TestOutputTrue (
2083 [["grub_install"; "/"; "/dev/sda1"];
2084 ["is_dir"; "/boot"]])],
2087 This command installs GRUB (the Grand Unified Bootloader) on
2088 C<device>, with the root directory being C<root>.");
2090 ("cp", (RErr, [String "src"; String "dest"]), 87, [],
2091 [InitBasicFS, Always, TestOutput (
2092 [["write_file"; "/old"; "file content"; "0"];
2093 ["cp"; "/old"; "/new"];
2094 ["cat"; "/new"]], "file content");
2095 InitBasicFS, Always, TestOutputTrue (
2096 [["write_file"; "/old"; "file content"; "0"];
2097 ["cp"; "/old"; "/new"];
2098 ["is_file"; "/old"]]);
2099 InitBasicFS, Always, TestOutput (
2100 [["write_file"; "/old"; "file content"; "0"];
2102 ["cp"; "/old"; "/dir/new"];
2103 ["cat"; "/dir/new"]], "file content")],
2106 This copies a file from C<src> to C<dest> where C<dest> is
2107 either a destination filename or destination directory.");
2109 ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2110 [InitBasicFS, Always, TestOutput (
2111 [["mkdir"; "/olddir"];
2112 ["mkdir"; "/newdir"];
2113 ["write_file"; "/olddir/file"; "file content"; "0"];
2114 ["cp_a"; "/olddir"; "/newdir"];
2115 ["cat"; "/newdir/olddir/file"]], "file content")],
2116 "copy a file or directory recursively",
2118 This copies a file or directory from C<src> to C<dest>
2119 recursively using the C<cp -a> command.");
2121 ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2122 [InitBasicFS, Always, TestOutput (
2123 [["write_file"; "/old"; "file content"; "0"];
2124 ["mv"; "/old"; "/new"];
2125 ["cat"; "/new"]], "file content");
2126 InitBasicFS, Always, TestOutputFalse (
2127 [["write_file"; "/old"; "file content"; "0"];
2128 ["mv"; "/old"; "/new"];
2129 ["is_file"; "/old"]])],
2132 This moves a file from C<src> to C<dest> where C<dest> is
2133 either a destination filename or destination directory.");
2135 ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2136 [InitEmpty, Always, TestRun (
2137 [["drop_caches"; "3"]])],
2138 "drop kernel page cache, dentries and inodes",
2140 This instructs the guest kernel to drop its page cache,
2141 and/or dentries and inode caches. The parameter C<whattodrop>
2142 tells the kernel what precisely to drop, see
2143 L<http://linux-mm.org/Drop_Caches>
2145 Setting C<whattodrop> to 3 should drop everything.
2147 This automatically calls L<sync(2)> before the operation,
2148 so that the maximum guest memory is freed.");
2150 ("dmesg", (RString "kmsgs", []), 91, [],
2151 [InitEmpty, Always, TestRun (
2153 "return kernel messages",
2155 This returns the kernel messages (C<dmesg> output) from
2156 the guest kernel. This is sometimes useful for extended
2157 debugging of problems.
2159 Another way to get the same information is to enable
2160 verbose messages with C<guestfs_set_verbose> or by setting
2161 the environment variable C<LIBGUESTFS_DEBUG=1> before
2162 running the program.");
2164 ("ping_daemon", (RErr, []), 92, [],
2165 [InitEmpty, Always, TestRun (
2166 [["ping_daemon"]])],
2167 "ping the guest daemon",
2169 This is a test probe into the guestfs daemon running inside
2170 the qemu subprocess. Calling this function checks that the
2171 daemon responds to the ping message, without affecting the daemon
2172 or attached block device(s) in any other way.");
2174 ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2175 [InitBasicFS, Always, TestOutputTrue (
2176 [["write_file"; "/file1"; "contents of a file"; "0"];
2177 ["cp"; "/file1"; "/file2"];
2178 ["equal"; "/file1"; "/file2"]]);
2179 InitBasicFS, Always, TestOutputFalse (
2180 [["write_file"; "/file1"; "contents of a file"; "0"];
2181 ["write_file"; "/file2"; "contents of another file"; "0"];
2182 ["equal"; "/file1"; "/file2"]]);
2183 InitBasicFS, Always, TestLastFail (
2184 [["equal"; "/file1"; "/file2"]])],
2185 "test if two files have equal contents",
2187 This compares the two files C<file1> and C<file2> and returns
2188 true if their content is exactly equal, or false otherwise.
2190 The external L<cmp(1)> program is used for the comparison.");
2192 ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2193 [InitBasicFS, Always, TestOutputList (
2194 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2195 ["strings"; "/new"]], ["hello"; "world"]);
2196 InitBasicFS, Always, TestOutputList (
2198 ["strings"; "/new"]], [])],
2199 "print the printable strings in a file",
2201 This runs the L<strings(1)> command on a file and returns
2202 the list of printable strings found.");
2204 ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2205 [InitBasicFS, Always, TestOutputList (
2206 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2207 ["strings_e"; "b"; "/new"]], []);
2208 InitBasicFS, Disabled, TestOutputList (
2209 [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2210 ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2211 "print the printable strings in a file",
2213 This is like the C<guestfs_strings> command, but allows you to
2214 specify the encoding.
2216 See the L<strings(1)> manpage for the full list of encodings.
2218 Commonly useful encodings are C<l> (lower case L) which will
2219 show strings inside Windows/x86 files.
2221 The returned strings are transcoded to UTF-8.");
2223 ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2224 [InitBasicFS, Always, TestOutput (
2225 [["write_file"; "/new"; "hello\nworld\n"; "12"];
2226 ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n");
2227 (* Test for RHBZ#501888c2 regression which caused large hexdump
2228 * commands to segfault.
2230 InitBasicFS, Always, TestRun (
2231 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2232 ["hexdump"; "/100krandom"]])],
2233 "dump a file in hexadecimal",
2235 This runs C<hexdump -C> on the given C<path>. The result is
2236 the human-readable, canonical hex dump of the file.");
2238 ("zerofree", (RErr, [String "device"]), 97, [],
2239 [InitNone, Always, TestOutput (
2240 [["sfdiskM"; "/dev/sda"; ","];
2241 ["mkfs"; "ext3"; "/dev/sda1"];
2242 ["mount"; "/dev/sda1"; "/"];
2243 ["write_file"; "/new"; "test file"; "0"];
2244 ["umount"; "/dev/sda1"];
2245 ["zerofree"; "/dev/sda1"];
2246 ["mount"; "/dev/sda1"; "/"];
2247 ["cat"; "/new"]], "test file")],
2248 "zero unused inodes and disk blocks on ext2/3 filesystem",
2250 This runs the I<zerofree> program on C<device>. This program
2251 claims to zero unused inodes and disk blocks on an ext2/3
2252 filesystem, thus making it possible to compress the filesystem
2255 You should B<not> run this program if the filesystem is
2258 It is possible that using this program can damage the filesystem
2259 or data on the filesystem.");
2261 ("pvresize", (RErr, [String "device"]), 98, [],
2263 "resize an LVM physical volume",
2265 This resizes (expands or shrinks) an existing LVM physical
2266 volume to match the new size of the underlying device.");
2268 ("sfdisk_N", (RErr, [String "device"; Int "partnum";
2269 Int "cyls"; Int "heads"; Int "sectors";
2270 String "line"]), 99, [DangerWillRobinson],
2272 "modify a single partition on a block device",
2274 This runs L<sfdisk(8)> option to modify just the single
2275 partition C<n> (note: C<n> counts from 1).
2277 For other parameters, see C<guestfs_sfdisk>. You should usually
2278 pass C<0> for the cyls/heads/sectors parameters.");
2280 ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2282 "display the partition table",
2284 This displays the partition table on C<device>, in the
2285 human-readable output of the L<sfdisk(8)> command. It is
2286 not intended to be parsed.");
2288 ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2290 "display the kernel geometry",
2292 This displays the kernel's idea of the geometry of C<device>.
2294 The result is in human-readable format, and not designed to
2297 ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2299 "display the disk geometry from the partition table",
2301 This displays the disk geometry of C<device> read from the
2302 partition table. Especially in the case where the underlying
2303 block device has been resized, this can be different from the
2304 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2306 The result is in human-readable format, and not designed to
2309 ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2311 "activate or deactivate all volume groups",
2313 This command activates or (if C<activate> is false) deactivates
2314 all logical volumes in all volume groups.
2315 If activated, then they are made known to the
2316 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2317 then those devices disappear.
2319 This command is the same as running C<vgchange -a y|n>");
2321 ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2323 "activate or deactivate some volume groups",
2325 This command activates or (if C<activate> is false) deactivates
2326 all logical volumes in the listed volume groups C<volgroups>.
2327 If activated, then they are made known to the
2328 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2329 then those devices disappear.
2331 This command is the same as running C<vgchange -a y|n volgroups...>
2333 Note that if C<volgroups> is an empty list then B<all> volume groups
2334 are activated or deactivated.");
2336 ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2337 [InitNone, Always, TestOutput (
2338 [["sfdiskM"; "/dev/sda"; ","];
2339 ["pvcreate"; "/dev/sda1"];
2340 ["vgcreate"; "VG"; "/dev/sda1"];
2341 ["lvcreate"; "LV"; "VG"; "10"];
2342 ["mkfs"; "ext2"; "/dev/VG/LV"];
2343 ["mount"; "/dev/VG/LV"; "/"];
2344 ["write_file"; "/new"; "test content"; "0"];
2346 ["lvresize"; "/dev/VG/LV"; "20"];
2347 ["e2fsck_f"; "/dev/VG/LV"];
2348 ["resize2fs"; "/dev/VG/LV"];
2349 ["mount"; "/dev/VG/LV"; "/"];
2350 ["cat"; "/new"]], "test content")],
2351 "resize an LVM logical volume",
2353 This resizes (expands or shrinks) an existing LVM logical
2354 volume to C<mbytes>. When reducing, data in the reduced part
2357 ("resize2fs", (RErr, [String "device"]), 106, [],
2358 [], (* lvresize tests this *)
2359 "resize an ext2/ext3 filesystem",
2361 This resizes an ext2 or ext3 filesystem to match the size of
2362 the underlying device.
2364 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2365 on the C<device> before calling this command. For unknown reasons
2366 C<resize2fs> sometimes gives an error about this and sometimes not.
2367 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2368 calling this function.");
2370 ("find", (RStringList "names", [String "directory"]), 107, [],
2371 [InitBasicFS, Always, TestOutputList (
2372 [["find"; "/"]], ["lost+found"]);
2373 InitBasicFS, Always, TestOutputList (
2377 ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2378 InitBasicFS, Always, TestOutputList (
2379 [["mkdir_p"; "/a/b/c"];
2380 ["touch"; "/a/b/c/d"];
2381 ["find"; "/a/b/"]], ["c"; "c/d"])],
2382 "find all files and directories",
2384 This command lists out all files and directories, recursively,
2385 starting at C<directory>. It is essentially equivalent to
2386 running the shell command C<find directory -print> but some
2387 post-processing happens on the output, described below.
2389 This returns a list of strings I<without any prefix>. Thus
2390 if the directory structure was:
2396 then the returned list from C<guestfs_find> C</tmp> would be
2404 If C<directory> is not a directory, then this command returns
2407 The returned list is sorted.");
2409 ("e2fsck_f", (RErr, [String "device"]), 108, [],
2410 [], (* lvresize tests this *)
2411 "check an ext2/ext3 filesystem",
2413 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2414 filesystem checker on C<device>, noninteractively (C<-p>),
2415 even if the filesystem appears to be clean (C<-f>).
2417 This command is only needed because of C<guestfs_resize2fs>
2418 (q.v.). Normally you should use C<guestfs_fsck>.");
2420 ("sleep", (RErr, [Int "secs"]), 109, [],
2421 [InitNone, Always, TestRun (
2423 "sleep for some seconds",
2425 Sleep for C<secs> seconds.");
2427 ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [],
2428 [InitNone, Always, TestOutputInt (
2429 [["sfdiskM"; "/dev/sda"; ","];
2430 ["mkfs"; "ntfs"; "/dev/sda1"];
2431 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2432 InitNone, Always, TestOutputInt (
2433 [["sfdiskM"; "/dev/sda"; ","];
2434 ["mkfs"; "ext2"; "/dev/sda1"];
2435 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2436 "probe NTFS volume",
2438 This command runs the L<ntfs-3g.probe(8)> command which probes
2439 an NTFS C<device> for mountability. (Not all NTFS volumes can
2440 be mounted read-write, and some cannot be mounted at all).
2442 C<rw> is a boolean flag. Set it to true if you want to test
2443 if the volume can be mounted read-write. Set it to false if
2444 you want to test if the volume can be mounted read-only.
2446 The return value is an integer which C<0> if the operation
2447 would succeed, or some non-zero value documented in the
2448 L<ntfs-3g.probe(8)> manual page.");
2450 ("sh", (RString "output", [String "command"]), 111, [],
2451 [], (* XXX needs tests *)
2452 "run a command via the shell",
2454 This call runs a command from the guest filesystem via the
2457 This is like C<guestfs_command>, but passes the command to:
2459 /bin/sh -c \"command\"
2461 Depending on the guest's shell, this usually results in
2462 wildcards being expanded, shell expressions being interpolated
2465 All the provisos about C<guestfs_command> apply to this call.");
2467 ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2468 [], (* XXX needs tests *)
2469 "run a command via the shell returning lines",
2471 This is the same as C<guestfs_sh>, but splits the result
2472 into a list of lines.
2474 See also: C<guestfs_command_lines>");
2476 ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [],
2477 [InitBasicFS, Always, TestOutputList (
2478 [["mkdir_p"; "/a/b/c"];
2479 ["touch"; "/a/b/c/d"];
2480 ["touch"; "/a/b/c/e"];
2481 ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2482 InitBasicFS, Always, TestOutputList (
2483 [["mkdir_p"; "/a/b/c"];
2484 ["touch"; "/a/b/c/d"];
2485 ["touch"; "/a/b/c/e"];
2486 ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2487 InitBasicFS, Always, TestOutputList (
2488 [["mkdir_p"; "/a/b/c"];
2489 ["touch"; "/a/b/c/d"];
2490 ["touch"; "/a/b/c/e"];
2491 ["glob_expand"; "/a/*/x/*"]], [])],
2492 "expand a wildcard path",
2494 This command searches for all the pathnames matching
2495 C<pattern> according to the wildcard expansion rules
2498 If no paths match, then this returns an empty list
2499 (note: not an error).
2501 It is just a wrapper around the C L<glob(3)> function
2502 with flags C<GLOB_MARK|GLOB_BRACE>.
2503 See that manual page for more details.");
2505 ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson],
2506 [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2507 [["scrub_device"; "/dev/sdc"]])],
2508 "scrub (securely wipe) a device",
2510 This command writes patterns over C<device> to make data retrieval
2513 It is an interface to the L<scrub(1)> program. See that
2514 manual page for more details.");
2516 ("scrub_file", (RErr, [String "file"]), 115, [],
2517 [InitBasicFS, Always, TestRun (
2518 [["write_file"; "/file"; "content"; "0"];
2519 ["scrub_file"; "/file"]])],
2520 "scrub (securely wipe) a file",
2522 This command writes patterns over a file to make data retrieval
2525 The file is I<removed> after scrubbing.
2527 It is an interface to the L<scrub(1)> program. See that
2528 manual page for more details.");
2530 ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2531 [], (* XXX needs testing *)
2532 "scrub (securely wipe) free space",
2534 This command creates the directory C<dir> and then fills it
2535 with files until the filesystem is full, and scrubs the files
2536 as for C<guestfs_scrub_file>, and deletes them.
2537 The intention is to scrub any free space on the partition
2540 It is an interface to the L<scrub(1)> program. See that
2541 manual page for more details.");
2543 ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2544 [InitBasicFS, Always, TestRun (
2546 ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2547 "create a temporary directory",
2549 This command creates a temporary directory. The
2550 C<template> parameter should be a full pathname for the
2551 temporary directory name with the final six characters being
2554 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2555 the second one being suitable for Windows filesystems.
2557 The name of the temporary directory that was created
2560 The temporary directory is created with mode 0700
2561 and is owned by root.
2563 The caller is responsible for deleting the temporary
2564 directory and its contents after use.
2566 See also: L<mkdtemp(3)>");
2568 ("wc_l", (RInt "lines", [String "path"]), 118, [],
2569 [InitBasicFS, Always, TestOutputInt (
2570 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2571 ["wc_l"; "/10klines"]], 10000)],
2572 "count lines in a file",
2574 This command counts the lines in a file, using the
2575 C<wc -l> external command.");
2577 ("wc_w", (RInt "words", [String "path"]), 119, [],
2578 [InitBasicFS, Always, TestOutputInt (
2579 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2580 ["wc_w"; "/10klines"]], 10000)],
2581 "count words in a file",
2583 This command counts the words in a file, using the
2584 C<wc -w> external command.");
2586 ("wc_c", (RInt "chars", [String "path"]), 120, [],
2587 [InitBasicFS, Always, TestOutputInt (
2588 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2589 ["wc_c"; "/100kallspaces"]], 102400)],
2590 "count characters in a file",
2592 This command counts the characters in a file, using the
2593 C<wc -c> external command.");
2595 ("head", (RStringList "lines", [String "path"]), 121, [ProtocolLimitWarning],
2596 [InitBasicFS, Always, TestOutputList (
2597 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2598 ["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2599 "return first 10 lines of a file",
2601 This command returns up to the first 10 lines of a file as
2602 a list of strings.");
2604 ("head_n", (RStringList "lines", [Int "nrlines"; String "path"]), 122, [ProtocolLimitWarning],
2605 [InitBasicFS, Always, TestOutputList (
2606 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2607 ["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2608 InitBasicFS, Always, TestOutputList (
2609 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2610 ["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2611 InitBasicFS, Always, TestOutputList (
2612 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2613 ["head_n"; "0"; "/10klines"]], [])],
2614 "return first N lines of a file",
2616 If the parameter C<nrlines> is a positive number, this returns the first
2617 C<nrlines> lines of the file C<path>.
2619 If the parameter C<nrlines> is a negative number, this returns lines
2620 from the file C<path>, excluding the last C<nrlines> lines.
2622 If the parameter C<nrlines> is zero, this returns an empty list.");
2624 ("tail", (RStringList "lines", [String "path"]), 123, [ProtocolLimitWarning],
2625 [InitBasicFS, Always, TestOutputList (
2626 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2627 ["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2628 "return last 10 lines of a file",
2630 This command returns up to the last 10 lines of a file as
2631 a list of strings.");
2633 ("tail_n", (RStringList "lines", [Int "nrlines"; String "path"]), 124, [ProtocolLimitWarning],
2634 [InitBasicFS, Always, TestOutputList (
2635 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2636 ["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2637 InitBasicFS, Always, TestOutputList (
2638 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2639 ["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2640 InitBasicFS, Always, TestOutputList (
2641 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2642 ["tail_n"; "0"; "/10klines"]], [])],
2643 "return last N lines of a file",
2645 If the parameter C<nrlines> is a positive number, this returns the last
2646 C<nrlines> lines of the file C<path>.
2648 If the parameter C<nrlines> is a negative number, this returns lines
2649 from the file C<path>, starting with the C<-nrlines>th line.
2651 If the parameter C<nrlines> is zero, this returns an empty list.");
2653 ("df", (RString "output", []), 125, [],
2654 [], (* XXX Tricky to test because it depends on the exact format
2655 * of the 'df' command and other imponderables.
2657 "report file system disk space usage",
2659 This command runs the C<df> command to report disk space used.
2661 This command is mostly useful for interactive sessions. It
2662 is I<not> intended that you try to parse the output string.
2663 Use C<statvfs> from programs.");
2665 ("df_h", (RString "output", []), 126, [],
2666 [], (* XXX Tricky to test because it depends on the exact format
2667 * of the 'df' command and other imponderables.
2669 "report file system disk space usage (human readable)",
2671 This command runs the C<df -h> command to report disk space used
2672 in human-readable format.
2674 This command is mostly useful for interactive sessions. It
2675 is I<not> intended that you try to parse the output string.
2676 Use C<statvfs> from programs.");
2678 ("du", (RInt64 "sizekb", [String "path"]), 127, [],
2679 [InitBasicFS, Always, TestOutputInt (
2681 ["du"; "/p"]], 1 (* ie. 1 block, so depends on ext3 blocksize *))],
2682 "estimate file space usage",
2684 This command runs the C<du -s> command to estimate file space
2687 C<path> can be a file or a directory. If C<path> is a directory
2688 then the estimate includes the contents of the directory and all
2689 subdirectories (recursively).
2691 The result is the estimated size in I<kilobytes>
2692 (ie. units of 1024 bytes).");
2694 ("initrd_list", (RStringList "filenames", [String "path"]), 128, [],
2695 [InitBasicFS, Always, TestOutputList (
2696 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2697 ["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3"])],
2698 "list files in an initrd",
2700 This command lists out files contained in an initrd.
2702 The files are listed without any initial C</> character. The
2703 files are listed in the order they appear (not necessarily
2704 alphabetical). Directory names are listed as separate items.
2706 Old Linux kernels (2.4 and earlier) used a compressed ext2
2707 filesystem as initrd. We I<only> support the newer initramfs
2708 format (compressed cpio files).");
2710 ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
2712 "mount a file using the loop device",
2714 This command lets you mount C<file> (a filesystem image
2715 in a file) on a mount point. It is entirely equivalent to
2716 the command C<mount -o loop file mountpoint>.");
2718 ("mkswap", (RErr, [String "device"]), 130, [],
2719 [InitEmpty, Always, TestRun (
2720 [["sfdiskM"; "/dev/sda"; ","];
2721 ["mkswap"; "/dev/sda1"]])],
2722 "create a swap partition",
2724 Create a swap partition on C<device>.");
2726 ("mkswap_L", (RErr, [String "label"; String "device"]), 131, [],
2727 [InitEmpty, Always, TestRun (
2728 [["sfdiskM"; "/dev/sda"; ","];
2729 ["mkswap_L"; "hello"; "/dev/sda1"]])],
2730 "create a swap partition with a label",
2732 Create a swap partition on C<device> with label C<label>.");
2734 ("mkswap_U", (RErr, [String "uuid"; String "device"]), 132, [],
2735 [InitEmpty, Always, TestRun (
2736 [["sfdiskM"; "/dev/sda"; ","];
2737 ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
2738 "create a swap partition with an explicit UUID",
2740 Create a swap partition on C<device> with UUID C<uuid>.");
2742 ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 133, [],
2743 [InitBasicFS, Always, TestOutputStruct (
2744 [["mknod"; "0o10777"; "0"; "0"; "/node"];
2745 (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2746 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2747 InitBasicFS, Always, TestOutputStruct (
2748 [["mknod"; "0o60777"; "66"; "99"; "/node"];
2749 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2750 "make block, character or FIFO devices",
2752 This call creates block or character special devices, or
2753 named pipes (FIFOs).
2755 The C<mode> parameter should be the mode, using the standard
2756 constants. C<devmajor> and C<devminor> are the
2757 device major and minor numbers, only used when creating block
2758 and character special devices.");
2760 ("mkfifo", (RErr, [Int "mode"; String "path"]), 134, [],
2761 [InitBasicFS, Always, TestOutputStruct (
2762 [["mkfifo"; "0o777"; "/node"];
2763 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2764 "make FIFO (named pipe)",
2766 This call creates a FIFO (named pipe) called C<path> with
2767 mode C<mode>. It is just a convenient wrapper around
2768 C<guestfs_mknod>.");
2770 ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 135, [],
2771 [InitBasicFS, Always, TestOutputStruct (
2772 [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2773 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2774 "make block device node",
2776 This call creates a block device node called C<path> with
2777 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2778 It is just a convenient wrapper around C<guestfs_mknod>.");
2780 ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 136, [],
2781 [InitBasicFS, Always, TestOutputStruct (
2782 [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2783 ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2784 "make char device node",
2786 This call creates a char device node called C<path> with
2787 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2788 It is just a convenient wrapper around C<guestfs_mknod>.");
2790 ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2791 [], (* XXX umask is one of those stateful things that we should
2792 * reset between each test.
2794 "set file mode creation mask (umask)",
2796 This function sets the mask used for creating new files and
2797 device nodes to C<mask & 0777>.
2799 Typical umask values would be C<022> which creates new files
2800 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2801 C<002> which creates new files with permissions like
2802 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2804 The default umask is C<022>. This is important because it
2805 means that directories and device nodes will be created with
2806 C<0644> or C<0755> mode even if you specify C<0777>.
2808 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2810 This call returns the previous umask.");
2812 ("readdir", (RStructList ("entries", "dirent"), [String "dir"]), 138, [],
2814 "read directories entries",
2816 This returns the list of directory entries in directory C<dir>.
2818 All entries in the directory are returned, including C<.> and
2819 C<..>. The entries are I<not> sorted, but returned in the same
2820 order as the underlying filesystem.
2822 This function is primarily intended for use by programs. To
2823 get a simple list of names, use C<guestfs_ls>. To get a printable
2824 directory for human consumption, use C<guestfs_ll>.");
2826 ("sfdiskM", (RErr, [String "device"; StringList "lines"]), 139, [DangerWillRobinson],
2828 "create partitions on a block device",
2830 This is a simplified interface to the C<guestfs_sfdisk>
2831 command, where partition sizes are specified in megabytes
2832 only (rounded to the nearest cylinder) and you don't need
2833 to specify the cyls, heads and sectors parameters which
2834 were rarely if ever used anyway.
2836 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
2840 let all_functions = non_daemon_functions @ daemon_functions
2842 (* In some places we want the functions to be displayed sorted
2843 * alphabetically, so this is useful:
2845 let all_functions_sorted =
2846 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2847 compare n1 n2) all_functions
2849 (* Field types for structures. *)
2851 | FChar (* C 'char' (really, a 7 bit byte). *)
2852 | FString (* nul-terminated ASCII string. *)
2857 | FBytes (* Any int measure that counts bytes. *)
2858 | FUUID (* 32 bytes long, NOT nul-terminated. *)
2859 | FOptPercent (* [0..100], or -1 meaning "not present". *)
2861 (* Because we generate extra parsing code for LVM command line tools,
2862 * we have to pull out the LVM columns separately here.
2872 "pv_attr", FString (* XXX *);
2873 "pv_pe_count", FInt64;
2874 "pv_pe_alloc_count", FInt64;
2877 "pv_mda_count", FInt64;
2878 "pv_mda_free", FBytes;
2879 (* Not in Fedora 10:
2880 "pv_mda_size", FBytes;
2887 "vg_attr", FString (* XXX *);
2890 "vg_sysid", FString;
2891 "vg_extent_size", FBytes;
2892 "vg_extent_count", FInt64;
2893 "vg_free_count", FInt64;
2898 "snap_count", FInt64;
2901 "vg_mda_count", FInt64;
2902 "vg_mda_free", FBytes;
2903 (* Not in Fedora 10:
2904 "vg_mda_size", FBytes;
2910 "lv_attr", FString (* XXX *);
2913 "lv_kernel_major", FInt64;
2914 "lv_kernel_minor", FInt64;
2916 "seg_count", FInt64;
2918 "snap_percent", FOptPercent;
2919 "copy_percent", FOptPercent;
2922 "mirror_log", FString;
2926 (* Names and fields in all structures (in RStruct and RStructList)
2930 (* The old RIntBool return type, only ever used for aug_defnode. Do
2931 * not use this struct in any new code.
2934 "i", FInt32; (* for historical compatibility *)
2935 "b", FInt32; (* for historical compatibility *)
2938 (* LVM PVs, VGs, LVs. *)
2939 "lvm_pv", lvm_pv_cols;
2940 "lvm_vg", lvm_vg_cols;
2941 "lvm_lv", lvm_lv_cols;
2943 (* Column names and types from stat structures.
2944 * NB. Can't use things like 'st_atime' because glibc header files
2945 * define some of these as macros. Ugh.
2976 (* Column names in dirent structure. *)
2979 (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
2984 (* Version numbers. *)
2991 ] (* end of structs *)
2993 (* Ugh, Java has to be different ..
2994 * These names are also used by the Haskell bindings.
2996 let java_structs = [
2997 "int_bool", "IntBool";
3002 "statvfs", "StatVFS";
3004 "version", "Version";
3007 (* Used for testing language bindings. *)
3009 | CallString of string
3010 | CallOptString of string option
3011 | CallStringList of string list
3015 (* Used to memoize the result of pod2text. *)
3016 let pod2text_memo_filename = "src/.pod2text.data"
3017 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
3019 let chan = open_in pod2text_memo_filename in
3020 let v = input_value chan in
3024 _ -> Hashtbl.create 13
3026 (* Useful functions.
3027 * Note we don't want to use any external OCaml libraries which
3028 * makes this a bit harder than it should be.
3030 let failwithf fs = ksprintf failwith fs
3032 let replace_char s c1 c2 =
3033 let s2 = String.copy s in
3034 let r = ref false in
3035 for i = 0 to String.length s2 - 1 do
3036 if String.unsafe_get s2 i = c1 then (
3037 String.unsafe_set s2 i c2;
3041 if not !r then s else s2
3045 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
3047 let triml ?(test = isspace) str =
3049 let n = ref (String.length str) in
3050 while !n > 0 && test str.[!i]; do
3055 else String.sub str !i !n
3057 let trimr ?(test = isspace) str =
3058 let n = ref (String.length str) in
3059 while !n > 0 && test str.[!n-1]; do
3062 if !n = String.length str then str
3063 else String.sub str 0 !n
3065 let trim ?(test = isspace) str =
3066 trimr ~test (triml ~test str)
3068 let rec find s sub =
3069 let len = String.length s in
3070 let sublen = String.length sub in
3072 if i <= len-sublen then (
3074 if j < sublen then (
3075 if s.[i+j] = sub.[j] then loop2 (j+1)
3081 if r = -1 then loop (i+1) else r
3087 let rec replace_str s s1 s2 =
3088 let len = String.length s in
3089 let sublen = String.length s1 in
3090 let i = find s s1 in
3093 let s' = String.sub s 0 i in
3094 let s'' = String.sub s (i+sublen) (len-i-sublen) in
3095 s' ^ s2 ^ replace_str s'' s1 s2
3098 let rec string_split sep str =
3099 let len = String.length str in
3100 let seplen = String.length sep in
3101 let i = find str sep in
3102 if i = -1 then [str]
3104 let s' = String.sub str 0 i in
3105 let s'' = String.sub str (i+seplen) (len-i-seplen) in
3106 s' :: string_split sep s''
3109 let files_equal n1 n2 =
3110 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
3111 match Sys.command cmd with
3114 | i -> failwithf "%s: failed with error code %d" cmd i
3116 let rec find_map f = function
3117 | [] -> raise Not_found
3121 | None -> find_map f xs
3124 let rec loop i = function
3126 | x :: xs -> f i x; loop (i+1) xs
3131 let rec loop i = function
3133 | x :: xs -> let r = f i x in r :: loop (i+1) xs
3137 let name_of_argt = function
3138 | String n | OptString n | StringList n | Bool n | Int n
3139 | FileIn n | FileOut n -> n
3141 let java_name_of_struct typ =
3142 try List.assoc typ java_structs
3145 "java_name_of_struct: no java_structs entry corresponding to %s" typ
3147 let cols_of_struct typ =
3148 try List.assoc typ structs
3150 failwithf "cols_of_struct: unknown struct %s" typ
3152 let seq_of_test = function
3153 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
3154 | TestOutputListOfDevices (s, _)
3155 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
3156 | TestOutputLength (s, _) | TestOutputStruct (s, _)
3157 | TestLastFail s -> s
3159 (* Check function names etc. for consistency. *)
3160 let check_functions () =
3161 let contains_uppercase str =
3162 let len = String.length str in
3164 if i >= len then false
3167 if c >= 'A' && c <= 'Z' then true
3174 (* Check function names. *)
3176 fun (name, _, _, _, _, _, _) ->
3177 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
3178 failwithf "function name %s does not need 'guestfs' prefix" name;
3180 failwithf "function name is empty";
3181 if name.[0] < 'a' || name.[0] > 'z' then
3182 failwithf "function name %s must start with lowercase a-z" name;
3183 if String.contains name '-' then
3184 failwithf "function name %s should not contain '-', use '_' instead."
3188 (* Check function parameter/return names. *)
3190 fun (name, style, _, _, _, _, _) ->
3191 let check_arg_ret_name n =
3192 if contains_uppercase n then
3193 failwithf "%s param/ret %s should not contain uppercase chars"
3195 if String.contains n '-' || String.contains n '_' then
3196 failwithf "%s param/ret %s should not contain '-' or '_'"
3199 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;
3200 if n = "int" || n = "char" || n = "short" || n = "long" then
3201 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
3202 if n = "i" || n = "n" then
3203 failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
3204 if n = "argv" || n = "args" then
3205 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
3208 (match fst style with
3210 | RInt n | RInt64 n | RBool n | RConstString n | RString n
3211 | RStringList n | RStruct (n, _) | RStructList (n, _)
3213 check_arg_ret_name n
3215 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
3218 (* Check short descriptions. *)
3220 fun (name, _, _, _, _, shortdesc, _) ->
3221 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
3222 failwithf "short description of %s should begin with lowercase." name;
3223 let c = shortdesc.[String.length shortdesc-1] in
3224 if c = '\n' || c = '.' then
3225 failwithf "short description of %s should not end with . or \\n." name
3228 (* Check long dscriptions. *)
3230 fun (name, _, _, _, _, _, longdesc) ->
3231 if longdesc.[String.length longdesc-1] = '\n' then
3232 failwithf "long description of %s should not end with \\n." name
3235 (* Check proc_nrs. *)
3237 fun (name, _, proc_nr, _, _, _, _) ->
3238 if proc_nr <= 0 then
3239 failwithf "daemon function %s should have proc_nr > 0" name
3243 fun (name, _, proc_nr, _, _, _, _) ->
3244 if proc_nr <> -1 then
3245 failwithf "non-daemon function %s should have proc_nr -1" name
3246 ) non_daemon_functions;
3249 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
3252 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
3253 let rec loop = function
3256 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
3258 | (name1,nr1) :: (name2,nr2) :: _ ->
3259 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
3267 (* Ignore functions that have no tests. We generate a
3268 * warning when the user does 'make check' instead.
3270 | name, _, _, _, [], _, _ -> ()
3271 | name, _, _, _, tests, _, _ ->
3275 match seq_of_test test with
3277 failwithf "%s has a test containing an empty sequence" name
3278 | cmds -> List.map List.hd cmds
3280 let funcs = List.flatten funcs in
3282 let tested = List.mem name funcs in
3285 failwithf "function %s has tests but does not test itself" name
3288 (* 'pr' prints to the current output file. *)
3289 let chan = ref stdout
3290 let pr fs = ksprintf (output_string !chan) fs
3292 (* Generate a header block in a number of standard styles. *)
3293 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
3294 type license = GPLv2 | LGPLv2
3296 let generate_header comment license =
3297 let c = match comment with
3298 | CStyle -> pr "/* "; " *"
3299 | HashStyle -> pr "# "; "#"
3300 | OCamlStyle -> pr "(* "; " *"
3301 | HaskellStyle -> pr "{- "; " " in
3302 pr "libguestfs generated file\n";
3303 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
3304 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
3306 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
3310 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
3311 pr "%s it under the terms of the GNU General Public License as published by\n" c;
3312 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
3313 pr "%s (at your option) any later version.\n" c;
3315 pr "%s This program is distributed in the hope that it will be useful,\n" c;
3316 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3317 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
3318 pr "%s GNU General Public License for more details.\n" c;
3320 pr "%s You should have received a copy of the GNU General Public License along\n" c;
3321 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
3322 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
3325 pr "%s This library is free software; you can redistribute it and/or\n" c;
3326 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
3327 pr "%s License as published by the Free Software Foundation; either\n" c;
3328 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
3330 pr "%s This library is distributed in the hope that it will be useful,\n" c;
3331 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3332 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
3333 pr "%s Lesser General Public License for more details.\n" c;
3335 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
3336 pr "%s License along with this library; if not, write to the Free Software\n" c;
3337 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
3340 | CStyle -> pr " */\n"
3342 | OCamlStyle -> pr " *)\n"
3343 | HaskellStyle -> pr "-}\n"
3347 (* Start of main code generation functions below this line. *)
3349 (* Generate the pod documentation for the C API. *)
3350 let rec generate_actions_pod () =
3352 fun (shortname, style, _, flags, _, _, longdesc) ->
3353 if not (List.mem NotInDocs flags) then (
3354 let name = "guestfs_" ^ shortname in
3355 pr "=head2 %s\n\n" name;
3357 generate_prototype ~extern:false ~handle:"handle" name style;
3359 pr "%s\n\n" longdesc;
3360 (match fst style with
3362 pr "This function returns 0 on success or -1 on error.\n\n"
3364 pr "On error this function returns -1.\n\n"
3366 pr "On error this function returns -1.\n\n"
3368 pr "This function returns a C truth value on success or -1 on error.\n\n"
3370 pr "This function returns a string, or NULL on error.
3371 The string is owned by the guest handle and must I<not> be freed.\n\n"
3373 pr "This function returns a string, or NULL on error.
3374 I<The caller must free the returned string after use>.\n\n"
3376 pr "This function returns a NULL-terminated array of strings
3377 (like L<environ(3)>), or NULL if there was an error.
3378 I<The caller must free the strings and the array after use>.\n\n"
3379 | RStruct (_, typ) ->
3380 pr "This function returns a C<struct guestfs_%s *>,
3381 or NULL if there was an error.
3382 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
3383 | RStructList (_, typ) ->
3384 pr "This function returns a C<struct guestfs_%s_list *>
3385 (see E<lt>guestfs-structs.hE<gt>),
3386 or NULL if there was an error.
3387 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
3389 pr "This function returns a NULL-terminated array of
3390 strings, or NULL if there was an error.
3391 The array of strings will always have length C<2n+1>, where
3392 C<n> keys and values alternate, followed by the trailing NULL entry.
3393 I<The caller must free the strings and the array after use>.\n\n"
3395 if List.mem ProtocolLimitWarning flags then
3396 pr "%s\n\n" protocol_limit_warning;
3397 if List.mem DangerWillRobinson flags then
3398 pr "%s\n\n" danger_will_robinson
3400 ) all_functions_sorted
3402 and generate_structs_pod () =
3403 (* Structs documentation. *)
3406 pr "=head2 guestfs_%s\n" typ;
3408 pr " struct guestfs_%s {\n" typ;
3411 | name, FChar -> pr " char %s;\n" name
3412 | name, FUInt32 -> pr " uint32_t %s;\n" name
3413 | name, FInt32 -> pr " int32_t %s;\n" name
3414 | name, (FUInt64|FBytes) -> pr " uint64_t %s;\n" name
3415 | name, FInt64 -> pr " int64_t %s;\n" name
3416 | name, FString -> pr " char *%s;\n" name
3418 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
3419 pr " char %s[32];\n" name
3420 | name, FOptPercent ->
3421 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
3422 pr " float %s;\n" name
3426 pr " struct guestfs_%s_list {\n" typ;
3427 pr " uint32_t len; /* Number of elements in list. */\n";
3428 pr " struct guestfs_%s *val; /* Elements. */\n" typ;
3431 pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
3432 pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
3437 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3438 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3440 * We have to use an underscore instead of a dash because otherwise
3441 * rpcgen generates incorrect code.
3443 * This header is NOT exported to clients, but see also generate_structs_h.
3445 and generate_xdr () =
3446 generate_header CStyle LGPLv2;
3448 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3449 pr "typedef string str<>;\n";
3452 (* Internal structures. *)
3456 pr "struct guestfs_int_%s {\n" typ;
3458 | name, FChar -> pr " char %s;\n" name
3459 | name, FString -> pr " string %s<>;\n" name
3460 | name, FUUID -> pr " opaque %s[32];\n" name
3461 | name, (FInt32|FUInt32) -> pr " int %s;\n" name
3462 | name, (FInt64|FUInt64|FBytes) -> pr " hyper %s;\n" name
3463 | name, FOptPercent -> pr " float %s;\n" name
3467 pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
3472 fun (shortname, style, _, _, _, _, _) ->
3473 let name = "guestfs_" ^ shortname in
3475 (match snd style with
3478 pr "struct %s_args {\n" name;
3481 | String n -> pr " string %s<>;\n" n
3482 | OptString n -> pr " str *%s;\n" n
3483 | StringList n -> pr " str %s<>;\n" n
3484 | Bool n -> pr " bool %s;\n" n
3485 | Int n -> pr " int %s;\n" n
3486 | FileIn _ | FileOut _ -> ()
3490 (match fst style with
3493 pr "struct %s_ret {\n" name;
3497 pr "struct %s_ret {\n" name;
3498 pr " hyper %s;\n" n;
3501 pr "struct %s_ret {\n" name;
3505 failwithf "RConstString cannot be returned from a daemon function"
3507 pr "struct %s_ret {\n" name;
3508 pr " string %s<>;\n" n;
3511 pr "struct %s_ret {\n" name;
3512 pr " str %s<>;\n" n;
3514 | RStruct (n, typ) ->
3515 pr "struct %s_ret {\n" name;
3516 pr " guestfs_int_%s %s;\n" typ n;
3518 | RStructList (n, typ) ->
3519 pr "struct %s_ret {\n" name;
3520 pr " guestfs_int_%s_list %s;\n" typ n;
3523 pr "struct %s_ret {\n" name;
3524 pr " str %s<>;\n" n;
3529 (* Table of procedure numbers. *)
3530 pr "enum guestfs_procedure {\n";
3532 fun (shortname, _, proc_nr, _, _, _, _) ->
3533 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3535 pr " GUESTFS_PROC_NR_PROCS\n";
3539 (* Having to choose a maximum message size is annoying for several
3540 * reasons (it limits what we can do in the API), but it (a) makes
3541 * the protocol a lot simpler, and (b) provides a bound on the size
3542 * of the daemon which operates in limited memory space. For large
3543 * file transfers you should use FTP.
3545 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3548 (* Message header, etc. *)
3550 /* The communication protocol is now documented in the guestfs(3)
3554 const GUESTFS_PROGRAM = 0x2000F5F5;
3555 const GUESTFS_PROTOCOL_VERSION = 1;
3557 /* These constants must be larger than any possible message length. */
3558 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3559 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3561 enum guestfs_message_direction {
3562 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
3563 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
3566 enum guestfs_message_status {
3567 GUESTFS_STATUS_OK = 0,
3568 GUESTFS_STATUS_ERROR = 1
3571 const GUESTFS_ERROR_LEN = 256;
3573 struct guestfs_message_error {
3574 string error_message<GUESTFS_ERROR_LEN>;
3577 struct guestfs_message_header {
3578 unsigned prog; /* GUESTFS_PROGRAM */
3579 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
3580 guestfs_procedure proc; /* GUESTFS_PROC_x */
3581 guestfs_message_direction direction;
3582 unsigned serial; /* message serial number */
3583 guestfs_message_status status;
3586 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3588 struct guestfs_chunk {
3589 int cancel; /* if non-zero, transfer is cancelled */
3590 /* data size is 0 bytes if the transfer has finished successfully */
3591 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3595 (* Generate the guestfs-structs.h file. *)
3596 and generate_structs_h () =
3597 generate_header CStyle LGPLv2;
3599 (* This is a public exported header file containing various
3600 * structures. The structures are carefully written to have
3601 * exactly the same in-memory format as the XDR structures that
3602 * we use on the wire to the daemon. The reason for creating
3603 * copies of these structures here is just so we don't have to
3604 * export the whole of guestfs_protocol.h (which includes much
3605 * unrelated and XDR-dependent stuff that we don't want to be
3606 * public, or required by clients).
3608 * To reiterate, we will pass these structures to and from the
3609 * client with a simple assignment or memcpy, so the format
3610 * must be identical to what rpcgen / the RFC defines.
3613 (* Public structures. *)
3616 pr "struct guestfs_%s {\n" typ;
3619 | name, FChar -> pr " char %s;\n" name
3620 | name, FString -> pr " char *%s;\n" name
3621 | name, FUUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3622 | name, FUInt32 -> pr " uint32_t %s;\n" name
3623 | name, FInt32 -> pr " int32_t %s;\n" name
3624 | name, (FUInt64|FBytes) -> pr " uint64_t %s;\n" name
3625 | name, FInt64 -> pr " int64_t %s;\n" name
3626 | name, FOptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
3630 pr "struct guestfs_%s_list {\n" typ;
3631 pr " uint32_t len;\n";
3632 pr " struct guestfs_%s *val;\n" typ;
3635 pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
3636 pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
3640 (* Generate the guestfs-actions.h file. *)
3641 and generate_actions_h () =
3642 generate_header CStyle LGPLv2;
3644 fun (shortname, style, _, _, _, _, _) ->
3645 let name = "guestfs_" ^ shortname in
3646 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3650 (* Generate the client-side dispatch stubs. *)
3651 and generate_client_actions () =
3652 generate_header CStyle LGPLv2;
3658 #include \"guestfs.h\"
3659 #include \"guestfs_protocol.h\"
3661 #define error guestfs_error
3662 #define perrorf guestfs_perrorf
3663 #define safe_malloc guestfs_safe_malloc
3664 #define safe_realloc guestfs_safe_realloc
3665 #define safe_strdup guestfs_safe_strdup
3666 #define safe_memdup guestfs_safe_memdup
3668 /* Check the return message from a call for validity. */
3670 check_reply_header (guestfs_h *g,
3671 const struct guestfs_message_header *hdr,
3672 int proc_nr, int serial)
3674 if (hdr->prog != GUESTFS_PROGRAM) {
3675 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3678 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3679 error (g, \"wrong protocol version (%%d/%%d)\",
3680 hdr->vers, GUESTFS_PROTOCOL_VERSION);
3683 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3684 error (g, \"unexpected message direction (%%d/%%d)\",
3685 hdr->direction, GUESTFS_DIRECTION_REPLY);
3688 if (hdr->proc != proc_nr) {
3689 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3692 if (hdr->serial != serial) {
3693 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3700 /* Check we are in the right state to run a high-level action. */
3702 check_state (guestfs_h *g, const char *caller)
3704 if (!guestfs_is_ready (g)) {
3705 if (guestfs_is_config (g))
3706 error (g, \"%%s: call launch() before using this function\",
3708 else if (guestfs_is_launching (g))
3709 error (g, \"%%s: call wait_ready() before using this function\",
3712 error (g, \"%%s called from the wrong state, %%d != READY\",
3713 caller, guestfs_get_state (g));
3721 (* Client-side stubs for each function. *)
3723 fun (shortname, style, _, _, _, _, _) ->
3724 let name = "guestfs_" ^ shortname in
3726 (* Generate the context struct which stores the high-level
3727 * state between callback functions.
3729 pr "struct %s_ctx {\n" shortname;
3730 pr " /* This flag is set by the callbacks, so we know we've done\n";
3731 pr " * the callbacks as expected, and in the right sequence.\n";
3732 pr " * 0 = not called, 1 = reply_cb called.\n";
3734 pr " int cb_sequence;\n";
3735 pr " struct guestfs_message_header hdr;\n";
3736 pr " struct guestfs_message_error err;\n";
3737 (match fst style with
3740 failwithf "RConstString cannot be returned from a daemon function"
3742 | RBool _ | RString _ | RStringList _
3743 | RStruct _ | RStructList _
3745 pr " struct %s_ret ret;\n" name
3750 (* Generate the reply callback function. *)
3751 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3753 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3754 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3756 pr " /* This should definitely not happen. */\n";
3757 pr " if (ctx->cb_sequence != 0) {\n";
3758 pr " ctx->cb_sequence = 9999;\n";
3759 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3763 pr " ml->main_loop_quit (ml, g);\n";
3765 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3766 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3769 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3770 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3771 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3778 (match fst style with
3781 failwithf "RConstString cannot be returned from a daemon function"
3783 | RBool _ | RString _ | RStringList _
3784 | RStruct _ | RStructList _
3786 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3787 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3793 pr " ctx->cb_sequence = 1;\n";
3796 (* Generate the action stub. *)
3797 generate_prototype ~extern:false ~semicolon:false ~newline:true
3798 ~handle:"g" name style;
3801 match fst style with
3802 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3804 failwithf "RConstString cannot be returned from a daemon function"
3805 | RString _ | RStringList _
3806 | RStruct _ | RStructList _
3812 (match snd style with
3814 | _ -> pr " struct %s_args args;\n" name
3817 pr " struct %s_ctx ctx;\n" shortname;
3818 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3819 pr " int serial;\n";
3821 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3822 pr " guestfs_set_busy (g);\n";
3824 pr " memset (&ctx, 0, sizeof ctx);\n";
3827 (* Send the main header and arguments. *)
3828 (match snd style with
3830 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3831 (String.uppercase shortname)
3836 pr " args.%s = (char *) %s;\n" n n
3838 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
3840 pr " args.%s.%s_val = (char **) %s;\n" n n n;
3841 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3843 pr " args.%s = %s;\n" n n
3845 pr " args.%s = %s;\n" n n
3846 | FileIn _ | FileOut _ -> ()
3848 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3849 (String.uppercase shortname);
3850 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3853 pr " if (serial == -1) {\n";
3854 pr " guestfs_end_busy (g);\n";
3855 pr " return %s;\n" error_code;
3859 (* Send any additional files (FileIn) requested. *)
3860 let need_read_reply_label = ref false in
3867 pr " r = guestfs__send_file_sync (g, %s);\n" n;
3868 pr " if (r == -1) {\n";
3869 pr " guestfs_end_busy (g);\n";
3870 pr " return %s;\n" error_code;
3872 pr " if (r == -2) /* daemon cancelled */\n";
3873 pr " goto read_reply;\n";
3874 need_read_reply_label := true;
3880 (* Wait for the reply from the remote end. *)
3881 if !need_read_reply_label then pr " read_reply:\n";
3882 pr " guestfs__switch_to_receiving (g);\n";
3883 pr " ctx.cb_sequence = 0;\n";
3884 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3885 pr " (void) ml->main_loop_run (ml, g);\n";
3886 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
3887 pr " if (ctx.cb_sequence != 1) {\n";
3888 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3889 pr " guestfs_end_busy (g);\n";
3890 pr " return %s;\n" error_code;
3894 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3895 (String.uppercase shortname);
3896 pr " guestfs_end_busy (g);\n";
3897 pr " return %s;\n" error_code;
3901 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3902 pr " error (g, \"%%s\", ctx.err.error_message);\n";
3903 pr " free (ctx.err.error_message);\n";
3904 pr " guestfs_end_busy (g);\n";
3905 pr " return %s;\n" error_code;
3909 (* Expecting to receive further files (FileOut)? *)
3913 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3914 pr " guestfs_end_busy (g);\n";
3915 pr " return %s;\n" error_code;
3921 pr " guestfs_end_busy (g);\n";
3923 (match fst style with
3924 | RErr -> pr " return 0;\n"
3925 | RInt n | RInt64 n | RBool n ->
3926 pr " return ctx.ret.%s;\n" n
3928 failwithf "RConstString cannot be returned from a daemon function"
3930 pr " return ctx.ret.%s; /* caller will free */\n" n
3931 | RStringList n | RHashtable n ->
3932 pr " /* caller will free this, but we need to add a NULL entry */\n";
3933 pr " ctx.ret.%s.%s_val =\n" n n;
3934 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3935 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3937 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3938 pr " return ctx.ret.%s.%s_val;\n" n n
3940 pr " /* caller will free this */\n";
3941 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3942 | RStructList (n, _) ->
3943 pr " /* caller will free this */\n";
3944 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3950 (* Functions to free structures. *)
3951 pr "/* Structure-freeing functions. These rely on the fact that the\n";
3952 pr " * structure format is identical to the XDR format. See note in\n";
3953 pr " * generator.ml.\n";
3960 pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
3962 pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
3968 pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
3970 pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
3977 (* Generate daemon/actions.h. *)
3978 and generate_daemon_actions_h () =
3979 generate_header CStyle GPLv2;
3981 pr "#include \"../src/guestfs_protocol.h\"\n";
3985 fun (name, style, _, _, _, _, _) ->
3987 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3991 (* Generate the server-side stubs. *)
3992 and generate_daemon_actions () =
3993 generate_header CStyle GPLv2;
3995 pr "#include <config.h>\n";
3997 pr "#include <stdio.h>\n";
3998 pr "#include <stdlib.h>\n";
3999 pr "#include <string.h>\n";
4000 pr "#include <inttypes.h>\n";
4001 pr "#include <ctype.h>\n";
4002 pr "#include <rpc/types.h>\n";
4003 pr "#include <rpc/xdr.h>\n";
4005 pr "#include \"daemon.h\"\n";
4006 pr "#include \"../src/guestfs_protocol.h\"\n";
4007 pr "#include \"actions.h\"\n";
4011 fun (name, style, _, _, _, _, _) ->
4012 (* Generate server-side stubs. *)
4013 pr "static void %s_stub (XDR *xdr_in)\n" name;
4016 match fst style with
4017 | RErr | RInt _ -> pr " int r;\n"; "-1"
4018 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4019 | RBool _ -> pr " int r;\n"; "-1"
4021 failwithf "RConstString cannot be returned from a daemon function"
4022 | RString _ -> pr " char *r;\n"; "NULL"
4023 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
4024 | RStruct (_, typ) -> pr " guestfs_int_%s *r;\n" typ; "NULL"
4025 | RStructList (_, typ) -> pr " guestfs_int_%s_list *r;\n" typ; "NULL" in
4027 (match snd style with
4030 pr " struct guestfs_%s_args args;\n" name;
4033 (* Note we allow the string to be writable, in order to
4034 * allow device name translation. This is safe because
4035 * we can modify the string (passed from RPC).
4038 | OptString n -> pr " char *%s;\n" n
4039 | StringList n -> pr " char **%s;\n" n
4040 | Bool n -> pr " int %s;\n" n
4041 | Int n -> pr " int %s;\n" n
4042 | FileIn _ | FileOut _ -> ()
4047 (match snd style with
4050 pr " memset (&args, 0, sizeof args);\n";
4052 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4053 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4058 | String n -> pr " %s = args.%s;\n" n n
4059 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
4061 pr " %s = realloc (args.%s.%s_val,\n" n n n;
4062 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4063 pr " if (%s == NULL) {\n" n;
4064 pr " reply_with_perror (\"realloc\");\n";
4067 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
4068 pr " args.%s.%s_val = %s;\n" n n n;
4069 | Bool n -> pr " %s = args.%s;\n" n n
4070 | Int n -> pr " %s = args.%s;\n" n n
4071 | FileIn _ | FileOut _ -> ()
4076 (* Don't want to call the impl with any FileIn or FileOut
4077 * parameters, since these go "outside" the RPC protocol.
4080 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
4082 pr " r = do_%s " name;
4083 generate_call_args argsnofile;
4086 pr " if (r == %s)\n" error_code;
4087 pr " /* do_%s has already called reply_with_error */\n" name;
4091 (* If there are any FileOut parameters, then the impl must
4092 * send its own reply.
4095 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
4097 pr " /* do_%s has already sent a reply */\n" name
4099 match fst style with
4100 | RErr -> pr " reply (NULL, NULL);\n"
4101 | RInt n | RInt64 n | RBool n ->
4102 pr " struct guestfs_%s_ret ret;\n" name;
4103 pr " ret.%s = r;\n" n;
4104 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4107 failwithf "RConstString cannot be returned from a daemon function"
4109 pr " struct guestfs_%s_ret ret;\n" name;
4110 pr " ret.%s = r;\n" n;
4111 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4114 | RStringList n | RHashtable n ->
4115 pr " struct guestfs_%s_ret ret;\n" name;
4116 pr " ret.%s.%s_len = count_strings (r);\n" n n;
4117 pr " ret.%s.%s_val = r;\n" n n;
4118 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4120 pr " free_strings (r);\n"
4122 pr " struct guestfs_%s_ret ret;\n" name;
4123 pr " ret.%s = *r;\n" n;
4124 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4126 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4128 | RStructList (n, _) ->
4129 pr " struct guestfs_%s_ret ret;\n" name;
4130 pr " ret.%s = *r;\n" n;
4131 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4133 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4137 (* Free the args. *)
4138 (match snd style with
4143 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4150 (* Dispatch function. *)
4151 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4153 pr " switch (proc_nr) {\n";
4156 fun (name, style, _, _, _, _, _) ->
4157 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
4158 pr " %s_stub (xdr_in);\n" name;
4163 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d, set LIBGUESTFS_PATH to point to the matching libguestfs appliance directory\", proc_nr);\n";
4168 (* LVM columns and tokenization functions. *)
4169 (* XXX This generates crap code. We should rethink how we
4175 pr "static const char *lvm_%s_cols = \"%s\";\n"
4176 typ (String.concat "," (List.map fst cols));
4179 pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
4181 pr " char *tok, *p, *next;\n";
4185 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4188 pr " if (!str) {\n";
4189 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4192 pr " if (!*str || isspace (*str)) {\n";
4193 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4198 fun (name, coltype) ->
4199 pr " if (!tok) {\n";
4200 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4203 pr " p = strchrnul (tok, ',');\n";
4204 pr " if (*p) next = p+1; else next = NULL;\n";
4205 pr " *p = '\\0';\n";
4208 pr " r->%s = strdup (tok);\n" name;
4209 pr " if (r->%s == NULL) {\n" name;
4210 pr " perror (\"strdup\");\n";
4214 pr " for (i = j = 0; i < 32; ++j) {\n";
4215 pr " if (tok[j] == '\\0') {\n";
4216 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4218 pr " } else if (tok[j] != '-')\n";
4219 pr " r->%s[i++] = tok[j];\n" name;
4222 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4223 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4227 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4228 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4232 pr " if (tok[0] == '\\0')\n";
4233 pr " r->%s = -1;\n" name;
4234 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4235 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4238 | FInt32 | FUInt32 | FUInt64 | FChar ->
4239 assert false (* can never be an LVM column *)
4241 pr " tok = next;\n";
4244 pr " if (tok != NULL) {\n";
4245 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4252 pr "guestfs_int_lvm_%s_list *\n" typ;
4253 pr "parse_command_line_%ss (void)\n" typ;
4255 pr " char *out, *err;\n";
4256 pr " char *p, *pend;\n";
4258 pr " guestfs_int_lvm_%s_list *ret;\n" typ;
4259 pr " void *newp;\n";
4261 pr " ret = malloc (sizeof *ret);\n";
4262 pr " if (!ret) {\n";
4263 pr " reply_with_perror (\"malloc\");\n";
4264 pr " return NULL;\n";
4267 pr " ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
4268 pr " ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
4270 pr " r = command (&out, &err,\n";
4271 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
4272 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4273 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4274 pr " if (r == -1) {\n";
4275 pr " reply_with_error (\"%%s\", err);\n";
4276 pr " free (out);\n";
4277 pr " free (err);\n";
4278 pr " free (ret);\n";
4279 pr " return NULL;\n";
4282 pr " free (err);\n";
4284 pr " /* Tokenize each line of the output. */\n";
4287 pr " while (p) {\n";
4288 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
4289 pr " if (pend) {\n";
4290 pr " *pend = '\\0';\n";
4294 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
4297 pr " if (!*p) { /* Empty line? Skip it. */\n";
4302 pr " /* Allocate some space to store this next entry. */\n";
4303 pr " newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
4304 pr " sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
4305 pr " if (newp == NULL) {\n";
4306 pr " reply_with_perror (\"realloc\");\n";
4307 pr " free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
4308 pr " free (ret);\n";
4309 pr " free (out);\n";
4310 pr " return NULL;\n";
4312 pr " ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
4314 pr " /* Tokenize the next entry. */\n";
4315 pr " r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
4316 pr " if (r == -1) {\n";
4317 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
4318 pr " free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
4319 pr " free (ret);\n";
4320 pr " free (out);\n";
4321 pr " return NULL;\n";
4328 pr " ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
4330 pr " free (out);\n";
4331 pr " return ret;\n";
4334 ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
4336 (* Generate a list of function names, for debugging in the daemon.. *)
4337 and generate_daemon_names () =
4338 generate_header CStyle GPLv2;
4340 pr "#include <config.h>\n";
4342 pr "#include \"daemon.h\"\n";
4345 pr "/* This array is indexed by proc_nr. See guestfs_protocol.x. */\n";
4346 pr "const char *function_names[] = {\n";
4348 fun (name, _, proc_nr, _, _, _, _) -> pr " [%d] = \"%s\",\n" proc_nr name
4352 (* Generate the tests. *)
4353 and generate_tests () =
4354 generate_header CStyle GPLv2;
4361 #include <sys/types.h>
4364 #include \"guestfs.h\"
4366 static guestfs_h *g;
4367 static int suppress_error = 0;
4369 static void print_error (guestfs_h *g, void *data, const char *msg)
4371 if (!suppress_error)
4372 fprintf (stderr, \"%%s\\n\", msg);
4375 static void print_strings (char * const * const argv)
4379 for (argc = 0; argv[argc] != NULL; ++argc)
4380 printf (\"\\t%%s\\n\", argv[argc]);
4384 static void print_table (char * const * const argv)
4388 for (i = 0; argv[i] != NULL; i += 2)
4389 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
4393 static void no_test_warnings (void)
4399 | name, _, _, _, [], _, _ ->
4400 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
4401 | name, _, _, _, tests, _, _ -> ()
4407 (* Generate the actual tests. Note that we generate the tests
4408 * in reverse order, deliberately, so that (in general) the
4409 * newest tests run first. This makes it quicker and easier to
4414 fun (name, _, _, _, tests, _, _) ->
4415 mapi (generate_one_test name) tests
4416 ) (List.rev all_functions) in
4417 let test_names = List.concat test_names in
4418 let nr_tests = List.length test_names in
4421 int main (int argc, char *argv[])
4425 const char *filename;
4427 int nr_tests, test_num = 0;
4429 setbuf (stdout, NULL);
4431 no_test_warnings ();
4433 g = guestfs_create ();
4435 printf (\"guestfs_create FAILED\\n\");
4439 guestfs_set_error_handler (g, print_error, NULL);
4441 guestfs_set_path (g, \"../appliance\");
4443 filename = \"test1.img\";
4444 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4449 if (lseek (fd, %d, SEEK_SET) == -1) {
4455 if (write (fd, &c, 1) == -1) {
4461 if (close (fd) == -1) {
4466 if (guestfs_add_drive (g, filename) == -1) {
4467 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4471 filename = \"test2.img\";
4472 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4477 if (lseek (fd, %d, SEEK_SET) == -1) {
4483 if (write (fd, &c, 1) == -1) {
4489 if (close (fd) == -1) {
4494 if (guestfs_add_drive (g, filename) == -1) {
4495 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4499 filename = \"test3.img\";
4500 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4505 if (lseek (fd, %d, SEEK_SET) == -1) {
4511 if (write (fd, &c, 1) == -1) {
4517 if (close (fd) == -1) {
4522 if (guestfs_add_drive (g, filename) == -1) {
4523 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4527 if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4528 printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4532 if (guestfs_launch (g) == -1) {
4533 printf (\"guestfs_launch FAILED\\n\");
4537 /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4540 if (guestfs_wait_ready (g) == -1) {
4541 printf (\"guestfs_wait_ready FAILED\\n\");
4545 /* Cancel previous alarm. */
4550 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4554 pr " test_num++;\n";
4555 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4556 pr " if (%s () == -1) {\n" test_name;
4557 pr " printf (\"%s FAILED\\n\");\n" test_name;
4563 pr " guestfs_close (g);\n";
4564 pr " unlink (\"test1.img\");\n";
4565 pr " unlink (\"test2.img\");\n";
4566 pr " unlink (\"test3.img\");\n";
4569 pr " if (failed > 0) {\n";
4570 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4578 and generate_one_test name i (init, prereq, test) =
4579 let test_name = sprintf "test_%s_%d" name i in
4582 static int %s_skip (void)
4586 str = getenv (\"TEST_ONLY\");
4588 return strstr (str, \"%s\") == NULL;
4589 str = getenv (\"SKIP_%s\");
4590 if (str && strcmp (str, \"1\") == 0) return 1;
4591 str = getenv (\"SKIP_TEST_%s\");
4592 if (str && strcmp (str, \"1\") == 0) return 1;
4596 " test_name name (String.uppercase test_name) (String.uppercase name);
4599 | Disabled | Always -> ()
4600 | If code | Unless code ->
4601 pr "static int %s_prereq (void)\n" test_name;
4609 static int %s (void)
4612 printf (\" %%s skipped (reason: environment variable set)\\n\", \"%s\");
4616 " test_name test_name test_name;
4620 pr " printf (\" %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4622 pr " if (! %s_prereq ()) {\n" test_name;
4623 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4627 generate_one_test_body name i test_name init test;
4629 pr " if (%s_prereq ()) {\n" test_name;
4630 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4634 generate_one_test_body name i test_name init test;
4636 generate_one_test_body name i test_name init test
4644 and generate_one_test_body name i test_name init test =
4646 | InitNone (* XXX at some point, InitNone and InitEmpty became
4647 * folded together as the same thing. Really we should
4648 * make InitNone do nothing at all, but the tests may
4649 * need to be checked to make sure this is OK.
4652 pr " /* InitNone|InitEmpty for %s */\n" test_name;
4653 List.iter (generate_test_command_call test_name)
4654 [["blockdev_setrw"; "/dev/sda"];
4658 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4659 List.iter (generate_test_command_call test_name)
4660 [["blockdev_setrw"; "/dev/sda"];
4663 ["sfdiskM"; "/dev/sda"; ","];
4664 ["mkfs"; "ext2"; "/dev/sda1"];
4665 ["mount"; "/dev/sda1"; "/"]]
4666 | InitBasicFSonLVM ->
4667 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4669 List.iter (generate_test_command_call test_name)
4670 [["blockdev_setrw"; "/dev/sda"];
4673 ["sfdiskM"; "/dev/sda"; ","];
4674 ["pvcreate"; "/dev/sda1"];
4675 ["vgcreate"; "VG"; "/dev/sda1"];
4676 ["lvcreate"; "LV"; "VG"; "8"];
4677 ["mkfs"; "ext2"; "/dev/VG/LV"];
4678 ["mount"; "/dev/VG/LV"; "/"]]
4681 let get_seq_last = function
4683 failwithf "%s: you cannot use [] (empty list) when expecting a command"
4686 let seq = List.rev seq in
4687 List.rev (List.tl seq), List.hd seq
4692 pr " /* TestRun for %s (%d) */\n" name i;
4693 List.iter (generate_test_command_call test_name) seq
4694 | TestOutput (seq, expected) ->
4695 pr " /* TestOutput for %s (%d) */\n" name i;
4696 pr " const char *expected = \"%s\";\n" (c_quote expected);
4697 let seq, last = get_seq_last seq in
4699 pr " if (strcmp (r, expected) != 0) {\n";
4700 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4704 List.iter (generate_test_command_call test_name) seq;
4705 generate_test_command_call ~test test_name last
4706 | TestOutputList (seq, expected) ->
4707 pr " /* TestOutputList for %s (%d) */\n" name i;
4708 let seq, last = get_seq_last seq in
4712 pr " if (!r[%d]) {\n" i;
4713 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4714 pr " print_strings (r);\n";
4718 pr " const char *expected = \"%s\";\n" (c_quote str);
4719 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4720 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4725 pr " if (r[%d] != NULL) {\n" (List.length expected);
4726 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4728 pr " print_strings (r);\n";
4732 List.iter (generate_test_command_call test_name) seq;
4733 generate_test_command_call ~test test_name last
4734 | TestOutputListOfDevices (seq, expected) ->
4735 pr " /* TestOutputListOfDevices for %s (%d) */\n" name i;
4736 let seq, last = get_seq_last seq in
4740 pr " if (!r[%d]) {\n" i;
4741 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4742 pr " print_strings (r);\n";
4746 pr " const char *expected = \"%s\";\n" (c_quote str);
4747 pr " r[%d][5] = 's';\n" i;
4748 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4749 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4754 pr " if (r[%d] != NULL) {\n" (List.length expected);
4755 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4757 pr " print_strings (r);\n";
4761 List.iter (generate_test_command_call test_name) seq;
4762 generate_test_command_call ~test test_name last
4763 | TestOutputInt (seq, expected) ->
4764 pr " /* TestOutputInt for %s (%d) */\n" name i;
4765 let seq, last = get_seq_last seq in
4767 pr " if (r != %d) {\n" expected;
4768 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4774 List.iter (generate_test_command_call test_name) seq;
4775 generate_test_command_call ~test test_name last
4776 | TestOutputTrue seq ->
4777 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4778 let seq, last = get_seq_last seq in
4781 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4786 List.iter (generate_test_command_call test_name) seq;
4787 generate_test_command_call ~test test_name last
4788 | TestOutputFalse seq ->
4789 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4790 let seq, last = get_seq_last seq in
4793 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4798 List.iter (generate_test_command_call test_name) seq;
4799 generate_test_command_call ~test test_name last
4800 | TestOutputLength (seq, expected) ->
4801 pr " /* TestOutputLength for %s (%d) */\n" name i;
4802 let seq, last = get_seq_last seq in
4805 pr " for (j = 0; j < %d; ++j)\n" expected;
4806 pr " if (r[j] == NULL) {\n";
4807 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4809 pr " print_strings (r);\n";
4812 pr " if (r[j] != NULL) {\n";
4813 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4815 pr " print_strings (r);\n";
4819 List.iter (generate_test_command_call test_name) seq;
4820 generate_test_command_call ~test test_name last
4821 | TestOutputStruct (seq, checks) ->
4822 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4823 let seq, last = get_seq_last seq in
4827 | CompareWithInt (field, expected) ->
4828 pr " if (r->%s != %d) {\n" field expected;
4829 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4830 test_name field expected;
4831 pr " (int) r->%s);\n" field;
4834 | CompareWithString (field, expected) ->
4835 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4836 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4837 test_name field expected;
4838 pr " r->%s);\n" field;
4841 | CompareFieldsIntEq (field1, field2) ->
4842 pr " if (r->%s != r->%s) {\n" field1 field2;
4843 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4844 test_name field1 field2;
4845 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4848 | CompareFieldsStrEq (field1, field2) ->
4849 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4850 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4851 test_name field1 field2;
4852 pr " r->%s, r->%s);\n" field1 field2;
4857 List.iter (generate_test_command_call test_name) seq;
4858 generate_test_command_call ~test test_name last
4859 | TestLastFail seq ->
4860 pr " /* TestLastFail for %s (%d) */\n" name i;
4861 let seq, last = get_seq_last seq in
4862 List.iter (generate_test_command_call test_name) seq;
4863 generate_test_command_call test_name ~expect_error:true last
4865 (* Generate the code to run a command, leaving the result in 'r'.
4866 * If you expect to get an error then you should set expect_error:true.
4868 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4870 | [] -> assert false
4872 (* Look up the command to find out what args/ret it has. *)
4875 let _, style, _, _, _, _, _ =
4876 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4879 failwithf "%s: in test, command %s was not found" test_name name in
4881 if List.length (snd style) <> List.length args then
4882 failwithf "%s: in test, wrong number of args given to %s"
4889 | OptString n, "NULL" -> ()
4891 | OptString n, arg ->
4892 pr " const char *%s = \"%s\";\n" n (c_quote arg);
4895 | FileIn _, _ | FileOut _, _ -> ()
4896 | StringList n, arg ->
4897 let strs = string_split " " arg in
4900 pr " const char *%s_%d = \"%s\";\n" n i (c_quote str);
4902 pr " const char *%s[] = {\n" n;
4904 fun i _ -> pr " %s_%d,\n" n i
4908 ) (List.combine (snd style) args);
4911 match fst style with
4912 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4913 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4914 | RConstString _ -> pr " const char *r;\n"; "NULL"
4915 | RString _ -> pr " char *r;\n"; "NULL"
4916 | RStringList _ | RHashtable _ ->
4920 | RStruct (_, typ) ->
4921 pr " struct guestfs_%s *r;\n" typ; "NULL"
4922 | RStructList (_, typ) ->
4923 pr " struct guestfs_%s_list *r;\n" typ; "NULL" in
4925 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4926 pr " r = guestfs_%s (g" name;
4928 (* Generate the parameters. *)
4931 | OptString _, "NULL" -> pr ", NULL"
4935 | FileIn _, arg | FileOut _, arg ->
4936 pr ", \"%s\"" (c_quote arg)
4937 | StringList n, _ ->
4941 try int_of_string arg
4942 with Failure "int_of_string" ->
4943 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4946 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4947 ) (List.combine (snd style) args);
4950 if not expect_error then
4951 pr " if (r == %s)\n" error_code
4953 pr " if (r != %s)\n" error_code;
4956 (* Insert the test code. *)
4962 (match fst style with
4963 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4964 | RString _ -> pr " free (r);\n"
4965 | RStringList _ | RHashtable _ ->
4966 pr " for (i = 0; r[i] != NULL; ++i)\n";
4967 pr " free (r[i]);\n";
4969 | RStruct (_, typ) ->
4970 pr " guestfs_free_%s (r);\n" typ
4971 | RStructList (_, typ) ->
4972 pr " guestfs_free_%s_list (r);\n" typ
4978 let str = replace_str str "\r" "\\r" in
4979 let str = replace_str str "\n" "\\n" in
4980 let str = replace_str str "\t" "\\t" in
4981 let str = replace_str str "\000" "\\0" in
4984 (* Generate a lot of different functions for guestfish. *)
4985 and generate_fish_cmds () =
4986 generate_header CStyle GPLv2;
4990 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4992 let all_functions_sorted =
4994 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4995 ) all_functions_sorted in
4997 pr "#include <stdio.h>\n";
4998 pr "#include <stdlib.h>\n";
4999 pr "#include <string.h>\n";
5000 pr "#include <inttypes.h>\n";
5002 pr "#include <guestfs.h>\n";
5003 pr "#include \"fish.h\"\n";
5006 (* list_commands function, which implements guestfish -h *)
5007 pr "void list_commands (void)\n";
5009 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
5010 pr " list_builtin_commands ();\n";
5012 fun (name, _, _, flags, _, shortdesc, _) ->
5013 let name = replace_char name '_' '-' in
5014 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
5016 ) all_functions_sorted;
5017 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
5021 (* display_command function, which implements guestfish -h cmd *)
5022 pr "void display_command (const char *cmd)\n";
5025 fun (name, style, _, flags, _, shortdesc, longdesc) ->
5026 let name2 = replace_char name '_' '-' in
5028 try find_map (function FishAlias n -> Some n | _ -> None) flags
5029 with Not_found -> name in
5030 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
5032 match snd style with
5036 name2 (String.concat "> <" (List.map name_of_argt args)) in
5039 if List.mem ProtocolLimitWarning flags then
5040 ("\n\n" ^ protocol_limit_warning)
5043 (* For DangerWillRobinson commands, we should probably have
5044 * guestfish prompt before allowing you to use them (especially
5045 * in interactive mode). XXX
5049 if List.mem DangerWillRobinson flags then
5050 ("\n\n" ^ danger_will_robinson)
5053 let describe_alias =
5054 if name <> alias then
5055 sprintf "\n\nYou can use '%s' as an alias for this command." alias
5059 pr "strcasecmp (cmd, \"%s\") == 0" name;
5060 if name <> name2 then
5061 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5062 if name <> alias then
5063 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5065 pr " pod2text (\"%s - %s\", %S);\n"
5067 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
5070 pr " display_builtin_command (cmd);\n";
5074 (* print_* functions *)
5078 List.exists (function (_, FUUID) -> true | _ -> false) cols in
5080 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
5089 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
5091 pr " printf (\"%s: \");\n" name;
5092 pr " for (i = 0; i < 32; ++i)\n";
5093 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
5094 pr " printf (\"\\n\");\n"
5095 | name, (FUInt64|FBytes) ->
5096 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
5098 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
5100 pr " printf (\"%s: %%\" PRIu32 \"\\n\", %s->%s);\n" name typ name
5102 pr " printf (\"%s: %%\" PRIi32 \"\\n\", %s->%s);\n" name typ name
5104 pr " printf (\"%s: %%c\\n\", %s->%s);\n" name typ name
5105 | name, FOptPercent ->
5106 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
5107 typ name name typ name;
5108 pr " else printf (\"%s: \\n\");\n" name
5112 pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
5117 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
5118 pr " print_%s (&%ss->val[i]);\n" typ typ;
5123 (* run_<action> actions *)
5125 fun (name, style, _, flags, _, _, _) ->
5126 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
5128 (match fst style with
5131 | RBool _ -> pr " int r;\n"
5132 | RInt64 _ -> pr " int64_t r;\n"
5133 | RConstString _ -> pr " const char *r;\n"
5134 | RString _ -> pr " char *r;\n"
5135 | RStringList _ | RHashtable _ -> pr " char **r;\n"
5136 | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ
5137 | RStructList (_, typ) -> pr " struct guestfs_%s_list *r;\n" typ
5144 | FileOut n -> pr " const char *%s;\n" n
5145 | StringList n -> pr " char **%s;\n" n
5146 | Bool n -> pr " int %s;\n" n
5147 | Int n -> pr " int %s;\n" n
5150 (* Check and convert parameters. *)
5151 let argc_expected = List.length (snd style) in
5152 pr " if (argc != %d) {\n" argc_expected;
5153 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
5155 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
5161 | String name -> pr " %s = argv[%d];\n" name i
5163 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5166 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5169 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5171 | StringList name ->
5172 pr " %s = parse_string_list (argv[%d]);\n" name i
5174 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5176 pr " %s = atoi (argv[%d]);\n" name i
5179 (* Call C API function. *)
5181 try find_map (function FishAction n -> Some n | _ -> None) flags
5182 with Not_found -> sprintf "guestfs_%s" name in
5184 generate_call_args ~handle:"g" (snd style);
5187 (* Check return value for errors and display command results. *)
5188 (match fst style with
5189 | RErr -> pr " return r;\n"
5191 pr " if (r == -1) return -1;\n";
5192 pr " printf (\"%%d\\n\", r);\n";
5195 pr " if (r == -1) return -1;\n";
5196 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
5199 pr " if (r == -1) return -1;\n";
5200 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
5203 pr " if (r == NULL) return -1;\n";
5204 pr " printf (\"%%s\\n\", r);\n";
5207 pr " if (r == NULL) return -1;\n";
5208 pr " printf (\"%%s\\n\", r);\n";
5212 pr " if (r == NULL) return -1;\n";
5213 pr " print_strings (r);\n";
5214 pr " free_strings (r);\n";
5216 | RStruct (_, typ) ->
5217 pr " if (r == NULL) return -1;\n";
5218 pr " print_%s (r);\n" typ;
5219 pr " guestfs_free_%s (r);\n" typ;
5221 | RStructList (_, typ) ->
5222 pr " if (r == NULL) return -1;\n";
5223 pr " print_%s_list (r);\n" typ;
5224 pr " guestfs_free_%s_list (r);\n" typ;
5227 pr " if (r == NULL) return -1;\n";
5228 pr " print_table (r);\n";
5229 pr " free_strings (r);\n";
5236 (* run_action function *)
5237 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
5240 fun (name, _, _, flags, _, _, _) ->
5241 let name2 = replace_char name '_' '-' in
5243 try find_map (function FishAlias n -> Some n | _ -> None) flags
5244 with Not_found -> name in
5246 pr "strcasecmp (cmd, \"%s\") == 0" name;
5247 if name <> name2 then
5248 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5249 if name <> alias then
5250 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5252 pr " return run_%s (cmd, argc, argv);\n" name;
5256 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
5263 (* Readline completion for guestfish. *)
5264 and generate_fish_completion () =
5265 generate_header CStyle GPLv2;
5269 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5279 #ifdef HAVE_LIBREADLINE
5280 #include <readline/readline.h>
5285 #ifdef HAVE_LIBREADLINE
5287 static const char *const commands[] = {
5288 BUILTIN_COMMANDS_FOR_COMPLETION,
5291 (* Get the commands, including the aliases. They don't need to be
5292 * sorted - the generator() function just does a dumb linear search.
5296 fun (name, _, _, flags, _, _, _) ->
5297 let name2 = replace_char name '_' '-' in
5299 try find_map (function FishAlias n -> Some n | _ -> None) flags
5300 with Not_found -> name in
5302 if name <> alias then [name2; alias] else [name2]
5304 let commands = List.flatten commands in
5306 List.iter (pr " \"%s\",\n") commands;
5312 generator (const char *text, int state)
5314 static int index, len;
5319 len = strlen (text);
5322 rl_attempted_completion_over = 1;
5324 while ((name = commands[index]) != NULL) {
5326 if (strncasecmp (name, text, len) == 0)
5327 return strdup (name);
5333 #endif /* HAVE_LIBREADLINE */
5335 char **do_completion (const char *text, int start, int end)
5337 char **matches = NULL;
5339 #ifdef HAVE_LIBREADLINE
5340 rl_completion_append_character = ' ';
5343 matches = rl_completion_matches (text, generator);
5344 else if (complete_dest_paths)
5345 matches = rl_completion_matches (text, complete_dest_paths_generator);
5352 (* Generate the POD documentation for guestfish. *)
5353 and generate_fish_actions_pod () =
5354 let all_functions_sorted =
5356 fun (_, _, _, flags, _, _, _) ->
5357 not (List.mem NotInFish flags || List.mem NotInDocs flags)
5358 ) all_functions_sorted in
5360 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
5363 fun (name, style, _, flags, _, _, longdesc) ->
5365 Str.global_substitute rex (
5368 try Str.matched_group 1 s
5370 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
5371 "C<" ^ replace_char sub '_' '-' ^ ">"
5373 let name = replace_char name '_' '-' in
5375 try find_map (function FishAlias n -> Some n | _ -> None) flags
5376 with Not_found -> name in
5378 pr "=head2 %s" name;
5379 if name <> alias then
5386 | String n -> pr " %s" n
5387 | OptString n -> pr " %s" n
5388 | StringList n -> pr " '%s ...'" n
5389 | Bool _ -> pr " true|false"
5390 | Int n -> pr " %s" n
5391 | FileIn n | FileOut n -> pr " (%s|-)" n
5395 pr "%s\n\n" longdesc;
5397 if List.exists (function FileIn _ | FileOut _ -> true
5398 | _ -> false) (snd style) then
5399 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5401 if List.mem ProtocolLimitWarning flags then
5402 pr "%s\n\n" protocol_limit_warning;
5404 if List.mem DangerWillRobinson flags then
5405 pr "%s\n\n" danger_will_robinson
5406 ) all_functions_sorted
5408 (* Generate a C function prototype. *)
5409 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5410 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5412 ?handle name style =
5413 if extern then pr "extern ";
5414 if static then pr "static ";
5415 (match fst style with
5417 | RInt _ -> pr "int "
5418 | RInt64 _ -> pr "int64_t "
5419 | RBool _ -> pr "int "
5420 | RConstString _ -> pr "const char *"
5421 | RString _ -> pr "char *"
5422 | RStringList _ | RHashtable _ -> pr "char **"
5423 | RStruct (_, typ) ->
5424 if not in_daemon then pr "struct guestfs_%s *" typ
5425 else pr "guestfs_int_%s *" typ
5426 | RStructList (_, typ) ->
5427 if not in_daemon then pr "struct guestfs_%s_list *" typ
5428 else pr "guestfs_int_%s_list *" typ
5430 pr "%s%s (" prefix name;
5431 if handle = None && List.length (snd style) = 0 then
5434 let comma = ref false in
5437 | Some handle -> pr "guestfs_h *%s" handle; comma := true
5441 if single_line then pr ", " else pr ",\n\t\t"
5450 if not in_daemon then pr "const char *%s" n
5451 else pr "char *%s" n
5454 if not in_daemon then pr "char * const* const %s" n
5455 else pr "char **%s" n
5456 | Bool n -> next (); pr "int %s" n
5457 | Int n -> next (); pr "int %s" n
5460 if not in_daemon then (next (); pr "const char *%s" n)
5464 if semicolon then pr ";";
5465 if newline then pr "\n"
5467 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5468 and generate_call_args ?handle args =
5470 let comma = ref false in
5473 | Some handle -> pr "%s" handle; comma := true
5477 if !comma then pr ", ";
5479 pr "%s" (name_of_argt arg)
5483 (* Generate the OCaml bindings interface. *)
5484 and generate_ocaml_mli () =
5485 generate_header OCamlStyle LGPLv2;
5488 (** For API documentation you should refer to the C API
5489 in the guestfs(3) manual page. The OCaml API uses almost
5490 exactly the same calls. *)
5493 (** A [guestfs_h] handle. *)
5495 exception Error of string
5496 (** This exception is raised when there is an error. *)
5498 val create : unit -> t
5500 val close : t -> unit
5501 (** Handles are closed by the garbage collector when they become
5502 unreferenced, but callers can also call this in order to
5503 provide predictable cleanup. *)
5506 generate_ocaml_structure_decls ();
5510 fun (name, style, _, _, _, shortdesc, _) ->
5511 generate_ocaml_prototype name style;
5512 pr "(** %s *)\n" shortdesc;
5516 (* Generate the OCaml bindings implementation. *)
5517 and generate_ocaml_ml () =
5518 generate_header OCamlStyle LGPLv2;
5522 exception Error of string
5523 external create : unit -> t = \"ocaml_guestfs_create\"
5524 external close : t -> unit = \"ocaml_guestfs_close\"
5527 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
5531 generate_ocaml_structure_decls ();
5535 fun (name, style, _, _, _, shortdesc, _) ->
5536 generate_ocaml_prototype ~is_external:true name style;
5539 (* Generate the OCaml bindings C implementation. *)
5540 and generate_ocaml_c () =
5541 generate_header CStyle LGPLv2;
5548 #include <caml/config.h>
5549 #include <caml/alloc.h>
5550 #include <caml/callback.h>
5551 #include <caml/fail.h>
5552 #include <caml/memory.h>
5553 #include <caml/mlvalues.h>
5554 #include <caml/signals.h>
5556 #include <guestfs.h>
5558 #include \"guestfs_c.h\"
5560 /* Copy a hashtable of string pairs into an assoc-list. We return
5561 * the list in reverse order, but hashtables aren't supposed to be
5564 static CAMLprim value
5565 copy_table (char * const * argv)
5568 CAMLlocal5 (rv, pairv, kv, vv, cons);
5572 for (i = 0; argv[i] != NULL; i += 2) {
5573 kv = caml_copy_string (argv[i]);
5574 vv = caml_copy_string (argv[i+1]);
5575 pairv = caml_alloc (2, 0);
5576 Store_field (pairv, 0, kv);
5577 Store_field (pairv, 1, vv);
5578 cons = caml_alloc (2, 0);
5579 Store_field (cons, 1, rv);
5581 Store_field (cons, 0, pairv);
5589 (* Struct copy functions. *)
5592 let has_optpercent_col =
5593 List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
5595 pr "static CAMLprim value\n";
5596 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5598 pr " CAMLparam0 ();\n";
5599 if has_optpercent_col then
5600 pr " CAMLlocal3 (rv, v, v2);\n"
5602 pr " CAMLlocal2 (rv, v);\n";
5604 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5609 pr " v = caml_copy_string (%s->%s);\n" typ name
5611 pr " v = caml_alloc_string (32);\n";
5612 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
5613 | name, (FBytes|FInt64|FUInt64) ->
5614 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5615 | name, (FInt32|FUInt32) ->
5616 pr " v = caml_copy_int32 (%s->%s);\n" typ name
5617 | name, FOptPercent ->
5618 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5619 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
5620 pr " v = caml_alloc (1, 0);\n";
5621 pr " Store_field (v, 0, v2);\n";
5622 pr " } else /* None */\n";
5623 pr " v = Val_int (0);\n";
5625 pr " v = Val_int (%s->%s);\n" typ name
5627 pr " Store_field (rv, %d, v);\n" i
5629 pr " CAMLreturn (rv);\n";
5633 pr "static CAMLprim value\n";
5634 pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n"
5637 pr " CAMLparam0 ();\n";
5638 pr " CAMLlocal2 (rv, v);\n";
5641 pr " if (%ss->len == 0)\n" typ;
5642 pr " CAMLreturn (Atom (0));\n";
5644 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
5645 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
5646 pr " v = copy_%s (&%ss->val[i]);\n" typ typ;
5647 pr " caml_modify (&Field (rv, i), v);\n";
5649 pr " CAMLreturn (rv);\n";
5657 fun (name, style, _, _, _, _, _) ->
5659 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5661 pr "CAMLprim value\n";
5662 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5663 List.iter (pr ", value %s") (List.tl params);
5668 | [p1; p2; p3; p4; p5] ->
5669 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
5670 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5671 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5672 pr " CAMLxparam%d (%s);\n"
5673 (List.length rest) (String.concat ", " rest)
5675 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5677 pr " CAMLlocal1 (rv);\n";
5680 pr " guestfs_h *g = Guestfs_val (gv);\n";
5681 pr " if (g == NULL)\n";
5682 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
5690 pr " const char *%s = String_val (%sv);\n" n n
5692 pr " const char *%s =\n" n;
5693 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5696 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5698 pr " int %s = Bool_val (%sv);\n" n n
5700 pr " int %s = Int_val (%sv);\n" n n
5703 match fst style with
5704 | RErr -> pr " int r;\n"; "-1"
5705 | RInt _ -> pr " int r;\n"; "-1"
5706 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5707 | RBool _ -> pr " int r;\n"; "-1"
5708 | RConstString _ -> pr " const char *r;\n"; "NULL"
5709 | RString _ -> pr " char *r;\n"; "NULL"
5714 | RStruct (_, typ) ->
5715 pr " struct guestfs_%s *r;\n" typ; "NULL"
5716 | RStructList (_, typ) ->
5717 pr " struct guestfs_%s_list *r;\n" typ; "NULL"
5724 pr " caml_enter_blocking_section ();\n";
5725 pr " r = guestfs_%s " name;
5726 generate_call_args ~handle:"g" (snd style);
5728 pr " caml_leave_blocking_section ();\n";
5733 pr " ocaml_guestfs_free_strings (%s);\n" n;
5734 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5737 pr " if (r == %s)\n" error_code;
5738 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5741 (match fst style with
5742 | RErr -> pr " rv = Val_unit;\n"
5743 | RInt _ -> pr " rv = Val_int (r);\n"
5745 pr " rv = caml_copy_int64 (r);\n"
5746 | RBool _ -> pr " rv = Val_bool (r);\n"
5747 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5749 pr " rv = caml_copy_string (r);\n";
5752 pr " rv = caml_copy_string_array ((const char **) r);\n";
5753 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5755 | RStruct (_, typ) ->
5756 pr " rv = copy_%s (r);\n" typ;
5757 pr " guestfs_free_%s (r);\n" typ;
5758 | RStructList (_, typ) ->
5759 pr " rv = copy_%s_list (r);\n" typ;
5760 pr " guestfs_free_%s_list (r);\n" typ;
5762 pr " rv = copy_table (r);\n";
5763 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5767 pr " CAMLreturn (rv);\n";
5771 if List.length params > 5 then (
5772 pr "CAMLprim value\n";
5773 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5775 pr " return ocaml_guestfs_%s (argv[0]" name;
5776 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5783 and generate_ocaml_structure_decls () =
5786 pr "type %s = {\n" typ;
5789 | name, FString -> pr " %s : string;\n" name
5790 | name, FUUID -> pr " %s : string;\n" name
5791 | name, (FBytes|FInt64|FUInt64) -> pr " %s : int64;\n" name
5792 | name, (FInt32|FUInt32) -> pr " %s : int32;\n" name
5793 | name, FChar -> pr " %s : char;\n" name
5794 | name, FOptPercent -> pr " %s : float option;\n" name
5800 and generate_ocaml_prototype ?(is_external = false) name style =
5801 if is_external then pr "external " else pr "val ";
5802 pr "%s : t -> " name;
5805 | String _ | FileIn _ | FileOut _ -> pr "string -> "
5806 | OptString _ -> pr "string option -> "
5807 | StringList _ -> pr "string array -> "
5808 | Bool _ -> pr "bool -> "
5809 | Int _ -> pr "int -> "
5811 (match fst style with
5812 | RErr -> pr "unit" (* all errors are turned into exceptions *)
5813 | RInt _ -> pr "int"
5814 | RInt64 _ -> pr "int64"
5815 | RBool _ -> pr "bool"
5816 | RConstString _ -> pr "string"
5817 | RString _ -> pr "string"
5818 | RStringList _ -> pr "string array"
5819 | RStruct (_, typ) -> pr "%s" typ
5820 | RStructList (_, typ) -> pr "%s array" typ
5821 | RHashtable _ -> pr "(string * string) list"
5823 if is_external then (
5825 if List.length (snd style) + 1 > 5 then
5826 pr "\"ocaml_guestfs_%s_byte\" " name;
5827 pr "\"ocaml_guestfs_%s\"" name
5831 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5832 and generate_perl_xs () =
5833 generate_header CStyle LGPLv2;
5836 #include \"EXTERN.h\"
5840 #include <guestfs.h>
5843 #define PRId64 \"lld\"
5847 my_newSVll(long long val) {
5848 #ifdef USE_64_BIT_ALL
5849 return newSViv(val);
5853 len = snprintf(buf, 100, \"%%\" PRId64, val);
5854 return newSVpv(buf, len);
5859 #define PRIu64 \"llu\"
5863 my_newSVull(unsigned long long val) {
5864 #ifdef USE_64_BIT_ALL
5865 return newSVuv(val);
5869 len = snprintf(buf, 100, \"%%\" PRIu64, val);
5870 return newSVpv(buf, len);
5874 /* http://www.perlmonks.org/?node_id=680842 */
5876 XS_unpack_charPtrPtr (SV *arg) {
5881 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5882 croak (\"array reference expected\");
5884 av = (AV *)SvRV (arg);
5885 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5887 croak (\"malloc failed\");
5889 for (i = 0; i <= av_len (av); i++) {
5890 SV **elem = av_fetch (av, i, 0);
5892 if (!elem || !*elem)
5893 croak (\"missing element in list\");
5895 ret[i] = SvPV_nolen (*elem);
5903 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
5910 RETVAL = guestfs_create ();
5912 croak (\"could not create guestfs handle\");
5913 guestfs_set_error_handler (RETVAL, NULL, NULL);
5926 fun (name, style, _, _, _, _, _) ->
5927 (match fst style with
5928 | RErr -> pr "void\n"
5929 | RInt _ -> pr "SV *\n"
5930 | RInt64 _ -> pr "SV *\n"
5931 | RBool _ -> pr "SV *\n"
5932 | RConstString _ -> pr "SV *\n"
5933 | RString _ -> pr "SV *\n"
5935 | RStruct _ | RStructList _
5937 pr "void\n" (* all lists returned implictly on the stack *)
5939 (* Call and arguments. *)
5941 generate_call_args ~handle:"g" (snd style);
5943 pr " guestfs_h *g;\n";
5947 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
5949 (* http://www.perlmonks.org/?node_id=554277
5950 * Note that the implicit handle argument means we have
5951 * to add 1 to the ST(x) operator.
5953 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
5954 | StringList n -> pr " char **%s;\n" n
5955 | Bool n -> pr " int %s;\n" n
5956 | Int n -> pr " int %s;\n" n
5959 let do_cleanups () =
5962 | String _ | OptString _ | Bool _ | Int _
5963 | FileIn _ | FileOut _ -> ()
5964 | StringList n -> pr " free (%s);\n" n
5969 (match fst style with
5974 pr " r = guestfs_%s " name;
5975 generate_call_args ~handle:"g" (snd style);
5978 pr " if (r == -1)\n";
5979 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5985 pr " %s = guestfs_%s " n name;
5986 generate_call_args ~handle:"g" (snd style);
5989 pr " if (%s == -1)\n" n;
5990 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5991 pr " RETVAL = newSViv (%s);\n" n;
5996 pr " int64_t %s;\n" n;
5998 pr " %s = guestfs_%s " n name;
5999 generate_call_args ~handle:"g" (snd style);
6002 pr " if (%s == -1)\n" n;
6003 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6004 pr " RETVAL = my_newSVll (%s);\n" n;
6009 pr " const char *%s;\n" n;
6011 pr " %s = guestfs_%s " n name;
6012 generate_call_args ~handle:"g" (snd style);
6015 pr " if (%s == NULL)\n" n;
6016 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6017 pr " RETVAL = newSVpv (%s, 0);\n" n;
6022 pr " char *%s;\n" n;
6024 pr " %s = guestfs_%s " n name;
6025 generate_call_args ~handle:"g" (snd style);
6028 pr " if (%s == NULL)\n" n;
6029 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6030 pr " RETVAL = newSVpv (%s, 0);\n" n;
6031 pr " free (%s);\n" n;
6034 | RStringList n | RHashtable n ->
6036 pr " char **%s;\n" n;
6039 pr " %s = guestfs_%s " n name;
6040 generate_call_args ~handle:"g" (snd style);
6043 pr " if (%s == NULL)\n" n;
6044 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6045 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6046 pr " EXTEND (SP, n);\n";
6047 pr " for (i = 0; i < n; ++i) {\n";
6048 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6049 pr " free (%s[i]);\n" n;
6051 pr " free (%s);\n" n;
6052 | RStruct (n, typ) ->
6053 let cols = cols_of_struct typ in
6054 generate_perl_struct_code typ cols name style n do_cleanups
6055 | RStructList (n, typ) ->
6056 let cols = cols_of_struct typ in
6057 generate_perl_struct_list_code typ cols name style n do_cleanups
6063 and generate_perl_struct_list_code typ cols name style n do_cleanups =
6065 pr " struct guestfs_%s_list *%s;\n" typ n;
6069 pr " %s = guestfs_%s " n name;
6070 generate_call_args ~handle:"g" (snd style);
6073 pr " if (%s == NULL)\n" n;
6074 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6075 pr " EXTEND (SP, %s->len);\n" n;
6076 pr " for (i = 0; i < %s->len; ++i) {\n" n;
6077 pr " hv = newHV ();\n";
6081 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6082 name (String.length name) n name
6084 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
6085 name (String.length name) n name
6086 | name, (FBytes|FUInt64) ->
6087 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6088 name (String.length name) n name
6090 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
6091 name (String.length name) n name
6092 | name, (FInt32|FUInt32) ->
6093 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6094 name (String.length name) n name
6096 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
6097 name (String.length name) n name
6098 | name, FOptPercent ->
6099 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6100 name (String.length name) n name
6102 pr " PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
6104 pr " guestfs_free_%s_list (%s);\n" typ n
6106 and generate_perl_struct_code typ cols name style n do_cleanups =
6108 pr " struct guestfs_%s *%s;\n" typ n;
6110 pr " %s = guestfs_%s " n name;
6111 generate_call_args ~handle:"g" (snd style);
6114 pr " if (%s == NULL)\n" n;
6115 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6116 pr " EXTEND (SP, 2 * %d);\n" (List.length cols);
6118 fun ((name, _) as col) ->
6119 pr " PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
6123 pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
6126 pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
6128 | name, (FBytes|FUInt64) ->
6129 pr " PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
6132 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
6134 | name, (FInt32|FUInt32) ->
6135 pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
6138 pr " PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
6140 | name, FOptPercent ->
6141 pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
6144 pr " free (%s);\n" n
6146 (* Generate Sys/Guestfs.pm. *)
6147 and generate_perl_pm () =
6148 generate_header HashStyle LGPLv2;
6155 Sys::Guestfs - Perl bindings for libguestfs
6161 my $h = Sys::Guestfs->new ();
6162 $h->add_drive ('guest.img');
6165 $h->mount ('/dev/sda1', '/');
6166 $h->touch ('/hello');
6171 The C<Sys::Guestfs> module provides a Perl XS binding to the
6172 libguestfs API for examining and modifying virtual machine
6175 Amongst the things this is good for: making batch configuration
6176 changes to guests, getting disk used/free statistics (see also:
6177 virt-df), migrating between virtualization systems (see also:
6178 virt-p2v), performing partial backups, performing partial guest
6179 clones, cloning guests and changing registry/UUID/hostname info, and
6182 Libguestfs uses Linux kernel and qemu code, and can access any type of
6183 guest filesystem that Linux and qemu can, including but not limited
6184 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6185 schemes, qcow, qcow2, vmdk.
6187 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6188 LVs, what filesystem is in each LV, etc.). It can also run commands
6189 in the context of the guest. Also you can access filesystems over FTP.
6191 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
6192 functions for using libguestfs from Perl, including integration
6197 All errors turn into calls to C<croak> (see L<Carp(3)>).
6205 package Sys::Guestfs;
6211 XSLoader::load ('Sys::Guestfs');
6213 =item $h = Sys::Guestfs->new ();
6215 Create a new guestfs handle.
6221 my $class = ref ($proto) || $proto;
6223 my $self = Sys::Guestfs::_create ();
6224 bless $self, $class;
6230 (* Actions. We only need to print documentation for these as
6231 * they are pulled in from the XS code automatically.
6234 fun (name, style, _, flags, _, _, longdesc) ->
6235 if not (List.mem NotInDocs flags) then (
6236 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
6238 generate_perl_prototype name style;
6240 pr "%s\n\n" longdesc;
6241 if List.mem ProtocolLimitWarning flags then
6242 pr "%s\n\n" protocol_limit_warning;
6243 if List.mem DangerWillRobinson flags then
6244 pr "%s\n\n" danger_will_robinson
6246 ) all_functions_sorted;
6258 Copyright (C) 2009 Red Hat Inc.
6262 Please see the file COPYING.LIB for the full license.
6268 L<http://libguestfs.org>,
6269 L<Sys::Guestfs::Lib(3)>.
6274 and generate_perl_prototype name style =
6275 (match fst style with
6281 | RString n -> pr "$%s = " n
6283 | RHashtable n -> pr "%%%s = " n
6285 | RStructList (n,_) -> pr "@%s = " n
6288 let comma = ref false in
6291 if !comma then pr ", ";
6294 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
6301 (* Generate Python C module. *)
6302 and generate_python_c () =
6303 generate_header CStyle LGPLv2;
6312 #include \"guestfs.h\"
6320 get_handle (PyObject *obj)
6323 assert (obj != Py_None);
6324 return ((Pyguestfs_Object *) obj)->g;
6328 put_handle (guestfs_h *g)
6332 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6335 /* This list should be freed (but not the strings) after use. */
6336 static const char **
6337 get_string_list (PyObject *obj)
6344 if (!PyList_Check (obj)) {
6345 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6349 len = PyList_Size (obj);
6350 r = malloc (sizeof (char *) * (len+1));
6352 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6356 for (i = 0; i < len; ++i)
6357 r[i] = PyString_AsString (PyList_GetItem (obj, i));
6364 put_string_list (char * const * const argv)
6369 for (argc = 0; argv[argc] != NULL; ++argc)
6372 list = PyList_New (argc);
6373 for (i = 0; i < argc; ++i)
6374 PyList_SetItem (list, i, PyString_FromString (argv[i]));
6380 put_table (char * const * const argv)
6382 PyObject *list, *item;
6385 for (argc = 0; argv[argc] != NULL; ++argc)
6388 list = PyList_New (argc >> 1);
6389 for (i = 0; i < argc; i += 2) {
6390 item = PyTuple_New (2);
6391 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
6392 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
6393 PyList_SetItem (list, i >> 1, item);
6400 free_strings (char **argv)
6404 for (argc = 0; argv[argc] != NULL; ++argc)
6410 py_guestfs_create (PyObject *self, PyObject *args)
6414 g = guestfs_create ();
6416 PyErr_SetString (PyExc_RuntimeError,
6417 \"guestfs.create: failed to allocate handle\");
6420 guestfs_set_error_handler (g, NULL, NULL);
6421 return put_handle (g);
6425 py_guestfs_close (PyObject *self, PyObject *args)
6430 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
6432 g = get_handle (py_g);
6436 Py_INCREF (Py_None);
6442 (* Structures, turned into Python dictionaries. *)
6445 pr "static PyObject *\n";
6446 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6448 pr " PyObject *dict;\n";
6450 pr " dict = PyDict_New ();\n";
6454 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6455 pr " PyString_FromString (%s->%s));\n"
6458 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6459 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
6461 | name, (FBytes|FUInt64) ->
6462 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6463 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
6466 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6467 pr " PyLong_FromLongLong (%s->%s));\n"
6470 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6471 pr " PyLong_FromUnsignedLong (%s->%s));\n"
6474 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6475 pr " PyLong_FromLong (%s->%s));\n"
6477 | name, FOptPercent ->
6478 pr " if (%s->%s >= 0)\n" typ name;
6479 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6480 pr " PyFloat_FromDouble ((double) %s->%s));\n"
6483 pr " Py_INCREF (Py_None);\n";
6484 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
6487 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6488 pr " PyString_FromStringAndSize (&dirent->%s, 1));\n" name
6490 pr " return dict;\n";
6494 pr "static PyObject *\n";
6495 pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
6497 pr " PyObject *list;\n";
6500 pr " list = PyList_New (%ss->len);\n" typ;
6501 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
6502 pr " PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
6503 pr " return list;\n";
6508 (* Python wrapper functions. *)
6510 fun (name, style, _, _, _, _, _) ->
6511 pr "static PyObject *\n";
6512 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6515 pr " PyObject *py_g;\n";
6516 pr " guestfs_h *g;\n";
6517 pr " PyObject *py_r;\n";
6520 match fst style with
6521 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6522 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6523 | RConstString _ -> pr " const char *r;\n"; "NULL"
6524 | RString _ -> pr " char *r;\n"; "NULL"
6525 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6526 | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ; "NULL"
6527 | RStructList (_, typ) ->
6528 pr " struct guestfs_%s_list *r;\n" typ; "NULL" in
6532 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
6533 | OptString n -> pr " const char *%s;\n" n
6535 pr " PyObject *py_%s;\n" n;
6536 pr " const char **%s;\n" n
6537 | Bool n -> pr " int %s;\n" n
6538 | Int n -> pr " int %s;\n" n
6543 (* Convert the parameters. *)
6544 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
6547 | String _ | FileIn _ | FileOut _ -> pr "s"
6548 | OptString _ -> pr "z"
6549 | StringList _ -> pr "O"
6550 | Bool _ -> pr "i" (* XXX Python has booleans? *)
6553 pr ":guestfs_%s\",\n" name;
6557 | String n | FileIn n | FileOut n -> pr ", &%s" n
6558 | OptString n -> pr ", &%s" n
6559 | StringList n -> pr ", &py_%s" n
6560 | Bool n -> pr ", &%s" n
6561 | Int n -> pr ", &%s" n
6565 pr " return NULL;\n";
6567 pr " g = get_handle (py_g);\n";
6570 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6572 pr " %s = get_string_list (py_%s);\n" n n;
6573 pr " if (!%s) return NULL;\n" n
6578 pr " r = guestfs_%s " name;
6579 generate_call_args ~handle:"g" (snd style);
6584 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6586 pr " free (%s);\n" n
6589 pr " if (r == %s) {\n" error_code;
6590 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6591 pr " return NULL;\n";
6595 (match fst style with
6597 pr " Py_INCREF (Py_None);\n";
6598 pr " py_r = Py_None;\n"
6600 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
6601 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
6602 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
6604 pr " py_r = PyString_FromString (r);\n";
6607 pr " py_r = put_string_list (r);\n";
6608 pr " free_strings (r);\n"
6609 | RStruct (_, typ) ->
6610 pr " py_r = put_%s (r);\n" typ;
6611 pr " guestfs_free_%s (r);\n" typ
6612 | RStructList (_, typ) ->
6613 pr " py_r = put_%s_list (r);\n" typ;
6614 pr " guestfs_free_%s_list (r);\n" typ
6616 pr " py_r = put_table (r);\n";
6617 pr " free_strings (r);\n"
6620 pr " return py_r;\n";
6625 (* Table of functions. *)
6626 pr "static PyMethodDef methods[] = {\n";
6627 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6628 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6630 fun (name, _, _, _, _, _, _) ->
6631 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6634 pr " { NULL, NULL, 0, NULL }\n";
6638 (* Init function. *)
6641 initlibguestfsmod (void)
6643 static int initialized = 0;
6645 if (initialized) return;
6646 Py_InitModule ((char *) \"libguestfsmod\", methods);
6651 (* Generate Python module. *)
6652 and generate_python_py () =
6653 generate_header HashStyle LGPLv2;
6656 u\"\"\"Python bindings for libguestfs
6659 g = guestfs.GuestFS ()
6660 g.add_drive (\"guest.img\")
6663 parts = g.list_partitions ()
6665 The guestfs module provides a Python binding to the libguestfs API
6666 for examining and modifying virtual machine disk images.
6668 Amongst the things this is good for: making batch configuration
6669 changes to guests, getting disk used/free statistics (see also:
6670 virt-df), migrating between virtualization systems (see also:
6671 virt-p2v), performing partial backups, performing partial guest
6672 clones, cloning guests and changing registry/UUID/hostname info, and
6675 Libguestfs uses Linux kernel and qemu code, and can access any type of
6676 guest filesystem that Linux and qemu can, including but not limited
6677 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6678 schemes, qcow, qcow2, vmdk.
6680 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6681 LVs, what filesystem is in each LV, etc.). It can also run commands
6682 in the context of the guest. Also you can access filesystems over FTP.
6684 Errors which happen while using the API are turned into Python
6685 RuntimeError exceptions.
6687 To create a guestfs handle you usually have to perform the following
6690 # Create the handle, call add_drive at least once, and possibly
6691 # several times if the guest has multiple block devices:
6692 g = guestfs.GuestFS ()
6693 g.add_drive (\"guest.img\")
6695 # Launch the qemu subprocess and wait for it to become ready:
6699 # Now you can issue commands, for example:
6704 import libguestfsmod
6707 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6709 def __init__ (self):
6710 \"\"\"Create a new libguestfs handle.\"\"\"
6711 self._o = libguestfsmod.create ()
6714 libguestfsmod.close (self._o)
6719 fun (name, style, _, flags, _, _, longdesc) ->
6721 generate_call_args ~handle:"self" (snd style);
6724 if not (List.mem NotInDocs flags) then (
6725 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6727 match fst style with
6728 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6731 doc ^ "\n\nThis function returns a list of strings."
6732 | RStruct (_, typ) ->
6733 doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
6734 | RStructList (_, typ) ->
6735 doc ^ sprintf "\n\nThis function returns a list of %ss. Each %s is represented as a dictionary." typ typ
6737 doc ^ "\n\nThis function returns a dictionary." in
6739 if List.mem ProtocolLimitWarning flags then
6740 doc ^ "\n\n" ^ protocol_limit_warning
6743 if List.mem DangerWillRobinson flags then
6744 doc ^ "\n\n" ^ danger_will_robinson
6746 let doc = pod2text ~width:60 name doc in
6747 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6748 let doc = String.concat "\n " doc in
6749 pr " u\"\"\"%s\"\"\"\n" doc;
6751 pr " return libguestfsmod.%s " name;
6752 generate_call_args ~handle:"self._o" (snd style);
6757 (* Useful if you need the longdesc POD text as plain text. Returns a
6760 * Because this is very slow (the slowest part of autogeneration),
6761 * we memoize the results.
6763 and pod2text ~width name longdesc =
6764 let key = width, name, longdesc in
6765 try Hashtbl.find pod2text_memo key
6767 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6768 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6770 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6771 let chan = Unix.open_process_in cmd in
6772 let lines = ref [] in
6774 let line = input_line chan in
6775 if i = 1 then (* discard the first line of output *)
6778 let line = triml line in
6779 lines := line :: !lines;
6782 let lines = try loop 1 with End_of_file -> List.rev !lines in
6783 Unix.unlink filename;
6784 (match Unix.close_process_in chan with
6785 | Unix.WEXITED 0 -> ()
6787 failwithf "pod2text: process exited with non-zero status (%d)" i
6788 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6789 failwithf "pod2text: process signalled or stopped by signal %d" i
6791 Hashtbl.add pod2text_memo key lines;
6792 let chan = open_out pod2text_memo_filename in
6793 output_value chan pod2text_memo;
6797 (* Generate ruby bindings. *)
6798 and generate_ruby_c () =
6799 generate_header CStyle LGPLv2;
6807 #include \"guestfs.h\"
6809 #include \"extconf.h\"
6811 /* For Ruby < 1.9 */
6813 #define RARRAY_LEN(r) (RARRAY((r))->len)
6816 static VALUE m_guestfs; /* guestfs module */
6817 static VALUE c_guestfs; /* guestfs_h handle */
6818 static VALUE e_Error; /* used for all errors */
6820 static void ruby_guestfs_free (void *p)
6823 guestfs_close ((guestfs_h *) p);
6826 static VALUE ruby_guestfs_create (VALUE m)
6830 g = guestfs_create ();
6832 rb_raise (e_Error, \"failed to create guestfs handle\");
6834 /* Don't print error messages to stderr by default. */
6835 guestfs_set_error_handler (g, NULL, NULL);
6837 /* Wrap it, and make sure the close function is called when the
6840 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6843 static VALUE ruby_guestfs_close (VALUE gv)
6846 Data_Get_Struct (gv, guestfs_h, g);
6848 ruby_guestfs_free (g);
6849 DATA_PTR (gv) = NULL;
6857 fun (name, style, _, _, _, _, _) ->
6858 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6859 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6862 pr " guestfs_h *g;\n";
6863 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
6865 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6871 | String n | FileIn n | FileOut n ->
6872 pr " Check_Type (%sv, T_STRING);\n" n;
6873 pr " const char *%s = StringValueCStr (%sv);\n" n n;
6875 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6876 pr " \"%s\", \"%s\");\n" n name
6878 pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
6880 pr " char **%s;\n" n;
6881 pr " Check_Type (%sv, T_ARRAY);\n" n;
6883 pr " int i, len;\n";
6884 pr " len = RARRAY_LEN (%sv);\n" n;
6885 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6887 pr " for (i = 0; i < len; ++i) {\n";
6888 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
6889 pr " %s[i] = StringValueCStr (v);\n" n;
6891 pr " %s[len] = NULL;\n" n;
6894 pr " int %s = RTEST (%sv);\n" n n
6896 pr " int %s = NUM2INT (%sv);\n" n n
6901 match fst style with
6902 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6903 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6904 | RConstString _ -> pr " const char *r;\n"; "NULL"
6905 | RString _ -> pr " char *r;\n"; "NULL"
6906 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6907 | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ; "NULL"
6908 | RStructList (_, typ) ->
6909 pr " struct guestfs_%s_list *r;\n" typ; "NULL" in
6912 pr " r = guestfs_%s " name;
6913 generate_call_args ~handle:"g" (snd style);
6918 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6920 pr " free (%s);\n" n
6923 pr " if (r == %s)\n" error_code;
6924 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6927 (match fst style with
6929 pr " return Qnil;\n"
6930 | RInt _ | RBool _ ->
6931 pr " return INT2NUM (r);\n"
6933 pr " return ULL2NUM (r);\n"
6935 pr " return rb_str_new2 (r);\n";
6937 pr " VALUE rv = rb_str_new2 (r);\n";
6941 pr " int i, len = 0;\n";
6942 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
6943 pr " VALUE rv = rb_ary_new2 (len);\n";
6944 pr " for (i = 0; r[i] != NULL; ++i) {\n";
6945 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6946 pr " free (r[i]);\n";
6950 | RStruct (_, typ) ->
6951 let cols = cols_of_struct typ in
6952 generate_ruby_struct_code typ cols
6953 | RStructList (_, typ) ->
6954 let cols = cols_of_struct typ in
6955 generate_ruby_struct_list_code typ cols
6957 pr " VALUE rv = rb_hash_new ();\n";
6959 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
6960 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6961 pr " free (r[i]);\n";
6962 pr " free (r[i+1]);\n";
6973 /* Initialize the module. */
6974 void Init__guestfs ()
6976 m_guestfs = rb_define_module (\"Guestfs\");
6977 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6978 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6980 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6981 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6984 (* Define the rest of the methods. *)
6986 fun (name, style, _, _, _, _, _) ->
6987 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
6988 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6993 (* Ruby code to return a struct. *)
6994 and generate_ruby_struct_code typ cols =
6995 pr " VALUE rv = rb_hash_new ();\n";
6999 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
7001 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
7002 | name, (FBytes|FUInt64) ->
7003 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7005 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
7007 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
7009 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
7010 | name, FOptPercent ->
7011 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
7012 | name, FChar -> (* XXX wrong? *)
7013 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7015 pr " guestfs_free_%s (r);\n" typ;
7018 (* Ruby code to return a struct list. *)
7019 and generate_ruby_struct_list_code typ cols =
7020 pr " VALUE rv = rb_ary_new2 (r->len);\n";
7022 pr " for (i = 0; i < r->len; ++i) {\n";
7023 pr " VALUE hv = rb_hash_new ();\n";
7027 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7029 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
7030 | name, (FBytes|FUInt64) ->
7031 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7033 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
7035 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
7037 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
7038 | name, FOptPercent ->
7039 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
7040 | name, FChar -> (* XXX wrong? *)
7041 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7043 pr " rb_ary_push (rv, hv);\n";
7045 pr " guestfs_free_%s_list (r);\n" typ;
7048 (* Generate Java bindings GuestFS.java file. *)
7049 and generate_java_java () =
7050 generate_header CStyle LGPLv2;
7053 package com.redhat.et.libguestfs;
7055 import java.util.HashMap;
7056 import com.redhat.et.libguestfs.LibGuestFSException;
7057 import com.redhat.et.libguestfs.PV;
7058 import com.redhat.et.libguestfs.VG;
7059 import com.redhat.et.libguestfs.LV;
7060 import com.redhat.et.libguestfs.Stat;
7061 import com.redhat.et.libguestfs.StatVFS;
7062 import com.redhat.et.libguestfs.IntBool;
7063 import com.redhat.et.libguestfs.Dirent;
7066 * The GuestFS object is a libguestfs handle.
7070 public class GuestFS {
7071 // Load the native code.
7073 System.loadLibrary (\"guestfs_jni\");
7077 * The native guestfs_h pointer.
7082 * Create a libguestfs handle.
7084 * @throws LibGuestFSException
7086 public GuestFS () throws LibGuestFSException
7090 private native long _create () throws LibGuestFSException;
7093 * Close a libguestfs handle.
7095 * You can also leave handles to be collected by the garbage
7096 * collector, but this method ensures that the resources used
7097 * by the handle are freed up immediately. If you call any
7098 * other methods after closing the handle, you will get an
7101 * @throws LibGuestFSException
7103 public void close () throws LibGuestFSException
7109 private native void _close (long g) throws LibGuestFSException;
7111 public void finalize () throws LibGuestFSException
7119 fun (name, style, _, flags, _, shortdesc, longdesc) ->
7120 if not (List.mem NotInDocs flags); then (
7121 let doc = replace_str longdesc "C<guestfs_" "C<g." in
7123 if List.mem ProtocolLimitWarning flags then
7124 doc ^ "\n\n" ^ protocol_limit_warning
7127 if List.mem DangerWillRobinson flags then
7128 doc ^ "\n\n" ^ danger_will_robinson
7130 let doc = pod2text ~width:60 name doc in
7131 let doc = List.map ( (* RHBZ#501883 *)
7134 | nonempty -> nonempty
7136 let doc = String.concat "\n * " doc in
7139 pr " * %s\n" shortdesc;
7142 pr " * @throws LibGuestFSException\n";
7146 generate_java_prototype ~public:true ~semicolon:false name style;
7149 pr " if (g == 0)\n";
7150 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
7153 if fst style <> RErr then pr "return ";
7155 generate_call_args ~handle:"g" (snd style);
7159 generate_java_prototype ~privat:true ~native:true name style;
7166 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
7167 ?(semicolon=true) name style =
7168 if privat then pr "private ";
7169 if public then pr "public ";
7170 if native then pr "native ";
7173 (match fst style with
7174 | RErr -> pr "void ";
7175 | RInt _ -> pr "int ";
7176 | RInt64 _ -> pr "long ";
7177 | RBool _ -> pr "boolean ";
7178 | RConstString _ | RString _ -> pr "String ";
7179 | RStringList _ -> pr "String[] ";
7180 | RStruct (_, typ) ->
7181 let name = java_name_of_struct typ in
7183 | RStructList (_, typ) ->
7184 let name = java_name_of_struct typ in
7186 | RHashtable _ -> pr "HashMap<String,String> ";
7189 if native then pr "_%s " name else pr "%s " name;
7191 let needs_comma = ref false in
7200 if !needs_comma then pr ", ";
7201 needs_comma := true;
7218 pr " throws LibGuestFSException";
7219 if semicolon then pr ";"
7221 and generate_java_struct jtyp cols =
7222 generate_header CStyle LGPLv2;
7225 package com.redhat.et.libguestfs;
7228 * Libguestfs %s structure.
7239 | name, FUUID -> pr " public String %s;\n" name
7240 | name, (FBytes|FUInt64|FInt64) -> pr " public long %s;\n" name
7241 | name, (FUInt32|FInt32) -> pr " public int %s;\n" name
7242 | name, FChar -> pr " public char %s;\n" name
7243 | name, FOptPercent ->
7244 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
7245 pr " public float %s;\n" name
7250 and generate_java_c () =
7251 generate_header CStyle LGPLv2;
7258 #include \"com_redhat_et_libguestfs_GuestFS.h\"
7259 #include \"guestfs.h\"
7261 /* Note that this function returns. The exception is not thrown
7262 * until after the wrapper function returns.
7265 throw_exception (JNIEnv *env, const char *msg)
7268 cl = (*env)->FindClass (env,
7269 \"com/redhat/et/libguestfs/LibGuestFSException\");
7270 (*env)->ThrowNew (env, cl, msg);
7273 JNIEXPORT jlong JNICALL
7274 Java_com_redhat_et_libguestfs_GuestFS__1create
7275 (JNIEnv *env, jobject obj)
7279 g = guestfs_create ();
7281 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
7284 guestfs_set_error_handler (g, NULL, NULL);
7285 return (jlong) (long) g;
7288 JNIEXPORT void JNICALL
7289 Java_com_redhat_et_libguestfs_GuestFS__1close
7290 (JNIEnv *env, jobject obj, jlong jg)
7292 guestfs_h *g = (guestfs_h *) (long) jg;
7299 fun (name, style, _, _, _, _, _) ->
7301 (match fst style with
7302 | RErr -> pr "void ";
7303 | RInt _ -> pr "jint ";
7304 | RInt64 _ -> pr "jlong ";
7305 | RBool _ -> pr "jboolean ";
7306 | RConstString _ | RString _ -> pr "jstring ";
7307 | RStruct _ | RHashtable _ ->
7309 | RStringList _ | RStructList _ ->
7313 pr "Java_com_redhat_et_libguestfs_GuestFS_";
7314 pr "%s" (replace_str ("_" ^ name) "_" "_1");
7316 pr " (JNIEnv *env, jobject obj, jlong jg";
7323 pr ", jstring j%s" n
7325 pr ", jobjectArray j%s" n
7327 pr ", jboolean j%s" n
7333 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
7334 let error_code, no_ret =
7335 match fst style with
7336 | RErr -> pr " int r;\n"; "-1", ""
7338 | RInt _ -> pr " int r;\n"; "-1", "0"
7339 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
7340 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
7342 pr " jstring jr;\n";
7343 pr " char *r;\n"; "NULL", "NULL"
7345 pr " jobjectArray jr;\n";
7348 pr " jstring jstr;\n";
7349 pr " char **r;\n"; "NULL", "NULL"
7350 | RStruct (_, typ) ->
7351 pr " jobject jr;\n";
7353 pr " jfieldID fl;\n";
7354 pr " struct guestfs_%s *r;\n" typ; "NULL", "NULL"
7355 | RStructList (_, typ) ->
7356 pr " jobjectArray jr;\n";
7358 pr " jfieldID fl;\n";
7359 pr " jobject jfl;\n";
7360 pr " struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
7361 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
7368 pr " const char *%s;\n" n
7370 pr " int %s_len;\n" n;
7371 pr " const char **%s;\n" n
7378 (match fst style with
7379 | RStringList _ | RStructList _ -> true
7380 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
7381 | RString _ | RStruct _ | RHashtable _ -> false) ||
7382 List.exists (function StringList _ -> true | _ -> false) (snd style) in
7388 (* Get the parameters. *)
7394 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
7396 (* This is completely undocumented, but Java null becomes
7399 pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
7401 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
7402 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
7403 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7404 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7406 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
7408 pr " %s[%s_len] = NULL;\n" n n;
7411 pr " %s = j%s;\n" n n
7414 (* Make the call. *)
7415 pr " r = guestfs_%s " name;
7416 generate_call_args ~handle:"g" (snd style);
7419 (* Release the parameters. *)
7425 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7428 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7430 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7431 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7433 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
7435 pr " free (%s);\n" n
7440 (* Check for errors. *)
7441 pr " if (r == %s) {\n" error_code;
7442 pr " throw_exception (env, guestfs_last_error (g));\n";
7443 pr " return %s;\n" no_ret;
7447 (match fst style with
7449 | RInt _ -> pr " return (jint) r;\n"
7450 | RBool _ -> pr " return (jboolean) r;\n"
7451 | RInt64 _ -> pr " return (jlong) r;\n"
7452 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
7454 pr " jr = (*env)->NewStringUTF (env, r);\n";
7458 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7459 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7460 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
7461 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7462 pr " for (i = 0; i < r_len; ++i) {\n";
7463 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
7464 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7465 pr " free (r[i]);\n";
7469 | RStruct (_, typ) ->
7470 let jtyp = java_name_of_struct typ in
7471 let cols = cols_of_struct typ in
7472 generate_java_struct_return typ jtyp cols
7473 | RStructList (_, typ) ->
7474 let jtyp = java_name_of_struct typ in
7475 let cols = cols_of_struct typ in
7476 generate_java_struct_list_return typ jtyp cols
7479 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7480 pr " return NULL;\n"
7487 and generate_java_struct_return typ jtyp cols =
7488 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7489 pr " jr = (*env)->AllocObject (env, cl);\n";
7493 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7494 pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
7497 pr " char s[33];\n";
7498 pr " memcpy (s, r->%s, 32);\n" name;
7500 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7501 pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
7503 | name, (FBytes|FUInt64|FInt64) ->
7504 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7505 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7506 | name, (FUInt32|FInt32) ->
7507 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
7508 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7509 | name, FOptPercent ->
7510 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7511 pr " (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
7513 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
7514 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7519 and generate_java_struct_list_return typ jtyp cols =
7520 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7521 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7522 pr " for (i = 0; i < r->len; ++i) {\n";
7523 pr " jfl = (*env)->AllocObject (env, cl);\n";
7527 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7528 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7531 pr " char s[33];\n";
7532 pr " memcpy (s, r->val[i].%s, 32);\n" name;
7534 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7535 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7537 | name, (FBytes|FUInt64|FInt64) ->
7538 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7539 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7540 | name, (FUInt32|FInt32) ->
7541 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
7542 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7543 | name, FOptPercent ->
7544 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7545 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7547 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
7548 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7550 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7552 pr " guestfs_free_%s_list (r);\n" typ;
7555 and generate_haskell_hs () =
7556 generate_header HaskellStyle LGPLv2;
7558 (* XXX We only know how to generate partial FFI for Haskell
7559 * at the moment. Please help out!
7561 let can_generate style =
7565 | RInt64 _, _ -> true
7572 | RHashtable _, _ -> false in
7575 {-# INCLUDE <guestfs.h> #-}
7576 {-# LANGUAGE ForeignFunctionInterface #-}
7581 (* List out the names of the actions we want to export. *)
7583 fun (name, style, _, _, _, _, _) ->
7584 if can_generate style then pr ",\n %s" name
7591 import Foreign.C.Types
7593 import Control.Exception
7594 import Data.Typeable
7596 data GuestfsS = GuestfsS -- represents the opaque C struct
7597 type GuestfsP = Ptr GuestfsS -- guestfs_h *
7598 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7600 -- XXX define properly later XXX
7604 data IntBool = IntBool
7606 data StatVFS = StatVFS
7607 data Hashtable = Hashtable
7609 foreign import ccall unsafe \"guestfs_create\" c_create
7611 foreign import ccall unsafe \"&guestfs_close\" c_close
7612 :: FunPtr (GuestfsP -> IO ())
7613 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
7614 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
7616 create :: IO GuestfsH
7619 c_set_error_handler p nullPtr nullPtr
7620 h <- newForeignPtr c_close p
7623 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
7624 :: GuestfsP -> IO CString
7626 -- last_error :: GuestfsH -> IO (Maybe String)
7627 -- last_error h = do
7628 -- str <- withForeignPtr h (\\p -> c_last_error p)
7629 -- maybePeek peekCString str
7631 last_error :: GuestfsH -> IO (String)
7633 str <- withForeignPtr h (\\p -> c_last_error p)
7635 then return \"no error\"
7636 else peekCString str
7640 (* Generate wrappers for each foreign function. *)
7642 fun (name, style, _, _, _, _, _) ->
7643 if can_generate style then (
7644 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7646 generate_haskell_prototype ~handle:"GuestfsP" style;
7650 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7652 pr "%s %s = do\n" name
7653 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7655 (* Convert pointer arguments using with* functions. *)
7660 | String n -> pr "withCString %s $ \\%s -> " n n
7661 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7662 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7663 | Bool _ | Int _ -> ()
7665 (* Convert integer arguments. *)
7669 | Bool n -> sprintf "(fromBool %s)" n
7670 | Int n -> sprintf "(fromIntegral %s)" n
7671 | FileIn n | FileOut n | String n | OptString n | StringList n -> n
7673 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7674 (String.concat " " ("p" :: args));
7675 (match fst style with
7676 | RErr | RInt _ | RInt64 _ | RBool _ ->
7677 pr " if (r == -1)\n";
7679 pr " err <- last_error h\n";
7681 | RConstString _ | RString _ | RStringList _ | RStruct _
7682 | RStructList _ | RHashtable _ ->
7683 pr " if (r == nullPtr)\n";
7685 pr " err <- last_error h\n";
7688 (match fst style with
7690 pr " else return ()\n"
7692 pr " else return (fromIntegral r)\n"
7694 pr " else return (fromIntegral r)\n"
7696 pr " else return (toBool r)\n"
7703 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7709 and generate_haskell_prototype ~handle ?(hs = false) style =
7711 let string = if hs then "String" else "CString" in
7712 let int = if hs then "Int" else "CInt" in
7713 let bool = if hs then "Bool" else "CInt" in
7714 let int64 = if hs then "Integer" else "Int64" in
7718 | String _ -> pr "%s" string
7719 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7720 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7721 | Bool _ -> pr "%s" bool
7722 | Int _ -> pr "%s" int
7723 | FileIn _ -> pr "%s" string
7724 | FileOut _ -> pr "%s" string
7729 (match fst style with
7730 | RErr -> if not hs then pr "CInt"
7731 | RInt _ -> pr "%s" int
7732 | RInt64 _ -> pr "%s" int64
7733 | RBool _ -> pr "%s" bool
7734 | RConstString _ -> pr "%s" string
7735 | RString _ -> pr "%s" string
7736 | RStringList _ -> pr "[%s]" string
7737 | RStruct (_, typ) ->
7738 let name = java_name_of_struct typ in
7740 | RStructList (_, typ) ->
7741 let name = java_name_of_struct typ in
7743 | RHashtable _ -> pr "Hashtable"
7747 and generate_bindtests () =
7748 generate_header CStyle LGPLv2;
7753 #include <inttypes.h>
7756 #include \"guestfs.h\"
7757 #include \"guestfs_protocol.h\"
7759 #define error guestfs_error
7760 #define safe_calloc guestfs_safe_calloc
7761 #define safe_malloc guestfs_safe_malloc
7764 print_strings (char * const* const argv)
7769 for (argc = 0; argv[argc] != NULL; ++argc) {
7770 if (argc > 0) printf (\", \");
7771 printf (\"\\\"%%s\\\"\", argv[argc]);
7776 /* The test0 function prints its parameters to stdout. */
7780 match test_functions with
7781 | [] -> assert false
7782 | test0 :: tests -> test0, tests in
7785 let (name, style, _, _, _, _, _) = test0 in
7786 generate_prototype ~extern:false ~semicolon:false ~newline:true
7787 ~handle:"g" ~prefix:"guestfs_" name style;
7793 | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
7794 | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
7795 | StringList n -> pr " print_strings (%s);\n" n
7796 | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
7797 | Int n -> pr " printf (\"%%d\\n\", %s);\n" n
7799 pr " /* Java changes stdout line buffering so we need this: */\n";
7800 pr " fflush (stdout);\n";
7806 fun (name, style, _, _, _, _, _) ->
7807 if String.sub name (String.length name - 3) 3 <> "err" then (
7808 pr "/* Test normal return. */\n";
7809 generate_prototype ~extern:false ~semicolon:false ~newline:true
7810 ~handle:"g" ~prefix:"guestfs_" name style;
7812 (match fst style with
7817 pr " sscanf (val, \"%%d\", &r);\n";
7821 pr " sscanf (val, \"%%\" SCNi64, &r);\n";
7824 pr " return strcmp (val, \"true\") == 0;\n"
7826 (* Can't return the input string here. Return a static
7827 * string so we ensure we get a segfault if the caller
7830 pr " return \"static string\";\n"
7832 pr " return strdup (val);\n"
7834 pr " char **strs;\n";
7836 pr " sscanf (val, \"%%d\", &n);\n";
7837 pr " strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
7838 pr " for (i = 0; i < n; ++i) {\n";
7839 pr " strs[i] = safe_malloc (g, 16);\n";
7840 pr " snprintf (strs[i], 16, \"%%d\", i);\n";
7842 pr " strs[n] = NULL;\n";
7843 pr " return strs;\n"
7844 | RStruct (_, typ) ->
7845 pr " struct guestfs_%s *r;\n" typ;
7846 pr " r = safe_calloc (g, sizeof *r, 1);\n";
7848 | RStructList (_, typ) ->
7849 pr " struct guestfs_%s_list *r;\n" typ;
7850 pr " r = safe_calloc (g, sizeof *r, 1);\n";
7851 pr " sscanf (val, \"%%d\", &r->len);\n";
7852 pr " r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
7855 pr " char **strs;\n";
7857 pr " sscanf (val, \"%%d\", &n);\n";
7858 pr " strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
7859 pr " for (i = 0; i < n; ++i) {\n";
7860 pr " strs[i*2] = safe_malloc (g, 16);\n";
7861 pr " strs[i*2+1] = safe_malloc (g, 16);\n";
7862 pr " snprintf (strs[i*2], 16, \"%%d\", i);\n";
7863 pr " snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
7865 pr " strs[n*2] = NULL;\n";
7866 pr " return strs;\n"
7871 pr "/* Test error return. */\n";
7872 generate_prototype ~extern:false ~semicolon:false ~newline:true
7873 ~handle:"g" ~prefix:"guestfs_" name style;
7875 pr " error (g, \"error\");\n";
7876 (match fst style with
7877 | RErr | RInt _ | RInt64 _ | RBool _ ->
7880 | RString _ | RStringList _ | RStruct _
7883 pr " return NULL;\n"
7890 and generate_ocaml_bindtests () =
7891 generate_header OCamlStyle GPLv2;
7895 let g = Guestfs.create () in
7902 | CallString s -> "\"" ^ s ^ "\""
7903 | CallOptString None -> "None"
7904 | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
7905 | CallStringList xs ->
7906 "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
7907 | CallInt i when i >= 0 -> string_of_int i
7908 | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
7909 | CallBool b -> string_of_bool b
7914 generate_lang_bindtests (
7915 fun f args -> pr " Guestfs.%s g %s;\n" f (mkargs args)
7918 pr "print_endline \"EOF\"\n"
7920 and generate_perl_bindtests () =
7921 pr "#!/usr/bin/perl -w\n";
7922 generate_header HashStyle GPLv2;
7929 my $g = Sys::Guestfs->new ();
7933 String.concat ", " (
7936 | CallString s -> "\"" ^ s ^ "\""
7937 | CallOptString None -> "undef"
7938 | CallOptString (Some s) -> sprintf "\"%s\"" s
7939 | CallStringList xs ->
7940 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7941 | CallInt i -> string_of_int i
7942 | CallBool b -> if b then "1" else "0"
7947 generate_lang_bindtests (
7948 fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
7951 pr "print \"EOF\\n\"\n"
7953 and generate_python_bindtests () =
7954 generate_header HashStyle GPLv2;
7959 g = guestfs.GuestFS ()
7963 String.concat ", " (
7966 | CallString s -> "\"" ^ s ^ "\""
7967 | CallOptString None -> "None"
7968 | CallOptString (Some s) -> sprintf "\"%s\"" s
7969 | CallStringList xs ->
7970 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7971 | CallInt i -> string_of_int i
7972 | CallBool b -> if b then "1" else "0"
7977 generate_lang_bindtests (
7978 fun f args -> pr "g.%s (%s)\n" f (mkargs args)
7981 pr "print \"EOF\"\n"
7983 and generate_ruby_bindtests () =
7984 generate_header HashStyle GPLv2;
7989 g = Guestfs::create()
7993 String.concat ", " (
7996 | CallString s -> "\"" ^ s ^ "\""
7997 | CallOptString None -> "nil"
7998 | CallOptString (Some s) -> sprintf "\"%s\"" s
7999 | CallStringList xs ->
8000 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8001 | CallInt i -> string_of_int i
8002 | CallBool b -> string_of_bool b
8007 generate_lang_bindtests (
8008 fun f args -> pr "g.%s(%s)\n" f (mkargs args)
8011 pr "print \"EOF\\n\"\n"
8013 and generate_java_bindtests () =
8014 generate_header CStyle GPLv2;
8017 import com.redhat.et.libguestfs.*;
8019 public class Bindtests {
8020 public static void main (String[] argv)
8023 GuestFS g = new GuestFS ();
8027 String.concat ", " (
8030 | CallString s -> "\"" ^ s ^ "\""
8031 | CallOptString None -> "null"
8032 | CallOptString (Some s) -> sprintf "\"%s\"" s
8033 | CallStringList xs ->
8035 String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
8036 | CallInt i -> string_of_int i
8037 | CallBool b -> string_of_bool b
8042 generate_lang_bindtests (
8043 fun f args -> pr " g.%s (%s);\n" f (mkargs args)
8047 System.out.println (\"EOF\");
8049 catch (Exception exn) {
8050 System.err.println (exn);
8057 and generate_haskell_bindtests () =
8058 generate_header HaskellStyle GPLv2;
8061 module Bindtests where
8062 import qualified Guestfs
8072 | CallString s -> "\"" ^ s ^ "\""
8073 | CallOptString None -> "Nothing"
8074 | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
8075 | CallStringList xs ->
8076 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8077 | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
8078 | CallInt i -> string_of_int i
8079 | CallBool true -> "True"
8080 | CallBool false -> "False"
8085 generate_lang_bindtests (
8086 fun f args -> pr " Guestfs.%s g %s\n" f (mkargs args)
8089 pr " putStrLn \"EOF\"\n"
8091 (* Language-independent bindings tests - we do it this way to
8092 * ensure there is parity in testing bindings across all languages.
8094 and generate_lang_bindtests call =
8095 call "test0" [CallString "abc"; CallOptString (Some "def");
8096 CallStringList []; CallBool false;
8097 CallInt 0; CallString "123"; CallString "456"];
8098 call "test0" [CallString "abc"; CallOptString None;
8099 CallStringList []; CallBool false;
8100 CallInt 0; CallString "123"; CallString "456"];
8101 call "test0" [CallString ""; CallOptString (Some "def");
8102 CallStringList []; CallBool false;
8103 CallInt 0; CallString "123"; CallString "456"];
8104 call "test0" [CallString ""; CallOptString (Some "");
8105 CallStringList []; CallBool false;
8106 CallInt 0; CallString "123"; CallString "456"];
8107 call "test0" [CallString "abc"; CallOptString (Some "def");
8108 CallStringList ["1"]; CallBool false;
8109 CallInt 0; CallString "123"; CallString "456"];
8110 call "test0" [CallString "abc"; CallOptString (Some "def");
8111 CallStringList ["1"; "2"]; CallBool false;
8112 CallInt 0; CallString "123"; CallString "456"];
8113 call "test0" [CallString "abc"; CallOptString (Some "def");
8114 CallStringList ["1"]; CallBool true;
8115 CallInt 0; CallString "123"; CallString "456"];
8116 call "test0" [CallString "abc"; CallOptString (Some "def");
8117 CallStringList ["1"]; CallBool false;
8118 CallInt (-1); CallString "123"; CallString "456"];
8119 call "test0" [CallString "abc"; CallOptString (Some "def");
8120 CallStringList ["1"]; CallBool false;
8121 CallInt (-2); CallString "123"; CallString "456"];
8122 call "test0" [CallString "abc"; CallOptString (Some "def");
8123 CallStringList ["1"]; CallBool false;
8124 CallInt 1; CallString "123"; CallString "456"];
8125 call "test0" [CallString "abc"; CallOptString (Some "def");
8126 CallStringList ["1"]; CallBool false;
8127 CallInt 2; CallString "123"; CallString "456"];
8128 call "test0" [CallString "abc"; CallOptString (Some "def");
8129 CallStringList ["1"]; CallBool false;
8130 CallInt 4095; CallString "123"; CallString "456"];
8131 call "test0" [CallString "abc"; CallOptString (Some "def");
8132 CallStringList ["1"]; CallBool false;
8133 CallInt 0; CallString ""; CallString ""]
8135 (* XXX Add here tests of the return and error functions. *)
8137 (* This is used to generate the src/MAX_PROC_NR file which
8138 * contains the maximum procedure number, a surrogate for the
8139 * ABI version number. See src/Makefile.am for the details.
8141 and generate_max_proc_nr () =
8142 let proc_nrs = List.map (
8143 fun (_, _, proc_nr, _, _, _, _) -> proc_nr
8144 ) daemon_functions in
8146 let max_proc_nr = List.fold_left max 0 proc_nrs in
8148 pr "%d\n" max_proc_nr
8150 let output_to filename =
8151 let filename_new = filename ^ ".new" in
8152 chan := open_out filename_new;
8157 (* Is the new file different from the current file? *)
8158 if Sys.file_exists filename && files_equal filename filename_new then
8159 Unix.unlink filename_new (* same, so skip it *)
8161 (* different, overwrite old one *)
8162 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
8163 Unix.rename filename_new filename;
8164 Unix.chmod filename 0o444;
8165 printf "written %s\n%!" filename;
8174 if not (Sys.file_exists "HACKING") then (
8176 You are probably running this from the wrong directory.
8177 Run it from the top source directory using the command
8183 let close = output_to "src/guestfs_protocol.x" in
8187 let close = output_to "src/guestfs-structs.h" in
8188 generate_structs_h ();
8191 let close = output_to "src/guestfs-actions.h" in
8192 generate_actions_h ();
8195 let close = output_to "src/guestfs-actions.c" in
8196 generate_client_actions ();
8199 let close = output_to "daemon/actions.h" in
8200 generate_daemon_actions_h ();
8203 let close = output_to "daemon/stubs.c" in
8204 generate_daemon_actions ();
8207 let close = output_to "daemon/names.c" in
8208 generate_daemon_names ();
8211 let close = output_to "capitests/tests.c" in
8215 let close = output_to "src/guestfs-bindtests.c" in
8216 generate_bindtests ();
8219 let close = output_to "fish/cmds.c" in
8220 generate_fish_cmds ();
8223 let close = output_to "fish/completion.c" in
8224 generate_fish_completion ();
8227 let close = output_to "guestfs-structs.pod" in
8228 generate_structs_pod ();
8231 let close = output_to "guestfs-actions.pod" in
8232 generate_actions_pod ();
8235 let close = output_to "guestfish-actions.pod" in
8236 generate_fish_actions_pod ();
8239 let close = output_to "ocaml/guestfs.mli" in
8240 generate_ocaml_mli ();
8243 let close = output_to "ocaml/guestfs.ml" in
8244 generate_ocaml_ml ();
8247 let close = output_to "ocaml/guestfs_c_actions.c" in
8248 generate_ocaml_c ();
8251 let close = output_to "ocaml/bindtests.ml" in
8252 generate_ocaml_bindtests ();
8255 let close = output_to "perl/Guestfs.xs" in
8256 generate_perl_xs ();
8259 let close = output_to "perl/lib/Sys/Guestfs.pm" in
8260 generate_perl_pm ();
8263 let close = output_to "perl/bindtests.pl" in
8264 generate_perl_bindtests ();
8267 let close = output_to "python/guestfs-py.c" in
8268 generate_python_c ();
8271 let close = output_to "python/guestfs.py" in
8272 generate_python_py ();
8275 let close = output_to "python/bindtests.py" in
8276 generate_python_bindtests ();
8279 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
8283 let close = output_to "ruby/bindtests.rb" in
8284 generate_ruby_bindtests ();
8287 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
8288 generate_java_java ();
8293 let cols = cols_of_struct typ in
8294 let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
8295 let close = output_to filename in
8296 generate_java_struct jtyp cols;
8300 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
8304 let close = output_to "java/Bindtests.java" in
8305 generate_java_bindtests ();
8308 let close = output_to "haskell/Guestfs.hs" in
8309 generate_haskell_hs ();
8312 let close = output_to "haskell/Bindtests.hs" in
8313 generate_haskell_bindtests ();
8316 let close = output_to "src/MAX_PROC_NR" in
8317 generate_max_proc_nr ();
8320 (* Always generate this file last, and unconditionally. It's used
8321 * by the Makefile to know when we must re-run the generator.
8323 let chan = open_out "src/stamp-generator" in