3 * Copyright (C) 2009 Red Hat Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 (* This script generates a large amount of code and documentation for
21 * all the daemon actions.
23 * To add a new action there are only two files you need to change,
24 * this one to describe the interface (see the big table below), and
25 * daemon/<somefile>.c to write the implementation.
27 * After editing this file, run it (./src/generator.ml) to regenerate
28 * all the output files.
30 * IMPORTANT: This script should NOT print any warnings. If it prints
31 * warnings, you should treat them as errors.
32 * [Need to add -warn-error to ocaml command line]
40 type style = ret * args
42 (* "RErr" as a return value means an int used as a simple error
43 * indication, ie. 0 or -1.
46 (* "RInt" as a return value means an int which is -1 for error
47 * or any value >= 0 on success. Only use this for smallish
48 * positive ints (0 <= i < 2^30).
51 (* "RInt64" is the same as RInt, but is guaranteed to be able
52 * to return a full 64 bit value, _except_ that -1 means error
53 * (so -1 cannot be a valid, non-error return value).
56 (* "RBool" is a bool return value which can be true/false or
60 (* "RConstString" is a string that refers to a constant value.
61 * Try to avoid using this. In particular you cannot use this
62 * for values returned from the daemon, because there is no
63 * thread-safe way to return them in the C API.
65 | RConstString of string
66 (* "RString" and "RStringList" are caller-frees. *)
68 | RStringList of string
69 (* Some limited tuples are possible: *)
70 | RIntBool of string * string
71 (* LVM PVs, VGs and LVs. *)
78 (* Key-value pairs of untyped strings. Turns into a hashtable or
79 * dictionary in languages which support it. DON'T use this as a
80 * general "bucket" for results. Prefer a stronger typed return
81 * value if one is available, or write a custom struct. Don't use
82 * this if the list could potentially be very long, since it is
83 * inefficient. Keys should be unique. NULLs are not permitted.
85 | RHashtable of string
87 and args = argt list (* Function parameters, guestfs handle is implicit. *)
89 (* Note in future we should allow a "variable args" parameter as
90 * the final parameter, to allow commands like
91 * chmod mode file [file(s)...]
92 * This is not implemented yet, but many commands (such as chmod)
93 * are currently defined with the argument order keeping this future
94 * possibility in mind.
97 | String of string (* const char *name, cannot be NULL *)
98 | OptString of string (* const char *name, may be NULL *)
99 | StringList of string(* list of strings (each string cannot be NULL) *)
100 | Bool of string (* boolean *)
101 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
102 (* These are treated as filenames (simple string parameters) in
103 * the C API and bindings. But in the RPC protocol, we transfer
104 * the actual file content up to or down from the daemon.
105 * FileIn: local machine -> daemon (in request)
106 * FileOut: daemon -> local machine (in reply)
107 * In guestfish (only), the special name "-" means read from
108 * stdin or write to stdout.
114 | ProtocolLimitWarning (* display warning about protocol size limits *)
115 | DangerWillRobinson (* flags particularly dangerous commands *)
116 | FishAlias of string (* provide an alias for this cmd in guestfish *)
117 | FishAction of string (* call this function in guestfish *)
118 | NotInFish (* do not export via guestfish *)
119 | NotInDocs (* do not add this function to documentation *)
121 let protocol_limit_warning =
122 "Because of the message protocol, there is a transfer limit
123 of somewhere between 2MB and 4MB. To transfer large files you should use
126 let danger_will_robinson =
127 "B<This command is dangerous. Without careful use you
128 can easily destroy all your data>."
130 (* You can supply zero or as many tests as you want per API call.
132 * Note that the test environment has 3 block devices, of size 500MB,
133 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
134 * a fourth squashfs block device with some known files on it (/dev/sdd).
136 * Note for partitioning purposes, the 500MB device has 63 cylinders.
138 * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
140 * To be able to run the tests in a reasonable amount of time,
141 * the virtual machine and block devices are reused between tests.
142 * So don't try testing kill_subprocess :-x
144 * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
146 * Don't assume anything about the previous contents of the block
147 * devices. Use 'Init*' to create some initial scenarios.
149 * You can add a prerequisite clause to any individual test. This
150 * is a run-time check, which, if it fails, causes the test to be
151 * skipped. Useful if testing a command which might not work on
152 * all variations of libguestfs builds. A test that has prerequisite
153 * of 'Always' is run unconditionally.
155 * In addition, packagers can skip individual tests by setting the
156 * environment variables: eg:
157 * SKIP_TEST_<CMD>_<NUM>=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command)
158 * SKIP_TEST_<CMD>=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests)
160 type tests = (test_init * test_prereq * test) list
162 (* Run the command sequence and just expect nothing to fail. *)
164 (* Run the command sequence and expect the output of the final
165 * command to be the string.
167 | TestOutput of seq * string
168 (* Run the command sequence and expect the output of the final
169 * command to be the list of strings.
171 | TestOutputList of seq * string list
172 (* Run the command sequence and expect the output of the final
173 * command to be the list of block devices (could be either
174 * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
175 * character of each string).
177 | TestOutputListOfDevices of seq * string list
178 (* Run the command sequence and expect the output of the final
179 * command to be the integer.
181 | TestOutputInt of seq * int
182 (* Run the command sequence and expect the output of the final
183 * command to be a true value (!= 0 or != NULL).
185 | TestOutputTrue of seq
186 (* Run the command sequence and expect the output of the final
187 * command to be a false value (== 0 or == NULL, but not an error).
189 | TestOutputFalse of seq
190 (* Run the command sequence and expect the output of the final
191 * command to be a list of the given length (but don't care about
194 | TestOutputLength of seq * int
195 (* Run the command sequence and expect the output of the final
196 * command to be a structure.
198 | TestOutputStruct of seq * test_field_compare list
199 (* Run the command sequence and expect the final command (only)
202 | TestLastFail of seq
204 and test_field_compare =
205 | CompareWithInt of string * int
206 | CompareWithString of string * string
207 | CompareFieldsIntEq of string * string
208 | CompareFieldsStrEq of string * string
210 (* Test prerequisites. *)
212 (* Test always runs. *)
214 (* Test is currently disabled - eg. it fails, or it tests some
215 * unimplemented feature.
218 (* 'string' is some C code (a function body) that should return
219 * true or false. The test will run if the code returns true.
222 (* As for 'If' but the test runs _unless_ the code returns true. *)
225 (* Some initial scenarios for testing. *)
227 (* Do nothing, block devices could contain random stuff including
228 * LVM PVs, and some filesystems might be mounted. This is usually
232 (* Block devices are empty and no filesystems are mounted. *)
234 (* /dev/sda contains a single partition /dev/sda1, which is formatted
235 * as ext2, empty [except for lost+found] and mounted on /.
236 * /dev/sdb and /dev/sdc may have random content.
241 * /dev/sda1 (is a PV):
242 * /dev/VG/LV (size 8MB):
243 * formatted as ext2, empty [except for lost+found], mounted on /
244 * /dev/sdb and /dev/sdc may have random content.
248 (* Sequence of commands for testing. *)
250 and cmd = string list
252 (* Note about long descriptions: When referring to another
253 * action, use the format C<guestfs_other> (ie. the full name of
254 * the C function). This will be replaced as appropriate in other
257 * Apart from that, long descriptions are just perldoc paragraphs.
260 (* These test functions are used in the language binding tests. *)
262 let test_all_args = [
265 StringList "strlist";
272 let test_all_rets = [
273 (* except for RErr, which is tested thoroughly elsewhere *)
274 "test0rint", RInt "valout";
275 "test0rint64", RInt64 "valout";
276 "test0rbool", RBool "valout";
277 "test0rconststring", RConstString "valout";
278 "test0rstring", RString "valout";
279 "test0rstringlist", RStringList "valout";
280 "test0rintbool", RIntBool ("valout", "valout");
281 "test0rpvlist", RPVList "valout";
282 "test0rvglist", RVGList "valout";
283 "test0rlvlist", RLVList "valout";
284 "test0rstat", RStat "valout";
285 "test0rstatvfs", RStatVFS "valout";
286 "test0rhashtable", RHashtable "valout";
289 let test_functions = [
290 ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
292 "internal test function - do not use",
294 This is an internal test function which is used to test whether
295 the automatically generated bindings can handle every possible
296 parameter type correctly.
298 It echos the contents of each parameter to stdout.
300 You probably don't want to call this function.");
304 [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
306 "internal test function - do not use",
308 This is an internal test function which is used to test whether
309 the automatically generated bindings can handle every possible
310 return type correctly.
312 It converts string C<val> to the return type.
314 You probably don't want to call this function.");
315 (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
317 "internal test function - do not use",
319 This is an internal test function which is used to test whether
320 the automatically generated bindings can handle every possible
321 return type correctly.
323 This function always returns an error.
325 You probably don't want to call this function.")]
329 (* non_daemon_functions are any functions which don't get processed
330 * in the daemon, eg. functions for setting and getting local
331 * configuration values.
334 let non_daemon_functions = test_functions @ [
335 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
337 "launch the qemu subprocess",
339 Internally libguestfs is implemented by running a virtual machine
342 You should call this after configuring the handle
343 (eg. adding drives) but before performing any actions.");
345 ("wait_ready", (RErr, []), -1, [NotInFish],
347 "wait until the qemu subprocess launches",
349 Internally libguestfs is implemented by running a virtual machine
352 You should call this after C<guestfs_launch> to wait for the launch
355 ("kill_subprocess", (RErr, []), -1, [],
357 "kill the qemu subprocess",
359 This kills the qemu subprocess. You should never need to call this.");
361 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
363 "add an image to examine or modify",
365 This function adds a virtual machine disk image C<filename> to the
366 guest. The first time you call this function, the disk appears as IDE
367 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
370 You don't necessarily need to be root when using libguestfs. However
371 you obviously do need sufficient permissions to access the filename
372 for whatever operations you want to perform (ie. read access if you
373 just want to read the image or write access if you want to modify the
376 This is equivalent to the qemu parameter C<-drive file=filename,cache=off>.
378 Note that this call checks for the existence of C<filename>. This
379 stops you from specifying other types of drive which are supported
380 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
381 the general C<guestfs_config> call instead.");
383 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
385 "add a CD-ROM disk image to examine",
387 This function adds a virtual CD-ROM disk image to the guest.
389 This is equivalent to the qemu parameter C<-cdrom filename>.
391 Note that this call checks for the existence of C<filename>. This
392 stops you from specifying other types of drive which are supported
393 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
394 the general C<guestfs_config> call instead.");
396 ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
398 "add a drive in snapshot mode (read-only)",
400 This adds a drive in snapshot mode, making it effectively
403 Note that writes to the device are allowed, and will be seen for
404 the duration of the guestfs handle, but they are written
405 to a temporary file which is discarded as soon as the guestfs
406 handle is closed. We don't currently have any method to enable
407 changes to be committed, although qemu can support this.
409 This is equivalent to the qemu parameter
410 C<-drive file=filename,snapshot=on>.
412 Note that this call checks for the existence of C<filename>. This
413 stops you from specifying other types of drive which are supported
414 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
415 the general C<guestfs_config> call instead.");
417 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
419 "add qemu parameters",
421 This can be used to add arbitrary qemu command line parameters
422 of the form C<-param value>. Actually it's not quite arbitrary - we
423 prevent you from setting some parameters which would interfere with
424 parameters that we use.
426 The first character of C<param> string must be a C<-> (dash).
428 C<value> can be NULL.");
430 ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
432 "set the qemu binary",
434 Set the qemu binary that we will use.
436 The default is chosen when the library was compiled by the
439 You can also override this by setting the C<LIBGUESTFS_QEMU>
440 environment variable.
442 Setting C<qemu> to C<NULL> restores the default qemu binary.");
444 ("get_qemu", (RConstString "qemu", []), -1, [],
446 "get the qemu binary",
448 Return the current qemu binary.
450 This is always non-NULL. If it wasn't set already, then this will
451 return the default qemu binary name.");
453 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
455 "set the search path",
457 Set the path that libguestfs searches for kernel and initrd.img.
459 The default is C<$libdir/guestfs> unless overridden by setting
460 C<LIBGUESTFS_PATH> environment variable.
462 Setting C<path> to C<NULL> restores the default path.");
464 ("get_path", (RConstString "path", []), -1, [],
466 "get the search path",
468 Return the current search path.
470 This is always non-NULL. If it wasn't set already, then this will
471 return the default path.");
473 ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
475 "add options to kernel command line",
477 This function is used to add additional options to the
478 guest kernel command line.
480 The default is C<NULL> unless overridden by setting
481 C<LIBGUESTFS_APPEND> environment variable.
483 Setting C<append> to C<NULL> means I<no> additional options
484 are passed (libguestfs always adds a few of its own).");
486 ("get_append", (RConstString "append", []), -1, [],
488 "get the additional kernel options",
490 Return the additional kernel options which are added to the
491 guest kernel command line.
493 If C<NULL> then no options are added.");
495 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
499 If C<autosync> is true, this enables autosync. Libguestfs will make a
500 best effort attempt to run C<guestfs_umount_all> followed by
501 C<guestfs_sync> when the handle is closed
502 (also if the program exits without closing handles).
504 This is disabled by default (except in guestfish where it is
505 enabled by default).");
507 ("get_autosync", (RBool "autosync", []), -1, [],
511 Get the autosync flag.");
513 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
517 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
519 Verbose messages are disabled unless the environment variable
520 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
522 ("get_verbose", (RBool "verbose", []), -1, [],
526 This returns the verbose messages flag.");
528 ("is_ready", (RBool "ready", []), -1, [],
530 "is ready to accept commands",
532 This returns true iff this handle is ready to accept commands
533 (in the C<READY> state).
535 For more information on states, see L<guestfs(3)>.");
537 ("is_config", (RBool "config", []), -1, [],
539 "is in configuration state",
541 This returns true iff this handle is being configured
542 (in the C<CONFIG> state).
544 For more information on states, see L<guestfs(3)>.");
546 ("is_launching", (RBool "launching", []), -1, [],
548 "is launching subprocess",
550 This returns true iff this handle is launching the subprocess
551 (in the C<LAUNCHING> state).
553 For more information on states, see L<guestfs(3)>.");
555 ("is_busy", (RBool "busy", []), -1, [],
557 "is busy processing a command",
559 This returns true iff this handle is busy processing a command
560 (in the C<BUSY> state).
562 For more information on states, see L<guestfs(3)>.");
564 ("get_state", (RInt "state", []), -1, [],
566 "get the current state",
568 This returns the current state as an opaque integer. This is
569 only useful for printing debug and internal error messages.
571 For more information on states, see L<guestfs(3)>.");
573 ("set_busy", (RErr, []), -1, [NotInFish],
577 This sets the state to C<BUSY>. This is only used when implementing
578 actions using the low-level API.
580 For more information on states, see L<guestfs(3)>.");
582 ("set_ready", (RErr, []), -1, [NotInFish],
584 "set state to ready",
586 This sets the state to C<READY>. This is only used when implementing
587 actions using the low-level API.
589 For more information on states, see L<guestfs(3)>.");
591 ("end_busy", (RErr, []), -1, [NotInFish],
593 "leave the busy state",
595 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
596 state as is. This is only used when implementing
597 actions using the low-level API.
599 For more information on states, see L<guestfs(3)>.");
603 (* daemon_functions are any functions which cause some action
604 * to take place in the daemon.
607 let daemon_functions = [
608 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
609 [InitEmpty, Always, TestOutput (
610 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
611 ["mkfs"; "ext2"; "/dev/sda1"];
612 ["mount"; "/dev/sda1"; "/"];
613 ["write_file"; "/new"; "new file contents"; "0"];
614 ["cat"; "/new"]], "new file contents")],
615 "mount a guest disk at a position in the filesystem",
617 Mount a guest disk at a position in the filesystem. Block devices
618 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
619 the guest. If those block devices contain partitions, they will have
620 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
623 The rules are the same as for L<mount(2)>: A filesystem must
624 first be mounted on C</> before others can be mounted. Other
625 filesystems can only be mounted on directories which already
628 The mounted filesystem is writable, if we have sufficient permissions
629 on the underlying device.
631 The filesystem options C<sync> and C<noatime> are set with this
632 call, in order to improve reliability.");
634 ("sync", (RErr, []), 2, [],
635 [ InitEmpty, Always, TestRun [["sync"]]],
636 "sync disks, writes are flushed through to the disk image",
638 This syncs the disk, so that any writes are flushed through to the
639 underlying disk image.
641 You should always call this if you have modified a disk image, before
642 closing the handle.");
644 ("touch", (RErr, [String "path"]), 3, [],
645 [InitBasicFS, Always, TestOutputTrue (
647 ["exists"; "/new"]])],
648 "update file timestamps or create a new file",
650 Touch acts like the L<touch(1)> command. It can be used to
651 update the timestamps on a file, or, if the file does not exist,
652 to create a new zero-length file.");
654 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
655 [InitBasicFS, Always, TestOutput (
656 [["write_file"; "/new"; "new file contents"; "0"];
657 ["cat"; "/new"]], "new file contents")],
658 "list the contents of a file",
660 Return the contents of the file named C<path>.
662 Note that this function cannot correctly handle binary files
663 (specifically, files containing C<\\0> character which is treated
664 as end of string). For those you need to use the C<guestfs_download>
665 function which has a more complex interface.");
667 ("ll", (RString "listing", [String "directory"]), 5, [],
668 [], (* XXX Tricky to test because it depends on the exact format
669 * of the 'ls -l' command, which changes between F10 and F11.
671 "list the files in a directory (long format)",
673 List the files in C<directory> (relative to the root directory,
674 there is no cwd) in the format of 'ls -la'.
676 This command is mostly useful for interactive sessions. It
677 is I<not> intended that you try to parse the output string.");
679 ("ls", (RStringList "listing", [String "directory"]), 6, [],
680 [InitBasicFS, Always, TestOutputList (
683 ["touch"; "/newest"];
684 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
685 "list the files in a directory",
687 List the files in C<directory> (relative to the root directory,
688 there is no cwd). The '.' and '..' entries are not returned, but
689 hidden files are shown.
691 This command is mostly useful for interactive sessions. Programs
692 should probably use C<guestfs_readdir> instead.");
694 ("list_devices", (RStringList "devices", []), 7, [],
695 [InitEmpty, Always, TestOutputListOfDevices (
696 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
697 "list the block devices",
699 List all the block devices.
701 The full block device names are returned, eg. C</dev/sda>");
703 ("list_partitions", (RStringList "partitions", []), 8, [],
704 [InitBasicFS, Always, TestOutputListOfDevices (
705 [["list_partitions"]], ["/dev/sda1"]);
706 InitEmpty, Always, TestOutputListOfDevices (
707 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
708 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
709 "list the partitions",
711 List all the partitions detected on all block devices.
713 The full partition device names are returned, eg. C</dev/sda1>
715 This does not return logical volumes. For that you will need to
716 call C<guestfs_lvs>.");
718 ("pvs", (RStringList "physvols", []), 9, [],
719 [InitBasicFSonLVM, Always, TestOutputListOfDevices (
720 [["pvs"]], ["/dev/sda1"]);
721 InitEmpty, Always, TestOutputListOfDevices (
722 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
723 ["pvcreate"; "/dev/sda1"];
724 ["pvcreate"; "/dev/sda2"];
725 ["pvcreate"; "/dev/sda3"];
726 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
727 "list the LVM physical volumes (PVs)",
729 List all the physical volumes detected. This is the equivalent
730 of the L<pvs(8)> command.
732 This returns a list of just the device names that contain
733 PVs (eg. C</dev/sda2>).
735 See also C<guestfs_pvs_full>.");
737 ("vgs", (RStringList "volgroups", []), 10, [],
738 [InitBasicFSonLVM, Always, TestOutputList (
740 InitEmpty, Always, TestOutputList (
741 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
742 ["pvcreate"; "/dev/sda1"];
743 ["pvcreate"; "/dev/sda2"];
744 ["pvcreate"; "/dev/sda3"];
745 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
746 ["vgcreate"; "VG2"; "/dev/sda3"];
747 ["vgs"]], ["VG1"; "VG2"])],
748 "list the LVM volume groups (VGs)",
750 List all the volumes groups detected. This is the equivalent
751 of the L<vgs(8)> command.
753 This returns a list of just the volume group names that were
754 detected (eg. C<VolGroup00>).
756 See also C<guestfs_vgs_full>.");
758 ("lvs", (RStringList "logvols", []), 11, [],
759 [InitBasicFSonLVM, Always, TestOutputList (
760 [["lvs"]], ["/dev/VG/LV"]);
761 InitEmpty, Always, TestOutputList (
762 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
763 ["pvcreate"; "/dev/sda1"];
764 ["pvcreate"; "/dev/sda2"];
765 ["pvcreate"; "/dev/sda3"];
766 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
767 ["vgcreate"; "VG2"; "/dev/sda3"];
768 ["lvcreate"; "LV1"; "VG1"; "50"];
769 ["lvcreate"; "LV2"; "VG1"; "50"];
770 ["lvcreate"; "LV3"; "VG2"; "50"];
771 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
772 "list the LVM logical volumes (LVs)",
774 List all the logical volumes detected. This is the equivalent
775 of the L<lvs(8)> command.
777 This returns a list of the logical volume device names
778 (eg. C</dev/VolGroup00/LogVol00>).
780 See also C<guestfs_lvs_full>.");
782 ("pvs_full", (RPVList "physvols", []), 12, [],
783 [], (* XXX how to test? *)
784 "list the LVM physical volumes (PVs)",
786 List all the physical volumes detected. This is the equivalent
787 of the L<pvs(8)> command. The \"full\" version includes all fields.");
789 ("vgs_full", (RVGList "volgroups", []), 13, [],
790 [], (* XXX how to test? *)
791 "list the LVM volume groups (VGs)",
793 List all the volumes groups detected. This is the equivalent
794 of the L<vgs(8)> command. The \"full\" version includes all fields.");
796 ("lvs_full", (RLVList "logvols", []), 14, [],
797 [], (* XXX how to test? *)
798 "list the LVM logical volumes (LVs)",
800 List all the logical volumes detected. This is the equivalent
801 of the L<lvs(8)> command. The \"full\" version includes all fields.");
803 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
804 [InitBasicFS, Always, TestOutputList (
805 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
806 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
807 InitBasicFS, Always, TestOutputList (
808 [["write_file"; "/new"; ""; "0"];
809 ["read_lines"; "/new"]], [])],
810 "read file as lines",
812 Return the contents of the file named C<path>.
814 The file contents are returned as a list of lines. Trailing
815 C<LF> and C<CRLF> character sequences are I<not> returned.
817 Note that this function cannot correctly handle binary files
818 (specifically, files containing C<\\0> character which is treated
819 as end of line). For those you need to use the C<guestfs_read_file>
820 function which has a more complex interface.");
822 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
823 [], (* XXX Augeas code needs tests. *)
824 "create a new Augeas handle",
826 Create a new Augeas handle for editing configuration files.
827 If there was any previous Augeas handle associated with this
828 guestfs session, then it is closed.
830 You must call this before using any other C<guestfs_aug_*>
833 C<root> is the filesystem root. C<root> must not be NULL,
836 The flags are the same as the flags defined in
837 E<lt>augeas.hE<gt>, the logical I<or> of the following
842 =item C<AUG_SAVE_BACKUP> = 1
844 Keep the original file with a C<.augsave> extension.
846 =item C<AUG_SAVE_NEWFILE> = 2
848 Save changes into a file with extension C<.augnew>, and
849 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
851 =item C<AUG_TYPE_CHECK> = 4
853 Typecheck lenses (can be expensive).
855 =item C<AUG_NO_STDINC> = 8
857 Do not use standard load path for modules.
859 =item C<AUG_SAVE_NOOP> = 16
861 Make save a no-op, just record what would have been changed.
863 =item C<AUG_NO_LOAD> = 32
865 Do not load the tree in C<guestfs_aug_init>.
869 To close the handle, you can call C<guestfs_aug_close>.
871 To find out more about Augeas, see L<http://augeas.net/>.");
873 ("aug_close", (RErr, []), 26, [],
874 [], (* XXX Augeas code needs tests. *)
875 "close the current Augeas handle",
877 Close the current Augeas handle and free up any resources
878 used by it. After calling this, you have to call
879 C<guestfs_aug_init> again before you can use any other
882 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
883 [], (* XXX Augeas code needs tests. *)
884 "define an Augeas variable",
886 Defines an Augeas variable C<name> whose value is the result
887 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
890 On success this returns the number of nodes in C<expr>, or
891 C<0> if C<expr> evaluates to something which is not a nodeset.");
893 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
894 [], (* XXX Augeas code needs tests. *)
895 "define an Augeas node",
897 Defines a variable C<name> whose value is the result of
900 If C<expr> evaluates to an empty nodeset, a node is created,
901 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
902 C<name> will be the nodeset containing that single node.
904 On success this returns a pair containing the
905 number of nodes in the nodeset, and a boolean flag
906 if a node was created.");
908 ("aug_get", (RString "val", [String "path"]), 19, [],
909 [], (* XXX Augeas code needs tests. *)
910 "look up the value of an Augeas path",
912 Look up the value associated with C<path>. If C<path>
913 matches exactly one node, the C<value> is returned.");
915 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
916 [], (* XXX Augeas code needs tests. *)
917 "set Augeas path to value",
919 Set the value associated with C<path> to C<value>.");
921 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
922 [], (* XXX Augeas code needs tests. *)
923 "insert a sibling Augeas node",
925 Create a new sibling C<label> for C<path>, inserting it into
926 the tree before or after C<path> (depending on the boolean
929 C<path> must match exactly one existing node in the tree, and
930 C<label> must be a label, ie. not contain C</>, C<*> or end
931 with a bracketed index C<[N]>.");
933 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
934 [], (* XXX Augeas code needs tests. *)
935 "remove an Augeas path",
937 Remove C<path> and all of its children.
939 On success this returns the number of entries which were removed.");
941 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
942 [], (* XXX Augeas code needs tests. *)
945 Move the node C<src> to C<dest>. C<src> must match exactly
946 one node. C<dest> is overwritten if it exists.");
948 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
949 [], (* XXX Augeas code needs tests. *)
950 "return Augeas nodes which match path",
952 Returns a list of paths which match the path expression C<path>.
953 The returned paths are sufficiently qualified so that they match
954 exactly one node in the current tree.");
956 ("aug_save", (RErr, []), 25, [],
957 [], (* XXX Augeas code needs tests. *)
958 "write all pending Augeas changes to disk",
960 This writes all pending changes to disk.
962 The flags which were passed to C<guestfs_aug_init> affect exactly
963 how files are saved.");
965 ("aug_load", (RErr, []), 27, [],
966 [], (* XXX Augeas code needs tests. *)
967 "load files into the tree",
969 Load files into the tree.
971 See C<aug_load> in the Augeas documentation for the full gory
974 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
975 [], (* XXX Augeas code needs tests. *)
976 "list Augeas nodes under a path",
978 This is just a shortcut for listing C<guestfs_aug_match>
979 C<path/*> and sorting the resulting nodes into alphabetical order.");
981 ("rm", (RErr, [String "path"]), 29, [],
982 [InitBasicFS, Always, TestRun
985 InitBasicFS, Always, TestLastFail
987 InitBasicFS, Always, TestLastFail
992 Remove the single file C<path>.");
994 ("rmdir", (RErr, [String "path"]), 30, [],
995 [InitBasicFS, Always, TestRun
998 InitBasicFS, Always, TestLastFail
1000 InitBasicFS, Always, TestLastFail
1002 ["rmdir"; "/new"]]],
1003 "remove a directory",
1005 Remove the single directory C<path>.");
1007 ("rm_rf", (RErr, [String "path"]), 31, [],
1008 [InitBasicFS, Always, TestOutputFalse
1010 ["mkdir"; "/new/foo"];
1011 ["touch"; "/new/foo/bar"];
1013 ["exists"; "/new"]]],
1014 "remove a file or directory recursively",
1016 Remove the file or directory C<path>, recursively removing the
1017 contents if its a directory. This is like the C<rm -rf> shell
1020 ("mkdir", (RErr, [String "path"]), 32, [],
1021 [InitBasicFS, Always, TestOutputTrue
1023 ["is_dir"; "/new"]];
1024 InitBasicFS, Always, TestLastFail
1025 [["mkdir"; "/new/foo/bar"]]],
1026 "create a directory",
1028 Create a directory named C<path>.");
1030 ("mkdir_p", (RErr, [String "path"]), 33, [],
1031 [InitBasicFS, Always, TestOutputTrue
1032 [["mkdir_p"; "/new/foo/bar"];
1033 ["is_dir"; "/new/foo/bar"]];
1034 InitBasicFS, Always, TestOutputTrue
1035 [["mkdir_p"; "/new/foo/bar"];
1036 ["is_dir"; "/new/foo"]];
1037 InitBasicFS, Always, TestOutputTrue
1038 [["mkdir_p"; "/new/foo/bar"];
1039 ["is_dir"; "/new"]];
1040 (* Regression tests for RHBZ#503133: *)
1041 InitBasicFS, Always, TestRun
1043 ["mkdir_p"; "/new"]];
1044 InitBasicFS, Always, TestLastFail
1046 ["mkdir_p"; "/new"]]],
1047 "create a directory and parents",
1049 Create a directory named C<path>, creating any parent directories
1050 as necessary. This is like the C<mkdir -p> shell command.");
1052 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1053 [], (* XXX Need stat command to test *)
1056 Change the mode (permissions) of C<path> to C<mode>. Only
1057 numeric modes are supported.");
1059 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1060 [], (* XXX Need stat command to test *)
1061 "change file owner and group",
1063 Change the file owner to C<owner> and group to C<group>.
1065 Only numeric uid and gid are supported. If you want to use
1066 names, you will need to locate and parse the password file
1067 yourself (Augeas support makes this relatively easy).");
1069 ("exists", (RBool "existsflag", [String "path"]), 36, [],
1070 [InitBasicFS, Always, TestOutputTrue (
1072 ["exists"; "/new"]]);
1073 InitBasicFS, Always, TestOutputTrue (
1075 ["exists"; "/new"]])],
1076 "test if file or directory exists",
1078 This returns C<true> if and only if there is a file, directory
1079 (or anything) with the given C<path> name.
1081 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1083 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1084 [InitBasicFS, Always, TestOutputTrue (
1086 ["is_file"; "/new"]]);
1087 InitBasicFS, Always, TestOutputFalse (
1089 ["is_file"; "/new"]])],
1090 "test if file exists",
1092 This returns C<true> if and only if there is a file
1093 with the given C<path> name. Note that it returns false for
1094 other objects like directories.
1096 See also C<guestfs_stat>.");
1098 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1099 [InitBasicFS, Always, TestOutputFalse (
1101 ["is_dir"; "/new"]]);
1102 InitBasicFS, Always, TestOutputTrue (
1104 ["is_dir"; "/new"]])],
1105 "test if file exists",
1107 This returns C<true> if and only if there is a directory
1108 with the given C<path> name. Note that it returns false for
1109 other objects like files.
1111 See also C<guestfs_stat>.");
1113 ("pvcreate", (RErr, [String "device"]), 39, [],
1114 [InitEmpty, Always, TestOutputListOfDevices (
1115 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1116 ["pvcreate"; "/dev/sda1"];
1117 ["pvcreate"; "/dev/sda2"];
1118 ["pvcreate"; "/dev/sda3"];
1119 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1120 "create an LVM physical volume",
1122 This creates an LVM physical volume on the named C<device>,
1123 where C<device> should usually be a partition name such
1126 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1127 [InitEmpty, Always, TestOutputList (
1128 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1129 ["pvcreate"; "/dev/sda1"];
1130 ["pvcreate"; "/dev/sda2"];
1131 ["pvcreate"; "/dev/sda3"];
1132 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1133 ["vgcreate"; "VG2"; "/dev/sda3"];
1134 ["vgs"]], ["VG1"; "VG2"])],
1135 "create an LVM volume group",
1137 This creates an LVM volume group called C<volgroup>
1138 from the non-empty list of physical volumes C<physvols>.");
1140 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1141 [InitEmpty, Always, TestOutputList (
1142 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1143 ["pvcreate"; "/dev/sda1"];
1144 ["pvcreate"; "/dev/sda2"];
1145 ["pvcreate"; "/dev/sda3"];
1146 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1147 ["vgcreate"; "VG2"; "/dev/sda3"];
1148 ["lvcreate"; "LV1"; "VG1"; "50"];
1149 ["lvcreate"; "LV2"; "VG1"; "50"];
1150 ["lvcreate"; "LV3"; "VG2"; "50"];
1151 ["lvcreate"; "LV4"; "VG2"; "50"];
1152 ["lvcreate"; "LV5"; "VG2"; "50"];
1154 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1155 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1156 "create an LVM volume group",
1158 This creates an LVM volume group called C<logvol>
1159 on the volume group C<volgroup>, with C<size> megabytes.");
1161 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1162 [InitEmpty, Always, TestOutput (
1163 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1164 ["mkfs"; "ext2"; "/dev/sda1"];
1165 ["mount"; "/dev/sda1"; "/"];
1166 ["write_file"; "/new"; "new file contents"; "0"];
1167 ["cat"; "/new"]], "new file contents")],
1168 "make a filesystem",
1170 This creates a filesystem on C<device> (usually a partition
1171 or LVM logical volume). The filesystem type is C<fstype>, for
1174 ("sfdisk", (RErr, [String "device";
1175 Int "cyls"; Int "heads"; Int "sectors";
1176 StringList "lines"]), 43, [DangerWillRobinson],
1178 "create partitions on a block device",
1180 This is a direct interface to the L<sfdisk(8)> program for creating
1181 partitions on block devices.
1183 C<device> should be a block device, for example C</dev/sda>.
1185 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1186 and sectors on the device, which are passed directly to sfdisk as
1187 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
1188 of these, then the corresponding parameter is omitted. Usually for
1189 'large' disks, you can just pass C<0> for these, but for small
1190 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1191 out the right geometry and you will need to tell it.
1193 C<lines> is a list of lines that we feed to C<sfdisk>. For more
1194 information refer to the L<sfdisk(8)> manpage.
1196 To create a single partition occupying the whole disk, you would
1197 pass C<lines> as a single element list, when the single element being
1198 the string C<,> (comma).
1200 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1202 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1203 [InitBasicFS, Always, TestOutput (
1204 [["write_file"; "/new"; "new file contents"; "0"];
1205 ["cat"; "/new"]], "new file contents");
1206 InitBasicFS, Always, TestOutput (
1207 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1208 ["cat"; "/new"]], "\nnew file contents\n");
1209 InitBasicFS, Always, TestOutput (
1210 [["write_file"; "/new"; "\n\n"; "0"];
1211 ["cat"; "/new"]], "\n\n");
1212 InitBasicFS, Always, TestOutput (
1213 [["write_file"; "/new"; ""; "0"];
1214 ["cat"; "/new"]], "");
1215 InitBasicFS, Always, TestOutput (
1216 [["write_file"; "/new"; "\n\n\n"; "0"];
1217 ["cat"; "/new"]], "\n\n\n");
1218 InitBasicFS, Always, TestOutput (
1219 [["write_file"; "/new"; "\n"; "0"];
1220 ["cat"; "/new"]], "\n")],
1223 This call creates a file called C<path>. The contents of the
1224 file is the string C<content> (which can contain any 8 bit data),
1225 with length C<size>.
1227 As a special case, if C<size> is C<0>
1228 then the length is calculated using C<strlen> (so in this case
1229 the content cannot contain embedded ASCII NULs).
1231 I<NB.> Owing to a bug, writing content containing ASCII NUL
1232 characters does I<not> work, even if the length is specified.
1233 We hope to resolve this bug in a future version. In the meantime
1234 use C<guestfs_upload>.");
1236 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1237 [InitEmpty, Always, TestOutputListOfDevices (
1238 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1239 ["mkfs"; "ext2"; "/dev/sda1"];
1240 ["mount"; "/dev/sda1"; "/"];
1241 ["mounts"]], ["/dev/sda1"]);
1242 InitEmpty, Always, TestOutputList (
1243 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1244 ["mkfs"; "ext2"; "/dev/sda1"];
1245 ["mount"; "/dev/sda1"; "/"];
1248 "unmount a filesystem",
1250 This unmounts the given filesystem. The filesystem may be
1251 specified either by its mountpoint (path) or the device which
1252 contains the filesystem.");
1254 ("mounts", (RStringList "devices", []), 46, [],
1255 [InitBasicFS, Always, TestOutputListOfDevices (
1256 [["mounts"]], ["/dev/sda1"])],
1257 "show mounted filesystems",
1259 This returns the list of currently mounted filesystems. It returns
1260 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1262 Some internal mounts are not shown.");
1264 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1265 [InitBasicFS, Always, TestOutputList (
1268 (* check that umount_all can unmount nested mounts correctly: *)
1269 InitEmpty, Always, TestOutputList (
1270 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1271 ["mkfs"; "ext2"; "/dev/sda1"];
1272 ["mkfs"; "ext2"; "/dev/sda2"];
1273 ["mkfs"; "ext2"; "/dev/sda3"];
1274 ["mount"; "/dev/sda1"; "/"];
1276 ["mount"; "/dev/sda2"; "/mp1"];
1277 ["mkdir"; "/mp1/mp2"];
1278 ["mount"; "/dev/sda3"; "/mp1/mp2"];
1279 ["mkdir"; "/mp1/mp2/mp3"];
1282 "unmount all filesystems",
1284 This unmounts all mounted filesystems.
1286 Some internal mounts are not unmounted by this call.");
1288 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1290 "remove all LVM LVs, VGs and PVs",
1292 This command removes all LVM logical volumes, volume groups
1293 and physical volumes.");
1295 ("file", (RString "description", [String "path"]), 49, [],
1296 [InitBasicFS, Always, TestOutput (
1298 ["file"; "/new"]], "empty");
1299 InitBasicFS, Always, TestOutput (
1300 [["write_file"; "/new"; "some content\n"; "0"];
1301 ["file"; "/new"]], "ASCII text");
1302 InitBasicFS, Always, TestLastFail (
1303 [["file"; "/nofile"]])],
1304 "determine file type",
1306 This call uses the standard L<file(1)> command to determine
1307 the type or contents of the file. This also works on devices,
1308 for example to find out whether a partition contains a filesystem.
1310 The exact command which runs is C<file -bsL path>. Note in
1311 particular that the filename is not prepended to the output
1312 (the C<-b> option).");
1314 ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1315 [InitBasicFS, Always, TestOutput (
1316 [["upload"; "test-command"; "/test-command"];
1317 ["chmod"; "493"; "/test-command"];
1318 ["command"; "/test-command 1"]], "Result1");
1319 InitBasicFS, Always, TestOutput (
1320 [["upload"; "test-command"; "/test-command"];
1321 ["chmod"; "493"; "/test-command"];
1322 ["command"; "/test-command 2"]], "Result2\n");
1323 InitBasicFS, Always, TestOutput (
1324 [["upload"; "test-command"; "/test-command"];
1325 ["chmod"; "493"; "/test-command"];
1326 ["command"; "/test-command 3"]], "\nResult3");
1327 InitBasicFS, Always, TestOutput (
1328 [["upload"; "test-command"; "/test-command"];
1329 ["chmod"; "493"; "/test-command"];
1330 ["command"; "/test-command 4"]], "\nResult4\n");
1331 InitBasicFS, Always, TestOutput (
1332 [["upload"; "test-command"; "/test-command"];
1333 ["chmod"; "493"; "/test-command"];
1334 ["command"; "/test-command 5"]], "\nResult5\n\n");
1335 InitBasicFS, Always, TestOutput (
1336 [["upload"; "test-command"; "/test-command"];
1337 ["chmod"; "493"; "/test-command"];
1338 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1339 InitBasicFS, Always, TestOutput (
1340 [["upload"; "test-command"; "/test-command"];
1341 ["chmod"; "493"; "/test-command"];
1342 ["command"; "/test-command 7"]], "");
1343 InitBasicFS, Always, TestOutput (
1344 [["upload"; "test-command"; "/test-command"];
1345 ["chmod"; "493"; "/test-command"];
1346 ["command"; "/test-command 8"]], "\n");
1347 InitBasicFS, Always, TestOutput (
1348 [["upload"; "test-command"; "/test-command"];
1349 ["chmod"; "493"; "/test-command"];
1350 ["command"; "/test-command 9"]], "\n\n");
1351 InitBasicFS, Always, TestOutput (
1352 [["upload"; "test-command"; "/test-command"];
1353 ["chmod"; "493"; "/test-command"];
1354 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1355 InitBasicFS, Always, TestOutput (
1356 [["upload"; "test-command"; "/test-command"];
1357 ["chmod"; "493"; "/test-command"];
1358 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1359 InitBasicFS, Always, TestLastFail (
1360 [["upload"; "test-command"; "/test-command"];
1361 ["chmod"; "493"; "/test-command"];
1362 ["command"; "/test-command"]])],
1363 "run a command from the guest filesystem",
1365 This call runs a command from the guest filesystem. The
1366 filesystem must be mounted, and must contain a compatible
1367 operating system (ie. something Linux, with the same
1368 or compatible processor architecture).
1370 The single parameter is an argv-style list of arguments.
1371 The first element is the name of the program to run.
1372 Subsequent elements are parameters. The list must be
1373 non-empty (ie. must contain a program name). Note that
1374 the command runs directly, and is I<not> invoked via
1375 the shell (see C<guestfs_sh>).
1377 The return value is anything printed to I<stdout> by
1380 If the command returns a non-zero exit status, then
1381 this function returns an error message. The error message
1382 string is the content of I<stderr> from the command.
1384 The C<$PATH> environment variable will contain at least
1385 C</usr/bin> and C</bin>. If you require a program from
1386 another location, you should provide the full path in the
1389 Shared libraries and data files required by the program
1390 must be available on filesystems which are mounted in the
1391 correct places. It is the caller's responsibility to ensure
1392 all filesystems that are needed are mounted at the right
1395 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1396 [InitBasicFS, Always, TestOutputList (
1397 [["upload"; "test-command"; "/test-command"];
1398 ["chmod"; "493"; "/test-command"];
1399 ["command_lines"; "/test-command 1"]], ["Result1"]);
1400 InitBasicFS, Always, TestOutputList (
1401 [["upload"; "test-command"; "/test-command"];
1402 ["chmod"; "493"; "/test-command"];
1403 ["command_lines"; "/test-command 2"]], ["Result2"]);
1404 InitBasicFS, Always, TestOutputList (
1405 [["upload"; "test-command"; "/test-command"];
1406 ["chmod"; "493"; "/test-command"];
1407 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1408 InitBasicFS, Always, TestOutputList (
1409 [["upload"; "test-command"; "/test-command"];
1410 ["chmod"; "493"; "/test-command"];
1411 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1412 InitBasicFS, Always, TestOutputList (
1413 [["upload"; "test-command"; "/test-command"];
1414 ["chmod"; "493"; "/test-command"];
1415 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1416 InitBasicFS, Always, TestOutputList (
1417 [["upload"; "test-command"; "/test-command"];
1418 ["chmod"; "493"; "/test-command"];
1419 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1420 InitBasicFS, Always, TestOutputList (
1421 [["upload"; "test-command"; "/test-command"];
1422 ["chmod"; "493"; "/test-command"];
1423 ["command_lines"; "/test-command 7"]], []);
1424 InitBasicFS, Always, TestOutputList (
1425 [["upload"; "test-command"; "/test-command"];
1426 ["chmod"; "493"; "/test-command"];
1427 ["command_lines"; "/test-command 8"]], [""]);
1428 InitBasicFS, Always, TestOutputList (
1429 [["upload"; "test-command"; "/test-command"];
1430 ["chmod"; "493"; "/test-command"];
1431 ["command_lines"; "/test-command 9"]], ["";""]);
1432 InitBasicFS, Always, TestOutputList (
1433 [["upload"; "test-command"; "/test-command"];
1434 ["chmod"; "493"; "/test-command"];
1435 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1436 InitBasicFS, Always, TestOutputList (
1437 [["upload"; "test-command"; "/test-command"];
1438 ["chmod"; "493"; "/test-command"];
1439 ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1440 "run a command, returning lines",
1442 This is the same as C<guestfs_command>, but splits the
1443 result into a list of lines.
1445 See also: C<guestfs_sh_lines>");
1447 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1448 [InitBasicFS, Always, TestOutputStruct (
1450 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1451 "get file information",
1453 Returns file information for the given C<path>.
1455 This is the same as the C<stat(2)> system call.");
1457 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1458 [InitBasicFS, Always, TestOutputStruct (
1460 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1461 "get file information for a symbolic link",
1463 Returns file information for the given C<path>.
1465 This is the same as C<guestfs_stat> except that if C<path>
1466 is a symbolic link, then the link is stat-ed, not the file it
1469 This is the same as the C<lstat(2)> system call.");
1471 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1472 [InitBasicFS, Always, TestOutputStruct (
1473 [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1474 CompareWithInt ("blocks", 490020);
1475 CompareWithInt ("bsize", 1024)])],
1476 "get file system statistics",
1478 Returns file system statistics for any mounted file system.
1479 C<path> should be a file or directory in the mounted file system
1480 (typically it is the mount point itself, but it doesn't need to be).
1482 This is the same as the C<statvfs(2)> system call.");
1484 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1486 "get ext2/ext3/ext4 superblock details",
1488 This returns the contents of the ext2, ext3 or ext4 filesystem
1489 superblock on C<device>.
1491 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1492 manpage for more details. The list of fields returned isn't
1493 clearly defined, and depends on both the version of C<tune2fs>
1494 that libguestfs was built against, and the filesystem itself.");
1496 ("blockdev_setro", (RErr, [String "device"]), 56, [],
1497 [InitEmpty, Always, TestOutputTrue (
1498 [["blockdev_setro"; "/dev/sda"];
1499 ["blockdev_getro"; "/dev/sda"]])],
1500 "set block device to read-only",
1502 Sets the block device named C<device> to read-only.
1504 This uses the L<blockdev(8)> command.");
1506 ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1507 [InitEmpty, Always, TestOutputFalse (
1508 [["blockdev_setrw"; "/dev/sda"];
1509 ["blockdev_getro"; "/dev/sda"]])],
1510 "set block device to read-write",
1512 Sets the block device named C<device> to read-write.
1514 This uses the L<blockdev(8)> command.");
1516 ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1517 [InitEmpty, Always, TestOutputTrue (
1518 [["blockdev_setro"; "/dev/sda"];
1519 ["blockdev_getro"; "/dev/sda"]])],
1520 "is block device set to read-only",
1522 Returns a boolean indicating if the block device is read-only
1523 (true if read-only, false if not).
1525 This uses the L<blockdev(8)> command.");
1527 ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1528 [InitEmpty, Always, TestOutputInt (
1529 [["blockdev_getss"; "/dev/sda"]], 512)],
1530 "get sectorsize of block device",
1532 This returns the size of sectors on a block device.
1533 Usually 512, but can be larger for modern devices.
1535 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1538 This uses the L<blockdev(8)> command.");
1540 ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1541 [InitEmpty, Always, TestOutputInt (
1542 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1543 "get blocksize of block device",
1545 This returns the block size of a device.
1547 (Note this is different from both I<size in blocks> and
1548 I<filesystem block size>).
1550 This uses the L<blockdev(8)> command.");
1552 ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1554 "set blocksize of block device",
1556 This sets the block size of a device.
1558 (Note this is different from both I<size in blocks> and
1559 I<filesystem block size>).
1561 This uses the L<blockdev(8)> command.");
1563 ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1564 [InitEmpty, Always, TestOutputInt (
1565 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1566 "get total size of device in 512-byte sectors",
1568 This returns the size of the device in units of 512-byte sectors
1569 (even if the sectorsize isn't 512 bytes ... weird).
1571 See also C<guestfs_blockdev_getss> for the real sector size of
1572 the device, and C<guestfs_blockdev_getsize64> for the more
1573 useful I<size in bytes>.
1575 This uses the L<blockdev(8)> command.");
1577 ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1578 [InitEmpty, Always, TestOutputInt (
1579 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1580 "get total size of device in bytes",
1582 This returns the size of the device in bytes.
1584 See also C<guestfs_blockdev_getsz>.
1586 This uses the L<blockdev(8)> command.");
1588 ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1589 [InitEmpty, Always, TestRun
1590 [["blockdev_flushbufs"; "/dev/sda"]]],
1591 "flush device buffers",
1593 This tells the kernel to flush internal buffers associated
1596 This uses the L<blockdev(8)> command.");
1598 ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1599 [InitEmpty, Always, TestRun
1600 [["blockdev_rereadpt"; "/dev/sda"]]],
1601 "reread partition table",
1603 Reread the partition table on C<device>.
1605 This uses the L<blockdev(8)> command.");
1607 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1608 [InitBasicFS, Always, TestOutput (
1609 (* Pick a file from cwd which isn't likely to change. *)
1610 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1611 ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1612 "upload a file from the local machine",
1614 Upload local file C<filename> to C<remotefilename> on the
1617 C<filename> can also be a named pipe.
1619 See also C<guestfs_download>.");
1621 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1622 [InitBasicFS, Always, TestOutput (
1623 (* Pick a file from cwd which isn't likely to change. *)
1624 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1625 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1626 ["upload"; "testdownload.tmp"; "/upload"];
1627 ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1628 "download a file to the local machine",
1630 Download file C<remotefilename> and save it as C<filename>
1631 on the local machine.
1633 C<filename> can also be a named pipe.
1635 See also C<guestfs_upload>, C<guestfs_cat>.");
1637 ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1638 [InitBasicFS, Always, TestOutput (
1639 [["write_file"; "/new"; "test\n"; "0"];
1640 ["checksum"; "crc"; "/new"]], "935282863");
1641 InitBasicFS, Always, TestLastFail (
1642 [["checksum"; "crc"; "/new"]]);
1643 InitBasicFS, Always, TestOutput (
1644 [["write_file"; "/new"; "test\n"; "0"];
1645 ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1646 InitBasicFS, Always, TestOutput (
1647 [["write_file"; "/new"; "test\n"; "0"];
1648 ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1649 InitBasicFS, Always, TestOutput (
1650 [["write_file"; "/new"; "test\n"; "0"];
1651 ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1652 InitBasicFS, Always, TestOutput (
1653 [["write_file"; "/new"; "test\n"; "0"];
1654 ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1655 InitBasicFS, Always, TestOutput (
1656 [["write_file"; "/new"; "test\n"; "0"];
1657 ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1658 InitBasicFS, Always, TestOutput (
1659 [["write_file"; "/new"; "test\n"; "0"];
1660 ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
1661 InitBasicFS, Always, TestOutput (
1662 (* RHEL 5 thinks this is an HFS+ filesystem unless we give
1663 * the type explicitly.
1665 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
1666 ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
1667 "compute MD5, SHAx or CRC checksum of file",
1669 This call computes the MD5, SHAx or CRC checksum of the
1672 The type of checksum to compute is given by the C<csumtype>
1673 parameter which must have one of the following values:
1679 Compute the cyclic redundancy check (CRC) specified by POSIX
1680 for the C<cksum> command.
1684 Compute the MD5 hash (using the C<md5sum> program).
1688 Compute the SHA1 hash (using the C<sha1sum> program).
1692 Compute the SHA224 hash (using the C<sha224sum> program).
1696 Compute the SHA256 hash (using the C<sha256sum> program).
1700 Compute the SHA384 hash (using the C<sha384sum> program).
1704 Compute the SHA512 hash (using the C<sha512sum> program).
1708 The checksum is returned as a printable string.");
1710 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1711 [InitBasicFS, Always, TestOutput (
1712 [["tar_in"; "../images/helloworld.tar"; "/"];
1713 ["cat"; "/hello"]], "hello\n")],
1714 "unpack tarfile to directory",
1716 This command uploads and unpacks local file C<tarfile> (an
1717 I<uncompressed> tar file) into C<directory>.
1719 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1721 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1723 "pack directory into tarfile",
1725 This command packs the contents of C<directory> and downloads
1726 it to local file C<tarfile>.
1728 To download a compressed tarball, use C<guestfs_tgz_out>.");
1730 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1731 [InitBasicFS, Always, TestOutput (
1732 [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1733 ["cat"; "/hello"]], "hello\n")],
1734 "unpack compressed tarball to directory",
1736 This command uploads and unpacks local file C<tarball> (a
1737 I<gzip compressed> tar file) into C<directory>.
1739 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1741 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1743 "pack directory into compressed tarball",
1745 This command packs the contents of C<directory> and downloads
1746 it to local file C<tarball>.
1748 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1750 ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1751 [InitBasicFS, Always, TestLastFail (
1753 ["mount_ro"; "/dev/sda1"; "/"];
1754 ["touch"; "/new"]]);
1755 InitBasicFS, Always, TestOutput (
1756 [["write_file"; "/new"; "data"; "0"];
1758 ["mount_ro"; "/dev/sda1"; "/"];
1759 ["cat"; "/new"]], "data")],
1760 "mount a guest disk, read-only",
1762 This is the same as the C<guestfs_mount> command, but it
1763 mounts the filesystem with the read-only (I<-o ro>) flag.");
1765 ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1767 "mount a guest disk with mount options",
1769 This is the same as the C<guestfs_mount> command, but it
1770 allows you to set the mount options as for the
1771 L<mount(8)> I<-o> flag.");
1773 ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1775 "mount a guest disk with mount options and vfstype",
1777 This is the same as the C<guestfs_mount> command, but it
1778 allows you to set both the mount options and the vfstype
1779 as for the L<mount(8)> I<-o> and I<-t> flags.");
1781 ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1783 "debugging and internals",
1785 The C<guestfs_debug> command exposes some internals of
1786 C<guestfsd> (the guestfs daemon) that runs inside the
1789 There is no comprehensive help for this command. You have
1790 to look at the file C<daemon/debug.c> in the libguestfs source
1791 to find out what you can do.");
1793 ("lvremove", (RErr, [String "device"]), 77, [],
1794 [InitEmpty, Always, TestOutputList (
1795 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1796 ["pvcreate"; "/dev/sda1"];
1797 ["vgcreate"; "VG"; "/dev/sda1"];
1798 ["lvcreate"; "LV1"; "VG"; "50"];
1799 ["lvcreate"; "LV2"; "VG"; "50"];
1800 ["lvremove"; "/dev/VG/LV1"];
1801 ["lvs"]], ["/dev/VG/LV2"]);
1802 InitEmpty, Always, TestOutputList (
1803 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1804 ["pvcreate"; "/dev/sda1"];
1805 ["vgcreate"; "VG"; "/dev/sda1"];
1806 ["lvcreate"; "LV1"; "VG"; "50"];
1807 ["lvcreate"; "LV2"; "VG"; "50"];
1808 ["lvremove"; "/dev/VG"];
1810 InitEmpty, Always, TestOutputList (
1811 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1812 ["pvcreate"; "/dev/sda1"];
1813 ["vgcreate"; "VG"; "/dev/sda1"];
1814 ["lvcreate"; "LV1"; "VG"; "50"];
1815 ["lvcreate"; "LV2"; "VG"; "50"];
1816 ["lvremove"; "/dev/VG"];
1818 "remove an LVM logical volume",
1820 Remove an LVM logical volume C<device>, where C<device> is
1821 the path to the LV, such as C</dev/VG/LV>.
1823 You can also remove all LVs in a volume group by specifying
1824 the VG name, C</dev/VG>.");
1826 ("vgremove", (RErr, [String "vgname"]), 78, [],
1827 [InitEmpty, Always, TestOutputList (
1828 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1829 ["pvcreate"; "/dev/sda1"];
1830 ["vgcreate"; "VG"; "/dev/sda1"];
1831 ["lvcreate"; "LV1"; "VG"; "50"];
1832 ["lvcreate"; "LV2"; "VG"; "50"];
1835 InitEmpty, Always, TestOutputList (
1836 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1837 ["pvcreate"; "/dev/sda1"];
1838 ["vgcreate"; "VG"; "/dev/sda1"];
1839 ["lvcreate"; "LV1"; "VG"; "50"];
1840 ["lvcreate"; "LV2"; "VG"; "50"];
1843 "remove an LVM volume group",
1845 Remove an LVM volume group C<vgname>, (for example C<VG>).
1847 This also forcibly removes all logical volumes in the volume
1850 ("pvremove", (RErr, [String "device"]), 79, [],
1851 [InitEmpty, Always, TestOutputListOfDevices (
1852 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1853 ["pvcreate"; "/dev/sda1"];
1854 ["vgcreate"; "VG"; "/dev/sda1"];
1855 ["lvcreate"; "LV1"; "VG"; "50"];
1856 ["lvcreate"; "LV2"; "VG"; "50"];
1858 ["pvremove"; "/dev/sda1"];
1860 InitEmpty, Always, TestOutputListOfDevices (
1861 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1862 ["pvcreate"; "/dev/sda1"];
1863 ["vgcreate"; "VG"; "/dev/sda1"];
1864 ["lvcreate"; "LV1"; "VG"; "50"];
1865 ["lvcreate"; "LV2"; "VG"; "50"];
1867 ["pvremove"; "/dev/sda1"];
1869 InitEmpty, Always, TestOutputListOfDevices (
1870 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1871 ["pvcreate"; "/dev/sda1"];
1872 ["vgcreate"; "VG"; "/dev/sda1"];
1873 ["lvcreate"; "LV1"; "VG"; "50"];
1874 ["lvcreate"; "LV2"; "VG"; "50"];
1876 ["pvremove"; "/dev/sda1"];
1878 "remove an LVM physical volume",
1880 This wipes a physical volume C<device> so that LVM will no longer
1883 The implementation uses the C<pvremove> command which refuses to
1884 wipe physical volumes that contain any volume groups, so you have
1885 to remove those first.");
1887 ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
1888 [InitBasicFS, Always, TestOutput (
1889 [["set_e2label"; "/dev/sda1"; "testlabel"];
1890 ["get_e2label"; "/dev/sda1"]], "testlabel")],
1891 "set the ext2/3/4 filesystem label",
1893 This sets the ext2/3/4 filesystem label of the filesystem on
1894 C<device> to C<label>. Filesystem labels are limited to
1897 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
1898 to return the existing label on a filesystem.");
1900 ("get_e2label", (RString "label", [String "device"]), 81, [],
1902 "get the ext2/3/4 filesystem label",
1904 This returns the ext2/3/4 filesystem label of the filesystem on
1907 ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
1908 [InitBasicFS, Always, TestOutput (
1909 [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
1910 ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
1911 InitBasicFS, Always, TestOutput (
1912 [["set_e2uuid"; "/dev/sda1"; "clear"];
1913 ["get_e2uuid"; "/dev/sda1"]], "");
1914 (* We can't predict what UUIDs will be, so just check the commands run. *)
1915 InitBasicFS, Always, TestRun (
1916 [["set_e2uuid"; "/dev/sda1"; "random"]]);
1917 InitBasicFS, Always, TestRun (
1918 [["set_e2uuid"; "/dev/sda1"; "time"]])],
1919 "set the ext2/3/4 filesystem UUID",
1921 This sets the ext2/3/4 filesystem UUID of the filesystem on
1922 C<device> to C<uuid>. The format of the UUID and alternatives
1923 such as C<clear>, C<random> and C<time> are described in the
1924 L<tune2fs(8)> manpage.
1926 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
1927 to return the existing UUID of a filesystem.");
1929 ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
1931 "get the ext2/3/4 filesystem UUID",
1933 This returns the ext2/3/4 filesystem UUID of the filesystem on
1936 ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
1937 [InitBasicFS, Always, TestOutputInt (
1938 [["umount"; "/dev/sda1"];
1939 ["fsck"; "ext2"; "/dev/sda1"]], 0);
1940 InitBasicFS, Always, TestOutputInt (
1941 [["umount"; "/dev/sda1"];
1942 ["zero"; "/dev/sda1"];
1943 ["fsck"; "ext2"; "/dev/sda1"]], 8)],
1944 "run the filesystem checker",
1946 This runs the filesystem checker (fsck) on C<device> which
1947 should have filesystem type C<fstype>.
1949 The returned integer is the status. See L<fsck(8)> for the
1950 list of status codes from C<fsck>.
1958 Multiple status codes can be summed together.
1962 A non-zero return code can mean \"success\", for example if
1963 errors have been corrected on the filesystem.
1967 Checking or repairing NTFS volumes is not supported
1972 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
1974 ("zero", (RErr, [String "device"]), 85, [],
1975 [InitBasicFS, Always, TestOutput (
1976 [["umount"; "/dev/sda1"];
1977 ["zero"; "/dev/sda1"];
1978 ["file"; "/dev/sda1"]], "data")],
1979 "write zeroes to the device",
1981 This command writes zeroes over the first few blocks of C<device>.
1983 How many blocks are zeroed isn't specified (but it's I<not> enough
1984 to securely wipe the device). It should be sufficient to remove
1985 any partition tables, filesystem superblocks and so on.
1987 See also: C<guestfs_scrub_device>.");
1989 ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
1990 [InitBasicFS, Always, TestOutputTrue (
1991 [["grub_install"; "/"; "/dev/sda1"];
1992 ["is_dir"; "/boot"]])],
1995 This command installs GRUB (the Grand Unified Bootloader) on
1996 C<device>, with the root directory being C<root>.");
1998 ("cp", (RErr, [String "src"; String "dest"]), 87, [],
1999 [InitBasicFS, Always, TestOutput (
2000 [["write_file"; "/old"; "file content"; "0"];
2001 ["cp"; "/old"; "/new"];
2002 ["cat"; "/new"]], "file content");
2003 InitBasicFS, Always, TestOutputTrue (
2004 [["write_file"; "/old"; "file content"; "0"];
2005 ["cp"; "/old"; "/new"];
2006 ["is_file"; "/old"]]);
2007 InitBasicFS, Always, TestOutput (
2008 [["write_file"; "/old"; "file content"; "0"];
2010 ["cp"; "/old"; "/dir/new"];
2011 ["cat"; "/dir/new"]], "file content")],
2014 This copies a file from C<src> to C<dest> where C<dest> is
2015 either a destination filename or destination directory.");
2017 ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2018 [InitBasicFS, Always, TestOutput (
2019 [["mkdir"; "/olddir"];
2020 ["mkdir"; "/newdir"];
2021 ["write_file"; "/olddir/file"; "file content"; "0"];
2022 ["cp_a"; "/olddir"; "/newdir"];
2023 ["cat"; "/newdir/olddir/file"]], "file content")],
2024 "copy a file or directory recursively",
2026 This copies a file or directory from C<src> to C<dest>
2027 recursively using the C<cp -a> command.");
2029 ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2030 [InitBasicFS, Always, TestOutput (
2031 [["write_file"; "/old"; "file content"; "0"];
2032 ["mv"; "/old"; "/new"];
2033 ["cat"; "/new"]], "file content");
2034 InitBasicFS, Always, TestOutputFalse (
2035 [["write_file"; "/old"; "file content"; "0"];
2036 ["mv"; "/old"; "/new"];
2037 ["is_file"; "/old"]])],
2040 This moves a file from C<src> to C<dest> where C<dest> is
2041 either a destination filename or destination directory.");
2043 ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2044 [InitEmpty, Always, TestRun (
2045 [["drop_caches"; "3"]])],
2046 "drop kernel page cache, dentries and inodes",
2048 This instructs the guest kernel to drop its page cache,
2049 and/or dentries and inode caches. The parameter C<whattodrop>
2050 tells the kernel what precisely to drop, see
2051 L<http://linux-mm.org/Drop_Caches>
2053 Setting C<whattodrop> to 3 should drop everything.
2055 This automatically calls L<sync(2)> before the operation,
2056 so that the maximum guest memory is freed.");
2058 ("dmesg", (RString "kmsgs", []), 91, [],
2059 [InitEmpty, Always, TestRun (
2061 "return kernel messages",
2063 This returns the kernel messages (C<dmesg> output) from
2064 the guest kernel. This is sometimes useful for extended
2065 debugging of problems.
2067 Another way to get the same information is to enable
2068 verbose messages with C<guestfs_set_verbose> or by setting
2069 the environment variable C<LIBGUESTFS_DEBUG=1> before
2070 running the program.");
2072 ("ping_daemon", (RErr, []), 92, [],
2073 [InitEmpty, Always, TestRun (
2074 [["ping_daemon"]])],
2075 "ping the guest daemon",
2077 This is a test probe into the guestfs daemon running inside
2078 the qemu subprocess. Calling this function checks that the
2079 daemon responds to the ping message, without affecting the daemon
2080 or attached block device(s) in any other way.");
2082 ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2083 [InitBasicFS, Always, TestOutputTrue (
2084 [["write_file"; "/file1"; "contents of a file"; "0"];
2085 ["cp"; "/file1"; "/file2"];
2086 ["equal"; "/file1"; "/file2"]]);
2087 InitBasicFS, Always, TestOutputFalse (
2088 [["write_file"; "/file1"; "contents of a file"; "0"];
2089 ["write_file"; "/file2"; "contents of another file"; "0"];
2090 ["equal"; "/file1"; "/file2"]]);
2091 InitBasicFS, Always, TestLastFail (
2092 [["equal"; "/file1"; "/file2"]])],
2093 "test if two files have equal contents",
2095 This compares the two files C<file1> and C<file2> and returns
2096 true if their content is exactly equal, or false otherwise.
2098 The external L<cmp(1)> program is used for the comparison.");
2100 ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2101 [InitBasicFS, Always, TestOutputList (
2102 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2103 ["strings"; "/new"]], ["hello"; "world"]);
2104 InitBasicFS, Always, TestOutputList (
2106 ["strings"; "/new"]], [])],
2107 "print the printable strings in a file",
2109 This runs the L<strings(1)> command on a file and returns
2110 the list of printable strings found.");
2112 ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2113 [InitBasicFS, Always, TestOutputList (
2114 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2115 ["strings_e"; "b"; "/new"]], []);
2116 InitBasicFS, Disabled, TestOutputList (
2117 [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2118 ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2119 "print the printable strings in a file",
2121 This is like the C<guestfs_strings> command, but allows you to
2122 specify the encoding.
2124 See the L<strings(1)> manpage for the full list of encodings.
2126 Commonly useful encodings are C<l> (lower case L) which will
2127 show strings inside Windows/x86 files.
2129 The returned strings are transcoded to UTF-8.");
2131 ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2132 [InitBasicFS, Always, TestOutput (
2133 [["write_file"; "/new"; "hello\nworld\n"; "12"];
2134 ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n");
2135 (* Test for RHBZ#501888c2 regression which caused large hexdump
2136 * commands to segfault.
2138 InitBasicFS, Always, TestRun (
2139 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2140 ["hexdump"; "/100krandom"]])],
2141 "dump a file in hexadecimal",
2143 This runs C<hexdump -C> on the given C<path>. The result is
2144 the human-readable, canonical hex dump of the file.");
2146 ("zerofree", (RErr, [String "device"]), 97, [],
2147 [InitNone, Always, TestOutput (
2148 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2149 ["mkfs"; "ext3"; "/dev/sda1"];
2150 ["mount"; "/dev/sda1"; "/"];
2151 ["write_file"; "/new"; "test file"; "0"];
2152 ["umount"; "/dev/sda1"];
2153 ["zerofree"; "/dev/sda1"];
2154 ["mount"; "/dev/sda1"; "/"];
2155 ["cat"; "/new"]], "test file")],
2156 "zero unused inodes and disk blocks on ext2/3 filesystem",
2158 This runs the I<zerofree> program on C<device>. This program
2159 claims to zero unused inodes and disk blocks on an ext2/3
2160 filesystem, thus making it possible to compress the filesystem
2163 You should B<not> run this program if the filesystem is
2166 It is possible that using this program can damage the filesystem
2167 or data on the filesystem.");
2169 ("pvresize", (RErr, [String "device"]), 98, [],
2171 "resize an LVM physical volume",
2173 This resizes (expands or shrinks) an existing LVM physical
2174 volume to match the new size of the underlying device.");
2176 ("sfdisk_N", (RErr, [String "device"; Int "partnum";
2177 Int "cyls"; Int "heads"; Int "sectors";
2178 String "line"]), 99, [DangerWillRobinson],
2180 "modify a single partition on a block device",
2182 This runs L<sfdisk(8)> option to modify just the single
2183 partition C<n> (note: C<n> counts from 1).
2185 For other parameters, see C<guestfs_sfdisk>. You should usually
2186 pass C<0> for the cyls/heads/sectors parameters.");
2188 ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2190 "display the partition table",
2192 This displays the partition table on C<device>, in the
2193 human-readable output of the L<sfdisk(8)> command. It is
2194 not intended to be parsed.");
2196 ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2198 "display the kernel geometry",
2200 This displays the kernel's idea of the geometry of C<device>.
2202 The result is in human-readable format, and not designed to
2205 ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2207 "display the disk geometry from the partition table",
2209 This displays the disk geometry of C<device> read from the
2210 partition table. Especially in the case where the underlying
2211 block device has been resized, this can be different from the
2212 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2214 The result is in human-readable format, and not designed to
2217 ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2219 "activate or deactivate all volume groups",
2221 This command activates or (if C<activate> is false) deactivates
2222 all logical volumes in all volume groups.
2223 If activated, then they are made known to the
2224 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2225 then those devices disappear.
2227 This command is the same as running C<vgchange -a y|n>");
2229 ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2231 "activate or deactivate some volume groups",
2233 This command activates or (if C<activate> is false) deactivates
2234 all logical volumes in the listed volume groups C<volgroups>.
2235 If activated, then they are made known to the
2236 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2237 then those devices disappear.
2239 This command is the same as running C<vgchange -a y|n volgroups...>
2241 Note that if C<volgroups> is an empty list then B<all> volume groups
2242 are activated or deactivated.");
2244 ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2245 [InitNone, Always, TestOutput (
2246 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2247 ["pvcreate"; "/dev/sda1"];
2248 ["vgcreate"; "VG"; "/dev/sda1"];
2249 ["lvcreate"; "LV"; "VG"; "10"];
2250 ["mkfs"; "ext2"; "/dev/VG/LV"];
2251 ["mount"; "/dev/VG/LV"; "/"];
2252 ["write_file"; "/new"; "test content"; "0"];
2254 ["lvresize"; "/dev/VG/LV"; "20"];
2255 ["e2fsck_f"; "/dev/VG/LV"];
2256 ["resize2fs"; "/dev/VG/LV"];
2257 ["mount"; "/dev/VG/LV"; "/"];
2258 ["cat"; "/new"]], "test content")],
2259 "resize an LVM logical volume",
2261 This resizes (expands or shrinks) an existing LVM logical
2262 volume to C<mbytes>. When reducing, data in the reduced part
2265 ("resize2fs", (RErr, [String "device"]), 106, [],
2266 [], (* lvresize tests this *)
2267 "resize an ext2/ext3 filesystem",
2269 This resizes an ext2 or ext3 filesystem to match the size of
2270 the underlying device.
2272 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2273 on the C<device> before calling this command. For unknown reasons
2274 C<resize2fs> sometimes gives an error about this and sometimes not.
2275 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2276 calling this function.");
2278 ("find", (RStringList "names", [String "directory"]), 107, [],
2279 [InitBasicFS, Always, TestOutputList (
2280 [["find"; "/"]], ["lost+found"]);
2281 InitBasicFS, Always, TestOutputList (
2285 ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2286 InitBasicFS, Always, TestOutputList (
2287 [["mkdir_p"; "/a/b/c"];
2288 ["touch"; "/a/b/c/d"];
2289 ["find"; "/a/b/"]], ["c"; "c/d"])],
2290 "find all files and directories",
2292 This command lists out all files and directories, recursively,
2293 starting at C<directory>. It is essentially equivalent to
2294 running the shell command C<find directory -print> but some
2295 post-processing happens on the output, described below.
2297 This returns a list of strings I<without any prefix>. Thus
2298 if the directory structure was:
2304 then the returned list from C<guestfs_find> C</tmp> would be
2312 If C<directory> is not a directory, then this command returns
2315 The returned list is sorted.");
2317 ("e2fsck_f", (RErr, [String "device"]), 108, [],
2318 [], (* lvresize tests this *)
2319 "check an ext2/ext3 filesystem",
2321 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2322 filesystem checker on C<device>, noninteractively (C<-p>),
2323 even if the filesystem appears to be clean (C<-f>).
2325 This command is only needed because of C<guestfs_resize2fs>
2326 (q.v.). Normally you should use C<guestfs_fsck>.");
2328 ("sleep", (RErr, [Int "secs"]), 109, [],
2329 [InitNone, Always, TestRun (
2331 "sleep for some seconds",
2333 Sleep for C<secs> seconds.");
2335 ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [],
2336 [InitNone, Always, TestOutputInt (
2337 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2338 ["mkfs"; "ntfs"; "/dev/sda1"];
2339 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2340 InitNone, Always, TestOutputInt (
2341 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2342 ["mkfs"; "ext2"; "/dev/sda1"];
2343 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2344 "probe NTFS volume",
2346 This command runs the L<ntfs-3g.probe(8)> command which probes
2347 an NTFS C<device> for mountability. (Not all NTFS volumes can
2348 be mounted read-write, and some cannot be mounted at all).
2350 C<rw> is a boolean flag. Set it to true if you want to test
2351 if the volume can be mounted read-write. Set it to false if
2352 you want to test if the volume can be mounted read-only.
2354 The return value is an integer which C<0> if the operation
2355 would succeed, or some non-zero value documented in the
2356 L<ntfs-3g.probe(8)> manual page.");
2358 ("sh", (RString "output", [String "command"]), 111, [],
2359 [], (* XXX needs tests *)
2360 "run a command via the shell",
2362 This call runs a command from the guest filesystem via the
2365 This is like C<guestfs_command>, but passes the command to:
2367 /bin/sh -c \"command\"
2369 Depending on the guest's shell, this usually results in
2370 wildcards being expanded, shell expressions being interpolated
2373 All the provisos about C<guestfs_command> apply to this call.");
2375 ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2376 [], (* XXX needs tests *)
2377 "run a command via the shell returning lines",
2379 This is the same as C<guestfs_sh>, but splits the result
2380 into a list of lines.
2382 See also: C<guestfs_command_lines>");
2384 ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [],
2385 [InitBasicFS, Always, TestOutputList (
2386 [["mkdir_p"; "/a/b/c"];
2387 ["touch"; "/a/b/c/d"];
2388 ["touch"; "/a/b/c/e"];
2389 ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2390 InitBasicFS, Always, TestOutputList (
2391 [["mkdir_p"; "/a/b/c"];
2392 ["touch"; "/a/b/c/d"];
2393 ["touch"; "/a/b/c/e"];
2394 ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2395 InitBasicFS, Always, TestOutputList (
2396 [["mkdir_p"; "/a/b/c"];
2397 ["touch"; "/a/b/c/d"];
2398 ["touch"; "/a/b/c/e"];
2399 ["glob_expand"; "/a/*/x/*"]], [])],
2400 "expand a wildcard path",
2402 This command searches for all the pathnames matching
2403 C<pattern> according to the wildcard expansion rules
2406 If no paths match, then this returns an empty list
2407 (note: not an error).
2409 It is just a wrapper around the C L<glob(3)> function
2410 with flags C<GLOB_MARK|GLOB_BRACE>.
2411 See that manual page for more details.");
2413 ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson],
2414 [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2415 [["scrub_device"; "/dev/sdc"]])],
2416 "scrub (securely wipe) a device",
2418 This command writes patterns over C<device> to make data retrieval
2421 It is an interface to the L<scrub(1)> program. See that
2422 manual page for more details.");
2424 ("scrub_file", (RErr, [String "file"]), 115, [],
2425 [InitBasicFS, Always, TestRun (
2426 [["write_file"; "/file"; "content"; "0"];
2427 ["scrub_file"; "/file"]])],
2428 "scrub (securely wipe) a file",
2430 This command writes patterns over a file to make data retrieval
2433 The file is I<removed> after scrubbing.
2435 It is an interface to the L<scrub(1)> program. See that
2436 manual page for more details.");
2438 ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2439 [], (* XXX needs testing *)
2440 "scrub (securely wipe) free space",
2442 This command creates the directory C<dir> and then fills it
2443 with files until the filesystem is full, and scrubs the files
2444 as for C<guestfs_scrub_file>, and deletes them.
2445 The intention is to scrub any free space on the partition
2448 It is an interface to the L<scrub(1)> program. See that
2449 manual page for more details.");
2451 ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2452 [InitBasicFS, Always, TestRun (
2454 ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2455 "create a temporary directory",
2457 This command creates a temporary directory. The
2458 C<template> parameter should be a full pathname for the
2459 temporary directory name with the final six characters being
2462 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2463 the second one being suitable for Windows filesystems.
2465 The name of the temporary directory that was created
2468 The temporary directory is created with mode 0700
2469 and is owned by root.
2471 The caller is responsible for deleting the temporary
2472 directory and its contents after use.
2474 See also: L<mkdtemp(3)>");
2476 ("wc_l", (RInt "lines", [String "path"]), 118, [],
2477 [InitBasicFS, Always, TestOutputInt (
2478 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2479 ["wc_l"; "/10klines"]], 10000)],
2480 "count lines in a file",
2482 This command counts the lines in a file, using the
2483 C<wc -l> external command.");
2485 ("wc_w", (RInt "words", [String "path"]), 119, [],
2486 [InitBasicFS, Always, TestOutputInt (
2487 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2488 ["wc_w"; "/10klines"]], 10000)],
2489 "count words in a file",
2491 This command counts the words in a file, using the
2492 C<wc -w> external command.");
2494 ("wc_c", (RInt "chars", [String "path"]), 120, [],
2495 [InitBasicFS, Always, TestOutputInt (
2496 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2497 ["wc_c"; "/100kallspaces"]], 102400)],
2498 "count characters in a file",
2500 This command counts the characters in a file, using the
2501 C<wc -c> external command.");
2503 ("head", (RStringList "lines", [String "path"]), 121, [ProtocolLimitWarning],
2504 [InitBasicFS, Always, TestOutputList (
2505 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2506 ["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2507 "return first 10 lines of a file",
2509 This command returns up to the first 10 lines of a file as
2510 a list of strings.");
2512 ("head_n", (RStringList "lines", [Int "nrlines"; String "path"]), 122, [ProtocolLimitWarning],
2513 [InitBasicFS, Always, TestOutputList (
2514 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2515 ["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2516 InitBasicFS, Always, TestOutputList (
2517 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2518 ["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2519 InitBasicFS, Always, TestOutputList (
2520 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2521 ["head_n"; "0"; "/10klines"]], [])],
2522 "return first N lines of a file",
2524 If the parameter C<nrlines> is a positive number, this returns the first
2525 C<nrlines> lines of the file C<path>.
2527 If the parameter C<nrlines> is a negative number, this returns lines
2528 from the file C<path>, excluding the last C<nrlines> lines.
2530 If the parameter C<nrlines> is zero, this returns an empty list.");
2532 ("tail", (RStringList "lines", [String "path"]), 123, [ProtocolLimitWarning],
2533 [InitBasicFS, Always, TestOutputList (
2534 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2535 ["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2536 "return last 10 lines of a file",
2538 This command returns up to the last 10 lines of a file as
2539 a list of strings.");
2541 ("tail_n", (RStringList "lines", [Int "nrlines"; String "path"]), 124, [ProtocolLimitWarning],
2542 [InitBasicFS, Always, TestOutputList (
2543 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2544 ["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2545 InitBasicFS, Always, TestOutputList (
2546 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2547 ["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2548 InitBasicFS, Always, TestOutputList (
2549 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2550 ["tail_n"; "0"; "/10klines"]], [])],
2551 "return last N lines of a file",
2553 If the parameter C<nrlines> is a positive number, this returns the last
2554 C<nrlines> lines of the file C<path>.
2556 If the parameter C<nrlines> is a negative number, this returns lines
2557 from the file C<path>, starting with the C<-nrlines>th line.
2559 If the parameter C<nrlines> is zero, this returns an empty list.");
2563 let all_functions = non_daemon_functions @ daemon_functions
2565 (* In some places we want the functions to be displayed sorted
2566 * alphabetically, so this is useful:
2568 let all_functions_sorted =
2569 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2570 compare n1 n2) all_functions
2572 (* Column names and types from LVM PVs/VGs/LVs. *)
2581 "pv_attr", `String (* XXX *);
2582 "pv_pe_count", `Int;
2583 "pv_pe_alloc_count", `Int;
2586 "pv_mda_count", `Int;
2587 "pv_mda_free", `Bytes;
2588 (* Not in Fedora 10:
2589 "pv_mda_size", `Bytes;
2596 "vg_attr", `String (* XXX *);
2599 "vg_sysid", `String;
2600 "vg_extent_size", `Bytes;
2601 "vg_extent_count", `Int;
2602 "vg_free_count", `Int;
2610 "vg_mda_count", `Int;
2611 "vg_mda_free", `Bytes;
2612 (* Not in Fedora 10:
2613 "vg_mda_size", `Bytes;
2619 "lv_attr", `String (* XXX *);
2622 "lv_kernel_major", `Int;
2623 "lv_kernel_minor", `Int;
2627 "snap_percent", `OptPercent;
2628 "copy_percent", `OptPercent;
2631 "mirror_log", `String;
2635 (* Column names and types from stat structures.
2636 * NB. Can't use things like 'st_atime' because glibc header files
2637 * define some of these as macros. Ugh.
2654 let statvfs_cols = [
2668 (* Used for testing language bindings. *)
2670 | CallString of string
2671 | CallOptString of string option
2672 | CallStringList of string list
2676 (* Useful functions.
2677 * Note we don't want to use any external OCaml libraries which
2678 * makes this a bit harder than it should be.
2680 let failwithf fs = ksprintf failwith fs
2682 let replace_char s c1 c2 =
2683 let s2 = String.copy s in
2684 let r = ref false in
2685 for i = 0 to String.length s2 - 1 do
2686 if String.unsafe_get s2 i = c1 then (
2687 String.unsafe_set s2 i c2;
2691 if not !r then s else s2
2695 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2697 let triml ?(test = isspace) str =
2699 let n = ref (String.length str) in
2700 while !n > 0 && test str.[!i]; do
2705 else String.sub str !i !n
2707 let trimr ?(test = isspace) str =
2708 let n = ref (String.length str) in
2709 while !n > 0 && test str.[!n-1]; do
2712 if !n = String.length str then str
2713 else String.sub str 0 !n
2715 let trim ?(test = isspace) str =
2716 trimr ~test (triml ~test str)
2718 let rec find s sub =
2719 let len = String.length s in
2720 let sublen = String.length sub in
2722 if i <= len-sublen then (
2724 if j < sublen then (
2725 if s.[i+j] = sub.[j] then loop2 (j+1)
2731 if r = -1 then loop (i+1) else r
2737 let rec replace_str s s1 s2 =
2738 let len = String.length s in
2739 let sublen = String.length s1 in
2740 let i = find s s1 in
2743 let s' = String.sub s 0 i in
2744 let s'' = String.sub s (i+sublen) (len-i-sublen) in
2745 s' ^ s2 ^ replace_str s'' s1 s2
2748 let rec string_split sep str =
2749 let len = String.length str in
2750 let seplen = String.length sep in
2751 let i = find str sep in
2752 if i = -1 then [str]
2754 let s' = String.sub str 0 i in
2755 let s'' = String.sub str (i+seplen) (len-i-seplen) in
2756 s' :: string_split sep s''
2759 let files_equal n1 n2 =
2760 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
2761 match Sys.command cmd with
2764 | i -> failwithf "%s: failed with error code %d" cmd i
2766 let rec find_map f = function
2767 | [] -> raise Not_found
2771 | None -> find_map f xs
2774 let rec loop i = function
2776 | x :: xs -> f i x; loop (i+1) xs
2781 let rec loop i = function
2783 | x :: xs -> let r = f i x in r :: loop (i+1) xs
2787 let name_of_argt = function
2788 | String n | OptString n | StringList n | Bool n | Int n
2789 | FileIn n | FileOut n -> n
2791 let seq_of_test = function
2792 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
2793 | TestOutputListOfDevices (s, _)
2794 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
2795 | TestOutputLength (s, _) | TestOutputStruct (s, _)
2796 | TestLastFail s -> s
2798 (* Check function names etc. for consistency. *)
2799 let check_functions () =
2800 let contains_uppercase str =
2801 let len = String.length str in
2803 if i >= len then false
2806 if c >= 'A' && c <= 'Z' then true
2813 (* Check function names. *)
2815 fun (name, _, _, _, _, _, _) ->
2816 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
2817 failwithf "function name %s does not need 'guestfs' prefix" name;
2819 failwithf "function name is empty";
2820 if name.[0] < 'a' || name.[0] > 'z' then
2821 failwithf "function name %s must start with lowercase a-z" name;
2822 if String.contains name '-' then
2823 failwithf "function name %s should not contain '-', use '_' instead."
2827 (* Check function parameter/return names. *)
2829 fun (name, style, _, _, _, _, _) ->
2830 let check_arg_ret_name n =
2831 if contains_uppercase n then
2832 failwithf "%s param/ret %s should not contain uppercase chars"
2834 if String.contains n '-' || String.contains n '_' then
2835 failwithf "%s param/ret %s should not contain '-' or '_'"
2838 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;
2839 if n = "int" || n = "char" || n = "short" || n = "long" then
2840 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
2841 if n = "i" || n = "n" then
2842 failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
2843 if n = "argv" || n = "args" then
2844 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
2847 (match fst style with
2849 | RInt n | RInt64 n | RBool n | RConstString n | RString n
2850 | RStringList n | RPVList n | RVGList n | RLVList n
2851 | RStat n | RStatVFS n
2853 check_arg_ret_name n
2855 check_arg_ret_name n;
2856 check_arg_ret_name m
2858 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
2861 (* Check short descriptions. *)
2863 fun (name, _, _, _, _, shortdesc, _) ->
2864 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
2865 failwithf "short description of %s should begin with lowercase." name;
2866 let c = shortdesc.[String.length shortdesc-1] in
2867 if c = '\n' || c = '.' then
2868 failwithf "short description of %s should not end with . or \\n." name
2871 (* Check long dscriptions. *)
2873 fun (name, _, _, _, _, _, longdesc) ->
2874 if longdesc.[String.length longdesc-1] = '\n' then
2875 failwithf "long description of %s should not end with \\n." name
2878 (* Check proc_nrs. *)
2880 fun (name, _, proc_nr, _, _, _, _) ->
2881 if proc_nr <= 0 then
2882 failwithf "daemon function %s should have proc_nr > 0" name
2886 fun (name, _, proc_nr, _, _, _, _) ->
2887 if proc_nr <> -1 then
2888 failwithf "non-daemon function %s should have proc_nr -1" name
2889 ) non_daemon_functions;
2892 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
2895 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
2896 let rec loop = function
2899 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
2901 | (name1,nr1) :: (name2,nr2) :: _ ->
2902 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
2910 (* Ignore functions that have no tests. We generate a
2911 * warning when the user does 'make check' instead.
2913 | name, _, _, _, [], _, _ -> ()
2914 | name, _, _, _, tests, _, _ ->
2918 match seq_of_test test with
2920 failwithf "%s has a test containing an empty sequence" name
2921 | cmds -> List.map List.hd cmds
2923 let funcs = List.flatten funcs in
2925 let tested = List.mem name funcs in
2928 failwithf "function %s has tests but does not test itself" name
2931 (* 'pr' prints to the current output file. *)
2932 let chan = ref stdout
2933 let pr fs = ksprintf (output_string !chan) fs
2935 (* Generate a header block in a number of standard styles. *)
2936 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
2937 type license = GPLv2 | LGPLv2
2939 let generate_header comment license =
2940 let c = match comment with
2941 | CStyle -> pr "/* "; " *"
2942 | HashStyle -> pr "# "; "#"
2943 | OCamlStyle -> pr "(* "; " *"
2944 | HaskellStyle -> pr "{- "; " " in
2945 pr "libguestfs generated file\n";
2946 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
2947 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
2949 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
2953 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
2954 pr "%s it under the terms of the GNU General Public License as published by\n" c;
2955 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
2956 pr "%s (at your option) any later version.\n" c;
2958 pr "%s This program is distributed in the hope that it will be useful,\n" c;
2959 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2960 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
2961 pr "%s GNU General Public License for more details.\n" c;
2963 pr "%s You should have received a copy of the GNU General Public License along\n" c;
2964 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
2965 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
2968 pr "%s This library is free software; you can redistribute it and/or\n" c;
2969 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
2970 pr "%s License as published by the Free Software Foundation; either\n" c;
2971 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
2973 pr "%s This library is distributed in the hope that it will be useful,\n" c;
2974 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2975 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
2976 pr "%s Lesser General Public License for more details.\n" c;
2978 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
2979 pr "%s License along with this library; if not, write to the Free Software\n" c;
2980 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
2983 | CStyle -> pr " */\n"
2985 | OCamlStyle -> pr " *)\n"
2986 | HaskellStyle -> pr "-}\n"
2990 (* Start of main code generation functions below this line. *)
2992 (* Generate the pod documentation for the C API. *)
2993 let rec generate_actions_pod () =
2995 fun (shortname, style, _, flags, _, _, longdesc) ->
2996 if not (List.mem NotInDocs flags) then (
2997 let name = "guestfs_" ^ shortname in
2998 pr "=head2 %s\n\n" name;
3000 generate_prototype ~extern:false ~handle:"handle" name style;
3002 pr "%s\n\n" longdesc;
3003 (match fst style with
3005 pr "This function returns 0 on success or -1 on error.\n\n"
3007 pr "On error this function returns -1.\n\n"
3009 pr "On error this function returns -1.\n\n"
3011 pr "This function returns a C truth value on success or -1 on error.\n\n"
3013 pr "This function returns a string, or NULL on error.
3014 The string is owned by the guest handle and must I<not> be freed.\n\n"
3016 pr "This function returns a string, or NULL on error.
3017 I<The caller must free the returned string after use>.\n\n"
3019 pr "This function returns a NULL-terminated array of strings
3020 (like L<environ(3)>), or NULL if there was an error.
3021 I<The caller must free the strings and the array after use>.\n\n"
3023 pr "This function returns a C<struct guestfs_int_bool *>,
3024 or NULL if there was an error.
3025 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
3027 pr "This function returns a C<struct guestfs_lvm_pv_list *>
3028 (see E<lt>guestfs-structs.hE<gt>),
3029 or NULL if there was an error.
3030 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
3032 pr "This function returns a C<struct guestfs_lvm_vg_list *>
3033 (see E<lt>guestfs-structs.hE<gt>),
3034 or NULL if there was an error.
3035 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
3037 pr "This function returns a C<struct guestfs_lvm_lv_list *>
3038 (see E<lt>guestfs-structs.hE<gt>),
3039 or NULL if there was an error.
3040 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
3042 pr "This function returns a C<struct guestfs_stat *>
3043 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
3044 or NULL if there was an error.
3045 I<The caller must call C<free> after use>.\n\n"
3047 pr "This function returns a C<struct guestfs_statvfs *>
3048 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
3049 or NULL if there was an error.
3050 I<The caller must call C<free> after use>.\n\n"
3052 pr "This function returns a NULL-terminated array of
3053 strings, or NULL if there was an error.
3054 The array of strings will always have length C<2n+1>, where
3055 C<n> keys and values alternate, followed by the trailing NULL entry.
3056 I<The caller must free the strings and the array after use>.\n\n"
3058 if List.mem ProtocolLimitWarning flags then
3059 pr "%s\n\n" protocol_limit_warning;
3060 if List.mem DangerWillRobinson flags then
3061 pr "%s\n\n" danger_will_robinson
3063 ) all_functions_sorted
3065 and generate_structs_pod () =
3066 (* LVM structs documentation. *)
3069 pr "=head2 guestfs_lvm_%s\n" typ;
3071 pr " struct guestfs_lvm_%s {\n" typ;
3074 | name, `String -> pr " char *%s;\n" name
3076 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
3077 pr " char %s[32];\n" name
3078 | name, `Bytes -> pr " uint64_t %s;\n" name
3079 | name, `Int -> pr " int64_t %s;\n" name
3080 | name, `OptPercent ->
3081 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
3082 pr " float %s;\n" name
3085 pr " struct guestfs_lvm_%s_list {\n" typ;
3086 pr " uint32_t len; /* Number of elements in list. */\n";
3087 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
3090 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
3093 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3095 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3096 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3098 * We have to use an underscore instead of a dash because otherwise
3099 * rpcgen generates incorrect code.
3101 * This header is NOT exported to clients, but see also generate_structs_h.
3103 and generate_xdr () =
3104 generate_header CStyle LGPLv2;
3106 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3107 pr "typedef string str<>;\n";
3110 (* LVM internal structures. *)
3114 pr "struct guestfs_lvm_int_%s {\n" typ;
3116 | name, `String -> pr " string %s<>;\n" name
3117 | name, `UUID -> pr " opaque %s[32];\n" name
3118 | name, `Bytes -> pr " hyper %s;\n" name
3119 | name, `Int -> pr " hyper %s;\n" name
3120 | name, `OptPercent -> pr " float %s;\n" name
3124 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
3126 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3128 (* Stat internal structures. *)
3132 pr "struct guestfs_int_%s {\n" typ;
3134 | name, `Int -> pr " hyper %s;\n" name
3138 ) ["stat", stat_cols; "statvfs", statvfs_cols];
3141 fun (shortname, style, _, _, _, _, _) ->
3142 let name = "guestfs_" ^ shortname in
3144 (match snd style with
3147 pr "struct %s_args {\n" name;
3150 | String n -> pr " string %s<>;\n" n
3151 | OptString n -> pr " str *%s;\n" n
3152 | StringList n -> pr " str %s<>;\n" n
3153 | Bool n -> pr " bool %s;\n" n
3154 | Int n -> pr " int %s;\n" n
3155 | FileIn _ | FileOut _ -> ()
3159 (match fst style with
3162 pr "struct %s_ret {\n" name;
3166 pr "struct %s_ret {\n" name;
3167 pr " hyper %s;\n" n;
3170 pr "struct %s_ret {\n" name;
3174 failwithf "RConstString cannot be returned from a daemon function"
3176 pr "struct %s_ret {\n" name;
3177 pr " string %s<>;\n" n;
3180 pr "struct %s_ret {\n" name;
3181 pr " str %s<>;\n" n;
3184 pr "struct %s_ret {\n" name;
3189 pr "struct %s_ret {\n" name;
3190 pr " guestfs_lvm_int_pv_list %s;\n" n;
3193 pr "struct %s_ret {\n" name;
3194 pr " guestfs_lvm_int_vg_list %s;\n" n;
3197 pr "struct %s_ret {\n" name;
3198 pr " guestfs_lvm_int_lv_list %s;\n" n;
3201 pr "struct %s_ret {\n" name;
3202 pr " guestfs_int_stat %s;\n" n;
3205 pr "struct %s_ret {\n" name;
3206 pr " guestfs_int_statvfs %s;\n" n;
3209 pr "struct %s_ret {\n" name;
3210 pr " str %s<>;\n" n;
3215 (* Table of procedure numbers. *)
3216 pr "enum guestfs_procedure {\n";
3218 fun (shortname, _, proc_nr, _, _, _, _) ->
3219 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3221 pr " GUESTFS_PROC_NR_PROCS\n";
3225 (* Having to choose a maximum message size is annoying for several
3226 * reasons (it limits what we can do in the API), but it (a) makes
3227 * the protocol a lot simpler, and (b) provides a bound on the size
3228 * of the daemon which operates in limited memory space. For large
3229 * file transfers you should use FTP.
3231 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3234 (* Message header, etc. *)
3236 /* The communication protocol is now documented in the guestfs(3)
3240 const GUESTFS_PROGRAM = 0x2000F5F5;
3241 const GUESTFS_PROTOCOL_VERSION = 1;
3243 /* These constants must be larger than any possible message length. */
3244 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3245 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3247 enum guestfs_message_direction {
3248 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
3249 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
3252 enum guestfs_message_status {
3253 GUESTFS_STATUS_OK = 0,
3254 GUESTFS_STATUS_ERROR = 1
3257 const GUESTFS_ERROR_LEN = 256;
3259 struct guestfs_message_error {
3260 string error_message<GUESTFS_ERROR_LEN>;
3263 struct guestfs_message_header {
3264 unsigned prog; /* GUESTFS_PROGRAM */
3265 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
3266 guestfs_procedure proc; /* GUESTFS_PROC_x */
3267 guestfs_message_direction direction;
3268 unsigned serial; /* message serial number */
3269 guestfs_message_status status;
3272 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3274 struct guestfs_chunk {
3275 int cancel; /* if non-zero, transfer is cancelled */
3276 /* data size is 0 bytes if the transfer has finished successfully */
3277 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3281 (* Generate the guestfs-structs.h file. *)
3282 and generate_structs_h () =
3283 generate_header CStyle LGPLv2;
3285 (* This is a public exported header file containing various
3286 * structures. The structures are carefully written to have
3287 * exactly the same in-memory format as the XDR structures that
3288 * we use on the wire to the daemon. The reason for creating
3289 * copies of these structures here is just so we don't have to
3290 * export the whole of guestfs_protocol.h (which includes much
3291 * unrelated and XDR-dependent stuff that we don't want to be
3292 * public, or required by clients).
3294 * To reiterate, we will pass these structures to and from the
3295 * client with a simple assignment or memcpy, so the format
3296 * must be identical to what rpcgen / the RFC defines.
3299 (* guestfs_int_bool structure. *)
3300 pr "struct guestfs_int_bool {\n";
3306 (* LVM public structures. *)
3310 pr "struct guestfs_lvm_%s {\n" typ;
3313 | name, `String -> pr " char *%s;\n" name
3314 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3315 | name, `Bytes -> pr " uint64_t %s;\n" name
3316 | name, `Int -> pr " int64_t %s;\n" name
3317 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
3321 pr "struct guestfs_lvm_%s_list {\n" typ;
3322 pr " uint32_t len;\n";
3323 pr " struct guestfs_lvm_%s *val;\n" typ;
3326 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3328 (* Stat structures. *)
3332 pr "struct guestfs_%s {\n" typ;
3335 | name, `Int -> pr " int64_t %s;\n" name
3339 ) ["stat", stat_cols; "statvfs", statvfs_cols]
3341 (* Generate the guestfs-actions.h file. *)
3342 and generate_actions_h () =
3343 generate_header CStyle LGPLv2;
3345 fun (shortname, style, _, _, _, _, _) ->
3346 let name = "guestfs_" ^ shortname in
3347 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3351 (* Generate the client-side dispatch stubs. *)
3352 and generate_client_actions () =
3353 generate_header CStyle LGPLv2;
3359 #include \"guestfs.h\"
3360 #include \"guestfs_protocol.h\"
3362 #define error guestfs_error
3363 #define perrorf guestfs_perrorf
3364 #define safe_malloc guestfs_safe_malloc
3365 #define safe_realloc guestfs_safe_realloc
3366 #define safe_strdup guestfs_safe_strdup
3367 #define safe_memdup guestfs_safe_memdup
3369 /* Check the return message from a call for validity. */
3371 check_reply_header (guestfs_h *g,
3372 const struct guestfs_message_header *hdr,
3373 int proc_nr, int serial)
3375 if (hdr->prog != GUESTFS_PROGRAM) {
3376 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3379 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3380 error (g, \"wrong protocol version (%%d/%%d)\",
3381 hdr->vers, GUESTFS_PROTOCOL_VERSION);
3384 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3385 error (g, \"unexpected message direction (%%d/%%d)\",
3386 hdr->direction, GUESTFS_DIRECTION_REPLY);
3389 if (hdr->proc != proc_nr) {
3390 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3393 if (hdr->serial != serial) {
3394 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3401 /* Check we are in the right state to run a high-level action. */
3403 check_state (guestfs_h *g, const char *caller)
3405 if (!guestfs_is_ready (g)) {
3406 if (guestfs_is_config (g))
3407 error (g, \"%%s: call launch() before using this function\",
3409 else if (guestfs_is_launching (g))
3410 error (g, \"%%s: call wait_ready() before using this function\",
3413 error (g, \"%%s called from the wrong state, %%d != READY\",
3414 caller, guestfs_get_state (g));
3422 (* Client-side stubs for each function. *)
3424 fun (shortname, style, _, _, _, _, _) ->
3425 let name = "guestfs_" ^ shortname in
3427 (* Generate the context struct which stores the high-level
3428 * state between callback functions.
3430 pr "struct %s_ctx {\n" shortname;
3431 pr " /* This flag is set by the callbacks, so we know we've done\n";
3432 pr " * the callbacks as expected, and in the right sequence.\n";
3433 pr " * 0 = not called, 1 = reply_cb called.\n";
3435 pr " int cb_sequence;\n";
3436 pr " struct guestfs_message_header hdr;\n";
3437 pr " struct guestfs_message_error err;\n";
3438 (match fst style with
3441 failwithf "RConstString cannot be returned from a daemon function"
3443 | RBool _ | RString _ | RStringList _
3445 | RPVList _ | RVGList _ | RLVList _
3446 | RStat _ | RStatVFS _
3448 pr " struct %s_ret ret;\n" name
3453 (* Generate the reply callback function. *)
3454 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3456 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3457 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3459 pr " /* This should definitely not happen. */\n";
3460 pr " if (ctx->cb_sequence != 0) {\n";
3461 pr " ctx->cb_sequence = 9999;\n";
3462 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3466 pr " ml->main_loop_quit (ml, g);\n";
3468 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3469 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3472 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3473 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3474 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3481 (match fst style with
3484 failwithf "RConstString cannot be returned from a daemon function"
3486 | RBool _ | RString _ | RStringList _
3488 | RPVList _ | RVGList _ | RLVList _
3489 | RStat _ | RStatVFS _
3491 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3492 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3498 pr " ctx->cb_sequence = 1;\n";
3501 (* Generate the action stub. *)
3502 generate_prototype ~extern:false ~semicolon:false ~newline:true
3503 ~handle:"g" name style;
3506 match fst style with
3507 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3509 failwithf "RConstString cannot be returned from a daemon function"
3510 | RString _ | RStringList _ | RIntBool _
3511 | RPVList _ | RVGList _ | RLVList _
3512 | RStat _ | RStatVFS _
3518 (match snd style with
3520 | _ -> pr " struct %s_args args;\n" name
3523 pr " struct %s_ctx ctx;\n" shortname;
3524 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3525 pr " int serial;\n";
3527 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3528 pr " guestfs_set_busy (g);\n";
3530 pr " memset (&ctx, 0, sizeof ctx);\n";
3533 (* Send the main header and arguments. *)
3534 (match snd style with
3536 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3537 (String.uppercase shortname)
3542 pr " args.%s = (char *) %s;\n" n n
3544 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
3546 pr " args.%s.%s_val = (char **) %s;\n" n n n;
3547 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3549 pr " args.%s = %s;\n" n n
3551 pr " args.%s = %s;\n" n n
3552 | FileIn _ | FileOut _ -> ()
3554 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3555 (String.uppercase shortname);
3556 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3559 pr " if (serial == -1) {\n";
3560 pr " guestfs_end_busy (g);\n";
3561 pr " return %s;\n" error_code;
3565 (* Send any additional files (FileIn) requested. *)
3566 let need_read_reply_label = ref false in
3573 pr " r = guestfs__send_file_sync (g, %s);\n" n;
3574 pr " if (r == -1) {\n";
3575 pr " guestfs_end_busy (g);\n";
3576 pr " return %s;\n" error_code;
3578 pr " if (r == -2) /* daemon cancelled */\n";
3579 pr " goto read_reply;\n";
3580 need_read_reply_label := true;
3586 (* Wait for the reply from the remote end. *)
3587 if !need_read_reply_label then pr " read_reply:\n";
3588 pr " guestfs__switch_to_receiving (g);\n";
3589 pr " ctx.cb_sequence = 0;\n";
3590 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3591 pr " (void) ml->main_loop_run (ml, g);\n";
3592 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
3593 pr " if (ctx.cb_sequence != 1) {\n";
3594 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3595 pr " guestfs_end_busy (g);\n";
3596 pr " return %s;\n" error_code;
3600 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3601 (String.uppercase shortname);
3602 pr " guestfs_end_busy (g);\n";
3603 pr " return %s;\n" error_code;
3607 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3608 pr " error (g, \"%%s\", ctx.err.error_message);\n";
3609 pr " free (ctx.err.error_message);\n";
3610 pr " guestfs_end_busy (g);\n";
3611 pr " return %s;\n" error_code;
3615 (* Expecting to receive further files (FileOut)? *)
3619 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3620 pr " guestfs_end_busy (g);\n";
3621 pr " return %s;\n" error_code;
3627 pr " guestfs_end_busy (g);\n";
3629 (match fst style with
3630 | RErr -> pr " return 0;\n"
3631 | RInt n | RInt64 n | RBool n ->
3632 pr " return ctx.ret.%s;\n" n
3634 failwithf "RConstString cannot be returned from a daemon function"
3636 pr " return ctx.ret.%s; /* caller will free */\n" n
3637 | RStringList n | RHashtable n ->
3638 pr " /* caller will free this, but we need to add a NULL entry */\n";
3639 pr " ctx.ret.%s.%s_val =\n" n n;
3640 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3641 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3643 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3644 pr " return ctx.ret.%s.%s_val;\n" n n
3646 pr " /* caller with free this */\n";
3647 pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3648 | RPVList n | RVGList n | RLVList n
3649 | RStat n | RStatVFS n ->
3650 pr " /* caller will free this */\n";
3651 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3657 (* Generate daemon/actions.h. *)
3658 and generate_daemon_actions_h () =
3659 generate_header CStyle GPLv2;
3661 pr "#include \"../src/guestfs_protocol.h\"\n";
3665 fun (name, style, _, _, _, _, _) ->
3667 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3671 (* Generate the server-side stubs. *)
3672 and generate_daemon_actions () =
3673 generate_header CStyle GPLv2;
3675 pr "#include <config.h>\n";
3677 pr "#include <stdio.h>\n";
3678 pr "#include <stdlib.h>\n";
3679 pr "#include <string.h>\n";
3680 pr "#include <inttypes.h>\n";
3681 pr "#include <ctype.h>\n";
3682 pr "#include <rpc/types.h>\n";
3683 pr "#include <rpc/xdr.h>\n";
3685 pr "#include \"daemon.h\"\n";
3686 pr "#include \"../src/guestfs_protocol.h\"\n";
3687 pr "#include \"actions.h\"\n";
3691 fun (name, style, _, _, _, _, _) ->
3692 (* Generate server-side stubs. *)
3693 pr "static void %s_stub (XDR *xdr_in)\n" name;
3696 match fst style with
3697 | RErr | RInt _ -> pr " int r;\n"; "-1"
3698 | RInt64 _ -> pr " int64_t r;\n"; "-1"
3699 | RBool _ -> pr " int r;\n"; "-1"
3701 failwithf "RConstString cannot be returned from a daemon function"
3702 | RString _ -> pr " char *r;\n"; "NULL"
3703 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
3704 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
3705 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
3706 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
3707 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
3708 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
3709 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
3711 (match snd style with
3714 pr " struct guestfs_%s_args args;\n" name;
3717 (* Note we allow the string to be writable, in order to
3718 * allow device name translation. This is safe because
3719 * we can modify the string (passed from RPC).
3722 | OptString n -> pr " char *%s;\n" n
3723 | StringList n -> pr " char **%s;\n" n
3724 | Bool n -> pr " int %s;\n" n
3725 | Int n -> pr " int %s;\n" n
3726 | FileIn _ | FileOut _ -> ()
3731 (match snd style with
3734 pr " memset (&args, 0, sizeof args);\n";
3736 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
3737 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
3742 | String n -> pr " %s = args.%s;\n" n n
3743 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
3745 pr " %s = realloc (args.%s.%s_val,\n" n n n;
3746 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
3747 pr " if (%s == NULL) {\n" n;
3748 pr " reply_with_perror (\"realloc\");\n";
3751 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
3752 pr " args.%s.%s_val = %s;\n" n n n;
3753 | Bool n -> pr " %s = args.%s;\n" n n
3754 | Int n -> pr " %s = args.%s;\n" n n
3755 | FileIn _ | FileOut _ -> ()
3760 (* Don't want to call the impl with any FileIn or FileOut
3761 * parameters, since these go "outside" the RPC protocol.
3764 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
3766 pr " r = do_%s " name;
3767 generate_call_args argsnofile;
3770 pr " if (r == %s)\n" error_code;
3771 pr " /* do_%s has already called reply_with_error */\n" name;
3775 (* If there are any FileOut parameters, then the impl must
3776 * send its own reply.
3779 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
3781 pr " /* do_%s has already sent a reply */\n" name
3783 match fst style with
3784 | RErr -> pr " reply (NULL, NULL);\n"
3785 | RInt n | RInt64 n | RBool n ->
3786 pr " struct guestfs_%s_ret ret;\n" name;
3787 pr " ret.%s = r;\n" n;
3788 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3791 failwithf "RConstString cannot be returned from a daemon function"
3793 pr " struct guestfs_%s_ret ret;\n" name;
3794 pr " ret.%s = r;\n" n;
3795 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3798 | RStringList n | RHashtable n ->
3799 pr " struct guestfs_%s_ret ret;\n" name;
3800 pr " ret.%s.%s_len = count_strings (r);\n" n n;
3801 pr " ret.%s.%s_val = r;\n" n n;
3802 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3804 pr " free_strings (r);\n"
3806 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
3808 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
3809 | RPVList n | RVGList n | RLVList n
3810 | RStat n | RStatVFS n ->
3811 pr " struct guestfs_%s_ret ret;\n" name;
3812 pr " ret.%s = *r;\n" n;
3813 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3815 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3819 (* Free the args. *)
3820 (match snd style with
3825 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
3832 (* Dispatch function. *)
3833 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
3835 pr " switch (proc_nr) {\n";
3838 fun (name, style, _, _, _, _, _) ->
3839 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
3840 pr " %s_stub (xdr_in);\n" name;
3845 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";
3850 (* LVM columns and tokenization functions. *)
3851 (* XXX This generates crap code. We should rethink how we
3857 pr "static const char *lvm_%s_cols = \"%s\";\n"
3858 typ (String.concat "," (List.map fst cols));
3861 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
3863 pr " char *tok, *p, *next;\n";
3867 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
3870 pr " if (!str) {\n";
3871 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
3874 pr " if (!*str || isspace (*str)) {\n";
3875 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
3880 fun (name, coltype) ->
3881 pr " if (!tok) {\n";
3882 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
3885 pr " p = strchrnul (tok, ',');\n";
3886 pr " if (*p) next = p+1; else next = NULL;\n";
3887 pr " *p = '\\0';\n";
3890 pr " r->%s = strdup (tok);\n" name;
3891 pr " if (r->%s == NULL) {\n" name;
3892 pr " perror (\"strdup\");\n";
3896 pr " for (i = j = 0; i < 32; ++j) {\n";
3897 pr " if (tok[j] == '\\0') {\n";
3898 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
3900 pr " } else if (tok[j] != '-')\n";
3901 pr " r->%s[i++] = tok[j];\n" name;
3904 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
3905 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3909 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
3910 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3914 pr " if (tok[0] == '\\0')\n";
3915 pr " r->%s = -1;\n" name;
3916 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
3917 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3921 pr " tok = next;\n";
3924 pr " if (tok != NULL) {\n";
3925 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
3932 pr "guestfs_lvm_int_%s_list *\n" typ;
3933 pr "parse_command_line_%ss (void)\n" typ;
3935 pr " char *out, *err;\n";
3936 pr " char *p, *pend;\n";
3938 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
3939 pr " void *newp;\n";
3941 pr " ret = malloc (sizeof *ret);\n";
3942 pr " if (!ret) {\n";
3943 pr " reply_with_perror (\"malloc\");\n";
3944 pr " return NULL;\n";
3947 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
3948 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
3950 pr " r = command (&out, &err,\n";
3951 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
3952 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
3953 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
3954 pr " if (r == -1) {\n";
3955 pr " reply_with_error (\"%%s\", err);\n";
3956 pr " free (out);\n";
3957 pr " free (err);\n";
3958 pr " free (ret);\n";
3959 pr " return NULL;\n";
3962 pr " free (err);\n";
3964 pr " /* Tokenize each line of the output. */\n";
3967 pr " while (p) {\n";
3968 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
3969 pr " if (pend) {\n";
3970 pr " *pend = '\\0';\n";
3974 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
3977 pr " if (!*p) { /* Empty line? Skip it. */\n";
3982 pr " /* Allocate some space to store this next entry. */\n";
3983 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
3984 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
3985 pr " if (newp == NULL) {\n";
3986 pr " reply_with_perror (\"realloc\");\n";
3987 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3988 pr " free (ret);\n";
3989 pr " free (out);\n";
3990 pr " return NULL;\n";
3992 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
3994 pr " /* Tokenize the next entry. */\n";
3995 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
3996 pr " if (r == -1) {\n";
3997 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
3998 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3999 pr " free (ret);\n";
4000 pr " free (out);\n";
4001 pr " return NULL;\n";
4008 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
4010 pr " free (out);\n";
4011 pr " return ret;\n";
4014 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4016 (* Generate the tests. *)
4017 and generate_tests () =
4018 generate_header CStyle GPLv2;
4025 #include <sys/types.h>
4028 #include \"guestfs.h\"
4030 static guestfs_h *g;
4031 static int suppress_error = 0;
4033 static void print_error (guestfs_h *g, void *data, const char *msg)
4035 if (!suppress_error)
4036 fprintf (stderr, \"%%s\\n\", msg);
4039 static void print_strings (char * const * const argv)
4043 for (argc = 0; argv[argc] != NULL; ++argc)
4044 printf (\"\\t%%s\\n\", argv[argc]);
4048 static void print_table (char * const * const argv)
4052 for (i = 0; argv[i] != NULL; i += 2)
4053 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
4057 static void no_test_warnings (void)
4063 | name, _, _, _, [], _, _ ->
4064 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
4065 | name, _, _, _, tests, _, _ -> ()
4071 (* Generate the actual tests. Note that we generate the tests
4072 * in reverse order, deliberately, so that (in general) the
4073 * newest tests run first. This makes it quicker and easier to
4078 fun (name, _, _, _, tests, _, _) ->
4079 mapi (generate_one_test name) tests
4080 ) (List.rev all_functions) in
4081 let test_names = List.concat test_names in
4082 let nr_tests = List.length test_names in
4085 int main (int argc, char *argv[])
4089 const char *filename;
4091 int nr_tests, test_num = 0;
4093 no_test_warnings ();
4095 g = guestfs_create ();
4097 printf (\"guestfs_create FAILED\\n\");
4101 guestfs_set_error_handler (g, print_error, NULL);
4103 guestfs_set_path (g, \"../appliance\");
4105 filename = \"test1.img\";
4106 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4111 if (lseek (fd, %d, SEEK_SET) == -1) {
4117 if (write (fd, &c, 1) == -1) {
4123 if (close (fd) == -1) {
4128 if (guestfs_add_drive (g, filename) == -1) {
4129 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4133 filename = \"test2.img\";
4134 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4139 if (lseek (fd, %d, SEEK_SET) == -1) {
4145 if (write (fd, &c, 1) == -1) {
4151 if (close (fd) == -1) {
4156 if (guestfs_add_drive (g, filename) == -1) {
4157 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4161 filename = \"test3.img\";
4162 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4167 if (lseek (fd, %d, SEEK_SET) == -1) {
4173 if (write (fd, &c, 1) == -1) {
4179 if (close (fd) == -1) {
4184 if (guestfs_add_drive (g, filename) == -1) {
4185 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4189 if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4190 printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4194 if (guestfs_launch (g) == -1) {
4195 printf (\"guestfs_launch FAILED\\n\");
4199 /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4202 if (guestfs_wait_ready (g) == -1) {
4203 printf (\"guestfs_wait_ready FAILED\\n\");
4207 /* Cancel previous alarm. */
4212 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4216 pr " test_num++;\n";
4217 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4218 pr " if (%s () == -1) {\n" test_name;
4219 pr " printf (\"%s FAILED\\n\");\n" test_name;
4225 pr " guestfs_close (g);\n";
4226 pr " unlink (\"test1.img\");\n";
4227 pr " unlink (\"test2.img\");\n";
4228 pr " unlink (\"test3.img\");\n";
4231 pr " if (failed > 0) {\n";
4232 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4240 and generate_one_test name i (init, prereq, test) =
4241 let test_name = sprintf "test_%s_%d" name i in
4244 static int %s_skip (void)
4248 str = getenv (\"TEST_ONLY\");
4250 return strstr (str, \"%s\") == NULL;
4251 str = getenv (\"SKIP_%s\");
4252 if (str && strcmp (str, \"1\") == 0) return 1;
4253 str = getenv (\"SKIP_TEST_%s\");
4254 if (str && strcmp (str, \"1\") == 0) return 1;
4258 " test_name name (String.uppercase test_name) (String.uppercase name);
4261 | Disabled | Always -> ()
4262 | If code | Unless code ->
4263 pr "static int %s_prereq (void)\n" test_name;
4271 static int %s (void)
4274 printf (\"%%s skipped (reason: environment variable set)\\n\", \"%s\");
4278 " test_name test_name test_name;
4282 pr " printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4284 pr " if (! %s_prereq ()) {\n" test_name;
4285 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4289 generate_one_test_body name i test_name init test;
4291 pr " if (%s_prereq ()) {\n" test_name;
4292 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4296 generate_one_test_body name i test_name init test;
4298 generate_one_test_body name i test_name init test
4306 and generate_one_test_body name i test_name init test =
4310 pr " /* InitNone|InitEmpty for %s */\n" test_name;
4311 List.iter (generate_test_command_call test_name)
4312 [["blockdev_setrw"; "/dev/sda"];
4316 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4317 List.iter (generate_test_command_call test_name)
4318 [["blockdev_setrw"; "/dev/sda"];
4321 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4322 ["mkfs"; "ext2"; "/dev/sda1"];
4323 ["mount"; "/dev/sda1"; "/"]]
4324 | InitBasicFSonLVM ->
4325 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4327 List.iter (generate_test_command_call test_name)
4328 [["blockdev_setrw"; "/dev/sda"];
4331 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4332 ["pvcreate"; "/dev/sda1"];
4333 ["vgcreate"; "VG"; "/dev/sda1"];
4334 ["lvcreate"; "LV"; "VG"; "8"];
4335 ["mkfs"; "ext2"; "/dev/VG/LV"];
4336 ["mount"; "/dev/VG/LV"; "/"]]
4339 let get_seq_last = function
4341 failwithf "%s: you cannot use [] (empty list) when expecting a command"
4344 let seq = List.rev seq in
4345 List.rev (List.tl seq), List.hd seq
4350 pr " /* TestRun for %s (%d) */\n" name i;
4351 List.iter (generate_test_command_call test_name) seq
4352 | TestOutput (seq, expected) ->
4353 pr " /* TestOutput for %s (%d) */\n" name i;
4354 pr " char expected[] = \"%s\";\n" (c_quote expected);
4355 let seq, last = get_seq_last seq in
4357 pr " if (strcmp (r, expected) != 0) {\n";
4358 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4362 List.iter (generate_test_command_call test_name) seq;
4363 generate_test_command_call ~test test_name last
4364 | TestOutputList (seq, expected) ->
4365 pr " /* TestOutputList for %s (%d) */\n" name i;
4366 let seq, last = get_seq_last seq in
4370 pr " if (!r[%d]) {\n" i;
4371 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4372 pr " print_strings (r);\n";
4376 pr " char expected[] = \"%s\";\n" (c_quote str);
4377 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4378 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4383 pr " if (r[%d] != NULL) {\n" (List.length expected);
4384 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4386 pr " print_strings (r);\n";
4390 List.iter (generate_test_command_call test_name) seq;
4391 generate_test_command_call ~test test_name last
4392 | TestOutputListOfDevices (seq, expected) ->
4393 pr " /* TestOutputListOfDevices for %s (%d) */\n" name i;
4394 let seq, last = get_seq_last seq in
4398 pr " if (!r[%d]) {\n" i;
4399 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4400 pr " print_strings (r);\n";
4404 pr " char expected[] = \"%s\";\n" (c_quote str);
4405 pr " r[%d][5] = 's';\n" i;
4406 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4407 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4412 pr " if (r[%d] != NULL) {\n" (List.length expected);
4413 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4415 pr " print_strings (r);\n";
4419 List.iter (generate_test_command_call test_name) seq;
4420 generate_test_command_call ~test test_name last
4421 | TestOutputInt (seq, expected) ->
4422 pr " /* TestOutputInt for %s (%d) */\n" name i;
4423 let seq, last = get_seq_last seq in
4425 pr " if (r != %d) {\n" expected;
4426 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4432 List.iter (generate_test_command_call test_name) seq;
4433 generate_test_command_call ~test test_name last
4434 | TestOutputTrue seq ->
4435 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4436 let seq, last = get_seq_last seq in
4439 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4444 List.iter (generate_test_command_call test_name) seq;
4445 generate_test_command_call ~test test_name last
4446 | TestOutputFalse seq ->
4447 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4448 let seq, last = get_seq_last seq in
4451 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4456 List.iter (generate_test_command_call test_name) seq;
4457 generate_test_command_call ~test test_name last
4458 | TestOutputLength (seq, expected) ->
4459 pr " /* TestOutputLength for %s (%d) */\n" name i;
4460 let seq, last = get_seq_last seq in
4463 pr " for (j = 0; j < %d; ++j)\n" expected;
4464 pr " if (r[j] == NULL) {\n";
4465 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4467 pr " print_strings (r);\n";
4470 pr " if (r[j] != NULL) {\n";
4471 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4473 pr " print_strings (r);\n";
4477 List.iter (generate_test_command_call test_name) seq;
4478 generate_test_command_call ~test test_name last
4479 | TestOutputStruct (seq, checks) ->
4480 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4481 let seq, last = get_seq_last seq in
4485 | CompareWithInt (field, expected) ->
4486 pr " if (r->%s != %d) {\n" field expected;
4487 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4488 test_name field expected;
4489 pr " (int) r->%s);\n" field;
4492 | CompareWithString (field, expected) ->
4493 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4494 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4495 test_name field expected;
4496 pr " r->%s);\n" field;
4499 | CompareFieldsIntEq (field1, field2) ->
4500 pr " if (r->%s != r->%s) {\n" field1 field2;
4501 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4502 test_name field1 field2;
4503 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4506 | CompareFieldsStrEq (field1, field2) ->
4507 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4508 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4509 test_name field1 field2;
4510 pr " r->%s, r->%s);\n" field1 field2;
4515 List.iter (generate_test_command_call test_name) seq;
4516 generate_test_command_call ~test test_name last
4517 | TestLastFail seq ->
4518 pr " /* TestLastFail for %s (%d) */\n" name i;
4519 let seq, last = get_seq_last seq in
4520 List.iter (generate_test_command_call test_name) seq;
4521 generate_test_command_call test_name ~expect_error:true last
4523 (* Generate the code to run a command, leaving the result in 'r'.
4524 * If you expect to get an error then you should set expect_error:true.
4526 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4528 | [] -> assert false
4530 (* Look up the command to find out what args/ret it has. *)
4533 let _, style, _, _, _, _, _ =
4534 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4537 failwithf "%s: in test, command %s was not found" test_name name in
4539 if List.length (snd style) <> List.length args then
4540 failwithf "%s: in test, wrong number of args given to %s"
4547 | OptString n, "NULL" -> ()
4549 | OptString n, arg ->
4550 pr " char %s[] = \"%s\";\n" n (c_quote arg);
4553 | FileIn _, _ | FileOut _, _ -> ()
4554 | StringList n, arg ->
4555 let strs = string_split " " arg in
4558 pr " char %s_%d[] = \"%s\";\n" n i (c_quote str);
4560 pr " char *%s[] = {\n" n;
4562 fun i _ -> pr " %s_%d,\n" n i
4566 ) (List.combine (snd style) args);
4569 match fst style with
4570 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4571 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4572 | RConstString _ -> pr " const char *r;\n"; "NULL"
4573 | RString _ -> pr " char *r;\n"; "NULL"
4574 | RStringList _ | RHashtable _ ->
4579 pr " struct guestfs_int_bool *r;\n"; "NULL"
4581 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4583 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4585 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4587 pr " struct guestfs_stat *r;\n"; "NULL"
4589 pr " struct guestfs_statvfs *r;\n"; "NULL" in
4591 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4592 pr " r = guestfs_%s (g" name;
4594 (* Generate the parameters. *)
4597 | OptString _, "NULL" -> pr ", NULL"
4601 | FileIn _, arg | FileOut _, arg ->
4602 pr ", \"%s\"" (c_quote arg)
4603 | StringList n, _ ->
4607 try int_of_string arg
4608 with Failure "int_of_string" ->
4609 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4612 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4613 ) (List.combine (snd style) args);
4616 if not expect_error then
4617 pr " if (r == %s)\n" error_code
4619 pr " if (r != %s)\n" error_code;
4622 (* Insert the test code. *)
4628 (match fst style with
4629 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4630 | RString _ -> pr " free (r);\n"
4631 | RStringList _ | RHashtable _ ->
4632 pr " for (i = 0; r[i] != NULL; ++i)\n";
4633 pr " free (r[i]);\n";
4636 pr " guestfs_free_int_bool (r);\n"
4638 pr " guestfs_free_lvm_pv_list (r);\n"
4640 pr " guestfs_free_lvm_vg_list (r);\n"
4642 pr " guestfs_free_lvm_lv_list (r);\n"
4643 | RStat _ | RStatVFS _ ->
4650 let str = replace_str str "\r" "\\r" in
4651 let str = replace_str str "\n" "\\n" in
4652 let str = replace_str str "\t" "\\t" in
4653 let str = replace_str str "\000" "\\0" in
4656 (* Generate a lot of different functions for guestfish. *)
4657 and generate_fish_cmds () =
4658 generate_header CStyle GPLv2;
4662 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4664 let all_functions_sorted =
4666 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4667 ) all_functions_sorted in
4669 pr "#include <stdio.h>\n";
4670 pr "#include <stdlib.h>\n";
4671 pr "#include <string.h>\n";
4672 pr "#include <inttypes.h>\n";
4674 pr "#include <guestfs.h>\n";
4675 pr "#include \"fish.h\"\n";
4678 (* list_commands function, which implements guestfish -h *)
4679 pr "void list_commands (void)\n";
4681 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
4682 pr " list_builtin_commands ();\n";
4684 fun (name, _, _, flags, _, shortdesc, _) ->
4685 let name = replace_char name '_' '-' in
4686 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4688 ) all_functions_sorted;
4689 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4693 (* display_command function, which implements guestfish -h cmd *)
4694 pr "void display_command (const char *cmd)\n";
4697 fun (name, style, _, flags, _, shortdesc, longdesc) ->
4698 let name2 = replace_char name '_' '-' in
4700 try find_map (function FishAlias n -> Some n | _ -> None) flags
4701 with Not_found -> name in
4702 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4704 match snd style with
4708 name2 (String.concat "> <" (List.map name_of_argt args)) in
4711 if List.mem ProtocolLimitWarning flags then
4712 ("\n\n" ^ protocol_limit_warning)
4715 (* For DangerWillRobinson commands, we should probably have
4716 * guestfish prompt before allowing you to use them (especially
4717 * in interactive mode). XXX
4721 if List.mem DangerWillRobinson flags then
4722 ("\n\n" ^ danger_will_robinson)
4725 let describe_alias =
4726 if name <> alias then
4727 sprintf "\n\nYou can use '%s' as an alias for this command." alias
4731 pr "strcasecmp (cmd, \"%s\") == 0" name;
4732 if name <> name2 then
4733 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4734 if name <> alias then
4735 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4737 pr " pod2text (\"%s - %s\", %S);\n"
4739 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4742 pr " display_builtin_command (cmd);\n";
4746 (* print_{pv,vg,lv}_list functions *)
4750 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4757 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4759 pr " printf (\"%s: \");\n" name;
4760 pr " for (i = 0; i < 32; ++i)\n";
4761 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
4762 pr " printf (\"\\n\");\n"
4764 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4766 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4767 | name, `OptPercent ->
4768 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4769 typ name name typ name;
4770 pr " else printf (\"%s: \\n\");\n" name
4774 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4779 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4780 pr " print_%s (&%ss->val[i]);\n" typ typ;
4783 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4785 (* print_{stat,statvfs} functions *)
4789 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4794 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4798 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4800 (* run_<action> actions *)
4802 fun (name, style, _, flags, _, _, _) ->
4803 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4805 (match fst style with
4808 | RBool _ -> pr " int r;\n"
4809 | RInt64 _ -> pr " int64_t r;\n"
4810 | RConstString _ -> pr " const char *r;\n"
4811 | RString _ -> pr " char *r;\n"
4812 | RStringList _ | RHashtable _ -> pr " char **r;\n"
4813 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
4814 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
4815 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
4816 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
4817 | RStat _ -> pr " struct guestfs_stat *r;\n"
4818 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
4825 | FileOut n -> pr " const char *%s;\n" n
4826 | StringList n -> pr " char **%s;\n" n
4827 | Bool n -> pr " int %s;\n" n
4828 | Int n -> pr " int %s;\n" n
4831 (* Check and convert parameters. *)
4832 let argc_expected = List.length (snd style) in
4833 pr " if (argc != %d) {\n" argc_expected;
4834 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
4836 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
4842 | String name -> pr " %s = argv[%d];\n" name i
4844 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
4847 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
4850 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
4852 | StringList name ->
4853 pr " %s = parse_string_list (argv[%d]);\n" name i
4855 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
4857 pr " %s = atoi (argv[%d]);\n" name i
4860 (* Call C API function. *)
4862 try find_map (function FishAction n -> Some n | _ -> None) flags
4863 with Not_found -> sprintf "guestfs_%s" name in
4865 generate_call_args ~handle:"g" (snd style);
4868 (* Check return value for errors and display command results. *)
4869 (match fst style with
4870 | RErr -> pr " return r;\n"
4872 pr " if (r == -1) return -1;\n";
4873 pr " printf (\"%%d\\n\", r);\n";
4876 pr " if (r == -1) return -1;\n";
4877 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
4880 pr " if (r == -1) return -1;\n";
4881 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
4884 pr " if (r == NULL) return -1;\n";
4885 pr " printf (\"%%s\\n\", r);\n";
4888 pr " if (r == NULL) return -1;\n";
4889 pr " printf (\"%%s\\n\", r);\n";
4893 pr " if (r == NULL) return -1;\n";
4894 pr " print_strings (r);\n";
4895 pr " free_strings (r);\n";
4898 pr " if (r == NULL) return -1;\n";
4899 pr " printf (\"%%d, %%s\\n\", r->i,\n";
4900 pr " r->b ? \"true\" : \"false\");\n";
4901 pr " guestfs_free_int_bool (r);\n";
4904 pr " if (r == NULL) return -1;\n";
4905 pr " print_pv_list (r);\n";
4906 pr " guestfs_free_lvm_pv_list (r);\n";
4909 pr " if (r == NULL) return -1;\n";
4910 pr " print_vg_list (r);\n";
4911 pr " guestfs_free_lvm_vg_list (r);\n";
4914 pr " if (r == NULL) return -1;\n";
4915 pr " print_lv_list (r);\n";
4916 pr " guestfs_free_lvm_lv_list (r);\n";
4919 pr " if (r == NULL) return -1;\n";
4920 pr " print_stat (r);\n";
4924 pr " if (r == NULL) return -1;\n";
4925 pr " print_statvfs (r);\n";
4929 pr " if (r == NULL) return -1;\n";
4930 pr " print_table (r);\n";
4931 pr " free_strings (r);\n";
4938 (* run_action function *)
4939 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
4942 fun (name, _, _, flags, _, _, _) ->
4943 let name2 = replace_char name '_' '-' in
4945 try find_map (function FishAlias n -> Some n | _ -> None) flags
4946 with Not_found -> name in
4948 pr "strcasecmp (cmd, \"%s\") == 0" name;
4949 if name <> name2 then
4950 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4951 if name <> alias then
4952 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4954 pr " return run_%s (cmd, argc, argv);\n" name;
4958 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
4965 (* Readline completion for guestfish. *)
4966 and generate_fish_completion () =
4967 generate_header CStyle GPLv2;
4971 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4981 #ifdef HAVE_LIBREADLINE
4982 #include <readline/readline.h>
4987 #ifdef HAVE_LIBREADLINE
4989 static const char *const commands[] = {
4990 BUILTIN_COMMANDS_FOR_COMPLETION,
4993 (* Get the commands, including the aliases. They don't need to be
4994 * sorted - the generator() function just does a dumb linear search.
4998 fun (name, _, _, flags, _, _, _) ->
4999 let name2 = replace_char name '_' '-' in
5001 try find_map (function FishAlias n -> Some n | _ -> None) flags
5002 with Not_found -> name in
5004 if name <> alias then [name2; alias] else [name2]
5006 let commands = List.flatten commands in
5008 List.iter (pr " \"%s\",\n") commands;
5014 generator (const char *text, int state)
5016 static int index, len;
5021 len = strlen (text);
5024 rl_attempted_completion_over = 1;
5026 while ((name = commands[index]) != NULL) {
5028 if (strncasecmp (name, text, len) == 0)
5029 return strdup (name);
5035 #endif /* HAVE_LIBREADLINE */
5037 char **do_completion (const char *text, int start, int end)
5039 char **matches = NULL;
5041 #ifdef HAVE_LIBREADLINE
5042 rl_completion_append_character = ' ';
5045 matches = rl_completion_matches (text, generator);
5046 else if (complete_dest_paths)
5047 matches = rl_completion_matches (text, complete_dest_paths_generator);
5054 (* Generate the POD documentation for guestfish. *)
5055 and generate_fish_actions_pod () =
5056 let all_functions_sorted =
5058 fun (_, _, _, flags, _, _, _) ->
5059 not (List.mem NotInFish flags || List.mem NotInDocs flags)
5060 ) all_functions_sorted in
5062 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
5065 fun (name, style, _, flags, _, _, longdesc) ->
5067 Str.global_substitute rex (
5070 try Str.matched_group 1 s
5072 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
5073 "C<" ^ replace_char sub '_' '-' ^ ">"
5075 let name = replace_char name '_' '-' in
5077 try find_map (function FishAlias n -> Some n | _ -> None) flags
5078 with Not_found -> name in
5080 pr "=head2 %s" name;
5081 if name <> alias then
5088 | String n -> pr " %s" n
5089 | OptString n -> pr " %s" n
5090 | StringList n -> pr " '%s ...'" n
5091 | Bool _ -> pr " true|false"
5092 | Int n -> pr " %s" n
5093 | FileIn n | FileOut n -> pr " (%s|-)" n
5097 pr "%s\n\n" longdesc;
5099 if List.exists (function FileIn _ | FileOut _ -> true
5100 | _ -> false) (snd style) then
5101 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5103 if List.mem ProtocolLimitWarning flags then
5104 pr "%s\n\n" protocol_limit_warning;
5106 if List.mem DangerWillRobinson flags then
5107 pr "%s\n\n" danger_will_robinson
5108 ) all_functions_sorted
5110 (* Generate a C function prototype. *)
5111 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5112 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5114 ?handle name style =
5115 if extern then pr "extern ";
5116 if static then pr "static ";
5117 (match fst style with
5119 | RInt _ -> pr "int "
5120 | RInt64 _ -> pr "int64_t "
5121 | RBool _ -> pr "int "
5122 | RConstString _ -> pr "const char *"
5123 | RString _ -> pr "char *"
5124 | RStringList _ | RHashtable _ -> pr "char **"
5126 if not in_daemon then pr "struct guestfs_int_bool *"
5127 else pr "guestfs_%s_ret *" name
5129 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
5130 else pr "guestfs_lvm_int_pv_list *"
5132 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
5133 else pr "guestfs_lvm_int_vg_list *"
5135 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
5136 else pr "guestfs_lvm_int_lv_list *"
5138 if not in_daemon then pr "struct guestfs_stat *"
5139 else pr "guestfs_int_stat *"
5141 if not in_daemon then pr "struct guestfs_statvfs *"
5142 else pr "guestfs_int_statvfs *"
5144 pr "%s%s (" prefix name;
5145 if handle = None && List.length (snd style) = 0 then
5148 let comma = ref false in
5151 | Some handle -> pr "guestfs_h *%s" handle; comma := true
5155 if single_line then pr ", " else pr ",\n\t\t"
5164 if not in_daemon then pr "const char *%s" n
5165 else pr "char *%s" n
5168 if not in_daemon then pr "char * const* const %s" n
5169 else pr "char **%s" n
5170 | Bool n -> next (); pr "int %s" n
5171 | Int n -> next (); pr "int %s" n
5174 if not in_daemon then (next (); pr "const char *%s" n)
5178 if semicolon then pr ";";
5179 if newline then pr "\n"
5181 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5182 and generate_call_args ?handle args =
5184 let comma = ref false in
5187 | Some handle -> pr "%s" handle; comma := true
5191 if !comma then pr ", ";
5193 pr "%s" (name_of_argt arg)
5197 (* Generate the OCaml bindings interface. *)
5198 and generate_ocaml_mli () =
5199 generate_header OCamlStyle LGPLv2;
5202 (** For API documentation you should refer to the C API
5203 in the guestfs(3) manual page. The OCaml API uses almost
5204 exactly the same calls. *)
5207 (** A [guestfs_h] handle. *)
5209 exception Error of string
5210 (** This exception is raised when there is an error. *)
5212 val create : unit -> t
5214 val close : t -> unit
5215 (** Handles are closed by the garbage collector when they become
5216 unreferenced, but callers can also call this in order to
5217 provide predictable cleanup. *)
5220 generate_ocaml_lvm_structure_decls ();
5222 generate_ocaml_stat_structure_decls ();
5226 fun (name, style, _, _, _, shortdesc, _) ->
5227 generate_ocaml_prototype name style;
5228 pr "(** %s *)\n" shortdesc;
5232 (* Generate the OCaml bindings implementation. *)
5233 and generate_ocaml_ml () =
5234 generate_header OCamlStyle LGPLv2;
5238 exception Error of string
5239 external create : unit -> t = \"ocaml_guestfs_create\"
5240 external close : t -> unit = \"ocaml_guestfs_close\"
5243 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
5247 generate_ocaml_lvm_structure_decls ();
5249 generate_ocaml_stat_structure_decls ();
5253 fun (name, style, _, _, _, shortdesc, _) ->
5254 generate_ocaml_prototype ~is_external:true name style;
5257 (* Generate the OCaml bindings C implementation. *)
5258 and generate_ocaml_c () =
5259 generate_header CStyle LGPLv2;
5266 #include <caml/config.h>
5267 #include <caml/alloc.h>
5268 #include <caml/callback.h>
5269 #include <caml/fail.h>
5270 #include <caml/memory.h>
5271 #include <caml/mlvalues.h>
5272 #include <caml/signals.h>
5274 #include <guestfs.h>
5276 #include \"guestfs_c.h\"
5278 /* Copy a hashtable of string pairs into an assoc-list. We return
5279 * the list in reverse order, but hashtables aren't supposed to be
5282 static CAMLprim value
5283 copy_table (char * const * argv)
5286 CAMLlocal5 (rv, pairv, kv, vv, cons);
5290 for (i = 0; argv[i] != NULL; i += 2) {
5291 kv = caml_copy_string (argv[i]);
5292 vv = caml_copy_string (argv[i+1]);
5293 pairv = caml_alloc (2, 0);
5294 Store_field (pairv, 0, kv);
5295 Store_field (pairv, 1, vv);
5296 cons = caml_alloc (2, 0);
5297 Store_field (cons, 1, rv);
5299 Store_field (cons, 0, pairv);
5307 (* LVM struct copy functions. *)
5310 let has_optpercent_col =
5311 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
5313 pr "static CAMLprim value\n";
5314 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
5316 pr " CAMLparam0 ();\n";
5317 if has_optpercent_col then
5318 pr " CAMLlocal3 (rv, v, v2);\n"
5320 pr " CAMLlocal2 (rv, v);\n";
5322 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5327 pr " v = caml_copy_string (%s->%s);\n" typ name
5329 pr " v = caml_alloc_string (32);\n";
5330 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
5333 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5334 | name, `OptPercent ->
5335 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5336 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
5337 pr " v = caml_alloc (1, 0);\n";
5338 pr " Store_field (v, 0, v2);\n";
5339 pr " } else /* None */\n";
5340 pr " v = Val_int (0);\n";
5342 pr " Store_field (rv, %d, v);\n" i
5344 pr " CAMLreturn (rv);\n";
5348 pr "static CAMLprim value\n";
5349 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
5352 pr " CAMLparam0 ();\n";
5353 pr " CAMLlocal2 (rv, v);\n";
5356 pr " if (%ss->len == 0)\n" typ;
5357 pr " CAMLreturn (Atom (0));\n";
5359 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
5360 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
5361 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
5362 pr " caml_modify (&Field (rv, i), v);\n";
5364 pr " CAMLreturn (rv);\n";
5368 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5370 (* Stat copy functions. *)
5373 pr "static CAMLprim value\n";
5374 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5376 pr " CAMLparam0 ();\n";
5377 pr " CAMLlocal2 (rv, v);\n";
5379 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5384 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5386 pr " Store_field (rv, %d, v);\n" i
5388 pr " CAMLreturn (rv);\n";
5391 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5395 fun (name, style, _, _, _, _, _) ->
5397 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5399 pr "CAMLprim value\n";
5400 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5401 List.iter (pr ", value %s") (List.tl params);
5406 | [p1; p2; p3; p4; p5] ->
5407 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
5408 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5409 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5410 pr " CAMLxparam%d (%s);\n"
5411 (List.length rest) (String.concat ", " rest)
5413 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5415 pr " CAMLlocal1 (rv);\n";
5418 pr " guestfs_h *g = Guestfs_val (gv);\n";
5419 pr " if (g == NULL)\n";
5420 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
5428 pr " const char *%s = String_val (%sv);\n" n n
5430 pr " const char *%s =\n" n;
5431 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5434 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5436 pr " int %s = Bool_val (%sv);\n" n n
5438 pr " int %s = Int_val (%sv);\n" n n
5441 match fst style with
5442 | RErr -> pr " int r;\n"; "-1"
5443 | RInt _ -> pr " int r;\n"; "-1"
5444 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5445 | RBool _ -> pr " int r;\n"; "-1"
5446 | RConstString _ -> pr " const char *r;\n"; "NULL"
5447 | RString _ -> pr " char *r;\n"; "NULL"
5453 pr " struct guestfs_int_bool *r;\n"; "NULL"
5455 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5457 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5459 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5461 pr " struct guestfs_stat *r;\n"; "NULL"
5463 pr " struct guestfs_statvfs *r;\n"; "NULL"
5470 pr " caml_enter_blocking_section ();\n";
5471 pr " r = guestfs_%s " name;
5472 generate_call_args ~handle:"g" (snd style);
5474 pr " caml_leave_blocking_section ();\n";
5479 pr " ocaml_guestfs_free_strings (%s);\n" n;
5480 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5483 pr " if (r == %s)\n" error_code;
5484 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5487 (match fst style with
5488 | RErr -> pr " rv = Val_unit;\n"
5489 | RInt _ -> pr " rv = Val_int (r);\n"
5491 pr " rv = caml_copy_int64 (r);\n"
5492 | RBool _ -> pr " rv = Val_bool (r);\n"
5493 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5495 pr " rv = caml_copy_string (r);\n";
5498 pr " rv = caml_copy_string_array ((const char **) r);\n";
5499 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5502 pr " rv = caml_alloc (2, 0);\n";
5503 pr " Store_field (rv, 0, Val_int (r->i));\n";
5504 pr " Store_field (rv, 1, Val_bool (r->b));\n";
5505 pr " guestfs_free_int_bool (r);\n";
5507 pr " rv = copy_lvm_pv_list (r);\n";
5508 pr " guestfs_free_lvm_pv_list (r);\n";
5510 pr " rv = copy_lvm_vg_list (r);\n";
5511 pr " guestfs_free_lvm_vg_list (r);\n";
5513 pr " rv = copy_lvm_lv_list (r);\n";
5514 pr " guestfs_free_lvm_lv_list (r);\n";
5516 pr " rv = copy_stat (r);\n";
5519 pr " rv = copy_statvfs (r);\n";
5522 pr " rv = copy_table (r);\n";
5523 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5527 pr " CAMLreturn (rv);\n";
5531 if List.length params > 5 then (
5532 pr "CAMLprim value\n";
5533 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5535 pr " return ocaml_guestfs_%s (argv[0]" name;
5536 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5543 and generate_ocaml_lvm_structure_decls () =
5546 pr "type lvm_%s = {\n" typ;
5549 | name, `String -> pr " %s : string;\n" name
5550 | name, `UUID -> pr " %s : string;\n" name
5551 | name, `Bytes -> pr " %s : int64;\n" name
5552 | name, `Int -> pr " %s : int64;\n" name
5553 | name, `OptPercent -> pr " %s : float option;\n" name
5557 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5559 and generate_ocaml_stat_structure_decls () =
5562 pr "type %s = {\n" typ;
5565 | name, `Int -> pr " %s : int64;\n" name
5569 ) ["stat", stat_cols; "statvfs", statvfs_cols]
5571 and generate_ocaml_prototype ?(is_external = false) name style =
5572 if is_external then pr "external " else pr "val ";
5573 pr "%s : t -> " name;
5576 | String _ | FileIn _ | FileOut _ -> pr "string -> "
5577 | OptString _ -> pr "string option -> "
5578 | StringList _ -> pr "string array -> "
5579 | Bool _ -> pr "bool -> "
5580 | Int _ -> pr "int -> "
5582 (match fst style with
5583 | RErr -> pr "unit" (* all errors are turned into exceptions *)
5584 | RInt _ -> pr "int"
5585 | RInt64 _ -> pr "int64"
5586 | RBool _ -> pr "bool"
5587 | RConstString _ -> pr "string"
5588 | RString _ -> pr "string"
5589 | RStringList _ -> pr "string array"
5590 | RIntBool _ -> pr "int * bool"
5591 | RPVList _ -> pr "lvm_pv array"
5592 | RVGList _ -> pr "lvm_vg array"
5593 | RLVList _ -> pr "lvm_lv array"
5594 | RStat _ -> pr "stat"
5595 | RStatVFS _ -> pr "statvfs"
5596 | RHashtable _ -> pr "(string * string) list"
5598 if is_external then (
5600 if List.length (snd style) + 1 > 5 then
5601 pr "\"ocaml_guestfs_%s_byte\" " name;
5602 pr "\"ocaml_guestfs_%s\"" name
5606 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5607 and generate_perl_xs () =
5608 generate_header CStyle LGPLv2;
5611 #include \"EXTERN.h\"
5615 #include <guestfs.h>
5618 #define PRId64 \"lld\"
5622 my_newSVll(long long val) {
5623 #ifdef USE_64_BIT_ALL
5624 return newSViv(val);
5628 len = snprintf(buf, 100, \"%%\" PRId64, val);
5629 return newSVpv(buf, len);
5634 #define PRIu64 \"llu\"
5638 my_newSVull(unsigned long long val) {
5639 #ifdef USE_64_BIT_ALL
5640 return newSVuv(val);
5644 len = snprintf(buf, 100, \"%%\" PRIu64, val);
5645 return newSVpv(buf, len);
5649 /* http://www.perlmonks.org/?node_id=680842 */
5651 XS_unpack_charPtrPtr (SV *arg) {
5656 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5657 croak (\"array reference expected\");
5659 av = (AV *)SvRV (arg);
5660 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5662 croak (\"malloc failed\");
5664 for (i = 0; i <= av_len (av); i++) {
5665 SV **elem = av_fetch (av, i, 0);
5667 if (!elem || !*elem)
5668 croak (\"missing element in list\");
5670 ret[i] = SvPV_nolen (*elem);
5678 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
5685 RETVAL = guestfs_create ();
5687 croak (\"could not create guestfs handle\");
5688 guestfs_set_error_handler (RETVAL, NULL, NULL);
5701 fun (name, style, _, _, _, _, _) ->
5702 (match fst style with
5703 | RErr -> pr "void\n"
5704 | RInt _ -> pr "SV *\n"
5705 | RInt64 _ -> pr "SV *\n"
5706 | RBool _ -> pr "SV *\n"
5707 | RConstString _ -> pr "SV *\n"
5708 | RString _ -> pr "SV *\n"
5711 | RPVList _ | RVGList _ | RLVList _
5712 | RStat _ | RStatVFS _
5714 pr "void\n" (* all lists returned implictly on the stack *)
5716 (* Call and arguments. *)
5718 generate_call_args ~handle:"g" (snd style);
5720 pr " guestfs_h *g;\n";
5724 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
5726 (* http://www.perlmonks.org/?node_id=554277
5727 * Note that the implicit handle argument means we have
5728 * to add 1 to the ST(x) operator.
5730 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
5731 | StringList n -> pr " char **%s;\n" n
5732 | Bool n -> pr " int %s;\n" n
5733 | Int n -> pr " int %s;\n" n
5736 let do_cleanups () =
5739 | String _ | OptString _ | Bool _ | Int _
5740 | FileIn _ | FileOut _ -> ()
5741 | StringList n -> pr " free (%s);\n" n
5746 (match fst style with
5751 pr " r = guestfs_%s " name;
5752 generate_call_args ~handle:"g" (snd style);
5755 pr " if (r == -1)\n";
5756 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5762 pr " %s = guestfs_%s " n name;
5763 generate_call_args ~handle:"g" (snd style);
5766 pr " if (%s == -1)\n" n;
5767 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5768 pr " RETVAL = newSViv (%s);\n" n;
5773 pr " int64_t %s;\n" n;
5775 pr " %s = guestfs_%s " n name;
5776 generate_call_args ~handle:"g" (snd style);
5779 pr " if (%s == -1)\n" n;
5780 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5781 pr " RETVAL = my_newSVll (%s);\n" n;
5786 pr " const char *%s;\n" n;
5788 pr " %s = guestfs_%s " n name;
5789 generate_call_args ~handle:"g" (snd style);
5792 pr " if (%s == NULL)\n" n;
5793 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5794 pr " RETVAL = newSVpv (%s, 0);\n" n;
5799 pr " char *%s;\n" n;
5801 pr " %s = guestfs_%s " n name;
5802 generate_call_args ~handle:"g" (snd style);
5805 pr " if (%s == NULL)\n" n;
5806 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5807 pr " RETVAL = newSVpv (%s, 0);\n" n;
5808 pr " free (%s);\n" n;
5811 | RStringList n | RHashtable n ->
5813 pr " char **%s;\n" n;
5816 pr " %s = guestfs_%s " n name;
5817 generate_call_args ~handle:"g" (snd style);
5820 pr " if (%s == NULL)\n" n;
5821 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5822 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
5823 pr " EXTEND (SP, n);\n";
5824 pr " for (i = 0; i < n; ++i) {\n";
5825 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
5826 pr " free (%s[i]);\n" n;
5828 pr " free (%s);\n" n;
5831 pr " struct guestfs_int_bool *r;\n";
5833 pr " r = guestfs_%s " name;
5834 generate_call_args ~handle:"g" (snd style);
5837 pr " if (r == NULL)\n";
5838 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5839 pr " EXTEND (SP, 2);\n";
5840 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
5841 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
5842 pr " guestfs_free_int_bool (r);\n";
5844 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
5846 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
5848 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
5850 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
5852 generate_perl_stat_code
5853 "statvfs" statvfs_cols name style n do_cleanups
5859 and generate_perl_lvm_code typ cols name style n do_cleanups =
5861 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
5865 pr " %s = guestfs_%s " n name;
5866 generate_call_args ~handle:"g" (snd style);
5869 pr " if (%s == NULL)\n" n;
5870 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5871 pr " EXTEND (SP, %s->len);\n" n;
5872 pr " for (i = 0; i < %s->len; ++i) {\n" n;
5873 pr " hv = newHV ();\n";
5877 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
5878 name (String.length name) n name
5880 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
5881 name (String.length name) n name
5883 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
5884 name (String.length name) n name
5886 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
5887 name (String.length name) n name
5888 | name, `OptPercent ->
5889 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
5890 name (String.length name) n name
5892 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
5894 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
5896 and generate_perl_stat_code typ cols name style n do_cleanups =
5898 pr " struct guestfs_%s *%s;\n" typ n;
5900 pr " %s = guestfs_%s " n name;
5901 generate_call_args ~handle:"g" (snd style);
5904 pr " if (%s == NULL)\n" n;
5905 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5906 pr " EXTEND (SP, %d);\n" (List.length cols);
5910 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
5912 pr " free (%s);\n" n
5914 (* Generate Sys/Guestfs.pm. *)
5915 and generate_perl_pm () =
5916 generate_header HashStyle LGPLv2;
5923 Sys::Guestfs - Perl bindings for libguestfs
5929 my $h = Sys::Guestfs->new ();
5930 $h->add_drive ('guest.img');
5933 $h->mount ('/dev/sda1', '/');
5934 $h->touch ('/hello');
5939 The C<Sys::Guestfs> module provides a Perl XS binding to the
5940 libguestfs API for examining and modifying virtual machine
5943 Amongst the things this is good for: making batch configuration
5944 changes to guests, getting disk used/free statistics (see also:
5945 virt-df), migrating between virtualization systems (see also:
5946 virt-p2v), performing partial backups, performing partial guest
5947 clones, cloning guests and changing registry/UUID/hostname info, and
5950 Libguestfs uses Linux kernel and qemu code, and can access any type of
5951 guest filesystem that Linux and qemu can, including but not limited
5952 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5953 schemes, qcow, qcow2, vmdk.
5955 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5956 LVs, what filesystem is in each LV, etc.). It can also run commands
5957 in the context of the guest. Also you can access filesystems over FTP.
5961 All errors turn into calls to C<croak> (see L<Carp(3)>).
5969 package Sys::Guestfs;
5975 XSLoader::load ('Sys::Guestfs');
5977 =item $h = Sys::Guestfs->new ();
5979 Create a new guestfs handle.
5985 my $class = ref ($proto) || $proto;
5987 my $self = Sys::Guestfs::_create ();
5988 bless $self, $class;
5994 (* Actions. We only need to print documentation for these as
5995 * they are pulled in from the XS code automatically.
5998 fun (name, style, _, flags, _, _, longdesc) ->
5999 if not (List.mem NotInDocs flags) then (
6000 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
6002 generate_perl_prototype name style;
6004 pr "%s\n\n" longdesc;
6005 if List.mem ProtocolLimitWarning flags then
6006 pr "%s\n\n" protocol_limit_warning;
6007 if List.mem DangerWillRobinson flags then
6008 pr "%s\n\n" danger_will_robinson
6010 ) all_functions_sorted;
6022 Copyright (C) 2009 Red Hat Inc.
6026 Please see the file COPYING.LIB for the full license.
6030 L<guestfs(3)>, L<guestfish(1)>.
6035 and generate_perl_prototype name style =
6036 (match fst style with
6042 | RString n -> pr "$%s = " n
6043 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
6047 | RLVList n -> pr "@%s = " n
6050 | RHashtable n -> pr "%%%s = " n
6053 let comma = ref false in
6056 if !comma then pr ", ";
6059 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
6066 (* Generate Python C module. *)
6067 and generate_python_c () =
6068 generate_header CStyle LGPLv2;
6077 #include \"guestfs.h\"
6085 get_handle (PyObject *obj)
6088 assert (obj != Py_None);
6089 return ((Pyguestfs_Object *) obj)->g;
6093 put_handle (guestfs_h *g)
6097 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6100 /* This list should be freed (but not the strings) after use. */
6101 static const char **
6102 get_string_list (PyObject *obj)
6109 if (!PyList_Check (obj)) {
6110 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6114 len = PyList_Size (obj);
6115 r = malloc (sizeof (char *) * (len+1));
6117 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6121 for (i = 0; i < len; ++i)
6122 r[i] = PyString_AsString (PyList_GetItem (obj, i));
6129 put_string_list (char * const * const argv)
6134 for (argc = 0; argv[argc] != NULL; ++argc)
6137 list = PyList_New (argc);
6138 for (i = 0; i < argc; ++i)
6139 PyList_SetItem (list, i, PyString_FromString (argv[i]));
6145 put_table (char * const * const argv)
6147 PyObject *list, *item;
6150 for (argc = 0; argv[argc] != NULL; ++argc)
6153 list = PyList_New (argc >> 1);
6154 for (i = 0; i < argc; i += 2) {
6155 item = PyTuple_New (2);
6156 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
6157 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
6158 PyList_SetItem (list, i >> 1, item);
6165 free_strings (char **argv)
6169 for (argc = 0; argv[argc] != NULL; ++argc)
6175 py_guestfs_create (PyObject *self, PyObject *args)
6179 g = guestfs_create ();
6181 PyErr_SetString (PyExc_RuntimeError,
6182 \"guestfs.create: failed to allocate handle\");
6185 guestfs_set_error_handler (g, NULL, NULL);
6186 return put_handle (g);
6190 py_guestfs_close (PyObject *self, PyObject *args)
6195 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
6197 g = get_handle (py_g);
6201 Py_INCREF (Py_None);
6207 (* LVM structures, turned into Python dictionaries. *)
6210 pr "static PyObject *\n";
6211 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
6213 pr " PyObject *dict;\n";
6215 pr " dict = PyDict_New ();\n";
6219 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6220 pr " PyString_FromString (%s->%s));\n"
6223 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6224 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
6227 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6228 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
6231 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6232 pr " PyLong_FromLongLong (%s->%s));\n"
6234 | name, `OptPercent ->
6235 pr " if (%s->%s >= 0)\n" typ name;
6236 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6237 pr " PyFloat_FromDouble ((double) %s->%s));\n"
6240 pr " Py_INCREF (Py_None);\n";
6241 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
6244 pr " return dict;\n";
6248 pr "static PyObject *\n";
6249 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
6251 pr " PyObject *list;\n";
6254 pr " list = PyList_New (%ss->len);\n" typ;
6255 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
6256 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
6257 pr " return list;\n";
6260 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
6262 (* Stat structures, turned into Python dictionaries. *)
6265 pr "static PyObject *\n";
6266 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6268 pr " PyObject *dict;\n";
6270 pr " dict = PyDict_New ();\n";
6274 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6275 pr " PyLong_FromLongLong (%s->%s));\n"
6278 pr " return dict;\n";
6281 ) ["stat", stat_cols; "statvfs", statvfs_cols];
6283 (* Python wrapper functions. *)
6285 fun (name, style, _, _, _, _, _) ->
6286 pr "static PyObject *\n";
6287 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6290 pr " PyObject *py_g;\n";
6291 pr " guestfs_h *g;\n";
6292 pr " PyObject *py_r;\n";
6295 match fst style with
6296 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6297 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6298 | RConstString _ -> pr " const char *r;\n"; "NULL"
6299 | RString _ -> pr " char *r;\n"; "NULL"
6300 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6301 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6302 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6303 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6304 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6305 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6306 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6310 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
6311 | OptString n -> pr " const char *%s;\n" n
6313 pr " PyObject *py_%s;\n" n;
6314 pr " const char **%s;\n" n
6315 | Bool n -> pr " int %s;\n" n
6316 | Int n -> pr " int %s;\n" n
6321 (* Convert the parameters. *)
6322 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
6325 | String _ | FileIn _ | FileOut _ -> pr "s"
6326 | OptString _ -> pr "z"
6327 | StringList _ -> pr "O"
6328 | Bool _ -> pr "i" (* XXX Python has booleans? *)
6331 pr ":guestfs_%s\",\n" name;
6335 | String n | FileIn n | FileOut n -> pr ", &%s" n
6336 | OptString n -> pr ", &%s" n
6337 | StringList n -> pr ", &py_%s" n
6338 | Bool n -> pr ", &%s" n
6339 | Int n -> pr ", &%s" n
6343 pr " return NULL;\n";
6345 pr " g = get_handle (py_g);\n";
6348 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6350 pr " %s = get_string_list (py_%s);\n" n n;
6351 pr " if (!%s) return NULL;\n" n
6356 pr " r = guestfs_%s " name;
6357 generate_call_args ~handle:"g" (snd style);
6362 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6364 pr " free (%s);\n" n
6367 pr " if (r == %s) {\n" error_code;
6368 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6369 pr " return NULL;\n";
6373 (match fst style with
6375 pr " Py_INCREF (Py_None);\n";
6376 pr " py_r = Py_None;\n"
6378 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
6379 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
6380 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
6382 pr " py_r = PyString_FromString (r);\n";
6385 pr " py_r = put_string_list (r);\n";
6386 pr " free_strings (r);\n"
6388 pr " py_r = PyTuple_New (2);\n";
6389 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
6390 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
6391 pr " guestfs_free_int_bool (r);\n"
6393 pr " py_r = put_lvm_pv_list (r);\n";
6394 pr " guestfs_free_lvm_pv_list (r);\n"
6396 pr " py_r = put_lvm_vg_list (r);\n";
6397 pr " guestfs_free_lvm_vg_list (r);\n"
6399 pr " py_r = put_lvm_lv_list (r);\n";
6400 pr " guestfs_free_lvm_lv_list (r);\n"
6402 pr " py_r = put_stat (r);\n";
6405 pr " py_r = put_statvfs (r);\n";
6408 pr " py_r = put_table (r);\n";
6409 pr " free_strings (r);\n"
6412 pr " return py_r;\n";
6417 (* Table of functions. *)
6418 pr "static PyMethodDef methods[] = {\n";
6419 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6420 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6422 fun (name, _, _, _, _, _, _) ->
6423 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6426 pr " { NULL, NULL, 0, NULL }\n";
6430 (* Init function. *)
6433 initlibguestfsmod (void)
6435 static int initialized = 0;
6437 if (initialized) return;
6438 Py_InitModule ((char *) \"libguestfsmod\", methods);
6443 (* Generate Python module. *)
6444 and generate_python_py () =
6445 generate_header HashStyle LGPLv2;
6448 u\"\"\"Python bindings for libguestfs
6451 g = guestfs.GuestFS ()
6452 g.add_drive (\"guest.img\")
6455 parts = g.list_partitions ()
6457 The guestfs module provides a Python binding to the libguestfs API
6458 for examining and modifying virtual machine disk images.
6460 Amongst the things this is good for: making batch configuration
6461 changes to guests, getting disk used/free statistics (see also:
6462 virt-df), migrating between virtualization systems (see also:
6463 virt-p2v), performing partial backups, performing partial guest
6464 clones, cloning guests and changing registry/UUID/hostname info, and
6467 Libguestfs uses Linux kernel and qemu code, and can access any type of
6468 guest filesystem that Linux and qemu can, including but not limited
6469 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6470 schemes, qcow, qcow2, vmdk.
6472 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6473 LVs, what filesystem is in each LV, etc.). It can also run commands
6474 in the context of the guest. Also you can access filesystems over FTP.
6476 Errors which happen while using the API are turned into Python
6477 RuntimeError exceptions.
6479 To create a guestfs handle you usually have to perform the following
6482 # Create the handle, call add_drive at least once, and possibly
6483 # several times if the guest has multiple block devices:
6484 g = guestfs.GuestFS ()
6485 g.add_drive (\"guest.img\")
6487 # Launch the qemu subprocess and wait for it to become ready:
6491 # Now you can issue commands, for example:
6496 import libguestfsmod
6499 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6501 def __init__ (self):
6502 \"\"\"Create a new libguestfs handle.\"\"\"
6503 self._o = libguestfsmod.create ()
6506 libguestfsmod.close (self._o)
6511 fun (name, style, _, flags, _, _, longdesc) ->
6513 generate_call_args ~handle:"self" (snd style);
6516 if not (List.mem NotInDocs flags) then (
6517 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6519 match fst style with
6520 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6523 doc ^ "\n\nThis function returns a list of strings."
6525 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6527 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
6529 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
6531 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
6533 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6535 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6537 doc ^ "\n\nThis function returns a dictionary." in
6539 if List.mem ProtocolLimitWarning flags then
6540 doc ^ "\n\n" ^ protocol_limit_warning
6543 if List.mem DangerWillRobinson flags then
6544 doc ^ "\n\n" ^ danger_will_robinson
6546 let doc = pod2text ~width:60 name doc in
6547 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6548 let doc = String.concat "\n " doc in
6549 pr " u\"\"\"%s\"\"\"\n" doc;
6551 pr " return libguestfsmod.%s " name;
6552 generate_call_args ~handle:"self._o" (snd style);
6557 (* Useful if you need the longdesc POD text as plain text. Returns a
6560 * This is the slowest thing about autogeneration.
6562 and pod2text ~width name longdesc =
6563 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6564 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6566 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6567 let chan = Unix.open_process_in cmd in
6568 let lines = ref [] in
6570 let line = input_line chan in
6571 if i = 1 then (* discard the first line of output *)
6574 let line = triml line in
6575 lines := line :: !lines;
6578 let lines = try loop 1 with End_of_file -> List.rev !lines in
6579 Unix.unlink filename;
6580 match Unix.close_process_in chan with
6581 | Unix.WEXITED 0 -> lines
6583 failwithf "pod2text: process exited with non-zero status (%d)" i
6584 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6585 failwithf "pod2text: process signalled or stopped by signal %d" i
6587 (* Generate ruby bindings. *)
6588 and generate_ruby_c () =
6589 generate_header CStyle LGPLv2;
6597 #include \"guestfs.h\"
6599 #include \"extconf.h\"
6601 /* For Ruby < 1.9 */
6603 #define RARRAY_LEN(r) (RARRAY((r))->len)
6606 static VALUE m_guestfs; /* guestfs module */
6607 static VALUE c_guestfs; /* guestfs_h handle */
6608 static VALUE e_Error; /* used for all errors */
6610 static void ruby_guestfs_free (void *p)
6613 guestfs_close ((guestfs_h *) p);
6616 static VALUE ruby_guestfs_create (VALUE m)
6620 g = guestfs_create ();
6622 rb_raise (e_Error, \"failed to create guestfs handle\");
6624 /* Don't print error messages to stderr by default. */
6625 guestfs_set_error_handler (g, NULL, NULL);
6627 /* Wrap it, and make sure the close function is called when the
6630 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6633 static VALUE ruby_guestfs_close (VALUE gv)
6636 Data_Get_Struct (gv, guestfs_h, g);
6638 ruby_guestfs_free (g);
6639 DATA_PTR (gv) = NULL;
6647 fun (name, style, _, _, _, _, _) ->
6648 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6649 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6652 pr " guestfs_h *g;\n";
6653 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
6655 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6661 | String n | FileIn n | FileOut n ->
6662 pr " Check_Type (%sv, T_STRING);\n" n;
6663 pr " const char *%s = StringValueCStr (%sv);\n" n n;
6665 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6666 pr " \"%s\", \"%s\");\n" n name
6668 pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
6670 pr " char **%s;\n" n;
6671 pr " Check_Type (%sv, T_ARRAY);\n" n;
6673 pr " int i, len;\n";
6674 pr " len = RARRAY_LEN (%sv);\n" n;
6675 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6677 pr " for (i = 0; i < len; ++i) {\n";
6678 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
6679 pr " %s[i] = StringValueCStr (v);\n" n;
6681 pr " %s[len] = NULL;\n" n;
6684 pr " int %s = RTEST (%sv);\n" n n
6686 pr " int %s = NUM2INT (%sv);\n" n n
6691 match fst style with
6692 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6693 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6694 | RConstString _ -> pr " const char *r;\n"; "NULL"
6695 | RString _ -> pr " char *r;\n"; "NULL"
6696 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6697 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6698 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6699 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6700 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6701 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6702 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6705 pr " r = guestfs_%s " name;
6706 generate_call_args ~handle:"g" (snd style);
6711 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6713 pr " free (%s);\n" n
6716 pr " if (r == %s)\n" error_code;
6717 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6720 (match fst style with
6722 pr " return Qnil;\n"
6723 | RInt _ | RBool _ ->
6724 pr " return INT2NUM (r);\n"
6726 pr " return ULL2NUM (r);\n"
6728 pr " return rb_str_new2 (r);\n";
6730 pr " VALUE rv = rb_str_new2 (r);\n";
6734 pr " int i, len = 0;\n";
6735 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
6736 pr " VALUE rv = rb_ary_new2 (len);\n";
6737 pr " for (i = 0; r[i] != NULL; ++i) {\n";
6738 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6739 pr " free (r[i]);\n";
6744 pr " VALUE rv = rb_ary_new2 (2);\n";
6745 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
6746 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
6747 pr " guestfs_free_int_bool (r);\n";
6750 generate_ruby_lvm_code "pv" pv_cols
6752 generate_ruby_lvm_code "vg" vg_cols
6754 generate_ruby_lvm_code "lv" lv_cols
6756 pr " VALUE rv = rb_hash_new ();\n";
6760 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6765 pr " VALUE rv = rb_hash_new ();\n";
6769 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6774 pr " VALUE rv = rb_hash_new ();\n";
6776 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
6777 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6778 pr " free (r[i]);\n";
6779 pr " free (r[i+1]);\n";
6790 /* Initialize the module. */
6791 void Init__guestfs ()
6793 m_guestfs = rb_define_module (\"Guestfs\");
6794 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6795 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6797 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6798 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6801 (* Define the rest of the methods. *)
6803 fun (name, style, _, _, _, _, _) ->
6804 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
6805 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6810 (* Ruby code to return an LVM struct list. *)
6811 and generate_ruby_lvm_code typ cols =
6812 pr " VALUE rv = rb_ary_new2 (r->len);\n";
6814 pr " for (i = 0; i < r->len; ++i) {\n";
6815 pr " VALUE hv = rb_hash_new ();\n";
6819 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
6821 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
6824 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
6825 | name, `OptPercent ->
6826 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
6828 pr " rb_ary_push (rv, hv);\n";
6830 pr " guestfs_free_lvm_%s_list (r);\n" typ;
6833 (* Generate Java bindings GuestFS.java file. *)
6834 and generate_java_java () =
6835 generate_header CStyle LGPLv2;
6838 package com.redhat.et.libguestfs;
6840 import java.util.HashMap;
6841 import com.redhat.et.libguestfs.LibGuestFSException;
6842 import com.redhat.et.libguestfs.PV;
6843 import com.redhat.et.libguestfs.VG;
6844 import com.redhat.et.libguestfs.LV;
6845 import com.redhat.et.libguestfs.Stat;
6846 import com.redhat.et.libguestfs.StatVFS;
6847 import com.redhat.et.libguestfs.IntBool;
6850 * The GuestFS object is a libguestfs handle.
6854 public class GuestFS {
6855 // Load the native code.
6857 System.loadLibrary (\"guestfs_jni\");
6861 * The native guestfs_h pointer.
6866 * Create a libguestfs handle.
6868 * @throws LibGuestFSException
6870 public GuestFS () throws LibGuestFSException
6874 private native long _create () throws LibGuestFSException;
6877 * Close a libguestfs handle.
6879 * You can also leave handles to be collected by the garbage
6880 * collector, but this method ensures that the resources used
6881 * by the handle are freed up immediately. If you call any
6882 * other methods after closing the handle, you will get an
6885 * @throws LibGuestFSException
6887 public void close () throws LibGuestFSException
6893 private native void _close (long g) throws LibGuestFSException;
6895 public void finalize () throws LibGuestFSException
6903 fun (name, style, _, flags, _, shortdesc, longdesc) ->
6904 if not (List.mem NotInDocs flags); then (
6905 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6907 if List.mem ProtocolLimitWarning flags then
6908 doc ^ "\n\n" ^ protocol_limit_warning
6911 if List.mem DangerWillRobinson flags then
6912 doc ^ "\n\n" ^ danger_will_robinson
6914 let doc = pod2text ~width:60 name doc in
6915 let doc = List.map ( (* RHBZ#501883 *)
6918 | nonempty -> nonempty
6920 let doc = String.concat "\n * " doc in
6923 pr " * %s\n" shortdesc;
6926 pr " * @throws LibGuestFSException\n";
6930 generate_java_prototype ~public:true ~semicolon:false name style;
6933 pr " if (g == 0)\n";
6934 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
6937 if fst style <> RErr then pr "return ";
6939 generate_call_args ~handle:"g" (snd style);
6943 generate_java_prototype ~privat:true ~native:true name style;
6950 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
6951 ?(semicolon=true) name style =
6952 if privat then pr "private ";
6953 if public then pr "public ";
6954 if native then pr "native ";
6957 (match fst style with
6958 | RErr -> pr "void ";
6959 | RInt _ -> pr "int ";
6960 | RInt64 _ -> pr "long ";
6961 | RBool _ -> pr "boolean ";
6962 | RConstString _ | RString _ -> pr "String ";
6963 | RStringList _ -> pr "String[] ";
6964 | RIntBool _ -> pr "IntBool ";
6965 | RPVList _ -> pr "PV[] ";
6966 | RVGList _ -> pr "VG[] ";
6967 | RLVList _ -> pr "LV[] ";
6968 | RStat _ -> pr "Stat ";
6969 | RStatVFS _ -> pr "StatVFS ";
6970 | RHashtable _ -> pr "HashMap<String,String> ";
6973 if native then pr "_%s " name else pr "%s " name;
6975 let needs_comma = ref false in
6984 if !needs_comma then pr ", ";
6985 needs_comma := true;
7002 pr " throws LibGuestFSException";
7003 if semicolon then pr ";"
7005 and generate_java_struct typ cols =
7006 generate_header CStyle LGPLv2;
7009 package com.redhat.et.libguestfs;
7012 * Libguestfs %s structure.
7023 | name, `UUID -> pr " public String %s;\n" name
7025 | name, `Int -> pr " public long %s;\n" name
7026 | name, `OptPercent ->
7027 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
7028 pr " public float %s;\n" name
7033 and generate_java_c () =
7034 generate_header CStyle LGPLv2;
7041 #include \"com_redhat_et_libguestfs_GuestFS.h\"
7042 #include \"guestfs.h\"
7044 /* Note that this function returns. The exception is not thrown
7045 * until after the wrapper function returns.
7048 throw_exception (JNIEnv *env, const char *msg)
7051 cl = (*env)->FindClass (env,
7052 \"com/redhat/et/libguestfs/LibGuestFSException\");
7053 (*env)->ThrowNew (env, cl, msg);
7056 JNIEXPORT jlong JNICALL
7057 Java_com_redhat_et_libguestfs_GuestFS__1create
7058 (JNIEnv *env, jobject obj)
7062 g = guestfs_create ();
7064 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
7067 guestfs_set_error_handler (g, NULL, NULL);
7068 return (jlong) (long) g;
7071 JNIEXPORT void JNICALL
7072 Java_com_redhat_et_libguestfs_GuestFS__1close
7073 (JNIEnv *env, jobject obj, jlong jg)
7075 guestfs_h *g = (guestfs_h *) (long) jg;
7082 fun (name, style, _, _, _, _, _) ->
7084 (match fst style with
7085 | RErr -> pr "void ";
7086 | RInt _ -> pr "jint ";
7087 | RInt64 _ -> pr "jlong ";
7088 | RBool _ -> pr "jboolean ";
7089 | RConstString _ | RString _ -> pr "jstring ";
7090 | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
7092 | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
7096 pr "Java_com_redhat_et_libguestfs_GuestFS_";
7097 pr "%s" (replace_str ("_" ^ name) "_" "_1");
7099 pr " (JNIEnv *env, jobject obj, jlong jg";
7106 pr ", jstring j%s" n
7108 pr ", jobjectArray j%s" n
7110 pr ", jboolean j%s" n
7116 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
7117 let error_code, no_ret =
7118 match fst style with
7119 | RErr -> pr " int r;\n"; "-1", ""
7121 | RInt _ -> pr " int r;\n"; "-1", "0"
7122 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
7123 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
7125 pr " jstring jr;\n";
7126 pr " char *r;\n"; "NULL", "NULL"
7128 pr " jobjectArray jr;\n";
7131 pr " jstring jstr;\n";
7132 pr " char **r;\n"; "NULL", "NULL"
7134 pr " jobject jr;\n";
7136 pr " jfieldID fl;\n";
7137 pr " struct guestfs_int_bool *r;\n"; "NULL", "NULL"
7139 pr " jobject jr;\n";
7141 pr " jfieldID fl;\n";
7142 pr " struct guestfs_stat *r;\n"; "NULL", "NULL"
7144 pr " jobject jr;\n";
7146 pr " jfieldID fl;\n";
7147 pr " struct guestfs_statvfs *r;\n"; "NULL", "NULL"
7149 pr " jobjectArray jr;\n";
7151 pr " jfieldID fl;\n";
7152 pr " jobject jfl;\n";
7153 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
7155 pr " jobjectArray jr;\n";
7157 pr " jfieldID fl;\n";
7158 pr " jobject jfl;\n";
7159 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
7161 pr " jobjectArray jr;\n";
7163 pr " jfieldID fl;\n";
7164 pr " jobject jfl;\n";
7165 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
7166 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
7173 pr " const char *%s;\n" n
7175 pr " int %s_len;\n" n;
7176 pr " const char **%s;\n" n
7183 (match fst style with
7184 | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
7185 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
7186 | RString _ | RIntBool _ | RStat _ | RStatVFS _
7187 | RHashtable _ -> false) ||
7188 List.exists (function StringList _ -> true | _ -> false) (snd style) in
7194 (* Get the parameters. *)
7200 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
7202 (* This is completely undocumented, but Java null becomes
7205 pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
7207 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
7208 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
7209 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7210 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7212 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
7214 pr " %s[%s_len] = NULL;\n" n n;
7217 pr " %s = j%s;\n" n n
7220 (* Make the call. *)
7221 pr " r = guestfs_%s " name;
7222 generate_call_args ~handle:"g" (snd style);
7225 (* Release the parameters. *)
7231 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7234 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7236 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7237 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7239 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
7241 pr " free (%s);\n" n
7246 (* Check for errors. *)
7247 pr " if (r == %s) {\n" error_code;
7248 pr " throw_exception (env, guestfs_last_error (g));\n";
7249 pr " return %s;\n" no_ret;
7253 (match fst style with
7255 | RInt _ -> pr " return (jint) r;\n"
7256 | RBool _ -> pr " return (jboolean) r;\n"
7257 | RInt64 _ -> pr " return (jlong) r;\n"
7258 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
7260 pr " jr = (*env)->NewStringUTF (env, r);\n";
7264 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7265 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7266 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
7267 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7268 pr " for (i = 0; i < r_len; ++i) {\n";
7269 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
7270 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7271 pr " free (r[i]);\n";
7276 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
7277 pr " jr = (*env)->AllocObject (env, cl);\n";
7278 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
7279 pr " (*env)->SetIntField (env, jr, fl, r->i);\n";
7280 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
7281 pr " (*env)->SetBooleanField (env, jr, fl, r->b);\n";
7282 pr " guestfs_free_int_bool (r);\n";
7285 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
7286 pr " jr = (*env)->AllocObject (env, cl);\n";
7290 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7292 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7297 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
7298 pr " jr = (*env)->AllocObject (env, cl);\n";
7302 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7304 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7309 generate_java_lvm_return "pv" "PV" pv_cols
7311 generate_java_lvm_return "vg" "VG" vg_cols
7313 generate_java_lvm_return "lv" "LV" lv_cols
7316 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7317 pr " return NULL;\n"
7324 and generate_java_lvm_return typ jtyp cols =
7325 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7326 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7327 pr " for (i = 0; i < r->len; ++i) {\n";
7328 pr " jfl = (*env)->AllocObject (env, cl);\n";
7332 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7333 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7336 pr " char s[33];\n";
7337 pr " memcpy (s, r->val[i].%s, 32);\n" name;
7339 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7340 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7342 | name, (`Bytes|`Int) ->
7343 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7344 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7345 | name, `OptPercent ->
7346 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7347 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7349 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7351 pr " guestfs_free_lvm_%s_list (r);\n" typ;
7354 and generate_haskell_hs () =
7355 generate_header HaskellStyle LGPLv2;
7357 (* XXX We only know how to generate partial FFI for Haskell
7358 * at the moment. Please help out!
7360 let can_generate style =
7364 | RInt64 _, _ -> true
7375 | RHashtable _, _ -> false in
7378 {-# INCLUDE <guestfs.h> #-}
7379 {-# LANGUAGE ForeignFunctionInterface #-}
7384 (* List out the names of the actions we want to export. *)
7386 fun (name, style, _, _, _, _, _) ->
7387 if can_generate style then pr ",\n %s" name
7394 import Foreign.C.Types
7396 import Control.Exception
7397 import Data.Typeable
7399 data GuestfsS = GuestfsS -- represents the opaque C struct
7400 type GuestfsP = Ptr GuestfsS -- guestfs_h *
7401 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7403 -- XXX define properly later XXX
7407 data IntBool = IntBool
7409 data StatVFS = StatVFS
7410 data Hashtable = Hashtable
7412 foreign import ccall unsafe \"guestfs_create\" c_create
7414 foreign import ccall unsafe \"&guestfs_close\" c_close
7415 :: FunPtr (GuestfsP -> IO ())
7416 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
7417 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
7419 create :: IO GuestfsH
7422 c_set_error_handler p nullPtr nullPtr
7423 h <- newForeignPtr c_close p
7426 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
7427 :: GuestfsP -> IO CString
7429 -- last_error :: GuestfsH -> IO (Maybe String)
7430 -- last_error h = do
7431 -- str <- withForeignPtr h (\\p -> c_last_error p)
7432 -- maybePeek peekCString str
7434 last_error :: GuestfsH -> IO (String)
7436 str <- withForeignPtr h (\\p -> c_last_error p)
7438 then return \"no error\"
7439 else peekCString str
7443 (* Generate wrappers for each foreign function. *)
7445 fun (name, style, _, _, _, _, _) ->
7446 if can_generate style then (
7447 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7449 generate_haskell_prototype ~handle:"GuestfsP" style;
7453 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7455 pr "%s %s = do\n" name
7456 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7458 (* Convert pointer arguments using with* functions. *)
7463 | String n -> pr "withCString %s $ \\%s -> " n n
7464 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7465 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7466 | Bool _ | Int _ -> ()
7468 (* Convert integer arguments. *)
7472 | Bool n -> sprintf "(fromBool %s)" n
7473 | Int n -> sprintf "(fromIntegral %s)" n
7474 | FileIn n | FileOut n | String n | OptString n | StringList n -> n
7476 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7477 (String.concat " " ("p" :: args));
7478 (match fst style with
7479 | RErr | RInt _ | RInt64 _ | RBool _ ->
7480 pr " if (r == -1)\n";
7482 pr " err <- last_error h\n";
7484 | RConstString _ | RString _ | RStringList _ | RIntBool _
7485 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7487 pr " if (r == nullPtr)\n";
7489 pr " err <- last_error h\n";
7492 (match fst style with
7494 pr " else return ()\n"
7496 pr " else return (fromIntegral r)\n"
7498 pr " else return (fromIntegral r)\n"
7500 pr " else return (toBool r)\n"
7511 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7517 and generate_haskell_prototype ~handle ?(hs = false) style =
7519 let string = if hs then "String" else "CString" in
7520 let int = if hs then "Int" else "CInt" in
7521 let bool = if hs then "Bool" else "CInt" in
7522 let int64 = if hs then "Integer" else "Int64" in
7526 | String _ -> pr "%s" string
7527 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7528 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7529 | Bool _ -> pr "%s" bool
7530 | Int _ -> pr "%s" int
7531 | FileIn _ -> pr "%s" string
7532 | FileOut _ -> pr "%s" string
7537 (match fst style with
7538 | RErr -> if not hs then pr "CInt"
7539 | RInt _ -> pr "%s" int
7540 | RInt64 _ -> pr "%s" int64
7541 | RBool _ -> pr "%s" bool
7542 | RConstString _ -> pr "%s" string
7543 | RString _ -> pr "%s" string
7544 | RStringList _ -> pr "[%s]" string
7545 | RIntBool _ -> pr "IntBool"
7546 | RPVList _ -> pr "[PV]"
7547 | RVGList _ -> pr "[VG]"
7548 | RLVList _ -> pr "[LV]"
7549 | RStat _ -> pr "Stat"
7550 | RStatVFS _ -> pr "StatVFS"
7551 | RHashtable _ -> pr "Hashtable"
7555 and generate_bindtests () =
7556 generate_header CStyle LGPLv2;
7561 #include <inttypes.h>
7564 #include \"guestfs.h\"
7565 #include \"guestfs_protocol.h\"
7567 #define error guestfs_error
7570 print_strings (char * const* const argv)
7575 for (argc = 0; argv[argc] != NULL; ++argc) {
7576 if (argc > 0) printf (\", \");
7577 printf (\"\\\"%%s\\\"\", argv[argc]);
7582 /* The test0 function prints its parameters to stdout. */
7586 match test_functions with
7587 | [] -> assert false
7588 | test0 :: tests -> test0, tests in
7591 let (name, style, _, _, _, _, _) = test0 in
7592 generate_prototype ~extern:false ~semicolon:false ~newline:true
7593 ~handle:"g" ~prefix:"guestfs_" name style;
7599 | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
7600 | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
7601 | StringList n -> pr " print_strings (%s);\n" n
7602 | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
7603 | Int n -> pr " printf (\"%%d\\n\", %s);\n" n
7605 pr " /* Java changes stdout line buffering so we need this: */\n";
7606 pr " fflush (stdout);\n";
7612 fun (name, style, _, _, _, _, _) ->
7613 if String.sub name (String.length name - 3) 3 <> "err" then (
7614 pr "/* Test normal return. */\n";
7615 generate_prototype ~extern:false ~semicolon:false ~newline:true
7616 ~handle:"g" ~prefix:"guestfs_" name style;
7618 (match fst style with
7623 pr " sscanf (val, \"%%d\", &r);\n";
7627 pr " sscanf (val, \"%%\" SCNi64, &r);\n";
7630 pr " return strcmp (val, \"true\") == 0;\n"
7632 (* Can't return the input string here. Return a static
7633 * string so we ensure we get a segfault if the caller
7636 pr " return \"static string\";\n"
7638 pr " return strdup (val);\n"
7640 pr " char **strs;\n";
7642 pr " sscanf (val, \"%%d\", &n);\n";
7643 pr " strs = malloc ((n+1) * sizeof (char *));\n";
7644 pr " for (i = 0; i < n; ++i) {\n";
7645 pr " strs[i] = malloc (16);\n";
7646 pr " snprintf (strs[i], 16, \"%%d\", i);\n";
7648 pr " strs[n] = NULL;\n";
7649 pr " return strs;\n"
7651 pr " struct guestfs_int_bool *r;\n";
7652 pr " r = malloc (sizeof (struct guestfs_int_bool));\n";
7653 pr " sscanf (val, \"%%\" SCNi32, &r->i);\n";
7657 pr " struct guestfs_lvm_pv_list *r;\n";
7659 pr " r = malloc (sizeof (struct guestfs_lvm_pv_list));\n";
7660 pr " sscanf (val, \"%%d\", &r->len);\n";
7661 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_pv));\n";
7662 pr " for (i = 0; i < r->len; ++i) {\n";
7663 pr " r->val[i].pv_name = malloc (16);\n";
7664 pr " snprintf (r->val[i].pv_name, 16, \"%%d\", i);\n";
7668 pr " struct guestfs_lvm_vg_list *r;\n";
7670 pr " r = malloc (sizeof (struct guestfs_lvm_vg_list));\n";
7671 pr " sscanf (val, \"%%d\", &r->len);\n";
7672 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_vg));\n";
7673 pr " for (i = 0; i < r->len; ++i) {\n";
7674 pr " r->val[i].vg_name = malloc (16);\n";
7675 pr " snprintf (r->val[i].vg_name, 16, \"%%d\", i);\n";
7679 pr " struct guestfs_lvm_lv_list *r;\n";
7681 pr " r = malloc (sizeof (struct guestfs_lvm_lv_list));\n";
7682 pr " sscanf (val, \"%%d\", &r->len);\n";
7683 pr " r->val = calloc (r->len, sizeof (struct guestfs_lvm_lv));\n";
7684 pr " for (i = 0; i < r->len; ++i) {\n";
7685 pr " r->val[i].lv_name = malloc (16);\n";
7686 pr " snprintf (r->val[i].lv_name, 16, \"%%d\", i);\n";
7690 pr " struct guestfs_stat *r;\n";
7691 pr " r = calloc (1, sizeof (*r));\n";
7692 pr " sscanf (val, \"%%\" SCNi64, &r->dev);\n";
7695 pr " struct guestfs_statvfs *r;\n";
7696 pr " r = calloc (1, sizeof (*r));\n";
7697 pr " sscanf (val, \"%%\" SCNi64, &r->bsize);\n";
7700 pr " char **strs;\n";
7702 pr " sscanf (val, \"%%d\", &n);\n";
7703 pr " strs = malloc ((n*2+1) * sizeof (char *));\n";
7704 pr " for (i = 0; i < n; ++i) {\n";
7705 pr " strs[i*2] = malloc (16);\n";
7706 pr " strs[i*2+1] = malloc (16);\n";
7707 pr " snprintf (strs[i*2], 16, \"%%d\", i);\n";
7708 pr " snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
7710 pr " strs[n*2] = NULL;\n";
7711 pr " return strs;\n"
7716 pr "/* Test error return. */\n";
7717 generate_prototype ~extern:false ~semicolon:false ~newline:true
7718 ~handle:"g" ~prefix:"guestfs_" name style;
7720 pr " error (g, \"error\");\n";
7721 (match fst style with
7722 | RErr | RInt _ | RInt64 _ | RBool _ ->
7725 | RString _ | RStringList _ | RIntBool _
7726 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7728 pr " return NULL;\n"
7735 and generate_ocaml_bindtests () =
7736 generate_header OCamlStyle GPLv2;
7740 let g = Guestfs.create () in
7747 | CallString s -> "\"" ^ s ^ "\""
7748 | CallOptString None -> "None"
7749 | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
7750 | CallStringList xs ->
7751 "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
7752 | CallInt i when i >= 0 -> string_of_int i
7753 | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
7754 | CallBool b -> string_of_bool b
7759 generate_lang_bindtests (
7760 fun f args -> pr " Guestfs.%s g %s;\n" f (mkargs args)
7763 pr "print_endline \"EOF\"\n"
7765 and generate_perl_bindtests () =
7766 pr "#!/usr/bin/perl -w\n";
7767 generate_header HashStyle GPLv2;
7774 my $g = Sys::Guestfs->new ();
7778 String.concat ", " (
7781 | CallString s -> "\"" ^ s ^ "\""
7782 | CallOptString None -> "undef"
7783 | CallOptString (Some s) -> sprintf "\"%s\"" s
7784 | CallStringList xs ->
7785 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7786 | CallInt i -> string_of_int i
7787 | CallBool b -> if b then "1" else "0"
7792 generate_lang_bindtests (
7793 fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
7796 pr "print \"EOF\\n\"\n"
7798 and generate_python_bindtests () =
7799 generate_header HashStyle GPLv2;
7804 g = guestfs.GuestFS ()
7808 String.concat ", " (
7811 | CallString s -> "\"" ^ s ^ "\""
7812 | CallOptString None -> "None"
7813 | CallOptString (Some s) -> sprintf "\"%s\"" s
7814 | CallStringList xs ->
7815 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7816 | CallInt i -> string_of_int i
7817 | CallBool b -> if b then "1" else "0"
7822 generate_lang_bindtests (
7823 fun f args -> pr "g.%s (%s)\n" f (mkargs args)
7826 pr "print \"EOF\"\n"
7828 and generate_ruby_bindtests () =
7829 generate_header HashStyle GPLv2;
7834 g = Guestfs::create()
7838 String.concat ", " (
7841 | CallString s -> "\"" ^ s ^ "\""
7842 | CallOptString None -> "nil"
7843 | CallOptString (Some s) -> sprintf "\"%s\"" s
7844 | CallStringList xs ->
7845 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7846 | CallInt i -> string_of_int i
7847 | CallBool b -> string_of_bool b
7852 generate_lang_bindtests (
7853 fun f args -> pr "g.%s(%s)\n" f (mkargs args)
7856 pr "print \"EOF\\n\"\n"
7858 and generate_java_bindtests () =
7859 generate_header CStyle GPLv2;
7862 import com.redhat.et.libguestfs.*;
7864 public class Bindtests {
7865 public static void main (String[] argv)
7868 GuestFS g = new GuestFS ();
7872 String.concat ", " (
7875 | CallString s -> "\"" ^ s ^ "\""
7876 | CallOptString None -> "null"
7877 | CallOptString (Some s) -> sprintf "\"%s\"" s
7878 | CallStringList xs ->
7880 String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
7881 | CallInt i -> string_of_int i
7882 | CallBool b -> string_of_bool b
7887 generate_lang_bindtests (
7888 fun f args -> pr " g.%s (%s);\n" f (mkargs args)
7892 System.out.println (\"EOF\");
7894 catch (Exception exn) {
7895 System.err.println (exn);
7902 and generate_haskell_bindtests () =
7903 generate_header HaskellStyle GPLv2;
7906 module Bindtests where
7907 import qualified Guestfs
7917 | CallString s -> "\"" ^ s ^ "\""
7918 | CallOptString None -> "Nothing"
7919 | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
7920 | CallStringList xs ->
7921 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7922 | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
7923 | CallInt i -> string_of_int i
7924 | CallBool true -> "True"
7925 | CallBool false -> "False"
7930 generate_lang_bindtests (
7931 fun f args -> pr " Guestfs.%s g %s\n" f (mkargs args)
7934 pr " putStrLn \"EOF\"\n"
7936 (* Language-independent bindings tests - we do it this way to
7937 * ensure there is parity in testing bindings across all languages.
7939 and generate_lang_bindtests call =
7940 call "test0" [CallString "abc"; CallOptString (Some "def");
7941 CallStringList []; CallBool false;
7942 CallInt 0; CallString "123"; CallString "456"];
7943 call "test0" [CallString "abc"; CallOptString None;
7944 CallStringList []; CallBool false;
7945 CallInt 0; CallString "123"; CallString "456"];
7946 call "test0" [CallString ""; CallOptString (Some "def");
7947 CallStringList []; CallBool false;
7948 CallInt 0; CallString "123"; CallString "456"];
7949 call "test0" [CallString ""; CallOptString (Some "");
7950 CallStringList []; CallBool false;
7951 CallInt 0; CallString "123"; CallString "456"];
7952 call "test0" [CallString "abc"; CallOptString (Some "def");
7953 CallStringList ["1"]; CallBool false;
7954 CallInt 0; CallString "123"; CallString "456"];
7955 call "test0" [CallString "abc"; CallOptString (Some "def");
7956 CallStringList ["1"; "2"]; CallBool false;
7957 CallInt 0; CallString "123"; CallString "456"];
7958 call "test0" [CallString "abc"; CallOptString (Some "def");
7959 CallStringList ["1"]; CallBool true;
7960 CallInt 0; CallString "123"; CallString "456"];
7961 call "test0" [CallString "abc"; CallOptString (Some "def");
7962 CallStringList ["1"]; CallBool false;
7963 CallInt (-1); CallString "123"; CallString "456"];
7964 call "test0" [CallString "abc"; CallOptString (Some "def");
7965 CallStringList ["1"]; CallBool false;
7966 CallInt (-2); CallString "123"; CallString "456"];
7967 call "test0" [CallString "abc"; CallOptString (Some "def");
7968 CallStringList ["1"]; CallBool false;
7969 CallInt 1; CallString "123"; CallString "456"];
7970 call "test0" [CallString "abc"; CallOptString (Some "def");
7971 CallStringList ["1"]; CallBool false;
7972 CallInt 2; CallString "123"; CallString "456"];
7973 call "test0" [CallString "abc"; CallOptString (Some "def");
7974 CallStringList ["1"]; CallBool false;
7975 CallInt 4095; CallString "123"; CallString "456"];
7976 call "test0" [CallString "abc"; CallOptString (Some "def");
7977 CallStringList ["1"]; CallBool false;
7978 CallInt 0; CallString ""; CallString ""]
7980 (* XXX Add here tests of the return and error functions. *)
7982 (* This is used to generate the src/MAX_PROC_NR file which
7983 * contains the maximum procedure number, a surrogate for the
7984 * ABI version number. See src/Makefile.am for the details.
7986 and generate_max_proc_nr () =
7987 let proc_nrs = List.map (
7988 fun (_, _, proc_nr, _, _, _, _) -> proc_nr
7989 ) daemon_functions in
7991 let max_proc_nr = List.fold_left max 0 proc_nrs in
7993 pr "%d\n" max_proc_nr
7995 let output_to filename =
7996 let filename_new = filename ^ ".new" in
7997 chan := open_out filename_new;
8002 (* Is the new file different from the current file? *)
8003 if Sys.file_exists filename && files_equal filename filename_new then
8004 Unix.unlink filename_new (* same, so skip it *)
8006 (* different, overwrite old one *)
8007 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
8008 Unix.rename filename_new filename;
8009 Unix.chmod filename 0o444;
8010 printf "written %s\n%!" filename;
8019 if not (Sys.file_exists "configure.ac") then (
8021 You are probably running this from the wrong directory.
8022 Run it from the top source directory using the command
8028 let close = output_to "src/guestfs_protocol.x" in
8032 let close = output_to "src/guestfs-structs.h" in
8033 generate_structs_h ();
8036 let close = output_to "src/guestfs-actions.h" in
8037 generate_actions_h ();
8040 let close = output_to "src/guestfs-actions.c" in
8041 generate_client_actions ();
8044 let close = output_to "daemon/actions.h" in
8045 generate_daemon_actions_h ();
8048 let close = output_to "daemon/stubs.c" in
8049 generate_daemon_actions ();
8052 let close = output_to "capitests/tests.c" in
8056 let close = output_to "src/guestfs-bindtests.c" in
8057 generate_bindtests ();
8060 let close = output_to "fish/cmds.c" in
8061 generate_fish_cmds ();
8064 let close = output_to "fish/completion.c" in
8065 generate_fish_completion ();
8068 let close = output_to "guestfs-structs.pod" in
8069 generate_structs_pod ();
8072 let close = output_to "guestfs-actions.pod" in
8073 generate_actions_pod ();
8076 let close = output_to "guestfish-actions.pod" in
8077 generate_fish_actions_pod ();
8080 let close = output_to "ocaml/guestfs.mli" in
8081 generate_ocaml_mli ();
8084 let close = output_to "ocaml/guestfs.ml" in
8085 generate_ocaml_ml ();
8088 let close = output_to "ocaml/guestfs_c_actions.c" in
8089 generate_ocaml_c ();
8092 let close = output_to "ocaml/bindtests.ml" in
8093 generate_ocaml_bindtests ();
8096 let close = output_to "perl/Guestfs.xs" in
8097 generate_perl_xs ();
8100 let close = output_to "perl/lib/Sys/Guestfs.pm" in
8101 generate_perl_pm ();
8104 let close = output_to "perl/bindtests.pl" in
8105 generate_perl_bindtests ();
8108 let close = output_to "python/guestfs-py.c" in
8109 generate_python_c ();
8112 let close = output_to "python/guestfs.py" in
8113 generate_python_py ();
8116 let close = output_to "python/bindtests.py" in
8117 generate_python_bindtests ();
8120 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
8124 let close = output_to "ruby/bindtests.rb" in
8125 generate_ruby_bindtests ();
8128 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
8129 generate_java_java ();
8132 let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
8133 generate_java_struct "PV" pv_cols;
8136 let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
8137 generate_java_struct "VG" vg_cols;
8140 let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
8141 generate_java_struct "LV" lv_cols;
8144 let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
8145 generate_java_struct "Stat" stat_cols;
8148 let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
8149 generate_java_struct "StatVFS" statvfs_cols;
8152 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
8156 let close = output_to "java/Bindtests.java" in
8157 generate_java_bindtests ();
8160 let close = output_to "haskell/Guestfs.hs" in
8161 generate_haskell_hs ();
8164 let close = output_to "haskell/Bindtests.hs" in
8165 generate_haskell_bindtests ();
8168 let close = output_to "src/MAX_PROC_NR" in
8169 generate_max_proc_nr ();