3 * Copyright (C) 2009 Red Hat Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 (* This script generates a large amount of code and documentation for
21 * all the daemon actions.
23 * To add a new action there are only two files you need to change,
24 * this one to describe the interface (see the big table below), and
25 * daemon/<somefile>.c to write the implementation.
27 * After editing this file, run it (./src/generator.ml) to regenerate
28 * all the output files.
30 * IMPORTANT: This script should NOT print any warnings. If it prints
31 * warnings, you should treat them as errors.
32 * [Need to add -warn-error to ocaml command line]
40 type style = ret * args
42 (* "RErr" as a return value means an int used as a simple error
43 * indication, ie. 0 or -1.
46 (* "RInt" as a return value means an int which is -1 for error
47 * or any value >= 0 on success. Only use this for smallish
48 * positive ints (0 <= i < 2^30).
51 (* "RInt64" is the same as RInt, but is guaranteed to be able
52 * to return a full 64 bit value, _except_ that -1 means error
53 * (so -1 cannot be a valid, non-error return value).
56 (* "RBool" is a bool return value which can be true/false or
60 (* "RConstString" is a string that refers to a constant value.
61 * Try to avoid using this. In particular you cannot use this
62 * for values returned from the daemon, because there is no
63 * thread-safe way to return them in the C API.
65 | RConstString of string
66 (* "RString" and "RStringList" are caller-frees. *)
68 | RStringList of string
69 (* Some limited tuples are possible: *)
70 | RIntBool of string * string
71 (* LVM PVs, VGs and LVs. *)
78 (* Key-value pairs of untyped strings. Turns into a hashtable or
79 * dictionary in languages which support it. DON'T use this as a
80 * general "bucket" for results. Prefer a stronger typed return
81 * value if one is available, or write a custom struct. Don't use
82 * this if the list could potentially be very long, since it is
83 * inefficient. Keys should be unique. NULLs are not permitted.
85 | RHashtable of string
87 and args = argt list (* Function parameters, guestfs handle is implicit. *)
89 (* Note in future we should allow a "variable args" parameter as
90 * the final parameter, to allow commands like
91 * chmod mode file [file(s)...]
92 * This is not implemented yet, but many commands (such as chmod)
93 * are currently defined with the argument order keeping this future
94 * possibility in mind.
97 | String of string (* const char *name, cannot be NULL *)
98 | OptString of string (* const char *name, may be NULL *)
99 | StringList of string(* list of strings (each string cannot be NULL) *)
100 | Bool of string (* boolean *)
101 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
102 (* These are treated as filenames (simple string parameters) in
103 * the C API and bindings. But in the RPC protocol, we transfer
104 * the actual file content up to or down from the daemon.
105 * FileIn: local machine -> daemon (in request)
106 * FileOut: daemon -> local machine (in reply)
107 * In guestfish (only), the special name "-" means read from
108 * stdin or write to stdout.
114 | ProtocolLimitWarning (* display warning about protocol size limits *)
115 | DangerWillRobinson (* flags particularly dangerous commands *)
116 | FishAlias of string (* provide an alias for this cmd in guestfish *)
117 | FishAction of string (* call this function in guestfish *)
118 | NotInFish (* do not export via guestfish *)
120 let protocol_limit_warning =
121 "Because of the message protocol, there is a transfer limit
122 of somewhere between 2MB and 4MB. To transfer large files you should use
125 let danger_will_robinson =
126 "B<This command is dangerous. Without careful use you
127 can easily destroy all your data>."
129 (* You can supply zero or as many tests as you want per API call.
131 * Note that the test environment has 3 block devices, of size 500MB,
132 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc).
133 * Note for partitioning purposes, the 500MB device has 63 cylinders.
135 * To be able to run the tests in a reasonable amount of time,
136 * the virtual machine and block devices are reused between tests.
137 * So don't try testing kill_subprocess :-x
139 * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
141 * If the appliance is running an older Linux kernel (eg. RHEL 5) then
142 * devices are named /dev/hda etc. To cope with this, the test suite
143 * adds some hairly logic to detect this case, and then automagically
144 * replaces all strings which match "/dev/sd.*" with "/dev/hd.*".
145 * When writing test cases you shouldn't have to worry about this
148 * Don't assume anything about the previous contents of the block
149 * devices. Use 'Init*' to create some initial scenarios.
151 * You can add a prerequisite clause to any individual test. This
152 * is a run-time check, which, if it fails, causes the test to be
153 * skipped. Useful if testing a command which might not work on
154 * all variations of libguestfs builds. A test that has prerequisite
155 * of 'Always' is run unconditionally.
157 * In addition, packagers can skip individual tests by setting the
158 * environment variables: eg:
159 * SKIP_TEST_<CMD>_<NUM>=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command)
160 * SKIP_TEST_<CMD>=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests)
162 type tests = (test_init * test_prereq * test) list
164 (* Run the command sequence and just expect nothing to fail. *)
166 (* Run the command sequence and expect the output of the final
167 * command to be the string.
169 | TestOutput of seq * string
170 (* Run the command sequence and expect the output of the final
171 * command to be the list of strings.
173 | TestOutputList of seq * string list
174 (* Run the command sequence and expect the output of the final
175 * command to be the integer.
177 | TestOutputInt of seq * int
178 (* Run the command sequence and expect the output of the final
179 * command to be a true value (!= 0 or != NULL).
181 | TestOutputTrue of seq
182 (* Run the command sequence and expect the output of the final
183 * command to be a false value (== 0 or == NULL, but not an error).
185 | TestOutputFalse of seq
186 (* Run the command sequence and expect the output of the final
187 * command to be a list of the given length (but don't care about
190 | TestOutputLength of seq * int
191 (* Run the command sequence and expect the output of the final
192 * command to be a structure.
194 | TestOutputStruct of seq * test_field_compare list
195 (* Run the command sequence and expect the final command (only)
198 | TestLastFail of seq
200 and test_field_compare =
201 | CompareWithInt of string * int
202 | CompareWithString of string * string
203 | CompareFieldsIntEq of string * string
204 | CompareFieldsStrEq of string * string
206 (* Test prerequisites. *)
208 (* Test always runs. *)
210 (* Test is currently disabled - eg. it fails, or it tests some
211 * unimplemented feature.
214 (* 'string' is some C code (a function body) that should return
215 * true or false. The test will run if the code returns true.
218 (* As for 'If' but the test runs _unless_ the code returns true. *)
221 (* Some initial scenarios for testing. *)
223 (* Do nothing, block devices could contain random stuff including
224 * LVM PVs, and some filesystems might be mounted. This is usually
228 (* Block devices are empty and no filesystems are mounted. *)
230 (* /dev/sda contains a single partition /dev/sda1, which is formatted
231 * as ext2, empty [except for lost+found] and mounted on /.
232 * /dev/sdb and /dev/sdc may have random content.
237 * /dev/sda1 (is a PV):
238 * /dev/VG/LV (size 8MB):
239 * formatted as ext2, empty [except for lost+found], mounted on /
240 * /dev/sdb and /dev/sdc may have random content.
244 (* Sequence of commands for testing. *)
246 and cmd = string list
248 (* Note about long descriptions: When referring to another
249 * action, use the format C<guestfs_other> (ie. the full name of
250 * the C function). This will be replaced as appropriate in other
253 * Apart from that, long descriptions are just perldoc paragraphs.
256 let non_daemon_functions = [
257 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
259 "launch the qemu subprocess",
261 Internally libguestfs is implemented by running a virtual machine
264 You should call this after configuring the handle
265 (eg. adding drives) but before performing any actions.");
267 ("wait_ready", (RErr, []), -1, [NotInFish],
269 "wait until the qemu subprocess launches",
271 Internally libguestfs is implemented by running a virtual machine
274 You should call this after C<guestfs_launch> to wait for the launch
277 ("kill_subprocess", (RErr, []), -1, [],
279 "kill the qemu subprocess",
281 This kills the qemu subprocess. You should never need to call this.");
283 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
285 "add an image to examine or modify",
287 This function adds a virtual machine disk image C<filename> to the
288 guest. The first time you call this function, the disk appears as IDE
289 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
292 You don't necessarily need to be root when using libguestfs. However
293 you obviously do need sufficient permissions to access the filename
294 for whatever operations you want to perform (ie. read access if you
295 just want to read the image or write access if you want to modify the
298 This is equivalent to the qemu parameter C<-drive file=filename>.");
300 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
302 "add a CD-ROM disk image to examine",
304 This function adds a virtual CD-ROM disk image to the guest.
306 This is equivalent to the qemu parameter C<-cdrom filename>.");
308 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
310 "add qemu parameters",
312 This can be used to add arbitrary qemu command line parameters
313 of the form C<-param value>. Actually it's not quite arbitrary - we
314 prevent you from setting some parameters which would interfere with
315 parameters that we use.
317 The first character of C<param> string must be a C<-> (dash).
319 C<value> can be NULL.");
321 ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
323 "set the qemu binary",
325 Set the qemu binary that we will use.
327 The default is chosen when the library was compiled by the
330 You can also override this by setting the C<LIBGUESTFS_QEMU>
331 environment variable.
333 Setting C<qemu> to C<NULL> restores the default qemu binary.");
335 ("get_qemu", (RConstString "qemu", []), -1, [],
337 "get the qemu binary",
339 Return the current qemu binary.
341 This is always non-NULL. If it wasn't set already, then this will
342 return the default qemu binary name.");
344 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
346 "set the search path",
348 Set the path that libguestfs searches for kernel and initrd.img.
350 The default is C<$libdir/guestfs> unless overridden by setting
351 C<LIBGUESTFS_PATH> environment variable.
353 Setting C<path> to C<NULL> restores the default path.");
355 ("get_path", (RConstString "path", []), -1, [],
357 "get the search path",
359 Return the current search path.
361 This is always non-NULL. If it wasn't set already, then this will
362 return the default path.");
364 ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
366 "add options to kernel command line",
368 This function is used to add additional options to the
369 guest kernel command line.
371 The default is C<NULL> unless overridden by setting
372 C<LIBGUESTFS_APPEND> environment variable.
374 Setting C<append> to C<NULL> means I<no> additional options
375 are passed (libguestfs always adds a few of its own).");
377 ("get_append", (RConstString "append", []), -1, [],
379 "get the additional kernel options",
381 Return the additional kernel options which are added to the
382 guest kernel command line.
384 If C<NULL> then no options are added.");
386 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
390 If C<autosync> is true, this enables autosync. Libguestfs will make a
391 best effort attempt to run C<guestfs_umount_all> followed by
392 C<guestfs_sync> when the handle is closed
393 (also if the program exits without closing handles).
395 This is disabled by default (except in guestfish where it is
396 enabled by default).");
398 ("get_autosync", (RBool "autosync", []), -1, [],
402 Get the autosync flag.");
404 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
408 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
410 Verbose messages are disabled unless the environment variable
411 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
413 ("get_verbose", (RBool "verbose", []), -1, [],
417 This returns the verbose messages flag.");
419 ("is_ready", (RBool "ready", []), -1, [],
421 "is ready to accept commands",
423 This returns true iff this handle is ready to accept commands
424 (in the C<READY> state).
426 For more information on states, see L<guestfs(3)>.");
428 ("is_config", (RBool "config", []), -1, [],
430 "is in configuration state",
432 This returns true iff this handle is being configured
433 (in the C<CONFIG> state).
435 For more information on states, see L<guestfs(3)>.");
437 ("is_launching", (RBool "launching", []), -1, [],
439 "is launching subprocess",
441 This returns true iff this handle is launching the subprocess
442 (in the C<LAUNCHING> state).
444 For more information on states, see L<guestfs(3)>.");
446 ("is_busy", (RBool "busy", []), -1, [],
448 "is busy processing a command",
450 This returns true iff this handle is busy processing a command
451 (in the C<BUSY> state).
453 For more information on states, see L<guestfs(3)>.");
455 ("get_state", (RInt "state", []), -1, [],
457 "get the current state",
459 This returns the current state as an opaque integer. This is
460 only useful for printing debug and internal error messages.
462 For more information on states, see L<guestfs(3)>.");
464 ("set_busy", (RErr, []), -1, [NotInFish],
468 This sets the state to C<BUSY>. This is only used when implementing
469 actions using the low-level API.
471 For more information on states, see L<guestfs(3)>.");
473 ("set_ready", (RErr, []), -1, [NotInFish],
475 "set state to ready",
477 This sets the state to C<READY>. This is only used when implementing
478 actions using the low-level API.
480 For more information on states, see L<guestfs(3)>.");
482 ("end_busy", (RErr, []), -1, [NotInFish],
484 "leave the busy state",
486 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
487 state as is. This is only used when implementing
488 actions using the low-level API.
490 For more information on states, see L<guestfs(3)>.");
494 let daemon_functions = [
495 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
496 [InitEmpty, Always, TestOutput (
497 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
498 ["mkfs"; "ext2"; "/dev/sda1"];
499 ["mount"; "/dev/sda1"; "/"];
500 ["write_file"; "/new"; "new file contents"; "0"];
501 ["cat"; "/new"]], "new file contents")],
502 "mount a guest disk at a position in the filesystem",
504 Mount a guest disk at a position in the filesystem. Block devices
505 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
506 the guest. If those block devices contain partitions, they will have
507 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
510 The rules are the same as for L<mount(2)>: A filesystem must
511 first be mounted on C</> before others can be mounted. Other
512 filesystems can only be mounted on directories which already
515 The mounted filesystem is writable, if we have sufficient permissions
516 on the underlying device.
518 The filesystem options C<sync> and C<noatime> are set with this
519 call, in order to improve reliability.");
521 ("sync", (RErr, []), 2, [],
522 [ InitEmpty, Always, TestRun [["sync"]]],
523 "sync disks, writes are flushed through to the disk image",
525 This syncs the disk, so that any writes are flushed through to the
526 underlying disk image.
528 You should always call this if you have modified a disk image, before
529 closing the handle.");
531 ("touch", (RErr, [String "path"]), 3, [],
532 [InitBasicFS, Always, TestOutputTrue (
534 ["exists"; "/new"]])],
535 "update file timestamps or create a new file",
537 Touch acts like the L<touch(1)> command. It can be used to
538 update the timestamps on a file, or, if the file does not exist,
539 to create a new zero-length file.");
541 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
542 [InitBasicFS, Always, TestOutput (
543 [["write_file"; "/new"; "new file contents"; "0"];
544 ["cat"; "/new"]], "new file contents")],
545 "list the contents of a file",
547 Return the contents of the file named C<path>.
549 Note that this function cannot correctly handle binary files
550 (specifically, files containing C<\\0> character which is treated
551 as end of string). For those you need to use the C<guestfs_download>
552 function which has a more complex interface.");
554 ("ll", (RString "listing", [String "directory"]), 5, [],
555 [], (* XXX Tricky to test because it depends on the exact format
556 * of the 'ls -l' command, which changes between F10 and F11.
558 "list the files in a directory (long format)",
560 List the files in C<directory> (relative to the root directory,
561 there is no cwd) in the format of 'ls -la'.
563 This command is mostly useful for interactive sessions. It
564 is I<not> intended that you try to parse the output string.");
566 ("ls", (RStringList "listing", [String "directory"]), 6, [],
567 [InitBasicFS, Always, TestOutputList (
570 ["touch"; "/newest"];
571 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
572 "list the files in a directory",
574 List the files in C<directory> (relative to the root directory,
575 there is no cwd). The '.' and '..' entries are not returned, but
576 hidden files are shown.
578 This command is mostly useful for interactive sessions. Programs
579 should probably use C<guestfs_readdir> instead.");
581 ("list_devices", (RStringList "devices", []), 7, [],
582 [InitEmpty, Always, TestOutputList (
583 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
584 "list the block devices",
586 List all the block devices.
588 The full block device names are returned, eg. C</dev/sda>");
590 ("list_partitions", (RStringList "partitions", []), 8, [],
591 [InitBasicFS, Always, TestOutputList (
592 [["list_partitions"]], ["/dev/sda1"]);
593 InitEmpty, Always, TestOutputList (
594 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
595 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
596 "list the partitions",
598 List all the partitions detected on all block devices.
600 The full partition device names are returned, eg. C</dev/sda1>
602 This does not return logical volumes. For that you will need to
603 call C<guestfs_lvs>.");
605 ("pvs", (RStringList "physvols", []), 9, [],
606 [InitBasicFSonLVM, Always, TestOutputList (
607 [["pvs"]], ["/dev/sda1"]);
608 InitEmpty, Always, TestOutputList (
609 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
610 ["pvcreate"; "/dev/sda1"];
611 ["pvcreate"; "/dev/sda2"];
612 ["pvcreate"; "/dev/sda3"];
613 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
614 "list the LVM physical volumes (PVs)",
616 List all the physical volumes detected. This is the equivalent
617 of the L<pvs(8)> command.
619 This returns a list of just the device names that contain
620 PVs (eg. C</dev/sda2>).
622 See also C<guestfs_pvs_full>.");
624 ("vgs", (RStringList "volgroups", []), 10, [],
625 [InitBasicFSonLVM, Always, TestOutputList (
627 InitEmpty, Always, TestOutputList (
628 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
629 ["pvcreate"; "/dev/sda1"];
630 ["pvcreate"; "/dev/sda2"];
631 ["pvcreate"; "/dev/sda3"];
632 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
633 ["vgcreate"; "VG2"; "/dev/sda3"];
634 ["vgs"]], ["VG1"; "VG2"])],
635 "list the LVM volume groups (VGs)",
637 List all the volumes groups detected. This is the equivalent
638 of the L<vgs(8)> command.
640 This returns a list of just the volume group names that were
641 detected (eg. C<VolGroup00>).
643 See also C<guestfs_vgs_full>.");
645 ("lvs", (RStringList "logvols", []), 11, [],
646 [InitBasicFSonLVM, Always, TestOutputList (
647 [["lvs"]], ["/dev/VG/LV"]);
648 InitEmpty, Always, TestOutputList (
649 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
650 ["pvcreate"; "/dev/sda1"];
651 ["pvcreate"; "/dev/sda2"];
652 ["pvcreate"; "/dev/sda3"];
653 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
654 ["vgcreate"; "VG2"; "/dev/sda3"];
655 ["lvcreate"; "LV1"; "VG1"; "50"];
656 ["lvcreate"; "LV2"; "VG1"; "50"];
657 ["lvcreate"; "LV3"; "VG2"; "50"];
658 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
659 "list the LVM logical volumes (LVs)",
661 List all the logical volumes detected. This is the equivalent
662 of the L<lvs(8)> command.
664 This returns a list of the logical volume device names
665 (eg. C</dev/VolGroup00/LogVol00>).
667 See also C<guestfs_lvs_full>.");
669 ("pvs_full", (RPVList "physvols", []), 12, [],
670 [], (* XXX how to test? *)
671 "list the LVM physical volumes (PVs)",
673 List all the physical volumes detected. This is the equivalent
674 of the L<pvs(8)> command. The \"full\" version includes all fields.");
676 ("vgs_full", (RVGList "volgroups", []), 13, [],
677 [], (* XXX how to test? *)
678 "list the LVM volume groups (VGs)",
680 List all the volumes groups detected. This is the equivalent
681 of the L<vgs(8)> command. The \"full\" version includes all fields.");
683 ("lvs_full", (RLVList "logvols", []), 14, [],
684 [], (* XXX how to test? *)
685 "list the LVM logical volumes (LVs)",
687 List all the logical volumes detected. This is the equivalent
688 of the L<lvs(8)> command. The \"full\" version includes all fields.");
690 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
691 [InitBasicFS, Always, TestOutputList (
692 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
693 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
694 InitBasicFS, Always, TestOutputList (
695 [["write_file"; "/new"; ""; "0"];
696 ["read_lines"; "/new"]], [])],
697 "read file as lines",
699 Return the contents of the file named C<path>.
701 The file contents are returned as a list of lines. Trailing
702 C<LF> and C<CRLF> character sequences are I<not> returned.
704 Note that this function cannot correctly handle binary files
705 (specifically, files containing C<\\0> character which is treated
706 as end of line). For those you need to use the C<guestfs_read_file>
707 function which has a more complex interface.");
709 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
710 [], (* XXX Augeas code needs tests. *)
711 "create a new Augeas handle",
713 Create a new Augeas handle for editing configuration files.
714 If there was any previous Augeas handle associated with this
715 guestfs session, then it is closed.
717 You must call this before using any other C<guestfs_aug_*>
720 C<root> is the filesystem root. C<root> must not be NULL,
723 The flags are the same as the flags defined in
724 E<lt>augeas.hE<gt>, the logical I<or> of the following
729 =item C<AUG_SAVE_BACKUP> = 1
731 Keep the original file with a C<.augsave> extension.
733 =item C<AUG_SAVE_NEWFILE> = 2
735 Save changes into a file with extension C<.augnew>, and
736 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
738 =item C<AUG_TYPE_CHECK> = 4
740 Typecheck lenses (can be expensive).
742 =item C<AUG_NO_STDINC> = 8
744 Do not use standard load path for modules.
746 =item C<AUG_SAVE_NOOP> = 16
748 Make save a no-op, just record what would have been changed.
750 =item C<AUG_NO_LOAD> = 32
752 Do not load the tree in C<guestfs_aug_init>.
756 To close the handle, you can call C<guestfs_aug_close>.
758 To find out more about Augeas, see L<http://augeas.net/>.");
760 ("aug_close", (RErr, []), 26, [],
761 [], (* XXX Augeas code needs tests. *)
762 "close the current Augeas handle",
764 Close the current Augeas handle and free up any resources
765 used by it. After calling this, you have to call
766 C<guestfs_aug_init> again before you can use any other
769 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
770 [], (* XXX Augeas code needs tests. *)
771 "define an Augeas variable",
773 Defines an Augeas variable C<name> whose value is the result
774 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
777 On success this returns the number of nodes in C<expr>, or
778 C<0> if C<expr> evaluates to something which is not a nodeset.");
780 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
781 [], (* XXX Augeas code needs tests. *)
782 "define an Augeas node",
784 Defines a variable C<name> whose value is the result of
787 If C<expr> evaluates to an empty nodeset, a node is created,
788 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
789 C<name> will be the nodeset containing that single node.
791 On success this returns a pair containing the
792 number of nodes in the nodeset, and a boolean flag
793 if a node was created.");
795 ("aug_get", (RString "val", [String "path"]), 19, [],
796 [], (* XXX Augeas code needs tests. *)
797 "look up the value of an Augeas path",
799 Look up the value associated with C<path>. If C<path>
800 matches exactly one node, the C<value> is returned.");
802 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
803 [], (* XXX Augeas code needs tests. *)
804 "set Augeas path to value",
806 Set the value associated with C<path> to C<value>.");
808 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
809 [], (* XXX Augeas code needs tests. *)
810 "insert a sibling Augeas node",
812 Create a new sibling C<label> for C<path>, inserting it into
813 the tree before or after C<path> (depending on the boolean
816 C<path> must match exactly one existing node in the tree, and
817 C<label> must be a label, ie. not contain C</>, C<*> or end
818 with a bracketed index C<[N]>.");
820 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
821 [], (* XXX Augeas code needs tests. *)
822 "remove an Augeas path",
824 Remove C<path> and all of its children.
826 On success this returns the number of entries which were removed.");
828 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
829 [], (* XXX Augeas code needs tests. *)
832 Move the node C<src> to C<dest>. C<src> must match exactly
833 one node. C<dest> is overwritten if it exists.");
835 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
836 [], (* XXX Augeas code needs tests. *)
837 "return Augeas nodes which match path",
839 Returns a list of paths which match the path expression C<path>.
840 The returned paths are sufficiently qualified so that they match
841 exactly one node in the current tree.");
843 ("aug_save", (RErr, []), 25, [],
844 [], (* XXX Augeas code needs tests. *)
845 "write all pending Augeas changes to disk",
847 This writes all pending changes to disk.
849 The flags which were passed to C<guestfs_aug_init> affect exactly
850 how files are saved.");
852 ("aug_load", (RErr, []), 27, [],
853 [], (* XXX Augeas code needs tests. *)
854 "load files into the tree",
856 Load files into the tree.
858 See C<aug_load> in the Augeas documentation for the full gory
861 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
862 [], (* XXX Augeas code needs tests. *)
863 "list Augeas nodes under a path",
865 This is just a shortcut for listing C<guestfs_aug_match>
866 C<path/*> and sorting the resulting nodes into alphabetical order.");
868 ("rm", (RErr, [String "path"]), 29, [],
869 [InitBasicFS, Always, TestRun
872 InitBasicFS, Always, TestLastFail
874 InitBasicFS, Always, TestLastFail
879 Remove the single file C<path>.");
881 ("rmdir", (RErr, [String "path"]), 30, [],
882 [InitBasicFS, Always, TestRun
885 InitBasicFS, Always, TestLastFail
887 InitBasicFS, Always, TestLastFail
890 "remove a directory",
892 Remove the single directory C<path>.");
894 ("rm_rf", (RErr, [String "path"]), 31, [],
895 [InitBasicFS, Always, TestOutputFalse
897 ["mkdir"; "/new/foo"];
898 ["touch"; "/new/foo/bar"];
900 ["exists"; "/new"]]],
901 "remove a file or directory recursively",
903 Remove the file or directory C<path>, recursively removing the
904 contents if its a directory. This is like the C<rm -rf> shell
907 ("mkdir", (RErr, [String "path"]), 32, [],
908 [InitBasicFS, Always, TestOutputTrue
911 InitBasicFS, Always, TestLastFail
912 [["mkdir"; "/new/foo/bar"]]],
913 "create a directory",
915 Create a directory named C<path>.");
917 ("mkdir_p", (RErr, [String "path"]), 33, [],
918 [InitBasicFS, Always, TestOutputTrue
919 [["mkdir_p"; "/new/foo/bar"];
920 ["is_dir"; "/new/foo/bar"]];
921 InitBasicFS, Always, TestOutputTrue
922 [["mkdir_p"; "/new/foo/bar"];
923 ["is_dir"; "/new/foo"]];
924 InitBasicFS, Always, TestOutputTrue
925 [["mkdir_p"; "/new/foo/bar"];
926 ["is_dir"; "/new"]]],
927 "create a directory and parents",
929 Create a directory named C<path>, creating any parent directories
930 as necessary. This is like the C<mkdir -p> shell command.");
932 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
933 [], (* XXX Need stat command to test *)
936 Change the mode (permissions) of C<path> to C<mode>. Only
937 numeric modes are supported.");
939 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
940 [], (* XXX Need stat command to test *)
941 "change file owner and group",
943 Change the file owner to C<owner> and group to C<group>.
945 Only numeric uid and gid are supported. If you want to use
946 names, you will need to locate and parse the password file
947 yourself (Augeas support makes this relatively easy).");
949 ("exists", (RBool "existsflag", [String "path"]), 36, [],
950 [InitBasicFS, Always, TestOutputTrue (
952 ["exists"; "/new"]]);
953 InitBasicFS, Always, TestOutputTrue (
955 ["exists"; "/new"]])],
956 "test if file or directory exists",
958 This returns C<true> if and only if there is a file, directory
959 (or anything) with the given C<path> name.
961 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
963 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
964 [InitBasicFS, Always, TestOutputTrue (
966 ["is_file"; "/new"]]);
967 InitBasicFS, Always, TestOutputFalse (
969 ["is_file"; "/new"]])],
970 "test if file exists",
972 This returns C<true> if and only if there is a file
973 with the given C<path> name. Note that it returns false for
974 other objects like directories.
976 See also C<guestfs_stat>.");
978 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
979 [InitBasicFS, Always, TestOutputFalse (
981 ["is_dir"; "/new"]]);
982 InitBasicFS, Always, TestOutputTrue (
984 ["is_dir"; "/new"]])],
985 "test if file exists",
987 This returns C<true> if and only if there is a directory
988 with the given C<path> name. Note that it returns false for
989 other objects like files.
991 See also C<guestfs_stat>.");
993 ("pvcreate", (RErr, [String "device"]), 39, [],
994 [InitEmpty, Always, TestOutputList (
995 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
996 ["pvcreate"; "/dev/sda1"];
997 ["pvcreate"; "/dev/sda2"];
998 ["pvcreate"; "/dev/sda3"];
999 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1000 "create an LVM physical volume",
1002 This creates an LVM physical volume on the named C<device>,
1003 where C<device> should usually be a partition name such
1006 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1007 [InitEmpty, Always, TestOutputList (
1008 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1009 ["pvcreate"; "/dev/sda1"];
1010 ["pvcreate"; "/dev/sda2"];
1011 ["pvcreate"; "/dev/sda3"];
1012 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1013 ["vgcreate"; "VG2"; "/dev/sda3"];
1014 ["vgs"]], ["VG1"; "VG2"])],
1015 "create an LVM volume group",
1017 This creates an LVM volume group called C<volgroup>
1018 from the non-empty list of physical volumes C<physvols>.");
1020 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1021 [InitEmpty, Always, TestOutputList (
1022 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1023 ["pvcreate"; "/dev/sda1"];
1024 ["pvcreate"; "/dev/sda2"];
1025 ["pvcreate"; "/dev/sda3"];
1026 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1027 ["vgcreate"; "VG2"; "/dev/sda3"];
1028 ["lvcreate"; "LV1"; "VG1"; "50"];
1029 ["lvcreate"; "LV2"; "VG1"; "50"];
1030 ["lvcreate"; "LV3"; "VG2"; "50"];
1031 ["lvcreate"; "LV4"; "VG2"; "50"];
1032 ["lvcreate"; "LV5"; "VG2"; "50"];
1034 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1035 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1036 "create an LVM volume group",
1038 This creates an LVM volume group called C<logvol>
1039 on the volume group C<volgroup>, with C<size> megabytes.");
1041 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1042 [InitEmpty, Always, TestOutput (
1043 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1044 ["mkfs"; "ext2"; "/dev/sda1"];
1045 ["mount"; "/dev/sda1"; "/"];
1046 ["write_file"; "/new"; "new file contents"; "0"];
1047 ["cat"; "/new"]], "new file contents")],
1048 "make a filesystem",
1050 This creates a filesystem on C<device> (usually a partition
1051 or LVM logical volume). The filesystem type is C<fstype>, for
1054 ("sfdisk", (RErr, [String "device";
1055 Int "cyls"; Int "heads"; Int "sectors";
1056 StringList "lines"]), 43, [DangerWillRobinson],
1058 "create partitions on a block device",
1060 This is a direct interface to the L<sfdisk(8)> program for creating
1061 partitions on block devices.
1063 C<device> should be a block device, for example C</dev/sda>.
1065 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1066 and sectors on the device, which are passed directly to sfdisk as
1067 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
1068 of these, then the corresponding parameter is omitted. Usually for
1069 'large' disks, you can just pass C<0> for these, but for small
1070 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1071 out the right geometry and you will need to tell it.
1073 C<lines> is a list of lines that we feed to C<sfdisk>. For more
1074 information refer to the L<sfdisk(8)> manpage.
1076 To create a single partition occupying the whole disk, you would
1077 pass C<lines> as a single element list, when the single element being
1078 the string C<,> (comma).
1080 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1082 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1083 [InitBasicFS, Always, TestOutput (
1084 [["write_file"; "/new"; "new file contents"; "0"];
1085 ["cat"; "/new"]], "new file contents");
1086 InitBasicFS, Always, TestOutput (
1087 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1088 ["cat"; "/new"]], "\nnew file contents\n");
1089 InitBasicFS, Always, TestOutput (
1090 [["write_file"; "/new"; "\n\n"; "0"];
1091 ["cat"; "/new"]], "\n\n");
1092 InitBasicFS, Always, TestOutput (
1093 [["write_file"; "/new"; ""; "0"];
1094 ["cat"; "/new"]], "");
1095 InitBasicFS, Always, TestOutput (
1096 [["write_file"; "/new"; "\n\n\n"; "0"];
1097 ["cat"; "/new"]], "\n\n\n");
1098 InitBasicFS, Always, TestOutput (
1099 [["write_file"; "/new"; "\n"; "0"];
1100 ["cat"; "/new"]], "\n")],
1103 This call creates a file called C<path>. The contents of the
1104 file is the string C<content> (which can contain any 8 bit data),
1105 with length C<size>.
1107 As a special case, if C<size> is C<0>
1108 then the length is calculated using C<strlen> (so in this case
1109 the content cannot contain embedded ASCII NULs).
1111 I<NB.> Owing to a bug, writing content containing ASCII NUL
1112 characters does I<not> work, even if the length is specified.
1113 We hope to resolve this bug in a future version. In the meantime
1114 use C<guestfs_upload>.");
1116 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1117 [InitEmpty, Always, TestOutputList (
1118 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1119 ["mkfs"; "ext2"; "/dev/sda1"];
1120 ["mount"; "/dev/sda1"; "/"];
1121 ["mounts"]], ["/dev/sda1"]);
1122 InitEmpty, Always, TestOutputList (
1123 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1124 ["mkfs"; "ext2"; "/dev/sda1"];
1125 ["mount"; "/dev/sda1"; "/"];
1128 "unmount a filesystem",
1130 This unmounts the given filesystem. The filesystem may be
1131 specified either by its mountpoint (path) or the device which
1132 contains the filesystem.");
1134 ("mounts", (RStringList "devices", []), 46, [],
1135 [InitBasicFS, Always, TestOutputList (
1136 [["mounts"]], ["/dev/sda1"])],
1137 "show mounted filesystems",
1139 This returns the list of currently mounted filesystems. It returns
1140 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1142 Some internal mounts are not shown.");
1144 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1145 [InitBasicFS, Always, TestOutputList (
1148 (* check that umount_all can unmount nested mounts correctly: *)
1149 InitEmpty, Always, TestOutputList (
1150 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1151 ["mkfs"; "ext2"; "/dev/sda1"];
1152 ["mkfs"; "ext2"; "/dev/sda2"];
1153 ["mkfs"; "ext2"; "/dev/sda3"];
1154 ["mount"; "/dev/sda1"; "/"];
1156 ["mount"; "/dev/sda2"; "/mp1"];
1157 ["mkdir"; "/mp1/mp2"];
1158 ["mount"; "/dev/sda3"; "/mp1/mp2"];
1159 ["mkdir"; "/mp1/mp2/mp3"];
1162 "unmount all filesystems",
1164 This unmounts all mounted filesystems.
1166 Some internal mounts are not unmounted by this call.");
1168 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1170 "remove all LVM LVs, VGs and PVs",
1172 This command removes all LVM logical volumes, volume groups
1173 and physical volumes.");
1175 ("file", (RString "description", [String "path"]), 49, [],
1176 [InitBasicFS, Always, TestOutput (
1178 ["file"; "/new"]], "empty");
1179 InitBasicFS, Always, TestOutput (
1180 [["write_file"; "/new"; "some content\n"; "0"];
1181 ["file"; "/new"]], "ASCII text");
1182 InitBasicFS, Always, TestLastFail (
1183 [["file"; "/nofile"]])],
1184 "determine file type",
1186 This call uses the standard L<file(1)> command to determine
1187 the type or contents of the file. This also works on devices,
1188 for example to find out whether a partition contains a filesystem.
1190 The exact command which runs is C<file -bsL path>. Note in
1191 particular that the filename is not prepended to the output
1192 (the C<-b> option).");
1194 ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1195 [InitBasicFS, Always, TestOutput (
1196 [["upload"; "test-command"; "/test-command"];
1197 ["chmod"; "493"; "/test-command"];
1198 ["command"; "/test-command 1"]], "Result1");
1199 InitBasicFS, Always, TestOutput (
1200 [["upload"; "test-command"; "/test-command"];
1201 ["chmod"; "493"; "/test-command"];
1202 ["command"; "/test-command 2"]], "Result2\n");
1203 InitBasicFS, Always, TestOutput (
1204 [["upload"; "test-command"; "/test-command"];
1205 ["chmod"; "493"; "/test-command"];
1206 ["command"; "/test-command 3"]], "\nResult3");
1207 InitBasicFS, Always, TestOutput (
1208 [["upload"; "test-command"; "/test-command"];
1209 ["chmod"; "493"; "/test-command"];
1210 ["command"; "/test-command 4"]], "\nResult4\n");
1211 InitBasicFS, Always, TestOutput (
1212 [["upload"; "test-command"; "/test-command"];
1213 ["chmod"; "493"; "/test-command"];
1214 ["command"; "/test-command 5"]], "\nResult5\n\n");
1215 InitBasicFS, Always, TestOutput (
1216 [["upload"; "test-command"; "/test-command"];
1217 ["chmod"; "493"; "/test-command"];
1218 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1219 InitBasicFS, Always, TestOutput (
1220 [["upload"; "test-command"; "/test-command"];
1221 ["chmod"; "493"; "/test-command"];
1222 ["command"; "/test-command 7"]], "");
1223 InitBasicFS, Always, TestOutput (
1224 [["upload"; "test-command"; "/test-command"];
1225 ["chmod"; "493"; "/test-command"];
1226 ["command"; "/test-command 8"]], "\n");
1227 InitBasicFS, Always, TestOutput (
1228 [["upload"; "test-command"; "/test-command"];
1229 ["chmod"; "493"; "/test-command"];
1230 ["command"; "/test-command 9"]], "\n\n");
1231 InitBasicFS, Always, TestOutput (
1232 [["upload"; "test-command"; "/test-command"];
1233 ["chmod"; "493"; "/test-command"];
1234 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1235 InitBasicFS, Always, TestOutput (
1236 [["upload"; "test-command"; "/test-command"];
1237 ["chmod"; "493"; "/test-command"];
1238 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1239 InitBasicFS, Always, TestLastFail (
1240 [["upload"; "test-command"; "/test-command"];
1241 ["chmod"; "493"; "/test-command"];
1242 ["command"; "/test-command"]])],
1243 "run a command from the guest filesystem",
1245 This call runs a command from the guest filesystem. The
1246 filesystem must be mounted, and must contain a compatible
1247 operating system (ie. something Linux, with the same
1248 or compatible processor architecture).
1250 The single parameter is an argv-style list of arguments.
1251 The first element is the name of the program to run.
1252 Subsequent elements are parameters. The list must be
1253 non-empty (ie. must contain a program name).
1255 The return value is anything printed to I<stdout> by
1258 If the command returns a non-zero exit status, then
1259 this function returns an error message. The error message
1260 string is the content of I<stderr> from the command.
1262 The C<$PATH> environment variable will contain at least
1263 C</usr/bin> and C</bin>. If you require a program from
1264 another location, you should provide the full path in the
1267 Shared libraries and data files required by the program
1268 must be available on filesystems which are mounted in the
1269 correct places. It is the caller's responsibility to ensure
1270 all filesystems that are needed are mounted at the right
1273 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1274 [InitBasicFS, Always, TestOutputList (
1275 [["upload"; "test-command"; "/test-command"];
1276 ["chmod"; "493"; "/test-command"];
1277 ["command_lines"; "/test-command 1"]], ["Result1"]);
1278 InitBasicFS, Always, TestOutputList (
1279 [["upload"; "test-command"; "/test-command"];
1280 ["chmod"; "493"; "/test-command"];
1281 ["command_lines"; "/test-command 2"]], ["Result2"]);
1282 InitBasicFS, Always, TestOutputList (
1283 [["upload"; "test-command"; "/test-command"];
1284 ["chmod"; "493"; "/test-command"];
1285 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1286 InitBasicFS, Always, TestOutputList (
1287 [["upload"; "test-command"; "/test-command"];
1288 ["chmod"; "493"; "/test-command"];
1289 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1290 InitBasicFS, Always, TestOutputList (
1291 [["upload"; "test-command"; "/test-command"];
1292 ["chmod"; "493"; "/test-command"];
1293 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1294 InitBasicFS, Always, TestOutputList (
1295 [["upload"; "test-command"; "/test-command"];
1296 ["chmod"; "493"; "/test-command"];
1297 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1298 InitBasicFS, Always, TestOutputList (
1299 [["upload"; "test-command"; "/test-command"];
1300 ["chmod"; "493"; "/test-command"];
1301 ["command_lines"; "/test-command 7"]], []);
1302 InitBasicFS, Always, TestOutputList (
1303 [["upload"; "test-command"; "/test-command"];
1304 ["chmod"; "493"; "/test-command"];
1305 ["command_lines"; "/test-command 8"]], [""]);
1306 InitBasicFS, Always, TestOutputList (
1307 [["upload"; "test-command"; "/test-command"];
1308 ["chmod"; "493"; "/test-command"];
1309 ["command_lines"; "/test-command 9"]], ["";""]);
1310 InitBasicFS, Always, TestOutputList (
1311 [["upload"; "test-command"; "/test-command"];
1312 ["chmod"; "493"; "/test-command"];
1313 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1314 InitBasicFS, Always, TestOutputList (
1315 [["upload"; "test-command"; "/test-command"];
1316 ["chmod"; "493"; "/test-command"];
1317 ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1318 "run a command, returning lines",
1320 This is the same as C<guestfs_command>, but splits the
1321 result into a list of lines.");
1323 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1324 [InitBasicFS, Always, TestOutputStruct (
1326 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1327 "get file information",
1329 Returns file information for the given C<path>.
1331 This is the same as the C<stat(2)> system call.");
1333 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1334 [InitBasicFS, Always, TestOutputStruct (
1336 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1337 "get file information for a symbolic link",
1339 Returns file information for the given C<path>.
1341 This is the same as C<guestfs_stat> except that if C<path>
1342 is a symbolic link, then the link is stat-ed, not the file it
1345 This is the same as the C<lstat(2)> system call.");
1347 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1348 [InitBasicFS, Always, TestOutputStruct (
1349 [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1350 CompareWithInt ("blocks", 490020);
1351 CompareWithInt ("bsize", 1024)])],
1352 "get file system statistics",
1354 Returns file system statistics for any mounted file system.
1355 C<path> should be a file or directory in the mounted file system
1356 (typically it is the mount point itself, but it doesn't need to be).
1358 This is the same as the C<statvfs(2)> system call.");
1360 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1362 "get ext2/ext3/ext4 superblock details",
1364 This returns the contents of the ext2, ext3 or ext4 filesystem
1365 superblock on C<device>.
1367 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1368 manpage for more details. The list of fields returned isn't
1369 clearly defined, and depends on both the version of C<tune2fs>
1370 that libguestfs was built against, and the filesystem itself.");
1372 ("blockdev_setro", (RErr, [String "device"]), 56, [],
1373 [InitEmpty, Always, TestOutputTrue (
1374 [["blockdev_setro"; "/dev/sda"];
1375 ["blockdev_getro"; "/dev/sda"]])],
1376 "set block device to read-only",
1378 Sets the block device named C<device> to read-only.
1380 This uses the L<blockdev(8)> command.");
1382 ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1383 [InitEmpty, Always, TestOutputFalse (
1384 [["blockdev_setrw"; "/dev/sda"];
1385 ["blockdev_getro"; "/dev/sda"]])],
1386 "set block device to read-write",
1388 Sets the block device named C<device> to read-write.
1390 This uses the L<blockdev(8)> command.");
1392 ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1393 [InitEmpty, Always, TestOutputTrue (
1394 [["blockdev_setro"; "/dev/sda"];
1395 ["blockdev_getro"; "/dev/sda"]])],
1396 "is block device set to read-only",
1398 Returns a boolean indicating if the block device is read-only
1399 (true if read-only, false if not).
1401 This uses the L<blockdev(8)> command.");
1403 ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1404 [InitEmpty, Always, TestOutputInt (
1405 [["blockdev_getss"; "/dev/sda"]], 512)],
1406 "get sectorsize of block device",
1408 This returns the size of sectors on a block device.
1409 Usually 512, but can be larger for modern devices.
1411 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1414 This uses the L<blockdev(8)> command.");
1416 ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1417 [InitEmpty, Always, TestOutputInt (
1418 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1419 "get blocksize of block device",
1421 This returns the block size of a device.
1423 (Note this is different from both I<size in blocks> and
1424 I<filesystem block size>).
1426 This uses the L<blockdev(8)> command.");
1428 ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1430 "set blocksize of block device",
1432 This sets the block size of a device.
1434 (Note this is different from both I<size in blocks> and
1435 I<filesystem block size>).
1437 This uses the L<blockdev(8)> command.");
1439 ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1440 [InitEmpty, Always, TestOutputInt (
1441 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1442 "get total size of device in 512-byte sectors",
1444 This returns the size of the device in units of 512-byte sectors
1445 (even if the sectorsize isn't 512 bytes ... weird).
1447 See also C<guestfs_blockdev_getss> for the real sector size of
1448 the device, and C<guestfs_blockdev_getsize64> for the more
1449 useful I<size in bytes>.
1451 This uses the L<blockdev(8)> command.");
1453 ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1454 [InitEmpty, Always, TestOutputInt (
1455 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1456 "get total size of device in bytes",
1458 This returns the size of the device in bytes.
1460 See also C<guestfs_blockdev_getsz>.
1462 This uses the L<blockdev(8)> command.");
1464 ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1465 [InitEmpty, Always, TestRun
1466 [["blockdev_flushbufs"; "/dev/sda"]]],
1467 "flush device buffers",
1469 This tells the kernel to flush internal buffers associated
1472 This uses the L<blockdev(8)> command.");
1474 ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1475 [InitEmpty, Always, TestRun
1476 [["blockdev_rereadpt"; "/dev/sda"]]],
1477 "reread partition table",
1479 Reread the partition table on C<device>.
1481 This uses the L<blockdev(8)> command.");
1483 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1484 [InitBasicFS, Always, TestOutput (
1485 (* Pick a file from cwd which isn't likely to change. *)
1486 [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
1487 ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1488 "upload a file from the local machine",
1490 Upload local file C<filename> to C<remotefilename> on the
1493 C<filename> can also be a named pipe.
1495 See also C<guestfs_download>.");
1497 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1498 [InitBasicFS, Always, TestOutput (
1499 (* Pick a file from cwd which isn't likely to change. *)
1500 [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
1501 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1502 ["upload"; "testdownload.tmp"; "/upload"];
1503 ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1504 "download a file to the local machine",
1506 Download file C<remotefilename> and save it as C<filename>
1507 on the local machine.
1509 C<filename> can also be a named pipe.
1511 See also C<guestfs_upload>, C<guestfs_cat>.");
1513 ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1514 [InitBasicFS, Always, TestOutput (
1515 [["write_file"; "/new"; "test\n"; "0"];
1516 ["checksum"; "crc"; "/new"]], "935282863");
1517 InitBasicFS, Always, TestLastFail (
1518 [["checksum"; "crc"; "/new"]]);
1519 InitBasicFS, Always, TestOutput (
1520 [["write_file"; "/new"; "test\n"; "0"];
1521 ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1522 InitBasicFS, Always, TestOutput (
1523 [["write_file"; "/new"; "test\n"; "0"];
1524 ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1525 InitBasicFS, Always, TestOutput (
1526 [["write_file"; "/new"; "test\n"; "0"];
1527 ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1528 InitBasicFS, Always, TestOutput (
1529 [["write_file"; "/new"; "test\n"; "0"];
1530 ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1531 InitBasicFS, Always, TestOutput (
1532 [["write_file"; "/new"; "test\n"; "0"];
1533 ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1534 InitBasicFS, Always, TestOutput (
1535 [["write_file"; "/new"; "test\n"; "0"];
1536 ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123")],
1537 "compute MD5, SHAx or CRC checksum of file",
1539 This call computes the MD5, SHAx or CRC checksum of the
1542 The type of checksum to compute is given by the C<csumtype>
1543 parameter which must have one of the following values:
1549 Compute the cyclic redundancy check (CRC) specified by POSIX
1550 for the C<cksum> command.
1554 Compute the MD5 hash (using the C<md5sum> program).
1558 Compute the SHA1 hash (using the C<sha1sum> program).
1562 Compute the SHA224 hash (using the C<sha224sum> program).
1566 Compute the SHA256 hash (using the C<sha256sum> program).
1570 Compute the SHA384 hash (using the C<sha384sum> program).
1574 Compute the SHA512 hash (using the C<sha512sum> program).
1578 The checksum is returned as a printable string.");
1580 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1581 [InitBasicFS, Always, TestOutput (
1582 [["tar_in"; "images/helloworld.tar"; "/"];
1583 ["cat"; "/hello"]], "hello\n")],
1584 "unpack tarfile to directory",
1586 This command uploads and unpacks local file C<tarfile> (an
1587 I<uncompressed> tar file) into C<directory>.
1589 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1591 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1593 "pack directory into tarfile",
1595 This command packs the contents of C<directory> and downloads
1596 it to local file C<tarfile>.
1598 To download a compressed tarball, use C<guestfs_tgz_out>.");
1600 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1601 [InitBasicFS, Always, TestOutput (
1602 [["tgz_in"; "images/helloworld.tar.gz"; "/"];
1603 ["cat"; "/hello"]], "hello\n")],
1604 "unpack compressed tarball to directory",
1606 This command uploads and unpacks local file C<tarball> (a
1607 I<gzip compressed> tar file) into C<directory>.
1609 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1611 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1613 "pack directory into compressed tarball",
1615 This command packs the contents of C<directory> and downloads
1616 it to local file C<tarball>.
1618 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1620 ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1621 [InitBasicFS, Always, TestLastFail (
1623 ["mount_ro"; "/dev/sda1"; "/"];
1624 ["touch"; "/new"]]);
1625 InitBasicFS, Always, TestOutput (
1626 [["write_file"; "/new"; "data"; "0"];
1628 ["mount_ro"; "/dev/sda1"; "/"];
1629 ["cat"; "/new"]], "data")],
1630 "mount a guest disk, read-only",
1632 This is the same as the C<guestfs_mount> command, but it
1633 mounts the filesystem with the read-only (I<-o ro>) flag.");
1635 ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1637 "mount a guest disk with mount options",
1639 This is the same as the C<guestfs_mount> command, but it
1640 allows you to set the mount options as for the
1641 L<mount(8)> I<-o> flag.");
1643 ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1645 "mount a guest disk with mount options and vfstype",
1647 This is the same as the C<guestfs_mount> command, but it
1648 allows you to set both the mount options and the vfstype
1649 as for the L<mount(8)> I<-o> and I<-t> flags.");
1651 ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1653 "debugging and internals",
1655 The C<guestfs_debug> command exposes some internals of
1656 C<guestfsd> (the guestfs daemon) that runs inside the
1659 There is no comprehensive help for this command. You have
1660 to look at the file C<daemon/debug.c> in the libguestfs source
1661 to find out what you can do.");
1663 ("lvremove", (RErr, [String "device"]), 77, [],
1664 [InitEmpty, Always, TestOutputList (
1665 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1666 ["pvcreate"; "/dev/sda1"];
1667 ["vgcreate"; "VG"; "/dev/sda1"];
1668 ["lvcreate"; "LV1"; "VG"; "50"];
1669 ["lvcreate"; "LV2"; "VG"; "50"];
1670 ["lvremove"; "/dev/VG/LV1"];
1671 ["lvs"]], ["/dev/VG/LV2"]);
1672 InitEmpty, Always, TestOutputList (
1673 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1674 ["pvcreate"; "/dev/sda1"];
1675 ["vgcreate"; "VG"; "/dev/sda1"];
1676 ["lvcreate"; "LV1"; "VG"; "50"];
1677 ["lvcreate"; "LV2"; "VG"; "50"];
1678 ["lvremove"; "/dev/VG"];
1680 InitEmpty, Always, TestOutputList (
1681 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1682 ["pvcreate"; "/dev/sda1"];
1683 ["vgcreate"; "VG"; "/dev/sda1"];
1684 ["lvcreate"; "LV1"; "VG"; "50"];
1685 ["lvcreate"; "LV2"; "VG"; "50"];
1686 ["lvremove"; "/dev/VG"];
1688 "remove an LVM logical volume",
1690 Remove an LVM logical volume C<device>, where C<device> is
1691 the path to the LV, such as C</dev/VG/LV>.
1693 You can also remove all LVs in a volume group by specifying
1694 the VG name, C</dev/VG>.");
1696 ("vgremove", (RErr, [String "vgname"]), 78, [],
1697 [InitEmpty, Always, TestOutputList (
1698 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1699 ["pvcreate"; "/dev/sda1"];
1700 ["vgcreate"; "VG"; "/dev/sda1"];
1701 ["lvcreate"; "LV1"; "VG"; "50"];
1702 ["lvcreate"; "LV2"; "VG"; "50"];
1705 InitEmpty, Always, TestOutputList (
1706 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1707 ["pvcreate"; "/dev/sda1"];
1708 ["vgcreate"; "VG"; "/dev/sda1"];
1709 ["lvcreate"; "LV1"; "VG"; "50"];
1710 ["lvcreate"; "LV2"; "VG"; "50"];
1713 "remove an LVM volume group",
1715 Remove an LVM volume group C<vgname>, (for example C<VG>).
1717 This also forcibly removes all logical volumes in the volume
1720 ("pvremove", (RErr, [String "device"]), 79, [],
1721 [InitEmpty, Always, TestOutputList (
1722 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1723 ["pvcreate"; "/dev/sda1"];
1724 ["vgcreate"; "VG"; "/dev/sda1"];
1725 ["lvcreate"; "LV1"; "VG"; "50"];
1726 ["lvcreate"; "LV2"; "VG"; "50"];
1728 ["pvremove"; "/dev/sda1"];
1730 InitEmpty, Always, TestOutputList (
1731 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1732 ["pvcreate"; "/dev/sda1"];
1733 ["vgcreate"; "VG"; "/dev/sda1"];
1734 ["lvcreate"; "LV1"; "VG"; "50"];
1735 ["lvcreate"; "LV2"; "VG"; "50"];
1737 ["pvremove"; "/dev/sda1"];
1739 InitEmpty, Always, TestOutputList (
1740 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1741 ["pvcreate"; "/dev/sda1"];
1742 ["vgcreate"; "VG"; "/dev/sda1"];
1743 ["lvcreate"; "LV1"; "VG"; "50"];
1744 ["lvcreate"; "LV2"; "VG"; "50"];
1746 ["pvremove"; "/dev/sda1"];
1748 "remove an LVM physical volume",
1750 This wipes a physical volume C<device> so that LVM will no longer
1753 The implementation uses the C<pvremove> command which refuses to
1754 wipe physical volumes that contain any volume groups, so you have
1755 to remove those first.");
1757 ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
1758 [InitBasicFS, Always, TestOutput (
1759 [["set_e2label"; "/dev/sda1"; "testlabel"];
1760 ["get_e2label"; "/dev/sda1"]], "testlabel")],
1761 "set the ext2/3/4 filesystem label",
1763 This sets the ext2/3/4 filesystem label of the filesystem on
1764 C<device> to C<label>. Filesystem labels are limited to
1767 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
1768 to return the existing label on a filesystem.");
1770 ("get_e2label", (RString "label", [String "device"]), 81, [],
1772 "get the ext2/3/4 filesystem label",
1774 This returns the ext2/3/4 filesystem label of the filesystem on
1777 ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
1778 [InitBasicFS, Always, TestOutput (
1779 [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
1780 ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
1781 InitBasicFS, Always, TestOutput (
1782 [["set_e2uuid"; "/dev/sda1"; "clear"];
1783 ["get_e2uuid"; "/dev/sda1"]], "");
1784 (* We can't predict what UUIDs will be, so just check the commands run. *)
1785 InitBasicFS, Always, TestRun (
1786 [["set_e2uuid"; "/dev/sda1"; "random"]]);
1787 InitBasicFS, Always, TestRun (
1788 [["set_e2uuid"; "/dev/sda1"; "time"]])],
1789 "set the ext2/3/4 filesystem UUID",
1791 This sets the ext2/3/4 filesystem UUID of the filesystem on
1792 C<device> to C<uuid>. The format of the UUID and alternatives
1793 such as C<clear>, C<random> and C<time> are described in the
1794 L<tune2fs(8)> manpage.
1796 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
1797 to return the existing UUID of a filesystem.");
1799 ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
1801 "get the ext2/3/4 filesystem UUID",
1803 This returns the ext2/3/4 filesystem UUID of the filesystem on
1806 ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
1807 [InitBasicFS, Always, TestOutputInt (
1808 [["umount"; "/dev/sda1"];
1809 ["fsck"; "ext2"; "/dev/sda1"]], 0);
1810 InitBasicFS, Always, TestOutputInt (
1811 [["umount"; "/dev/sda1"];
1812 ["zero"; "/dev/sda1"];
1813 ["fsck"; "ext2"; "/dev/sda1"]], 8)],
1814 "run the filesystem checker",
1816 This runs the filesystem checker (fsck) on C<device> which
1817 should have filesystem type C<fstype>.
1819 The returned integer is the status. See L<fsck(8)> for the
1820 list of status codes from C<fsck>.
1828 Multiple status codes can be summed together.
1832 A non-zero return code can mean \"success\", for example if
1833 errors have been corrected on the filesystem.
1837 Checking or repairing NTFS volumes is not supported
1842 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
1844 ("zero", (RErr, [String "device"]), 85, [],
1845 [InitBasicFS, Always, TestOutput (
1846 [["umount"; "/dev/sda1"];
1847 ["zero"; "/dev/sda1"];
1848 ["file"; "/dev/sda1"]], "data")],
1849 "write zeroes to the device",
1851 This command writes zeroes over the first few blocks of C<device>.
1853 How many blocks are zeroed isn't specified (but it's I<not> enough
1854 to securely wipe the device). It should be sufficient to remove
1855 any partition tables, filesystem superblocks and so on.");
1857 ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
1858 [InitBasicFS, Always, TestOutputTrue (
1859 [["grub_install"; "/"; "/dev/sda1"];
1860 ["is_dir"; "/boot"]])],
1863 This command installs GRUB (the Grand Unified Bootloader) on
1864 C<device>, with the root directory being C<root>.");
1866 ("cp", (RErr, [String "src"; String "dest"]), 87, [],
1867 [InitBasicFS, Always, TestOutput (
1868 [["write_file"; "/old"; "file content"; "0"];
1869 ["cp"; "/old"; "/new"];
1870 ["cat"; "/new"]], "file content");
1871 InitBasicFS, Always, TestOutputTrue (
1872 [["write_file"; "/old"; "file content"; "0"];
1873 ["cp"; "/old"; "/new"];
1874 ["is_file"; "/old"]]);
1875 InitBasicFS, Always, TestOutput (
1876 [["write_file"; "/old"; "file content"; "0"];
1878 ["cp"; "/old"; "/dir/new"];
1879 ["cat"; "/dir/new"]], "file content")],
1882 This copies a file from C<src> to C<dest> where C<dest> is
1883 either a destination filename or destination directory.");
1885 ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
1886 [InitBasicFS, Always, TestOutput (
1887 [["mkdir"; "/olddir"];
1888 ["mkdir"; "/newdir"];
1889 ["write_file"; "/olddir/file"; "file content"; "0"];
1890 ["cp_a"; "/olddir"; "/newdir"];
1891 ["cat"; "/newdir/olddir/file"]], "file content")],
1892 "copy a file or directory recursively",
1894 This copies a file or directory from C<src> to C<dest>
1895 recursively using the C<cp -a> command.");
1897 ("mv", (RErr, [String "src"; String "dest"]), 89, [],
1898 [InitBasicFS, Always, TestOutput (
1899 [["write_file"; "/old"; "file content"; "0"];
1900 ["mv"; "/old"; "/new"];
1901 ["cat"; "/new"]], "file content");
1902 InitBasicFS, Always, TestOutputFalse (
1903 [["write_file"; "/old"; "file content"; "0"];
1904 ["mv"; "/old"; "/new"];
1905 ["is_file"; "/old"]])],
1908 This moves a file from C<src> to C<dest> where C<dest> is
1909 either a destination filename or destination directory.");
1911 ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
1912 [InitEmpty, Always, TestRun (
1913 [["drop_caches"; "3"]])],
1914 "drop kernel page cache, dentries and inodes",
1916 This instructs the guest kernel to drop its page cache,
1917 and/or dentries and inode caches. The parameter C<whattodrop>
1918 tells the kernel what precisely to drop, see
1919 L<http://linux-mm.org/Drop_Caches>
1921 Setting C<whattodrop> to 3 should drop everything.
1923 This automatically calls L<sync(2)> before the operation,
1924 so that the maximum guest memory is freed.");
1926 ("dmesg", (RString "kmsgs", []), 91, [],
1927 [InitEmpty, Always, TestRun (
1929 "return kernel messages",
1931 This returns the kernel messages (C<dmesg> output) from
1932 the guest kernel. This is sometimes useful for extended
1933 debugging of problems.
1935 Another way to get the same information is to enable
1936 verbose messages with C<guestfs_set_verbose> or by setting
1937 the environment variable C<LIBGUESTFS_DEBUG=1> before
1938 running the program.");
1940 ("ping_daemon", (RErr, []), 92, [],
1941 [InitEmpty, Always, TestRun (
1942 [["ping_daemon"]])],
1943 "ping the guest daemon",
1945 This is a test probe into the guestfs daemon running inside
1946 the qemu subprocess. Calling this function checks that the
1947 daemon responds to the ping message, without affecting the daemon
1948 or attached block device(s) in any other way.");
1950 ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
1951 [InitBasicFS, Always, TestOutputTrue (
1952 [["write_file"; "/file1"; "contents of a file"; "0"];
1953 ["cp"; "/file1"; "/file2"];
1954 ["equal"; "/file1"; "/file2"]]);
1955 InitBasicFS, Always, TestOutputFalse (
1956 [["write_file"; "/file1"; "contents of a file"; "0"];
1957 ["write_file"; "/file2"; "contents of another file"; "0"];
1958 ["equal"; "/file1"; "/file2"]]);
1959 InitBasicFS, Always, TestLastFail (
1960 [["equal"; "/file1"; "/file2"]])],
1961 "test if two files have equal contents",
1963 This compares the two files C<file1> and C<file2> and returns
1964 true if their content is exactly equal, or false otherwise.
1966 The external L<cmp(1)> program is used for the comparison.");
1968 ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
1969 [InitBasicFS, Always, TestOutputList (
1970 [["write_file"; "/new"; "hello\nworld\n"; "0"];
1971 ["strings"; "/new"]], ["hello"; "world"]);
1972 InitBasicFS, Always, TestOutputList (
1974 ["strings"; "/new"]], [])],
1975 "print the printable strings in a file",
1977 This runs the L<strings(1)> command on a file and returns
1978 the list of printable strings found.");
1980 ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
1981 [InitBasicFS, Always, TestOutputList (
1982 [["write_file"; "/new"; "hello\nworld\n"; "0"];
1983 ["strings_e"; "b"; "/new"]], []);
1984 InitBasicFS, Disabled, TestOutputList (
1985 [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
1986 ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
1987 "print the printable strings in a file",
1989 This is like the C<guestfs_strings> command, but allows you to
1990 specify the encoding.
1992 See the L<strings(1)> manpage for the full list of encodings.
1994 Commonly useful encodings are C<l> (lower case L) which will
1995 show strings inside Windows/x86 files.
1997 The returned strings are transcoded to UTF-8.");
1999 ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2000 [InitBasicFS, Always, TestOutput (
2001 [["write_file"; "/new"; "hello\nworld\n"; "12"];
2002 ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n")],
2003 "dump a file in hexadecimal",
2005 This runs C<hexdump -C> on the given C<path>. The result is
2006 the human-readable, canonical hex dump of the file.");
2008 ("zerofree", (RErr, [String "device"]), 97, [],
2009 [InitNone, Always, TestOutput (
2010 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2011 ["mkfs"; "ext3"; "/dev/sda1"];
2012 ["mount"; "/dev/sda1"; "/"];
2013 ["write_file"; "/new"; "test file"; "0"];
2014 ["umount"; "/dev/sda1"];
2015 ["zerofree"; "/dev/sda1"];
2016 ["mount"; "/dev/sda1"; "/"];
2017 ["cat"; "/new"]], "test file")],
2018 "zero unused inodes and disk blocks on ext2/3 filesystem",
2020 This runs the I<zerofree> program on C<device>. This program
2021 claims to zero unused inodes and disk blocks on an ext2/3
2022 filesystem, thus making it possible to compress the filesystem
2025 You should B<not> run this program if the filesystem is
2028 It is possible that using this program can damage the filesystem
2029 or data on the filesystem.");
2031 ("pvresize", (RErr, [String "device"]), 98, [],
2033 "resize an LVM physical volume",
2035 This resizes (expands or shrinks) an existing LVM physical
2036 volume to match the new size of the underlying device.");
2038 ("sfdisk_N", (RErr, [String "device"; Int "n";
2039 Int "cyls"; Int "heads"; Int "sectors";
2040 String "line"]), 99, [DangerWillRobinson],
2042 "modify a single partition on a block device",
2044 This runs L<sfdisk(8)> option to modify just the single
2045 partition C<n> (note: C<n> counts from 1).
2047 For other parameters, see C<guestfs_sfdisk>. You should usually
2048 pass C<0> for the cyls/heads/sectors parameters.");
2050 ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2052 "display the partition table",
2054 This displays the partition table on C<device>, in the
2055 human-readable output of the L<sfdisk(8)> command. It is
2056 not intended to be parsed.");
2058 ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2060 "display the kernel geometry",
2062 This displays the kernel's idea of the geometry of C<device>.
2064 The result is in human-readable format, and not designed to
2067 ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2069 "display the disk geometry from the partition table",
2071 This displays the disk geometry of C<device> read from the
2072 partition table. Especially in the case where the underlying
2073 block device has been resized, this can be different from the
2074 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2076 The result is in human-readable format, and not designed to
2079 ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2081 "activate or deactivate all volume groups",
2083 This command activates or (if C<activate> is false) deactivates
2084 all logical volumes in all volume groups.
2085 If activated, then they are made known to the
2086 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2087 then those devices disappear.
2089 This command is the same as running C<vgchange -a y|n>");
2091 ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2093 "activate or deactivate some volume groups",
2095 This command activates or (if C<activate> is false) deactivates
2096 all logical volumes in the listed volume groups C<volgroups>.
2097 If activated, then they are made known to the
2098 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2099 then those devices disappear.
2101 This command is the same as running C<vgchange -a y|n volgroups...>
2103 Note that if C<volgroups> is an empty list then B<all> volume groups
2104 are activated or deactivated.");
2106 ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2107 [InitNone, Always, TestOutput (
2108 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2109 ["pvcreate"; "/dev/sda1"];
2110 ["vgcreate"; "VG"; "/dev/sda1"];
2111 ["lvcreate"; "LV"; "VG"; "10"];
2112 ["mkfs"; "ext2"; "/dev/VG/LV"];
2113 ["mount"; "/dev/VG/LV"; "/"];
2114 ["write_file"; "/new"; "test content"; "0"];
2116 ["lvresize"; "/dev/VG/LV"; "20"];
2117 ["e2fsck_f"; "/dev/VG/LV"];
2118 ["resize2fs"; "/dev/VG/LV"];
2119 ["mount"; "/dev/VG/LV"; "/"];
2120 ["cat"; "/new"]], "test content")],
2121 "resize an LVM logical volume",
2123 This resizes (expands or shrinks) an existing LVM logical
2124 volume to C<mbytes>. When reducing, data in the reduced part
2127 ("resize2fs", (RErr, [String "device"]), 106, [],
2128 [], (* lvresize tests this *)
2129 "resize an ext2/ext3 filesystem",
2131 This resizes an ext2 or ext3 filesystem to match the size of
2132 the underlying device.
2134 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2135 on the C<device> before calling this command. For unknown reasons
2136 C<resize2fs> sometimes gives an error about this and sometimes not.
2137 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2138 calling this function.");
2140 ("find", (RStringList "names", [String "directory"]), 107, [],
2141 [InitBasicFS, Always, TestOutputList (
2142 [["find"; "/"]], ["lost+found"]);
2143 InitBasicFS, Always, TestOutputList (
2147 ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2148 InitBasicFS, Always, TestOutputList (
2149 [["mkdir_p"; "/a/b/c"];
2150 ["touch"; "/a/b/c/d"];
2151 ["find"; "/a/b/"]], ["c"; "c/d"])],
2152 "find all files and directories",
2154 This command lists out all files and directories, recursively,
2155 starting at C<directory>. It is essentially equivalent to
2156 running the shell command C<find directory -print> but some
2157 post-processing happens on the output, described below.
2159 This returns a list of strings I<without any prefix>. Thus
2160 if the directory structure was:
2166 then the returned list from C<guestfs_find> C</tmp> would be
2174 If C<directory> is not a directory, then this command returns
2177 The returned list is sorted.");
2179 ("e2fsck_f", (RErr, [String "device"]), 108, [],
2180 [], (* lvresize tests this *)
2181 "check an ext2/ext3 filesystem",
2183 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2184 filesystem checker on C<device>, noninteractively (C<-p>),
2185 even if the filesystem appears to be clean (C<-f>).
2187 This command is only needed because of C<guestfs_resize2fs>
2188 (q.v.). Normally you should use C<guestfs_fsck>.");
2192 let all_functions = non_daemon_functions @ daemon_functions
2194 (* In some places we want the functions to be displayed sorted
2195 * alphabetically, so this is useful:
2197 let all_functions_sorted =
2198 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2199 compare n1 n2) all_functions
2201 (* Column names and types from LVM PVs/VGs/LVs. *)
2210 "pv_attr", `String (* XXX *);
2211 "pv_pe_count", `Int;
2212 "pv_pe_alloc_count", `Int;
2215 "pv_mda_count", `Int;
2216 "pv_mda_free", `Bytes;
2217 (* Not in Fedora 10:
2218 "pv_mda_size", `Bytes;
2225 "vg_attr", `String (* XXX *);
2228 "vg_sysid", `String;
2229 "vg_extent_size", `Bytes;
2230 "vg_extent_count", `Int;
2231 "vg_free_count", `Int;
2239 "vg_mda_count", `Int;
2240 "vg_mda_free", `Bytes;
2241 (* Not in Fedora 10:
2242 "vg_mda_size", `Bytes;
2248 "lv_attr", `String (* XXX *);
2251 "lv_kernel_major", `Int;
2252 "lv_kernel_minor", `Int;
2256 "snap_percent", `OptPercent;
2257 "copy_percent", `OptPercent;
2260 "mirror_log", `String;
2264 (* Column names and types from stat structures.
2265 * NB. Can't use things like 'st_atime' because glibc header files
2266 * define some of these as macros. Ugh.
2283 let statvfs_cols = [
2297 (* Useful functions.
2298 * Note we don't want to use any external OCaml libraries which
2299 * makes this a bit harder than it should be.
2301 let failwithf fs = ksprintf failwith fs
2303 let replace_char s c1 c2 =
2304 let s2 = String.copy s in
2305 let r = ref false in
2306 for i = 0 to String.length s2 - 1 do
2307 if String.unsafe_get s2 i = c1 then (
2308 String.unsafe_set s2 i c2;
2312 if not !r then s else s2
2316 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2318 let triml ?(test = isspace) str =
2320 let n = ref (String.length str) in
2321 while !n > 0 && test str.[!i]; do
2326 else String.sub str !i !n
2328 let trimr ?(test = isspace) str =
2329 let n = ref (String.length str) in
2330 while !n > 0 && test str.[!n-1]; do
2333 if !n = String.length str then str
2334 else String.sub str 0 !n
2336 let trim ?(test = isspace) str =
2337 trimr ~test (triml ~test str)
2339 let rec find s sub =
2340 let len = String.length s in
2341 let sublen = String.length sub in
2343 if i <= len-sublen then (
2345 if j < sublen then (
2346 if s.[i+j] = sub.[j] then loop2 (j+1)
2352 if r = -1 then loop (i+1) else r
2358 let rec replace_str s s1 s2 =
2359 let len = String.length s in
2360 let sublen = String.length s1 in
2361 let i = find s s1 in
2364 let s' = String.sub s 0 i in
2365 let s'' = String.sub s (i+sublen) (len-i-sublen) in
2366 s' ^ s2 ^ replace_str s'' s1 s2
2369 let rec string_split sep str =
2370 let len = String.length str in
2371 let seplen = String.length sep in
2372 let i = find str sep in
2373 if i = -1 then [str]
2375 let s' = String.sub str 0 i in
2376 let s'' = String.sub str (i+seplen) (len-i-seplen) in
2377 s' :: string_split sep s''
2380 let files_equal n1 n2 =
2381 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
2382 match Sys.command cmd with
2385 | i -> failwithf "%s: failed with error code %d" cmd i
2387 let rec find_map f = function
2388 | [] -> raise Not_found
2392 | None -> find_map f xs
2395 let rec loop i = function
2397 | x :: xs -> f i x; loop (i+1) xs
2402 let rec loop i = function
2404 | x :: xs -> let r = f i x in r :: loop (i+1) xs
2408 let name_of_argt = function
2409 | String n | OptString n | StringList n | Bool n | Int n
2410 | FileIn n | FileOut n -> n
2412 let seq_of_test = function
2413 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
2414 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
2415 | TestOutputLength (s, _) | TestOutputStruct (s, _)
2416 | TestLastFail s -> s
2418 (* Check function names etc. for consistency. *)
2419 let check_functions () =
2420 let contains_uppercase str =
2421 let len = String.length str in
2423 if i >= len then false
2426 if c >= 'A' && c <= 'Z' then true
2433 (* Check function names. *)
2435 fun (name, _, _, _, _, _, _) ->
2436 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
2437 failwithf "function name %s does not need 'guestfs' prefix" name;
2439 failwithf "function name is empty";
2440 if name.[0] < 'a' || name.[0] > 'z' then
2441 failwithf "function name %s must start with lowercase a-z" name;
2442 if String.contains name '-' then
2443 failwithf "function name %s should not contain '-', use '_' instead."
2447 (* Check function parameter/return names. *)
2449 fun (name, style, _, _, _, _, _) ->
2450 let check_arg_ret_name n =
2451 if contains_uppercase n then
2452 failwithf "%s param/ret %s should not contain uppercase chars"
2454 if String.contains n '-' || String.contains n '_' then
2455 failwithf "%s param/ret %s should not contain '-' or '_'"
2458 failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" n;
2459 if n = "argv" || n = "args" then
2460 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
2463 (match fst style with
2465 | RInt n | RInt64 n | RBool n | RConstString n | RString n
2466 | RStringList n | RPVList n | RVGList n | RLVList n
2467 | RStat n | RStatVFS n
2469 check_arg_ret_name n
2471 check_arg_ret_name n;
2472 check_arg_ret_name m
2474 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
2477 (* Check short descriptions. *)
2479 fun (name, _, _, _, _, shortdesc, _) ->
2480 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
2481 failwithf "short description of %s should begin with lowercase." name;
2482 let c = shortdesc.[String.length shortdesc-1] in
2483 if c = '\n' || c = '.' then
2484 failwithf "short description of %s should not end with . or \\n." name
2487 (* Check long dscriptions. *)
2489 fun (name, _, _, _, _, _, longdesc) ->
2490 if longdesc.[String.length longdesc-1] = '\n' then
2491 failwithf "long description of %s should not end with \\n." name
2494 (* Check proc_nrs. *)
2496 fun (name, _, proc_nr, _, _, _, _) ->
2497 if proc_nr <= 0 then
2498 failwithf "daemon function %s should have proc_nr > 0" name
2502 fun (name, _, proc_nr, _, _, _, _) ->
2503 if proc_nr <> -1 then
2504 failwithf "non-daemon function %s should have proc_nr -1" name
2505 ) non_daemon_functions;
2508 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
2511 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
2512 let rec loop = function
2515 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
2517 | (name1,nr1) :: (name2,nr2) :: _ ->
2518 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
2526 (* Ignore functions that have no tests. We generate a
2527 * warning when the user does 'make check' instead.
2529 | name, _, _, _, [], _, _ -> ()
2530 | name, _, _, _, tests, _, _ ->
2534 match seq_of_test test with
2536 failwithf "%s has a test containing an empty sequence" name
2537 | cmds -> List.map List.hd cmds
2539 let funcs = List.flatten funcs in
2541 let tested = List.mem name funcs in
2544 failwithf "function %s has tests but does not test itself" name
2547 (* 'pr' prints to the current output file. *)
2548 let chan = ref stdout
2549 let pr fs = ksprintf (output_string !chan) fs
2551 (* Generate a header block in a number of standard styles. *)
2552 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
2553 type license = GPLv2 | LGPLv2
2555 let generate_header comment license =
2556 let c = match comment with
2557 | CStyle -> pr "/* "; " *"
2558 | HashStyle -> pr "# "; "#"
2559 | OCamlStyle -> pr "(* "; " *"
2560 | HaskellStyle -> pr "{- "; " " in
2561 pr "libguestfs generated file\n";
2562 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
2563 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
2565 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
2569 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
2570 pr "%s it under the terms of the GNU General Public License as published by\n" c;
2571 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
2572 pr "%s (at your option) any later version.\n" c;
2574 pr "%s This program is distributed in the hope that it will be useful,\n" c;
2575 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2576 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
2577 pr "%s GNU General Public License for more details.\n" c;
2579 pr "%s You should have received a copy of the GNU General Public License along\n" c;
2580 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
2581 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
2584 pr "%s This library is free software; you can redistribute it and/or\n" c;
2585 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
2586 pr "%s License as published by the Free Software Foundation; either\n" c;
2587 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
2589 pr "%s This library is distributed in the hope that it will be useful,\n" c;
2590 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2591 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
2592 pr "%s Lesser General Public License for more details.\n" c;
2594 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
2595 pr "%s License along with this library; if not, write to the Free Software\n" c;
2596 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
2599 | CStyle -> pr " */\n"
2601 | OCamlStyle -> pr " *)\n"
2602 | HaskellStyle -> pr "-}\n"
2606 (* Start of main code generation functions below this line. *)
2608 (* Generate the pod documentation for the C API. *)
2609 let rec generate_actions_pod () =
2611 fun (shortname, style, _, flags, _, _, longdesc) ->
2612 let name = "guestfs_" ^ shortname in
2613 pr "=head2 %s\n\n" name;
2615 generate_prototype ~extern:false ~handle:"handle" name style;
2617 pr "%s\n\n" longdesc;
2618 (match fst style with
2620 pr "This function returns 0 on success or -1 on error.\n\n"
2622 pr "On error this function returns -1.\n\n"
2624 pr "On error this function returns -1.\n\n"
2626 pr "This function returns a C truth value on success or -1 on error.\n\n"
2628 pr "This function returns a string, or NULL on error.
2629 The string is owned by the guest handle and must I<not> be freed.\n\n"
2631 pr "This function returns a string, or NULL on error.
2632 I<The caller must free the returned string after use>.\n\n"
2634 pr "This function returns a NULL-terminated array of strings
2635 (like L<environ(3)>), or NULL if there was an error.
2636 I<The caller must free the strings and the array after use>.\n\n"
2638 pr "This function returns a C<struct guestfs_int_bool *>,
2639 or NULL if there was an error.
2640 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
2642 pr "This function returns a C<struct guestfs_lvm_pv_list *>
2643 (see E<lt>guestfs-structs.hE<gt>),
2644 or NULL if there was an error.
2645 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
2647 pr "This function returns a C<struct guestfs_lvm_vg_list *>
2648 (see E<lt>guestfs-structs.hE<gt>),
2649 or NULL if there was an error.
2650 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
2652 pr "This function returns a C<struct guestfs_lvm_lv_list *>
2653 (see E<lt>guestfs-structs.hE<gt>),
2654 or NULL if there was an error.
2655 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
2657 pr "This function returns a C<struct guestfs_stat *>
2658 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
2659 or NULL if there was an error.
2660 I<The caller must call C<free> after use>.\n\n"
2662 pr "This function returns a C<struct guestfs_statvfs *>
2663 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
2664 or NULL if there was an error.
2665 I<The caller must call C<free> after use>.\n\n"
2667 pr "This function returns a NULL-terminated array of
2668 strings, or NULL if there was an error.
2669 The array of strings will always have length C<2n+1>, where
2670 C<n> keys and values alternate, followed by the trailing NULL entry.
2671 I<The caller must free the strings and the array after use>.\n\n"
2673 if List.mem ProtocolLimitWarning flags then
2674 pr "%s\n\n" protocol_limit_warning;
2675 if List.mem DangerWillRobinson flags then
2676 pr "%s\n\n" danger_will_robinson;
2677 ) all_functions_sorted
2679 and generate_structs_pod () =
2680 (* LVM structs documentation. *)
2683 pr "=head2 guestfs_lvm_%s\n" typ;
2685 pr " struct guestfs_lvm_%s {\n" typ;
2688 | name, `String -> pr " char *%s;\n" name
2690 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
2691 pr " char %s[32];\n" name
2692 | name, `Bytes -> pr " uint64_t %s;\n" name
2693 | name, `Int -> pr " int64_t %s;\n" name
2694 | name, `OptPercent ->
2695 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
2696 pr " float %s;\n" name
2699 pr " struct guestfs_lvm_%s_list {\n" typ;
2700 pr " uint32_t len; /* Number of elements in list. */\n";
2701 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
2704 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
2707 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2709 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
2710 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
2712 * We have to use an underscore instead of a dash because otherwise
2713 * rpcgen generates incorrect code.
2715 * This header is NOT exported to clients, but see also generate_structs_h.
2717 and generate_xdr () =
2718 generate_header CStyle LGPLv2;
2720 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
2721 pr "typedef string str<>;\n";
2724 (* LVM internal structures. *)
2728 pr "struct guestfs_lvm_int_%s {\n" typ;
2730 | name, `String -> pr " string %s<>;\n" name
2731 | name, `UUID -> pr " opaque %s[32];\n" name
2732 | name, `Bytes -> pr " hyper %s;\n" name
2733 | name, `Int -> pr " hyper %s;\n" name
2734 | name, `OptPercent -> pr " float %s;\n" name
2738 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
2740 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2742 (* Stat internal structures. *)
2746 pr "struct guestfs_int_%s {\n" typ;
2748 | name, `Int -> pr " hyper %s;\n" name
2752 ) ["stat", stat_cols; "statvfs", statvfs_cols];
2755 fun (shortname, style, _, _, _, _, _) ->
2756 let name = "guestfs_" ^ shortname in
2758 (match snd style with
2761 pr "struct %s_args {\n" name;
2764 | String n -> pr " string %s<>;\n" n
2765 | OptString n -> pr " str *%s;\n" n
2766 | StringList n -> pr " str %s<>;\n" n
2767 | Bool n -> pr " bool %s;\n" n
2768 | Int n -> pr " int %s;\n" n
2769 | FileIn _ | FileOut _ -> ()
2773 (match fst style with
2776 pr "struct %s_ret {\n" name;
2780 pr "struct %s_ret {\n" name;
2781 pr " hyper %s;\n" n;
2784 pr "struct %s_ret {\n" name;
2788 failwithf "RConstString cannot be returned from a daemon function"
2790 pr "struct %s_ret {\n" name;
2791 pr " string %s<>;\n" n;
2794 pr "struct %s_ret {\n" name;
2795 pr " str %s<>;\n" n;
2798 pr "struct %s_ret {\n" name;
2803 pr "struct %s_ret {\n" name;
2804 pr " guestfs_lvm_int_pv_list %s;\n" n;
2807 pr "struct %s_ret {\n" name;
2808 pr " guestfs_lvm_int_vg_list %s;\n" n;
2811 pr "struct %s_ret {\n" name;
2812 pr " guestfs_lvm_int_lv_list %s;\n" n;
2815 pr "struct %s_ret {\n" name;
2816 pr " guestfs_int_stat %s;\n" n;
2819 pr "struct %s_ret {\n" name;
2820 pr " guestfs_int_statvfs %s;\n" n;
2823 pr "struct %s_ret {\n" name;
2824 pr " str %s<>;\n" n;
2829 (* Table of procedure numbers. *)
2830 pr "enum guestfs_procedure {\n";
2832 fun (shortname, _, proc_nr, _, _, _, _) ->
2833 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
2835 pr " GUESTFS_PROC_NR_PROCS\n";
2839 (* Having to choose a maximum message size is annoying for several
2840 * reasons (it limits what we can do in the API), but it (a) makes
2841 * the protocol a lot simpler, and (b) provides a bound on the size
2842 * of the daemon which operates in limited memory space. For large
2843 * file transfers you should use FTP.
2845 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
2848 (* Message header, etc. *)
2850 /* The communication protocol is now documented in the guestfs(3)
2854 const GUESTFS_PROGRAM = 0x2000F5F5;
2855 const GUESTFS_PROTOCOL_VERSION = 1;
2857 /* These constants must be larger than any possible message length. */
2858 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
2859 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
2861 enum guestfs_message_direction {
2862 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
2863 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
2866 enum guestfs_message_status {
2867 GUESTFS_STATUS_OK = 0,
2868 GUESTFS_STATUS_ERROR = 1
2871 const GUESTFS_ERROR_LEN = 256;
2873 struct guestfs_message_error {
2874 string error_message<GUESTFS_ERROR_LEN>;
2877 struct guestfs_message_header {
2878 unsigned prog; /* GUESTFS_PROGRAM */
2879 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
2880 guestfs_procedure proc; /* GUESTFS_PROC_x */
2881 guestfs_message_direction direction;
2882 unsigned serial; /* message serial number */
2883 guestfs_message_status status;
2886 const GUESTFS_MAX_CHUNK_SIZE = 8192;
2888 struct guestfs_chunk {
2889 int cancel; /* if non-zero, transfer is cancelled */
2890 /* data size is 0 bytes if the transfer has finished successfully */
2891 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
2895 (* Generate the guestfs-structs.h file. *)
2896 and generate_structs_h () =
2897 generate_header CStyle LGPLv2;
2899 (* This is a public exported header file containing various
2900 * structures. The structures are carefully written to have
2901 * exactly the same in-memory format as the XDR structures that
2902 * we use on the wire to the daemon. The reason for creating
2903 * copies of these structures here is just so we don't have to
2904 * export the whole of guestfs_protocol.h (which includes much
2905 * unrelated and XDR-dependent stuff that we don't want to be
2906 * public, or required by clients).
2908 * To reiterate, we will pass these structures to and from the
2909 * client with a simple assignment or memcpy, so the format
2910 * must be identical to what rpcgen / the RFC defines.
2913 (* guestfs_int_bool structure. *)
2914 pr "struct guestfs_int_bool {\n";
2920 (* LVM public structures. *)
2924 pr "struct guestfs_lvm_%s {\n" typ;
2927 | name, `String -> pr " char *%s;\n" name
2928 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
2929 | name, `Bytes -> pr " uint64_t %s;\n" name
2930 | name, `Int -> pr " int64_t %s;\n" name
2931 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
2935 pr "struct guestfs_lvm_%s_list {\n" typ;
2936 pr " uint32_t len;\n";
2937 pr " struct guestfs_lvm_%s *val;\n" typ;
2940 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2942 (* Stat structures. *)
2946 pr "struct guestfs_%s {\n" typ;
2949 | name, `Int -> pr " int64_t %s;\n" name
2953 ) ["stat", stat_cols; "statvfs", statvfs_cols]
2955 (* Generate the guestfs-actions.h file. *)
2956 and generate_actions_h () =
2957 generate_header CStyle LGPLv2;
2959 fun (shortname, style, _, _, _, _, _) ->
2960 let name = "guestfs_" ^ shortname in
2961 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
2965 (* Generate the client-side dispatch stubs. *)
2966 and generate_client_actions () =
2967 generate_header CStyle LGPLv2;
2973 #include \"guestfs.h\"
2974 #include \"guestfs_protocol.h\"
2976 #define error guestfs_error
2977 #define perrorf guestfs_perrorf
2978 #define safe_malloc guestfs_safe_malloc
2979 #define safe_realloc guestfs_safe_realloc
2980 #define safe_strdup guestfs_safe_strdup
2981 #define safe_memdup guestfs_safe_memdup
2983 /* Check the return message from a call for validity. */
2985 check_reply_header (guestfs_h *g,
2986 const struct guestfs_message_header *hdr,
2987 int proc_nr, int serial)
2989 if (hdr->prog != GUESTFS_PROGRAM) {
2990 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
2993 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
2994 error (g, \"wrong protocol version (%%d/%%d)\",
2995 hdr->vers, GUESTFS_PROTOCOL_VERSION);
2998 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
2999 error (g, \"unexpected message direction (%%d/%%d)\",
3000 hdr->direction, GUESTFS_DIRECTION_REPLY);
3003 if (hdr->proc != proc_nr) {
3004 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3007 if (hdr->serial != serial) {
3008 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3015 /* Check we are in the right state to run a high-level action. */
3017 check_state (guestfs_h *g, const char *caller)
3019 if (!guestfs_is_ready (g)) {
3020 if (guestfs_is_config (g))
3021 error (g, \"%%s: call launch() before using this function\",
3023 else if (guestfs_is_launching (g))
3024 error (g, \"%%s: call wait_ready() before using this function\",
3027 error (g, \"%%s called from the wrong state, %%d != READY\",
3028 caller, guestfs_get_state (g));
3036 (* Client-side stubs for each function. *)
3038 fun (shortname, style, _, _, _, _, _) ->
3039 let name = "guestfs_" ^ shortname in
3041 (* Generate the context struct which stores the high-level
3042 * state between callback functions.
3044 pr "struct %s_ctx {\n" shortname;
3045 pr " /* This flag is set by the callbacks, so we know we've done\n";
3046 pr " * the callbacks as expected, and in the right sequence.\n";
3047 pr " * 0 = not called, 1 = reply_cb called.\n";
3049 pr " int cb_sequence;\n";
3050 pr " struct guestfs_message_header hdr;\n";
3051 pr " struct guestfs_message_error err;\n";
3052 (match fst style with
3055 failwithf "RConstString cannot be returned from a daemon function"
3057 | RBool _ | RString _ | RStringList _
3059 | RPVList _ | RVGList _ | RLVList _
3060 | RStat _ | RStatVFS _
3062 pr " struct %s_ret ret;\n" name
3067 (* Generate the reply callback function. *)
3068 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3070 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3071 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3073 pr " /* This should definitely not happen. */\n";
3074 pr " if (ctx->cb_sequence != 0) {\n";
3075 pr " ctx->cb_sequence = 9999;\n";
3076 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3080 pr " ml->main_loop_quit (ml, g);\n";
3082 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3083 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3086 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3087 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3088 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3095 (match fst style with
3098 failwithf "RConstString cannot be returned from a daemon function"
3100 | RBool _ | RString _ | RStringList _
3102 | RPVList _ | RVGList _ | RLVList _
3103 | RStat _ | RStatVFS _
3105 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3106 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3112 pr " ctx->cb_sequence = 1;\n";
3115 (* Generate the action stub. *)
3116 generate_prototype ~extern:false ~semicolon:false ~newline:true
3117 ~handle:"g" name style;
3120 match fst style with
3121 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3123 failwithf "RConstString cannot be returned from a daemon function"
3124 | RString _ | RStringList _ | RIntBool _
3125 | RPVList _ | RVGList _ | RLVList _
3126 | RStat _ | RStatVFS _
3132 (match snd style with
3134 | _ -> pr " struct %s_args args;\n" name
3137 pr " struct %s_ctx ctx;\n" shortname;
3138 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3139 pr " int serial;\n";
3141 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3142 pr " guestfs_set_busy (g);\n";
3144 pr " memset (&ctx, 0, sizeof ctx);\n";
3147 (* Send the main header and arguments. *)
3148 (match snd style with
3150 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3151 (String.uppercase shortname)
3156 pr " args.%s = (char *) %s;\n" n n
3158 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
3160 pr " args.%s.%s_val = (char **) %s;\n" n n n;
3161 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3163 pr " args.%s = %s;\n" n n
3165 pr " args.%s = %s;\n" n n
3166 | FileIn _ | FileOut _ -> ()
3168 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3169 (String.uppercase shortname);
3170 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3173 pr " if (serial == -1) {\n";
3174 pr " guestfs_end_busy (g);\n";
3175 pr " return %s;\n" error_code;
3179 (* Send any additional files (FileIn) requested. *)
3180 let need_read_reply_label = ref false in
3187 pr " r = guestfs__send_file_sync (g, %s);\n" n;
3188 pr " if (r == -1) {\n";
3189 pr " guestfs_end_busy (g);\n";
3190 pr " return %s;\n" error_code;
3192 pr " if (r == -2) /* daemon cancelled */\n";
3193 pr " goto read_reply;\n";
3194 need_read_reply_label := true;
3200 (* Wait for the reply from the remote end. *)
3201 if !need_read_reply_label then pr " read_reply:\n";
3202 pr " guestfs__switch_to_receiving (g);\n";
3203 pr " ctx.cb_sequence = 0;\n";
3204 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3205 pr " (void) ml->main_loop_run (ml, g);\n";
3206 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
3207 pr " if (ctx.cb_sequence != 1) {\n";
3208 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3209 pr " guestfs_end_busy (g);\n";
3210 pr " return %s;\n" error_code;
3214 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3215 (String.uppercase shortname);
3216 pr " guestfs_end_busy (g);\n";
3217 pr " return %s;\n" error_code;
3221 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3222 pr " error (g, \"%%s\", ctx.err.error_message);\n";
3223 pr " free (ctx.err.error_message);\n";
3224 pr " guestfs_end_busy (g);\n";
3225 pr " return %s;\n" error_code;
3229 (* Expecting to receive further files (FileOut)? *)
3233 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3234 pr " guestfs_end_busy (g);\n";
3235 pr " return %s;\n" error_code;
3241 pr " guestfs_end_busy (g);\n";
3243 (match fst style with
3244 | RErr -> pr " return 0;\n"
3245 | RInt n | RInt64 n | RBool n ->
3246 pr " return ctx.ret.%s;\n" n
3248 failwithf "RConstString cannot be returned from a daemon function"
3250 pr " return ctx.ret.%s; /* caller will free */\n" n
3251 | RStringList n | RHashtable n ->
3252 pr " /* caller will free this, but we need to add a NULL entry */\n";
3253 pr " ctx.ret.%s.%s_val =\n" n n;
3254 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3255 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3257 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3258 pr " return ctx.ret.%s.%s_val;\n" n n
3260 pr " /* caller with free this */\n";
3261 pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3262 | RPVList n | RVGList n | RLVList n
3263 | RStat n | RStatVFS n ->
3264 pr " /* caller will free this */\n";
3265 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3271 (* Generate daemon/actions.h. *)
3272 and generate_daemon_actions_h () =
3273 generate_header CStyle GPLv2;
3275 pr "#include \"../src/guestfs_protocol.h\"\n";
3279 fun (name, style, _, _, _, _, _) ->
3281 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3285 (* Generate the server-side stubs. *)
3286 and generate_daemon_actions () =
3287 generate_header CStyle GPLv2;
3289 pr "#include <config.h>\n";
3291 pr "#include <stdio.h>\n";
3292 pr "#include <stdlib.h>\n";
3293 pr "#include <string.h>\n";
3294 pr "#include <inttypes.h>\n";
3295 pr "#include <ctype.h>\n";
3296 pr "#include <rpc/types.h>\n";
3297 pr "#include <rpc/xdr.h>\n";
3299 pr "#include \"daemon.h\"\n";
3300 pr "#include \"../src/guestfs_protocol.h\"\n";
3301 pr "#include \"actions.h\"\n";
3305 fun (name, style, _, _, _, _, _) ->
3306 (* Generate server-side stubs. *)
3307 pr "static void %s_stub (XDR *xdr_in)\n" name;
3310 match fst style with
3311 | RErr | RInt _ -> pr " int r;\n"; "-1"
3312 | RInt64 _ -> pr " int64_t r;\n"; "-1"
3313 | RBool _ -> pr " int r;\n"; "-1"
3315 failwithf "RConstString cannot be returned from a daemon function"
3316 | RString _ -> pr " char *r;\n"; "NULL"
3317 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
3318 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
3319 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
3320 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
3321 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
3322 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
3323 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
3325 (match snd style with
3328 pr " struct guestfs_%s_args args;\n" name;
3332 | OptString n -> pr " const char *%s;\n" n
3333 | StringList n -> pr " char **%s;\n" n
3334 | Bool n -> pr " int %s;\n" n
3335 | Int n -> pr " int %s;\n" n
3336 | FileIn _ | FileOut _ -> ()
3341 (match snd style with
3344 pr " memset (&args, 0, sizeof args);\n";
3346 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
3347 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
3352 | String n -> pr " %s = args.%s;\n" n n
3353 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
3355 pr " %s = realloc (args.%s.%s_val,\n" n n n;
3356 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
3357 pr " if (%s == NULL) {\n" n;
3358 pr " reply_with_perror (\"realloc\");\n";
3361 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
3362 pr " args.%s.%s_val = %s;\n" n n n;
3363 | Bool n -> pr " %s = args.%s;\n" n n
3364 | Int n -> pr " %s = args.%s;\n" n n
3365 | FileIn _ | FileOut _ -> ()
3370 (* Don't want to call the impl with any FileIn or FileOut
3371 * parameters, since these go "outside" the RPC protocol.
3374 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
3376 pr " r = do_%s " name;
3377 generate_call_args argsnofile;
3380 pr " if (r == %s)\n" error_code;
3381 pr " /* do_%s has already called reply_with_error */\n" name;
3385 (* If there are any FileOut parameters, then the impl must
3386 * send its own reply.
3389 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
3391 pr " /* do_%s has already sent a reply */\n" name
3393 match fst style with
3394 | RErr -> pr " reply (NULL, NULL);\n"
3395 | RInt n | RInt64 n | RBool n ->
3396 pr " struct guestfs_%s_ret ret;\n" name;
3397 pr " ret.%s = r;\n" n;
3398 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3401 failwithf "RConstString cannot be returned from a daemon function"
3403 pr " struct guestfs_%s_ret ret;\n" name;
3404 pr " ret.%s = r;\n" n;
3405 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3408 | RStringList n | RHashtable n ->
3409 pr " struct guestfs_%s_ret ret;\n" name;
3410 pr " ret.%s.%s_len = count_strings (r);\n" n n;
3411 pr " ret.%s.%s_val = r;\n" n n;
3412 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3414 pr " free_strings (r);\n"
3416 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
3418 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
3419 | RPVList n | RVGList n | RLVList n
3420 | RStat n | RStatVFS n ->
3421 pr " struct guestfs_%s_ret ret;\n" name;
3422 pr " ret.%s = *r;\n" n;
3423 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3425 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3429 (* Free the args. *)
3430 (match snd style with
3435 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
3442 (* Dispatch function. *)
3443 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
3445 pr " switch (proc_nr) {\n";
3448 fun (name, style, _, _, _, _, _) ->
3449 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
3450 pr " %s_stub (xdr_in);\n" name;
3455 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
3460 (* LVM columns and tokenization functions. *)
3461 (* XXX This generates crap code. We should rethink how we
3467 pr "static const char *lvm_%s_cols = \"%s\";\n"
3468 typ (String.concat "," (List.map fst cols));
3471 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
3473 pr " char *tok, *p, *next;\n";
3477 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
3480 pr " if (!str) {\n";
3481 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
3484 pr " if (!*str || isspace (*str)) {\n";
3485 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
3490 fun (name, coltype) ->
3491 pr " if (!tok) {\n";
3492 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
3495 pr " p = strchrnul (tok, ',');\n";
3496 pr " if (*p) next = p+1; else next = NULL;\n";
3497 pr " *p = '\\0';\n";
3500 pr " r->%s = strdup (tok);\n" name;
3501 pr " if (r->%s == NULL) {\n" name;
3502 pr " perror (\"strdup\");\n";
3506 pr " for (i = j = 0; i < 32; ++j) {\n";
3507 pr " if (tok[j] == '\\0') {\n";
3508 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
3510 pr " } else if (tok[j] != '-')\n";
3511 pr " r->%s[i++] = tok[j];\n" name;
3514 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
3515 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3519 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
3520 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3524 pr " if (tok[0] == '\\0')\n";
3525 pr " r->%s = -1;\n" name;
3526 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
3527 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3531 pr " tok = next;\n";
3534 pr " if (tok != NULL) {\n";
3535 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
3542 pr "guestfs_lvm_int_%s_list *\n" typ;
3543 pr "parse_command_line_%ss (void)\n" typ;
3545 pr " char *out, *err;\n";
3546 pr " char *p, *pend;\n";
3548 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
3549 pr " void *newp;\n";
3551 pr " ret = malloc (sizeof *ret);\n";
3552 pr " if (!ret) {\n";
3553 pr " reply_with_perror (\"malloc\");\n";
3554 pr " return NULL;\n";
3557 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
3558 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
3560 pr " r = command (&out, &err,\n";
3561 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
3562 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
3563 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
3564 pr " if (r == -1) {\n";
3565 pr " reply_with_error (\"%%s\", err);\n";
3566 pr " free (out);\n";
3567 pr " free (err);\n";
3568 pr " free (ret);\n";
3569 pr " return NULL;\n";
3572 pr " free (err);\n";
3574 pr " /* Tokenize each line of the output. */\n";
3577 pr " while (p) {\n";
3578 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
3579 pr " if (pend) {\n";
3580 pr " *pend = '\\0';\n";
3584 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
3587 pr " if (!*p) { /* Empty line? Skip it. */\n";
3592 pr " /* Allocate some space to store this next entry. */\n";
3593 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
3594 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
3595 pr " if (newp == NULL) {\n";
3596 pr " reply_with_perror (\"realloc\");\n";
3597 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3598 pr " free (ret);\n";
3599 pr " free (out);\n";
3600 pr " return NULL;\n";
3602 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
3604 pr " /* Tokenize the next entry. */\n";
3605 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
3606 pr " if (r == -1) {\n";
3607 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
3608 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3609 pr " free (ret);\n";
3610 pr " free (out);\n";
3611 pr " return NULL;\n";
3618 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
3620 pr " free (out);\n";
3621 pr " return ret;\n";
3624 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3626 (* Generate the tests. *)
3627 and generate_tests () =
3628 generate_header CStyle GPLv2;
3635 #include <sys/types.h>
3638 #include \"guestfs.h\"
3640 static guestfs_h *g;
3641 static int suppress_error = 0;
3643 /* This will be 's' or 'h' depending on whether the guest kernel
3644 * names IDE devices /dev/sd* or /dev/hd*.
3646 static char devchar = 's';
3648 static void print_error (guestfs_h *g, void *data, const char *msg)
3650 if (!suppress_error)
3651 fprintf (stderr, \"%%s\\n\", msg);
3654 static void print_strings (char * const * const argv)
3658 for (argc = 0; argv[argc] != NULL; ++argc)
3659 printf (\"\\t%%s\\n\", argv[argc]);
3663 static void print_table (char * const * const argv)
3667 for (i = 0; argv[i] != NULL; i += 2)
3668 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
3672 static void no_test_warnings (void)
3678 | name, _, _, _, [], _, _ ->
3679 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
3680 | name, _, _, _, tests, _, _ -> ()
3686 (* Generate the actual tests. Note that we generate the tests
3687 * in reverse order, deliberately, so that (in general) the
3688 * newest tests run first. This makes it quicker and easier to
3693 fun (name, _, _, _, tests, _, _) ->
3694 mapi (generate_one_test name) tests
3695 ) (List.rev all_functions) in
3696 let test_names = List.concat test_names in
3697 let nr_tests = List.length test_names in
3700 int main (int argc, char *argv[])
3705 const char *filename;
3707 int nr_tests, test_num = 0;
3710 no_test_warnings ();
3712 g = guestfs_create ();
3714 printf (\"guestfs_create FAILED\\n\");
3718 guestfs_set_error_handler (g, print_error, NULL);
3720 guestfs_set_path (g, \"../appliance\");
3722 filename = \"test1.img\";
3723 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3728 if (lseek (fd, %d, SEEK_SET) == -1) {
3734 if (write (fd, &c, 1) == -1) {
3740 if (close (fd) == -1) {
3745 if (guestfs_add_drive (g, filename) == -1) {
3746 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3750 filename = \"test2.img\";
3751 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3756 if (lseek (fd, %d, SEEK_SET) == -1) {
3762 if (write (fd, &c, 1) == -1) {
3768 if (close (fd) == -1) {
3773 if (guestfs_add_drive (g, filename) == -1) {
3774 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3778 filename = \"test3.img\";
3779 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3784 if (lseek (fd, %d, SEEK_SET) == -1) {
3790 if (write (fd, &c, 1) == -1) {
3796 if (close (fd) == -1) {
3801 if (guestfs_add_drive (g, filename) == -1) {
3802 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3806 if (guestfs_launch (g) == -1) {
3807 printf (\"guestfs_launch FAILED\\n\");
3810 if (guestfs_wait_ready (g) == -1) {
3811 printf (\"guestfs_wait_ready FAILED\\n\");
3815 /* Detect if the appliance uses /dev/sd* or /dev/hd* in device
3816 * names. This changed between RHEL 5 and RHEL 6 so we have to
3819 devs = guestfs_list_devices (g);
3820 if (devs == NULL || devs[0] == NULL) {
3821 printf (\"guestfs_list_devices FAILED\\n\");
3824 if (strncmp (devs[0], \"/dev/sd\", 7) == 0)
3826 else if (strncmp (devs[0], \"/dev/hd\", 7) == 0)
3829 printf (\"guestfs_list_devices returned unexpected string '%%s'\\n\",
3833 for (i = 0; devs[i] != NULL; ++i)
3839 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
3843 pr " test_num++;\n";
3844 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
3845 pr " if (%s () == -1) {\n" test_name;
3846 pr " printf (\"%s FAILED\\n\");\n" test_name;
3852 pr " guestfs_close (g);\n";
3853 pr " unlink (\"test1.img\");\n";
3854 pr " unlink (\"test2.img\");\n";
3855 pr " unlink (\"test3.img\");\n";
3858 pr " if (failed > 0) {\n";
3859 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
3867 and generate_one_test name i (init, prereq, test) =
3868 let test_name = sprintf "test_%s_%d" name i in
3871 static int %s_skip (void)
3875 str = getenv (\"SKIP_%s\");
3876 if (str && strcmp (str, \"1\") == 0) return 1;
3877 str = getenv (\"SKIP_TEST_%s\");
3878 if (str && strcmp (str, \"1\") == 0) return 1;
3882 " test_name (String.uppercase test_name) (String.uppercase name);
3885 | Disabled | Always -> ()
3886 | If code | Unless code ->
3887 pr "static int %s_prereq (void)\n" test_name;
3895 static int %s (void)
3898 printf (\"%%s skipped (reason: SKIP_TEST_* variable set)\\n\", \"%s\");
3902 " test_name test_name test_name;
3906 pr " printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
3908 pr " if (! %s_prereq ()) {\n" test_name;
3909 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
3913 generate_one_test_body name i test_name init test;
3915 pr " if (%s_prereq ()) {\n" test_name;
3916 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
3920 generate_one_test_body name i test_name init test;
3922 generate_one_test_body name i test_name init test
3930 and generate_one_test_body name i test_name init test =
3934 pr " /* InitNone|InitEmpty for %s */\n" test_name;
3935 List.iter (generate_test_command_call test_name)
3936 [["blockdev_setrw"; "/dev/sda"];
3940 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
3941 List.iter (generate_test_command_call test_name)
3942 [["blockdev_setrw"; "/dev/sda"];
3945 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3946 ["mkfs"; "ext2"; "/dev/sda1"];
3947 ["mount"; "/dev/sda1"; "/"]]
3948 | InitBasicFSonLVM ->
3949 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
3951 List.iter (generate_test_command_call test_name)
3952 [["blockdev_setrw"; "/dev/sda"];
3955 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3956 ["pvcreate"; "/dev/sda1"];
3957 ["vgcreate"; "VG"; "/dev/sda1"];
3958 ["lvcreate"; "LV"; "VG"; "8"];
3959 ["mkfs"; "ext2"; "/dev/VG/LV"];
3960 ["mount"; "/dev/VG/LV"; "/"]]
3963 let get_seq_last = function
3965 failwithf "%s: you cannot use [] (empty list) when expecting a command"
3968 let seq = List.rev seq in
3969 List.rev (List.tl seq), List.hd seq
3974 pr " /* TestRun for %s (%d) */\n" name i;
3975 List.iter (generate_test_command_call test_name) seq
3976 | TestOutput (seq, expected) ->
3977 pr " /* TestOutput for %s (%d) */\n" name i;
3978 pr " char expected[] = \"%s\";\n" (c_quote expected);
3979 if String.length expected > 7 &&
3980 String.sub expected 0 7 = "/dev/sd" then
3981 pr " expected[5] = devchar;\n";
3982 let seq, last = get_seq_last seq in
3984 pr " if (strcmp (r, expected) != 0) {\n";
3985 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
3989 List.iter (generate_test_command_call test_name) seq;
3990 generate_test_command_call ~test test_name last
3991 | TestOutputList (seq, expected) ->
3992 pr " /* TestOutputList for %s (%d) */\n" name i;
3993 let seq, last = get_seq_last seq in
3997 pr " if (!r[%d]) {\n" i;
3998 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
3999 pr " print_strings (r);\n";
4003 pr " char expected[] = \"%s\";\n" (c_quote str);
4004 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
4005 pr " expected[5] = devchar;\n";
4006 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
4007 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4012 pr " if (r[%d] != NULL) {\n" (List.length expected);
4013 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4015 pr " print_strings (r);\n";
4019 List.iter (generate_test_command_call test_name) seq;
4020 generate_test_command_call ~test test_name last
4021 | TestOutputInt (seq, expected) ->
4022 pr " /* TestOutputInt for %s (%d) */\n" name i;
4023 let seq, last = get_seq_last seq in
4025 pr " if (r != %d) {\n" expected;
4026 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4032 List.iter (generate_test_command_call test_name) seq;
4033 generate_test_command_call ~test test_name last
4034 | TestOutputTrue seq ->
4035 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4036 let seq, last = get_seq_last seq in
4039 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4044 List.iter (generate_test_command_call test_name) seq;
4045 generate_test_command_call ~test test_name last
4046 | TestOutputFalse seq ->
4047 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4048 let seq, last = get_seq_last seq in
4051 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4056 List.iter (generate_test_command_call test_name) seq;
4057 generate_test_command_call ~test test_name last
4058 | TestOutputLength (seq, expected) ->
4059 pr " /* TestOutputLength for %s (%d) */\n" name i;
4060 let seq, last = get_seq_last seq in
4063 pr " for (j = 0; j < %d; ++j)\n" expected;
4064 pr " if (r[j] == NULL) {\n";
4065 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4067 pr " print_strings (r);\n";
4070 pr " if (r[j] != NULL) {\n";
4071 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4073 pr " print_strings (r);\n";
4077 List.iter (generate_test_command_call test_name) seq;
4078 generate_test_command_call ~test test_name last
4079 | TestOutputStruct (seq, checks) ->
4080 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4081 let seq, last = get_seq_last seq in
4085 | CompareWithInt (field, expected) ->
4086 pr " if (r->%s != %d) {\n" field expected;
4087 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4088 test_name field expected;
4089 pr " (int) r->%s);\n" field;
4092 | CompareWithString (field, expected) ->
4093 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4094 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4095 test_name field expected;
4096 pr " r->%s);\n" field;
4099 | CompareFieldsIntEq (field1, field2) ->
4100 pr " if (r->%s != r->%s) {\n" field1 field2;
4101 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4102 test_name field1 field2;
4103 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4106 | CompareFieldsStrEq (field1, field2) ->
4107 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4108 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4109 test_name field1 field2;
4110 pr " r->%s, r->%s);\n" field1 field2;
4115 List.iter (generate_test_command_call test_name) seq;
4116 generate_test_command_call ~test test_name last
4117 | TestLastFail seq ->
4118 pr " /* TestLastFail for %s (%d) */\n" name i;
4119 let seq, last = get_seq_last seq in
4120 List.iter (generate_test_command_call test_name) seq;
4121 generate_test_command_call test_name ~expect_error:true last
4123 (* Generate the code to run a command, leaving the result in 'r'.
4124 * If you expect to get an error then you should set expect_error:true.
4126 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4128 | [] -> assert false
4130 (* Look up the command to find out what args/ret it has. *)
4133 let _, style, _, _, _, _, _ =
4134 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4137 failwithf "%s: in test, command %s was not found" test_name name in
4139 if List.length (snd style) <> List.length args then
4140 failwithf "%s: in test, wrong number of args given to %s"
4147 | OptString n, "NULL" -> ()
4149 | OptString n, arg ->
4150 pr " char %s[] = \"%s\";\n" n (c_quote arg);
4151 if String.length arg > 7 && String.sub arg 0 7 = "/dev/sd" then
4152 pr " %s[5] = devchar;\n" n
4155 | FileIn _, _ | FileOut _, _ -> ()
4156 | StringList n, arg ->
4157 let strs = string_split " " arg in
4160 pr " char %s_%d[] = \"%s\";\n" n i (c_quote str);
4161 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
4162 pr " %s_%d[5] = devchar;\n" n i
4164 pr " char *%s[] = {\n" n;
4166 fun i _ -> pr " %s_%d,\n" n i
4170 ) (List.combine (snd style) args);
4173 match fst style with
4174 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4175 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4176 | RConstString _ -> pr " const char *r;\n"; "NULL"
4177 | RString _ -> pr " char *r;\n"; "NULL"
4178 | RStringList _ | RHashtable _ ->
4183 pr " struct guestfs_int_bool *r;\n"; "NULL"
4185 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4187 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4189 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4191 pr " struct guestfs_stat *r;\n"; "NULL"
4193 pr " struct guestfs_statvfs *r;\n"; "NULL" in
4195 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4196 pr " r = guestfs_%s (g" name;
4198 (* Generate the parameters. *)
4201 | OptString _, "NULL" -> pr ", NULL"
4205 | FileIn _, arg | FileOut _, arg ->
4206 pr ", \"%s\"" (c_quote arg)
4207 | StringList n, _ ->
4211 try int_of_string arg
4212 with Failure "int_of_string" ->
4213 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4216 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4217 ) (List.combine (snd style) args);
4220 if not expect_error then
4221 pr " if (r == %s)\n" error_code
4223 pr " if (r != %s)\n" error_code;
4226 (* Insert the test code. *)
4232 (match fst style with
4233 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4234 | RString _ -> pr " free (r);\n"
4235 | RStringList _ | RHashtable _ ->
4236 pr " for (i = 0; r[i] != NULL; ++i)\n";
4237 pr " free (r[i]);\n";
4240 pr " guestfs_free_int_bool (r);\n"
4242 pr " guestfs_free_lvm_pv_list (r);\n"
4244 pr " guestfs_free_lvm_vg_list (r);\n"
4246 pr " guestfs_free_lvm_lv_list (r);\n"
4247 | RStat _ | RStatVFS _ ->
4254 let str = replace_str str "\r" "\\r" in
4255 let str = replace_str str "\n" "\\n" in
4256 let str = replace_str str "\t" "\\t" in
4257 let str = replace_str str "\000" "\\0" in
4260 (* Generate a lot of different functions for guestfish. *)
4261 and generate_fish_cmds () =
4262 generate_header CStyle GPLv2;
4266 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4268 let all_functions_sorted =
4270 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4271 ) all_functions_sorted in
4273 pr "#include <stdio.h>\n";
4274 pr "#include <stdlib.h>\n";
4275 pr "#include <string.h>\n";
4276 pr "#include <inttypes.h>\n";
4278 pr "#include <guestfs.h>\n";
4279 pr "#include \"fish.h\"\n";
4282 (* list_commands function, which implements guestfish -h *)
4283 pr "void list_commands (void)\n";
4285 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
4286 pr " list_builtin_commands ();\n";
4288 fun (name, _, _, flags, _, shortdesc, _) ->
4289 let name = replace_char name '_' '-' in
4290 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4292 ) all_functions_sorted;
4293 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4297 (* display_command function, which implements guestfish -h cmd *)
4298 pr "void display_command (const char *cmd)\n";
4301 fun (name, style, _, flags, _, shortdesc, longdesc) ->
4302 let name2 = replace_char name '_' '-' in
4304 try find_map (function FishAlias n -> Some n | _ -> None) flags
4305 with Not_found -> name in
4306 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4308 match snd style with
4312 name2 (String.concat "> <" (List.map name_of_argt args)) in
4315 if List.mem ProtocolLimitWarning flags then
4316 ("\n\n" ^ protocol_limit_warning)
4319 (* For DangerWillRobinson commands, we should probably have
4320 * guestfish prompt before allowing you to use them (especially
4321 * in interactive mode). XXX
4325 if List.mem DangerWillRobinson flags then
4326 ("\n\n" ^ danger_will_robinson)
4329 let describe_alias =
4330 if name <> alias then
4331 sprintf "\n\nYou can use '%s' as an alias for this command." alias
4335 pr "strcasecmp (cmd, \"%s\") == 0" name;
4336 if name <> name2 then
4337 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4338 if name <> alias then
4339 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4341 pr " pod2text (\"%s - %s\", %S);\n"
4343 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4346 pr " display_builtin_command (cmd);\n";
4350 (* print_{pv,vg,lv}_list functions *)
4354 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4361 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4363 pr " printf (\"%s: \");\n" name;
4364 pr " for (i = 0; i < 32; ++i)\n";
4365 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
4366 pr " printf (\"\\n\");\n"
4368 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4370 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4371 | name, `OptPercent ->
4372 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4373 typ name name typ name;
4374 pr " else printf (\"%s: \\n\");\n" name
4378 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4383 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4384 pr " print_%s (&%ss->val[i]);\n" typ typ;
4387 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4389 (* print_{stat,statvfs} functions *)
4393 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4398 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4402 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4404 (* run_<action> actions *)
4406 fun (name, style, _, flags, _, _, _) ->
4407 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4409 (match fst style with
4412 | RBool _ -> pr " int r;\n"
4413 | RInt64 _ -> pr " int64_t r;\n"
4414 | RConstString _ -> pr " const char *r;\n"
4415 | RString _ -> pr " char *r;\n"
4416 | RStringList _ | RHashtable _ -> pr " char **r;\n"
4417 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
4418 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
4419 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
4420 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
4421 | RStat _ -> pr " struct guestfs_stat *r;\n"
4422 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
4429 | FileOut n -> pr " const char *%s;\n" n
4430 | StringList n -> pr " char **%s;\n" n
4431 | Bool n -> pr " int %s;\n" n
4432 | Int n -> pr " int %s;\n" n
4435 (* Check and convert parameters. *)
4436 let argc_expected = List.length (snd style) in
4437 pr " if (argc != %d) {\n" argc_expected;
4438 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
4440 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
4446 | String name -> pr " %s = argv[%d];\n" name i
4448 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
4451 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
4454 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
4456 | StringList name ->
4457 pr " %s = parse_string_list (argv[%d]);\n" name i
4459 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
4461 pr " %s = atoi (argv[%d]);\n" name i
4464 (* Call C API function. *)
4466 try find_map (function FishAction n -> Some n | _ -> None) flags
4467 with Not_found -> sprintf "guestfs_%s" name in
4469 generate_call_args ~handle:"g" (snd style);
4472 (* Check return value for errors and display command results. *)
4473 (match fst style with
4474 | RErr -> pr " return r;\n"
4476 pr " if (r == -1) return -1;\n";
4477 pr " printf (\"%%d\\n\", r);\n";
4480 pr " if (r == -1) return -1;\n";
4481 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
4484 pr " if (r == -1) return -1;\n";
4485 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
4488 pr " if (r == NULL) return -1;\n";
4489 pr " printf (\"%%s\\n\", r);\n";
4492 pr " if (r == NULL) return -1;\n";
4493 pr " printf (\"%%s\\n\", r);\n";
4497 pr " if (r == NULL) return -1;\n";
4498 pr " print_strings (r);\n";
4499 pr " free_strings (r);\n";
4502 pr " if (r == NULL) return -1;\n";
4503 pr " printf (\"%%d, %%s\\n\", r->i,\n";
4504 pr " r->b ? \"true\" : \"false\");\n";
4505 pr " guestfs_free_int_bool (r);\n";
4508 pr " if (r == NULL) return -1;\n";
4509 pr " print_pv_list (r);\n";
4510 pr " guestfs_free_lvm_pv_list (r);\n";
4513 pr " if (r == NULL) return -1;\n";
4514 pr " print_vg_list (r);\n";
4515 pr " guestfs_free_lvm_vg_list (r);\n";
4518 pr " if (r == NULL) return -1;\n";
4519 pr " print_lv_list (r);\n";
4520 pr " guestfs_free_lvm_lv_list (r);\n";
4523 pr " if (r == NULL) return -1;\n";
4524 pr " print_stat (r);\n";
4528 pr " if (r == NULL) return -1;\n";
4529 pr " print_statvfs (r);\n";
4533 pr " if (r == NULL) return -1;\n";
4534 pr " print_table (r);\n";
4535 pr " free_strings (r);\n";
4542 (* run_action function *)
4543 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
4546 fun (name, _, _, flags, _, _, _) ->
4547 let name2 = replace_char name '_' '-' in
4549 try find_map (function FishAlias n -> Some n | _ -> None) flags
4550 with Not_found -> name in
4552 pr "strcasecmp (cmd, \"%s\") == 0" name;
4553 if name <> name2 then
4554 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4555 if name <> alias then
4556 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4558 pr " return run_%s (cmd, argc, argv);\n" name;
4562 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
4569 (* Readline completion for guestfish. *)
4570 and generate_fish_completion () =
4571 generate_header CStyle GPLv2;
4575 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4585 #ifdef HAVE_LIBREADLINE
4586 #include <readline/readline.h>
4591 #ifdef HAVE_LIBREADLINE
4593 static const char *const commands[] = {
4594 BUILTIN_COMMANDS_FOR_COMPLETION,
4597 (* Get the commands, including the aliases. They don't need to be
4598 * sorted - the generator() function just does a dumb linear search.
4602 fun (name, _, _, flags, _, _, _) ->
4603 let name2 = replace_char name '_' '-' in
4605 try find_map (function FishAlias n -> Some n | _ -> None) flags
4606 with Not_found -> name in
4608 if name <> alias then [name2; alias] else [name2]
4610 let commands = List.flatten commands in
4612 List.iter (pr " \"%s\",\n") commands;
4618 generator (const char *text, int state)
4620 static int index, len;
4625 len = strlen (text);
4628 while ((name = commands[index]) != NULL) {
4630 if (strncasecmp (name, text, len) == 0)
4631 return strdup (name);
4637 #endif /* HAVE_LIBREADLINE */
4639 char **do_completion (const char *text, int start, int end)
4641 char **matches = NULL;
4643 #ifdef HAVE_LIBREADLINE
4645 matches = rl_completion_matches (text, generator);
4652 (* Generate the POD documentation for guestfish. *)
4653 and generate_fish_actions_pod () =
4654 let all_functions_sorted =
4656 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4657 ) all_functions_sorted in
4659 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
4662 fun (name, style, _, flags, _, _, longdesc) ->
4664 Str.global_substitute rex (
4667 try Str.matched_group 1 s
4669 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
4670 "C<" ^ replace_char sub '_' '-' ^ ">"
4672 let name = replace_char name '_' '-' in
4674 try find_map (function FishAlias n -> Some n | _ -> None) flags
4675 with Not_found -> name in
4677 pr "=head2 %s" name;
4678 if name <> alias then
4685 | String n -> pr " %s" n
4686 | OptString n -> pr " %s" n
4687 | StringList n -> pr " '%s ...'" n
4688 | Bool _ -> pr " true|false"
4689 | Int n -> pr " %s" n
4690 | FileIn n | FileOut n -> pr " (%s|-)" n
4694 pr "%s\n\n" longdesc;
4696 if List.exists (function FileIn _ | FileOut _ -> true
4697 | _ -> false) (snd style) then
4698 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
4700 if List.mem ProtocolLimitWarning flags then
4701 pr "%s\n\n" protocol_limit_warning;
4703 if List.mem DangerWillRobinson flags then
4704 pr "%s\n\n" danger_will_robinson
4705 ) all_functions_sorted
4707 (* Generate a C function prototype. *)
4708 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
4709 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
4711 ?handle name style =
4712 if extern then pr "extern ";
4713 if static then pr "static ";
4714 (match fst style with
4716 | RInt _ -> pr "int "
4717 | RInt64 _ -> pr "int64_t "
4718 | RBool _ -> pr "int "
4719 | RConstString _ -> pr "const char *"
4720 | RString _ -> pr "char *"
4721 | RStringList _ | RHashtable _ -> pr "char **"
4723 if not in_daemon then pr "struct guestfs_int_bool *"
4724 else pr "guestfs_%s_ret *" name
4726 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
4727 else pr "guestfs_lvm_int_pv_list *"
4729 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
4730 else pr "guestfs_lvm_int_vg_list *"
4732 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
4733 else pr "guestfs_lvm_int_lv_list *"
4735 if not in_daemon then pr "struct guestfs_stat *"
4736 else pr "guestfs_int_stat *"
4738 if not in_daemon then pr "struct guestfs_statvfs *"
4739 else pr "guestfs_int_statvfs *"
4741 pr "%s%s (" prefix name;
4742 if handle = None && List.length (snd style) = 0 then
4745 let comma = ref false in
4748 | Some handle -> pr "guestfs_h *%s" handle; comma := true
4752 if single_line then pr ", " else pr ",\n\t\t"
4759 | OptString n -> next (); pr "const char *%s" n
4760 | StringList n -> next (); pr "char * const* const %s" n
4761 | Bool n -> next (); pr "int %s" n
4762 | Int n -> next (); pr "int %s" n
4765 if not in_daemon then (next (); pr "const char *%s" n)
4769 if semicolon then pr ";";
4770 if newline then pr "\n"
4772 (* Generate C call arguments, eg "(handle, foo, bar)" *)
4773 and generate_call_args ?handle args =
4775 let comma = ref false in
4778 | Some handle -> pr "%s" handle; comma := true
4782 if !comma then pr ", ";
4784 pr "%s" (name_of_argt arg)
4788 (* Generate the OCaml bindings interface. *)
4789 and generate_ocaml_mli () =
4790 generate_header OCamlStyle LGPLv2;
4793 (** For API documentation you should refer to the C API
4794 in the guestfs(3) manual page. The OCaml API uses almost
4795 exactly the same calls. *)
4798 (** A [guestfs_h] handle. *)
4800 exception Error of string
4801 (** This exception is raised when there is an error. *)
4803 val create : unit -> t
4805 val close : t -> unit
4806 (** Handles are closed by the garbage collector when they become
4807 unreferenced, but callers can also call this in order to
4808 provide predictable cleanup. *)
4811 generate_ocaml_lvm_structure_decls ();
4813 generate_ocaml_stat_structure_decls ();
4817 fun (name, style, _, _, _, shortdesc, _) ->
4818 generate_ocaml_prototype name style;
4819 pr "(** %s *)\n" shortdesc;
4823 (* Generate the OCaml bindings implementation. *)
4824 and generate_ocaml_ml () =
4825 generate_header OCamlStyle LGPLv2;
4829 exception Error of string
4830 external create : unit -> t = \"ocaml_guestfs_create\"
4831 external close : t -> unit = \"ocaml_guestfs_close\"
4834 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
4838 generate_ocaml_lvm_structure_decls ();
4840 generate_ocaml_stat_structure_decls ();
4844 fun (name, style, _, _, _, shortdesc, _) ->
4845 generate_ocaml_prototype ~is_external:true name style;
4848 (* Generate the OCaml bindings C implementation. *)
4849 and generate_ocaml_c () =
4850 generate_header CStyle LGPLv2;
4857 #include <caml/config.h>
4858 #include <caml/alloc.h>
4859 #include <caml/callback.h>
4860 #include <caml/fail.h>
4861 #include <caml/memory.h>
4862 #include <caml/mlvalues.h>
4863 #include <caml/signals.h>
4865 #include <guestfs.h>
4867 #include \"guestfs_c.h\"
4869 /* Copy a hashtable of string pairs into an assoc-list. We return
4870 * the list in reverse order, but hashtables aren't supposed to be
4873 static CAMLprim value
4874 copy_table (char * const * argv)
4877 CAMLlocal5 (rv, pairv, kv, vv, cons);
4881 for (i = 0; argv[i] != NULL; i += 2) {
4882 kv = caml_copy_string (argv[i]);
4883 vv = caml_copy_string (argv[i+1]);
4884 pairv = caml_alloc (2, 0);
4885 Store_field (pairv, 0, kv);
4886 Store_field (pairv, 1, vv);
4887 cons = caml_alloc (2, 0);
4888 Store_field (cons, 1, rv);
4890 Store_field (cons, 0, pairv);
4898 (* LVM struct copy functions. *)
4901 let has_optpercent_col =
4902 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
4904 pr "static CAMLprim value\n";
4905 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
4907 pr " CAMLparam0 ();\n";
4908 if has_optpercent_col then
4909 pr " CAMLlocal3 (rv, v, v2);\n"
4911 pr " CAMLlocal2 (rv, v);\n";
4913 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
4918 pr " v = caml_copy_string (%s->%s);\n" typ name
4920 pr " v = caml_alloc_string (32);\n";
4921 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
4924 pr " v = caml_copy_int64 (%s->%s);\n" typ name
4925 | name, `OptPercent ->
4926 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
4927 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
4928 pr " v = caml_alloc (1, 0);\n";
4929 pr " Store_field (v, 0, v2);\n";
4930 pr " } else /* None */\n";
4931 pr " v = Val_int (0);\n";
4933 pr " Store_field (rv, %d, v);\n" i
4935 pr " CAMLreturn (rv);\n";
4939 pr "static CAMLprim value\n";
4940 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
4943 pr " CAMLparam0 ();\n";
4944 pr " CAMLlocal2 (rv, v);\n";
4947 pr " if (%ss->len == 0)\n" typ;
4948 pr " CAMLreturn (Atom (0));\n";
4950 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
4951 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
4952 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
4953 pr " caml_modify (&Field (rv, i), v);\n";
4955 pr " CAMLreturn (rv);\n";
4959 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4961 (* Stat copy functions. *)
4964 pr "static CAMLprim value\n";
4965 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
4967 pr " CAMLparam0 ();\n";
4968 pr " CAMLlocal2 (rv, v);\n";
4970 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
4975 pr " v = caml_copy_int64 (%s->%s);\n" typ name
4977 pr " Store_field (rv, %d, v);\n" i
4979 pr " CAMLreturn (rv);\n";
4982 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4986 fun (name, style, _, _, _, _, _) ->
4988 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
4990 pr "CAMLprim value\n";
4991 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
4992 List.iter (pr ", value %s") (List.tl params);
4997 | [p1; p2; p3; p4; p5] ->
4998 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
4999 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5000 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5001 pr " CAMLxparam%d (%s);\n"
5002 (List.length rest) (String.concat ", " rest)
5004 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5006 pr " CAMLlocal1 (rv);\n";
5009 pr " guestfs_h *g = Guestfs_val (gv);\n";
5010 pr " if (g == NULL)\n";
5011 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
5019 pr " const char *%s = String_val (%sv);\n" n n
5021 pr " const char *%s =\n" n;
5022 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5025 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5027 pr " int %s = Bool_val (%sv);\n" n n
5029 pr " int %s = Int_val (%sv);\n" n n
5032 match fst style with
5033 | RErr -> pr " int r;\n"; "-1"
5034 | RInt _ -> pr " int r;\n"; "-1"
5035 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5036 | RBool _ -> pr " int r;\n"; "-1"
5037 | RConstString _ -> pr " const char *r;\n"; "NULL"
5038 | RString _ -> pr " char *r;\n"; "NULL"
5044 pr " struct guestfs_int_bool *r;\n"; "NULL"
5046 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5048 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5050 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5052 pr " struct guestfs_stat *r;\n"; "NULL"
5054 pr " struct guestfs_statvfs *r;\n"; "NULL"
5061 pr " caml_enter_blocking_section ();\n";
5062 pr " r = guestfs_%s " name;
5063 generate_call_args ~handle:"g" (snd style);
5065 pr " caml_leave_blocking_section ();\n";
5070 pr " ocaml_guestfs_free_strings (%s);\n" n;
5071 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5074 pr " if (r == %s)\n" error_code;
5075 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5078 (match fst style with
5079 | RErr -> pr " rv = Val_unit;\n"
5080 | RInt _ -> pr " rv = Val_int (r);\n"
5082 pr " rv = caml_copy_int64 (r);\n"
5083 | RBool _ -> pr " rv = Val_bool (r);\n"
5084 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5086 pr " rv = caml_copy_string (r);\n";
5089 pr " rv = caml_copy_string_array ((const char **) r);\n";
5090 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5093 pr " rv = caml_alloc (2, 0);\n";
5094 pr " Store_field (rv, 0, Val_int (r->i));\n";
5095 pr " Store_field (rv, 1, Val_bool (r->b));\n";
5096 pr " guestfs_free_int_bool (r);\n";
5098 pr " rv = copy_lvm_pv_list (r);\n";
5099 pr " guestfs_free_lvm_pv_list (r);\n";
5101 pr " rv = copy_lvm_vg_list (r);\n";
5102 pr " guestfs_free_lvm_vg_list (r);\n";
5104 pr " rv = copy_lvm_lv_list (r);\n";
5105 pr " guestfs_free_lvm_lv_list (r);\n";
5107 pr " rv = copy_stat (r);\n";
5110 pr " rv = copy_statvfs (r);\n";
5113 pr " rv = copy_table (r);\n";
5114 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5118 pr " CAMLreturn (rv);\n";
5122 if List.length params > 5 then (
5123 pr "CAMLprim value\n";
5124 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5126 pr " return ocaml_guestfs_%s (argv[0]" name;
5127 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5134 and generate_ocaml_lvm_structure_decls () =
5137 pr "type lvm_%s = {\n" typ;
5140 | name, `String -> pr " %s : string;\n" name
5141 | name, `UUID -> pr " %s : string;\n" name
5142 | name, `Bytes -> pr " %s : int64;\n" name
5143 | name, `Int -> pr " %s : int64;\n" name
5144 | name, `OptPercent -> pr " %s : float option;\n" name
5148 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5150 and generate_ocaml_stat_structure_decls () =
5153 pr "type %s = {\n" typ;
5156 | name, `Int -> pr " %s : int64;\n" name
5160 ) ["stat", stat_cols; "statvfs", statvfs_cols]
5162 and generate_ocaml_prototype ?(is_external = false) name style =
5163 if is_external then pr "external " else pr "val ";
5164 pr "%s : t -> " name;
5167 | String _ | FileIn _ | FileOut _ -> pr "string -> "
5168 | OptString _ -> pr "string option -> "
5169 | StringList _ -> pr "string array -> "
5170 | Bool _ -> pr "bool -> "
5171 | Int _ -> pr "int -> "
5173 (match fst style with
5174 | RErr -> pr "unit" (* all errors are turned into exceptions *)
5175 | RInt _ -> pr "int"
5176 | RInt64 _ -> pr "int64"
5177 | RBool _ -> pr "bool"
5178 | RConstString _ -> pr "string"
5179 | RString _ -> pr "string"
5180 | RStringList _ -> pr "string array"
5181 | RIntBool _ -> pr "int * bool"
5182 | RPVList _ -> pr "lvm_pv array"
5183 | RVGList _ -> pr "lvm_vg array"
5184 | RLVList _ -> pr "lvm_lv array"
5185 | RStat _ -> pr "stat"
5186 | RStatVFS _ -> pr "statvfs"
5187 | RHashtable _ -> pr "(string * string) list"
5189 if is_external then (
5191 if List.length (snd style) + 1 > 5 then
5192 pr "\"ocaml_guestfs_%s_byte\" " name;
5193 pr "\"ocaml_guestfs_%s\"" name
5197 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5198 and generate_perl_xs () =
5199 generate_header CStyle LGPLv2;
5202 #include \"EXTERN.h\"
5206 #include <guestfs.h>
5209 #define PRId64 \"lld\"
5213 my_newSVll(long long val) {
5214 #ifdef USE_64_BIT_ALL
5215 return newSViv(val);
5219 len = snprintf(buf, 100, \"%%\" PRId64, val);
5220 return newSVpv(buf, len);
5225 #define PRIu64 \"llu\"
5229 my_newSVull(unsigned long long val) {
5230 #ifdef USE_64_BIT_ALL
5231 return newSVuv(val);
5235 len = snprintf(buf, 100, \"%%\" PRIu64, val);
5236 return newSVpv(buf, len);
5240 /* http://www.perlmonks.org/?node_id=680842 */
5242 XS_unpack_charPtrPtr (SV *arg) {
5247 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5248 croak (\"array reference expected\");
5250 av = (AV *)SvRV (arg);
5251 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5253 croak (\"malloc failed\");
5255 for (i = 0; i <= av_len (av); i++) {
5256 SV **elem = av_fetch (av, i, 0);
5258 if (!elem || !*elem)
5259 croak (\"missing element in list\");
5261 ret[i] = SvPV_nolen (*elem);
5269 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
5276 RETVAL = guestfs_create ();
5278 croak (\"could not create guestfs handle\");
5279 guestfs_set_error_handler (RETVAL, NULL, NULL);
5292 fun (name, style, _, _, _, _, _) ->
5293 (match fst style with
5294 | RErr -> pr "void\n"
5295 | RInt _ -> pr "SV *\n"
5296 | RInt64 _ -> pr "SV *\n"
5297 | RBool _ -> pr "SV *\n"
5298 | RConstString _ -> pr "SV *\n"
5299 | RString _ -> pr "SV *\n"
5302 | RPVList _ | RVGList _ | RLVList _
5303 | RStat _ | RStatVFS _
5305 pr "void\n" (* all lists returned implictly on the stack *)
5307 (* Call and arguments. *)
5309 generate_call_args ~handle:"g" (snd style);
5311 pr " guestfs_h *g;\n";
5314 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
5315 | OptString n -> pr " char *%s;\n" n
5316 | StringList n -> pr " char **%s;\n" n
5317 | Bool n -> pr " int %s;\n" n
5318 | Int n -> pr " int %s;\n" n
5321 let do_cleanups () =
5324 | String _ | OptString _ | Bool _ | Int _
5325 | FileIn _ | FileOut _ -> ()
5326 | StringList n -> pr " free (%s);\n" n
5331 (match fst style with
5336 pr " r = guestfs_%s " name;
5337 generate_call_args ~handle:"g" (snd style);
5340 pr " if (r == -1)\n";
5341 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5347 pr " %s = guestfs_%s " n name;
5348 generate_call_args ~handle:"g" (snd style);
5351 pr " if (%s == -1)\n" n;
5352 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5353 pr " RETVAL = newSViv (%s);\n" n;
5358 pr " int64_t %s;\n" n;
5360 pr " %s = guestfs_%s " n name;
5361 generate_call_args ~handle:"g" (snd style);
5364 pr " if (%s == -1)\n" n;
5365 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5366 pr " RETVAL = my_newSVll (%s);\n" n;
5371 pr " const char *%s;\n" n;
5373 pr " %s = guestfs_%s " n name;
5374 generate_call_args ~handle:"g" (snd style);
5377 pr " if (%s == NULL)\n" n;
5378 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5379 pr " RETVAL = newSVpv (%s, 0);\n" n;
5384 pr " char *%s;\n" n;
5386 pr " %s = guestfs_%s " n name;
5387 generate_call_args ~handle:"g" (snd style);
5390 pr " if (%s == NULL)\n" n;
5391 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5392 pr " RETVAL = newSVpv (%s, 0);\n" n;
5393 pr " free (%s);\n" n;
5396 | RStringList n | RHashtable n ->
5398 pr " char **%s;\n" n;
5401 pr " %s = guestfs_%s " n name;
5402 generate_call_args ~handle:"g" (snd style);
5405 pr " if (%s == NULL)\n" n;
5406 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5407 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
5408 pr " EXTEND (SP, n);\n";
5409 pr " for (i = 0; i < n; ++i) {\n";
5410 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
5411 pr " free (%s[i]);\n" n;
5413 pr " free (%s);\n" n;
5416 pr " struct guestfs_int_bool *r;\n";
5418 pr " r = guestfs_%s " name;
5419 generate_call_args ~handle:"g" (snd style);
5422 pr " if (r == NULL)\n";
5423 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5424 pr " EXTEND (SP, 2);\n";
5425 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
5426 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
5427 pr " guestfs_free_int_bool (r);\n";
5429 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
5431 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
5433 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
5435 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
5437 generate_perl_stat_code
5438 "statvfs" statvfs_cols name style n do_cleanups
5444 and generate_perl_lvm_code typ cols name style n do_cleanups =
5446 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
5450 pr " %s = guestfs_%s " n name;
5451 generate_call_args ~handle:"g" (snd style);
5454 pr " if (%s == NULL)\n" n;
5455 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5456 pr " EXTEND (SP, %s->len);\n" n;
5457 pr " for (i = 0; i < %s->len; ++i) {\n" n;
5458 pr " hv = newHV ();\n";
5462 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
5463 name (String.length name) n name
5465 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
5466 name (String.length name) n name
5468 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
5469 name (String.length name) n name
5471 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
5472 name (String.length name) n name
5473 | name, `OptPercent ->
5474 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
5475 name (String.length name) n name
5477 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
5479 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
5481 and generate_perl_stat_code typ cols name style n do_cleanups =
5483 pr " struct guestfs_%s *%s;\n" typ n;
5485 pr " %s = guestfs_%s " n name;
5486 generate_call_args ~handle:"g" (snd style);
5489 pr " if (%s == NULL)\n" n;
5490 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5491 pr " EXTEND (SP, %d);\n" (List.length cols);
5495 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
5497 pr " free (%s);\n" n
5499 (* Generate Sys/Guestfs.pm. *)
5500 and generate_perl_pm () =
5501 generate_header HashStyle LGPLv2;
5508 Sys::Guestfs - Perl bindings for libguestfs
5514 my $h = Sys::Guestfs->new ();
5515 $h->add_drive ('guest.img');
5518 $h->mount ('/dev/sda1', '/');
5519 $h->touch ('/hello');
5524 The C<Sys::Guestfs> module provides a Perl XS binding to the
5525 libguestfs API for examining and modifying virtual machine
5528 Amongst the things this is good for: making batch configuration
5529 changes to guests, getting disk used/free statistics (see also:
5530 virt-df), migrating between virtualization systems (see also:
5531 virt-p2v), performing partial backups, performing partial guest
5532 clones, cloning guests and changing registry/UUID/hostname info, and
5535 Libguestfs uses Linux kernel and qemu code, and can access any type of
5536 guest filesystem that Linux and qemu can, including but not limited
5537 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5538 schemes, qcow, qcow2, vmdk.
5540 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5541 LVs, what filesystem is in each LV, etc.). It can also run commands
5542 in the context of the guest. Also you can access filesystems over FTP.
5546 All errors turn into calls to C<croak> (see L<Carp(3)>).
5554 package Sys::Guestfs;
5560 XSLoader::load ('Sys::Guestfs');
5562 =item $h = Sys::Guestfs->new ();
5564 Create a new guestfs handle.
5570 my $class = ref ($proto) || $proto;
5572 my $self = Sys::Guestfs::_create ();
5573 bless $self, $class;
5579 (* Actions. We only need to print documentation for these as
5580 * they are pulled in from the XS code automatically.
5583 fun (name, style, _, flags, _, _, longdesc) ->
5584 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
5586 generate_perl_prototype name style;
5588 pr "%s\n\n" longdesc;
5589 if List.mem ProtocolLimitWarning flags then
5590 pr "%s\n\n" protocol_limit_warning;
5591 if List.mem DangerWillRobinson flags then
5592 pr "%s\n\n" danger_will_robinson
5593 ) all_functions_sorted;
5605 Copyright (C) 2009 Red Hat Inc.
5609 Please see the file COPYING.LIB for the full license.
5613 L<guestfs(3)>, L<guestfish(1)>.
5618 and generate_perl_prototype name style =
5619 (match fst style with
5625 | RString n -> pr "$%s = " n
5626 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
5630 | RLVList n -> pr "@%s = " n
5633 | RHashtable n -> pr "%%%s = " n
5636 let comma = ref false in
5639 if !comma then pr ", ";
5642 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
5649 (* Generate Python C module. *)
5650 and generate_python_c () =
5651 generate_header CStyle LGPLv2;
5660 #include \"guestfs.h\"
5668 get_handle (PyObject *obj)
5671 assert (obj != Py_None);
5672 return ((Pyguestfs_Object *) obj)->g;
5676 put_handle (guestfs_h *g)
5680 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
5683 /* This list should be freed (but not the strings) after use. */
5684 static const char **
5685 get_string_list (PyObject *obj)
5692 if (!PyList_Check (obj)) {
5693 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
5697 len = PyList_Size (obj);
5698 r = malloc (sizeof (char *) * (len+1));
5700 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
5704 for (i = 0; i < len; ++i)
5705 r[i] = PyString_AsString (PyList_GetItem (obj, i));
5712 put_string_list (char * const * const argv)
5717 for (argc = 0; argv[argc] != NULL; ++argc)
5720 list = PyList_New (argc);
5721 for (i = 0; i < argc; ++i)
5722 PyList_SetItem (list, i, PyString_FromString (argv[i]));
5728 put_table (char * const * const argv)
5730 PyObject *list, *item;
5733 for (argc = 0; argv[argc] != NULL; ++argc)
5736 list = PyList_New (argc >> 1);
5737 for (i = 0; i < argc; i += 2) {
5738 item = PyTuple_New (2);
5739 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
5740 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
5741 PyList_SetItem (list, i >> 1, item);
5748 free_strings (char **argv)
5752 for (argc = 0; argv[argc] != NULL; ++argc)
5758 py_guestfs_create (PyObject *self, PyObject *args)
5762 g = guestfs_create ();
5764 PyErr_SetString (PyExc_RuntimeError,
5765 \"guestfs.create: failed to allocate handle\");
5768 guestfs_set_error_handler (g, NULL, NULL);
5769 return put_handle (g);
5773 py_guestfs_close (PyObject *self, PyObject *args)
5778 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
5780 g = get_handle (py_g);
5784 Py_INCREF (Py_None);
5790 (* LVM structures, turned into Python dictionaries. *)
5793 pr "static PyObject *\n";
5794 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
5796 pr " PyObject *dict;\n";
5798 pr " dict = PyDict_New ();\n";
5802 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5803 pr " PyString_FromString (%s->%s));\n"
5806 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5807 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
5810 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5811 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
5814 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5815 pr " PyLong_FromLongLong (%s->%s));\n"
5817 | name, `OptPercent ->
5818 pr " if (%s->%s >= 0)\n" typ name;
5819 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5820 pr " PyFloat_FromDouble ((double) %s->%s));\n"
5823 pr " Py_INCREF (Py_None);\n";
5824 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
5827 pr " return dict;\n";
5831 pr "static PyObject *\n";
5832 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
5834 pr " PyObject *list;\n";
5837 pr " list = PyList_New (%ss->len);\n" typ;
5838 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
5839 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
5840 pr " return list;\n";
5843 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5845 (* Stat structures, turned into Python dictionaries. *)
5848 pr "static PyObject *\n";
5849 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
5851 pr " PyObject *dict;\n";
5853 pr " dict = PyDict_New ();\n";
5857 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5858 pr " PyLong_FromLongLong (%s->%s));\n"
5861 pr " return dict;\n";
5864 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5866 (* Python wrapper functions. *)
5868 fun (name, style, _, _, _, _, _) ->
5869 pr "static PyObject *\n";
5870 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
5873 pr " PyObject *py_g;\n";
5874 pr " guestfs_h *g;\n";
5875 pr " PyObject *py_r;\n";
5878 match fst style with
5879 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
5880 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5881 | RConstString _ -> pr " const char *r;\n"; "NULL"
5882 | RString _ -> pr " char *r;\n"; "NULL"
5883 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
5884 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
5885 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5886 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5887 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5888 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
5889 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
5893 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
5894 | OptString n -> pr " const char *%s;\n" n
5896 pr " PyObject *py_%s;\n" n;
5897 pr " const char **%s;\n" n
5898 | Bool n -> pr " int %s;\n" n
5899 | Int n -> pr " int %s;\n" n
5904 (* Convert the parameters. *)
5905 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
5908 | String _ | FileIn _ | FileOut _ -> pr "s"
5909 | OptString _ -> pr "z"
5910 | StringList _ -> pr "O"
5911 | Bool _ -> pr "i" (* XXX Python has booleans? *)
5914 pr ":guestfs_%s\",\n" name;
5918 | String n | FileIn n | FileOut n -> pr ", &%s" n
5919 | OptString n -> pr ", &%s" n
5920 | StringList n -> pr ", &py_%s" n
5921 | Bool n -> pr ", &%s" n
5922 | Int n -> pr ", &%s" n
5926 pr " return NULL;\n";
5928 pr " g = get_handle (py_g);\n";
5931 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5933 pr " %s = get_string_list (py_%s);\n" n n;
5934 pr " if (!%s) return NULL;\n" n
5939 pr " r = guestfs_%s " name;
5940 generate_call_args ~handle:"g" (snd style);
5945 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5947 pr " free (%s);\n" n
5950 pr " if (r == %s) {\n" error_code;
5951 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
5952 pr " return NULL;\n";
5956 (match fst style with
5958 pr " Py_INCREF (Py_None);\n";
5959 pr " py_r = Py_None;\n"
5961 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
5962 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
5963 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
5965 pr " py_r = PyString_FromString (r);\n";
5968 pr " py_r = put_string_list (r);\n";
5969 pr " free_strings (r);\n"
5971 pr " py_r = PyTuple_New (2);\n";
5972 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
5973 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
5974 pr " guestfs_free_int_bool (r);\n"
5976 pr " py_r = put_lvm_pv_list (r);\n";
5977 pr " guestfs_free_lvm_pv_list (r);\n"
5979 pr " py_r = put_lvm_vg_list (r);\n";
5980 pr " guestfs_free_lvm_vg_list (r);\n"
5982 pr " py_r = put_lvm_lv_list (r);\n";
5983 pr " guestfs_free_lvm_lv_list (r);\n"
5985 pr " py_r = put_stat (r);\n";
5988 pr " py_r = put_statvfs (r);\n";
5991 pr " py_r = put_table (r);\n";
5992 pr " free_strings (r);\n"
5995 pr " return py_r;\n";
6000 (* Table of functions. *)
6001 pr "static PyMethodDef methods[] = {\n";
6002 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6003 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6005 fun (name, _, _, _, _, _, _) ->
6006 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6009 pr " { NULL, NULL, 0, NULL }\n";
6013 (* Init function. *)
6016 initlibguestfsmod (void)
6018 static int initialized = 0;
6020 if (initialized) return;
6021 Py_InitModule ((char *) \"libguestfsmod\", methods);
6026 (* Generate Python module. *)
6027 and generate_python_py () =
6028 generate_header HashStyle LGPLv2;
6031 u\"\"\"Python bindings for libguestfs
6034 g = guestfs.GuestFS ()
6035 g.add_drive (\"guest.img\")
6038 parts = g.list_partitions ()
6040 The guestfs module provides a Python binding to the libguestfs API
6041 for examining and modifying virtual machine disk images.
6043 Amongst the things this is good for: making batch configuration
6044 changes to guests, getting disk used/free statistics (see also:
6045 virt-df), migrating between virtualization systems (see also:
6046 virt-p2v), performing partial backups, performing partial guest
6047 clones, cloning guests and changing registry/UUID/hostname info, and
6050 Libguestfs uses Linux kernel and qemu code, and can access any type of
6051 guest filesystem that Linux and qemu can, including but not limited
6052 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6053 schemes, qcow, qcow2, vmdk.
6055 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6056 LVs, what filesystem is in each LV, etc.). It can also run commands
6057 in the context of the guest. Also you can access filesystems over FTP.
6059 Errors which happen while using the API are turned into Python
6060 RuntimeError exceptions.
6062 To create a guestfs handle you usually have to perform the following
6065 # Create the handle, call add_drive at least once, and possibly
6066 # several times if the guest has multiple block devices:
6067 g = guestfs.GuestFS ()
6068 g.add_drive (\"guest.img\")
6070 # Launch the qemu subprocess and wait for it to become ready:
6074 # Now you can issue commands, for example:
6079 import libguestfsmod
6082 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6084 def __init__ (self):
6085 \"\"\"Create a new libguestfs handle.\"\"\"
6086 self._o = libguestfsmod.create ()
6089 libguestfsmod.close (self._o)
6094 fun (name, style, _, flags, _, _, longdesc) ->
6095 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6097 match fst style with
6098 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6101 doc ^ "\n\nThis function returns a list of strings."
6103 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6105 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
6107 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
6109 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
6111 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6113 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6115 doc ^ "\n\nThis function returns a dictionary." in
6117 if List.mem ProtocolLimitWarning flags then
6118 doc ^ "\n\n" ^ protocol_limit_warning
6121 if List.mem DangerWillRobinson flags then
6122 doc ^ "\n\n" ^ danger_will_robinson
6124 let doc = pod2text ~width:60 name doc in
6125 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6126 let doc = String.concat "\n " doc in
6129 generate_call_args ~handle:"self" (snd style);
6131 pr " u\"\"\"%s\"\"\"\n" doc;
6132 pr " return libguestfsmod.%s " name;
6133 generate_call_args ~handle:"self._o" (snd style);
6138 (* Useful if you need the longdesc POD text as plain text. Returns a
6141 * This is the slowest thing about autogeneration.
6143 and pod2text ~width name longdesc =
6144 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6145 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6147 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6148 let chan = Unix.open_process_in cmd in
6149 let lines = ref [] in
6151 let line = input_line chan in
6152 if i = 1 then (* discard the first line of output *)
6155 let line = triml line in
6156 lines := line :: !lines;
6159 let lines = try loop 1 with End_of_file -> List.rev !lines in
6160 Unix.unlink filename;
6161 match Unix.close_process_in chan with
6162 | Unix.WEXITED 0 -> lines
6164 failwithf "pod2text: process exited with non-zero status (%d)" i
6165 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6166 failwithf "pod2text: process signalled or stopped by signal %d" i
6168 (* Generate ruby bindings. *)
6169 and generate_ruby_c () =
6170 generate_header CStyle LGPLv2;
6178 #include \"guestfs.h\"
6180 #include \"extconf.h\"
6182 /* For Ruby < 1.9 */
6184 #define RARRAY_LEN(r) (RARRAY((r))->len)
6187 static VALUE m_guestfs; /* guestfs module */
6188 static VALUE c_guestfs; /* guestfs_h handle */
6189 static VALUE e_Error; /* used for all errors */
6191 static void ruby_guestfs_free (void *p)
6194 guestfs_close ((guestfs_h *) p);
6197 static VALUE ruby_guestfs_create (VALUE m)
6201 g = guestfs_create ();
6203 rb_raise (e_Error, \"failed to create guestfs handle\");
6205 /* Don't print error messages to stderr by default. */
6206 guestfs_set_error_handler (g, NULL, NULL);
6208 /* Wrap it, and make sure the close function is called when the
6211 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6214 static VALUE ruby_guestfs_close (VALUE gv)
6217 Data_Get_Struct (gv, guestfs_h, g);
6219 ruby_guestfs_free (g);
6220 DATA_PTR (gv) = NULL;
6228 fun (name, style, _, _, _, _, _) ->
6229 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6230 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6233 pr " guestfs_h *g;\n";
6234 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
6236 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6242 | String n | FileIn n | FileOut n ->
6243 pr " const char *%s = StringValueCStr (%sv);\n" n n;
6245 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6246 pr " \"%s\", \"%s\");\n" n name
6248 pr " const char *%s = StringValueCStr (%sv);\n" n n
6252 pr " int i, len;\n";
6253 pr " len = RARRAY_LEN (%sv);\n" n;
6254 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6256 pr " for (i = 0; i < len; ++i) {\n";
6257 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
6258 pr " %s[i] = StringValueCStr (v);\n" n;
6260 pr " %s[len] = NULL;\n" n;
6264 pr " int %s = NUM2INT (%sv);\n" n n
6269 match fst style with
6270 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6271 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6272 | RConstString _ -> pr " const char *r;\n"; "NULL"
6273 | RString _ -> pr " char *r;\n"; "NULL"
6274 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6275 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6276 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6277 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6278 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6279 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6280 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6283 pr " r = guestfs_%s " name;
6284 generate_call_args ~handle:"g" (snd style);
6289 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6291 pr " free (%s);\n" n
6294 pr " if (r == %s)\n" error_code;
6295 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6298 (match fst style with
6300 pr " return Qnil;\n"
6301 | RInt _ | RBool _ ->
6302 pr " return INT2NUM (r);\n"
6304 pr " return ULL2NUM (r);\n"
6306 pr " return rb_str_new2 (r);\n";
6308 pr " VALUE rv = rb_str_new2 (r);\n";
6312 pr " int i, len = 0;\n";
6313 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
6314 pr " VALUE rv = rb_ary_new2 (len);\n";
6315 pr " for (i = 0; r[i] != NULL; ++i) {\n";
6316 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6317 pr " free (r[i]);\n";
6322 pr " VALUE rv = rb_ary_new2 (2);\n";
6323 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
6324 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
6325 pr " guestfs_free_int_bool (r);\n";
6328 generate_ruby_lvm_code "pv" pv_cols
6330 generate_ruby_lvm_code "vg" vg_cols
6332 generate_ruby_lvm_code "lv" lv_cols
6334 pr " VALUE rv = rb_hash_new ();\n";
6338 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6343 pr " VALUE rv = rb_hash_new ();\n";
6347 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6352 pr " VALUE rv = rb_hash_new ();\n";
6354 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
6355 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6356 pr " free (r[i]);\n";
6357 pr " free (r[i+1]);\n";
6368 /* Initialize the module. */
6369 void Init__guestfs ()
6371 m_guestfs = rb_define_module (\"Guestfs\");
6372 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6373 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6375 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6376 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6379 (* Define the rest of the methods. *)
6381 fun (name, style, _, _, _, _, _) ->
6382 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
6383 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6388 (* Ruby code to return an LVM struct list. *)
6389 and generate_ruby_lvm_code typ cols =
6390 pr " VALUE rv = rb_ary_new2 (r->len);\n";
6392 pr " for (i = 0; i < r->len; ++i) {\n";
6393 pr " VALUE hv = rb_hash_new ();\n";
6397 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
6399 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
6402 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
6403 | name, `OptPercent ->
6404 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
6406 pr " rb_ary_push (rv, hv);\n";
6408 pr " guestfs_free_lvm_%s_list (r);\n" typ;
6411 (* Generate Java bindings GuestFS.java file. *)
6412 and generate_java_java () =
6413 generate_header CStyle LGPLv2;
6416 package com.redhat.et.libguestfs;
6418 import java.util.HashMap;
6419 import com.redhat.et.libguestfs.LibGuestFSException;
6420 import com.redhat.et.libguestfs.PV;
6421 import com.redhat.et.libguestfs.VG;
6422 import com.redhat.et.libguestfs.LV;
6423 import com.redhat.et.libguestfs.Stat;
6424 import com.redhat.et.libguestfs.StatVFS;
6425 import com.redhat.et.libguestfs.IntBool;
6428 * The GuestFS object is a libguestfs handle.
6432 public class GuestFS {
6433 // Load the native code.
6435 System.loadLibrary (\"guestfs_jni\");
6439 * The native guestfs_h pointer.
6444 * Create a libguestfs handle.
6446 * @throws LibGuestFSException
6448 public GuestFS () throws LibGuestFSException
6452 private native long _create () throws LibGuestFSException;
6455 * Close a libguestfs handle.
6457 * You can also leave handles to be collected by the garbage
6458 * collector, but this method ensures that the resources used
6459 * by the handle are freed up immediately. If you call any
6460 * other methods after closing the handle, you will get an
6463 * @throws LibGuestFSException
6465 public void close () throws LibGuestFSException
6471 private native void _close (long g) throws LibGuestFSException;
6473 public void finalize () throws LibGuestFSException
6481 fun (name, style, _, flags, _, shortdesc, longdesc) ->
6482 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6484 if List.mem ProtocolLimitWarning flags then
6485 doc ^ "\n\n" ^ protocol_limit_warning
6488 if List.mem DangerWillRobinson flags then
6489 doc ^ "\n\n" ^ danger_will_robinson
6491 let doc = pod2text ~width:60 name doc in
6492 let doc = List.map ( (* RHBZ#501883 *)
6495 | nonempty -> nonempty
6497 let doc = String.concat "\n * " doc in
6500 pr " * %s\n" shortdesc;
6503 pr " * @throws LibGuestFSException\n";
6506 generate_java_prototype ~public:true ~semicolon:false name style;
6509 pr " if (g == 0)\n";
6510 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
6513 if fst style <> RErr then pr "return ";
6515 generate_call_args ~handle:"g" (snd style);
6519 generate_java_prototype ~privat:true ~native:true name style;
6526 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
6527 ?(semicolon=true) name style =
6528 if privat then pr "private ";
6529 if public then pr "public ";
6530 if native then pr "native ";
6533 (match fst style with
6534 | RErr -> pr "void ";
6535 | RInt _ -> pr "int ";
6536 | RInt64 _ -> pr "long ";
6537 | RBool _ -> pr "boolean ";
6538 | RConstString _ | RString _ -> pr "String ";
6539 | RStringList _ -> pr "String[] ";
6540 | RIntBool _ -> pr "IntBool ";
6541 | RPVList _ -> pr "PV[] ";
6542 | RVGList _ -> pr "VG[] ";
6543 | RLVList _ -> pr "LV[] ";
6544 | RStat _ -> pr "Stat ";
6545 | RStatVFS _ -> pr "StatVFS ";
6546 | RHashtable _ -> pr "HashMap<String,String> ";
6549 if native then pr "_%s " name else pr "%s " name;
6551 let needs_comma = ref false in
6560 if !needs_comma then pr ", ";
6561 needs_comma := true;
6578 pr " throws LibGuestFSException";
6579 if semicolon then pr ";"
6581 and generate_java_struct typ cols =
6582 generate_header CStyle LGPLv2;
6585 package com.redhat.et.libguestfs;
6588 * Libguestfs %s structure.
6599 | name, `UUID -> pr " public String %s;\n" name
6601 | name, `Int -> pr " public long %s;\n" name
6602 | name, `OptPercent ->
6603 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
6604 pr " public float %s;\n" name
6609 and generate_java_c () =
6610 generate_header CStyle LGPLv2;
6617 #include \"com_redhat_et_libguestfs_GuestFS.h\"
6618 #include \"guestfs.h\"
6620 /* Note that this function returns. The exception is not thrown
6621 * until after the wrapper function returns.
6624 throw_exception (JNIEnv *env, const char *msg)
6627 cl = (*env)->FindClass (env,
6628 \"com/redhat/et/libguestfs/LibGuestFSException\");
6629 (*env)->ThrowNew (env, cl, msg);
6632 JNIEXPORT jlong JNICALL
6633 Java_com_redhat_et_libguestfs_GuestFS__1create
6634 (JNIEnv *env, jobject obj)
6638 g = guestfs_create ();
6640 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
6643 guestfs_set_error_handler (g, NULL, NULL);
6644 return (jlong) (long) g;
6647 JNIEXPORT void JNICALL
6648 Java_com_redhat_et_libguestfs_GuestFS__1close
6649 (JNIEnv *env, jobject obj, jlong jg)
6651 guestfs_h *g = (guestfs_h *) (long) jg;
6658 fun (name, style, _, _, _, _, _) ->
6660 (match fst style with
6661 | RErr -> pr "void ";
6662 | RInt _ -> pr "jint ";
6663 | RInt64 _ -> pr "jlong ";
6664 | RBool _ -> pr "jboolean ";
6665 | RConstString _ | RString _ -> pr "jstring ";
6666 | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
6668 | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
6672 pr "Java_com_redhat_et_libguestfs_GuestFS_";
6673 pr "%s" (replace_str ("_" ^ name) "_" "_1");
6675 pr " (JNIEnv *env, jobject obj, jlong jg";
6682 pr ", jstring j%s" n
6684 pr ", jobjectArray j%s" n
6686 pr ", jboolean j%s" n
6692 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
6693 let error_code, no_ret =
6694 match fst style with
6695 | RErr -> pr " int r;\n"; "-1", ""
6697 | RInt _ -> pr " int r;\n"; "-1", "0"
6698 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
6699 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
6701 pr " jstring jr;\n";
6702 pr " char *r;\n"; "NULL", "NULL"
6704 pr " jobjectArray jr;\n";
6707 pr " jstring jstr;\n";
6708 pr " char **r;\n"; "NULL", "NULL"
6710 pr " jobject jr;\n";
6712 pr " jfieldID fl;\n";
6713 pr " struct guestfs_int_bool *r;\n"; "NULL", "NULL"
6715 pr " jobject jr;\n";
6717 pr " jfieldID fl;\n";
6718 pr " struct guestfs_stat *r;\n"; "NULL", "NULL"
6720 pr " jobject jr;\n";
6722 pr " jfieldID fl;\n";
6723 pr " struct guestfs_statvfs *r;\n"; "NULL", "NULL"
6725 pr " jobjectArray jr;\n";
6727 pr " jfieldID fl;\n";
6728 pr " jobject jfl;\n";
6729 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
6731 pr " jobjectArray jr;\n";
6733 pr " jfieldID fl;\n";
6734 pr " jobject jfl;\n";
6735 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
6737 pr " jobjectArray jr;\n";
6739 pr " jfieldID fl;\n";
6740 pr " jobject jfl;\n";
6741 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
6742 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
6749 pr " const char *%s;\n" n
6751 pr " int %s_len;\n" n;
6752 pr " const char **%s;\n" n
6759 (match fst style with
6760 | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
6761 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
6762 | RString _ | RIntBool _ | RStat _ | RStatVFS _
6763 | RHashtable _ -> false) ||
6764 List.exists (function StringList _ -> true | _ -> false) (snd style) in
6770 (* Get the parameters. *)
6777 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
6779 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
6780 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
6781 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6782 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6784 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
6786 pr " %s[%s_len] = NULL;\n" n n;
6789 pr " %s = j%s;\n" n n
6792 (* Make the call. *)
6793 pr " r = guestfs_%s " name;
6794 generate_call_args ~handle:"g" (snd style);
6797 (* Release the parameters. *)
6804 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
6806 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6807 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6809 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
6811 pr " free (%s);\n" n
6816 (* Check for errors. *)
6817 pr " if (r == %s) {\n" error_code;
6818 pr " throw_exception (env, guestfs_last_error (g));\n";
6819 pr " return %s;\n" no_ret;
6823 (match fst style with
6825 | RInt _ -> pr " return (jint) r;\n"
6826 | RBool _ -> pr " return (jboolean) r;\n"
6827 | RInt64 _ -> pr " return (jlong) r;\n"
6828 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
6830 pr " jr = (*env)->NewStringUTF (env, r);\n";
6834 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
6835 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
6836 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
6837 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
6838 pr " for (i = 0; i < r_len; ++i) {\n";
6839 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
6840 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
6841 pr " free (r[i]);\n";
6846 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
6847 pr " jr = (*env)->AllocObject (env, cl);\n";
6848 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
6849 pr " (*env)->SetIntField (env, jr, fl, r->i);\n";
6850 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
6851 pr " (*env)->SetBooleanField (env, jr, fl, r->b);\n";
6852 pr " guestfs_free_int_bool (r);\n";
6855 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
6856 pr " jr = (*env)->AllocObject (env, cl);\n";
6860 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
6862 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
6867 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
6868 pr " jr = (*env)->AllocObject (env, cl);\n";
6872 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
6874 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
6879 generate_java_lvm_return "pv" "PV" pv_cols
6881 generate_java_lvm_return "vg" "VG" vg_cols
6883 generate_java_lvm_return "lv" "LV" lv_cols
6886 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
6887 pr " return NULL;\n"
6894 and generate_java_lvm_return typ jtyp cols =
6895 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
6896 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
6897 pr " for (i = 0; i < r->len; ++i) {\n";
6898 pr " jfl = (*env)->AllocObject (env, cl);\n";
6902 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
6903 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
6906 pr " char s[33];\n";
6907 pr " memcpy (s, r->val[i].%s, 32);\n" name;
6909 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
6910 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
6912 | name, (`Bytes|`Int) ->
6913 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
6914 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
6915 | name, `OptPercent ->
6916 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
6917 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
6919 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
6921 pr " guestfs_free_lvm_%s_list (r);\n" typ;
6924 and generate_haskell_hs () =
6925 generate_header HaskellStyle LGPLv2;
6927 (* XXX We only know how to generate partial FFI for Haskell
6928 * at the moment. Please help out!
6930 let can_generate style =
6931 let check_no_bad_args =
6932 List.for_all (function Bool _ | Int _ -> false | _ -> true)
6935 | RErr, args -> check_no_bad_args args
6948 | RHashtable _, _ -> false in
6951 {-# INCLUDE <guestfs.h> #-}
6952 {-# LANGUAGE ForeignFunctionInterface #-}
6957 (* List out the names of the actions we want to export. *)
6959 fun (name, style, _, _, _, _, _) ->
6960 if can_generate style then pr ",\n %s" name
6968 import Control.Exception
6969 import Data.Typeable
6971 data GuestfsS = GuestfsS -- represents the opaque C struct
6972 type GuestfsP = Ptr GuestfsS -- guestfs_h *
6973 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
6975 -- XXX define properly later XXX
6979 data IntBool = IntBool
6981 data StatVFS = StatVFS
6982 data Hashtable = Hashtable
6984 foreign import ccall unsafe \"guestfs_create\" c_create
6986 foreign import ccall unsafe \"&guestfs_close\" c_close
6987 :: FunPtr (GuestfsP -> IO ())
6988 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
6989 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
6991 create :: IO GuestfsH
6994 c_set_error_handler p nullPtr nullPtr
6995 h <- newForeignPtr c_close p
6998 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
6999 :: GuestfsP -> IO CString
7001 -- last_error :: GuestfsH -> IO (Maybe String)
7002 -- last_error h = do
7003 -- str <- withForeignPtr h (\\p -> c_last_error p)
7004 -- maybePeek peekCString str
7006 last_error :: GuestfsH -> IO (String)
7008 str <- withForeignPtr h (\\p -> c_last_error p)
7010 then return \"no error\"
7011 else peekCString str
7015 (* Generate wrappers for each foreign function. *)
7017 fun (name, style, _, _, _, _, _) ->
7018 if can_generate style then (
7019 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7021 generate_haskell_prototype ~handle:"GuestfsP" style;
7025 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7027 pr "%s %s = do\n" name
7028 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7034 | String n -> pr "withCString %s $ \\%s -> " n n
7035 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7036 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7038 (* XXX this doesn't work *)
7040 pr " %s = case %s of\n" n n;
7043 pr " in fromIntegral %s $ \\%s ->\n" n n
7044 | Int n -> pr "fromIntegral %s $ \\%s -> " n n
7046 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7047 (String.concat " " ("p" :: List.map name_of_argt (snd style)));
7048 (match fst style with
7049 | RErr | RInt _ | RInt64 _ | RBool _ ->
7050 pr " if (r == -1)\n";
7052 pr " err <- last_error h\n";
7054 | RConstString _ | RString _ | RStringList _ | RIntBool _
7055 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7057 pr " if (r == nullPtr)\n";
7059 pr " err <- last_error h\n";
7062 (match fst style with
7064 pr " else return ()\n"
7066 pr " else return (fromIntegral r)\n"
7068 pr " else return (fromIntegral r)\n"
7070 pr " else return (toBool r)\n"
7081 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7087 and generate_haskell_prototype ~handle ?(hs = false) style =
7089 let string = if hs then "String" else "CString" in
7090 let int = if hs then "Int" else "CInt" in
7091 let bool = if hs then "Bool" else "CInt" in
7092 let int64 = if hs then "Integer" else "Int64" in
7096 | String _ -> pr "%s" string
7097 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7098 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7099 | Bool _ -> pr "%s" bool
7100 | Int _ -> pr "%s" int
7101 | FileIn _ -> pr "%s" string
7102 | FileOut _ -> pr "%s" string
7107 (match fst style with
7108 | RErr -> if not hs then pr "CInt"
7109 | RInt _ -> pr "%s" int
7110 | RInt64 _ -> pr "%s" int64
7111 | RBool _ -> pr "%s" bool
7112 | RConstString _ -> pr "%s" string
7113 | RString _ -> pr "%s" string
7114 | RStringList _ -> pr "[%s]" string
7115 | RIntBool _ -> pr "IntBool"
7116 | RPVList _ -> pr "[PV]"
7117 | RVGList _ -> pr "[VG]"
7118 | RLVList _ -> pr "[LV]"
7119 | RStat _ -> pr "Stat"
7120 | RStatVFS _ -> pr "StatVFS"
7121 | RHashtable _ -> pr "Hashtable"
7125 let output_to filename =
7126 let filename_new = filename ^ ".new" in
7127 chan := open_out filename_new;
7132 (* Is the new file different from the current file? *)
7133 if Sys.file_exists filename && files_equal filename filename_new then
7134 Unix.unlink filename_new (* same, so skip it *)
7136 (* different, overwrite old one *)
7137 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
7138 Unix.rename filename_new filename;
7139 Unix.chmod filename 0o444;
7140 printf "written %s\n%!" filename;
7149 if not (Sys.file_exists "configure.ac") then (
7151 You are probably running this from the wrong directory.
7152 Run it from the top source directory using the command
7158 let close = output_to "src/guestfs_protocol.x" in
7162 let close = output_to "src/guestfs-structs.h" in
7163 generate_structs_h ();
7166 let close = output_to "src/guestfs-actions.h" in
7167 generate_actions_h ();
7170 let close = output_to "src/guestfs-actions.c" in
7171 generate_client_actions ();
7174 let close = output_to "daemon/actions.h" in
7175 generate_daemon_actions_h ();
7178 let close = output_to "daemon/stubs.c" in
7179 generate_daemon_actions ();
7182 let close = output_to "capitests/tests.c" in
7186 let close = output_to "fish/cmds.c" in
7187 generate_fish_cmds ();
7190 let close = output_to "fish/completion.c" in
7191 generate_fish_completion ();
7194 let close = output_to "guestfs-structs.pod" in
7195 generate_structs_pod ();
7198 let close = output_to "guestfs-actions.pod" in
7199 generate_actions_pod ();
7202 let close = output_to "guestfish-actions.pod" in
7203 generate_fish_actions_pod ();
7206 let close = output_to "ocaml/guestfs.mli" in
7207 generate_ocaml_mli ();
7210 let close = output_to "ocaml/guestfs.ml" in
7211 generate_ocaml_ml ();
7214 let close = output_to "ocaml/guestfs_c_actions.c" in
7215 generate_ocaml_c ();
7218 let close = output_to "perl/Guestfs.xs" in
7219 generate_perl_xs ();
7222 let close = output_to "perl/lib/Sys/Guestfs.pm" in
7223 generate_perl_pm ();
7226 let close = output_to "python/guestfs-py.c" in
7227 generate_python_c ();
7230 let close = output_to "python/guestfs.py" in
7231 generate_python_py ();
7234 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
7238 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
7239 generate_java_java ();
7242 let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
7243 generate_java_struct "PV" pv_cols;
7246 let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
7247 generate_java_struct "VG" vg_cols;
7250 let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
7251 generate_java_struct "LV" lv_cols;
7254 let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
7255 generate_java_struct "Stat" stat_cols;
7258 let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
7259 generate_java_struct "StatVFS" statvfs_cols;
7262 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
7266 let close = output_to "haskell/Guestfs.hs" in
7267 generate_haskell_hs ();