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 type tests = (test_init * test_prereq * test) list
159 (* Run the command sequence and just expect nothing to fail. *)
161 (* Run the command sequence and expect the output of the final
162 * command to be the string.
164 | TestOutput of seq * string
165 (* Run the command sequence and expect the output of the final
166 * command to be the list of strings.
168 | TestOutputList of seq * string list
169 (* Run the command sequence and expect the output of the final
170 * command to be the integer.
172 | TestOutputInt of seq * int
173 (* Run the command sequence and expect the output of the final
174 * command to be a true value (!= 0 or != NULL).
176 | TestOutputTrue of seq
177 (* Run the command sequence and expect the output of the final
178 * command to be a false value (== 0 or == NULL, but not an error).
180 | TestOutputFalse of seq
181 (* Run the command sequence and expect the output of the final
182 * command to be a list of the given length (but don't care about
185 | TestOutputLength of seq * int
186 (* Run the command sequence and expect the output of the final
187 * command to be a structure.
189 | TestOutputStruct of seq * test_field_compare list
190 (* Run the command sequence and expect the final command (only)
193 | TestLastFail of seq
195 and test_field_compare =
196 | CompareWithInt of string * int
197 | CompareWithString of string * string
198 | CompareFieldsIntEq of string * string
199 | CompareFieldsStrEq of string * string
201 (* Test prerequisites. *)
203 (* Test always runs. *)
205 (* Test is currently disabled - eg. it fails, or it tests some
206 * unimplemented feature.
209 (* 'string' is some C code (a function body) that should return
210 * true or false. The test will run if the code returns true.
213 (* As for 'If' but the test runs _unless_ the code returns true. *)
216 (* Some initial scenarios for testing. *)
218 (* Do nothing, block devices could contain random stuff including
219 * LVM PVs, and some filesystems might be mounted. This is usually
223 (* Block devices are empty and no filesystems are mounted. *)
225 (* /dev/sda contains a single partition /dev/sda1, which is formatted
226 * as ext2, empty [except for lost+found] and mounted on /.
227 * /dev/sdb and /dev/sdc may have random content.
232 * /dev/sda1 (is a PV):
233 * /dev/VG/LV (size 8MB):
234 * formatted as ext2, empty [except for lost+found], mounted on /
235 * /dev/sdb and /dev/sdc may have random content.
239 (* Sequence of commands for testing. *)
241 and cmd = string list
243 (* Canned test prerequisites. *)
244 let env_is_true env =
245 sprintf "const char *str = getenv (\"%s\");
246 return str && strcmp (str, \"1\") == 0;" env
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, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1196 [["upload"; "test-command"; "/test-command"];
1197 ["chmod"; "493"; "/test-command"];
1198 ["command"; "/test-command 1"]], "Result1");
1199 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1200 [["upload"; "test-command"; "/test-command"];
1201 ["chmod"; "493"; "/test-command"];
1202 ["command"; "/test-command 2"]], "Result2\n");
1203 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1204 [["upload"; "test-command"; "/test-command"];
1205 ["chmod"; "493"; "/test-command"];
1206 ["command"; "/test-command 3"]], "\nResult3");
1207 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1208 [["upload"; "test-command"; "/test-command"];
1209 ["chmod"; "493"; "/test-command"];
1210 ["command"; "/test-command 4"]], "\nResult4\n");
1211 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1212 [["upload"; "test-command"; "/test-command"];
1213 ["chmod"; "493"; "/test-command"];
1214 ["command"; "/test-command 5"]], "\nResult5\n\n");
1215 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1216 [["upload"; "test-command"; "/test-command"];
1217 ["chmod"; "493"; "/test-command"];
1218 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1219 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1220 [["upload"; "test-command"; "/test-command"];
1221 ["chmod"; "493"; "/test-command"];
1222 ["command"; "/test-command 7"]], "");
1223 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1224 [["upload"; "test-command"; "/test-command"];
1225 ["chmod"; "493"; "/test-command"];
1226 ["command"; "/test-command 8"]], "\n");
1227 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1228 [["upload"; "test-command"; "/test-command"];
1229 ["chmod"; "493"; "/test-command"];
1230 ["command"; "/test-command 9"]], "\n\n");
1231 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1232 [["upload"; "test-command"; "/test-command"];
1233 ["chmod"; "493"; "/test-command"];
1234 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1235 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
1236 [["upload"; "test-command"; "/test-command"];
1237 ["chmod"; "493"; "/test-command"];
1238 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1239 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), 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, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1275 [["upload"; "test-command"; "/test-command"];
1276 ["chmod"; "493"; "/test-command"];
1277 ["command_lines"; "/test-command 1"]], ["Result1"]);
1278 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1279 [["upload"; "test-command"; "/test-command"];
1280 ["chmod"; "493"; "/test-command"];
1281 ["command_lines"; "/test-command 2"]], ["Result2"]);
1282 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1283 [["upload"; "test-command"; "/test-command"];
1284 ["chmod"; "493"; "/test-command"];
1285 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1286 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1287 [["upload"; "test-command"; "/test-command"];
1288 ["chmod"; "493"; "/test-command"];
1289 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1290 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1291 [["upload"; "test-command"; "/test-command"];
1292 ["chmod"; "493"; "/test-command"];
1293 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1294 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1295 [["upload"; "test-command"; "/test-command"];
1296 ["chmod"; "493"; "/test-command"];
1297 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1298 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1299 [["upload"; "test-command"; "/test-command"];
1300 ["chmod"; "493"; "/test-command"];
1301 ["command_lines"; "/test-command 7"]], []);
1302 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1303 [["upload"; "test-command"; "/test-command"];
1304 ["chmod"; "493"; "/test-command"];
1305 ["command_lines"; "/test-command 8"]], [""]);
1306 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1307 [["upload"; "test-command"; "/test-command"];
1308 ["chmod"; "493"; "/test-command"];
1309 ["command_lines"; "/test-command 9"]], ["";""]);
1310 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
1311 [["upload"; "test-command"; "/test-command"];
1312 ["chmod"; "493"; "/test-command"];
1313 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1314 InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), 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, Unless (env_is_true "SKIP_ZEROFREE"), 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 srcdir = getenv (\"srcdir\");
3721 if (!srcdir) srcdir = \".\";
3723 guestfs_set_path (g, \".\");
3725 filename = \"test1.img\";
3726 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3731 if (lseek (fd, %d, SEEK_SET) == -1) {
3737 if (write (fd, &c, 1) == -1) {
3743 if (close (fd) == -1) {
3748 if (guestfs_add_drive (g, filename) == -1) {
3749 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3753 filename = \"test2.img\";
3754 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3759 if (lseek (fd, %d, SEEK_SET) == -1) {
3765 if (write (fd, &c, 1) == -1) {
3771 if (close (fd) == -1) {
3776 if (guestfs_add_drive (g, filename) == -1) {
3777 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3781 filename = \"test3.img\";
3782 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3787 if (lseek (fd, %d, SEEK_SET) == -1) {
3793 if (write (fd, &c, 1) == -1) {
3799 if (close (fd) == -1) {
3804 if (guestfs_add_drive (g, filename) == -1) {
3805 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3809 if (guestfs_launch (g) == -1) {
3810 printf (\"guestfs_launch FAILED\\n\");
3813 if (guestfs_wait_ready (g) == -1) {
3814 printf (\"guestfs_wait_ready FAILED\\n\");
3818 /* Detect if the appliance uses /dev/sd* or /dev/hd* in device
3819 * names. This changed between RHEL 5 and RHEL 6 so we have to
3822 devs = guestfs_list_devices (g);
3823 if (devs == NULL || devs[0] == NULL) {
3824 printf (\"guestfs_list_devices FAILED\\n\");
3827 if (strncmp (devs[0], \"/dev/sd\", 7) == 0)
3829 else if (strncmp (devs[0], \"/dev/hd\", 7) == 0)
3832 printf (\"guestfs_list_devices returned unexpected string '%%s'\\n\",
3836 for (i = 0; devs[i] != NULL; ++i)
3842 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
3846 pr " test_num++;\n";
3847 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
3848 pr " if (%s () == -1) {\n" test_name;
3849 pr " printf (\"%s FAILED\\n\");\n" test_name;
3855 pr " guestfs_close (g);\n";
3856 pr " unlink (\"test1.img\");\n";
3857 pr " unlink (\"test2.img\");\n";
3858 pr " unlink (\"test3.img\");\n";
3861 pr " if (failed > 0) {\n";
3862 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
3870 and generate_one_test name i (init, prereq, test) =
3871 let test_name = sprintf "test_%s_%d" name i in
3874 | Disabled | Always -> ()
3875 | If code | Unless code ->
3876 pr "static int %s_prereq (void)\n" test_name;
3883 pr "static int %s (void)\n" test_name;
3888 pr " printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
3890 pr " if (%s_prereq ()) {\n" test_name;
3891 generate_one_test_body name i test_name init test;
3893 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name
3895 pr " if (! %s_prereq ()) {\n" test_name;
3896 generate_one_test_body name i test_name init test;
3898 pr " printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name
3900 generate_one_test_body name i test_name init test
3908 and generate_one_test_body name i test_name init test =
3912 pr " /* InitNone|InitEmpty for %s */\n" test_name;
3913 List.iter (generate_test_command_call test_name)
3914 [["blockdev_setrw"; "/dev/sda"];
3918 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
3919 List.iter (generate_test_command_call test_name)
3920 [["blockdev_setrw"; "/dev/sda"];
3923 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3924 ["mkfs"; "ext2"; "/dev/sda1"];
3925 ["mount"; "/dev/sda1"; "/"]]
3926 | InitBasicFSonLVM ->
3927 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
3929 List.iter (generate_test_command_call test_name)
3930 [["blockdev_setrw"; "/dev/sda"];
3933 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3934 ["pvcreate"; "/dev/sda1"];
3935 ["vgcreate"; "VG"; "/dev/sda1"];
3936 ["lvcreate"; "LV"; "VG"; "8"];
3937 ["mkfs"; "ext2"; "/dev/VG/LV"];
3938 ["mount"; "/dev/VG/LV"; "/"]]
3941 let get_seq_last = function
3943 failwithf "%s: you cannot use [] (empty list) when expecting a command"
3946 let seq = List.rev seq in
3947 List.rev (List.tl seq), List.hd seq
3952 pr " /* TestRun for %s (%d) */\n" name i;
3953 List.iter (generate_test_command_call test_name) seq
3954 | TestOutput (seq, expected) ->
3955 pr " /* TestOutput for %s (%d) */\n" name i;
3956 pr " char expected[] = \"%s\";\n" (c_quote expected);
3957 if String.length expected > 7 &&
3958 String.sub expected 0 7 = "/dev/sd" then
3959 pr " expected[5] = devchar;\n";
3960 let seq, last = get_seq_last seq in
3962 pr " if (strcmp (r, expected) != 0) {\n";
3963 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
3967 List.iter (generate_test_command_call test_name) seq;
3968 generate_test_command_call ~test test_name last
3969 | TestOutputList (seq, expected) ->
3970 pr " /* TestOutputList for %s (%d) */\n" name i;
3971 let seq, last = get_seq_last seq in
3975 pr " if (!r[%d]) {\n" i;
3976 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
3977 pr " print_strings (r);\n";
3981 pr " char expected[] = \"%s\";\n" (c_quote str);
3982 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
3983 pr " expected[5] = devchar;\n";
3984 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
3985 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
3990 pr " if (r[%d] != NULL) {\n" (List.length expected);
3991 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
3993 pr " print_strings (r);\n";
3997 List.iter (generate_test_command_call test_name) seq;
3998 generate_test_command_call ~test test_name last
3999 | TestOutputInt (seq, expected) ->
4000 pr " /* TestOutputInt for %s (%d) */\n" name i;
4001 let seq, last = get_seq_last seq in
4003 pr " if (r != %d) {\n" expected;
4004 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4010 List.iter (generate_test_command_call test_name) seq;
4011 generate_test_command_call ~test test_name last
4012 | TestOutputTrue seq ->
4013 pr " /* TestOutputTrue for %s (%d) */\n" name i;
4014 let seq, last = get_seq_last seq in
4017 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4022 List.iter (generate_test_command_call test_name) seq;
4023 generate_test_command_call ~test test_name last
4024 | TestOutputFalse seq ->
4025 pr " /* TestOutputFalse for %s (%d) */\n" name i;
4026 let seq, last = get_seq_last seq in
4029 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4034 List.iter (generate_test_command_call test_name) seq;
4035 generate_test_command_call ~test test_name last
4036 | TestOutputLength (seq, expected) ->
4037 pr " /* TestOutputLength for %s (%d) */\n" name i;
4038 let seq, last = get_seq_last seq in
4041 pr " for (j = 0; j < %d; ++j)\n" expected;
4042 pr " if (r[j] == NULL) {\n";
4043 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
4045 pr " print_strings (r);\n";
4048 pr " if (r[j] != NULL) {\n";
4049 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
4051 pr " print_strings (r);\n";
4055 List.iter (generate_test_command_call test_name) seq;
4056 generate_test_command_call ~test test_name last
4057 | TestOutputStruct (seq, checks) ->
4058 pr " /* TestOutputStruct for %s (%d) */\n" name i;
4059 let seq, last = get_seq_last seq in
4063 | CompareWithInt (field, expected) ->
4064 pr " if (r->%s != %d) {\n" field expected;
4065 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4066 test_name field expected;
4067 pr " (int) r->%s);\n" field;
4070 | CompareWithString (field, expected) ->
4071 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4072 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4073 test_name field expected;
4074 pr " r->%s);\n" field;
4077 | CompareFieldsIntEq (field1, field2) ->
4078 pr " if (r->%s != r->%s) {\n" field1 field2;
4079 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4080 test_name field1 field2;
4081 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
4084 | CompareFieldsStrEq (field1, field2) ->
4085 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4086 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4087 test_name field1 field2;
4088 pr " r->%s, r->%s);\n" field1 field2;
4093 List.iter (generate_test_command_call test_name) seq;
4094 generate_test_command_call ~test test_name last
4095 | TestLastFail seq ->
4096 pr " /* TestLastFail for %s (%d) */\n" name i;
4097 let seq, last = get_seq_last seq in
4098 List.iter (generate_test_command_call test_name) seq;
4099 generate_test_command_call test_name ~expect_error:true last
4101 (* Generate the code to run a command, leaving the result in 'r'.
4102 * If you expect to get an error then you should set expect_error:true.
4104 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4106 | [] -> assert false
4108 (* Look up the command to find out what args/ret it has. *)
4111 let _, style, _, _, _, _, _ =
4112 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4115 failwithf "%s: in test, command %s was not found" test_name name in
4117 if List.length (snd style) <> List.length args then
4118 failwithf "%s: in test, wrong number of args given to %s"
4125 | OptString n, "NULL" -> ()
4127 | OptString n, arg ->
4128 pr " char %s[] = \"%s\";\n" n (c_quote arg);
4129 if String.length arg > 7 && String.sub arg 0 7 = "/dev/sd" then
4130 pr " %s[5] = devchar;\n" n
4133 | FileIn _, _ | FileOut _, _ -> ()
4134 | StringList n, arg ->
4135 let strs = string_split " " arg in
4138 pr " char %s_%d[] = \"%s\";\n" n i (c_quote str);
4139 if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
4140 pr " %s_%d[5] = devchar;\n" n i
4142 pr " char *%s[] = {\n" n;
4144 fun i _ -> pr " %s_%d,\n" n i
4148 ) (List.combine (snd style) args);
4151 match fst style with
4152 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4153 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4154 | RConstString _ -> pr " const char *r;\n"; "NULL"
4155 | RString _ -> pr " char *r;\n"; "NULL"
4156 | RStringList _ | RHashtable _ ->
4161 pr " struct guestfs_int_bool *r;\n"; "NULL"
4163 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4165 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4167 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4169 pr " struct guestfs_stat *r;\n"; "NULL"
4171 pr " struct guestfs_statvfs *r;\n"; "NULL" in
4173 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
4174 pr " r = guestfs_%s (g" name;
4176 (* Generate the parameters. *)
4179 | OptString _, "NULL" -> pr ", NULL"
4183 | FileIn _, arg | FileOut _, arg ->
4184 pr ", \"%s\"" (c_quote arg)
4185 | StringList n, _ ->
4189 try int_of_string arg
4190 with Failure "int_of_string" ->
4191 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4194 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4195 ) (List.combine (snd style) args);
4198 if not expect_error then
4199 pr " if (r == %s)\n" error_code
4201 pr " if (r != %s)\n" error_code;
4204 (* Insert the test code. *)
4210 (match fst style with
4211 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4212 | RString _ -> pr " free (r);\n"
4213 | RStringList _ | RHashtable _ ->
4214 pr " for (i = 0; r[i] != NULL; ++i)\n";
4215 pr " free (r[i]);\n";
4218 pr " guestfs_free_int_bool (r);\n"
4220 pr " guestfs_free_lvm_pv_list (r);\n"
4222 pr " guestfs_free_lvm_vg_list (r);\n"
4224 pr " guestfs_free_lvm_lv_list (r);\n"
4225 | RStat _ | RStatVFS _ ->
4232 let str = replace_str str "\r" "\\r" in
4233 let str = replace_str str "\n" "\\n" in
4234 let str = replace_str str "\t" "\\t" in
4235 let str = replace_str str "\000" "\\0" in
4238 (* Generate a lot of different functions for guestfish. *)
4239 and generate_fish_cmds () =
4240 generate_header CStyle GPLv2;
4244 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4246 let all_functions_sorted =
4248 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4249 ) all_functions_sorted in
4251 pr "#include <stdio.h>\n";
4252 pr "#include <stdlib.h>\n";
4253 pr "#include <string.h>\n";
4254 pr "#include <inttypes.h>\n";
4256 pr "#include <guestfs.h>\n";
4257 pr "#include \"fish.h\"\n";
4260 (* list_commands function, which implements guestfish -h *)
4261 pr "void list_commands (void)\n";
4263 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
4264 pr " list_builtin_commands ();\n";
4266 fun (name, _, _, flags, _, shortdesc, _) ->
4267 let name = replace_char name '_' '-' in
4268 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4270 ) all_functions_sorted;
4271 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4275 (* display_command function, which implements guestfish -h cmd *)
4276 pr "void display_command (const char *cmd)\n";
4279 fun (name, style, _, flags, _, shortdesc, longdesc) ->
4280 let name2 = replace_char name '_' '-' in
4282 try find_map (function FishAlias n -> Some n | _ -> None) flags
4283 with Not_found -> name in
4284 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4286 match snd style with
4290 name2 (String.concat "> <" (List.map name_of_argt args)) in
4293 if List.mem ProtocolLimitWarning flags then
4294 ("\n\n" ^ protocol_limit_warning)
4297 (* For DangerWillRobinson commands, we should probably have
4298 * guestfish prompt before allowing you to use them (especially
4299 * in interactive mode). XXX
4303 if List.mem DangerWillRobinson flags then
4304 ("\n\n" ^ danger_will_robinson)
4307 let describe_alias =
4308 if name <> alias then
4309 sprintf "\n\nYou can use '%s' as an alias for this command." alias
4313 pr "strcasecmp (cmd, \"%s\") == 0" name;
4314 if name <> name2 then
4315 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4316 if name <> alias then
4317 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4319 pr " pod2text (\"%s - %s\", %S);\n"
4321 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4324 pr " display_builtin_command (cmd);\n";
4328 (* print_{pv,vg,lv}_list functions *)
4332 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4339 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4341 pr " printf (\"%s: \");\n" name;
4342 pr " for (i = 0; i < 32; ++i)\n";
4343 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
4344 pr " printf (\"\\n\");\n"
4346 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4348 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4349 | name, `OptPercent ->
4350 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4351 typ name name typ name;
4352 pr " else printf (\"%s: \\n\");\n" name
4356 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4361 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4362 pr " print_%s (&%ss->val[i]);\n" typ typ;
4365 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4367 (* print_{stat,statvfs} functions *)
4371 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4376 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4380 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4382 (* run_<action> actions *)
4384 fun (name, style, _, flags, _, _, _) ->
4385 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4387 (match fst style with
4390 | RBool _ -> pr " int r;\n"
4391 | RInt64 _ -> pr " int64_t r;\n"
4392 | RConstString _ -> pr " const char *r;\n"
4393 | RString _ -> pr " char *r;\n"
4394 | RStringList _ | RHashtable _ -> pr " char **r;\n"
4395 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
4396 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
4397 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
4398 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
4399 | RStat _ -> pr " struct guestfs_stat *r;\n"
4400 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
4407 | FileOut n -> pr " const char *%s;\n" n
4408 | StringList n -> pr " char **%s;\n" n
4409 | Bool n -> pr " int %s;\n" n
4410 | Int n -> pr " int %s;\n" n
4413 (* Check and convert parameters. *)
4414 let argc_expected = List.length (snd style) in
4415 pr " if (argc != %d) {\n" argc_expected;
4416 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
4418 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
4424 | String name -> pr " %s = argv[%d];\n" name i
4426 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
4429 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
4432 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
4434 | StringList name ->
4435 pr " %s = parse_string_list (argv[%d]);\n" name i
4437 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
4439 pr " %s = atoi (argv[%d]);\n" name i
4442 (* Call C API function. *)
4444 try find_map (function FishAction n -> Some n | _ -> None) flags
4445 with Not_found -> sprintf "guestfs_%s" name in
4447 generate_call_args ~handle:"g" (snd style);
4450 (* Check return value for errors and display command results. *)
4451 (match fst style with
4452 | RErr -> pr " return r;\n"
4454 pr " if (r == -1) return -1;\n";
4455 pr " printf (\"%%d\\n\", r);\n";
4458 pr " if (r == -1) return -1;\n";
4459 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
4462 pr " if (r == -1) return -1;\n";
4463 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
4466 pr " if (r == NULL) return -1;\n";
4467 pr " printf (\"%%s\\n\", r);\n";
4470 pr " if (r == NULL) return -1;\n";
4471 pr " printf (\"%%s\\n\", r);\n";
4475 pr " if (r == NULL) return -1;\n";
4476 pr " print_strings (r);\n";
4477 pr " free_strings (r);\n";
4480 pr " if (r == NULL) return -1;\n";
4481 pr " printf (\"%%d, %%s\\n\", r->i,\n";
4482 pr " r->b ? \"true\" : \"false\");\n";
4483 pr " guestfs_free_int_bool (r);\n";
4486 pr " if (r == NULL) return -1;\n";
4487 pr " print_pv_list (r);\n";
4488 pr " guestfs_free_lvm_pv_list (r);\n";
4491 pr " if (r == NULL) return -1;\n";
4492 pr " print_vg_list (r);\n";
4493 pr " guestfs_free_lvm_vg_list (r);\n";
4496 pr " if (r == NULL) return -1;\n";
4497 pr " print_lv_list (r);\n";
4498 pr " guestfs_free_lvm_lv_list (r);\n";
4501 pr " if (r == NULL) return -1;\n";
4502 pr " print_stat (r);\n";
4506 pr " if (r == NULL) return -1;\n";
4507 pr " print_statvfs (r);\n";
4511 pr " if (r == NULL) return -1;\n";
4512 pr " print_table (r);\n";
4513 pr " free_strings (r);\n";
4520 (* run_action function *)
4521 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
4524 fun (name, _, _, flags, _, _, _) ->
4525 let name2 = replace_char name '_' '-' in
4527 try find_map (function FishAlias n -> Some n | _ -> None) flags
4528 with Not_found -> name in
4530 pr "strcasecmp (cmd, \"%s\") == 0" name;
4531 if name <> name2 then
4532 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4533 if name <> alias then
4534 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4536 pr " return run_%s (cmd, argc, argv);\n" name;
4540 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
4547 (* Readline completion for guestfish. *)
4548 and generate_fish_completion () =
4549 generate_header CStyle GPLv2;
4553 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4563 #ifdef HAVE_LIBREADLINE
4564 #include <readline/readline.h>
4569 #ifdef HAVE_LIBREADLINE
4571 static const char *const commands[] = {
4574 (* Get the commands and sort them, including the aliases. *)
4577 fun (name, _, _, flags, _, _, _) ->
4578 let name2 = replace_char name '_' '-' in
4580 try find_map (function FishAlias n -> Some n | _ -> None) flags
4581 with Not_found -> name in
4583 if name <> alias then [name2; alias] else [name2]
4585 let commands = List.flatten commands in
4586 let commands = List.sort compare commands in
4588 List.iter (pr " \"%s\",\n") commands;
4594 generator (const char *text, int state)
4596 static int index, len;
4601 len = strlen (text);
4604 while ((name = commands[index]) != NULL) {
4606 if (strncasecmp (name, text, len) == 0)
4607 return strdup (name);
4613 #endif /* HAVE_LIBREADLINE */
4615 char **do_completion (const char *text, int start, int end)
4617 char **matches = NULL;
4619 #ifdef HAVE_LIBREADLINE
4621 matches = rl_completion_matches (text, generator);
4628 (* Generate the POD documentation for guestfish. *)
4629 and generate_fish_actions_pod () =
4630 let all_functions_sorted =
4632 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4633 ) all_functions_sorted in
4635 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
4638 fun (name, style, _, flags, _, _, longdesc) ->
4640 Str.global_substitute rex (
4643 try Str.matched_group 1 s
4645 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
4646 "C<" ^ replace_char sub '_' '-' ^ ">"
4648 let name = replace_char name '_' '-' in
4650 try find_map (function FishAlias n -> Some n | _ -> None) flags
4651 with Not_found -> name in
4653 pr "=head2 %s" name;
4654 if name <> alias then
4661 | String n -> pr " %s" n
4662 | OptString n -> pr " %s" n
4663 | StringList n -> pr " '%s ...'" n
4664 | Bool _ -> pr " true|false"
4665 | Int n -> pr " %s" n
4666 | FileIn n | FileOut n -> pr " (%s|-)" n
4670 pr "%s\n\n" longdesc;
4672 if List.exists (function FileIn _ | FileOut _ -> true
4673 | _ -> false) (snd style) then
4674 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
4676 if List.mem ProtocolLimitWarning flags then
4677 pr "%s\n\n" protocol_limit_warning;
4679 if List.mem DangerWillRobinson flags then
4680 pr "%s\n\n" danger_will_robinson
4681 ) all_functions_sorted
4683 (* Generate a C function prototype. *)
4684 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
4685 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
4687 ?handle name style =
4688 if extern then pr "extern ";
4689 if static then pr "static ";
4690 (match fst style with
4692 | RInt _ -> pr "int "
4693 | RInt64 _ -> pr "int64_t "
4694 | RBool _ -> pr "int "
4695 | RConstString _ -> pr "const char *"
4696 | RString _ -> pr "char *"
4697 | RStringList _ | RHashtable _ -> pr "char **"
4699 if not in_daemon then pr "struct guestfs_int_bool *"
4700 else pr "guestfs_%s_ret *" name
4702 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
4703 else pr "guestfs_lvm_int_pv_list *"
4705 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
4706 else pr "guestfs_lvm_int_vg_list *"
4708 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
4709 else pr "guestfs_lvm_int_lv_list *"
4711 if not in_daemon then pr "struct guestfs_stat *"
4712 else pr "guestfs_int_stat *"
4714 if not in_daemon then pr "struct guestfs_statvfs *"
4715 else pr "guestfs_int_statvfs *"
4717 pr "%s%s (" prefix name;
4718 if handle = None && List.length (snd style) = 0 then
4721 let comma = ref false in
4724 | Some handle -> pr "guestfs_h *%s" handle; comma := true
4728 if single_line then pr ", " else pr ",\n\t\t"
4735 | OptString n -> next (); pr "const char *%s" n
4736 | StringList n -> next (); pr "char * const* const %s" n
4737 | Bool n -> next (); pr "int %s" n
4738 | Int n -> next (); pr "int %s" n
4741 if not in_daemon then (next (); pr "const char *%s" n)
4745 if semicolon then pr ";";
4746 if newline then pr "\n"
4748 (* Generate C call arguments, eg "(handle, foo, bar)" *)
4749 and generate_call_args ?handle args =
4751 let comma = ref false in
4754 | Some handle -> pr "%s" handle; comma := true
4758 if !comma then pr ", ";
4760 pr "%s" (name_of_argt arg)
4764 (* Generate the OCaml bindings interface. *)
4765 and generate_ocaml_mli () =
4766 generate_header OCamlStyle LGPLv2;
4769 (** For API documentation you should refer to the C API
4770 in the guestfs(3) manual page. The OCaml API uses almost
4771 exactly the same calls. *)
4774 (** A [guestfs_h] handle. *)
4776 exception Error of string
4777 (** This exception is raised when there is an error. *)
4779 val create : unit -> t
4781 val close : t -> unit
4782 (** Handles are closed by the garbage collector when they become
4783 unreferenced, but callers can also call this in order to
4784 provide predictable cleanup. *)
4787 generate_ocaml_lvm_structure_decls ();
4789 generate_ocaml_stat_structure_decls ();
4793 fun (name, style, _, _, _, shortdesc, _) ->
4794 generate_ocaml_prototype name style;
4795 pr "(** %s *)\n" shortdesc;
4799 (* Generate the OCaml bindings implementation. *)
4800 and generate_ocaml_ml () =
4801 generate_header OCamlStyle LGPLv2;
4805 exception Error of string
4806 external create : unit -> t = \"ocaml_guestfs_create\"
4807 external close : t -> unit = \"ocaml_guestfs_close\"
4810 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
4814 generate_ocaml_lvm_structure_decls ();
4816 generate_ocaml_stat_structure_decls ();
4820 fun (name, style, _, _, _, shortdesc, _) ->
4821 generate_ocaml_prototype ~is_external:true name style;
4824 (* Generate the OCaml bindings C implementation. *)
4825 and generate_ocaml_c () =
4826 generate_header CStyle LGPLv2;
4833 #include <caml/config.h>
4834 #include <caml/alloc.h>
4835 #include <caml/callback.h>
4836 #include <caml/fail.h>
4837 #include <caml/memory.h>
4838 #include <caml/mlvalues.h>
4839 #include <caml/signals.h>
4841 #include <guestfs.h>
4843 #include \"guestfs_c.h\"
4845 /* Copy a hashtable of string pairs into an assoc-list. We return
4846 * the list in reverse order, but hashtables aren't supposed to be
4849 static CAMLprim value
4850 copy_table (char * const * argv)
4853 CAMLlocal5 (rv, pairv, kv, vv, cons);
4857 for (i = 0; argv[i] != NULL; i += 2) {
4858 kv = caml_copy_string (argv[i]);
4859 vv = caml_copy_string (argv[i+1]);
4860 pairv = caml_alloc (2, 0);
4861 Store_field (pairv, 0, kv);
4862 Store_field (pairv, 1, vv);
4863 cons = caml_alloc (2, 0);
4864 Store_field (cons, 1, rv);
4866 Store_field (cons, 0, pairv);
4874 (* LVM struct copy functions. *)
4877 let has_optpercent_col =
4878 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
4880 pr "static CAMLprim value\n";
4881 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
4883 pr " CAMLparam0 ();\n";
4884 if has_optpercent_col then
4885 pr " CAMLlocal3 (rv, v, v2);\n"
4887 pr " CAMLlocal2 (rv, v);\n";
4889 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
4894 pr " v = caml_copy_string (%s->%s);\n" typ name
4896 pr " v = caml_alloc_string (32);\n";
4897 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
4900 pr " v = caml_copy_int64 (%s->%s);\n" typ name
4901 | name, `OptPercent ->
4902 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
4903 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
4904 pr " v = caml_alloc (1, 0);\n";
4905 pr " Store_field (v, 0, v2);\n";
4906 pr " } else /* None */\n";
4907 pr " v = Val_int (0);\n";
4909 pr " Store_field (rv, %d, v);\n" i
4911 pr " CAMLreturn (rv);\n";
4915 pr "static CAMLprim value\n";
4916 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
4919 pr " CAMLparam0 ();\n";
4920 pr " CAMLlocal2 (rv, v);\n";
4923 pr " if (%ss->len == 0)\n" typ;
4924 pr " CAMLreturn (Atom (0));\n";
4926 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
4927 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
4928 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
4929 pr " caml_modify (&Field (rv, i), v);\n";
4931 pr " CAMLreturn (rv);\n";
4935 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4937 (* Stat copy functions. *)
4940 pr "static CAMLprim value\n";
4941 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
4943 pr " CAMLparam0 ();\n";
4944 pr " CAMLlocal2 (rv, v);\n";
4946 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
4951 pr " v = caml_copy_int64 (%s->%s);\n" typ name
4953 pr " Store_field (rv, %d, v);\n" i
4955 pr " CAMLreturn (rv);\n";
4958 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4962 fun (name, style, _, _, _, _, _) ->
4964 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
4966 pr "CAMLprim value\n";
4967 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
4968 List.iter (pr ", value %s") (List.tl params);
4973 | [p1; p2; p3; p4; p5] ->
4974 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
4975 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
4976 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
4977 pr " CAMLxparam%d (%s);\n"
4978 (List.length rest) (String.concat ", " rest)
4980 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
4982 pr " CAMLlocal1 (rv);\n";
4985 pr " guestfs_h *g = Guestfs_val (gv);\n";
4986 pr " if (g == NULL)\n";
4987 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
4995 pr " const char *%s = String_val (%sv);\n" n n
4997 pr " const char *%s =\n" n;
4998 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5001 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5003 pr " int %s = Bool_val (%sv);\n" n n
5005 pr " int %s = Int_val (%sv);\n" n n
5008 match fst style with
5009 | RErr -> pr " int r;\n"; "-1"
5010 | RInt _ -> pr " int r;\n"; "-1"
5011 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5012 | RBool _ -> pr " int r;\n"; "-1"
5013 | RConstString _ -> pr " const char *r;\n"; "NULL"
5014 | RString _ -> pr " char *r;\n"; "NULL"
5020 pr " struct guestfs_int_bool *r;\n"; "NULL"
5022 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5024 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5026 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5028 pr " struct guestfs_stat *r;\n"; "NULL"
5030 pr " struct guestfs_statvfs *r;\n"; "NULL"
5037 pr " caml_enter_blocking_section ();\n";
5038 pr " r = guestfs_%s " name;
5039 generate_call_args ~handle:"g" (snd style);
5041 pr " caml_leave_blocking_section ();\n";
5046 pr " ocaml_guestfs_free_strings (%s);\n" n;
5047 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5050 pr " if (r == %s)\n" error_code;
5051 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5054 (match fst style with
5055 | RErr -> pr " rv = Val_unit;\n"
5056 | RInt _ -> pr " rv = Val_int (r);\n"
5058 pr " rv = caml_copy_int64 (r);\n"
5059 | RBool _ -> pr " rv = Val_bool (r);\n"
5060 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
5062 pr " rv = caml_copy_string (r);\n";
5065 pr " rv = caml_copy_string_array ((const char **) r);\n";
5066 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5069 pr " rv = caml_alloc (2, 0);\n";
5070 pr " Store_field (rv, 0, Val_int (r->i));\n";
5071 pr " Store_field (rv, 1, Val_bool (r->b));\n";
5072 pr " guestfs_free_int_bool (r);\n";
5074 pr " rv = copy_lvm_pv_list (r);\n";
5075 pr " guestfs_free_lvm_pv_list (r);\n";
5077 pr " rv = copy_lvm_vg_list (r);\n";
5078 pr " guestfs_free_lvm_vg_list (r);\n";
5080 pr " rv = copy_lvm_lv_list (r);\n";
5081 pr " guestfs_free_lvm_lv_list (r);\n";
5083 pr " rv = copy_stat (r);\n";
5086 pr " rv = copy_statvfs (r);\n";
5089 pr " rv = copy_table (r);\n";
5090 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5094 pr " CAMLreturn (rv);\n";
5098 if List.length params > 5 then (
5099 pr "CAMLprim value\n";
5100 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5102 pr " return ocaml_guestfs_%s (argv[0]" name;
5103 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5110 and generate_ocaml_lvm_structure_decls () =
5113 pr "type lvm_%s = {\n" typ;
5116 | name, `String -> pr " %s : string;\n" name
5117 | name, `UUID -> pr " %s : string;\n" name
5118 | name, `Bytes -> pr " %s : int64;\n" name
5119 | name, `Int -> pr " %s : int64;\n" name
5120 | name, `OptPercent -> pr " %s : float option;\n" name
5124 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5126 and generate_ocaml_stat_structure_decls () =
5129 pr "type %s = {\n" typ;
5132 | name, `Int -> pr " %s : int64;\n" name
5136 ) ["stat", stat_cols; "statvfs", statvfs_cols]
5138 and generate_ocaml_prototype ?(is_external = false) name style =
5139 if is_external then pr "external " else pr "val ";
5140 pr "%s : t -> " name;
5143 | String _ | FileIn _ | FileOut _ -> pr "string -> "
5144 | OptString _ -> pr "string option -> "
5145 | StringList _ -> pr "string array -> "
5146 | Bool _ -> pr "bool -> "
5147 | Int _ -> pr "int -> "
5149 (match fst style with
5150 | RErr -> pr "unit" (* all errors are turned into exceptions *)
5151 | RInt _ -> pr "int"
5152 | RInt64 _ -> pr "int64"
5153 | RBool _ -> pr "bool"
5154 | RConstString _ -> pr "string"
5155 | RString _ -> pr "string"
5156 | RStringList _ -> pr "string array"
5157 | RIntBool _ -> pr "int * bool"
5158 | RPVList _ -> pr "lvm_pv array"
5159 | RVGList _ -> pr "lvm_vg array"
5160 | RLVList _ -> pr "lvm_lv array"
5161 | RStat _ -> pr "stat"
5162 | RStatVFS _ -> pr "statvfs"
5163 | RHashtable _ -> pr "(string * string) list"
5165 if is_external then (
5167 if List.length (snd style) + 1 > 5 then
5168 pr "\"ocaml_guestfs_%s_byte\" " name;
5169 pr "\"ocaml_guestfs_%s\"" name
5173 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5174 and generate_perl_xs () =
5175 generate_header CStyle LGPLv2;
5178 #include \"EXTERN.h\"
5182 #include <guestfs.h>
5185 #define PRId64 \"lld\"
5189 my_newSVll(long long val) {
5190 #ifdef USE_64_BIT_ALL
5191 return newSViv(val);
5195 len = snprintf(buf, 100, \"%%\" PRId64, val);
5196 return newSVpv(buf, len);
5201 #define PRIu64 \"llu\"
5205 my_newSVull(unsigned long long val) {
5206 #ifdef USE_64_BIT_ALL
5207 return newSVuv(val);
5211 len = snprintf(buf, 100, \"%%\" PRIu64, val);
5212 return newSVpv(buf, len);
5216 /* http://www.perlmonks.org/?node_id=680842 */
5218 XS_unpack_charPtrPtr (SV *arg) {
5223 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5224 croak (\"array reference expected\");
5226 av = (AV *)SvRV (arg);
5227 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5229 croak (\"malloc failed\");
5231 for (i = 0; i <= av_len (av); i++) {
5232 SV **elem = av_fetch (av, i, 0);
5234 if (!elem || !*elem)
5235 croak (\"missing element in list\");
5237 ret[i] = SvPV_nolen (*elem);
5245 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
5252 RETVAL = guestfs_create ();
5254 croak (\"could not create guestfs handle\");
5255 guestfs_set_error_handler (RETVAL, NULL, NULL);
5268 fun (name, style, _, _, _, _, _) ->
5269 (match fst style with
5270 | RErr -> pr "void\n"
5271 | RInt _ -> pr "SV *\n"
5272 | RInt64 _ -> pr "SV *\n"
5273 | RBool _ -> pr "SV *\n"
5274 | RConstString _ -> pr "SV *\n"
5275 | RString _ -> pr "SV *\n"
5278 | RPVList _ | RVGList _ | RLVList _
5279 | RStat _ | RStatVFS _
5281 pr "void\n" (* all lists returned implictly on the stack *)
5283 (* Call and arguments. *)
5285 generate_call_args ~handle:"g" (snd style);
5287 pr " guestfs_h *g;\n";
5290 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
5291 | OptString n -> pr " char *%s;\n" n
5292 | StringList n -> pr " char **%s;\n" n
5293 | Bool n -> pr " int %s;\n" n
5294 | Int n -> pr " int %s;\n" n
5297 let do_cleanups () =
5300 | String _ | OptString _ | Bool _ | Int _
5301 | FileIn _ | FileOut _ -> ()
5302 | StringList n -> pr " free (%s);\n" n
5307 (match fst style with
5312 pr " r = guestfs_%s " name;
5313 generate_call_args ~handle:"g" (snd style);
5316 pr " if (r == -1)\n";
5317 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5323 pr " %s = guestfs_%s " n name;
5324 generate_call_args ~handle:"g" (snd style);
5327 pr " if (%s == -1)\n" n;
5328 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5329 pr " RETVAL = newSViv (%s);\n" n;
5334 pr " int64_t %s;\n" n;
5336 pr " %s = guestfs_%s " n name;
5337 generate_call_args ~handle:"g" (snd style);
5340 pr " if (%s == -1)\n" n;
5341 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5342 pr " RETVAL = my_newSVll (%s);\n" n;
5347 pr " const char *%s;\n" n;
5349 pr " %s = guestfs_%s " n name;
5350 generate_call_args ~handle:"g" (snd style);
5353 pr " if (%s == NULL)\n" n;
5354 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5355 pr " RETVAL = newSVpv (%s, 0);\n" n;
5360 pr " char *%s;\n" n;
5362 pr " %s = guestfs_%s " n name;
5363 generate_call_args ~handle:"g" (snd style);
5366 pr " if (%s == NULL)\n" n;
5367 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5368 pr " RETVAL = newSVpv (%s, 0);\n" n;
5369 pr " free (%s);\n" n;
5372 | RStringList n | RHashtable n ->
5374 pr " char **%s;\n" n;
5377 pr " %s = guestfs_%s " n name;
5378 generate_call_args ~handle:"g" (snd style);
5381 pr " if (%s == NULL)\n" n;
5382 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5383 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
5384 pr " EXTEND (SP, n);\n";
5385 pr " for (i = 0; i < n; ++i) {\n";
5386 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
5387 pr " free (%s[i]);\n" n;
5389 pr " free (%s);\n" n;
5392 pr " struct guestfs_int_bool *r;\n";
5394 pr " r = guestfs_%s " name;
5395 generate_call_args ~handle:"g" (snd style);
5398 pr " if (r == NULL)\n";
5399 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5400 pr " EXTEND (SP, 2);\n";
5401 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
5402 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
5403 pr " guestfs_free_int_bool (r);\n";
5405 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
5407 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
5409 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
5411 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
5413 generate_perl_stat_code
5414 "statvfs" statvfs_cols name style n do_cleanups
5420 and generate_perl_lvm_code typ cols name style n do_cleanups =
5422 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
5426 pr " %s = guestfs_%s " n name;
5427 generate_call_args ~handle:"g" (snd style);
5430 pr " if (%s == NULL)\n" n;
5431 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5432 pr " EXTEND (SP, %s->len);\n" n;
5433 pr " for (i = 0; i < %s->len; ++i) {\n" n;
5434 pr " hv = newHV ();\n";
5438 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
5439 name (String.length name) n name
5441 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
5442 name (String.length name) n name
5444 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
5445 name (String.length name) n name
5447 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
5448 name (String.length name) n name
5449 | name, `OptPercent ->
5450 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
5451 name (String.length name) n name
5453 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
5455 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
5457 and generate_perl_stat_code typ cols name style n do_cleanups =
5459 pr " struct guestfs_%s *%s;\n" typ n;
5461 pr " %s = guestfs_%s " n name;
5462 generate_call_args ~handle:"g" (snd style);
5465 pr " if (%s == NULL)\n" n;
5466 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5467 pr " EXTEND (SP, %d);\n" (List.length cols);
5471 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
5473 pr " free (%s);\n" n
5475 (* Generate Sys/Guestfs.pm. *)
5476 and generate_perl_pm () =
5477 generate_header HashStyle LGPLv2;
5484 Sys::Guestfs - Perl bindings for libguestfs
5490 my $h = Sys::Guestfs->new ();
5491 $h->add_drive ('guest.img');
5494 $h->mount ('/dev/sda1', '/');
5495 $h->touch ('/hello');
5500 The C<Sys::Guestfs> module provides a Perl XS binding to the
5501 libguestfs API for examining and modifying virtual machine
5504 Amongst the things this is good for: making batch configuration
5505 changes to guests, getting disk used/free statistics (see also:
5506 virt-df), migrating between virtualization systems (see also:
5507 virt-p2v), performing partial backups, performing partial guest
5508 clones, cloning guests and changing registry/UUID/hostname info, and
5511 Libguestfs uses Linux kernel and qemu code, and can access any type of
5512 guest filesystem that Linux and qemu can, including but not limited
5513 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5514 schemes, qcow, qcow2, vmdk.
5516 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5517 LVs, what filesystem is in each LV, etc.). It can also run commands
5518 in the context of the guest. Also you can access filesystems over FTP.
5522 All errors turn into calls to C<croak> (see L<Carp(3)>).
5530 package Sys::Guestfs;
5536 XSLoader::load ('Sys::Guestfs');
5538 =item $h = Sys::Guestfs->new ();
5540 Create a new guestfs handle.
5546 my $class = ref ($proto) || $proto;
5548 my $self = Sys::Guestfs::_create ();
5549 bless $self, $class;
5555 (* Actions. We only need to print documentation for these as
5556 * they are pulled in from the XS code automatically.
5559 fun (name, style, _, flags, _, _, longdesc) ->
5560 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
5562 generate_perl_prototype name style;
5564 pr "%s\n\n" longdesc;
5565 if List.mem ProtocolLimitWarning flags then
5566 pr "%s\n\n" protocol_limit_warning;
5567 if List.mem DangerWillRobinson flags then
5568 pr "%s\n\n" danger_will_robinson
5569 ) all_functions_sorted;
5581 Copyright (C) 2009 Red Hat Inc.
5585 Please see the file COPYING.LIB for the full license.
5589 L<guestfs(3)>, L<guestfish(1)>.
5594 and generate_perl_prototype name style =
5595 (match fst style with
5601 | RString n -> pr "$%s = " n
5602 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
5606 | RLVList n -> pr "@%s = " n
5609 | RHashtable n -> pr "%%%s = " n
5612 let comma = ref false in
5615 if !comma then pr ", ";
5618 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
5625 (* Generate Python C module. *)
5626 and generate_python_c () =
5627 generate_header CStyle LGPLv2;
5636 #include \"guestfs.h\"
5644 get_handle (PyObject *obj)
5647 assert (obj != Py_None);
5648 return ((Pyguestfs_Object *) obj)->g;
5652 put_handle (guestfs_h *g)
5656 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
5659 /* This list should be freed (but not the strings) after use. */
5660 static const char **
5661 get_string_list (PyObject *obj)
5668 if (!PyList_Check (obj)) {
5669 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
5673 len = PyList_Size (obj);
5674 r = malloc (sizeof (char *) * (len+1));
5676 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
5680 for (i = 0; i < len; ++i)
5681 r[i] = PyString_AsString (PyList_GetItem (obj, i));
5688 put_string_list (char * const * const argv)
5693 for (argc = 0; argv[argc] != NULL; ++argc)
5696 list = PyList_New (argc);
5697 for (i = 0; i < argc; ++i)
5698 PyList_SetItem (list, i, PyString_FromString (argv[i]));
5704 put_table (char * const * const argv)
5706 PyObject *list, *item;
5709 for (argc = 0; argv[argc] != NULL; ++argc)
5712 list = PyList_New (argc >> 1);
5713 for (i = 0; i < argc; i += 2) {
5714 item = PyTuple_New (2);
5715 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
5716 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
5717 PyList_SetItem (list, i >> 1, item);
5724 free_strings (char **argv)
5728 for (argc = 0; argv[argc] != NULL; ++argc)
5734 py_guestfs_create (PyObject *self, PyObject *args)
5738 g = guestfs_create ();
5740 PyErr_SetString (PyExc_RuntimeError,
5741 \"guestfs.create: failed to allocate handle\");
5744 guestfs_set_error_handler (g, NULL, NULL);
5745 return put_handle (g);
5749 py_guestfs_close (PyObject *self, PyObject *args)
5754 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
5756 g = get_handle (py_g);
5760 Py_INCREF (Py_None);
5766 (* LVM structures, turned into Python dictionaries. *)
5769 pr "static PyObject *\n";
5770 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
5772 pr " PyObject *dict;\n";
5774 pr " dict = PyDict_New ();\n";
5778 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5779 pr " PyString_FromString (%s->%s));\n"
5782 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5783 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
5786 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5787 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
5790 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5791 pr " PyLong_FromLongLong (%s->%s));\n"
5793 | name, `OptPercent ->
5794 pr " if (%s->%s >= 0)\n" typ name;
5795 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5796 pr " PyFloat_FromDouble ((double) %s->%s));\n"
5799 pr " Py_INCREF (Py_None);\n";
5800 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
5803 pr " return dict;\n";
5807 pr "static PyObject *\n";
5808 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
5810 pr " PyObject *list;\n";
5813 pr " list = PyList_New (%ss->len);\n" typ;
5814 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
5815 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
5816 pr " return list;\n";
5819 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5821 (* Stat structures, turned into Python dictionaries. *)
5824 pr "static PyObject *\n";
5825 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
5827 pr " PyObject *dict;\n";
5829 pr " dict = PyDict_New ();\n";
5833 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
5834 pr " PyLong_FromLongLong (%s->%s));\n"
5837 pr " return dict;\n";
5840 ) ["stat", stat_cols; "statvfs", statvfs_cols];
5842 (* Python wrapper functions. *)
5844 fun (name, style, _, _, _, _, _) ->
5845 pr "static PyObject *\n";
5846 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
5849 pr " PyObject *py_g;\n";
5850 pr " guestfs_h *g;\n";
5851 pr " PyObject *py_r;\n";
5854 match fst style with
5855 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
5856 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5857 | RConstString _ -> pr " const char *r;\n"; "NULL"
5858 | RString _ -> pr " char *r;\n"; "NULL"
5859 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
5860 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
5861 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5862 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5863 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5864 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
5865 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
5869 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
5870 | OptString n -> pr " const char *%s;\n" n
5872 pr " PyObject *py_%s;\n" n;
5873 pr " const char **%s;\n" n
5874 | Bool n -> pr " int %s;\n" n
5875 | Int n -> pr " int %s;\n" n
5880 (* Convert the parameters. *)
5881 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
5884 | String _ | FileIn _ | FileOut _ -> pr "s"
5885 | OptString _ -> pr "z"
5886 | StringList _ -> pr "O"
5887 | Bool _ -> pr "i" (* XXX Python has booleans? *)
5890 pr ":guestfs_%s\",\n" name;
5894 | String n | FileIn n | FileOut n -> pr ", &%s" n
5895 | OptString n -> pr ", &%s" n
5896 | StringList n -> pr ", &py_%s" n
5897 | Bool n -> pr ", &%s" n
5898 | Int n -> pr ", &%s" n
5902 pr " return NULL;\n";
5904 pr " g = get_handle (py_g);\n";
5907 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5909 pr " %s = get_string_list (py_%s);\n" n n;
5910 pr " if (!%s) return NULL;\n" n
5915 pr " r = guestfs_%s " name;
5916 generate_call_args ~handle:"g" (snd style);
5921 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5923 pr " free (%s);\n" n
5926 pr " if (r == %s) {\n" error_code;
5927 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
5928 pr " return NULL;\n";
5932 (match fst style with
5934 pr " Py_INCREF (Py_None);\n";
5935 pr " py_r = Py_None;\n"
5937 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
5938 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
5939 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
5941 pr " py_r = PyString_FromString (r);\n";
5944 pr " py_r = put_string_list (r);\n";
5945 pr " free_strings (r);\n"
5947 pr " py_r = PyTuple_New (2);\n";
5948 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
5949 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
5950 pr " guestfs_free_int_bool (r);\n"
5952 pr " py_r = put_lvm_pv_list (r);\n";
5953 pr " guestfs_free_lvm_pv_list (r);\n"
5955 pr " py_r = put_lvm_vg_list (r);\n";
5956 pr " guestfs_free_lvm_vg_list (r);\n"
5958 pr " py_r = put_lvm_lv_list (r);\n";
5959 pr " guestfs_free_lvm_lv_list (r);\n"
5961 pr " py_r = put_stat (r);\n";
5964 pr " py_r = put_statvfs (r);\n";
5967 pr " py_r = put_table (r);\n";
5968 pr " free_strings (r);\n"
5971 pr " return py_r;\n";
5976 (* Table of functions. *)
5977 pr "static PyMethodDef methods[] = {\n";
5978 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
5979 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
5981 fun (name, _, _, _, _, _, _) ->
5982 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
5985 pr " { NULL, NULL, 0, NULL }\n";
5989 (* Init function. *)
5992 initlibguestfsmod (void)
5994 static int initialized = 0;
5996 if (initialized) return;
5997 Py_InitModule ((char *) \"libguestfsmod\", methods);
6002 (* Generate Python module. *)
6003 and generate_python_py () =
6004 generate_header HashStyle LGPLv2;
6007 u\"\"\"Python bindings for libguestfs
6010 g = guestfs.GuestFS ()
6011 g.add_drive (\"guest.img\")
6014 parts = g.list_partitions ()
6016 The guestfs module provides a Python binding to the libguestfs API
6017 for examining and modifying virtual machine disk images.
6019 Amongst the things this is good for: making batch configuration
6020 changes to guests, getting disk used/free statistics (see also:
6021 virt-df), migrating between virtualization systems (see also:
6022 virt-p2v), performing partial backups, performing partial guest
6023 clones, cloning guests and changing registry/UUID/hostname info, and
6026 Libguestfs uses Linux kernel and qemu code, and can access any type of
6027 guest filesystem that Linux and qemu can, including but not limited
6028 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6029 schemes, qcow, qcow2, vmdk.
6031 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6032 LVs, what filesystem is in each LV, etc.). It can also run commands
6033 in the context of the guest. Also you can access filesystems over FTP.
6035 Errors which happen while using the API are turned into Python
6036 RuntimeError exceptions.
6038 To create a guestfs handle you usually have to perform the following
6041 # Create the handle, call add_drive at least once, and possibly
6042 # several times if the guest has multiple block devices:
6043 g = guestfs.GuestFS ()
6044 g.add_drive (\"guest.img\")
6046 # Launch the qemu subprocess and wait for it to become ready:
6050 # Now you can issue commands, for example:
6055 import libguestfsmod
6058 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6060 def __init__ (self):
6061 \"\"\"Create a new libguestfs handle.\"\"\"
6062 self._o = libguestfsmod.create ()
6065 libguestfsmod.close (self._o)
6070 fun (name, style, _, flags, _, _, longdesc) ->
6071 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6073 match fst style with
6074 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6077 doc ^ "\n\nThis function returns a list of strings."
6079 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6081 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
6083 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
6085 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
6087 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6089 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6091 doc ^ "\n\nThis function returns a dictionary." in
6093 if List.mem ProtocolLimitWarning flags then
6094 doc ^ "\n\n" ^ protocol_limit_warning
6097 if List.mem DangerWillRobinson flags then
6098 doc ^ "\n\n" ^ danger_will_robinson
6100 let doc = pod2text ~width:60 name doc in
6101 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6102 let doc = String.concat "\n " doc in
6105 generate_call_args ~handle:"self" (snd style);
6107 pr " u\"\"\"%s\"\"\"\n" doc;
6108 pr " return libguestfsmod.%s " name;
6109 generate_call_args ~handle:"self._o" (snd style);
6114 (* Useful if you need the longdesc POD text as plain text. Returns a
6117 * This is the slowest thing about autogeneration.
6119 and pod2text ~width name longdesc =
6120 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6121 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6123 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6124 let chan = Unix.open_process_in cmd in
6125 let lines = ref [] in
6127 let line = input_line chan in
6128 if i = 1 then (* discard the first line of output *)
6131 let line = triml line in
6132 lines := line :: !lines;
6135 let lines = try loop 1 with End_of_file -> List.rev !lines in
6136 Unix.unlink filename;
6137 match Unix.close_process_in chan with
6138 | Unix.WEXITED 0 -> lines
6140 failwithf "pod2text: process exited with non-zero status (%d)" i
6141 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6142 failwithf "pod2text: process signalled or stopped by signal %d" i
6144 (* Generate ruby bindings. *)
6145 and generate_ruby_c () =
6146 generate_header CStyle LGPLv2;
6154 #include \"guestfs.h\"
6156 #include \"extconf.h\"
6158 /* For Ruby < 1.9 */
6160 #define RARRAY_LEN(r) (RARRAY((r))->len)
6163 static VALUE m_guestfs; /* guestfs module */
6164 static VALUE c_guestfs; /* guestfs_h handle */
6165 static VALUE e_Error; /* used for all errors */
6167 static void ruby_guestfs_free (void *p)
6170 guestfs_close ((guestfs_h *) p);
6173 static VALUE ruby_guestfs_create (VALUE m)
6177 g = guestfs_create ();
6179 rb_raise (e_Error, \"failed to create guestfs handle\");
6181 /* Don't print error messages to stderr by default. */
6182 guestfs_set_error_handler (g, NULL, NULL);
6184 /* Wrap it, and make sure the close function is called when the
6187 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6190 static VALUE ruby_guestfs_close (VALUE gv)
6193 Data_Get_Struct (gv, guestfs_h, g);
6195 ruby_guestfs_free (g);
6196 DATA_PTR (gv) = NULL;
6204 fun (name, style, _, _, _, _, _) ->
6205 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6206 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6209 pr " guestfs_h *g;\n";
6210 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
6212 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6218 | String n | FileIn n | FileOut n ->
6219 pr " const char *%s = StringValueCStr (%sv);\n" n n;
6221 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6222 pr " \"%s\", \"%s\");\n" n name
6224 pr " const char *%s = StringValueCStr (%sv);\n" n n
6228 pr " int i, len;\n";
6229 pr " len = RARRAY_LEN (%sv);\n" n;
6230 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6232 pr " for (i = 0; i < len; ++i) {\n";
6233 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
6234 pr " %s[i] = StringValueCStr (v);\n" n;
6236 pr " %s[len] = NULL;\n" n;
6240 pr " int %s = NUM2INT (%sv);\n" n n
6245 match fst style with
6246 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
6247 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6248 | RConstString _ -> pr " const char *r;\n"; "NULL"
6249 | RString _ -> pr " char *r;\n"; "NULL"
6250 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
6251 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
6252 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
6253 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
6254 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
6255 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
6256 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
6259 pr " r = guestfs_%s " name;
6260 generate_call_args ~handle:"g" (snd style);
6265 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6267 pr " free (%s);\n" n
6270 pr " if (r == %s)\n" error_code;
6271 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6274 (match fst style with
6276 pr " return Qnil;\n"
6277 | RInt _ | RBool _ ->
6278 pr " return INT2NUM (r);\n"
6280 pr " return ULL2NUM (r);\n"
6282 pr " return rb_str_new2 (r);\n";
6284 pr " VALUE rv = rb_str_new2 (r);\n";
6288 pr " int i, len = 0;\n";
6289 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
6290 pr " VALUE rv = rb_ary_new2 (len);\n";
6291 pr " for (i = 0; r[i] != NULL; ++i) {\n";
6292 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6293 pr " free (r[i]);\n";
6298 pr " VALUE rv = rb_ary_new2 (2);\n";
6299 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
6300 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
6301 pr " guestfs_free_int_bool (r);\n";
6304 generate_ruby_lvm_code "pv" pv_cols
6306 generate_ruby_lvm_code "vg" vg_cols
6308 generate_ruby_lvm_code "lv" lv_cols
6310 pr " VALUE rv = rb_hash_new ();\n";
6314 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6319 pr " VALUE rv = rb_hash_new ();\n";
6323 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6328 pr " VALUE rv = rb_hash_new ();\n";
6330 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
6331 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6332 pr " free (r[i]);\n";
6333 pr " free (r[i+1]);\n";
6344 /* Initialize the module. */
6345 void Init__guestfs ()
6347 m_guestfs = rb_define_module (\"Guestfs\");
6348 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6349 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6351 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6352 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6355 (* Define the rest of the methods. *)
6357 fun (name, style, _, _, _, _, _) ->
6358 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
6359 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6364 (* Ruby code to return an LVM struct list. *)
6365 and generate_ruby_lvm_code typ cols =
6366 pr " VALUE rv = rb_ary_new2 (r->len);\n";
6368 pr " for (i = 0; i < r->len; ++i) {\n";
6369 pr " VALUE hv = rb_hash_new ();\n";
6373 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
6375 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
6378 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
6379 | name, `OptPercent ->
6380 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
6382 pr " rb_ary_push (rv, hv);\n";
6384 pr " guestfs_free_lvm_%s_list (r);\n" typ;
6387 (* Generate Java bindings GuestFS.java file. *)
6388 and generate_java_java () =
6389 generate_header CStyle LGPLv2;
6392 package com.redhat.et.libguestfs;
6394 import java.util.HashMap;
6395 import com.redhat.et.libguestfs.LibGuestFSException;
6396 import com.redhat.et.libguestfs.PV;
6397 import com.redhat.et.libguestfs.VG;
6398 import com.redhat.et.libguestfs.LV;
6399 import com.redhat.et.libguestfs.Stat;
6400 import com.redhat.et.libguestfs.StatVFS;
6401 import com.redhat.et.libguestfs.IntBool;
6404 * The GuestFS object is a libguestfs handle.
6408 public class GuestFS {
6409 // Load the native code.
6411 System.loadLibrary (\"guestfs_jni\");
6415 * The native guestfs_h pointer.
6420 * Create a libguestfs handle.
6422 * @throws LibGuestFSException
6424 public GuestFS () throws LibGuestFSException
6428 private native long _create () throws LibGuestFSException;
6431 * Close a libguestfs handle.
6433 * You can also leave handles to be collected by the garbage
6434 * collector, but this method ensures that the resources used
6435 * by the handle are freed up immediately. If you call any
6436 * other methods after closing the handle, you will get an
6439 * @throws LibGuestFSException
6441 public void close () throws LibGuestFSException
6447 private native void _close (long g) throws LibGuestFSException;
6449 public void finalize () throws LibGuestFSException
6457 fun (name, style, _, flags, _, shortdesc, longdesc) ->
6458 let doc = replace_str longdesc "C<guestfs_" "C<g." in
6460 if List.mem ProtocolLimitWarning flags then
6461 doc ^ "\n\n" ^ protocol_limit_warning
6464 if List.mem DangerWillRobinson flags then
6465 doc ^ "\n\n" ^ danger_will_robinson
6467 let doc = pod2text ~width:60 name doc in
6468 let doc = String.concat "\n * " doc in
6471 pr " * %s\n" shortdesc;
6474 pr " * @throws LibGuestFSException\n";
6477 generate_java_prototype ~public:true ~semicolon:false name style;
6480 pr " if (g == 0)\n";
6481 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
6484 if fst style <> RErr then pr "return ";
6486 generate_call_args ~handle:"g" (snd style);
6490 generate_java_prototype ~privat:true ~native:true name style;
6497 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
6498 ?(semicolon=true) name style =
6499 if privat then pr "private ";
6500 if public then pr "public ";
6501 if native then pr "native ";
6504 (match fst style with
6505 | RErr -> pr "void ";
6506 | RInt _ -> pr "int ";
6507 | RInt64 _ -> pr "long ";
6508 | RBool _ -> pr "boolean ";
6509 | RConstString _ | RString _ -> pr "String ";
6510 | RStringList _ -> pr "String[] ";
6511 | RIntBool _ -> pr "IntBool ";
6512 | RPVList _ -> pr "PV[] ";
6513 | RVGList _ -> pr "VG[] ";
6514 | RLVList _ -> pr "LV[] ";
6515 | RStat _ -> pr "Stat ";
6516 | RStatVFS _ -> pr "StatVFS ";
6517 | RHashtable _ -> pr "HashMap<String,String> ";
6520 if native then pr "_%s " name else pr "%s " name;
6522 let needs_comma = ref false in
6531 if !needs_comma then pr ", ";
6532 needs_comma := true;
6549 pr " throws LibGuestFSException";
6550 if semicolon then pr ";"
6552 and generate_java_struct typ cols =
6553 generate_header CStyle LGPLv2;
6556 package com.redhat.et.libguestfs;
6559 * Libguestfs %s structure.
6570 | name, `UUID -> pr " public String %s;\n" name
6572 | name, `Int -> pr " public long %s;\n" name
6573 | name, `OptPercent ->
6574 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
6575 pr " public float %s;\n" name
6580 and generate_java_c () =
6581 generate_header CStyle LGPLv2;
6588 #include \"com_redhat_et_libguestfs_GuestFS.h\"
6589 #include \"guestfs.h\"
6591 /* Note that this function returns. The exception is not thrown
6592 * until after the wrapper function returns.
6595 throw_exception (JNIEnv *env, const char *msg)
6598 cl = (*env)->FindClass (env,
6599 \"com/redhat/et/libguestfs/LibGuestFSException\");
6600 (*env)->ThrowNew (env, cl, msg);
6603 JNIEXPORT jlong JNICALL
6604 Java_com_redhat_et_libguestfs_GuestFS__1create
6605 (JNIEnv *env, jobject obj)
6609 g = guestfs_create ();
6611 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
6614 guestfs_set_error_handler (g, NULL, NULL);
6615 return (jlong) (long) g;
6618 JNIEXPORT void JNICALL
6619 Java_com_redhat_et_libguestfs_GuestFS__1close
6620 (JNIEnv *env, jobject obj, jlong jg)
6622 guestfs_h *g = (guestfs_h *) (long) jg;
6629 fun (name, style, _, _, _, _, _) ->
6631 (match fst style with
6632 | RErr -> pr "void ";
6633 | RInt _ -> pr "jint ";
6634 | RInt64 _ -> pr "jlong ";
6635 | RBool _ -> pr "jboolean ";
6636 | RConstString _ | RString _ -> pr "jstring ";
6637 | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
6639 | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
6643 pr "Java_com_redhat_et_libguestfs_GuestFS_";
6644 pr "%s" (replace_str ("_" ^ name) "_" "_1");
6646 pr " (JNIEnv *env, jobject obj, jlong jg";
6653 pr ", jstring j%s" n
6655 pr ", jobjectArray j%s" n
6657 pr ", jboolean j%s" n
6663 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
6664 let error_code, no_ret =
6665 match fst style with
6666 | RErr -> pr " int r;\n"; "-1", ""
6668 | RInt _ -> pr " int r;\n"; "-1", "0"
6669 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
6670 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
6672 pr " jstring jr;\n";
6673 pr " char *r;\n"; "NULL", "NULL"
6675 pr " jobjectArray jr;\n";
6678 pr " jstring jstr;\n";
6679 pr " char **r;\n"; "NULL", "NULL"
6681 pr " jobject jr;\n";
6683 pr " jfieldID fl;\n";
6684 pr " struct guestfs_int_bool *r;\n"; "NULL", "NULL"
6686 pr " jobject jr;\n";
6688 pr " jfieldID fl;\n";
6689 pr " struct guestfs_stat *r;\n"; "NULL", "NULL"
6691 pr " jobject jr;\n";
6693 pr " jfieldID fl;\n";
6694 pr " struct guestfs_statvfs *r;\n"; "NULL", "NULL"
6696 pr " jobjectArray jr;\n";
6698 pr " jfieldID fl;\n";
6699 pr " jobject jfl;\n";
6700 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
6702 pr " jobjectArray jr;\n";
6704 pr " jfieldID fl;\n";
6705 pr " jobject jfl;\n";
6706 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
6708 pr " jobjectArray jr;\n";
6710 pr " jfieldID fl;\n";
6711 pr " jobject jfl;\n";
6712 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
6713 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
6720 pr " const char *%s;\n" n
6722 pr " int %s_len;\n" n;
6723 pr " const char **%s;\n" n
6730 (match fst style with
6731 | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
6732 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
6733 | RString _ | RIntBool _ | RStat _ | RStatVFS _
6734 | RHashtable _ -> false) ||
6735 List.exists (function StringList _ -> true | _ -> false) (snd style) in
6741 (* Get the parameters. *)
6748 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
6750 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
6751 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
6752 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6753 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6755 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
6757 pr " %s[%s_len] = NULL;\n" n n;
6760 pr " %s = j%s;\n" n n
6763 (* Make the call. *)
6764 pr " r = guestfs_%s " name;
6765 generate_call_args ~handle:"g" (snd style);
6768 (* Release the parameters. *)
6775 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
6777 pr " for (i = 0; i < %s_len; ++i) {\n" n;
6778 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
6780 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
6782 pr " free (%s);\n" n
6787 (* Check for errors. *)
6788 pr " if (r == %s) {\n" error_code;
6789 pr " throw_exception (env, guestfs_last_error (g));\n";
6790 pr " return %s;\n" no_ret;
6794 (match fst style with
6796 | RInt _ -> pr " return (jint) r;\n"
6797 | RBool _ -> pr " return (jboolean) r;\n"
6798 | RInt64 _ -> pr " return (jlong) r;\n"
6799 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
6801 pr " jr = (*env)->NewStringUTF (env, r);\n";
6805 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
6806 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
6807 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
6808 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
6809 pr " for (i = 0; i < r_len; ++i) {\n";
6810 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
6811 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
6812 pr " free (r[i]);\n";
6817 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
6818 pr " jr = (*env)->AllocObject (env, cl);\n";
6819 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
6820 pr " (*env)->SetIntField (env, jr, fl, r->i);\n";
6821 pr " fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
6822 pr " (*env)->SetBooleanField (env, jr, fl, r->b);\n";
6823 pr " guestfs_free_int_bool (r);\n";
6826 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
6827 pr " jr = (*env)->AllocObject (env, cl);\n";
6831 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
6833 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
6838 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
6839 pr " jr = (*env)->AllocObject (env, cl);\n";
6843 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
6845 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
6850 generate_java_lvm_return "pv" "PV" pv_cols
6852 generate_java_lvm_return "vg" "VG" vg_cols
6854 generate_java_lvm_return "lv" "LV" lv_cols
6857 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
6858 pr " return NULL;\n"
6865 and generate_java_lvm_return typ jtyp cols =
6866 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
6867 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
6868 pr " for (i = 0; i < r->len; ++i) {\n";
6869 pr " jfl = (*env)->AllocObject (env, cl);\n";
6873 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
6874 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
6877 pr " char s[33];\n";
6878 pr " memcpy (s, r->val[i].%s, 32);\n" name;
6880 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
6881 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
6883 | name, (`Bytes|`Int) ->
6884 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
6885 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
6886 | name, `OptPercent ->
6887 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
6888 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
6890 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
6892 pr " guestfs_free_lvm_%s_list (r);\n" typ;
6895 and generate_haskell_hs () =
6896 generate_header HaskellStyle LGPLv2;
6898 (* XXX We only know how to generate partial FFI for Haskell
6899 * at the moment. Please help out!
6901 let can_generate style =
6902 let check_no_bad_args =
6903 List.for_all (function Bool _ | Int _ -> false | _ -> true)
6906 | RErr, args -> check_no_bad_args args
6919 | RHashtable _, _ -> false in
6922 {-# INCLUDE <guestfs.h> #-}
6923 {-# LANGUAGE ForeignFunctionInterface #-}
6928 (* List out the names of the actions we want to export. *)
6930 fun (name, style, _, _, _, _, _) ->
6931 if can_generate style then pr ",\n %s" name
6939 import Control.Exception
6940 import Data.Typeable
6942 data GuestfsS = GuestfsS -- represents the opaque C struct
6943 type GuestfsP = Ptr GuestfsS -- guestfs_h *
6944 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
6946 -- XXX define properly later XXX
6950 data IntBool = IntBool
6952 data StatVFS = StatVFS
6953 data Hashtable = Hashtable
6955 foreign import ccall unsafe \"guestfs_create\" c_create
6957 foreign import ccall unsafe \"&guestfs_close\" c_close
6958 :: FunPtr (GuestfsP -> IO ())
6959 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
6960 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
6962 create :: IO GuestfsH
6965 c_set_error_handler p nullPtr nullPtr
6966 h <- newForeignPtr c_close p
6969 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
6970 :: GuestfsP -> IO CString
6972 -- last_error :: GuestfsH -> IO (Maybe String)
6973 -- last_error h = do
6974 -- str <- withForeignPtr h (\\p -> c_last_error p)
6975 -- maybePeek peekCString str
6977 last_error :: GuestfsH -> IO (String)
6979 str <- withForeignPtr h (\\p -> c_last_error p)
6981 then return \"no error\"
6982 else peekCString str
6986 (* Generate wrappers for each foreign function. *)
6988 fun (name, style, _, _, _, _, _) ->
6989 if can_generate style then (
6990 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
6992 generate_haskell_prototype ~handle:"GuestfsP" style;
6996 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
6998 pr "%s %s = do\n" name
6999 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7005 | String n -> pr "withCString %s $ \\%s -> " n n
7006 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7007 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7009 (* XXX this doesn't work *)
7011 pr " %s = case %s of\n" n n;
7014 pr " in fromIntegral %s $ \\%s ->\n" n n
7015 | Int n -> pr "fromIntegral %s $ \\%s -> " n n
7017 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7018 (String.concat " " ("p" :: List.map name_of_argt (snd style)));
7019 (match fst style with
7020 | RErr | RInt _ | RInt64 _ | RBool _ ->
7021 pr " if (r == -1)\n";
7023 pr " err <- last_error h\n";
7025 | RConstString _ | RString _ | RStringList _ | RIntBool _
7026 | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7028 pr " if (r == nullPtr)\n";
7030 pr " err <- last_error h\n";
7033 (match fst style with
7035 pr " else return ()\n"
7037 pr " else return (fromIntegral r)\n"
7039 pr " else return (fromIntegral r)\n"
7041 pr " else return (toBool r)\n"
7052 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7058 and generate_haskell_prototype ~handle ?(hs = false) style =
7060 let string = if hs then "String" else "CString" in
7061 let int = if hs then "Int" else "CInt" in
7062 let bool = if hs then "Bool" else "CInt" in
7063 let int64 = if hs then "Integer" else "Int64" in
7067 | String _ -> pr "%s" string
7068 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7069 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7070 | Bool _ -> pr "%s" bool
7071 | Int _ -> pr "%s" int
7072 | FileIn _ -> pr "%s" string
7073 | FileOut _ -> pr "%s" string
7078 (match fst style with
7079 | RErr -> if not hs then pr "CInt"
7080 | RInt _ -> pr "%s" int
7081 | RInt64 _ -> pr "%s" int64
7082 | RBool _ -> pr "%s" bool
7083 | RConstString _ -> pr "%s" string
7084 | RString _ -> pr "%s" string
7085 | RStringList _ -> pr "[%s]" string
7086 | RIntBool _ -> pr "IntBool"
7087 | RPVList _ -> pr "[PV]"
7088 | RVGList _ -> pr "[VG]"
7089 | RLVList _ -> pr "[LV]"
7090 | RStat _ -> pr "Stat"
7091 | RStatVFS _ -> pr "StatVFS"
7092 | RHashtable _ -> pr "Hashtable"
7096 let output_to filename =
7097 let filename_new = filename ^ ".new" in
7098 chan := open_out filename_new;
7103 (* Is the new file different from the current file? *)
7104 if Sys.file_exists filename && files_equal filename filename_new then
7105 Unix.unlink filename_new (* same, so skip it *)
7107 (* different, overwrite old one *)
7108 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
7109 Unix.rename filename_new filename;
7110 Unix.chmod filename 0o444;
7111 printf "written %s\n%!" filename;
7120 if not (Sys.file_exists "configure.ac") then (
7122 You are probably running this from the wrong directory.
7123 Run it from the top source directory using the command
7129 let close = output_to "src/guestfs_protocol.x" in
7133 let close = output_to "src/guestfs-structs.h" in
7134 generate_structs_h ();
7137 let close = output_to "src/guestfs-actions.h" in
7138 generate_actions_h ();
7141 let close = output_to "src/guestfs-actions.c" in
7142 generate_client_actions ();
7145 let close = output_to "daemon/actions.h" in
7146 generate_daemon_actions_h ();
7149 let close = output_to "daemon/stubs.c" in
7150 generate_daemon_actions ();
7153 let close = output_to "tests.c" in
7157 let close = output_to "fish/cmds.c" in
7158 generate_fish_cmds ();
7161 let close = output_to "fish/completion.c" in
7162 generate_fish_completion ();
7165 let close = output_to "guestfs-structs.pod" in
7166 generate_structs_pod ();
7169 let close = output_to "guestfs-actions.pod" in
7170 generate_actions_pod ();
7173 let close = output_to "guestfish-actions.pod" in
7174 generate_fish_actions_pod ();
7177 let close = output_to "ocaml/guestfs.mli" in
7178 generate_ocaml_mli ();
7181 let close = output_to "ocaml/guestfs.ml" in
7182 generate_ocaml_ml ();
7185 let close = output_to "ocaml/guestfs_c_actions.c" in
7186 generate_ocaml_c ();
7189 let close = output_to "perl/Guestfs.xs" in
7190 generate_perl_xs ();
7193 let close = output_to "perl/lib/Sys/Guestfs.pm" in
7194 generate_perl_pm ();
7197 let close = output_to "python/guestfs-py.c" in
7198 generate_python_c ();
7201 let close = output_to "python/guestfs.py" in
7202 generate_python_py ();
7205 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
7209 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
7210 generate_java_java ();
7213 let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
7214 generate_java_struct "PV" pv_cols;
7217 let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
7218 generate_java_struct "VG" vg_cols;
7221 let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
7222 generate_java_struct "LV" lv_cols;
7225 let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
7226 generate_java_struct "Stat" stat_cols;
7229 let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
7230 generate_java_struct "StatVFS" statvfs_cols;
7233 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
7237 let close = output_to "haskell/Guestfs.hs" in
7238 generate_haskell_hs ();