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
86 (* List of directory entries (the result of readdir(3)). *)
87 | RDirentList of string
89 and args = argt list (* Function parameters, guestfs handle is implicit. *)
91 (* Note in future we should allow a "variable args" parameter as
92 * the final parameter, to allow commands like
93 * chmod mode file [file(s)...]
94 * This is not implemented yet, but many commands (such as chmod)
95 * are currently defined with the argument order keeping this future
96 * possibility in mind.
99 | String of string (* const char *name, cannot be NULL *)
100 | OptString of string (* const char *name, may be NULL *)
101 | StringList of string(* list of strings (each string cannot be NULL) *)
102 | Bool of string (* boolean *)
103 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
104 (* These are treated as filenames (simple string parameters) in
105 * the C API and bindings. But in the RPC protocol, we transfer
106 * the actual file content up to or down from the daemon.
107 * FileIn: local machine -> daemon (in request)
108 * FileOut: daemon -> local machine (in reply)
109 * In guestfish (only), the special name "-" means read from
110 * stdin or write to stdout.
116 | ProtocolLimitWarning (* display warning about protocol size limits *)
117 | DangerWillRobinson (* flags particularly dangerous commands *)
118 | FishAlias of string (* provide an alias for this cmd in guestfish *)
119 | FishAction of string (* call this function in guestfish *)
120 | NotInFish (* do not export via guestfish *)
121 | NotInDocs (* do not add this function to documentation *)
123 let protocol_limit_warning =
124 "Because of the message protocol, there is a transfer limit
125 of somewhere between 2MB and 4MB. To transfer large files you should use
128 let danger_will_robinson =
129 "B<This command is dangerous. Without careful use you
130 can easily destroy all your data>."
132 (* You can supply zero or as many tests as you want per API call.
134 * Note that the test environment has 3 block devices, of size 500MB,
135 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
136 * a fourth squashfs block device with some known files on it (/dev/sdd).
138 * Note for partitioning purposes, the 500MB device has 1015 cylinders.
139 * Number of cylinders was 63 for IDE emulated disks with precisely
140 * the same size. How exactly this is calculated is a mystery.
142 * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
144 * To be able to run the tests in a reasonable amount of time,
145 * the virtual machine and block devices are reused between tests.
146 * So don't try testing kill_subprocess :-x
148 * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
150 * Don't assume anything about the previous contents of the block
151 * devices. Use 'Init*' to create some initial scenarios.
153 * You can add a prerequisite clause to any individual test. This
154 * is a run-time check, which, if it fails, causes the test to be
155 * skipped. Useful if testing a command which might not work on
156 * all variations of libguestfs builds. A test that has prerequisite
157 * of 'Always' is run unconditionally.
159 * In addition, packagers can skip individual tests by setting the
160 * environment variables: eg:
161 * SKIP_TEST_<CMD>_<NUM>=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command)
162 * SKIP_TEST_<CMD>=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests)
164 type tests = (test_init * test_prereq * test) list
166 (* Run the command sequence and just expect nothing to fail. *)
168 (* Run the command sequence and expect the output of the final
169 * command to be the string.
171 | TestOutput of seq * string
172 (* Run the command sequence and expect the output of the final
173 * command to be the list of strings.
175 | TestOutputList of seq * string list
176 (* Run the command sequence and expect the output of the final
177 * command to be the list of block devices (could be either
178 * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
179 * character of each string).
181 | TestOutputListOfDevices of seq * string list
182 (* Run the command sequence and expect the output of the final
183 * command to be the integer.
185 | TestOutputInt of seq * int
186 (* Run the command sequence and expect the output of the final
187 * command to be a true value (!= 0 or != NULL).
189 | TestOutputTrue of seq
190 (* Run the command sequence and expect the output of the final
191 * command to be a false value (== 0 or == NULL, but not an error).
193 | TestOutputFalse of seq
194 (* Run the command sequence and expect the output of the final
195 * command to be a list of the given length (but don't care about
198 | TestOutputLength of seq * int
199 (* Run the command sequence and expect the output of the final
200 * command to be a structure.
202 | TestOutputStruct of seq * test_field_compare list
203 (* Run the command sequence and expect the final command (only)
206 | TestLastFail of seq
208 and test_field_compare =
209 | CompareWithInt of string * int
210 | CompareWithString of string * string
211 | CompareFieldsIntEq of string * string
212 | CompareFieldsStrEq of string * string
214 (* Test prerequisites. *)
216 (* Test always runs. *)
218 (* Test is currently disabled - eg. it fails, or it tests some
219 * unimplemented feature.
222 (* 'string' is some C code (a function body) that should return
223 * true or false. The test will run if the code returns true.
226 (* As for 'If' but the test runs _unless_ the code returns true. *)
229 (* Some initial scenarios for testing. *)
231 (* Do nothing, block devices could contain random stuff including
232 * LVM PVs, and some filesystems might be mounted. This is usually
236 (* Block devices are empty and no filesystems are mounted. *)
238 (* /dev/sda contains a single partition /dev/sda1, which is formatted
239 * as ext2, empty [except for lost+found] and mounted on /.
240 * /dev/sdb and /dev/sdc may have random content.
245 * /dev/sda1 (is a PV):
246 * /dev/VG/LV (size 8MB):
247 * formatted as ext2, empty [except for lost+found], mounted on /
248 * /dev/sdb and /dev/sdc may have random content.
252 (* Sequence of commands for testing. *)
254 and cmd = string list
256 (* Note about long descriptions: When referring to another
257 * action, use the format C<guestfs_other> (ie. the full name of
258 * the C function). This will be replaced as appropriate in other
261 * Apart from that, long descriptions are just perldoc paragraphs.
264 (* These test functions are used in the language binding tests. *)
266 let test_all_args = [
269 StringList "strlist";
276 let test_all_rets = [
277 (* except for RErr, which is tested thoroughly elsewhere *)
278 "test0rint", RInt "valout";
279 "test0rint64", RInt64 "valout";
280 "test0rbool", RBool "valout";
281 "test0rconststring", RConstString "valout";
282 "test0rstring", RString "valout";
283 "test0rstringlist", RStringList "valout";
284 "test0rintbool", RIntBool ("valout", "valout");
285 "test0rpvlist", RPVList "valout";
286 "test0rvglist", RVGList "valout";
287 "test0rlvlist", RLVList "valout";
288 "test0rstat", RStat "valout";
289 "test0rstatvfs", RStatVFS "valout";
290 "test0rhashtable", RHashtable "valout";
293 let test_functions = [
294 ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
296 "internal test function - do not use",
298 This is an internal test function which is used to test whether
299 the automatically generated bindings can handle every possible
300 parameter type correctly.
302 It echos the contents of each parameter to stdout.
304 You probably don't want to call this function.");
308 [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
310 "internal test function - do not use",
312 This is an internal test function which is used to test whether
313 the automatically generated bindings can handle every possible
314 return type correctly.
316 It converts string C<val> to the return type.
318 You probably don't want to call this function.");
319 (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
321 "internal test function - do not use",
323 This is an internal test function which is used to test whether
324 the automatically generated bindings can handle every possible
325 return type correctly.
327 This function always returns an error.
329 You probably don't want to call this function.")]
333 (* non_daemon_functions are any functions which don't get processed
334 * in the daemon, eg. functions for setting and getting local
335 * configuration values.
338 let non_daemon_functions = test_functions @ [
339 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
341 "launch the qemu subprocess",
343 Internally libguestfs is implemented by running a virtual machine
346 You should call this after configuring the handle
347 (eg. adding drives) but before performing any actions.");
349 ("wait_ready", (RErr, []), -1, [NotInFish],
351 "wait until the qemu subprocess launches",
353 Internally libguestfs is implemented by running a virtual machine
356 You should call this after C<guestfs_launch> to wait for the launch
359 ("kill_subprocess", (RErr, []), -1, [],
361 "kill the qemu subprocess",
363 This kills the qemu subprocess. You should never need to call this.");
365 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
367 "add an image to examine or modify",
369 This function adds a virtual machine disk image C<filename> to the
370 guest. The first time you call this function, the disk appears as IDE
371 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
374 You don't necessarily need to be root when using libguestfs. However
375 you obviously do need sufficient permissions to access the filename
376 for whatever operations you want to perform (ie. read access if you
377 just want to read the image or write access if you want to modify the
380 This is equivalent to the qemu parameter
381 C<-drive file=filename,cache=off,if=...>.
383 Note that this call checks for the existence of C<filename>. This
384 stops you from specifying other types of drive which are supported
385 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
386 the general C<guestfs_config> call instead.");
388 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
390 "add a CD-ROM disk image to examine",
392 This function adds a virtual CD-ROM disk image to the guest.
394 This is equivalent to the qemu parameter C<-cdrom filename>.
396 Note that this call checks for the existence of C<filename>. This
397 stops you from specifying other types of drive which are supported
398 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
399 the general C<guestfs_config> call instead.");
401 ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
403 "add a drive in snapshot mode (read-only)",
405 This adds a drive in snapshot mode, making it effectively
408 Note that writes to the device are allowed, and will be seen for
409 the duration of the guestfs handle, but they are written
410 to a temporary file which is discarded as soon as the guestfs
411 handle is closed. We don't currently have any method to enable
412 changes to be committed, although qemu can support this.
414 This is equivalent to the qemu parameter
415 C<-drive file=filename,snapshot=on,if=...>.
417 Note that this call checks for the existence of C<filename>. This
418 stops you from specifying other types of drive which are supported
419 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
420 the general C<guestfs_config> call instead.");
422 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
424 "add qemu parameters",
426 This can be used to add arbitrary qemu command line parameters
427 of the form C<-param value>. Actually it's not quite arbitrary - we
428 prevent you from setting some parameters which would interfere with
429 parameters that we use.
431 The first character of C<param> string must be a C<-> (dash).
433 C<value> can be NULL.");
435 ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
437 "set the qemu binary",
439 Set the qemu binary that we will use.
441 The default is chosen when the library was compiled by the
444 You can also override this by setting the C<LIBGUESTFS_QEMU>
445 environment variable.
447 Setting C<qemu> to C<NULL> restores the default qemu binary.");
449 ("get_qemu", (RConstString "qemu", []), -1, [],
451 "get the qemu binary",
453 Return the current qemu binary.
455 This is always non-NULL. If it wasn't set already, then this will
456 return the default qemu binary name.");
458 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
460 "set the search path",
462 Set the path that libguestfs searches for kernel and initrd.img.
464 The default is C<$libdir/guestfs> unless overridden by setting
465 C<LIBGUESTFS_PATH> environment variable.
467 Setting C<path> to C<NULL> restores the default path.");
469 ("get_path", (RConstString "path", []), -1, [],
471 "get the search path",
473 Return the current search path.
475 This is always non-NULL. If it wasn't set already, then this will
476 return the default path.");
478 ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
480 "add options to kernel command line",
482 This function is used to add additional options to the
483 guest kernel command line.
485 The default is C<NULL> unless overridden by setting
486 C<LIBGUESTFS_APPEND> environment variable.
488 Setting C<append> to C<NULL> means I<no> additional options
489 are passed (libguestfs always adds a few of its own).");
491 ("get_append", (RConstString "append", []), -1, [],
493 "get the additional kernel options",
495 Return the additional kernel options which are added to the
496 guest kernel command line.
498 If C<NULL> then no options are added.");
500 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
504 If C<autosync> is true, this enables autosync. Libguestfs will make a
505 best effort attempt to run C<guestfs_umount_all> followed by
506 C<guestfs_sync> when the handle is closed
507 (also if the program exits without closing handles).
509 This is disabled by default (except in guestfish where it is
510 enabled by default).");
512 ("get_autosync", (RBool "autosync", []), -1, [],
516 Get the autosync flag.");
518 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
522 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
524 Verbose messages are disabled unless the environment variable
525 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
527 ("get_verbose", (RBool "verbose", []), -1, [],
531 This returns the verbose messages flag.");
533 ("is_ready", (RBool "ready", []), -1, [],
535 "is ready to accept commands",
537 This returns true iff this handle is ready to accept commands
538 (in the C<READY> state).
540 For more information on states, see L<guestfs(3)>.");
542 ("is_config", (RBool "config", []), -1, [],
544 "is in configuration state",
546 This returns true iff this handle is being configured
547 (in the C<CONFIG> state).
549 For more information on states, see L<guestfs(3)>.");
551 ("is_launching", (RBool "launching", []), -1, [],
553 "is launching subprocess",
555 This returns true iff this handle is launching the subprocess
556 (in the C<LAUNCHING> state).
558 For more information on states, see L<guestfs(3)>.");
560 ("is_busy", (RBool "busy", []), -1, [],
562 "is busy processing a command",
564 This returns true iff this handle is busy processing a command
565 (in the C<BUSY> state).
567 For more information on states, see L<guestfs(3)>.");
569 ("get_state", (RInt "state", []), -1, [],
571 "get the current state",
573 This returns the current state as an opaque integer. This is
574 only useful for printing debug and internal error messages.
576 For more information on states, see L<guestfs(3)>.");
578 ("set_busy", (RErr, []), -1, [NotInFish],
582 This sets the state to C<BUSY>. This is only used when implementing
583 actions using the low-level API.
585 For more information on states, see L<guestfs(3)>.");
587 ("set_ready", (RErr, []), -1, [NotInFish],
589 "set state to ready",
591 This sets the state to C<READY>. This is only used when implementing
592 actions using the low-level API.
594 For more information on states, see L<guestfs(3)>.");
596 ("end_busy", (RErr, []), -1, [NotInFish],
598 "leave the busy state",
600 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
601 state as is. This is only used when implementing
602 actions using the low-level API.
604 For more information on states, see L<guestfs(3)>.");
606 ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
608 "set memory allocated to the qemu subprocess",
610 This sets the memory size in megabytes allocated to the
611 qemu subprocess. This only has any effect if called before
614 You can also change this by setting the environment
615 variable C<LIBGUESTFS_MEMSIZE> before the handle is
618 For more information on the architecture of libguestfs,
619 see L<guestfs(3)>.");
621 ("get_memsize", (RInt "memsize", []), -1, [],
623 "get memory allocated to the qemu subprocess",
625 This gets the memory size in megabytes allocated to the
628 If C<guestfs_set_memsize> was not called
629 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
630 then this returns the compiled-in default value for memsize.
632 For more information on the architecture of libguestfs,
633 see L<guestfs(3)>.");
635 ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
637 "get PID of qemu subprocess",
639 Return the process ID of the qemu subprocess. If there is no
640 qemu subprocess, then this will return an error.
642 This is an internal call used for debugging and testing.");
646 (* daemon_functions are any functions which cause some action
647 * to take place in the daemon.
650 let daemon_functions = [
651 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
652 [InitEmpty, Always, TestOutput (
653 [["sfdiskM"; "/dev/sda"; ","];
654 ["mkfs"; "ext2"; "/dev/sda1"];
655 ["mount"; "/dev/sda1"; "/"];
656 ["write_file"; "/new"; "new file contents"; "0"];
657 ["cat"; "/new"]], "new file contents")],
658 "mount a guest disk at a position in the filesystem",
660 Mount a guest disk at a position in the filesystem. Block devices
661 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
662 the guest. If those block devices contain partitions, they will have
663 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
666 The rules are the same as for L<mount(2)>: A filesystem must
667 first be mounted on C</> before others can be mounted. Other
668 filesystems can only be mounted on directories which already
671 The mounted filesystem is writable, if we have sufficient permissions
672 on the underlying device.
674 The filesystem options C<sync> and C<noatime> are set with this
675 call, in order to improve reliability.");
677 ("sync", (RErr, []), 2, [],
678 [ InitEmpty, Always, TestRun [["sync"]]],
679 "sync disks, writes are flushed through to the disk image",
681 This syncs the disk, so that any writes are flushed through to the
682 underlying disk image.
684 You should always call this if you have modified a disk image, before
685 closing the handle.");
687 ("touch", (RErr, [String "path"]), 3, [],
688 [InitBasicFS, Always, TestOutputTrue (
690 ["exists"; "/new"]])],
691 "update file timestamps or create a new file",
693 Touch acts like the L<touch(1)> command. It can be used to
694 update the timestamps on a file, or, if the file does not exist,
695 to create a new zero-length file.");
697 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
698 [InitBasicFS, Always, TestOutput (
699 [["write_file"; "/new"; "new file contents"; "0"];
700 ["cat"; "/new"]], "new file contents")],
701 "list the contents of a file",
703 Return the contents of the file named C<path>.
705 Note that this function cannot correctly handle binary files
706 (specifically, files containing C<\\0> character which is treated
707 as end of string). For those you need to use the C<guestfs_download>
708 function which has a more complex interface.");
710 ("ll", (RString "listing", [String "directory"]), 5, [],
711 [], (* XXX Tricky to test because it depends on the exact format
712 * of the 'ls -l' command, which changes between F10 and F11.
714 "list the files in a directory (long format)",
716 List the files in C<directory> (relative to the root directory,
717 there is no cwd) in the format of 'ls -la'.
719 This command is mostly useful for interactive sessions. It
720 is I<not> intended that you try to parse the output string.");
722 ("ls", (RStringList "listing", [String "directory"]), 6, [],
723 [InitBasicFS, Always, TestOutputList (
726 ["touch"; "/newest"];
727 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
728 "list the files in a directory",
730 List the files in C<directory> (relative to the root directory,
731 there is no cwd). The '.' and '..' entries are not returned, but
732 hidden files are shown.
734 This command is mostly useful for interactive sessions. Programs
735 should probably use C<guestfs_readdir> instead.");
737 ("list_devices", (RStringList "devices", []), 7, [],
738 [InitEmpty, Always, TestOutputListOfDevices (
739 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
740 "list the block devices",
742 List all the block devices.
744 The full block device names are returned, eg. C</dev/sda>");
746 ("list_partitions", (RStringList "partitions", []), 8, [],
747 [InitBasicFS, Always, TestOutputListOfDevices (
748 [["list_partitions"]], ["/dev/sda1"]);
749 InitEmpty, Always, TestOutputListOfDevices (
750 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
751 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
752 "list the partitions",
754 List all the partitions detected on all block devices.
756 The full partition device names are returned, eg. C</dev/sda1>
758 This does not return logical volumes. For that you will need to
759 call C<guestfs_lvs>.");
761 ("pvs", (RStringList "physvols", []), 9, [],
762 [InitBasicFSonLVM, Always, TestOutputListOfDevices (
763 [["pvs"]], ["/dev/sda1"]);
764 InitEmpty, Always, TestOutputListOfDevices (
765 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
766 ["pvcreate"; "/dev/sda1"];
767 ["pvcreate"; "/dev/sda2"];
768 ["pvcreate"; "/dev/sda3"];
769 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
770 "list the LVM physical volumes (PVs)",
772 List all the physical volumes detected. This is the equivalent
773 of the L<pvs(8)> command.
775 This returns a list of just the device names that contain
776 PVs (eg. C</dev/sda2>).
778 See also C<guestfs_pvs_full>.");
780 ("vgs", (RStringList "volgroups", []), 10, [],
781 [InitBasicFSonLVM, Always, TestOutputList (
783 InitEmpty, Always, TestOutputList (
784 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
785 ["pvcreate"; "/dev/sda1"];
786 ["pvcreate"; "/dev/sda2"];
787 ["pvcreate"; "/dev/sda3"];
788 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
789 ["vgcreate"; "VG2"; "/dev/sda3"];
790 ["vgs"]], ["VG1"; "VG2"])],
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.
796 This returns a list of just the volume group names that were
797 detected (eg. C<VolGroup00>).
799 See also C<guestfs_vgs_full>.");
801 ("lvs", (RStringList "logvols", []), 11, [],
802 [InitBasicFSonLVM, Always, TestOutputList (
803 [["lvs"]], ["/dev/VG/LV"]);
804 InitEmpty, Always, TestOutputList (
805 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
806 ["pvcreate"; "/dev/sda1"];
807 ["pvcreate"; "/dev/sda2"];
808 ["pvcreate"; "/dev/sda3"];
809 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
810 ["vgcreate"; "VG2"; "/dev/sda3"];
811 ["lvcreate"; "LV1"; "VG1"; "50"];
812 ["lvcreate"; "LV2"; "VG1"; "50"];
813 ["lvcreate"; "LV3"; "VG2"; "50"];
814 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
815 "list the LVM logical volumes (LVs)",
817 List all the logical volumes detected. This is the equivalent
818 of the L<lvs(8)> command.
820 This returns a list of the logical volume device names
821 (eg. C</dev/VolGroup00/LogVol00>).
823 See also C<guestfs_lvs_full>.");
825 ("pvs_full", (RPVList "physvols", []), 12, [],
826 [], (* XXX how to test? *)
827 "list the LVM physical volumes (PVs)",
829 List all the physical volumes detected. This is the equivalent
830 of the L<pvs(8)> command. The \"full\" version includes all fields.");
832 ("vgs_full", (RVGList "volgroups", []), 13, [],
833 [], (* XXX how to test? *)
834 "list the LVM volume groups (VGs)",
836 List all the volumes groups detected. This is the equivalent
837 of the L<vgs(8)> command. The \"full\" version includes all fields.");
839 ("lvs_full", (RLVList "logvols", []), 14, [],
840 [], (* XXX how to test? *)
841 "list the LVM logical volumes (LVs)",
843 List all the logical volumes detected. This is the equivalent
844 of the L<lvs(8)> command. The \"full\" version includes all fields.");
846 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
847 [InitBasicFS, Always, TestOutputList (
848 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
849 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
850 InitBasicFS, Always, TestOutputList (
851 [["write_file"; "/new"; ""; "0"];
852 ["read_lines"; "/new"]], [])],
853 "read file as lines",
855 Return the contents of the file named C<path>.
857 The file contents are returned as a list of lines. Trailing
858 C<LF> and C<CRLF> character sequences are I<not> returned.
860 Note that this function cannot correctly handle binary files
861 (specifically, files containing C<\\0> character which is treated
862 as end of line). For those you need to use the C<guestfs_read_file>
863 function which has a more complex interface.");
865 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
866 [], (* XXX Augeas code needs tests. *)
867 "create a new Augeas handle",
869 Create a new Augeas handle for editing configuration files.
870 If there was any previous Augeas handle associated with this
871 guestfs session, then it is closed.
873 You must call this before using any other C<guestfs_aug_*>
876 C<root> is the filesystem root. C<root> must not be NULL,
879 The flags are the same as the flags defined in
880 E<lt>augeas.hE<gt>, the logical I<or> of the following
885 =item C<AUG_SAVE_BACKUP> = 1
887 Keep the original file with a C<.augsave> extension.
889 =item C<AUG_SAVE_NEWFILE> = 2
891 Save changes into a file with extension C<.augnew>, and
892 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
894 =item C<AUG_TYPE_CHECK> = 4
896 Typecheck lenses (can be expensive).
898 =item C<AUG_NO_STDINC> = 8
900 Do not use standard load path for modules.
902 =item C<AUG_SAVE_NOOP> = 16
904 Make save a no-op, just record what would have been changed.
906 =item C<AUG_NO_LOAD> = 32
908 Do not load the tree in C<guestfs_aug_init>.
912 To close the handle, you can call C<guestfs_aug_close>.
914 To find out more about Augeas, see L<http://augeas.net/>.");
916 ("aug_close", (RErr, []), 26, [],
917 [], (* XXX Augeas code needs tests. *)
918 "close the current Augeas handle",
920 Close the current Augeas handle and free up any resources
921 used by it. After calling this, you have to call
922 C<guestfs_aug_init> again before you can use any other
925 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
926 [], (* XXX Augeas code needs tests. *)
927 "define an Augeas variable",
929 Defines an Augeas variable C<name> whose value is the result
930 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
933 On success this returns the number of nodes in C<expr>, or
934 C<0> if C<expr> evaluates to something which is not a nodeset.");
936 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
937 [], (* XXX Augeas code needs tests. *)
938 "define an Augeas node",
940 Defines a variable C<name> whose value is the result of
943 If C<expr> evaluates to an empty nodeset, a node is created,
944 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
945 C<name> will be the nodeset containing that single node.
947 On success this returns a pair containing the
948 number of nodes in the nodeset, and a boolean flag
949 if a node was created.");
951 ("aug_get", (RString "val", [String "path"]), 19, [],
952 [], (* XXX Augeas code needs tests. *)
953 "look up the value of an Augeas path",
955 Look up the value associated with C<path>. If C<path>
956 matches exactly one node, the C<value> is returned.");
958 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
959 [], (* XXX Augeas code needs tests. *)
960 "set Augeas path to value",
962 Set the value associated with C<path> to C<value>.");
964 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
965 [], (* XXX Augeas code needs tests. *)
966 "insert a sibling Augeas node",
968 Create a new sibling C<label> for C<path>, inserting it into
969 the tree before or after C<path> (depending on the boolean
972 C<path> must match exactly one existing node in the tree, and
973 C<label> must be a label, ie. not contain C</>, C<*> or end
974 with a bracketed index C<[N]>.");
976 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
977 [], (* XXX Augeas code needs tests. *)
978 "remove an Augeas path",
980 Remove C<path> and all of its children.
982 On success this returns the number of entries which were removed.");
984 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
985 [], (* XXX Augeas code needs tests. *)
988 Move the node C<src> to C<dest>. C<src> must match exactly
989 one node. C<dest> is overwritten if it exists.");
991 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
992 [], (* XXX Augeas code needs tests. *)
993 "return Augeas nodes which match path",
995 Returns a list of paths which match the path expression C<path>.
996 The returned paths are sufficiently qualified so that they match
997 exactly one node in the current tree.");
999 ("aug_save", (RErr, []), 25, [],
1000 [], (* XXX Augeas code needs tests. *)
1001 "write all pending Augeas changes to disk",
1003 This writes all pending changes to disk.
1005 The flags which were passed to C<guestfs_aug_init> affect exactly
1006 how files are saved.");
1008 ("aug_load", (RErr, []), 27, [],
1009 [], (* XXX Augeas code needs tests. *)
1010 "load files into the tree",
1012 Load files into the tree.
1014 See C<aug_load> in the Augeas documentation for the full gory
1017 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
1018 [], (* XXX Augeas code needs tests. *)
1019 "list Augeas nodes under a path",
1021 This is just a shortcut for listing C<guestfs_aug_match>
1022 C<path/*> and sorting the resulting nodes into alphabetical order.");
1024 ("rm", (RErr, [String "path"]), 29, [],
1025 [InitBasicFS, Always, TestRun
1028 InitBasicFS, Always, TestLastFail
1030 InitBasicFS, Always, TestLastFail
1035 Remove the single file C<path>.");
1037 ("rmdir", (RErr, [String "path"]), 30, [],
1038 [InitBasicFS, Always, TestRun
1041 InitBasicFS, Always, TestLastFail
1042 [["rmdir"; "/new"]];
1043 InitBasicFS, Always, TestLastFail
1045 ["rmdir"; "/new"]]],
1046 "remove a directory",
1048 Remove the single directory C<path>.");
1050 ("rm_rf", (RErr, [String "path"]), 31, [],
1051 [InitBasicFS, Always, TestOutputFalse
1053 ["mkdir"; "/new/foo"];
1054 ["touch"; "/new/foo/bar"];
1056 ["exists"; "/new"]]],
1057 "remove a file or directory recursively",
1059 Remove the file or directory C<path>, recursively removing the
1060 contents if its a directory. This is like the C<rm -rf> shell
1063 ("mkdir", (RErr, [String "path"]), 32, [],
1064 [InitBasicFS, Always, TestOutputTrue
1066 ["is_dir"; "/new"]];
1067 InitBasicFS, Always, TestLastFail
1068 [["mkdir"; "/new/foo/bar"]]],
1069 "create a directory",
1071 Create a directory named C<path>.");
1073 ("mkdir_p", (RErr, [String "path"]), 33, [],
1074 [InitBasicFS, Always, TestOutputTrue
1075 [["mkdir_p"; "/new/foo/bar"];
1076 ["is_dir"; "/new/foo/bar"]];
1077 InitBasicFS, Always, TestOutputTrue
1078 [["mkdir_p"; "/new/foo/bar"];
1079 ["is_dir"; "/new/foo"]];
1080 InitBasicFS, Always, TestOutputTrue
1081 [["mkdir_p"; "/new/foo/bar"];
1082 ["is_dir"; "/new"]];
1083 (* Regression tests for RHBZ#503133: *)
1084 InitBasicFS, Always, TestRun
1086 ["mkdir_p"; "/new"]];
1087 InitBasicFS, Always, TestLastFail
1089 ["mkdir_p"; "/new"]]],
1090 "create a directory and parents",
1092 Create a directory named C<path>, creating any parent directories
1093 as necessary. This is like the C<mkdir -p> shell command.");
1095 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1096 [], (* XXX Need stat command to test *)
1099 Change the mode (permissions) of C<path> to C<mode>. Only
1100 numeric modes are supported.");
1102 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1103 [], (* XXX Need stat command to test *)
1104 "change file owner and group",
1106 Change the file owner to C<owner> and group to C<group>.
1108 Only numeric uid and gid are supported. If you want to use
1109 names, you will need to locate and parse the password file
1110 yourself (Augeas support makes this relatively easy).");
1112 ("exists", (RBool "existsflag", [String "path"]), 36, [],
1113 [InitBasicFS, Always, TestOutputTrue (
1115 ["exists"; "/new"]]);
1116 InitBasicFS, Always, TestOutputTrue (
1118 ["exists"; "/new"]])],
1119 "test if file or directory exists",
1121 This returns C<true> if and only if there is a file, directory
1122 (or anything) with the given C<path> name.
1124 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1126 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1127 [InitBasicFS, Always, TestOutputTrue (
1129 ["is_file"; "/new"]]);
1130 InitBasicFS, Always, TestOutputFalse (
1132 ["is_file"; "/new"]])],
1133 "test if file exists",
1135 This returns C<true> if and only if there is a file
1136 with the given C<path> name. Note that it returns false for
1137 other objects like directories.
1139 See also C<guestfs_stat>.");
1141 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1142 [InitBasicFS, Always, TestOutputFalse (
1144 ["is_dir"; "/new"]]);
1145 InitBasicFS, Always, TestOutputTrue (
1147 ["is_dir"; "/new"]])],
1148 "test if file exists",
1150 This returns C<true> if and only if there is a directory
1151 with the given C<path> name. Note that it returns false for
1152 other objects like files.
1154 See also C<guestfs_stat>.");
1156 ("pvcreate", (RErr, [String "device"]), 39, [],
1157 [InitEmpty, Always, TestOutputListOfDevices (
1158 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1159 ["pvcreate"; "/dev/sda1"];
1160 ["pvcreate"; "/dev/sda2"];
1161 ["pvcreate"; "/dev/sda3"];
1162 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1163 "create an LVM physical volume",
1165 This creates an LVM physical volume on the named C<device>,
1166 where C<device> should usually be a partition name such
1169 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1170 [InitEmpty, Always, TestOutputList (
1171 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1172 ["pvcreate"; "/dev/sda1"];
1173 ["pvcreate"; "/dev/sda2"];
1174 ["pvcreate"; "/dev/sda3"];
1175 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1176 ["vgcreate"; "VG2"; "/dev/sda3"];
1177 ["vgs"]], ["VG1"; "VG2"])],
1178 "create an LVM volume group",
1180 This creates an LVM volume group called C<volgroup>
1181 from the non-empty list of physical volumes C<physvols>.");
1183 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1184 [InitEmpty, Always, TestOutputList (
1185 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1186 ["pvcreate"; "/dev/sda1"];
1187 ["pvcreate"; "/dev/sda2"];
1188 ["pvcreate"; "/dev/sda3"];
1189 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1190 ["vgcreate"; "VG2"; "/dev/sda3"];
1191 ["lvcreate"; "LV1"; "VG1"; "50"];
1192 ["lvcreate"; "LV2"; "VG1"; "50"];
1193 ["lvcreate"; "LV3"; "VG2"; "50"];
1194 ["lvcreate"; "LV4"; "VG2"; "50"];
1195 ["lvcreate"; "LV5"; "VG2"; "50"];
1197 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1198 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1199 "create an LVM volume group",
1201 This creates an LVM volume group called C<logvol>
1202 on the volume group C<volgroup>, with C<size> megabytes.");
1204 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1205 [InitEmpty, Always, TestOutput (
1206 [["sfdiskM"; "/dev/sda"; ","];
1207 ["mkfs"; "ext2"; "/dev/sda1"];
1208 ["mount"; "/dev/sda1"; "/"];
1209 ["write_file"; "/new"; "new file contents"; "0"];
1210 ["cat"; "/new"]], "new file contents")],
1211 "make a filesystem",
1213 This creates a filesystem on C<device> (usually a partition
1214 or LVM logical volume). The filesystem type is C<fstype>, for
1217 ("sfdisk", (RErr, [String "device";
1218 Int "cyls"; Int "heads"; Int "sectors";
1219 StringList "lines"]), 43, [DangerWillRobinson],
1221 "create partitions on a block device",
1223 This is a direct interface to the L<sfdisk(8)> program for creating
1224 partitions on block devices.
1226 C<device> should be a block device, for example C</dev/sda>.
1228 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1229 and sectors on the device, which are passed directly to sfdisk as
1230 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
1231 of these, then the corresponding parameter is omitted. Usually for
1232 'large' disks, you can just pass C<0> for these, but for small
1233 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1234 out the right geometry and you will need to tell it.
1236 C<lines> is a list of lines that we feed to C<sfdisk>. For more
1237 information refer to the L<sfdisk(8)> manpage.
1239 To create a single partition occupying the whole disk, you would
1240 pass C<lines> as a single element list, when the single element being
1241 the string C<,> (comma).
1243 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1245 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1246 [InitBasicFS, Always, TestOutput (
1247 [["write_file"; "/new"; "new file contents"; "0"];
1248 ["cat"; "/new"]], "new file contents");
1249 InitBasicFS, Always, TestOutput (
1250 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1251 ["cat"; "/new"]], "\nnew file contents\n");
1252 InitBasicFS, Always, TestOutput (
1253 [["write_file"; "/new"; "\n\n"; "0"];
1254 ["cat"; "/new"]], "\n\n");
1255 InitBasicFS, Always, TestOutput (
1256 [["write_file"; "/new"; ""; "0"];
1257 ["cat"; "/new"]], "");
1258 InitBasicFS, Always, TestOutput (
1259 [["write_file"; "/new"; "\n\n\n"; "0"];
1260 ["cat"; "/new"]], "\n\n\n");
1261 InitBasicFS, Always, TestOutput (
1262 [["write_file"; "/new"; "\n"; "0"];
1263 ["cat"; "/new"]], "\n")],
1266 This call creates a file called C<path>. The contents of the
1267 file is the string C<content> (which can contain any 8 bit data),
1268 with length C<size>.
1270 As a special case, if C<size> is C<0>
1271 then the length is calculated using C<strlen> (so in this case
1272 the content cannot contain embedded ASCII NULs).
1274 I<NB.> Owing to a bug, writing content containing ASCII NUL
1275 characters does I<not> work, even if the length is specified.
1276 We hope to resolve this bug in a future version. In the meantime
1277 use C<guestfs_upload>.");
1279 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1280 [InitEmpty, Always, TestOutputListOfDevices (
1281 [["sfdiskM"; "/dev/sda"; ","];
1282 ["mkfs"; "ext2"; "/dev/sda1"];
1283 ["mount"; "/dev/sda1"; "/"];
1284 ["mounts"]], ["/dev/sda1"]);
1285 InitEmpty, Always, TestOutputList (
1286 [["sfdiskM"; "/dev/sda"; ","];
1287 ["mkfs"; "ext2"; "/dev/sda1"];
1288 ["mount"; "/dev/sda1"; "/"];
1291 "unmount a filesystem",
1293 This unmounts the given filesystem. The filesystem may be
1294 specified either by its mountpoint (path) or the device which
1295 contains the filesystem.");
1297 ("mounts", (RStringList "devices", []), 46, [],
1298 [InitBasicFS, Always, TestOutputListOfDevices (
1299 [["mounts"]], ["/dev/sda1"])],
1300 "show mounted filesystems",
1302 This returns the list of currently mounted filesystems. It returns
1303 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1305 Some internal mounts are not shown.");
1307 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1308 [InitBasicFS, Always, TestOutputList (
1311 (* check that umount_all can unmount nested mounts correctly: *)
1312 InitEmpty, Always, TestOutputList (
1313 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1314 ["mkfs"; "ext2"; "/dev/sda1"];
1315 ["mkfs"; "ext2"; "/dev/sda2"];
1316 ["mkfs"; "ext2"; "/dev/sda3"];
1317 ["mount"; "/dev/sda1"; "/"];
1319 ["mount"; "/dev/sda2"; "/mp1"];
1320 ["mkdir"; "/mp1/mp2"];
1321 ["mount"; "/dev/sda3"; "/mp1/mp2"];
1322 ["mkdir"; "/mp1/mp2/mp3"];
1325 "unmount all filesystems",
1327 This unmounts all mounted filesystems.
1329 Some internal mounts are not unmounted by this call.");
1331 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1333 "remove all LVM LVs, VGs and PVs",
1335 This command removes all LVM logical volumes, volume groups
1336 and physical volumes.");
1338 ("file", (RString "description", [String "path"]), 49, [],
1339 [InitBasicFS, Always, TestOutput (
1341 ["file"; "/new"]], "empty");
1342 InitBasicFS, Always, TestOutput (
1343 [["write_file"; "/new"; "some content\n"; "0"];
1344 ["file"; "/new"]], "ASCII text");
1345 InitBasicFS, Always, TestLastFail (
1346 [["file"; "/nofile"]])],
1347 "determine file type",
1349 This call uses the standard L<file(1)> command to determine
1350 the type or contents of the file. This also works on devices,
1351 for example to find out whether a partition contains a filesystem.
1353 The exact command which runs is C<file -bsL path>. Note in
1354 particular that the filename is not prepended to the output
1355 (the C<-b> option).");
1357 ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1358 [InitBasicFS, Always, TestOutput (
1359 [["upload"; "test-command"; "/test-command"];
1360 ["chmod"; "0o755"; "/test-command"];
1361 ["command"; "/test-command 1"]], "Result1");
1362 InitBasicFS, Always, TestOutput (
1363 [["upload"; "test-command"; "/test-command"];
1364 ["chmod"; "0o755"; "/test-command"];
1365 ["command"; "/test-command 2"]], "Result2\n");
1366 InitBasicFS, Always, TestOutput (
1367 [["upload"; "test-command"; "/test-command"];
1368 ["chmod"; "0o755"; "/test-command"];
1369 ["command"; "/test-command 3"]], "\nResult3");
1370 InitBasicFS, Always, TestOutput (
1371 [["upload"; "test-command"; "/test-command"];
1372 ["chmod"; "0o755"; "/test-command"];
1373 ["command"; "/test-command 4"]], "\nResult4\n");
1374 InitBasicFS, Always, TestOutput (
1375 [["upload"; "test-command"; "/test-command"];
1376 ["chmod"; "0o755"; "/test-command"];
1377 ["command"; "/test-command 5"]], "\nResult5\n\n");
1378 InitBasicFS, Always, TestOutput (
1379 [["upload"; "test-command"; "/test-command"];
1380 ["chmod"; "0o755"; "/test-command"];
1381 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1382 InitBasicFS, Always, TestOutput (
1383 [["upload"; "test-command"; "/test-command"];
1384 ["chmod"; "0o755"; "/test-command"];
1385 ["command"; "/test-command 7"]], "");
1386 InitBasicFS, Always, TestOutput (
1387 [["upload"; "test-command"; "/test-command"];
1388 ["chmod"; "0o755"; "/test-command"];
1389 ["command"; "/test-command 8"]], "\n");
1390 InitBasicFS, Always, TestOutput (
1391 [["upload"; "test-command"; "/test-command"];
1392 ["chmod"; "0o755"; "/test-command"];
1393 ["command"; "/test-command 9"]], "\n\n");
1394 InitBasicFS, Always, TestOutput (
1395 [["upload"; "test-command"; "/test-command"];
1396 ["chmod"; "0o755"; "/test-command"];
1397 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1398 InitBasicFS, Always, TestOutput (
1399 [["upload"; "test-command"; "/test-command"];
1400 ["chmod"; "0o755"; "/test-command"];
1401 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1402 InitBasicFS, Always, TestLastFail (
1403 [["upload"; "test-command"; "/test-command"];
1404 ["chmod"; "0o755"; "/test-command"];
1405 ["command"; "/test-command"]])],
1406 "run a command from the guest filesystem",
1408 This call runs a command from the guest filesystem. The
1409 filesystem must be mounted, and must contain a compatible
1410 operating system (ie. something Linux, with the same
1411 or compatible processor architecture).
1413 The single parameter is an argv-style list of arguments.
1414 The first element is the name of the program to run.
1415 Subsequent elements are parameters. The list must be
1416 non-empty (ie. must contain a program name). Note that
1417 the command runs directly, and is I<not> invoked via
1418 the shell (see C<guestfs_sh>).
1420 The return value is anything printed to I<stdout> by
1423 If the command returns a non-zero exit status, then
1424 this function returns an error message. The error message
1425 string is the content of I<stderr> from the command.
1427 The C<$PATH> environment variable will contain at least
1428 C</usr/bin> and C</bin>. If you require a program from
1429 another location, you should provide the full path in the
1432 Shared libraries and data files required by the program
1433 must be available on filesystems which are mounted in the
1434 correct places. It is the caller's responsibility to ensure
1435 all filesystems that are needed are mounted at the right
1438 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1439 [InitBasicFS, Always, TestOutputList (
1440 [["upload"; "test-command"; "/test-command"];
1441 ["chmod"; "0o755"; "/test-command"];
1442 ["command_lines"; "/test-command 1"]], ["Result1"]);
1443 InitBasicFS, Always, TestOutputList (
1444 [["upload"; "test-command"; "/test-command"];
1445 ["chmod"; "0o755"; "/test-command"];
1446 ["command_lines"; "/test-command 2"]], ["Result2"]);
1447 InitBasicFS, Always, TestOutputList (
1448 [["upload"; "test-command"; "/test-command"];
1449 ["chmod"; "0o755"; "/test-command"];
1450 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1451 InitBasicFS, Always, TestOutputList (
1452 [["upload"; "test-command"; "/test-command"];
1453 ["chmod"; "0o755"; "/test-command"];
1454 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1455 InitBasicFS, Always, TestOutputList (
1456 [["upload"; "test-command"; "/test-command"];
1457 ["chmod"; "0o755"; "/test-command"];
1458 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1459 InitBasicFS, Always, TestOutputList (
1460 [["upload"; "test-command"; "/test-command"];
1461 ["chmod"; "0o755"; "/test-command"];
1462 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1463 InitBasicFS, Always, TestOutputList (
1464 [["upload"; "test-command"; "/test-command"];
1465 ["chmod"; "0o755"; "/test-command"];
1466 ["command_lines"; "/test-command 7"]], []);
1467 InitBasicFS, Always, TestOutputList (
1468 [["upload"; "test-command"; "/test-command"];
1469 ["chmod"; "0o755"; "/test-command"];
1470 ["command_lines"; "/test-command 8"]], [""]);
1471 InitBasicFS, Always, TestOutputList (
1472 [["upload"; "test-command"; "/test-command"];
1473 ["chmod"; "0o755"; "/test-command"];
1474 ["command_lines"; "/test-command 9"]], ["";""]);
1475 InitBasicFS, Always, TestOutputList (
1476 [["upload"; "test-command"; "/test-command"];
1477 ["chmod"; "0o755"; "/test-command"];
1478 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1479 InitBasicFS, Always, TestOutputList (
1480 [["upload"; "test-command"; "/test-command"];
1481 ["chmod"; "0o755"; "/test-command"];
1482 ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1483 "run a command, returning lines",
1485 This is the same as C<guestfs_command>, but splits the
1486 result into a list of lines.
1488 See also: C<guestfs_sh_lines>");
1490 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1491 [InitBasicFS, Always, TestOutputStruct (
1493 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1494 "get file information",
1496 Returns file information for the given C<path>.
1498 This is the same as the C<stat(2)> system call.");
1500 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1501 [InitBasicFS, Always, TestOutputStruct (
1503 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1504 "get file information for a symbolic link",
1506 Returns file information for the given C<path>.
1508 This is the same as C<guestfs_stat> except that if C<path>
1509 is a symbolic link, then the link is stat-ed, not the file it
1512 This is the same as the C<lstat(2)> system call.");
1514 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1515 [InitBasicFS, Always, TestOutputStruct (
1516 [["statvfs"; "/"]], [CompareWithInt ("namemax", 255);
1517 CompareWithInt ("bsize", 1024)])],
1518 "get file system statistics",
1520 Returns file system statistics for any mounted file system.
1521 C<path> should be a file or directory in the mounted file system
1522 (typically it is the mount point itself, but it doesn't need to be).
1524 This is the same as the C<statvfs(2)> system call.");
1526 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1528 "get ext2/ext3/ext4 superblock details",
1530 This returns the contents of the ext2, ext3 or ext4 filesystem
1531 superblock on C<device>.
1533 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1534 manpage for more details. The list of fields returned isn't
1535 clearly defined, and depends on both the version of C<tune2fs>
1536 that libguestfs was built against, and the filesystem itself.");
1538 ("blockdev_setro", (RErr, [String "device"]), 56, [],
1539 [InitEmpty, Always, TestOutputTrue (
1540 [["blockdev_setro"; "/dev/sda"];
1541 ["blockdev_getro"; "/dev/sda"]])],
1542 "set block device to read-only",
1544 Sets the block device named C<device> to read-only.
1546 This uses the L<blockdev(8)> command.");
1548 ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1549 [InitEmpty, Always, TestOutputFalse (
1550 [["blockdev_setrw"; "/dev/sda"];
1551 ["blockdev_getro"; "/dev/sda"]])],
1552 "set block device to read-write",
1554 Sets the block device named C<device> to read-write.
1556 This uses the L<blockdev(8)> command.");
1558 ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1559 [InitEmpty, Always, TestOutputTrue (
1560 [["blockdev_setro"; "/dev/sda"];
1561 ["blockdev_getro"; "/dev/sda"]])],
1562 "is block device set to read-only",
1564 Returns a boolean indicating if the block device is read-only
1565 (true if read-only, false if not).
1567 This uses the L<blockdev(8)> command.");
1569 ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1570 [InitEmpty, Always, TestOutputInt (
1571 [["blockdev_getss"; "/dev/sda"]], 512)],
1572 "get sectorsize of block device",
1574 This returns the size of sectors on a block device.
1575 Usually 512, but can be larger for modern devices.
1577 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1580 This uses the L<blockdev(8)> command.");
1582 ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1583 [InitEmpty, Always, TestOutputInt (
1584 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1585 "get blocksize of block device",
1587 This returns the block size of a device.
1589 (Note this is different from both I<size in blocks> and
1590 I<filesystem block size>).
1592 This uses the L<blockdev(8)> command.");
1594 ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1596 "set blocksize of block device",
1598 This sets the block size of a device.
1600 (Note this is different from both I<size in blocks> and
1601 I<filesystem block size>).
1603 This uses the L<blockdev(8)> command.");
1605 ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1606 [InitEmpty, Always, TestOutputInt (
1607 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1608 "get total size of device in 512-byte sectors",
1610 This returns the size of the device in units of 512-byte sectors
1611 (even if the sectorsize isn't 512 bytes ... weird).
1613 See also C<guestfs_blockdev_getss> for the real sector size of
1614 the device, and C<guestfs_blockdev_getsize64> for the more
1615 useful I<size in bytes>.
1617 This uses the L<blockdev(8)> command.");
1619 ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1620 [InitEmpty, Always, TestOutputInt (
1621 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1622 "get total size of device in bytes",
1624 This returns the size of the device in bytes.
1626 See also C<guestfs_blockdev_getsz>.
1628 This uses the L<blockdev(8)> command.");
1630 ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1631 [InitEmpty, Always, TestRun
1632 [["blockdev_flushbufs"; "/dev/sda"]]],
1633 "flush device buffers",
1635 This tells the kernel to flush internal buffers associated
1638 This uses the L<blockdev(8)> command.");
1640 ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1641 [InitEmpty, Always, TestRun
1642 [["blockdev_rereadpt"; "/dev/sda"]]],
1643 "reread partition table",
1645 Reread the partition table on C<device>.
1647 This uses the L<blockdev(8)> command.");
1649 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1650 [InitBasicFS, Always, TestOutput (
1651 (* Pick a file from cwd which isn't likely to change. *)
1652 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1653 ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1654 "upload a file from the local machine",
1656 Upload local file C<filename> to C<remotefilename> on the
1659 C<filename> can also be a named pipe.
1661 See also C<guestfs_download>.");
1663 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1664 [InitBasicFS, Always, TestOutput (
1665 (* Pick a file from cwd which isn't likely to change. *)
1666 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1667 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1668 ["upload"; "testdownload.tmp"; "/upload"];
1669 ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1670 "download a file to the local machine",
1672 Download file C<remotefilename> and save it as C<filename>
1673 on the local machine.
1675 C<filename> can also be a named pipe.
1677 See also C<guestfs_upload>, C<guestfs_cat>.");
1679 ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1680 [InitBasicFS, Always, TestOutput (
1681 [["write_file"; "/new"; "test\n"; "0"];
1682 ["checksum"; "crc"; "/new"]], "935282863");
1683 InitBasicFS, Always, TestLastFail (
1684 [["checksum"; "crc"; "/new"]]);
1685 InitBasicFS, Always, TestOutput (
1686 [["write_file"; "/new"; "test\n"; "0"];
1687 ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1688 InitBasicFS, Always, TestOutput (
1689 [["write_file"; "/new"; "test\n"; "0"];
1690 ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1691 InitBasicFS, Always, TestOutput (
1692 [["write_file"; "/new"; "test\n"; "0"];
1693 ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1694 InitBasicFS, Always, TestOutput (
1695 [["write_file"; "/new"; "test\n"; "0"];
1696 ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1697 InitBasicFS, Always, TestOutput (
1698 [["write_file"; "/new"; "test\n"; "0"];
1699 ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1700 InitBasicFS, Always, TestOutput (
1701 [["write_file"; "/new"; "test\n"; "0"];
1702 ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
1703 InitBasicFS, Always, TestOutput (
1704 (* RHEL 5 thinks this is an HFS+ filesystem unless we give
1705 * the type explicitly.
1707 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
1708 ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
1709 "compute MD5, SHAx or CRC checksum of file",
1711 This call computes the MD5, SHAx or CRC checksum of the
1714 The type of checksum to compute is given by the C<csumtype>
1715 parameter which must have one of the following values:
1721 Compute the cyclic redundancy check (CRC) specified by POSIX
1722 for the C<cksum> command.
1726 Compute the MD5 hash (using the C<md5sum> program).
1730 Compute the SHA1 hash (using the C<sha1sum> program).
1734 Compute the SHA224 hash (using the C<sha224sum> program).
1738 Compute the SHA256 hash (using the C<sha256sum> program).
1742 Compute the SHA384 hash (using the C<sha384sum> program).
1746 Compute the SHA512 hash (using the C<sha512sum> program).
1750 The checksum is returned as a printable string.");
1752 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1753 [InitBasicFS, Always, TestOutput (
1754 [["tar_in"; "../images/helloworld.tar"; "/"];
1755 ["cat"; "/hello"]], "hello\n")],
1756 "unpack tarfile to directory",
1758 This command uploads and unpacks local file C<tarfile> (an
1759 I<uncompressed> tar file) into C<directory>.
1761 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1763 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1765 "pack directory into tarfile",
1767 This command packs the contents of C<directory> and downloads
1768 it to local file C<tarfile>.
1770 To download a compressed tarball, use C<guestfs_tgz_out>.");
1772 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1773 [InitBasicFS, Always, TestOutput (
1774 [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1775 ["cat"; "/hello"]], "hello\n")],
1776 "unpack compressed tarball to directory",
1778 This command uploads and unpacks local file C<tarball> (a
1779 I<gzip compressed> tar file) into C<directory>.
1781 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1783 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1785 "pack directory into compressed tarball",
1787 This command packs the contents of C<directory> and downloads
1788 it to local file C<tarball>.
1790 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1792 ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1793 [InitBasicFS, Always, TestLastFail (
1795 ["mount_ro"; "/dev/sda1"; "/"];
1796 ["touch"; "/new"]]);
1797 InitBasicFS, Always, TestOutput (
1798 [["write_file"; "/new"; "data"; "0"];
1800 ["mount_ro"; "/dev/sda1"; "/"];
1801 ["cat"; "/new"]], "data")],
1802 "mount a guest disk, read-only",
1804 This is the same as the C<guestfs_mount> command, but it
1805 mounts the filesystem with the read-only (I<-o ro>) flag.");
1807 ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1809 "mount a guest disk with mount options",
1811 This is the same as the C<guestfs_mount> command, but it
1812 allows you to set the mount options as for the
1813 L<mount(8)> I<-o> flag.");
1815 ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1817 "mount a guest disk with mount options and vfstype",
1819 This is the same as the C<guestfs_mount> command, but it
1820 allows you to set both the mount options and the vfstype
1821 as for the L<mount(8)> I<-o> and I<-t> flags.");
1823 ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1825 "debugging and internals",
1827 The C<guestfs_debug> command exposes some internals of
1828 C<guestfsd> (the guestfs daemon) that runs inside the
1831 There is no comprehensive help for this command. You have
1832 to look at the file C<daemon/debug.c> in the libguestfs source
1833 to find out what you can do.");
1835 ("lvremove", (RErr, [String "device"]), 77, [],
1836 [InitEmpty, Always, TestOutputList (
1837 [["sfdiskM"; "/dev/sda"; ","];
1838 ["pvcreate"; "/dev/sda1"];
1839 ["vgcreate"; "VG"; "/dev/sda1"];
1840 ["lvcreate"; "LV1"; "VG"; "50"];
1841 ["lvcreate"; "LV2"; "VG"; "50"];
1842 ["lvremove"; "/dev/VG/LV1"];
1843 ["lvs"]], ["/dev/VG/LV2"]);
1844 InitEmpty, Always, TestOutputList (
1845 [["sfdiskM"; "/dev/sda"; ","];
1846 ["pvcreate"; "/dev/sda1"];
1847 ["vgcreate"; "VG"; "/dev/sda1"];
1848 ["lvcreate"; "LV1"; "VG"; "50"];
1849 ["lvcreate"; "LV2"; "VG"; "50"];
1850 ["lvremove"; "/dev/VG"];
1852 InitEmpty, Always, TestOutputList (
1853 [["sfdiskM"; "/dev/sda"; ","];
1854 ["pvcreate"; "/dev/sda1"];
1855 ["vgcreate"; "VG"; "/dev/sda1"];
1856 ["lvcreate"; "LV1"; "VG"; "50"];
1857 ["lvcreate"; "LV2"; "VG"; "50"];
1858 ["lvremove"; "/dev/VG"];
1860 "remove an LVM logical volume",
1862 Remove an LVM logical volume C<device>, where C<device> is
1863 the path to the LV, such as C</dev/VG/LV>.
1865 You can also remove all LVs in a volume group by specifying
1866 the VG name, C</dev/VG>.");
1868 ("vgremove", (RErr, [String "vgname"]), 78, [],
1869 [InitEmpty, Always, TestOutputList (
1870 [["sfdiskM"; "/dev/sda"; ","];
1871 ["pvcreate"; "/dev/sda1"];
1872 ["vgcreate"; "VG"; "/dev/sda1"];
1873 ["lvcreate"; "LV1"; "VG"; "50"];
1874 ["lvcreate"; "LV2"; "VG"; "50"];
1877 InitEmpty, Always, TestOutputList (
1878 [["sfdiskM"; "/dev/sda"; ","];
1879 ["pvcreate"; "/dev/sda1"];
1880 ["vgcreate"; "VG"; "/dev/sda1"];
1881 ["lvcreate"; "LV1"; "VG"; "50"];
1882 ["lvcreate"; "LV2"; "VG"; "50"];
1885 "remove an LVM volume group",
1887 Remove an LVM volume group C<vgname>, (for example C<VG>).
1889 This also forcibly removes all logical volumes in the volume
1892 ("pvremove", (RErr, [String "device"]), 79, [],
1893 [InitEmpty, Always, TestOutputListOfDevices (
1894 [["sfdiskM"; "/dev/sda"; ","];
1895 ["pvcreate"; "/dev/sda1"];
1896 ["vgcreate"; "VG"; "/dev/sda1"];
1897 ["lvcreate"; "LV1"; "VG"; "50"];
1898 ["lvcreate"; "LV2"; "VG"; "50"];
1900 ["pvremove"; "/dev/sda1"];
1902 InitEmpty, Always, TestOutputListOfDevices (
1903 [["sfdiskM"; "/dev/sda"; ","];
1904 ["pvcreate"; "/dev/sda1"];
1905 ["vgcreate"; "VG"; "/dev/sda1"];
1906 ["lvcreate"; "LV1"; "VG"; "50"];
1907 ["lvcreate"; "LV2"; "VG"; "50"];
1909 ["pvremove"; "/dev/sda1"];
1911 InitEmpty, Always, TestOutputListOfDevices (
1912 [["sfdiskM"; "/dev/sda"; ","];
1913 ["pvcreate"; "/dev/sda1"];
1914 ["vgcreate"; "VG"; "/dev/sda1"];
1915 ["lvcreate"; "LV1"; "VG"; "50"];
1916 ["lvcreate"; "LV2"; "VG"; "50"];
1918 ["pvremove"; "/dev/sda1"];
1920 "remove an LVM physical volume",
1922 This wipes a physical volume C<device> so that LVM will no longer
1925 The implementation uses the C<pvremove> command which refuses to
1926 wipe physical volumes that contain any volume groups, so you have
1927 to remove those first.");
1929 ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
1930 [InitBasicFS, Always, TestOutput (
1931 [["set_e2label"; "/dev/sda1"; "testlabel"];
1932 ["get_e2label"; "/dev/sda1"]], "testlabel")],
1933 "set the ext2/3/4 filesystem label",
1935 This sets the ext2/3/4 filesystem label of the filesystem on
1936 C<device> to C<label>. Filesystem labels are limited to
1939 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
1940 to return the existing label on a filesystem.");
1942 ("get_e2label", (RString "label", [String "device"]), 81, [],
1944 "get the ext2/3/4 filesystem label",
1946 This returns the ext2/3/4 filesystem label of the filesystem on
1949 ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
1950 [InitBasicFS, Always, TestOutput (
1951 [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
1952 ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
1953 InitBasicFS, Always, TestOutput (
1954 [["set_e2uuid"; "/dev/sda1"; "clear"];
1955 ["get_e2uuid"; "/dev/sda1"]], "");
1956 (* We can't predict what UUIDs will be, so just check the commands run. *)
1957 InitBasicFS, Always, TestRun (
1958 [["set_e2uuid"; "/dev/sda1"; "random"]]);
1959 InitBasicFS, Always, TestRun (
1960 [["set_e2uuid"; "/dev/sda1"; "time"]])],
1961 "set the ext2/3/4 filesystem UUID",
1963 This sets the ext2/3/4 filesystem UUID of the filesystem on
1964 C<device> to C<uuid>. The format of the UUID and alternatives
1965 such as C<clear>, C<random> and C<time> are described in the
1966 L<tune2fs(8)> manpage.
1968 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
1969 to return the existing UUID of a filesystem.");
1971 ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
1973 "get the ext2/3/4 filesystem UUID",
1975 This returns the ext2/3/4 filesystem UUID of the filesystem on
1978 ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
1979 [InitBasicFS, Always, TestOutputInt (
1980 [["umount"; "/dev/sda1"];
1981 ["fsck"; "ext2"; "/dev/sda1"]], 0);
1982 InitBasicFS, Always, TestOutputInt (
1983 [["umount"; "/dev/sda1"];
1984 ["zero"; "/dev/sda1"];
1985 ["fsck"; "ext2"; "/dev/sda1"]], 8)],
1986 "run the filesystem checker",
1988 This runs the filesystem checker (fsck) on C<device> which
1989 should have filesystem type C<fstype>.
1991 The returned integer is the status. See L<fsck(8)> for the
1992 list of status codes from C<fsck>.
2000 Multiple status codes can be summed together.
2004 A non-zero return code can mean \"success\", for example if
2005 errors have been corrected on the filesystem.
2009 Checking or repairing NTFS volumes is not supported
2014 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2016 ("zero", (RErr, [String "device"]), 85, [],
2017 [InitBasicFS, Always, TestOutput (
2018 [["umount"; "/dev/sda1"];
2019 ["zero"; "/dev/sda1"];
2020 ["file"; "/dev/sda1"]], "data")],
2021 "write zeroes to the device",
2023 This command writes zeroes over the first few blocks of C<device>.
2025 How many blocks are zeroed isn't specified (but it's I<not> enough
2026 to securely wipe the device). It should be sufficient to remove
2027 any partition tables, filesystem superblocks and so on.
2029 See also: C<guestfs_scrub_device>.");
2031 ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
2032 (* Test disabled because grub-install incompatible with virtio-blk driver.
2033 * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2035 [InitBasicFS, Disabled, TestOutputTrue (
2036 [["grub_install"; "/"; "/dev/sda1"];
2037 ["is_dir"; "/boot"]])],
2040 This command installs GRUB (the Grand Unified Bootloader) on
2041 C<device>, with the root directory being C<root>.");
2043 ("cp", (RErr, [String "src"; String "dest"]), 87, [],
2044 [InitBasicFS, Always, TestOutput (
2045 [["write_file"; "/old"; "file content"; "0"];
2046 ["cp"; "/old"; "/new"];
2047 ["cat"; "/new"]], "file content");
2048 InitBasicFS, Always, TestOutputTrue (
2049 [["write_file"; "/old"; "file content"; "0"];
2050 ["cp"; "/old"; "/new"];
2051 ["is_file"; "/old"]]);
2052 InitBasicFS, Always, TestOutput (
2053 [["write_file"; "/old"; "file content"; "0"];
2055 ["cp"; "/old"; "/dir/new"];
2056 ["cat"; "/dir/new"]], "file content")],
2059 This copies a file from C<src> to C<dest> where C<dest> is
2060 either a destination filename or destination directory.");
2062 ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2063 [InitBasicFS, Always, TestOutput (
2064 [["mkdir"; "/olddir"];
2065 ["mkdir"; "/newdir"];
2066 ["write_file"; "/olddir/file"; "file content"; "0"];
2067 ["cp_a"; "/olddir"; "/newdir"];
2068 ["cat"; "/newdir/olddir/file"]], "file content")],
2069 "copy a file or directory recursively",
2071 This copies a file or directory from C<src> to C<dest>
2072 recursively using the C<cp -a> command.");
2074 ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2075 [InitBasicFS, Always, TestOutput (
2076 [["write_file"; "/old"; "file content"; "0"];
2077 ["mv"; "/old"; "/new"];
2078 ["cat"; "/new"]], "file content");
2079 InitBasicFS, Always, TestOutputFalse (
2080 [["write_file"; "/old"; "file content"; "0"];
2081 ["mv"; "/old"; "/new"];
2082 ["is_file"; "/old"]])],
2085 This moves a file from C<src> to C<dest> where C<dest> is
2086 either a destination filename or destination directory.");
2088 ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2089 [InitEmpty, Always, TestRun (
2090 [["drop_caches"; "3"]])],
2091 "drop kernel page cache, dentries and inodes",
2093 This instructs the guest kernel to drop its page cache,
2094 and/or dentries and inode caches. The parameter C<whattodrop>
2095 tells the kernel what precisely to drop, see
2096 L<http://linux-mm.org/Drop_Caches>
2098 Setting C<whattodrop> to 3 should drop everything.
2100 This automatically calls L<sync(2)> before the operation,
2101 so that the maximum guest memory is freed.");
2103 ("dmesg", (RString "kmsgs", []), 91, [],
2104 [InitEmpty, Always, TestRun (
2106 "return kernel messages",
2108 This returns the kernel messages (C<dmesg> output) from
2109 the guest kernel. This is sometimes useful for extended
2110 debugging of problems.
2112 Another way to get the same information is to enable
2113 verbose messages with C<guestfs_set_verbose> or by setting
2114 the environment variable C<LIBGUESTFS_DEBUG=1> before
2115 running the program.");
2117 ("ping_daemon", (RErr, []), 92, [],
2118 [InitEmpty, Always, TestRun (
2119 [["ping_daemon"]])],
2120 "ping the guest daemon",
2122 This is a test probe into the guestfs daemon running inside
2123 the qemu subprocess. Calling this function checks that the
2124 daemon responds to the ping message, without affecting the daemon
2125 or attached block device(s) in any other way.");
2127 ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2128 [InitBasicFS, Always, TestOutputTrue (
2129 [["write_file"; "/file1"; "contents of a file"; "0"];
2130 ["cp"; "/file1"; "/file2"];
2131 ["equal"; "/file1"; "/file2"]]);
2132 InitBasicFS, Always, TestOutputFalse (
2133 [["write_file"; "/file1"; "contents of a file"; "0"];
2134 ["write_file"; "/file2"; "contents of another file"; "0"];
2135 ["equal"; "/file1"; "/file2"]]);
2136 InitBasicFS, Always, TestLastFail (
2137 [["equal"; "/file1"; "/file2"]])],
2138 "test if two files have equal contents",
2140 This compares the two files C<file1> and C<file2> and returns
2141 true if their content is exactly equal, or false otherwise.
2143 The external L<cmp(1)> program is used for the comparison.");
2145 ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2146 [InitBasicFS, Always, TestOutputList (
2147 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2148 ["strings"; "/new"]], ["hello"; "world"]);
2149 InitBasicFS, Always, TestOutputList (
2151 ["strings"; "/new"]], [])],
2152 "print the printable strings in a file",
2154 This runs the L<strings(1)> command on a file and returns
2155 the list of printable strings found.");
2157 ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2158 [InitBasicFS, Always, TestOutputList (
2159 [["write_file"; "/new"; "hello\nworld\n"; "0"];
2160 ["strings_e"; "b"; "/new"]], []);
2161 InitBasicFS, Disabled, TestOutputList (
2162 [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2163 ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2164 "print the printable strings in a file",
2166 This is like the C<guestfs_strings> command, but allows you to
2167 specify the encoding.
2169 See the L<strings(1)> manpage for the full list of encodings.
2171 Commonly useful encodings are C<l> (lower case L) which will
2172 show strings inside Windows/x86 files.
2174 The returned strings are transcoded to UTF-8.");
2176 ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2177 [InitBasicFS, Always, TestOutput (
2178 [["write_file"; "/new"; "hello\nworld\n"; "12"];
2179 ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n");
2180 (* Test for RHBZ#501888c2 regression which caused large hexdump
2181 * commands to segfault.
2183 InitBasicFS, Always, TestRun (
2184 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2185 ["hexdump"; "/100krandom"]])],
2186 "dump a file in hexadecimal",
2188 This runs C<hexdump -C> on the given C<path>. The result is
2189 the human-readable, canonical hex dump of the file.");
2191 ("zerofree", (RErr, [String "device"]), 97, [],
2192 [InitNone, Always, TestOutput (
2193 [["sfdiskM"; "/dev/sda"; ","];
2194 ["mkfs"; "ext3"; "/dev/sda1"];
2195 ["mount"; "/dev/sda1"; "/"];
2196 ["write_file"; "/new"; "test file"; "0"];
2197 ["umount"; "/dev/sda1"];
2198 ["zerofree"; "/dev/sda1"];
2199 ["mount"; "/dev/sda1"; "/"];
2200 ["cat"; "/new"]], "test file")],
2201 "zero unused inodes and disk blocks on ext2/3 filesystem",
2203 This runs the I<zerofree> program on C<device>. This program
2204 claims to zero unused inodes and disk blocks on an ext2/3
2205 filesystem, thus making it possible to compress the filesystem
2208 You should B<not> run this program if the filesystem is
2211 It is possible that using this program can damage the filesystem
2212 or data on the filesystem.");
2214 ("pvresize", (RErr, [String "device"]), 98, [],
2216 "resize an LVM physical volume",
2218 This resizes (expands or shrinks) an existing LVM physical
2219 volume to match the new size of the underlying device.");
2221 ("sfdisk_N", (RErr, [String "device"; Int "partnum";
2222 Int "cyls"; Int "heads"; Int "sectors";
2223 String "line"]), 99, [DangerWillRobinson],
2225 "modify a single partition on a block device",
2227 This runs L<sfdisk(8)> option to modify just the single
2228 partition C<n> (note: C<n> counts from 1).
2230 For other parameters, see C<guestfs_sfdisk>. You should usually
2231 pass C<0> for the cyls/heads/sectors parameters.");
2233 ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2235 "display the partition table",
2237 This displays the partition table on C<device>, in the
2238 human-readable output of the L<sfdisk(8)> command. It is
2239 not intended to be parsed.");
2241 ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2243 "display the kernel geometry",
2245 This displays the kernel's idea of the geometry of C<device>.
2247 The result is in human-readable format, and not designed to
2250 ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2252 "display the disk geometry from the partition table",
2254 This displays the disk geometry of C<device> read from the
2255 partition table. Especially in the case where the underlying
2256 block device has been resized, this can be different from the
2257 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2259 The result is in human-readable format, and not designed to
2262 ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2264 "activate or deactivate all volume groups",
2266 This command activates or (if C<activate> is false) deactivates
2267 all logical volumes in all volume groups.
2268 If activated, then they are made known to the
2269 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2270 then those devices disappear.
2272 This command is the same as running C<vgchange -a y|n>");
2274 ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2276 "activate or deactivate some volume groups",
2278 This command activates or (if C<activate> is false) deactivates
2279 all logical volumes in the listed volume groups C<volgroups>.
2280 If activated, then they are made known to the
2281 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2282 then those devices disappear.
2284 This command is the same as running C<vgchange -a y|n volgroups...>
2286 Note that if C<volgroups> is an empty list then B<all> volume groups
2287 are activated or deactivated.");
2289 ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2290 [InitNone, Always, TestOutput (
2291 [["sfdiskM"; "/dev/sda"; ","];
2292 ["pvcreate"; "/dev/sda1"];
2293 ["vgcreate"; "VG"; "/dev/sda1"];
2294 ["lvcreate"; "LV"; "VG"; "10"];
2295 ["mkfs"; "ext2"; "/dev/VG/LV"];
2296 ["mount"; "/dev/VG/LV"; "/"];
2297 ["write_file"; "/new"; "test content"; "0"];
2299 ["lvresize"; "/dev/VG/LV"; "20"];
2300 ["e2fsck_f"; "/dev/VG/LV"];
2301 ["resize2fs"; "/dev/VG/LV"];
2302 ["mount"; "/dev/VG/LV"; "/"];
2303 ["cat"; "/new"]], "test content")],
2304 "resize an LVM logical volume",
2306 This resizes (expands or shrinks) an existing LVM logical
2307 volume to C<mbytes>. When reducing, data in the reduced part
2310 ("resize2fs", (RErr, [String "device"]), 106, [],
2311 [], (* lvresize tests this *)
2312 "resize an ext2/ext3 filesystem",
2314 This resizes an ext2 or ext3 filesystem to match the size of
2315 the underlying device.
2317 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2318 on the C<device> before calling this command. For unknown reasons
2319 C<resize2fs> sometimes gives an error about this and sometimes not.
2320 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2321 calling this function.");
2323 ("find", (RStringList "names", [String "directory"]), 107, [],
2324 [InitBasicFS, Always, TestOutputList (
2325 [["find"; "/"]], ["lost+found"]);
2326 InitBasicFS, Always, TestOutputList (
2330 ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2331 InitBasicFS, Always, TestOutputList (
2332 [["mkdir_p"; "/a/b/c"];
2333 ["touch"; "/a/b/c/d"];
2334 ["find"; "/a/b/"]], ["c"; "c/d"])],
2335 "find all files and directories",
2337 This command lists out all files and directories, recursively,
2338 starting at C<directory>. It is essentially equivalent to
2339 running the shell command C<find directory -print> but some
2340 post-processing happens on the output, described below.
2342 This returns a list of strings I<without any prefix>. Thus
2343 if the directory structure was:
2349 then the returned list from C<guestfs_find> C</tmp> would be
2357 If C<directory> is not a directory, then this command returns
2360 The returned list is sorted.");
2362 ("e2fsck_f", (RErr, [String "device"]), 108, [],
2363 [], (* lvresize tests this *)
2364 "check an ext2/ext3 filesystem",
2366 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2367 filesystem checker on C<device>, noninteractively (C<-p>),
2368 even if the filesystem appears to be clean (C<-f>).
2370 This command is only needed because of C<guestfs_resize2fs>
2371 (q.v.). Normally you should use C<guestfs_fsck>.");
2373 ("sleep", (RErr, [Int "secs"]), 109, [],
2374 [InitNone, Always, TestRun (
2376 "sleep for some seconds",
2378 Sleep for C<secs> seconds.");
2380 ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [],
2381 [InitNone, Always, TestOutputInt (
2382 [["sfdiskM"; "/dev/sda"; ","];
2383 ["mkfs"; "ntfs"; "/dev/sda1"];
2384 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2385 InitNone, Always, TestOutputInt (
2386 [["sfdiskM"; "/dev/sda"; ","];
2387 ["mkfs"; "ext2"; "/dev/sda1"];
2388 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2389 "probe NTFS volume",
2391 This command runs the L<ntfs-3g.probe(8)> command which probes
2392 an NTFS C<device> for mountability. (Not all NTFS volumes can
2393 be mounted read-write, and some cannot be mounted at all).
2395 C<rw> is a boolean flag. Set it to true if you want to test
2396 if the volume can be mounted read-write. Set it to false if
2397 you want to test if the volume can be mounted read-only.
2399 The return value is an integer which C<0> if the operation
2400 would succeed, or some non-zero value documented in the
2401 L<ntfs-3g.probe(8)> manual page.");
2403 ("sh", (RString "output", [String "command"]), 111, [],
2404 [], (* XXX needs tests *)
2405 "run a command via the shell",
2407 This call runs a command from the guest filesystem via the
2410 This is like C<guestfs_command>, but passes the command to:
2412 /bin/sh -c \"command\"
2414 Depending on the guest's shell, this usually results in
2415 wildcards being expanded, shell expressions being interpolated
2418 All the provisos about C<guestfs_command> apply to this call.");
2420 ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2421 [], (* XXX needs tests *)
2422 "run a command via the shell returning lines",
2424 This is the same as C<guestfs_sh>, but splits the result
2425 into a list of lines.
2427 See also: C<guestfs_command_lines>");
2429 ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [],
2430 [InitBasicFS, Always, TestOutputList (
2431 [["mkdir_p"; "/a/b/c"];
2432 ["touch"; "/a/b/c/d"];
2433 ["touch"; "/a/b/c/e"];
2434 ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2435 InitBasicFS, Always, TestOutputList (
2436 [["mkdir_p"; "/a/b/c"];
2437 ["touch"; "/a/b/c/d"];
2438 ["touch"; "/a/b/c/e"];
2439 ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2440 InitBasicFS, Always, TestOutputList (
2441 [["mkdir_p"; "/a/b/c"];
2442 ["touch"; "/a/b/c/d"];
2443 ["touch"; "/a/b/c/e"];
2444 ["glob_expand"; "/a/*/x/*"]], [])],
2445 "expand a wildcard path",
2447 This command searches for all the pathnames matching
2448 C<pattern> according to the wildcard expansion rules
2451 If no paths match, then this returns an empty list
2452 (note: not an error).
2454 It is just a wrapper around the C L<glob(3)> function
2455 with flags C<GLOB_MARK|GLOB_BRACE>.
2456 See that manual page for more details.");
2458 ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson],
2459 [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2460 [["scrub_device"; "/dev/sdc"]])],
2461 "scrub (securely wipe) a device",
2463 This command writes patterns over C<device> to make data retrieval
2466 It is an interface to the L<scrub(1)> program. See that
2467 manual page for more details.");
2469 ("scrub_file", (RErr, [String "file"]), 115, [],
2470 [InitBasicFS, Always, TestRun (
2471 [["write_file"; "/file"; "content"; "0"];
2472 ["scrub_file"; "/file"]])],
2473 "scrub (securely wipe) a file",
2475 This command writes patterns over a file to make data retrieval
2478 The file is I<removed> after scrubbing.
2480 It is an interface to the L<scrub(1)> program. See that
2481 manual page for more details.");
2483 ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2484 [], (* XXX needs testing *)
2485 "scrub (securely wipe) free space",
2487 This command creates the directory C<dir> and then fills it
2488 with files until the filesystem is full, and scrubs the files
2489 as for C<guestfs_scrub_file>, and deletes them.
2490 The intention is to scrub any free space on the partition
2493 It is an interface to the L<scrub(1)> program. See that
2494 manual page for more details.");
2496 ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2497 [InitBasicFS, Always, TestRun (
2499 ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2500 "create a temporary directory",
2502 This command creates a temporary directory. The
2503 C<template> parameter should be a full pathname for the
2504 temporary directory name with the final six characters being
2507 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2508 the second one being suitable for Windows filesystems.
2510 The name of the temporary directory that was created
2513 The temporary directory is created with mode 0700
2514 and is owned by root.
2516 The caller is responsible for deleting the temporary
2517 directory and its contents after use.
2519 See also: L<mkdtemp(3)>");
2521 ("wc_l", (RInt "lines", [String "path"]), 118, [],
2522 [InitBasicFS, Always, TestOutputInt (
2523 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2524 ["wc_l"; "/10klines"]], 10000)],
2525 "count lines in a file",
2527 This command counts the lines in a file, using the
2528 C<wc -l> external command.");
2530 ("wc_w", (RInt "words", [String "path"]), 119, [],
2531 [InitBasicFS, Always, TestOutputInt (
2532 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2533 ["wc_w"; "/10klines"]], 10000)],
2534 "count words in a file",
2536 This command counts the words in a file, using the
2537 C<wc -w> external command.");
2539 ("wc_c", (RInt "chars", [String "path"]), 120, [],
2540 [InitBasicFS, Always, TestOutputInt (
2541 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2542 ["wc_c"; "/100kallspaces"]], 102400)],
2543 "count characters in a file",
2545 This command counts the characters in a file, using the
2546 C<wc -c> external command.");
2548 ("head", (RStringList "lines", [String "path"]), 121, [ProtocolLimitWarning],
2549 [InitBasicFS, Always, TestOutputList (
2550 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2551 ["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2552 "return first 10 lines of a file",
2554 This command returns up to the first 10 lines of a file as
2555 a list of strings.");
2557 ("head_n", (RStringList "lines", [Int "nrlines"; String "path"]), 122, [ProtocolLimitWarning],
2558 [InitBasicFS, Always, TestOutputList (
2559 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2560 ["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2561 InitBasicFS, Always, TestOutputList (
2562 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2563 ["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2564 InitBasicFS, Always, TestOutputList (
2565 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2566 ["head_n"; "0"; "/10klines"]], [])],
2567 "return first N lines of a file",
2569 If the parameter C<nrlines> is a positive number, this returns the first
2570 C<nrlines> lines of the file C<path>.
2572 If the parameter C<nrlines> is a negative number, this returns lines
2573 from the file C<path>, excluding the last C<nrlines> lines.
2575 If the parameter C<nrlines> is zero, this returns an empty list.");
2577 ("tail", (RStringList "lines", [String "path"]), 123, [ProtocolLimitWarning],
2578 [InitBasicFS, Always, TestOutputList (
2579 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2580 ["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2581 "return last 10 lines of a file",
2583 This command returns up to the last 10 lines of a file as
2584 a list of strings.");
2586 ("tail_n", (RStringList "lines", [Int "nrlines"; String "path"]), 124, [ProtocolLimitWarning],
2587 [InitBasicFS, Always, TestOutputList (
2588 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2589 ["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2590 InitBasicFS, Always, TestOutputList (
2591 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2592 ["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2593 InitBasicFS, Always, TestOutputList (
2594 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2595 ["tail_n"; "0"; "/10klines"]], [])],
2596 "return last N lines of a file",
2598 If the parameter C<nrlines> is a positive number, this returns the last
2599 C<nrlines> lines of the file C<path>.
2601 If the parameter C<nrlines> is a negative number, this returns lines
2602 from the file C<path>, starting with the C<-nrlines>th line.
2604 If the parameter C<nrlines> is zero, this returns an empty list.");
2606 ("df", (RString "output", []), 125, [],
2607 [], (* XXX Tricky to test because it depends on the exact format
2608 * of the 'df' command and other imponderables.
2610 "report file system disk space usage",
2612 This command runs the C<df> command to report disk space used.
2614 This command is mostly useful for interactive sessions. It
2615 is I<not> intended that you try to parse the output string.
2616 Use C<statvfs> from programs.");
2618 ("df_h", (RString "output", []), 126, [],
2619 [], (* XXX Tricky to test because it depends on the exact format
2620 * of the 'df' command and other imponderables.
2622 "report file system disk space usage (human readable)",
2624 This command runs the C<df -h> command to report disk space used
2625 in human-readable format.
2627 This command is mostly useful for interactive sessions. It
2628 is I<not> intended that you try to parse the output string.
2629 Use C<statvfs> from programs.");
2631 ("du", (RInt64 "sizekb", [String "path"]), 127, [],
2632 [InitBasicFS, Always, TestOutputInt (
2634 ["du"; "/p"]], 1 (* ie. 1 block, so depends on ext3 blocksize *))],
2635 "estimate file space usage",
2637 This command runs the C<du -s> command to estimate file space
2640 C<path> can be a file or a directory. If C<path> is a directory
2641 then the estimate includes the contents of the directory and all
2642 subdirectories (recursively).
2644 The result is the estimated size in I<kilobytes>
2645 (ie. units of 1024 bytes).");
2647 ("initrd_list", (RStringList "filenames", [String "path"]), 128, [],
2648 [InitBasicFS, Always, TestOutputList (
2649 [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2650 ["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3"])],
2651 "list files in an initrd",
2653 This command lists out files contained in an initrd.
2655 The files are listed without any initial C</> character. The
2656 files are listed in the order they appear (not necessarily
2657 alphabetical). Directory names are listed as separate items.
2659 Old Linux kernels (2.4 and earlier) used a compressed ext2
2660 filesystem as initrd. We I<only> support the newer initramfs
2661 format (compressed cpio files).");
2663 ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
2665 "mount a file using the loop device",
2667 This command lets you mount C<file> (a filesystem image
2668 in a file) on a mount point. It is entirely equivalent to
2669 the command C<mount -o loop file mountpoint>.");
2671 ("mkswap", (RErr, [String "device"]), 130, [],
2672 [InitEmpty, Always, TestRun (
2673 [["sfdiskM"; "/dev/sda"; ","];
2674 ["mkswap"; "/dev/sda1"]])],
2675 "create a swap partition",
2677 Create a swap partition on C<device>.");
2679 ("mkswap_L", (RErr, [String "label"; String "device"]), 131, [],
2680 [InitEmpty, Always, TestRun (
2681 [["sfdiskM"; "/dev/sda"; ","];
2682 ["mkswap_L"; "hello"; "/dev/sda1"]])],
2683 "create a swap partition with a label",
2685 Create a swap partition on C<device> with label C<label>.");
2687 ("mkswap_U", (RErr, [String "uuid"; String "device"]), 132, [],
2688 [InitEmpty, Always, TestRun (
2689 [["sfdiskM"; "/dev/sda"; ","];
2690 ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
2691 "create a swap partition with an explicit UUID",
2693 Create a swap partition on C<device> with UUID C<uuid>.");
2695 ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 133, [],
2696 [InitBasicFS, Always, TestOutputStruct (
2697 [["mknod"; "0o10777"; "0"; "0"; "/node"];
2698 (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2699 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2700 InitBasicFS, Always, TestOutputStruct (
2701 [["mknod"; "0o60777"; "66"; "99"; "/node"];
2702 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2703 "make block, character or FIFO devices",
2705 This call creates block or character special devices, or
2706 named pipes (FIFOs).
2708 The C<mode> parameter should be the mode, using the standard
2709 constants. C<devmajor> and C<devminor> are the
2710 device major and minor numbers, only used when creating block
2711 and character special devices.");
2713 ("mkfifo", (RErr, [Int "mode"; String "path"]), 134, [],
2714 [InitBasicFS, Always, TestOutputStruct (
2715 [["mkfifo"; "0o777"; "/node"];
2716 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2717 "make FIFO (named pipe)",
2719 This call creates a FIFO (named pipe) called C<path> with
2720 mode C<mode>. It is just a convenient wrapper around
2721 C<guestfs_mknod>.");
2723 ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 135, [],
2724 [InitBasicFS, Always, TestOutputStruct (
2725 [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2726 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2727 "make block device node",
2729 This call creates a block device node called C<path> with
2730 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2731 It is just a convenient wrapper around C<guestfs_mknod>.");
2733 ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 136, [],
2734 [InitBasicFS, Always, TestOutputStruct (
2735 [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2736 ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2737 "make char device node",
2739 This call creates a char device node called C<path> with
2740 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2741 It is just a convenient wrapper around C<guestfs_mknod>.");
2743 ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2744 [], (* XXX umask is one of those stateful things that we should
2745 * reset between each test.
2747 "set file mode creation mask (umask)",
2749 This function sets the mask used for creating new files and
2750 device nodes to C<mask & 0777>.
2752 Typical umask values would be C<022> which creates new files
2753 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2754 C<002> which creates new files with permissions like
2755 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2757 The default umask is C<022>. This is important because it
2758 means that directories and device nodes will be created with
2759 C<0644> or C<0755> mode even if you specify C<0777>.
2761 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2763 This call returns the previous umask.");
2765 ("readdir", (RDirentList "entries", [String "dir"]), 138, [],
2767 "read directories entries",
2769 This returns the list of directory entries in directory C<dir>.
2771 All entries in the directory are returned, including C<.> and
2772 C<..>. The entries are I<not> sorted, but returned in the same
2773 order as the underlying filesystem.
2775 This function is primarily intended for use by programs. To
2776 get a simple list of names, use C<guestfs_ls>. To get a printable
2777 directory for human consumption, use C<guestfs_ll>.");
2779 ("sfdiskM", (RErr, [String "device"; StringList "lines"]), 139, [DangerWillRobinson],
2781 "create partitions on a block device",
2783 This is a simplified interface to the C<guestfs_sfdisk>
2784 command, where partition sizes are specified in megabytes
2785 only (rounded to the nearest cylinder) and you don't need
2786 to specify the cyls, heads and sectors parameters which
2787 were rarely if ever used anyway.
2789 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
2793 let all_functions = non_daemon_functions @ daemon_functions
2795 (* In some places we want the functions to be displayed sorted
2796 * alphabetically, so this is useful:
2798 let all_functions_sorted =
2799 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2800 compare n1 n2) all_functions
2802 (* Column names and types from LVM PVs/VGs/LVs. *)
2811 "pv_attr", `String (* XXX *);
2812 "pv_pe_count", `Int;
2813 "pv_pe_alloc_count", `Int;
2816 "pv_mda_count", `Int;
2817 "pv_mda_free", `Bytes;
2818 (* Not in Fedora 10:
2819 "pv_mda_size", `Bytes;
2826 "vg_attr", `String (* XXX *);
2829 "vg_sysid", `String;
2830 "vg_extent_size", `Bytes;
2831 "vg_extent_count", `Int;
2832 "vg_free_count", `Int;
2840 "vg_mda_count", `Int;
2841 "vg_mda_free", `Bytes;
2842 (* Not in Fedora 10:
2843 "vg_mda_size", `Bytes;
2849 "lv_attr", `String (* XXX *);
2852 "lv_kernel_major", `Int;
2853 "lv_kernel_minor", `Int;
2857 "snap_percent", `OptPercent;
2858 "copy_percent", `OptPercent;
2861 "mirror_log", `String;
2865 (* Column names and types from stat structures.
2866 * NB. Can't use things like 'st_atime' because glibc header files
2867 * define some of these as macros. Ugh.
2884 let statvfs_cols = [
2898 (* Column names in dirent structure. *)
2901 "ftyp", `Char; (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
2905 (* Used for testing language bindings. *)
2907 | CallString of string
2908 | CallOptString of string option
2909 | CallStringList of string list
2913 (* Used to memoize the result of pod2text. *)
2914 let pod2text_memo_filename = "src/.pod2text.data"
2915 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
2917 let chan = open_in pod2text_memo_filename in
2918 let v = input_value chan in
2922 _ -> Hashtbl.create 13
2924 (* Useful functions.
2925 * Note we don't want to use any external OCaml libraries which
2926 * makes this a bit harder than it should be.
2928 let failwithf fs = ksprintf failwith fs
2930 let replace_char s c1 c2 =
2931 let s2 = String.copy s in
2932 let r = ref false in
2933 for i = 0 to String.length s2 - 1 do
2934 if String.unsafe_get s2 i = c1 then (
2935 String.unsafe_set s2 i c2;
2939 if not !r then s else s2
2943 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2945 let triml ?(test = isspace) str =
2947 let n = ref (String.length str) in
2948 while !n > 0 && test str.[!i]; do
2953 else String.sub str !i !n
2955 let trimr ?(test = isspace) str =
2956 let n = ref (String.length str) in
2957 while !n > 0 && test str.[!n-1]; do
2960 if !n = String.length str then str
2961 else String.sub str 0 !n
2963 let trim ?(test = isspace) str =
2964 trimr ~test (triml ~test str)
2966 let rec find s sub =
2967 let len = String.length s in
2968 let sublen = String.length sub in
2970 if i <= len-sublen then (
2972 if j < sublen then (
2973 if s.[i+j] = sub.[j] then loop2 (j+1)
2979 if r = -1 then loop (i+1) else r
2985 let rec replace_str s s1 s2 =
2986 let len = String.length s in
2987 let sublen = String.length s1 in
2988 let i = find s s1 in
2991 let s' = String.sub s 0 i in
2992 let s'' = String.sub s (i+sublen) (len-i-sublen) in
2993 s' ^ s2 ^ replace_str s'' s1 s2
2996 let rec string_split sep str =
2997 let len = String.length str in
2998 let seplen = String.length sep in
2999 let i = find str sep in
3000 if i = -1 then [str]
3002 let s' = String.sub str 0 i in
3003 let s'' = String.sub str (i+seplen) (len-i-seplen) in
3004 s' :: string_split sep s''
3007 let files_equal n1 n2 =
3008 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
3009 match Sys.command cmd with
3012 | i -> failwithf "%s: failed with error code %d" cmd i
3014 let rec find_map f = function
3015 | [] -> raise Not_found
3019 | None -> find_map f xs
3022 let rec loop i = function
3024 | x :: xs -> f i x; loop (i+1) xs
3029 let rec loop i = function
3031 | x :: xs -> let r = f i x in r :: loop (i+1) xs
3035 let name_of_argt = function
3036 | String n | OptString n | StringList n | Bool n | Int n
3037 | FileIn n | FileOut n -> n
3039 let seq_of_test = function
3040 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
3041 | TestOutputListOfDevices (s, _)
3042 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
3043 | TestOutputLength (s, _) | TestOutputStruct (s, _)
3044 | TestLastFail s -> s
3046 (* Check function names etc. for consistency. *)
3047 let check_functions () =
3048 let contains_uppercase str =
3049 let len = String.length str in
3051 if i >= len then false
3054 if c >= 'A' && c <= 'Z' then true
3061 (* Check function names. *)
3063 fun (name, _, _, _, _, _, _) ->
3064 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
3065 failwithf "function name %s does not need 'guestfs' prefix" name;
3067 failwithf "function name is empty";
3068 if name.[0] < 'a' || name.[0] > 'z' then
3069 failwithf "function name %s must start with lowercase a-z" name;
3070 if String.contains name '-' then
3071 failwithf "function name %s should not contain '-', use '_' instead."
3075 (* Check function parameter/return names. *)
3077 fun (name, style, _, _, _, _, _) ->
3078 let check_arg_ret_name n =
3079 if contains_uppercase n then
3080 failwithf "%s param/ret %s should not contain uppercase chars"
3082 if String.contains n '-' || String.contains n '_' then
3083 failwithf "%s param/ret %s should not contain '-' or '_'"
3086 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;
3087 if n = "int" || n = "char" || n = "short" || n = "long" then
3088 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
3089 if n = "i" || n = "n" then
3090 failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
3091 if n = "argv" || n = "args" then
3092 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
3095 (match fst style with
3097 | RInt n | RInt64 n | RBool n | RConstString n | RString n
3098 | RStringList n | RPVList n | RVGList n | RLVList n
3099 | RStat n | RStatVFS n
3102 check_arg_ret_name n
3104 check_arg_ret_name n;
3105 check_arg_ret_name m
3107 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
3110 (* Check short descriptions. *)
3112 fun (name, _, _, _, _, shortdesc, _) ->
3113 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
3114 failwithf "short description of %s should begin with lowercase." name;
3115 let c = shortdesc.[String.length shortdesc-1] in
3116 if c = '\n' || c = '.' then
3117 failwithf "short description of %s should not end with . or \\n." name
3120 (* Check long dscriptions. *)
3122 fun (name, _, _, _, _, _, longdesc) ->
3123 if longdesc.[String.length longdesc-1] = '\n' then
3124 failwithf "long description of %s should not end with \\n." name
3127 (* Check proc_nrs. *)
3129 fun (name, _, proc_nr, _, _, _, _) ->
3130 if proc_nr <= 0 then
3131 failwithf "daemon function %s should have proc_nr > 0" name
3135 fun (name, _, proc_nr, _, _, _, _) ->
3136 if proc_nr <> -1 then
3137 failwithf "non-daemon function %s should have proc_nr -1" name
3138 ) non_daemon_functions;
3141 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
3144 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
3145 let rec loop = function
3148 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
3150 | (name1,nr1) :: (name2,nr2) :: _ ->
3151 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
3159 (* Ignore functions that have no tests. We generate a
3160 * warning when the user does 'make check' instead.
3162 | name, _, _, _, [], _, _ -> ()
3163 | name, _, _, _, tests, _, _ ->
3167 match seq_of_test test with
3169 failwithf "%s has a test containing an empty sequence" name
3170 | cmds -> List.map List.hd cmds
3172 let funcs = List.flatten funcs in
3174 let tested = List.mem name funcs in
3177 failwithf "function %s has tests but does not test itself" name
3180 (* 'pr' prints to the current output file. *)
3181 let chan = ref stdout
3182 let pr fs = ksprintf (output_string !chan) fs
3184 (* Generate a header block in a number of standard styles. *)
3185 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
3186 type license = GPLv2 | LGPLv2
3188 let generate_header comment license =
3189 let c = match comment with
3190 | CStyle -> pr "/* "; " *"
3191 | HashStyle -> pr "# "; "#"
3192 | OCamlStyle -> pr "(* "; " *"
3193 | HaskellStyle -> pr "{- "; " " in
3194 pr "libguestfs generated file\n";
3195 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
3196 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
3198 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
3202 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
3203 pr "%s it under the terms of the GNU General Public License as published by\n" c;
3204 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
3205 pr "%s (at your option) any later version.\n" c;
3207 pr "%s This program is distributed in the hope that it will be useful,\n" c;
3208 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3209 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
3210 pr "%s GNU General Public License for more details.\n" c;
3212 pr "%s You should have received a copy of the GNU General Public License along\n" c;
3213 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
3214 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
3217 pr "%s This library is free software; you can redistribute it and/or\n" c;
3218 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
3219 pr "%s License as published by the Free Software Foundation; either\n" c;
3220 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
3222 pr "%s This library is distributed in the hope that it will be useful,\n" c;
3223 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3224 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
3225 pr "%s Lesser General Public License for more details.\n" c;
3227 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
3228 pr "%s License along with this library; if not, write to the Free Software\n" c;
3229 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
3232 | CStyle -> pr " */\n"
3234 | OCamlStyle -> pr " *)\n"
3235 | HaskellStyle -> pr "-}\n"
3239 (* Start of main code generation functions below this line. *)
3241 (* Generate the pod documentation for the C API. *)
3242 let rec generate_actions_pod () =
3244 fun (shortname, style, _, flags, _, _, longdesc) ->
3245 if not (List.mem NotInDocs flags) then (
3246 let name = "guestfs_" ^ shortname in
3247 pr "=head2 %s\n\n" name;
3249 generate_prototype ~extern:false ~handle:"handle" name style;
3251 pr "%s\n\n" longdesc;
3252 (match fst style with
3254 pr "This function returns 0 on success or -1 on error.\n\n"
3256 pr "On error this function returns -1.\n\n"
3258 pr "On error this function returns -1.\n\n"
3260 pr "This function returns a C truth value on success or -1 on error.\n\n"
3262 pr "This function returns a string, or NULL on error.
3263 The string is owned by the guest handle and must I<not> be freed.\n\n"
3265 pr "This function returns a string, or NULL on error.
3266 I<The caller must free the returned string after use>.\n\n"
3268 pr "This function returns a NULL-terminated array of strings
3269 (like L<environ(3)>), or NULL if there was an error.
3270 I<The caller must free the strings and the array after use>.\n\n"
3272 pr "This function returns a C<struct guestfs_int_bool *>,
3273 or NULL if there was an error.
3274 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
3276 pr "This function returns a C<struct guestfs_lvm_pv_list *>
3277 (see E<lt>guestfs-structs.hE<gt>),
3278 or NULL if there was an error.
3279 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
3281 pr "This function returns a C<struct guestfs_lvm_vg_list *>
3282 (see E<lt>guestfs-structs.hE<gt>),
3283 or NULL if there was an error.
3284 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
3286 pr "This function returns a C<struct guestfs_lvm_lv_list *>
3287 (see E<lt>guestfs-structs.hE<gt>),
3288 or NULL if there was an error.
3289 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
3291 pr "This function returns a C<struct guestfs_stat *>
3292 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
3293 or NULL if there was an error.
3294 I<The caller must call C<free> after use>.\n\n"
3296 pr "This function returns a C<struct guestfs_statvfs *>
3297 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
3298 or NULL if there was an error.
3299 I<The caller must call C<free> after use>.\n\n"
3301 pr "This function returns a NULL-terminated array of
3302 strings, or NULL if there was an error.
3303 The array of strings will always have length C<2n+1>, where
3304 C<n> keys and values alternate, followed by the trailing NULL entry.
3305 I<The caller must free the strings and the array after use>.\n\n"
3307 pr "This function returns a C<struct guestfs_dirent_list *>
3308 (see E<lt>guestfs-structs.hE<gt>),
3309 or NULL if there was an error.
3310 I<The caller must call C<guestfs_free_dirent_list> after use>.\n\n"
3312 if List.mem ProtocolLimitWarning flags then
3313 pr "%s\n\n" protocol_limit_warning;
3314 if List.mem DangerWillRobinson flags then
3315 pr "%s\n\n" danger_will_robinson
3317 ) all_functions_sorted
3319 and generate_structs_pod () =
3320 (* LVM structs documentation. *)
3323 pr "=head2 guestfs_lvm_%s\n" typ;
3325 pr " struct guestfs_lvm_%s {\n" typ;
3328 | name, `String -> pr " char *%s;\n" name
3330 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
3331 pr " char %s[32];\n" name
3332 | name, `Bytes -> pr " uint64_t %s;\n" name
3333 | name, `Int -> pr " int64_t %s;\n" name
3334 | name, `OptPercent ->
3335 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
3336 pr " float %s;\n" name
3339 pr " struct guestfs_lvm_%s_list {\n" typ;
3340 pr " uint32_t len; /* Number of elements in list. */\n";
3341 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
3344 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
3347 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3352 pr "=head2 guestfs_%s\n" typ;
3354 pr " struct guestfs_%s {\n" typ;
3357 | name, `Int -> pr " int64_t %s;\n" name
3361 ) [ "stat", stat_cols; "statvfs", statvfs_cols ];
3364 pr "=head2 guestfs_dirent\n";
3366 pr " struct guestfs_dirent {\n";
3369 | name, `String -> pr " char *%s;\n" name
3370 | name, `Int -> pr " int64_t %s;\n" name
3371 | name, `Char -> pr " char %s;\n" name
3375 pr " struct guestfs_dirent_list {\n";
3376 pr " uint32_t len; /* Number of elements in list. */\n";
3377 pr " struct guestfs_dirent *val; /* Elements. */\n";
3380 pr " void guestfs_free_dirent_list (struct guestfs_free_dirent_list *);\n";
3383 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3384 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3386 * We have to use an underscore instead of a dash because otherwise
3387 * rpcgen generates incorrect code.
3389 * This header is NOT exported to clients, but see also generate_structs_h.
3391 and generate_xdr () =
3392 generate_header CStyle LGPLv2;
3394 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3395 pr "typedef string str<>;\n";
3398 (* LVM internal structures. *)
3402 pr "struct guestfs_lvm_int_%s {\n" typ;
3404 | name, `String -> pr " string %s<>;\n" name
3405 | name, `UUID -> pr " opaque %s[32];\n" name
3406 | name, `Bytes -> pr " hyper %s;\n" name
3407 | name, `Int -> pr " hyper %s;\n" name
3408 | name, `OptPercent -> pr " float %s;\n" name
3412 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
3414 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3416 (* Stat internal structures. *)
3420 pr "struct guestfs_int_%s {\n" typ;
3422 | name, `Int -> pr " hyper %s;\n" name
3426 ) ["stat", stat_cols; "statvfs", statvfs_cols];
3428 (* Dirent structures. *)
3429 pr "struct guestfs_int_dirent {\n";
3431 | name, `Int -> pr " hyper %s;\n" name
3432 | name, `Char -> pr " char %s;\n" name
3433 | name, `String -> pr " string %s<>;\n" name
3437 pr "typedef struct guestfs_int_dirent guestfs_int_dirent_list<>;\n";
3441 fun (shortname, style, _, _, _, _, _) ->
3442 let name = "guestfs_" ^ shortname in
3444 (match snd style with
3447 pr "struct %s_args {\n" name;
3450 | String n -> pr " string %s<>;\n" n
3451 | OptString n -> pr " str *%s;\n" n
3452 | StringList n -> pr " str %s<>;\n" n
3453 | Bool n -> pr " bool %s;\n" n
3454 | Int n -> pr " int %s;\n" n
3455 | FileIn _ | FileOut _ -> ()
3459 (match fst style with
3462 pr "struct %s_ret {\n" name;
3466 pr "struct %s_ret {\n" name;
3467 pr " hyper %s;\n" n;
3470 pr "struct %s_ret {\n" name;
3474 failwithf "RConstString cannot be returned from a daemon function"
3476 pr "struct %s_ret {\n" name;
3477 pr " string %s<>;\n" n;
3480 pr "struct %s_ret {\n" name;
3481 pr " str %s<>;\n" n;
3484 pr "struct %s_ret {\n" name;
3489 pr "struct %s_ret {\n" name;
3490 pr " guestfs_lvm_int_pv_list %s;\n" n;
3493 pr "struct %s_ret {\n" name;
3494 pr " guestfs_lvm_int_vg_list %s;\n" n;
3497 pr "struct %s_ret {\n" name;
3498 pr " guestfs_lvm_int_lv_list %s;\n" n;
3501 pr "struct %s_ret {\n" name;
3502 pr " guestfs_int_stat %s;\n" n;
3505 pr "struct %s_ret {\n" name;
3506 pr " guestfs_int_statvfs %s;\n" n;
3509 pr "struct %s_ret {\n" name;
3510 pr " str %s<>;\n" n;
3513 pr "struct %s_ret {\n" name;
3514 pr " guestfs_int_dirent_list %s;\n" n;
3519 (* Table of procedure numbers. *)
3520 pr "enum guestfs_procedure {\n";
3522 fun (shortname, _, proc_nr, _, _, _, _) ->
3523 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3525 pr " GUESTFS_PROC_NR_PROCS\n";
3529 (* Having to choose a maximum message size is annoying for several
3530 * reasons (it limits what we can do in the API), but it (a) makes
3531 * the protocol a lot simpler, and (b) provides a bound on the size
3532 * of the daemon which operates in limited memory space. For large
3533 * file transfers you should use FTP.
3535 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3538 (* Message header, etc. *)
3540 /* The communication protocol is now documented in the guestfs(3)
3544 const GUESTFS_PROGRAM = 0x2000F5F5;
3545 const GUESTFS_PROTOCOL_VERSION = 1;
3547 /* These constants must be larger than any possible message length. */
3548 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3549 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3551 enum guestfs_message_direction {
3552 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
3553 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
3556 enum guestfs_message_status {
3557 GUESTFS_STATUS_OK = 0,
3558 GUESTFS_STATUS_ERROR = 1
3561 const GUESTFS_ERROR_LEN = 256;
3563 struct guestfs_message_error {
3564 string error_message<GUESTFS_ERROR_LEN>;
3567 struct guestfs_message_header {
3568 unsigned prog; /* GUESTFS_PROGRAM */
3569 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
3570 guestfs_procedure proc; /* GUESTFS_PROC_x */
3571 guestfs_message_direction direction;
3572 unsigned serial; /* message serial number */
3573 guestfs_message_status status;
3576 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3578 struct guestfs_chunk {
3579 int cancel; /* if non-zero, transfer is cancelled */
3580 /* data size is 0 bytes if the transfer has finished successfully */
3581 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3585 (* Generate the guestfs-structs.h file. *)
3586 and generate_structs_h () =
3587 generate_header CStyle LGPLv2;
3589 (* This is a public exported header file containing various
3590 * structures. The structures are carefully written to have
3591 * exactly the same in-memory format as the XDR structures that
3592 * we use on the wire to the daemon. The reason for creating
3593 * copies of these structures here is just so we don't have to
3594 * export the whole of guestfs_protocol.h (which includes much
3595 * unrelated and XDR-dependent stuff that we don't want to be
3596 * public, or required by clients).
3598 * To reiterate, we will pass these structures to and from the
3599 * client with a simple assignment or memcpy, so the format
3600 * must be identical to what rpcgen / the RFC defines.
3603 (* guestfs_int_bool structure. *)
3604 pr "struct guestfs_int_bool {\n";
3610 (* LVM public structures. *)
3614 pr "struct guestfs_lvm_%s {\n" typ;
3617 | name, `String -> pr " char *%s;\n" name
3618 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3619 | name, `Bytes -> pr " uint64_t %s;\n" name
3620 | name, `Int -> pr " int64_t %s;\n" name
3621 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
3625 pr "struct guestfs_lvm_%s_list {\n" typ;
3626 pr " uint32_t len;\n";
3627 pr " struct guestfs_lvm_%s *val;\n" typ;
3630 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3632 (* Stat structures. *)
3636 pr "struct guestfs_%s {\n" typ;
3639 | name, `Int -> pr " int64_t %s;\n" name
3643 ) ["stat", stat_cols; "statvfs", statvfs_cols];
3645 (* Dirent structures. *)
3646 pr "struct guestfs_dirent {\n";
3649 | name, `Int -> pr " int64_t %s;\n" name
3650 | name, `Char -> pr " char %s;\n" name
3651 | name, `String -> pr " char *%s;\n" name
3655 pr "struct guestfs_dirent_list {\n";
3656 pr " uint32_t len;\n";
3657 pr " struct guestfs_dirent *val;\n";
3661 (* Generate the guestfs-actions.h file. *)
3662 and generate_actions_h () =
3663 generate_header CStyle LGPLv2;
3665 fun (shortname, style, _, _, _, _, _) ->
3666 let name = "guestfs_" ^ shortname in
3667 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3671 (* Generate the client-side dispatch stubs. *)
3672 and generate_client_actions () =
3673 generate_header CStyle LGPLv2;
3679 #include \"guestfs.h\"
3680 #include \"guestfs_protocol.h\"
3682 #define error guestfs_error
3683 #define perrorf guestfs_perrorf
3684 #define safe_malloc guestfs_safe_malloc
3685 #define safe_realloc guestfs_safe_realloc
3686 #define safe_strdup guestfs_safe_strdup
3687 #define safe_memdup guestfs_safe_memdup
3689 /* Check the return message from a call for validity. */
3691 check_reply_header (guestfs_h *g,
3692 const struct guestfs_message_header *hdr,
3693 int proc_nr, int serial)
3695 if (hdr->prog != GUESTFS_PROGRAM) {
3696 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3699 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3700 error (g, \"wrong protocol version (%%d/%%d)\",
3701 hdr->vers, GUESTFS_PROTOCOL_VERSION);
3704 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3705 error (g, \"unexpected message direction (%%d/%%d)\",
3706 hdr->direction, GUESTFS_DIRECTION_REPLY);
3709 if (hdr->proc != proc_nr) {
3710 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3713 if (hdr->serial != serial) {
3714 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3721 /* Check we are in the right state to run a high-level action. */
3723 check_state (guestfs_h *g, const char *caller)
3725 if (!guestfs_is_ready (g)) {
3726 if (guestfs_is_config (g))
3727 error (g, \"%%s: call launch() before using this function\",
3729 else if (guestfs_is_launching (g))
3730 error (g, \"%%s: call wait_ready() before using this function\",
3733 error (g, \"%%s called from the wrong state, %%d != READY\",
3734 caller, guestfs_get_state (g));
3742 (* Client-side stubs for each function. *)
3744 fun (shortname, style, _, _, _, _, _) ->
3745 let name = "guestfs_" ^ shortname in
3747 (* Generate the context struct which stores the high-level
3748 * state between callback functions.
3750 pr "struct %s_ctx {\n" shortname;
3751 pr " /* This flag is set by the callbacks, so we know we've done\n";
3752 pr " * the callbacks as expected, and in the right sequence.\n";
3753 pr " * 0 = not called, 1 = reply_cb called.\n";
3755 pr " int cb_sequence;\n";
3756 pr " struct guestfs_message_header hdr;\n";
3757 pr " struct guestfs_message_error err;\n";
3758 (match fst style with
3761 failwithf "RConstString cannot be returned from a daemon function"
3763 | RBool _ | RString _ | RStringList _
3765 | RPVList _ | RVGList _ | RLVList _
3766 | RStat _ | RStatVFS _
3769 pr " struct %s_ret ret;\n" name
3774 (* Generate the reply callback function. *)
3775 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3777 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3778 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3780 pr " /* This should definitely not happen. */\n";
3781 pr " if (ctx->cb_sequence != 0) {\n";
3782 pr " ctx->cb_sequence = 9999;\n";
3783 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3787 pr " ml->main_loop_quit (ml, g);\n";
3789 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3790 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3793 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3794 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3795 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3802 (match fst style with
3805 failwithf "RConstString cannot be returned from a daemon function"
3807 | RBool _ | RString _ | RStringList _
3809 | RPVList _ | RVGList _ | RLVList _
3810 | RStat _ | RStatVFS _
3813 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3814 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3820 pr " ctx->cb_sequence = 1;\n";
3823 (* Generate the action stub. *)
3824 generate_prototype ~extern:false ~semicolon:false ~newline:true
3825 ~handle:"g" name style;
3828 match fst style with
3829 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3831 failwithf "RConstString cannot be returned from a daemon function"
3832 | RString _ | RStringList _ | RIntBool _
3833 | RPVList _ | RVGList _ | RLVList _
3834 | RStat _ | RStatVFS _
3841 (match snd style with
3843 | _ -> pr " struct %s_args args;\n" name
3846 pr " struct %s_ctx ctx;\n" shortname;
3847 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3848 pr " int serial;\n";
3850 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3851 pr " guestfs_set_busy (g);\n";
3853 pr " memset (&ctx, 0, sizeof ctx);\n";
3856 (* Send the main header and arguments. *)
3857 (match snd style with
3859 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3860 (String.uppercase shortname)
3865 pr " args.%s = (char *) %s;\n" n n
3867 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
3869 pr " args.%s.%s_val = (char **) %s;\n" n n n;
3870 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3872 pr " args.%s = %s;\n" n n
3874 pr " args.%s = %s;\n" n n
3875 | FileIn _ | FileOut _ -> ()
3877 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3878 (String.uppercase shortname);
3879 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3882 pr " if (serial == -1) {\n";
3883 pr " guestfs_end_busy (g);\n";
3884 pr " return %s;\n" error_code;
3888 (* Send any additional files (FileIn) requested. *)
3889 let need_read_reply_label = ref false in
3896 pr " r = guestfs__send_file_sync (g, %s);\n" n;
3897 pr " if (r == -1) {\n";
3898 pr " guestfs_end_busy (g);\n";
3899 pr " return %s;\n" error_code;
3901 pr " if (r == -2) /* daemon cancelled */\n";
3902 pr " goto read_reply;\n";
3903 need_read_reply_label := true;
3909 (* Wait for the reply from the remote end. *)
3910 if !need_read_reply_label then pr " read_reply:\n";
3911 pr " guestfs__switch_to_receiving (g);\n";
3912 pr " ctx.cb_sequence = 0;\n";
3913 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3914 pr " (void) ml->main_loop_run (ml, g);\n";
3915 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
3916 pr " if (ctx.cb_sequence != 1) {\n";
3917 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3918 pr " guestfs_end_busy (g);\n";
3919 pr " return %s;\n" error_code;
3923 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3924 (String.uppercase shortname);
3925 pr " guestfs_end_busy (g);\n";
3926 pr " return %s;\n" error_code;
3930 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3931 pr " error (g, \"%%s\", ctx.err.error_message);\n";
3932 pr " free (ctx.err.error_message);\n";
3933 pr " guestfs_end_busy (g);\n";
3934 pr " return %s;\n" error_code;
3938 (* Expecting to receive further files (FileOut)? *)
3942 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3943 pr " guestfs_end_busy (g);\n";
3944 pr " return %s;\n" error_code;
3950 pr " guestfs_end_busy (g);\n";
3952 (match fst style with
3953 | RErr -> pr " return 0;\n"
3954 | RInt n | RInt64 n | RBool n ->
3955 pr " return ctx.ret.%s;\n" n
3957 failwithf "RConstString cannot be returned from a daemon function"
3959 pr " return ctx.ret.%s; /* caller will free */\n" n
3960 | RStringList n | RHashtable n ->
3961 pr " /* caller will free this, but we need to add a NULL entry */\n";
3962 pr " ctx.ret.%s.%s_val =\n" n n;
3963 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3964 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3966 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3967 pr " return ctx.ret.%s.%s_val;\n" n n
3969 pr " /* caller with free this */\n";
3970 pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3971 | RPVList n | RVGList n | RLVList n
3972 | RStat n | RStatVFS n
3974 pr " /* caller will free this */\n";
3975 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3981 (* Generate daemon/actions.h. *)
3982 and generate_daemon_actions_h () =
3983 generate_header CStyle GPLv2;
3985 pr "#include \"../src/guestfs_protocol.h\"\n";
3989 fun (name, style, _, _, _, _, _) ->
3991 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3995 (* Generate the server-side stubs. *)
3996 and generate_daemon_actions () =
3997 generate_header CStyle GPLv2;
3999 pr "#include <config.h>\n";
4001 pr "#include <stdio.h>\n";
4002 pr "#include <stdlib.h>\n";
4003 pr "#include <string.h>\n";
4004 pr "#include <inttypes.h>\n";
4005 pr "#include <ctype.h>\n";
4006 pr "#include <rpc/types.h>\n";
4007 pr "#include <rpc/xdr.h>\n";
4009 pr "#include \"daemon.h\"\n";
4010 pr "#include \"../src/guestfs_protocol.h\"\n";
4011 pr "#include \"actions.h\"\n";
4015 fun (name, style, _, _, _, _, _) ->
4016 (* Generate server-side stubs. *)
4017 pr "static void %s_stub (XDR *xdr_in)\n" name;
4020 match fst style with
4021 | RErr | RInt _ -> pr " int r;\n"; "-1"
4022 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4023 | RBool _ -> pr " int r;\n"; "-1"
4025 failwithf "RConstString cannot be returned from a daemon function"
4026 | RString _ -> pr " char *r;\n"; "NULL"
4027 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
4028 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
4029 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
4030 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
4031 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
4032 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
4033 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL"
4034 | RDirentList _ -> pr " guestfs_int_dirent_list *r;\n"; "NULL" in
4036 (match snd style with
4039 pr " struct guestfs_%s_args args;\n" name;
4042 (* Note we allow the string to be writable, in order to
4043 * allow device name translation. This is safe because
4044 * we can modify the string (passed from RPC).
4047 | OptString n -> pr " char *%s;\n" n
4048 | StringList n -> pr " char **%s;\n" n
4049 | Bool n -> pr " int %s;\n" n
4050 | Int n -> pr " int %s;\n" n
4051 | FileIn _ | FileOut _ -> ()
4056 (match snd style with
4059 pr " memset (&args, 0, sizeof args);\n";
4061 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4062 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4067 | String n -> pr " %s = args.%s;\n" n n
4068 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
4070 pr " %s = realloc (args.%s.%s_val,\n" n n n;
4071 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4072 pr " if (%s == NULL) {\n" n;
4073 pr " reply_with_perror (\"realloc\");\n";
4076 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
4077 pr " args.%s.%s_val = %s;\n" n n n;
4078 | Bool n -> pr " %s = args.%s;\n" n n
4079 | Int n -> pr " %s = args.%s;\n" n n
4080 | FileIn _ | FileOut _ -> ()
4085 (* Don't want to call the impl with any FileIn or FileOut
4086 * parameters, since these go "outside" the RPC protocol.
4089 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
4091 pr " r = do_%s " name;
4092 generate_call_args argsnofile;
4095 pr " if (r == %s)\n" error_code;
4096 pr " /* do_%s has already called reply_with_error */\n" name;
4100 (* If there are any FileOut parameters, then the impl must
4101 * send its own reply.
4104 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
4106 pr " /* do_%s has already sent a reply */\n" name
4108 match fst style with
4109 | RErr -> pr " reply (NULL, NULL);\n"
4110 | RInt n | RInt64 n | RBool n ->
4111 pr " struct guestfs_%s_ret ret;\n" name;
4112 pr " ret.%s = r;\n" n;
4113 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4116 failwithf "RConstString cannot be returned from a daemon function"
4118 pr " struct guestfs_%s_ret ret;\n" name;
4119 pr " ret.%s = r;\n" n;
4120 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4123 | RStringList n | RHashtable n ->
4124 pr " struct guestfs_%s_ret ret;\n" name;
4125 pr " ret.%s.%s_len = count_strings (r);\n" n n;
4126 pr " ret.%s.%s_val = r;\n" n n;
4127 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4129 pr " free_strings (r);\n"
4131 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
4133 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
4134 | RPVList n | RVGList n | RLVList n
4135 | RStat n | RStatVFS n
4137 pr " struct guestfs_%s_ret ret;\n" name;
4138 pr " ret.%s = *r;\n" n;
4139 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4141 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4145 (* Free the args. *)
4146 (match snd style with
4151 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4158 (* Dispatch function. *)
4159 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4161 pr " switch (proc_nr) {\n";
4164 fun (name, style, _, _, _, _, _) ->
4165 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
4166 pr " %s_stub (xdr_in);\n" name;
4171 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";
4176 (* LVM columns and tokenization functions. *)
4177 (* XXX This generates crap code. We should rethink how we
4183 pr "static const char *lvm_%s_cols = \"%s\";\n"
4184 typ (String.concat "," (List.map fst cols));
4187 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
4189 pr " char *tok, *p, *next;\n";
4193 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4196 pr " if (!str) {\n";
4197 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4200 pr " if (!*str || isspace (*str)) {\n";
4201 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4206 fun (name, coltype) ->
4207 pr " if (!tok) {\n";
4208 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4211 pr " p = strchrnul (tok, ',');\n";
4212 pr " if (*p) next = p+1; else next = NULL;\n";
4213 pr " *p = '\\0';\n";
4216 pr " r->%s = strdup (tok);\n" name;
4217 pr " if (r->%s == NULL) {\n" name;
4218 pr " perror (\"strdup\");\n";
4222 pr " for (i = j = 0; i < 32; ++j) {\n";
4223 pr " if (tok[j] == '\\0') {\n";
4224 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4226 pr " } else if (tok[j] != '-')\n";
4227 pr " r->%s[i++] = tok[j];\n" name;
4230 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4231 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4235 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4236 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4240 pr " if (tok[0] == '\\0')\n";
4241 pr " r->%s = -1;\n" name;
4242 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4243 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4247 pr " tok = next;\n";
4250 pr " if (tok != NULL) {\n";
4251 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4258 pr "guestfs_lvm_int_%s_list *\n" typ;
4259 pr "parse_command_line_%ss (void)\n" typ;
4261 pr " char *out, *err;\n";
4262 pr " char *p, *pend;\n";
4264 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
4265 pr " void *newp;\n";
4267 pr " ret = malloc (sizeof *ret);\n";
4268 pr " if (!ret) {\n";
4269 pr " reply_with_perror (\"malloc\");\n";
4270 pr " return NULL;\n";
4273 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
4274 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
4276 pr " r = command (&out, &err,\n";
4277 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
4278 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4279 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4280 pr " if (r == -1) {\n";
4281 pr " reply_with_error (\"%%s\", err);\n";
4282 pr " free (out);\n";
4283 pr " free (err);\n";
4284 pr " free (ret);\n";
4285 pr " return NULL;\n";
4288 pr " free (err);\n";
4290 pr " /* Tokenize each line of the output. */\n";
4293 pr " while (p) {\n";
4294 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
4295 pr " if (pend) {\n";
4296 pr " *pend = '\\0';\n";
4300 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
4303 pr " if (!*p) { /* Empty line? Skip it. */\n";
4308 pr " /* Allocate some space to store this next entry. */\n";
4309 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
4310 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
4311 pr " if (newp == NULL) {\n";
4312 pr " reply_with_perror (\"realloc\");\n";
4313 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
4314 pr " free (ret);\n";
4315 pr " free (out);\n";
4316 pr " return NULL;\n";
4318 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
4320 pr " /* Tokenize the next entry. */\n";
4321 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
4322 pr " if (r == -1) {\n";
4323 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
4324 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
4325 pr " free (ret);\n";
4326 pr " free (out);\n";
4327 pr " return NULL;\n";
4334 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
4336 pr " free (out);\n";
4337 pr " return ret;\n";
4340 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4342 (* Generate a list of function names, for debugging in the daemon.. *)
4343 and generate_daemon_names () =
4344 generate_header CStyle GPLv2;
4346 pr "#include <config.h>\n";
4348 pr "#include \"daemon.h\"\n";
4351 pr "/* This array is indexed by proc_nr. See guestfs_protocol.x. */\n";
4352 pr "const char *function_names[] = {\n";
4354 fun (name, _, proc_nr, _, _, _, _) -> pr " [%d] = \"%s\",\n" proc_nr name
4358 (* Generate the tests. *)
4359 and generate_tests () =
4360 generate_header CStyle GPLv2;
4367 #include <sys/types.h>
4370 #include \"guestfs.h\"
4372 static guestfs_h *g;
4373 static int suppress_error = 0;
4375 static void print_error (guestfs_h *g, void *data, const char *msg)
4377 if (!suppress_error)
4378 fprintf (stderr, \"%%s\\n\", msg);
4381 static void print_strings (char * const * const argv)
4385 for (argc = 0; argv[argc] != NULL; ++argc)
4386 printf (\"\\t%%s\\n\", argv[argc]);
4390 static void print_table (char * const * const argv)
4394 for (i = 0; argv[i] != NULL; i += 2)
4395 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
4399 static void no_test_warnings (void)
4405 | name, _, _, _, [], _, _ ->
4406 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
4407 | name, _, _, _, tests, _, _ -> ()
4413 (* Generate the actual tests. Note that we generate the tests
4414 * in reverse order, deliberately, so that (in general) the
4415 * newest tests run first. This makes it quicker and easier to
4420 fun (name, _, _, _, tests, _, _) ->
4421 mapi (generate_one_test name) tests
4422 ) (List.rev all_functions) in
4423 let test_names = List.concat test_names in
4424 let nr_tests = List.length test_names in
4427 int main (int argc, char *argv[])
4431 const char *filename;
4433 int nr_tests, test_num = 0;
4435 setbuf (stdout, NULL);
4437 no_test_warnings ();
4439 g = guestfs_create ();
4441 printf (\"guestfs_create FAILED\\n\");
4445 guestfs_set_error_handler (g, print_error, NULL);
4447 guestfs_set_path (g, \"../appliance\");
4449 filename = \"test1.img\";
4450 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4455 if (lseek (fd, %d, SEEK_SET) == -1) {
4461 if (write (fd, &c, 1) == -1) {
4467 if (close (fd) == -1) {
4472 if (guestfs_add_drive (g, filename) == -1) {
4473 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4477 filename = \"test2.img\";
4478 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4483 if (lseek (fd, %d, SEEK_SET) == -1) {
4489 if (write (fd, &c, 1) == -1) {
4495 if (close (fd) == -1) {
4500 if (guestfs_add_drive (g, filename) == -1) {
4501 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4505 filename = \"test3.img\";
4506 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4511 if (lseek (fd, %d, SEEK_SET) == -1) {
4517 if (write (fd, &c, 1) == -1) {
4523 if (close (fd) == -1) {
4528 if (guestfs_add_drive (g, filename) == -1) {
4529 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4533 if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4534 printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4538 if (guestfs_launch (g) == -1) {
4539 printf (\"guestfs_launch FAILED\\n\");
4543 /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4546 if (guestfs_wait_ready (g) == -1) {
4547 printf (\"guestfs_wait_ready FAILED\\n\");
4551 /* Cancel previous alarm. */
4556 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4560 pr " test_num++;\n";
4561 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4562 pr " if (%s () == -1) {\n" test_name;
4563 pr " printf (\"%s FAILED\\n\");\n" test_name;
4569 pr " guestfs_close (g);\n";
4570 pr " unlink (\"test1.img\");\n";
4571 pr " unlink (\"test2.img\");\n";
4572 pr " unlink (\"test3.img\");\n";
4575 pr " if (failed > 0) {\n";
4576 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4584 and generate_one_test name i (init, prereq, test) =
4585 let test_name = sprintf "test_%s_%d" name i in
4588 static int %s_skip (void)
4592 str = getenv (\"TEST_ONLY\");
4594 return strstr (str, \"%s\") == NULL;
4595 str = getenv (\"SKIP_%s\");
4596 if (str && strcmp (str, \"1\") == 0) return 1;
4597 str = getenv (\"SKIP_TEST_%s\");
4598 if (str && strcmp (str, \"1\") == 0) return 1;
4602 " test_name name (String.uppercase test_name) (String.uppercase name);
4605 | Disabled | Always -> ()
4606 | If code | Unless code ->
4607 pr "static int %s_prereq (void)\n" test_name;
4615 static int %s (void)
4618 printf (\" %%s skipped (reason: environment variable set)\\n\", \"%s\");
4622 " test_name test_name test_name;
4626 pr " printf (\" %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4628 pr " if (! %s_prereq ()) {\n" test_name;
4629 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4633 generate_one_test_body name i test_name init test;
4635 pr " if (%s_prereq ()) {\n" test_name;
4636 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4640 generate_one_test_body name i test_name init test;
4642 generate_one_test_body name i test_name init test
4650 and generate_one_test_body name i test_name init test =
4654 pr " /* InitNone|InitEmpty for %s */\n" test_name;
4655 List.iter (generate_test_command_call test_name)
4656 [["blockdev_setrw"; "/dev/sda"];
4660 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4661 List.iter (generate_test_command_call test_name)
4662 [["blockdev_setrw"; "/dev/sda"];
4665 ["sfdiskM"; "/dev/sda"; ","];
4666 ["mkfs"; "ext2"; "/dev/sda1"];
4667 ["mount"; "/dev/sda1"; "/"]]
4668 | InitBasicFSonLVM ->
4669 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4671 List.iter (generate_test_command_call test_name)
4672 [["blockdev_setrw"; "/dev/sda"];
4675 ["sfdiskM"; "/dev/sda"; ","];
4676 ["pvcreate"; "/dev/sda1"];
4677 ["vgcreate"; "VG"; "/dev/sda1"];
4678 ["lvcreate"; "LV"; "VG"; "8"];
4679 ["mkfs"; "ext2"; "/dev/VG/LV"];
4680 ["mount"; "/dev/VG/LV"; "/"]]
4683 let get_seq_last = function
4685 failwithf "%s: you cannot use [] (empty list) when expecting a command"
4688 let seq = List.rev seq in
4689 List.rev (List.tl seq), List.hd seq
4694 pr " /* TestRun for %s (%d) */\n" name i;
4695 List.iter (generate_test_command_call test_name) seq
4696 | TestOutput (seq, expected) ->
4697 pr " /* TestOutput for %s (%d) */\n" name i;
4698 pr " const char *expected = \"%s\";\n" (c_quote expected);
4699 let seq, last = get_seq_last seq in
4701 pr " if (strcmp (r, expected) != 0) {\n";
4702 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4706 List.iter (generate_test_command_call test_name) seq;
4707 generate_test_command_call ~test test_name last
4708 | TestOutputList (seq, expected) ->
4709 pr " /* TestOutputList for %s (%d) */\n" name i;
4710 let seq, last = get_seq_last seq in
4714 pr " if (!r[%d]) {\n" i;
4715 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4716 pr " print_strings (r);\n";
4720 pr " const char *expected = \"%s\";\n" (c_quote str);
4721 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4722 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4727 pr " if (r[%d] != NULL) {\n" (List.length expected);
4728 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4730 pr " print_strings (r);\n";
4734 List.iter (generate_test_command_call test_name) seq;
4735 generate_test_command_call ~test test_name last
4736 | TestOutputListOfDevices (seq, expected) ->
4737 pr " /* TestOutputListOfDevices for %s (%d) */\n" name i;
4738 let seq, last = get_seq_last seq in
4742 pr " if (!r[%d]) {\n" i;
4743 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4744 pr " print_strings (r);\n";
4748 pr " const char *expected = \"%s\";\n" (c_quote str);
4749 pr " r[%d][5] = 's';\n" i;
4750 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4751 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4756 pr " if (r[%d] != NULL) {\n" (List.length expected);
4757 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4759 pr " print_strings (r);\n";
4763 List.iter (generate_test_command_call test_name) seq;
4764 generate_test_command_call ~test test_name last
4765 | TestOutputInt (seq, expected) ->
4766 pr " /* TestOutputInt for %s (%d) */\n" name i;
4767 let seq, last = get_seq_last seq in
4769 pr " if (r != %d) {\n" expected;
4770 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4776 List.iter (generate_test_command_call test_name) seq;
4777 generate_test_command_call ~test test_name last
4778 | TestOutputTrue seq ->
4779 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4780 let seq, last = get_seq_last seq in
4783 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4788 List.iter (generate_test_command_call test_name) seq;
4789 generate_test_command_call ~test test_name last
4790 | TestOutputFalse seq ->
4791 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4792 let seq, last = get_seq_last seq in
4795 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4800 List.iter (generate_test_command_call test_name) seq;
4801 generate_test_command_call ~test test_name last
4802 | TestOutputLength (seq, expected) ->
4803 pr " /* TestOutputLength for %s (%d) */\n" name i;
4804 let seq, last = get_seq_last seq in
4807 pr " for (j = 0; j < %d; ++j)\n" expected;
4808 pr " if (r[j] == NULL) {\n";
4809 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4811 pr " print_strings (r);\n";
4814 pr " if (r[j] != NULL) {\n";
4815 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4817 pr " print_strings (r);\n";
4821 List.iter (generate_test_command_call test_name) seq;
4822 generate_test_command_call ~test test_name last
4823 | TestOutputStruct (seq, checks) ->
4824 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4825 let seq, last = get_seq_last seq in
4829 | CompareWithInt (field, expected) ->
4830 pr " if (r->%s != %d) {\n" field expected;
4831 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4832 test_name field expected;
4833 pr " (int) r->%s);\n" field;
4836 | CompareWithString (field, expected) ->
4837 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4838 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4839 test_name field expected;
4840 pr " r->%s);\n" field;
4843 | CompareFieldsIntEq (field1, field2) ->
4844 pr " if (r->%s != r->%s) {\n" field1 field2;
4845 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4846 test_name field1 field2;
4847 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4850 | CompareFieldsStrEq (field1, field2) ->
4851 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4852 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4853 test_name field1 field2;
4854 pr " r->%s, r->%s);\n" field1 field2;
4859 List.iter (generate_test_command_call test_name) seq;
4860 generate_test_command_call ~test test_name last
4861 | TestLastFail seq ->
4862 pr " /* TestLastFail for %s (%d) */\n" name i;
4863 let seq, last = get_seq_last seq in
4864 List.iter (generate_test_command_call test_name) seq;
4865 generate_test_command_call test_name ~expect_error:true last
4867 (* Generate the code to run a command, leaving the result in 'r'.
4868 * If you expect to get an error then you should set expect_error:true.
4870 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4872 | [] -> assert false
4874 (* Look up the command to find out what args/ret it has. *)
4877 let _, style, _, _, _, _, _ =
4878 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4881 failwithf "%s: in test, command %s was not found" test_name name in
4883 if List.length (snd style) <> List.length args then
4884 failwithf "%s: in test, wrong number of args given to %s"
4891 | OptString n, "NULL" -> ()
4893 | OptString n, arg ->
4894 pr " const char *%s = \"%s\";\n" n (c_quote arg);
4897 | FileIn _, _ | FileOut _, _ -> ()
4898 | StringList n, arg ->
4899 let strs = string_split " " arg in
4902 pr " const char *%s_%d = \"%s\";\n" n i (c_quote str);
4904 pr " const char *%s[] = {\n" n;
4906 fun i _ -> pr " %s_%d,\n" n i
4910 ) (List.combine (snd style) args);
4913 match fst style with
4914 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4915 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4916 | RConstString _ -> pr " const char *r;\n"; "NULL"
4917 | RString _ -> pr " char *r;\n"; "NULL"
4918 | RStringList _ | RHashtable _ ->
4923 pr " struct guestfs_int_bool *r;\n"; "NULL"
4925 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4927 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4929 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4931 pr " struct guestfs_stat *r;\n"; "NULL"
4933 pr " struct guestfs_statvfs *r;\n"; "NULL"
4935 pr " struct guestfs_dirent_list *r;\n"; "NULL" in
4937 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4938 pr " r = guestfs_%s (g" name;
4940 (* Generate the parameters. *)
4943 | OptString _, "NULL" -> pr ", NULL"
4947 | FileIn _, arg | FileOut _, arg ->
4948 pr ", \"%s\"" (c_quote arg)
4949 | StringList n, _ ->
4953 try int_of_string arg
4954 with Failure "int_of_string" ->
4955 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4958 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4959 ) (List.combine (snd style) args);
4962 if not expect_error then
4963 pr " if (r == %s)\n" error_code
4965 pr " if (r != %s)\n" error_code;
4968 (* Insert the test code. *)
4974 (match fst style with
4975 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4976 | RString _ -> pr " free (r);\n"
4977 | RStringList _ | RHashtable _ ->
4978 pr " for (i = 0; r[i] != NULL; ++i)\n";
4979 pr " free (r[i]);\n";
4982 pr " guestfs_free_int_bool (r);\n"
4984 pr " guestfs_free_lvm_pv_list (r);\n"
4986 pr " guestfs_free_lvm_vg_list (r);\n"
4988 pr " guestfs_free_lvm_lv_list (r);\n"
4989 | RStat _ | RStatVFS _ ->
4992 pr " guestfs_free_dirent_list (r);\n"
4998 let str = replace_str str "\r" "\\r" in
4999 let str = replace_str str "\n" "\\n" in
5000 let str = replace_str str "\t" "\\t" in
5001 let str = replace_str str "\000" "\\0" in
5004 (* Generate a lot of different functions for guestfish. *)
5005 and generate_fish_cmds () =
5006 generate_header CStyle GPLv2;
5010 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5012 let all_functions_sorted =
5014 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5015 ) all_functions_sorted in
5017 pr "#include <stdio.h>\n";
5018 pr "#include <stdlib.h>\n";
5019 pr "#include <string.h>\n";
5020 pr "#include <inttypes.h>\n";
5022 pr "#include <guestfs.h>\n";
5023 pr "#include \"fish.h\"\n";
5026 (* list_commands function, which implements guestfish -h *)
5027 pr "void list_commands (void)\n";
5029 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
5030 pr " list_builtin_commands ();\n";
5032 fun (name, _, _, flags, _, shortdesc, _) ->
5033 let name = replace_char name '_' '-' in
5034 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
5036 ) all_functions_sorted;
5037 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
5041 (* display_command function, which implements guestfish -h cmd *)
5042 pr "void display_command (const char *cmd)\n";
5045 fun (name, style, _, flags, _, shortdesc, longdesc) ->
5046 let name2 = replace_char name '_' '-' in
5048 try find_map (function FishAlias n -> Some n | _ -> None) flags
5049 with Not_found -> name in
5050 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
5052 match snd style with
5056 name2 (String.concat "> <" (List.map name_of_argt args)) in
5059 if List.mem ProtocolLimitWarning flags then
5060 ("\n\n" ^ protocol_limit_warning)
5063 (* For DangerWillRobinson commands, we should probably have
5064 * guestfish prompt before allowing you to use them (especially
5065 * in interactive mode). XXX
5069 if List.mem DangerWillRobinson flags then
5070 ("\n\n" ^ danger_will_robinson)
5073 let describe_alias =
5074 if name <> alias then
5075 sprintf "\n\nYou can use '%s' as an alias for this command." alias
5079 pr "strcasecmp (cmd, \"%s\") == 0" name;
5080 if name <> name2 then
5081 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5082 if name <> alias then
5083 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5085 pr " pod2text (\"%s - %s\", %S);\n"
5087 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
5090 pr " display_builtin_command (cmd);\n";
5094 (* print_{pv,vg,lv}_list functions *)
5098 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
5105 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
5107 pr " printf (\"%s: \");\n" name;
5108 pr " for (i = 0; i < 32; ++i)\n";
5109 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
5110 pr " printf (\"\\n\");\n"
5112 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
5114 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
5115 | name, `OptPercent ->
5116 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
5117 typ name name typ name;
5118 pr " else printf (\"%s: \\n\");\n" name
5122 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
5127 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
5128 pr " print_%s (&%ss->val[i]);\n" typ typ;
5131 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5133 (* print_{stat,statvfs} functions *)
5137 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
5142 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
5146 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5148 (* print_dirent_list function *)
5149 pr "static void print_dirent (struct guestfs_dirent *dirent)\n";
5154 pr " printf (\"%s: %%s\\n\", dirent->%s);\n" name name
5156 pr " printf (\"%s: %%\" PRIi64 \"\\n\", dirent->%s);\n" name name
5158 pr " printf (\"%s: %%c\\n\", dirent->%s);\n" name name
5162 pr "static void print_dirent_list (struct guestfs_dirent_list *dirents)\n";
5166 pr " for (i = 0; i < dirents->len; ++i)\n";
5167 pr " print_dirent (&dirents->val[i]);\n";
5171 (* run_<action> actions *)
5173 fun (name, style, _, flags, _, _, _) ->
5174 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
5176 (match fst style with
5179 | RBool _ -> pr " int r;\n"
5180 | RInt64 _ -> pr " int64_t r;\n"
5181 | RConstString _ -> pr " const char *r;\n"
5182 | RString _ -> pr " char *r;\n"
5183 | RStringList _ | RHashtable _ -> pr " char **r;\n"
5184 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
5185 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
5186 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
5187 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
5188 | RStat _ -> pr " struct guestfs_stat *r;\n"
5189 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
5190 | RDirentList _ -> pr " struct guestfs_dirent_list *r;\n"
5197 | FileOut n -> pr " const char *%s;\n" n
5198 | StringList n -> pr " char **%s;\n" n
5199 | Bool n -> pr " int %s;\n" n
5200 | Int n -> pr " int %s;\n" n
5203 (* Check and convert parameters. *)
5204 let argc_expected = List.length (snd style) in
5205 pr " if (argc != %d) {\n" argc_expected;
5206 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
5208 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
5214 | String name -> pr " %s = argv[%d];\n" name i
5216 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5219 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5222 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5224 | StringList name ->
5225 pr " %s = parse_string_list (argv[%d]);\n" name i
5227 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5229 pr " %s = atoi (argv[%d]);\n" name i
5232 (* Call C API function. *)
5234 try find_map (function FishAction n -> Some n | _ -> None) flags
5235 with Not_found -> sprintf "guestfs_%s" name in
5237 generate_call_args ~handle:"g" (snd style);
5240 (* Check return value for errors and display command results. *)
5241 (match fst style with
5242 | RErr -> pr " return r;\n"
5244 pr " if (r == -1) return -1;\n";
5245 pr " printf (\"%%d\\n\", r);\n";
5248 pr " if (r == -1) return -1;\n";
5249 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
5252 pr " if (r == -1) return -1;\n";
5253 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
5256 pr " if (r == NULL) return -1;\n";
5257 pr " printf (\"%%s\\n\", r);\n";
5260 pr " if (r == NULL) return -1;\n";
5261 pr " printf (\"%%s\\n\", r);\n";
5265 pr " if (r == NULL) return -1;\n";
5266 pr " print_strings (r);\n";
5267 pr " free_strings (r);\n";
5270 pr " if (r == NULL) return -1;\n";
5271 pr " printf (\"%%d, %%s\\n\", r->i,\n";
5272 pr " r->b ? \"true\" : \"false\");\n";
5273 pr " guestfs_free_int_bool (r);\n";
5276 pr " if (r == NULL) return -1;\n";
5277 pr " print_pv_list (r);\n";
5278 pr " guestfs_free_lvm_pv_list (r);\n";
5281 pr " if (r == NULL) return -1;\n";
5282 pr " print_vg_list (r);\n";
5283 pr " guestfs_free_lvm_vg_list (r);\n";
5286 pr " if (r == NULL) return -1;\n";
5287 pr " print_lv_list (r);\n";
5288 pr " guestfs_free_lvm_lv_list (r);\n";
5291 pr " if (r == NULL) return -1;\n";
5292 pr " print_stat (r);\n";
5296 pr " if (r == NULL) return -1;\n";
5297 pr " print_statvfs (r);\n";
5301 pr " if (r == NULL) return -1;\n";
5302 pr " print_table (r);\n";
5303 pr " free_strings (r);\n";
5306 pr " if (r == NULL) return -1;\n";
5307 pr " print_dirent_list (r);\n";
5308 pr " guestfs_free_dirent_list (r);\n";
5315 (* run_action function *)
5316 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
5319 fun (name, _, _, flags, _, _, _) ->
5320 let name2 = replace_char name '_' '-' in
5322 try find_map (function FishAlias n -> Some n | _ -> None) flags
5323 with Not_found -> name in
5325 pr "strcasecmp (cmd, \"%s\") == 0" name;
5326 if name <> name2 then
5327 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5328 if name <> alias then
5329 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5331 pr " return run_%s (cmd, argc, argv);\n" name;
5335 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
5342 (* Readline completion for guestfish. *)
5343 and generate_fish_completion () =
5344 generate_header CStyle GPLv2;
5348 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5358 #ifdef HAVE_LIBREADLINE
5359 #include <readline/readline.h>
5364 #ifdef HAVE_LIBREADLINE
5366 static const char *const commands[] = {
5367 BUILTIN_COMMANDS_FOR_COMPLETION,
5370 (* Get the commands, including the aliases. They don't need to be
5371 * sorted - the generator() function just does a dumb linear search.
5375 fun (name, _, _, flags, _, _, _) ->
5376 let name2 = replace_char name '_' '-' in
5378 try find_map (function FishAlias n -> Some n | _ -> None) flags
5379 with Not_found -> name in
5381 if name <> alias then [name2; alias] else [name2]
5383 let commands = List.flatten commands in
5385 List.iter (pr " \"%s\",\n") commands;
5391 generator (const char *text, int state)
5393 static int index, len;
5398 len = strlen (text);
5401 rl_attempted_completion_over = 1;
5403 while ((name = commands[index]) != NULL) {
5405 if (strncasecmp (name, text, len) == 0)
5406 return strdup (name);
5412 #endif /* HAVE_LIBREADLINE */
5414 char **do_completion (const char *text, int start, int end)
5416 char **matches = NULL;
5418 #ifdef HAVE_LIBREADLINE
5419 rl_completion_append_character = ' ';
5422 matches = rl_completion_matches (text, generator);
5423 else if (complete_dest_paths)
5424 matches = rl_completion_matches (text, complete_dest_paths_generator);
5431 (* Generate the POD documentation for guestfish. *)
5432 and generate_fish_actions_pod () =
5433 let all_functions_sorted =
5435 fun (_, _, _, flags, _, _, _) ->
5436 not (List.mem NotInFish flags || List.mem NotInDocs flags)
5437 ) all_functions_sorted in
5439 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
5442 fun (name, style, _, flags, _, _, longdesc) ->
5444 Str.global_substitute rex (
5447 try Str.matched_group 1 s
5449 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
5450 "C<" ^ replace_char sub '_' '-' ^ ">"
5452 let name = replace_char name '_' '-' in
5454 try find_map (function FishAlias n -> Some n | _ -> None) flags
5455 with Not_found -> name in
5457 pr "=head2 %s" name;
5458 if name <> alias then
5465 | String n -> pr " %s" n
5466 | OptString n -> pr " %s" n
5467 | StringList n -> pr " '%s ...'" n
5468 | Bool _ -> pr " true|false"
5469 | Int n -> pr " %s" n
5470 | FileIn n | FileOut n -> pr " (%s|-)" n
5474 pr "%s\n\n" longdesc;
5476 if List.exists (function FileIn _ | FileOut _ -> true
5477 | _ -> false) (snd style) then
5478 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5480 if List.mem ProtocolLimitWarning flags then
5481 pr "%s\n\n" protocol_limit_warning;
5483 if List.mem DangerWillRobinson flags then
5484 pr "%s\n\n" danger_will_robinson
5485 ) all_functions_sorted
5487 (* Generate a C function prototype. *)
5488 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5489 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5491 ?handle name style =
5492 if extern then pr "extern ";
5493 if static then pr "static ";
5494 (match fst style with
5496 | RInt _ -> pr "int "
5497 | RInt64 _ -> pr "int64_t "
5498 | RBool _ -> pr "int "
5499 | RConstString _ -> pr "const char *"
5500 | RString _ -> pr "char *"
5501 | RStringList _ | RHashtable _ -> pr "char **"
5503 if not in_daemon then pr "struct guestfs_int_bool *"
5504 else pr "guestfs_%s_ret *" name
5506 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
5507 else pr "guestfs_lvm_int_pv_list *"
5509 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
5510 else pr "guestfs_lvm_int_vg_list *"
5512 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
5513 else pr "guestfs_lvm_int_lv_list *"
5515 if not in_daemon then pr "struct guestfs_stat *"
5516 else pr "guestfs_int_stat *"
5518 if not in_daemon then pr "struct guestfs_statvfs *"
5519 else pr "guestfs_int_statvfs *"
5521 if not in_daemon then pr "struct guestfs_dirent_list *"
5522 else pr "guestfs_int_dirent_list *"
5524 pr "%s%s (" prefix name;
5525 if handle = None && List.length (snd style) = 0 then
5528 let comma = ref false in
5531 | Some handle -> pr "guestfs_h *%s" handle; comma := true
5535 if single_line then pr ", " else pr ",\n\t\t"
5544 if not in_daemon then pr "const char *%s" n
5545 else pr "char *%s" n
5548 if not in_daemon then pr "char * const* const %s" n
5549 else pr "char **%s" n
5550 | Bool n -> next (); pr "int %s" n
5551 | Int n -> next (); pr "int %s" n
5554 if not in_daemon then (next (); pr "const char *%s" n)
5558 if semicolon then pr ";";
5559 if newline then pr "\n"
5561 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5562 and generate_call_args ?handle args =
5564 let comma = ref false in
5567 | Some handle -> pr "%s" handle; comma := true
5571 if !comma then pr ", ";
5573 pr "%s" (name_of_argt arg)
5577 (* Generate the OCaml bindings interface. *)
5578 and generate_ocaml_mli () =
5579 generate_header OCamlStyle LGPLv2;
5582 (** For API documentation you should refer to the C API
5583 in the guestfs(3) manual page. The OCaml API uses almost
5584 exactly the same calls. *)
5587 (** A [guestfs_h] handle. *)
5589 exception Error of string
5590 (** This exception is raised when there is an error. *)
5592 val create : unit -> t
5594 val close : t -> unit
5595 (** Handles are closed by the garbage collector when they become
5596 unreferenced, but callers can also call this in order to
5597 provide predictable cleanup. *)
5600 generate_ocaml_lvm_structure_decls ();
5602 generate_ocaml_stat_structure_decls ();
5604 generate_ocaml_dirent_structure_decls ();
5608 fun (name, style, _, _, _, shortdesc, _) ->
5609 generate_ocaml_prototype name style;
5610 pr "(** %s *)\n" shortdesc;
5614 (* Generate the OCaml bindings implementation. *)
5615 and generate_ocaml_ml () =
5616 generate_header OCamlStyle LGPLv2;
5620 exception Error of string
5621 external create : unit -> t = \"ocaml_guestfs_create\"
5622 external close : t -> unit = \"ocaml_guestfs_close\"
5625 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
5629 generate_ocaml_lvm_structure_decls ();
5631 generate_ocaml_stat_structure_decls ();
5633 generate_ocaml_dirent_structure_decls ();
5637 fun (name, style, _, _, _, shortdesc, _) ->
5638 generate_ocaml_prototype ~is_external:true name style;
5641 (* Generate the OCaml bindings C implementation. *)
5642 and generate_ocaml_c () =
5643 generate_header CStyle LGPLv2;
5650 #include <caml/config.h>
5651 #include <caml/alloc.h>
5652 #include <caml/callback.h>
5653 #include <caml/fail.h>
5654 #include <caml/memory.h>
5655 #include <caml/mlvalues.h>
5656 #include <caml/signals.h>
5658 #include <guestfs.h>
5660 #include \"guestfs_c.h\"
5662 /* Copy a hashtable of string pairs into an assoc-list. We return
5663 * the list in reverse order, but hashtables aren't supposed to be
5666 static CAMLprim value
5667 copy_table (char * const * argv)
5670 CAMLlocal5 (rv, pairv, kv, vv, cons);
5674 for (i = 0; argv[i] != NULL; i += 2) {
5675 kv = caml_copy_string (argv[i]);
5676 vv = caml_copy_string (argv[i+1]);
5677 pairv = caml_alloc (2, 0);
5678 Store_field (pairv, 0, kv);
5679 Store_field (pairv, 1, vv);
5680 cons = caml_alloc (2, 0);
5681 Store_field (cons, 1, rv);
5683 Store_field (cons, 0, pairv);
5691 (* LVM struct copy functions. *)
5694 let has_optpercent_col =
5695 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
5697 pr "static CAMLprim value\n";
5698 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
5700 pr " CAMLparam0 ();\n";
5701 if has_optpercent_col then
5702 pr " CAMLlocal3 (rv, v, v2);\n"
5704 pr " CAMLlocal2 (rv, v);\n";
5706 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5711 pr " v = caml_copy_string (%s->%s);\n" typ name
5713 pr " v = caml_alloc_string (32);\n";
5714 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
5717 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5718 | name, `OptPercent ->
5719 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5720 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
5721 pr " v = caml_alloc (1, 0);\n";
5722 pr " Store_field (v, 0, v2);\n";
5723 pr " } else /* None */\n";
5724 pr " v = Val_int (0);\n";
5726 pr " Store_field (rv, %d, v);\n" i
5728 pr " CAMLreturn (rv);\n";
5732 pr "static CAMLprim value\n";
5733 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
5736 pr " CAMLparam0 ();\n";
5737 pr " CAMLlocal2 (rv, v);\n";
5740 pr " if (%ss->len == 0)\n" typ;
5741 pr " CAMLreturn (Atom (0));\n";
5743 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
5744 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
5745 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
5746 pr " caml_modify (&Field (rv, i), v);\n";
5748 pr " CAMLreturn (rv);\n";
5752 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5754 (* Stat copy functions. *)
5757 pr "static CAMLprim value\n";
5758 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5760 pr " CAMLparam0 ();\n";
5761 pr " CAMLlocal2 (rv, v);\n";
5763 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
5768 pr " v = caml_copy_int64 (%s->%s);\n" typ name
5770 pr " Store_field (rv, %d, v);\n" i
5772 pr " CAMLreturn (rv);\n";
5775 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5777 (* Dirent copy functions. *)
5778 pr "static CAMLprim value\n";
5779 pr "copy_dirent (const struct guestfs_dirent *dirent)\n";
5781 pr " CAMLparam0 ();\n";
5782 pr " CAMLlocal2 (rv, v);\n";
5784 pr " rv = caml_alloc (%d, 0);\n" (List.length dirent_cols);
5789 pr " v = caml_copy_string (dirent->%s);\n" name
5791 pr " v = caml_copy_int64 (dirent->%s);\n" name
5793 pr " v = Val_int (dirent->%s);\n" name
5795 pr " Store_field (rv, %d, v);\n" i
5797 pr " CAMLreturn (rv);\n";
5801 pr "static CAMLprim value\n";
5802 pr "copy_dirent_list (const struct guestfs_dirent_list *dirents)\n";
5804 pr " CAMLparam0 ();\n";
5805 pr " CAMLlocal2 (rv, v);\n";
5808 pr " if (dirents->len == 0)\n";
5809 pr " CAMLreturn (Atom (0));\n";
5811 pr " rv = caml_alloc (dirents->len, 0);\n";
5812 pr " for (i = 0; i < dirents->len; ++i) {\n";
5813 pr " v = copy_dirent (&dirents->val[i]);\n";
5814 pr " caml_modify (&Field (rv, i), v);\n";
5816 pr " CAMLreturn (rv);\n";
5823 fun (name, style, _, _, _, _, _) ->
5825 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5827 pr "CAMLprim value\n";
5828 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5829 List.iter (pr ", value %s") (List.tl params);
5834 | [p1; p2; p3; p4; p5] ->
5835 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
5836 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5837 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5838 pr " CAMLxparam%d (%s);\n"
5839 (List.length rest) (String.concat ", " rest)
5841 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5843 pr " CAMLlocal1 (rv);\n";
5846 pr " guestfs_h *g = Guestfs_val (gv);\n";
5847 pr " if (g == NULL)\n";
5848 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
5856 pr " const char *%s = String_val (%sv);\n" n n
5858 pr " const char *%s =\n" n;
5859 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5862 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5864 pr " int %s = Bool_val (%sv);\n" n n
5866 pr " int %s = Int_val (%sv);\n" n n
5869 match fst style with
5870 | RErr -> pr " int r;\n"; "-1"
5871 | RInt _ -> pr " int r;\n"; "-1"
5872 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5873 | RBool _ -> pr " int r;\n"; "-1"
5874 | RConstString _ -> pr " const char *r;\n"; "NULL"
5875 | RString _ -> pr " char *r;\n"; "NULL"
5881 pr " struct guestfs_int_bool *r;\n"; "NULL"
5883 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5885 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5887 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5889 pr " struct guestfs_stat *r;\n"; "NULL"
5891 pr " struct guestfs_statvfs *r;\n"; "NULL"
5897 pr " struct guestfs_dirent_list *r;\n"; "NULL" in
5900 pr " caml_enter_blocking_section ();\n";
5901 pr " r = guestfs_%s " name;
5902 generate_call_args ~handle:"g" (snd style);
5904 pr " caml_leave_blocking_section ();\n";
5909 pr " ocaml_guestfs_free_strings (%s);\n" n;
5910 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5913 pr " if (r == %s)\n" error_code;
5914 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5917 (match fst style with
5918 | RErr -> pr " rv = Val_unit;\n"
5919 | RInt _ -> pr " rv = Val_int (r);\n"
5921 pr " rv = caml_copy_int64 (r);\n"
5922 | RBool _ -> pr " rv = Val_bool (r);\n"
5923 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5925 pr " rv = caml_copy_string (r);\n";
5928 pr " rv = caml_copy_string_array ((const char **) r);\n";
5929 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5932 pr " rv = caml_alloc (2, 0);\n";
5933 pr " Store_field (rv, 0, Val_int (r->i));\n";
5934 pr " Store_field (rv, 1, Val_bool (r->b));\n";
5935 pr " guestfs_free_int_bool (r);\n";
5937 pr " rv = copy_lvm_pv_list (r);\n";
5938 pr " guestfs_free_lvm_pv_list (r);\n";
5940 pr " rv = copy_lvm_vg_list (r);\n";
5941 pr " guestfs_free_lvm_vg_list (r);\n";
5943 pr " rv = copy_lvm_lv_list (r);\n";
5944 pr " guestfs_free_lvm_lv_list (r);\n";
5946 pr " rv = copy_stat (r);\n";
5949 pr " rv = copy_statvfs (r);\n";
5952 pr " rv = copy_table (r);\n";
5953 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5956 pr " rv = copy_dirent_list (r);\n";
5957 pr " guestfs_free_dirent_list (r);\n";
5960 pr " CAMLreturn (rv);\n";
5964 if List.length params > 5 then (
5965 pr "CAMLprim value\n";
5966 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5968 pr " return ocaml_guestfs_%s (argv[0]" name;
5969 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5976 and generate_ocaml_lvm_structure_decls () =
5979 pr "type lvm_%s = {\n" typ;
5982 | name, `String -> pr " %s : string;\n" name
5983 | name, `UUID -> pr " %s : string;\n" name
5984 | name, `Bytes -> pr " %s : int64;\n" name
5985 | name, `Int -> pr " %s : int64;\n" name
5986 | name, `OptPercent -> pr " %s : float option;\n" name
5990 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5992 and generate_ocaml_stat_structure_decls () =
5995 pr "type %s = {\n" typ;
5998 | name, `Int -> pr " %s : int64;\n" name
6002 ) ["stat", stat_cols; "statvfs", statvfs_cols]
6004 and generate_ocaml_dirent_structure_decls () =
6005 pr "type dirent = {\n";
6008 | name, `Int -> pr " %s : int64;\n" name
6009 | name, `Char -> pr " %s : char;\n" name
6010 | name, `String -> pr " %s : string;\n" name
6015 and generate_ocaml_prototype ?(is_external = false) name style =
6016 if is_external then pr "external " else pr "val ";
6017 pr "%s : t -> " name;
6020 | String _ | FileIn _ | FileOut _ -> pr "string -> "
6021 | OptString _ -> pr "string option -> "
6022 | StringList _ -> pr "string array -> "
6023 | Bool _ -> pr "bool -> "
6024 | Int _ -> pr "int -> "
6026 (match fst style with
6027 | RErr -> pr "unit" (* all errors are turned into exceptions *)
6028 | RInt _ -> pr "int"
6029 | RInt64 _ -> pr "int64"
6030 | RBool _ -> pr "bool"
6031 | RConstString _ -> pr "string"
6032 | RString _ -> pr "string"
6033 | RStringList _ -> pr "string array"
6034 | RIntBool _ -> pr "int * bool"
6035 | RPVList _ -> pr "lvm_pv array"
6036 | RVGList _ -> pr "lvm_vg array"
6037 | RLVList _ -> pr "lvm_lv array"
6038 | RStat _ -> pr "stat"
6039 | RStatVFS _ -> pr "statvfs"
6040 | RHashtable _ -> pr "(string * string) list"
6041 | RDirentList _ -> pr "dirent array"
6043 if is_external then (
6045 if List.length (snd style) + 1 > 5 then
6046 pr "\"ocaml_guestfs_%s_byte\" " name;
6047 pr "\"ocaml_guestfs_%s\"" name
6051 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
6052 and generate_perl_xs () =
6053 generate_header CStyle LGPLv2;
6056 #include \"EXTERN.h\"
6060 #include <guestfs.h>
6063 #define PRId64 \"lld\"
6067 my_newSVll(long long val) {
6068 #ifdef USE_64_BIT_ALL
6069 return newSViv(val);
6073 len = snprintf(buf, 100, \"%%\" PRId64, val);
6074 return newSVpv(buf, len);
6079 #define PRIu64 \"llu\"
6083 my_newSVull(unsigned long long val) {
6084 #ifdef USE_64_BIT_ALL
6085 return newSVuv(val);
6089 len = snprintf(buf, 100, \"%%\" PRIu64, val);
6090 return newSVpv(buf, len);
6094 /* http://www.perlmonks.org/?node_id=680842 */
6096 XS_unpack_charPtrPtr (SV *arg) {
6101 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
6102 croak (\"array reference expected\");
6104 av = (AV *)SvRV (arg);
6105 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
6107 croak (\"malloc failed\");
6109 for (i = 0; i <= av_len (av); i++) {
6110 SV **elem = av_fetch (av, i, 0);
6112 if (!elem || !*elem)
6113 croak (\"missing element in list\");
6115 ret[i] = SvPV_nolen (*elem);
6123 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
6130 RETVAL = guestfs_create ();
6132 croak (\"could not create guestfs handle\");
6133 guestfs_set_error_handler (RETVAL, NULL, NULL);
6146 fun (name, style, _, _, _, _, _) ->
6147 (match fst style with
6148 | RErr -> pr "void\n"
6149 | RInt _ -> pr "SV *\n"
6150 | RInt64 _ -> pr "SV *\n"
6151 | RBool _ -> pr "SV *\n"
6152 | RConstString _ -> pr "SV *\n"
6153 | RString _ -> pr "SV *\n"
6156 | RPVList _ | RVGList _ | RLVList _
6157 | RStat _ | RStatVFS _
6160 pr "void\n" (* all lists returned implictly on the stack *)
6162 (* Call and arguments. *)
6164 generate_call_args ~handle:"g" (snd style);
6166 pr " guestfs_h *g;\n";
6170 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
6172 (* http://www.perlmonks.org/?node_id=554277
6173 * Note that the implicit handle argument means we have
6174 * to add 1 to the ST(x) operator.
6176 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
6177 | StringList n -> pr " char **%s;\n" n
6178 | Bool n -> pr " int %s;\n" n
6179 | Int n -> pr " int %s;\n" n
6182 let do_cleanups () =
6185 | String _ | OptString _ | Bool _ | Int _
6186 | FileIn _ | FileOut _ -> ()
6187 | StringList n -> pr " free (%s);\n" n
6192 (match fst style with
6197 pr " r = guestfs_%s " name;
6198 generate_call_args ~handle:"g" (snd style);
6201 pr " if (r == -1)\n";
6202 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6208 pr " %s = guestfs_%s " n name;
6209 generate_call_args ~handle:"g" (snd style);
6212 pr " if (%s == -1)\n" n;
6213 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6214 pr " RETVAL = newSViv (%s);\n" n;
6219 pr " int64_t %s;\n" n;
6221 pr " %s = guestfs_%s " n name;
6222 generate_call_args ~handle:"g" (snd style);
6225 pr " if (%s == -1)\n" n;
6226 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6227 pr " RETVAL = my_newSVll (%s);\n" n;
6232 pr " const char *%s;\n" n;
6234 pr " %s = guestfs_%s " n name;
6235 generate_call_args ~handle:"g" (snd style);
6238 pr " if (%s == NULL)\n" n;
6239 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6240 pr " RETVAL = newSVpv (%s, 0);\n" n;
6245 pr " char *%s;\n" n;
6247 pr " %s = guestfs_%s " n name;
6248 generate_call_args ~handle:"g" (snd style);
6251 pr " if (%s == NULL)\n" n;
6252 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6253 pr " RETVAL = newSVpv (%s, 0);\n" n;
6254 pr " free (%s);\n" n;
6257 | RStringList n | RHashtable n ->
6259 pr " char **%s;\n" n;
6262 pr " %s = guestfs_%s " n name;
6263 generate_call_args ~handle:"g" (snd style);
6266 pr " if (%s == NULL)\n" n;
6267 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6268 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6269 pr " EXTEND (SP, n);\n";
6270 pr " for (i = 0; i < n; ++i) {\n";
6271 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6272 pr " free (%s[i]);\n" n;
6274 pr " free (%s);\n" n;
6277 pr " struct guestfs_int_bool *r;\n";
6279 pr " r = guestfs_%s " name;
6280 generate_call_args ~handle:"g" (snd style);
6283 pr " if (r == NULL)\n";
6284 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6285 pr " EXTEND (SP, 2);\n";
6286 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
6287 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
6288 pr " guestfs_free_int_bool (r);\n";
6290 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
6292 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
6294 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
6296 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
6298 generate_perl_stat_code
6299 "statvfs" statvfs_cols name style n do_cleanups
6301 generate_perl_dirent_code
6302 "dirent" dirent_cols name style n do_cleanups
6308 and generate_perl_lvm_code typ cols name style n do_cleanups =
6310 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
6314 pr " %s = guestfs_%s " n name;
6315 generate_call_args ~handle:"g" (snd style);
6318 pr " if (%s == NULL)\n" n;
6319 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6320 pr " EXTEND (SP, %s->len);\n" n;
6321 pr " for (i = 0; i < %s->len; ++i) {\n" n;
6322 pr " hv = newHV ();\n";
6326 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6327 name (String.length name) n name
6329 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
6330 name (String.length name) n name
6332 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6333 name (String.length name) n name
6335 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
6336 name (String.length name) n name
6337 | name, `OptPercent ->
6338 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6339 name (String.length name) n name
6341 pr " PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
6343 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
6345 and generate_perl_stat_code typ cols name style n do_cleanups =
6347 pr " struct guestfs_%s *%s;\n" typ n;
6349 pr " %s = guestfs_%s " n name;
6350 generate_call_args ~handle:"g" (snd style);
6353 pr " if (%s == NULL)\n" n;
6354 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6355 pr " EXTEND (SP, %d);\n" (List.length cols);
6359 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
6361 pr " free (%s);\n" n
6363 and generate_perl_dirent_code typ cols name style n do_cleanups =
6365 pr " struct guestfs_%s_list *%s;\n" typ n;
6369 pr " %s = guestfs_%s " n name;
6370 generate_call_args ~handle:"g" (snd style);
6373 pr " if (%s == NULL)\n" n;
6374 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6375 pr " EXTEND (SP, %s->len);\n" n;
6376 pr " for (i = 0; i < %s->len; ++i) {\n" n;
6377 pr " hv = newHV ();\n";
6381 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6382 name (String.length name) n name
6384 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6385 name (String.length name) n name
6387 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
6388 name (String.length name) n name
6390 pr " PUSHs (newRV (sv_2mortal ((SV *) hv)));\n";
6392 pr " guestfs_free_%s_list (%s);\n" typ n
6394 (* Generate Sys/Guestfs.pm. *)
6395 and generate_perl_pm () =
6396 generate_header HashStyle LGPLv2;
6403 Sys::Guestfs - Perl bindings for libguestfs
6409 my $h = Sys::Guestfs->new ();
6410 $h->add_drive ('guest.img');
6413 $h->mount ('/dev/sda1', '/');
6414 $h->touch ('/hello');
6419 The C<Sys::Guestfs> module provides a Perl XS binding to the
6420 libguestfs API for examining and modifying virtual machine
6423 Amongst the things this is good for: making batch configuration
6424 changes to guests, getting disk used/free statistics (see also:
6425 virt-df), migrating between virtualization systems (see also:
6426 virt-p2v), performing partial backups, performing partial guest
6427 clones, cloning guests and changing registry/UUID/hostname info, and
6430 Libguestfs uses Linux kernel and qemu code, and can access any type of
6431 guest filesystem that Linux and qemu can, including but not limited
6432 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6433 schemes, qcow, qcow2, vmdk.
6435 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6436 LVs, what filesystem is in each LV, etc.). It can also run commands
6437 in the context of the guest. Also you can access filesystems over FTP.
6441 All errors turn into calls to C<croak> (see L<Carp(3)>).
6449 package Sys::Guestfs;
6455 XSLoader::load ('Sys::Guestfs');
6457 =item $h = Sys::Guestfs->new ();
6459 Create a new guestfs handle.
6465 my $class = ref ($proto) || $proto;
6467 my $self = Sys::Guestfs::_create ();
6468 bless $self, $class;
6474 (* Actions. We only need to print documentation for these as
6475 * they are pulled in from the XS code automatically.
6478 fun (name, style, _, flags, _, _, longdesc) ->
6479 if not (List.mem NotInDocs flags) then (
6480 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
6482 generate_perl_prototype name style;
6484 pr "%s\n\n" longdesc;
6485 if List.mem ProtocolLimitWarning flags then
6486 pr "%s\n\n" protocol_limit_warning;
6487 if List.mem DangerWillRobinson flags then
6488 pr "%s\n\n" danger_will_robinson
6490 ) all_functions_sorted;
6502 Copyright (C) 2009 Red Hat Inc.
6506 Please see the file COPYING.LIB for the full license.
6510 L<guestfs(3)>, L<guestfish(1)>.
6515 and generate_perl_prototype name style =
6516 (match fst style with
6522 | RString n -> pr "$%s = " n
6523 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
6528 | RDirentList n -> pr "@%s = " n
6531 | RHashtable n -> pr "%%%s = " n
6534 let comma = ref false in
6537 if !comma then pr ", ";
6540 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
6547 (* Generate Python C module. *)
6548 and generate_python_c () =
6549 generate_header CStyle LGPLv2;
6558 #include \"guestfs.h\"
6566 get_handle (PyObject *obj)
6569 assert (obj != Py_None);
6570 return ((Pyguestfs_Object *) obj)->g;
6574 put_handle (guestfs_h *g)
6578 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6581 /* This list should be freed (but not the strings) after use. */
6582 static const char **
6583 get_string_list (PyObject *obj)
6590 if (!PyList_Check (obj)) {
6591 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6595 len = PyList_Size (obj);
6596 r = malloc (sizeof (char *) * (len+1));
6598 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6602 for (i = 0; i < len; ++i)
6603 r[i] = PyString_AsString (PyList_GetItem (obj, i));
6610 put_string_list (char * const * const argv)
6615 for (argc = 0; argv[argc] != NULL; ++argc)
6618 list = PyList_New (argc);
6619 for (i = 0; i < argc; ++i)
6620 PyList_SetItem (list, i, PyString_FromString (argv[i]));
6626 put_table (char * const * const argv)
6628 PyObject *list, *item;
6631 for (argc = 0; argv[argc] != NULL; ++argc)
6634 list = PyList_New (argc >> 1);
6635 for (i = 0; i < argc; i += 2) {
6636 item = PyTuple_New (2);
6637 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
6638 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
6639 PyList_SetItem (list, i >> 1, item);
6646 free_strings (char **argv)
6650 for (argc = 0; argv[argc] != NULL; ++argc)
6656 py_guestfs_create (PyObject *self, PyObject *args)
6660 g = guestfs_create ();
6662 PyErr_SetString (PyExc_RuntimeError,
6663 \"guestfs.create: failed to allocate handle\");
6666 guestfs_set_error_handler (g, NULL, NULL);
6667 return put_handle (g);
6671 py_guestfs_close (PyObject *self, PyObject *args)
6676 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
6678 g = get_handle (py_g);
6682 Py_INCREF (Py_None);
6688 (* LVM structures, turned into Python dictionaries. *)
6691 pr "static PyObject *\n";
6692 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
6694 pr " PyObject *dict;\n";
6696 pr " dict = PyDict_New ();\n";
6700 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6701 pr " PyString_FromString (%s->%s));\n"
6704 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6705 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
6708 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6709 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
6712 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6713 pr " PyLong_FromLongLong (%s->%s));\n"
6715 | name, `OptPercent ->
6716 pr " if (%s->%s >= 0)\n" typ name;
6717 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6718 pr " PyFloat_FromDouble ((double) %s->%s));\n"
6721 pr " Py_INCREF (Py_None);\n";
6722 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
6725 pr " return dict;\n";
6729 pr "static PyObject *\n";
6730 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
6732 pr " PyObject *list;\n";
6735 pr " list = PyList_New (%ss->len);\n" typ;
6736 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
6737 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
6738 pr " return list;\n";
6741 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
6743 (* Stat structures, turned into Python dictionaries. *)
6746 pr "static PyObject *\n";
6747 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6749 pr " PyObject *dict;\n";
6751 pr " dict = PyDict_New ();\n";
6755 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6756 pr " PyLong_FromLongLong (%s->%s));\n"
6759 pr " return dict;\n";
6762 ) ["stat", stat_cols; "statvfs", statvfs_cols];
6764 (* Dirent structures, turned into Python dictionaries. *)
6765 pr "static PyObject *\n";
6766 pr "put_dirent (struct guestfs_dirent *dirent)\n";
6768 pr " PyObject *dict;\n";
6770 pr " dict = PyDict_New ();\n";
6774 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6775 pr " PyLong_FromLongLong (dirent->%s));\n" name
6777 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6778 pr " PyString_FromStringAndSize (&dirent->%s, 1));\n" name
6780 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
6781 pr " PyString_FromString (dirent->%s));\n" name
6783 pr " return dict;\n";
6787 pr "static PyObject *\n";
6788 pr "put_dirent_list (struct guestfs_dirent_list *dirents)\n";
6790 pr " PyObject *list;\n";
6793 pr " list = PyList_New (dirents->len);\n";
6794 pr " for (i = 0; i < dirents->len; ++i)\n";
6795 pr " PyList_SetItem (list, i, put_dirent (&dirents->val[i]));\n";
6796 pr " return list;\n";
6800 (* Python wrapper functions. *)
6802 fun (name, style, _, _, _, _, _) ->
6803 pr "static PyObject *\n";
6804 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6807 pr " PyObject *py_g;\n";
6808 pr " guestfs_h *g;\n";
6809 pr " PyObject *py_r;\n";
6812 match fst style with
6813 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6814 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6815 | RConstString _ -> pr " const char *r;\n"; "NULL"
6816 | RString _ -> pr " char *r;\n"; "NULL"
6817 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6818 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6819 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6820 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6821 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6822 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6823 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL"
6824 | RDirentList n -> pr " struct guestfs_dirent_list *r;\n"; "NULL" in
6828 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
6829 | OptString n -> pr " const char *%s;\n" n
6831 pr " PyObject *py_%s;\n" n;
6832 pr " const char **%s;\n" n
6833 | Bool n -> pr " int %s;\n" n
6834 | Int n -> pr " int %s;\n" n
6839 (* Convert the parameters. *)
6840 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
6843 | String _ | FileIn _ | FileOut _ -> pr "s"
6844 | OptString _ -> pr "z"
6845 | StringList _ -> pr "O"
6846 | Bool _ -> pr "i" (* XXX Python has booleans? *)
6849 pr ":guestfs_%s\",\n" name;
6853 | String n | FileIn n | FileOut n -> pr ", &%s" n
6854 | OptString n -> pr ", &%s" n
6855 | StringList n -> pr ", &py_%s" n
6856 | Bool n -> pr ", &%s" n
6857 | Int n -> pr ", &%s" n
6861 pr " return NULL;\n";
6863 pr " g = get_handle (py_g);\n";
6866 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6868 pr " %s = get_string_list (py_%s);\n" n n;
6869 pr " if (!%s) return NULL;\n" n
6874 pr " r = guestfs_%s " name;
6875 generate_call_args ~handle:"g" (snd style);
6880 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6882 pr " free (%s);\n" n
6885 pr " if (r == %s) {\n" error_code;
6886 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6887 pr " return NULL;\n";
6891 (match fst style with
6893 pr " Py_INCREF (Py_None);\n";
6894 pr " py_r = Py_None;\n"
6896 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
6897 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
6898 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
6900 pr " py_r = PyString_FromString (r);\n";
6903 pr " py_r = put_string_list (r);\n";
6904 pr " free_strings (r);\n"
6906 pr " py_r = PyTuple_New (2);\n";
6907 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
6908 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
6909 pr " guestfs_free_int_bool (r);\n"
6911 pr " py_r = put_lvm_pv_list (r);\n";
6912 pr " guestfs_free_lvm_pv_list (r);\n"
6914 pr " py_r = put_lvm_vg_list (r);\n";
6915 pr " guestfs_free_lvm_vg_list (r);\n"
6917 pr " py_r = put_lvm_lv_list (r);\n";
6918 pr " guestfs_free_lvm_lv_list (r);\n"
6920 pr " py_r = put_stat (r);\n";
6923 pr " py_r = put_statvfs (r);\n";
6926 pr " py_r = put_table (r);\n";
6927 pr " free_strings (r);\n"
6929 pr " py_r = put_dirent_list (r);\n";
6930 pr " guestfs_free_dirent_list (r);\n"
6933 pr " return py_r;\n";
6938 (* Table of functions. *)
6939 pr "static PyMethodDef methods[] = {\n";
6940 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6941 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6943 fun (name, _, _, _, _, _, _) ->
6944 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6947 pr " { NULL, NULL, 0, NULL }\n";
6951 (* Init function. *)
6954 initlibguestfsmod (void)
6956 static int initialized = 0;
6958 if (initialized) return;
6959 Py_InitModule ((char *) \"libguestfsmod\", methods);
6964 (* Generate Python module. *)
6965 and generate_python_py () =
6966 generate_header HashStyle LGPLv2;
6969 u\"\"\"Python bindings for libguestfs
6972 g = guestfs.GuestFS ()
6973 g.add_drive (\"guest.img\")
6976 parts = g.list_partitions ()
6978 The guestfs module provides a Python binding to the libguestfs API
6979 for examining and modifying virtual machine disk images.
6981 Amongst the things this is good for: making batch configuration
6982 changes to guests, getting disk used/free statistics (see also:
6983 virt-df), migrating between virtualization systems (see also:
6984 virt-p2v), performing partial backups, performing partial guest
6985 clones, cloning guests and changing registry/UUID/hostname info, and
6988 Libguestfs uses Linux kernel and qemu code, and can access any type of
6989 guest filesystem that Linux and qemu can, including but not limited
6990 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6991 schemes, qcow, qcow2, vmdk.
6993 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6994 LVs, what filesystem is in each LV, etc.). It can also run commands
6995 in the context of the guest. Also you can access filesystems over FTP.
6997 Errors which happen while using the API are turned into Python
6998 RuntimeError exceptions.
7000 To create a guestfs handle you usually have to perform the following
7003 # Create the handle, call add_drive at least once, and possibly
7004 # several times if the guest has multiple block devices:
7005 g = guestfs.GuestFS ()
7006 g.add_drive (\"guest.img\")
7008 # Launch the qemu subprocess and wait for it to become ready:
7012 # Now you can issue commands, for example:
7017 import libguestfsmod
7020 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
7022 def __init__ (self):
7023 \"\"\"Create a new libguestfs handle.\"\"\"
7024 self._o = libguestfsmod.create ()
7027 libguestfsmod.close (self._o)
7032 fun (name, style, _, flags, _, _, longdesc) ->
7034 generate_call_args ~handle:"self" (snd style);
7037 if not (List.mem NotInDocs flags) then (
7038 let doc = replace_str longdesc "C<guestfs_" "C<g." in
7040 match fst style with
7041 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
7044 doc ^ "\n\nThis function returns a list of strings."
7046 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
7048 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
7050 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
7052 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
7054 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
7056 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
7058 doc ^ "\n\nThis function returns a dictionary."
7060 doc ^ "\n\nThis function returns a list of directory entries. Each directory entry is represented as a dictionary." in
7062 if List.mem ProtocolLimitWarning flags then
7063 doc ^ "\n\n" ^ protocol_limit_warning
7066 if List.mem DangerWillRobinson flags then
7067 doc ^ "\n\n" ^ danger_will_robinson
7069 let doc = pod2text ~width:60 name doc in
7070 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
7071 let doc = String.concat "\n " doc in
7072 pr " u\"\"\"%s\"\"\"\n" doc;
7074 pr " return libguestfsmod.%s " name;
7075 generate_call_args ~handle:"self._o" (snd style);
7080 (* Useful if you need the longdesc POD text as plain text. Returns a
7083 * Because this is very slow (the slowest part of autogeneration),
7084 * we memoize the results.
7086 and pod2text ~width name longdesc =
7087 let key = width, name, longdesc in
7088 try Hashtbl.find pod2text_memo key
7090 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
7091 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
7093 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
7094 let chan = Unix.open_process_in cmd in
7095 let lines = ref [] in
7097 let line = input_line chan in
7098 if i = 1 then (* discard the first line of output *)
7101 let line = triml line in
7102 lines := line :: !lines;
7105 let lines = try loop 1 with End_of_file -> List.rev !lines in
7106 Unix.unlink filename;
7107 (match Unix.close_process_in chan with
7108 | Unix.WEXITED 0 -> ()
7110 failwithf "pod2text: process exited with non-zero status (%d)" i
7111 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
7112 failwithf "pod2text: process signalled or stopped by signal %d" i
7114 Hashtbl.add pod2text_memo key lines;
7115 let chan = open_out pod2text_memo_filename in
7116 output_value chan pod2text_memo;
7120 (* Generate ruby bindings. *)
7121 and generate_ruby_c () =
7122 generate_header CStyle LGPLv2;
7130 #include \"guestfs.h\"
7132 #include \"extconf.h\"
7134 /* For Ruby < 1.9 */
7136 #define RARRAY_LEN(r) (RARRAY((r))->len)
7139 static VALUE m_guestfs; /* guestfs module */
7140 static VALUE c_guestfs; /* guestfs_h handle */
7141 static VALUE e_Error; /* used for all errors */
7143 static void ruby_guestfs_free (void *p)
7146 guestfs_close ((guestfs_h *) p);
7149 static VALUE ruby_guestfs_create (VALUE m)
7153 g = guestfs_create ();
7155 rb_raise (e_Error, \"failed to create guestfs handle\");
7157 /* Don't print error messages to stderr by default. */
7158 guestfs_set_error_handler (g, NULL, NULL);
7160 /* Wrap it, and make sure the close function is called when the
7163 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
7166 static VALUE ruby_guestfs_close (VALUE gv)
7169 Data_Get_Struct (gv, guestfs_h, g);
7171 ruby_guestfs_free (g);
7172 DATA_PTR (gv) = NULL;
7180 fun (name, style, _, _, _, _, _) ->
7181 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
7182 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
7185 pr " guestfs_h *g;\n";
7186 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
7188 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
7194 | String n | FileIn n | FileOut n ->
7195 pr " Check_Type (%sv, T_STRING);\n" n;
7196 pr " const char *%s = StringValueCStr (%sv);\n" n n;
7198 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
7199 pr " \"%s\", \"%s\");\n" n name
7201 pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
7203 pr " char **%s;\n" n;
7204 pr " Check_Type (%sv, T_ARRAY);\n" n;
7206 pr " int i, len;\n";
7207 pr " len = RARRAY_LEN (%sv);\n" n;
7208 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
7210 pr " for (i = 0; i < len; ++i) {\n";
7211 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
7212 pr " %s[i] = StringValueCStr (v);\n" n;
7214 pr " %s[len] = NULL;\n" n;
7217 pr " int %s = RTEST (%sv);\n" n n
7219 pr " int %s = NUM2INT (%sv);\n" n n
7224 match fst style with
7225 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
7226 | RInt64 _ -> pr " int64_t r;\n"; "-1"
7227 | RConstString _ -> pr " const char *r;\n"; "NULL"
7228 | RString _ -> pr " char *r;\n"; "NULL"
7229 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
7230 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
7231 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
7232 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
7233 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
7234 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
7235 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL"
7236 | RDirentList n -> pr " struct guestfs_dirent_list *r;\n"; "NULL" in
7239 pr " r = guestfs_%s " name;
7240 generate_call_args ~handle:"g" (snd style);
7245 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7247 pr " free (%s);\n" n
7250 pr " if (r == %s)\n" error_code;
7251 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
7254 (match fst style with
7256 pr " return Qnil;\n"
7257 | RInt _ | RBool _ ->
7258 pr " return INT2NUM (r);\n"
7260 pr " return ULL2NUM (r);\n"
7262 pr " return rb_str_new2 (r);\n";
7264 pr " VALUE rv = rb_str_new2 (r);\n";
7268 pr " int i, len = 0;\n";
7269 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
7270 pr " VALUE rv = rb_ary_new2 (len);\n";
7271 pr " for (i = 0; r[i] != NULL; ++i) {\n";
7272 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
7273 pr " free (r[i]);\n";
7278 pr " VALUE rv = rb_ary_new2 (2);\n";
7279 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
7280 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
7281 pr " guestfs_free_int_bool (r);\n";
7284 generate_ruby_lvm_code "pv" pv_cols
7286 generate_ruby_lvm_code "vg" vg_cols
7288 generate_ruby_lvm_code "lv" lv_cols
7290 pr " VALUE rv = rb_hash_new ();\n";
7294 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7299 pr " VALUE rv = rb_hash_new ();\n";
7303 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7308 pr " VALUE rv = rb_hash_new ();\n";
7310 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
7311 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
7312 pr " free (r[i]);\n";
7313 pr " free (r[i+1]);\n";
7318 generate_ruby_dirent_code "dirent" dirent_cols
7326 /* Initialize the module. */
7327 void Init__guestfs ()
7329 m_guestfs = rb_define_module (\"Guestfs\");
7330 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
7331 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
7333 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
7334 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
7337 (* Define the rest of the methods. *)
7339 fun (name, style, _, _, _, _, _) ->
7340 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
7341 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
7346 (* Ruby code to return an LVM struct list. *)
7347 and generate_ruby_lvm_code typ cols =
7348 pr " VALUE rv = rb_ary_new2 (r->len);\n";
7350 pr " for (i = 0; i < r->len; ++i) {\n";
7351 pr " VALUE hv = rb_hash_new ();\n";
7355 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7357 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
7360 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7361 | name, `OptPercent ->
7362 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
7364 pr " rb_ary_push (rv, hv);\n";
7366 pr " guestfs_free_lvm_%s_list (r);\n" typ;
7369 (* Ruby code to return a dirent struct list. *)
7370 and generate_ruby_dirent_code typ cols =
7371 pr " VALUE rv = rb_ary_new2 (r->len);\n";
7373 pr " for (i = 0; i < r->len; ++i) {\n";
7374 pr " VALUE hv = rb_hash_new ();\n";
7378 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7379 | name, (`Char|`Int) ->
7380 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7382 pr " rb_ary_push (rv, hv);\n";
7384 pr " guestfs_free_%s_list (r);\n" typ;
7387 (* Generate Java bindings GuestFS.java file. *)
7388 and generate_java_java () =
7389 generate_header CStyle LGPLv2;
7392 package com.redhat.et.libguestfs;
7394 import java.util.HashMap;
7395 import com.redhat.et.libguestfs.LibGuestFSException;
7396 import com.redhat.et.libguestfs.PV;
7397 import com.redhat.et.libguestfs.VG;
7398 import com.redhat.et.libguestfs.LV;
7399 import com.redhat.et.libguestfs.Stat;
7400 import com.redhat.et.libguestfs.StatVFS;
7401 import com.redhat.et.libguestfs.IntBool;
7402 import com.redhat.et.libguestfs.Dirent;
7405 * The GuestFS object is a libguestfs handle.
7409 public class GuestFS {
7410 // Load the native code.
7412 System.loadLibrary (\"guestfs_jni\");
7416 * The native guestfs_h pointer.
7421 * Create a libguestfs handle.
7423 * @throws LibGuestFSException
7425 public GuestFS () throws LibGuestFSException
7429 private native long _create () throws LibGuestFSException;
7432 * Close a libguestfs handle.
7434 * You can also leave handles to be collected by the garbage
7435 * collector, but this method ensures that the resources used
7436 * by the handle are freed up immediately. If you call any
7437 * other methods after closing the handle, you will get an
7440 * @throws LibGuestFSException
7442 public void close () throws LibGuestFSException
7448 private native void _close (long g) throws LibGuestFSException;
7450 public void finalize () throws LibGuestFSException
7458 fun (name, style, _, flags, _, shortdesc, longdesc) ->
7459 if not (List.mem NotInDocs flags); then (
7460 let doc = replace_str longdesc "C<guestfs_" "C<g." in
7462 if List.mem ProtocolLimitWarning flags then
7463 doc ^ "\n\n" ^ protocol_limit_warning
7466 if List.mem DangerWillRobinson flags then
7467 doc ^ "\n\n" ^ danger_will_robinson
7469 let doc = pod2text ~width:60 name doc in
7470 let doc = List.map ( (* RHBZ#501883 *)
7473 | nonempty -> nonempty
7475 let doc = String.concat "\n * " doc in
7478 pr " * %s\n" shortdesc;
7481 pr " * @throws LibGuestFSException\n";
7485 generate_java_prototype ~public:true ~semicolon:false name style;
7488 pr " if (g == 0)\n";
7489 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
7492 if fst style <> RErr then pr "return ";
7494 generate_call_args ~handle:"g" (snd style);
7498 generate_java_prototype ~privat:true ~native:true name style;
7505 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
7506 ?(semicolon=true) name style =
7507 if privat then pr "private ";
7508 if public then pr "public ";
7509 if native then pr "native ";
7512 (match fst style with
7513 | RErr -> pr "void ";
7514 | RInt _ -> pr "int ";
7515 | RInt64 _ -> pr "long ";
7516 | RBool _ -> pr "boolean ";
7517 | RConstString _ | RString _ -> pr "String ";
7518 | RStringList _ -> pr "String[] ";
7519 | RIntBool _ -> pr "IntBool ";
7520 | RPVList _ -> pr "PV[] ";
7521 | RVGList _ -> pr "VG[] ";
7522 | RLVList _ -> pr "LV[] ";
7523 | RStat _ -> pr "Stat ";
7524 | RStatVFS _ -> pr "StatVFS ";
7525 | RHashtable _ -> pr "HashMap<String,String> ";
7526 | RDirentList _ -> pr "Dirent[] ";
7529 if native then pr "_%s " name else pr "%s " name;
7531 let needs_comma = ref false in
7540 if !needs_comma then pr ", ";
7541 needs_comma := true;
7558 pr " throws LibGuestFSException";
7559 if semicolon then pr ";"
7561 and generate_java_struct typ cols =
7562 generate_header CStyle LGPLv2;
7565 package com.redhat.et.libguestfs;
7568 * Libguestfs %s structure.
7579 | name, `UUID -> pr " public String %s;\n" name
7581 | name, `Int -> pr " public long %s;\n" name
7582 | name, `Char -> pr " public char %s;\n" name
7583 | name, `OptPercent ->
7584 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
7585 pr " public float %s;\n" name
7590 and generate_java_c () =
7591 generate_header CStyle LGPLv2;
7598 #include \"com_redhat_et_libguestfs_GuestFS.h\"
7599 #include \"guestfs.h\"
7601 /* Note that this function returns. The exception is not thrown
7602 * until after the wrapper function returns.
7605 throw_exception (JNIEnv *env, const char *msg)
7608 cl = (*env)->FindClass (env,
7609 \"com/redhat/et/libguestfs/LibGuestFSException\");
7610 (*env)->ThrowNew (env, cl, msg);
7613 JNIEXPORT jlong JNICALL
7614 Java_com_redhat_et_libguestfs_GuestFS__1create
7615 (JNIEnv *env, jobject obj)
7619 g = guestfs_create ();
7621 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
7624 guestfs_set_error_handler (g, NULL, NULL);
7625 return (jlong) (long) g;
7628 JNIEXPORT void JNICALL
7629 Java_com_redhat_et_libguestfs_GuestFS__1close
7630 (JNIEnv *env, jobject obj, jlong jg)
7632 guestfs_h *g = (guestfs_h *) (long) jg;
7639 fun (name, style, _, _, _, _, _) ->
7641 (match fst style with
7642 | RErr -> pr "void ";
7643 | RInt _ -> pr "jint ";
7644 | RInt64 _ -> pr "jlong ";
7645 | RBool _ -> pr "jboolean ";
7646 | RConstString _ | RString _ -> pr "jstring ";
7647 | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
7649 | RStringList _ | RPVList _ | RVGList _ | RLVList _ | RDirentList _ ->
7653 pr "Java_com_redhat_et_libguestfs_GuestFS_";
7654 pr "%s" (replace_str ("_" ^ name) "_" "_1");
7656 pr " (JNIEnv *env, jobject obj, jlong jg";
7663 pr ", jstring j%s" n
7665 pr ", jobjectArray j%s" n
7667 pr ", jboolean j%s" n
7673 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
7674 let error_code, no_ret =
7675 match fst style with
7676 | RErr -> pr " int r;\n"; "-1", ""
7678 | RInt _ -> pr " int r;\n"; "-1", "0"
7679 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
7680 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
7682 pr " jstring jr;\n";
7683 pr " char *r;\n"; "NULL", "NULL"
7685 pr " jobjectArray jr;\n";
7688 pr " jstring jstr;\n";
7689 pr " char **r;\n"; "NULL", "NULL"
7691 pr " jobject jr;\n";
7693 pr " jfieldID fl;\n";
7694 pr " struct guestfs_int_bool *r;\n"; "NULL", "NULL"
7696 pr " jobject jr;\n";
7698 pr " jfieldID fl;\n";
7699 pr " struct guestfs_stat *r;\n"; "NULL", "NULL"
7701 pr " jobject jr;\n";
7703 pr " jfieldID fl;\n";
7704 pr " struct guestfs_statvfs *r;\n"; "NULL", "NULL"
7706 pr " jobjectArray jr;\n";
7708 pr " jfieldID fl;\n";
7709 pr " jobject jfl;\n";
7710 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
7712 pr " jobjectArray jr;\n";
7714 pr " jfieldID fl;\n";
7715 pr " jobject jfl;\n";
7716 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
7718 pr " jobjectArray jr;\n";
7720 pr " jfieldID fl;\n";
7721 pr " jobject jfl;\n";
7722 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
7723 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL"
7725 pr " jobjectArray jr;\n";
7727 pr " jfieldID fl;\n";
7728 pr " jobject jfl;\n";
7729 pr " struct guestfs_dirent_list *r;\n"; "NULL", "NULL" in
7736 pr " const char *%s;\n" n
7738 pr " int %s_len;\n" n;
7739 pr " const char **%s;\n" n
7746 (match fst style with
7747 | RStringList _ | RPVList _ | RVGList _ | RLVList _
7748 | RDirentList _ -> true
7749 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
7750 | RString _ | RIntBool _ | RStat _ | RStatVFS _
7751 | RHashtable _ -> false) ||
7752 List.exists (function StringList _ -> true | _ -> false) (snd style) in
7758 (* Get the parameters. *)
7764 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
7766 (* This is completely undocumented, but Java null becomes
7769 pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
7771 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
7772 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
7773 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7774 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7776 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
7778 pr " %s[%s_len] = NULL;\n" n n;
7781 pr " %s = j%s;\n" n n
7784 (* Make the call. *)
7785 pr " r = guestfs_%s " name;
7786 generate_call_args ~handle:"g" (snd style);
7789 (* Release the parameters. *)
7795 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7798 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7800 pr " for (i = 0; i < %s_len; ++i) {\n" n;
7801 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7803 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
7805 pr " free (%s);\n" n
7810 (* Check for errors. *)
7811 pr " if (r == %s) {\n" error_code;
7812 pr " throw_exception (env, guestfs_last_error (g));\n";
7813 pr " return %s;\n" no_ret;
7817 (match fst style with
7819 | RInt _ -> pr " return (jint) r;\n"
7820 | RBool _ -> pr " return (jboolean) r;\n"
7821 | RInt64 _ -> pr " return (jlong) r;\n"
7822 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
7824 pr " jr = (*env)->NewStringUTF (env, r);\n";
7828 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7829 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7830 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
7831 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7832 pr " for (i = 0; i < r_len; ++i) {\n";
7833 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
7834 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7835 pr " free (r[i]);\n";
7840 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
7841 pr " jr = (*env)->AllocObject (env, cl);\n";
7842 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
7843 pr " (*env)->SetIntField (env, jr, fl, r->i);\n";
7844 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
7845 pr " (*env)->SetBooleanField (env, jr, fl, r->b);\n";
7846 pr " guestfs_free_int_bool (r);\n";
7849 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
7850 pr " jr = (*env)->AllocObject (env, cl);\n";
7854 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7856 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7861 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
7862 pr " jr = (*env)->AllocObject (env, cl);\n";
7866 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7868 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7873 generate_java_lvm_return "pv" "PV" pv_cols
7875 generate_java_lvm_return "vg" "VG" vg_cols
7877 generate_java_lvm_return "lv" "LV" lv_cols
7880 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7881 pr " return NULL;\n"
7883 generate_java_dirent_return "dirent" "Dirent" dirent_cols
7890 and generate_java_lvm_return typ jtyp cols =
7891 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7892 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7893 pr " for (i = 0; i < r->len; ++i) {\n";
7894 pr " jfl = (*env)->AllocObject (env, cl);\n";
7898 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7899 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7902 pr " char s[33];\n";
7903 pr " memcpy (s, r->val[i].%s, 32);\n" name;
7905 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7906 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7908 | name, (`Bytes|`Int) ->
7909 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7910 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7911 | name, `OptPercent ->
7912 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7913 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7915 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7917 pr " guestfs_free_lvm_%s_list (r);\n" typ;
7920 and generate_java_dirent_return typ jtyp cols =
7921 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7922 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7923 pr " for (i = 0; i < r->len; ++i) {\n";
7924 pr " jfl = (*env)->AllocObject (env, cl);\n";
7928 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7929 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7930 | name, (`Char|`Int) ->
7931 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7932 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7934 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7936 pr " guestfs_free_%s_list (r);\n" typ;
7939 and generate_haskell_hs () =
7940 generate_header HaskellStyle LGPLv2;
7942 (* XXX We only know how to generate partial FFI for Haskell
7943 * at the moment. Please help out!
7945 let can_generate style =
7949 | RInt64 _, _ -> true
7961 | RDirentList _, _ -> false in
7964 {-# INCLUDE <guestfs.h> #-}
7965 {-# LANGUAGE ForeignFunctionInterface #-}
7970 (* List out the names of the actions we want to export. *)
7972 fun (name, style, _, _, _, _, _) ->
7973 if can_generate style then pr ",\n %s" name
7980 import Foreign.C.Types
7982 import Control.Exception
7983 import Data.Typeable
7985 data GuestfsS = GuestfsS -- represents the opaque C struct
7986 type GuestfsP = Ptr GuestfsS -- guestfs_h *
7987 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7989 -- XXX define properly later XXX
7993 data IntBool = IntBool
7995 data StatVFS = StatVFS
7996 data Hashtable = Hashtable
7998 foreign import ccall unsafe \"guestfs_create\" c_create
8000 foreign import ccall unsafe \"&guestfs_close\" c_close
8001 :: FunPtr (GuestfsP -> IO ())
8002 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
8003 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
8005 create :: IO GuestfsH
8008 c_set_error_handler p nullPtr nullPtr
8009 h <- newForeignPtr c_close p
8012 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
8013 :: GuestfsP -> IO CString
8015 -- last_error :: GuestfsH -> IO (Maybe String)
8016 -- last_error h = do
8017 -- str <- withForeignPtr h (\\p -> c_last_error p)
8018 -- maybePeek peekCString str
8020 last_error :: GuestfsH -> IO (String)
8022 str <- withForeignPtr h (\\p -> c_last_error p)
8024 then return \"no error\"
8025 else peekCString str
8029 (* Generate wrappers for each foreign function. *)
8031 fun (name, style, _, _, _, _, _) ->
8032 if can_generate style then (
8033 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
8035 generate_haskell_prototype ~handle:"GuestfsP" style;
8039 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
8041 pr "%s %s = do\n" name
8042 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
8044 (* Convert pointer arguments using with* functions. *)
8049 | String n -> pr "withCString %s $ \\%s -> " n n
8050 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
8051 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
8052 | Bool _ | Int _ -> ()
8054 (* Convert integer arguments. *)
8058 | Bool n -> sprintf "(fromBool %s)" n
8059 | Int n -> sprintf "(fromIntegral %s)" n
8060 | FileIn n | FileOut n | String n | OptString n | StringList n -> n
8062 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
8063 (String.concat " " ("p" :: args));
8064 (match fst style with
8065 | RErr | RInt _ | RInt64 _ | RBool _ ->
8066 pr " if (r == -1)\n";
8068 pr " err <- last_error h\n";
8070 | RConstString _ | RString _ | RStringList _ | RIntBool _
8071 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
8072 | RHashtable _ | RDirentList _ ->
8073 pr " if (r == nullPtr)\n";
8075 pr " err <- last_error h\n";
8078 (match fst style with
8080 pr " else return ()\n"
8082 pr " else return (fromIntegral r)\n"
8084 pr " else return (fromIntegral r)\n"
8086 pr " else return (toBool r)\n"
8098 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
8104 and generate_haskell_prototype ~handle ?(hs = false) style =
8106 let string = if hs then "String" else "CString" in
8107 let int = if hs then "Int" else "CInt" in
8108 let bool = if hs then "Bool" else "CInt" in
8109 let int64 = if hs then "Integer" else "Int64" in
8113 | String _ -> pr "%s" string
8114 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
8115 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
8116 | Bool _ -> pr "%s" bool
8117 | Int _ -> pr "%s" int
8118 | FileIn _ -> pr "%s" string
8119 | FileOut _ -> pr "%s" string
8124 (match fst style with
8125 | RErr -> if not hs then pr "CInt"
8126 | RInt _ -> pr "%s" int
8127 | RInt64 _ -> pr "%s" int64
8128 | RBool _ -> pr "%s" bool
8129 | RConstString _ -> pr "%s" string
8130 | RString _ -> pr "%s" string
8131 | RStringList _ -> pr "[%s]" string
8132 | RIntBool _ -> pr "IntBool"
8133 | RPVList _ -> pr "[PV]"
8134 | RVGList _ -> pr "[VG]"
8135 | RLVList _ -> pr "[LV]"
8136 | RStat _ -> pr "Stat"
8137 | RStatVFS _ -> pr "StatVFS"
8138 | RHashtable _ -> pr "Hashtable"
8139 | RDirentList _ -> pr "[Dirent]"
8143 and generate_bindtests () =
8144 generate_header CStyle LGPLv2;
8149 #include <inttypes.h>
8152 #include \"guestfs.h\"
8153 #include \"guestfs_protocol.h\"
8155 #define error guestfs_error
8156 #define safe_calloc guestfs_safe_calloc
8157 #define safe_malloc guestfs_safe_malloc
8160 print_strings (char * const* const argv)
8165 for (argc = 0; argv[argc] != NULL; ++argc) {
8166 if (argc > 0) printf (\", \");
8167 printf (\"\\\"%%s\\\"\", argv[argc]);
8172 /* The test0 function prints its parameters to stdout. */
8176 match test_functions with
8177 | [] -> assert false
8178 | test0 :: tests -> test0, tests in
8181 let (name, style, _, _, _, _, _) = test0 in
8182 generate_prototype ~extern:false ~semicolon:false ~newline:true
8183 ~handle:"g" ~prefix:"guestfs_" name style;
8189 | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
8190 | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
8191 | StringList n -> pr " print_strings (%s);\n" n
8192 | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
8193 | Int n -> pr " printf (\"%%d\\n\", %s);\n" n
8195 pr " /* Java changes stdout line buffering so we need this: */\n";
8196 pr " fflush (stdout);\n";
8202 fun (name, style, _, _, _, _, _) ->
8203 if String.sub name (String.length name - 3) 3 <> "err" then (
8204 pr "/* Test normal return. */\n";
8205 generate_prototype ~extern:false ~semicolon:false ~newline:true
8206 ~handle:"g" ~prefix:"guestfs_" name style;
8208 (match fst style with
8213 pr " sscanf (val, \"%%d\", &r);\n";
8217 pr " sscanf (val, \"%%\" SCNi64, &r);\n";
8220 pr " return strcmp (val, \"true\") == 0;\n"
8222 (* Can't return the input string here. Return a static
8223 * string so we ensure we get a segfault if the caller
8226 pr " return \"static string\";\n"
8228 pr " return strdup (val);\n"
8230 pr " char **strs;\n";
8232 pr " sscanf (val, \"%%d\", &n);\n";
8233 pr " strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
8234 pr " for (i = 0; i < n; ++i) {\n";
8235 pr " strs[i] = safe_malloc (g, 16);\n";
8236 pr " snprintf (strs[i], 16, \"%%d\", i);\n";
8238 pr " strs[n] = NULL;\n";
8239 pr " return strs;\n"
8241 pr " struct guestfs_int_bool *r;\n";
8242 pr " r = safe_malloc (g, sizeof *r);\n";
8243 pr " sscanf (val, \"%%\" SCNi32, &r->i);\n";
8247 pr " struct guestfs_lvm_pv_list *r;\n";
8249 pr " r = safe_malloc (g, sizeof *r);\n";
8250 pr " sscanf (val, \"%%d\", &r->len);\n";
8251 pr " r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8252 pr " for (i = 0; i < r->len; ++i) {\n";
8253 pr " r->val[i].pv_name = safe_malloc (g, 16);\n";
8254 pr " snprintf (r->val[i].pv_name, 16, \"%%d\", i);\n";
8258 pr " struct guestfs_lvm_vg_list *r;\n";
8260 pr " r = safe_malloc (g, sizeof *r);\n";
8261 pr " sscanf (val, \"%%d\", &r->len);\n";
8262 pr " r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8263 pr " for (i = 0; i < r->len; ++i) {\n";
8264 pr " r->val[i].vg_name = safe_malloc (g, 16);\n";
8265 pr " snprintf (r->val[i].vg_name, 16, \"%%d\", i);\n";
8269 pr " struct guestfs_lvm_lv_list *r;\n";
8271 pr " r = safe_malloc (g, sizeof *r);\n";
8272 pr " sscanf (val, \"%%d\", &r->len);\n";
8273 pr " r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8274 pr " for (i = 0; i < r->len; ++i) {\n";
8275 pr " r->val[i].lv_name = safe_malloc (g, 16);\n";
8276 pr " snprintf (r->val[i].lv_name, 16, \"%%d\", i);\n";
8280 pr " struct guestfs_stat *r;\n";
8281 pr " r = safe_calloc (g, 1, sizeof (*r));\n";
8282 pr " sscanf (val, \"%%\" SCNi64, &r->dev);\n";
8285 pr " struct guestfs_statvfs *r;\n";
8286 pr " r = safe_calloc (g, 1, sizeof (*r));\n";
8287 pr " sscanf (val, \"%%\" SCNi64, &r->bsize);\n";
8290 pr " char **strs;\n";
8292 pr " sscanf (val, \"%%d\", &n);\n";
8293 pr " strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
8294 pr " for (i = 0; i < n; ++i) {\n";
8295 pr " strs[i*2] = safe_malloc (g, 16);\n";
8296 pr " strs[i*2+1] = safe_malloc (g, 16);\n";
8297 pr " snprintf (strs[i*2], 16, \"%%d\", i);\n";
8298 pr " snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
8300 pr " strs[n*2] = NULL;\n";
8301 pr " return strs;\n"
8303 pr " struct guestfs_dirent_list *r;\n";
8305 pr " r = safe_malloc (g, sizeof *r);\n";
8306 pr " sscanf (val, \"%%d\", &r->len);\n";
8307 pr " r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8308 pr " for (i = 0; i < r->len; ++i)\n";
8309 pr " r->val[i].ino = i;\n";
8315 pr "/* Test error return. */\n";
8316 generate_prototype ~extern:false ~semicolon:false ~newline:true
8317 ~handle:"g" ~prefix:"guestfs_" name style;
8319 pr " error (g, \"error\");\n";
8320 (match fst style with
8321 | RErr | RInt _ | RInt64 _ | RBool _ ->
8324 | RString _ | RStringList _ | RIntBool _
8325 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
8328 pr " return NULL;\n"
8335 and generate_ocaml_bindtests () =
8336 generate_header OCamlStyle GPLv2;
8340 let g = Guestfs.create () in
8347 | CallString s -> "\"" ^ s ^ "\""
8348 | CallOptString None -> "None"
8349 | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
8350 | CallStringList xs ->
8351 "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
8352 | CallInt i when i >= 0 -> string_of_int i
8353 | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
8354 | CallBool b -> string_of_bool b
8359 generate_lang_bindtests (
8360 fun f args -> pr " Guestfs.%s g %s;\n" f (mkargs args)
8363 pr "print_endline \"EOF\"\n"
8365 and generate_perl_bindtests () =
8366 pr "#!/usr/bin/perl -w\n";
8367 generate_header HashStyle GPLv2;
8374 my $g = Sys::Guestfs->new ();
8378 String.concat ", " (
8381 | CallString s -> "\"" ^ s ^ "\""
8382 | CallOptString None -> "undef"
8383 | CallOptString (Some s) -> sprintf "\"%s\"" s
8384 | CallStringList xs ->
8385 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8386 | CallInt i -> string_of_int i
8387 | CallBool b -> if b then "1" else "0"
8392 generate_lang_bindtests (
8393 fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
8396 pr "print \"EOF\\n\"\n"
8398 and generate_python_bindtests () =
8399 generate_header HashStyle GPLv2;
8404 g = guestfs.GuestFS ()
8408 String.concat ", " (
8411 | CallString s -> "\"" ^ s ^ "\""
8412 | CallOptString None -> "None"
8413 | CallOptString (Some s) -> sprintf "\"%s\"" s
8414 | CallStringList xs ->
8415 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8416 | CallInt i -> string_of_int i
8417 | CallBool b -> if b then "1" else "0"
8422 generate_lang_bindtests (
8423 fun f args -> pr "g.%s (%s)\n" f (mkargs args)
8426 pr "print \"EOF\"\n"
8428 and generate_ruby_bindtests () =
8429 generate_header HashStyle GPLv2;
8434 g = Guestfs::create()
8438 String.concat ", " (
8441 | CallString s -> "\"" ^ s ^ "\""
8442 | CallOptString None -> "nil"
8443 | CallOptString (Some s) -> sprintf "\"%s\"" s
8444 | CallStringList xs ->
8445 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8446 | CallInt i -> string_of_int i
8447 | CallBool b -> string_of_bool b
8452 generate_lang_bindtests (
8453 fun f args -> pr "g.%s(%s)\n" f (mkargs args)
8456 pr "print \"EOF\\n\"\n"
8458 and generate_java_bindtests () =
8459 generate_header CStyle GPLv2;
8462 import com.redhat.et.libguestfs.*;
8464 public class Bindtests {
8465 public static void main (String[] argv)
8468 GuestFS g = new GuestFS ();
8472 String.concat ", " (
8475 | CallString s -> "\"" ^ s ^ "\""
8476 | CallOptString None -> "null"
8477 | CallOptString (Some s) -> sprintf "\"%s\"" s
8478 | CallStringList xs ->
8480 String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
8481 | CallInt i -> string_of_int i
8482 | CallBool b -> string_of_bool b
8487 generate_lang_bindtests (
8488 fun f args -> pr " g.%s (%s);\n" f (mkargs args)
8492 System.out.println (\"EOF\");
8494 catch (Exception exn) {
8495 System.err.println (exn);
8502 and generate_haskell_bindtests () =
8503 generate_header HaskellStyle GPLv2;
8506 module Bindtests where
8507 import qualified Guestfs
8517 | CallString s -> "\"" ^ s ^ "\""
8518 | CallOptString None -> "Nothing"
8519 | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
8520 | CallStringList xs ->
8521 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8522 | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
8523 | CallInt i -> string_of_int i
8524 | CallBool true -> "True"
8525 | CallBool false -> "False"
8530 generate_lang_bindtests (
8531 fun f args -> pr " Guestfs.%s g %s\n" f (mkargs args)
8534 pr " putStrLn \"EOF\"\n"
8536 (* Language-independent bindings tests - we do it this way to
8537 * ensure there is parity in testing bindings across all languages.
8539 and generate_lang_bindtests call =
8540 call "test0" [CallString "abc"; CallOptString (Some "def");
8541 CallStringList []; CallBool false;
8542 CallInt 0; CallString "123"; CallString "456"];
8543 call "test0" [CallString "abc"; CallOptString None;
8544 CallStringList []; CallBool false;
8545 CallInt 0; CallString "123"; CallString "456"];
8546 call "test0" [CallString ""; CallOptString (Some "def");
8547 CallStringList []; CallBool false;
8548 CallInt 0; CallString "123"; CallString "456"];
8549 call "test0" [CallString ""; CallOptString (Some "");
8550 CallStringList []; CallBool false;
8551 CallInt 0; CallString "123"; CallString "456"];
8552 call "test0" [CallString "abc"; CallOptString (Some "def");
8553 CallStringList ["1"]; CallBool false;
8554 CallInt 0; CallString "123"; CallString "456"];
8555 call "test0" [CallString "abc"; CallOptString (Some "def");
8556 CallStringList ["1"; "2"]; CallBool false;
8557 CallInt 0; CallString "123"; CallString "456"];
8558 call "test0" [CallString "abc"; CallOptString (Some "def");
8559 CallStringList ["1"]; CallBool true;
8560 CallInt 0; CallString "123"; CallString "456"];
8561 call "test0" [CallString "abc"; CallOptString (Some "def");
8562 CallStringList ["1"]; CallBool false;
8563 CallInt (-1); CallString "123"; CallString "456"];
8564 call "test0" [CallString "abc"; CallOptString (Some "def");
8565 CallStringList ["1"]; CallBool false;
8566 CallInt (-2); CallString "123"; CallString "456"];
8567 call "test0" [CallString "abc"; CallOptString (Some "def");
8568 CallStringList ["1"]; CallBool false;
8569 CallInt 1; CallString "123"; CallString "456"];
8570 call "test0" [CallString "abc"; CallOptString (Some "def");
8571 CallStringList ["1"]; CallBool false;
8572 CallInt 2; CallString "123"; CallString "456"];
8573 call "test0" [CallString "abc"; CallOptString (Some "def");
8574 CallStringList ["1"]; CallBool false;
8575 CallInt 4095; CallString "123"; CallString "456"];
8576 call "test0" [CallString "abc"; CallOptString (Some "def");
8577 CallStringList ["1"]; CallBool false;
8578 CallInt 0; CallString ""; CallString ""]
8580 (* XXX Add here tests of the return and error functions. *)
8582 (* This is used to generate the src/MAX_PROC_NR file which
8583 * contains the maximum procedure number, a surrogate for the
8584 * ABI version number. See src/Makefile.am for the details.
8586 and generate_max_proc_nr () =
8587 let proc_nrs = List.map (
8588 fun (_, _, proc_nr, _, _, _, _) -> proc_nr
8589 ) daemon_functions in
8591 let max_proc_nr = List.fold_left max 0 proc_nrs in
8593 pr "%d\n" max_proc_nr
8595 let output_to filename =
8596 let filename_new = filename ^ ".new" in
8597 chan := open_out filename_new;
8602 (* Is the new file different from the current file? *)
8603 if Sys.file_exists filename && files_equal filename filename_new then
8604 Unix.unlink filename_new (* same, so skip it *)
8606 (* different, overwrite old one *)
8607 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
8608 Unix.rename filename_new filename;
8609 Unix.chmod filename 0o444;
8610 printf "written %s\n%!" filename;
8619 if not (Sys.file_exists "config.status") then (
8621 You are probably running this from the wrong directory.
8622 Run it from the top source directory using the command
8628 let close = output_to "src/guestfs_protocol.x" in
8632 let close = output_to "src/guestfs-structs.h" in
8633 generate_structs_h ();
8636 let close = output_to "src/guestfs-actions.h" in
8637 generate_actions_h ();
8640 let close = output_to "src/guestfs-actions.c" in
8641 generate_client_actions ();
8644 let close = output_to "daemon/actions.h" in
8645 generate_daemon_actions_h ();
8648 let close = output_to "daemon/stubs.c" in
8649 generate_daemon_actions ();
8652 let close = output_to "daemon/names.c" in
8653 generate_daemon_names ();
8656 let close = output_to "capitests/tests.c" in
8660 let close = output_to "src/guestfs-bindtests.c" in
8661 generate_bindtests ();
8664 let close = output_to "fish/cmds.c" in
8665 generate_fish_cmds ();
8668 let close = output_to "fish/completion.c" in
8669 generate_fish_completion ();
8672 let close = output_to "guestfs-structs.pod" in
8673 generate_structs_pod ();
8676 let close = output_to "guestfs-actions.pod" in
8677 generate_actions_pod ();
8680 let close = output_to "guestfish-actions.pod" in
8681 generate_fish_actions_pod ();
8684 let close = output_to "ocaml/guestfs.mli" in
8685 generate_ocaml_mli ();
8688 let close = output_to "ocaml/guestfs.ml" in
8689 generate_ocaml_ml ();
8692 let close = output_to "ocaml/guestfs_c_actions.c" in
8693 generate_ocaml_c ();
8696 let close = output_to "ocaml/bindtests.ml" in
8697 generate_ocaml_bindtests ();
8700 let close = output_to "perl/Guestfs.xs" in
8701 generate_perl_xs ();
8704 let close = output_to "perl/lib/Sys/Guestfs.pm" in
8705 generate_perl_pm ();
8708 let close = output_to "perl/bindtests.pl" in
8709 generate_perl_bindtests ();
8712 let close = output_to "python/guestfs-py.c" in
8713 generate_python_c ();
8716 let close = output_to "python/guestfs.py" in
8717 generate_python_py ();
8720 let close = output_to "python/bindtests.py" in
8721 generate_python_bindtests ();
8724 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
8728 let close = output_to "ruby/bindtests.rb" in
8729 generate_ruby_bindtests ();
8732 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
8733 generate_java_java ();
8736 let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
8737 generate_java_struct "PV" pv_cols;
8740 let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
8741 generate_java_struct "VG" vg_cols;
8744 let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
8745 generate_java_struct "LV" lv_cols;
8748 let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
8749 generate_java_struct "Stat" stat_cols;
8752 let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
8753 generate_java_struct "StatVFS" statvfs_cols;
8756 let close = output_to "java/com/redhat/et/libguestfs/Dirent.java" in
8757 generate_java_struct "Dirent" dirent_cols;
8760 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
8764 let close = output_to "java/Bindtests.java" in
8765 generate_java_bindtests ();
8768 let close = output_to "haskell/Guestfs.hs" in
8769 generate_haskell_hs ();
8772 let close = output_to "haskell/Bindtests.hs" in
8773 generate_haskell_bindtests ();
8776 let close = output_to "src/MAX_PROC_NR" in
8777 generate_max_proc_nr ();
8780 (* Always generate this file last, and unconditionally. It's used
8781 * by the Makefile to know when we must re-run the generator.
8783 let chan = open_out "src/stamp-generator" in