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]
39 type style = ret * args
41 (* "RErr" as a return value means an int used as a simple error
42 * indication, ie. 0 or -1.
45 (* "RInt" as a return value means an int which is -1 for error
46 * or any value >= 0 on success. Only use this for smallish
47 * positive ints (0 <= i < 2^30).
50 (* "RInt64" is the same as RInt, but is guaranteed to be able
51 * to return a full 64 bit value, _except_ that -1 means error
52 * (so -1 cannot be a valid, non-error return value).
55 (* "RBool" is a bool return value which can be true/false or
59 (* "RConstString" is a string that refers to a constant value.
60 * Try to avoid using this. In particular you cannot use this
61 * for values returned from the daemon, because there is no
62 * thread-safe way to return them in the C API.
64 | RConstString of string
65 (* "RString" and "RStringList" are caller-frees. *)
67 | RStringList of string
68 (* Some limited tuples are possible: *)
69 | RIntBool of string * string
70 (* LVM PVs, VGs and LVs. *)
77 (* Key-value pairs of untyped strings. Turns into a hashtable or
78 * dictionary in languages which support it. DON'T use this as a
79 * general "bucket" for results. Prefer a stronger typed return
80 * value if one is available, or write a custom struct. Don't use
81 * this if the list could potentially be very long, since it is
82 * inefficient. Keys should be unique. NULLs are not permitted.
84 | RHashtable of string
86 and args = argt list (* Function parameters, guestfs handle is implicit. *)
88 (* Note in future we should allow a "variable args" parameter as
89 * the final parameter, to allow commands like
90 * chmod mode file [file(s)...]
91 * This is not implemented yet, but many commands (such as chmod)
92 * are currently defined with the argument order keeping this future
93 * possibility in mind.
96 | String of string (* const char *name, cannot be NULL *)
97 | OptString of string (* const char *name, may be NULL *)
98 | StringList of string(* list of strings (each string cannot be NULL) *)
99 | Bool of string (* boolean *)
100 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
101 (* These are treated as filenames (simple string parameters) in
102 * the C API and bindings. But in the RPC protocol, we transfer
103 * the actual file content up to or down from the daemon.
104 * FileIn: local machine -> daemon (in request)
105 * FileOut: daemon -> local machine (in reply)
106 * In guestfish (only), the special name "-" means read from
107 * stdin or write to stdout.
113 | ProtocolLimitWarning (* display warning about protocol size limits *)
114 | DangerWillRobinson (* flags particularly dangerous commands *)
115 | FishAlias of string (* provide an alias for this cmd in guestfish *)
116 | FishAction of string (* call this function in guestfish *)
117 | NotInFish (* do not export via guestfish *)
119 let protocol_limit_warning =
120 "Because of the message protocol, there is a transfer limit
121 of somewhere between 2MB and 4MB. To transfer large files you should use
124 let danger_will_robinson =
125 "B<This command is dangerous. Without careful use you
126 can easily destroy all your data>."
128 (* You can supply zero or as many tests as you want per API call.
130 * Note that the test environment has 3 block devices, of size 500MB,
131 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc).
132 * Note for partitioning purposes, the 500MB device has 63 cylinders.
134 * To be able to run the tests in a reasonable amount of time,
135 * the virtual machine and block devices are reused between tests.
136 * So don't try testing kill_subprocess :-x
138 * Between each test we umount-all and lvm-remove-all (except InitNone).
140 * Don't assume anything about the previous contents of the block
141 * devices. Use 'Init*' to create some initial scenarios.
143 type tests = (test_init * test) list
145 (* Run the command sequence and just expect nothing to fail. *)
147 (* Run the command sequence and expect the output of the final
148 * command to be the string.
150 | TestOutput of seq * string
151 (* Run the command sequence and expect the output of the final
152 * command to be the list of strings.
154 | TestOutputList of seq * string list
155 (* Run the command sequence and expect the output of the final
156 * command to be the integer.
158 | TestOutputInt of seq * int
159 (* Run the command sequence and expect the output of the final
160 * command to be a true value (!= 0 or != NULL).
162 | TestOutputTrue of seq
163 (* Run the command sequence and expect the output of the final
164 * command to be a false value (== 0 or == NULL, but not an error).
166 | TestOutputFalse of seq
167 (* Run the command sequence and expect the output of the final
168 * command to be a list of the given length (but don't care about
171 | TestOutputLength of seq * int
172 (* Run the command sequence and expect the output of the final
173 * command to be a structure.
175 | TestOutputStruct of seq * test_field_compare list
176 (* Run the command sequence and expect the final command (only)
179 | TestLastFail of seq
181 and test_field_compare =
182 | CompareWithInt of string * int
183 | CompareWithString of string * string
184 | CompareFieldsIntEq of string * string
185 | CompareFieldsStrEq of string * string
187 (* Some initial scenarios for testing. *)
189 (* Do nothing, block devices could contain random stuff including
190 * LVM PVs, and some filesystems might be mounted. This is usually
194 (* Block devices are empty and no filesystems are mounted. *)
196 (* /dev/sda contains a single partition /dev/sda1, which is formatted
197 * as ext2, empty [except for lost+found] and mounted on /.
198 * /dev/sdb and /dev/sdc may have random content.
203 * /dev/sda1 (is a PV):
204 * /dev/VG/LV (size 8MB):
205 * formatted as ext2, empty [except for lost+found], mounted on /
206 * /dev/sdb and /dev/sdc may have random content.
210 (* Sequence of commands for testing. *)
212 and cmd = string list
214 (* Note about long descriptions: When referring to another
215 * action, use the format C<guestfs_other> (ie. the full name of
216 * the C function). This will be replaced as appropriate in other
219 * Apart from that, long descriptions are just perldoc paragraphs.
222 let non_daemon_functions = [
223 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
225 "launch the qemu subprocess",
227 Internally libguestfs is implemented by running a virtual machine
230 You should call this after configuring the handle
231 (eg. adding drives) but before performing any actions.");
233 ("wait_ready", (RErr, []), -1, [NotInFish],
235 "wait until the qemu subprocess launches",
237 Internally libguestfs is implemented by running a virtual machine
240 You should call this after C<guestfs_launch> to wait for the launch
243 ("kill_subprocess", (RErr, []), -1, [],
245 "kill the qemu subprocess",
247 This kills the qemu subprocess. You should never need to call this.");
249 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
251 "add an image to examine or modify",
253 This function adds a virtual machine disk image C<filename> to the
254 guest. The first time you call this function, the disk appears as IDE
255 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
258 You don't necessarily need to be root when using libguestfs. However
259 you obviously do need sufficient permissions to access the filename
260 for whatever operations you want to perform (ie. read access if you
261 just want to read the image or write access if you want to modify the
264 This is equivalent to the qemu parameter C<-drive file=filename>.");
266 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
268 "add a CD-ROM disk image to examine",
270 This function adds a virtual CD-ROM disk image to the guest.
272 This is equivalent to the qemu parameter C<-cdrom filename>.");
274 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
276 "add qemu parameters",
278 This can be used to add arbitrary qemu command line parameters
279 of the form C<-param value>. Actually it's not quite arbitrary - we
280 prevent you from setting some parameters which would interfere with
281 parameters that we use.
283 The first character of C<param> string must be a C<-> (dash).
285 C<value> can be NULL.");
287 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
289 "set the search path",
291 Set the path that libguestfs searches for kernel and initrd.img.
293 The default is C<$libdir/guestfs> unless overridden by setting
294 C<LIBGUESTFS_PATH> environment variable.
296 The string C<path> is stashed in the libguestfs handle, so the caller
297 must make sure it remains valid for the lifetime of the handle.
299 Setting C<path> to C<NULL> restores the default path.");
301 ("get_path", (RConstString "path", []), -1, [],
303 "get the search path",
305 Return the current search path.
307 This is always non-NULL. If it wasn't set already, then this will
308 return the default path.");
310 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
314 If C<autosync> is true, this enables autosync. Libguestfs will make a
315 best effort attempt to run C<guestfs_sync> when the handle is closed
316 (also if the program exits without closing handles).");
318 ("get_autosync", (RBool "autosync", []), -1, [],
322 Get the autosync flag.");
324 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
328 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
330 Verbose messages are disabled unless the environment variable
331 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
333 ("get_verbose", (RBool "verbose", []), -1, [],
337 This returns the verbose messages flag.");
339 ("is_ready", (RBool "ready", []), -1, [],
341 "is ready to accept commands",
343 This returns true iff this handle is ready to accept commands
344 (in the C<READY> state).
346 For more information on states, see L<guestfs(3)>.");
348 ("is_config", (RBool "config", []), -1, [],
350 "is in configuration state",
352 This returns true iff this handle is being configured
353 (in the C<CONFIG> state).
355 For more information on states, see L<guestfs(3)>.");
357 ("is_launching", (RBool "launching", []), -1, [],
359 "is launching subprocess",
361 This returns true iff this handle is launching the subprocess
362 (in the C<LAUNCHING> state).
364 For more information on states, see L<guestfs(3)>.");
366 ("is_busy", (RBool "busy", []), -1, [],
368 "is busy processing a command",
370 This returns true iff this handle is busy processing a command
371 (in the C<BUSY> state).
373 For more information on states, see L<guestfs(3)>.");
375 ("get_state", (RInt "state", []), -1, [],
377 "get the current state",
379 This returns the current state as an opaque integer. This is
380 only useful for printing debug and internal error messages.
382 For more information on states, see L<guestfs(3)>.");
384 ("set_busy", (RErr, []), -1, [NotInFish],
388 This sets the state to C<BUSY>. This is only used when implementing
389 actions using the low-level API.
391 For more information on states, see L<guestfs(3)>.");
393 ("set_ready", (RErr, []), -1, [NotInFish],
395 "set state to ready",
397 This sets the state to C<READY>. This is only used when implementing
398 actions using the low-level API.
400 For more information on states, see L<guestfs(3)>.");
404 let daemon_functions = [
405 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
406 [InitEmpty, TestOutput (
407 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
408 ["mkfs"; "ext2"; "/dev/sda1"];
409 ["mount"; "/dev/sda1"; "/"];
410 ["write_file"; "/new"; "new file contents"; "0"];
411 ["cat"; "/new"]], "new file contents")],
412 "mount a guest disk at a position in the filesystem",
414 Mount a guest disk at a position in the filesystem. Block devices
415 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
416 the guest. If those block devices contain partitions, they will have
417 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
420 The rules are the same as for L<mount(2)>: A filesystem must
421 first be mounted on C</> before others can be mounted. Other
422 filesystems can only be mounted on directories which already
425 The mounted filesystem is writable, if we have sufficient permissions
426 on the underlying device.
428 The filesystem options C<sync> and C<noatime> are set with this
429 call, in order to improve reliability.");
431 ("sync", (RErr, []), 2, [],
432 [ InitEmpty, TestRun [["sync"]]],
433 "sync disks, writes are flushed through to the disk image",
435 This syncs the disk, so that any writes are flushed through to the
436 underlying disk image.
438 You should always call this if you have modified a disk image, before
439 closing the handle.");
441 ("touch", (RErr, [String "path"]), 3, [],
442 [InitBasicFS, TestOutputTrue (
444 ["exists"; "/new"]])],
445 "update file timestamps or create a new file",
447 Touch acts like the L<touch(1)> command. It can be used to
448 update the timestamps on a file, or, if the file does not exist,
449 to create a new zero-length file.");
451 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
452 [InitBasicFS, TestOutput (
453 [["write_file"; "/new"; "new file contents"; "0"];
454 ["cat"; "/new"]], "new file contents")],
455 "list the contents of a file",
457 Return the contents of the file named C<path>.
459 Note that this function cannot correctly handle binary files
460 (specifically, files containing C<\\0> character which is treated
461 as end of string). For those you need to use the C<guestfs_download>
462 function which has a more complex interface.");
464 ("ll", (RString "listing", [String "directory"]), 5, [],
465 [], (* XXX Tricky to test because it depends on the exact format
466 * of the 'ls -l' command, which changes between F10 and F11.
468 "list the files in a directory (long format)",
470 List the files in C<directory> (relative to the root directory,
471 there is no cwd) in the format of 'ls -la'.
473 This command is mostly useful for interactive sessions. It
474 is I<not> intended that you try to parse the output string.");
476 ("ls", (RStringList "listing", [String "directory"]), 6, [],
477 [InitBasicFS, TestOutputList (
480 ["touch"; "/newest"];
481 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
482 "list the files in a directory",
484 List the files in C<directory> (relative to the root directory,
485 there is no cwd). The '.' and '..' entries are not returned, but
486 hidden files are shown.
488 This command is mostly useful for interactive sessions. Programs
489 should probably use C<guestfs_readdir> instead.");
491 ("list_devices", (RStringList "devices", []), 7, [],
492 [InitEmpty, TestOutputList (
493 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
494 "list the block devices",
496 List all the block devices.
498 The full block device names are returned, eg. C</dev/sda>");
500 ("list_partitions", (RStringList "partitions", []), 8, [],
501 [InitBasicFS, TestOutputList (
502 [["list_partitions"]], ["/dev/sda1"]);
503 InitEmpty, TestOutputList (
504 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
505 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
506 "list the partitions",
508 List all the partitions detected on all block devices.
510 The full partition device names are returned, eg. C</dev/sda1>
512 This does not return logical volumes. For that you will need to
513 call C<guestfs_lvs>.");
515 ("pvs", (RStringList "physvols", []), 9, [],
516 [InitBasicFSonLVM, TestOutputList (
517 [["pvs"]], ["/dev/sda1"]);
518 InitEmpty, TestOutputList (
519 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
520 ["pvcreate"; "/dev/sda1"];
521 ["pvcreate"; "/dev/sda2"];
522 ["pvcreate"; "/dev/sda3"];
523 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
524 "list the LVM physical volumes (PVs)",
526 List all the physical volumes detected. This is the equivalent
527 of the L<pvs(8)> command.
529 This returns a list of just the device names that contain
530 PVs (eg. C</dev/sda2>).
532 See also C<guestfs_pvs_full>.");
534 ("vgs", (RStringList "volgroups", []), 10, [],
535 [InitBasicFSonLVM, TestOutputList (
537 InitEmpty, TestOutputList (
538 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
539 ["pvcreate"; "/dev/sda1"];
540 ["pvcreate"; "/dev/sda2"];
541 ["pvcreate"; "/dev/sda3"];
542 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
543 ["vgcreate"; "VG2"; "/dev/sda3"];
544 ["vgs"]], ["VG1"; "VG2"])],
545 "list the LVM volume groups (VGs)",
547 List all the volumes groups detected. This is the equivalent
548 of the L<vgs(8)> command.
550 This returns a list of just the volume group names that were
551 detected (eg. C<VolGroup00>).
553 See also C<guestfs_vgs_full>.");
555 ("lvs", (RStringList "logvols", []), 11, [],
556 [InitBasicFSonLVM, TestOutputList (
557 [["lvs"]], ["/dev/VG/LV"]);
558 InitEmpty, TestOutputList (
559 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
560 ["pvcreate"; "/dev/sda1"];
561 ["pvcreate"; "/dev/sda2"];
562 ["pvcreate"; "/dev/sda3"];
563 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
564 ["vgcreate"; "VG2"; "/dev/sda3"];
565 ["lvcreate"; "LV1"; "VG1"; "50"];
566 ["lvcreate"; "LV2"; "VG1"; "50"];
567 ["lvcreate"; "LV3"; "VG2"; "50"];
568 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
569 "list the LVM logical volumes (LVs)",
571 List all the logical volumes detected. This is the equivalent
572 of the L<lvs(8)> command.
574 This returns a list of the logical volume device names
575 (eg. C</dev/VolGroup00/LogVol00>).
577 See also C<guestfs_lvs_full>.");
579 ("pvs_full", (RPVList "physvols", []), 12, [],
580 [], (* XXX how to test? *)
581 "list the LVM physical volumes (PVs)",
583 List all the physical volumes detected. This is the equivalent
584 of the L<pvs(8)> command. The \"full\" version includes all fields.");
586 ("vgs_full", (RVGList "volgroups", []), 13, [],
587 [], (* XXX how to test? *)
588 "list the LVM volume groups (VGs)",
590 List all the volumes groups detected. This is the equivalent
591 of the L<vgs(8)> command. The \"full\" version includes all fields.");
593 ("lvs_full", (RLVList "logvols", []), 14, [],
594 [], (* XXX how to test? *)
595 "list the LVM logical volumes (LVs)",
597 List all the logical volumes detected. This is the equivalent
598 of the L<lvs(8)> command. The \"full\" version includes all fields.");
600 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
601 [InitBasicFS, TestOutputList (
602 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
603 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
604 InitBasicFS, TestOutputList (
605 [["write_file"; "/new"; ""; "0"];
606 ["read_lines"; "/new"]], [])],
607 "read file as lines",
609 Return the contents of the file named C<path>.
611 The file contents are returned as a list of lines. Trailing
612 C<LF> and C<CRLF> character sequences are I<not> returned.
614 Note that this function cannot correctly handle binary files
615 (specifically, files containing C<\\0> character which is treated
616 as end of line). For those you need to use the C<guestfs_read_file>
617 function which has a more complex interface.");
619 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
620 [], (* XXX Augeas code needs tests. *)
621 "create a new Augeas handle",
623 Create a new Augeas handle for editing configuration files.
624 If there was any previous Augeas handle associated with this
625 guestfs session, then it is closed.
627 You must call this before using any other C<guestfs_aug_*>
630 C<root> is the filesystem root. C<root> must not be NULL,
633 The flags are the same as the flags defined in
634 E<lt>augeas.hE<gt>, the logical I<or> of the following
639 =item C<AUG_SAVE_BACKUP> = 1
641 Keep the original file with a C<.augsave> extension.
643 =item C<AUG_SAVE_NEWFILE> = 2
645 Save changes into a file with extension C<.augnew>, and
646 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
648 =item C<AUG_TYPE_CHECK> = 4
650 Typecheck lenses (can be expensive).
652 =item C<AUG_NO_STDINC> = 8
654 Do not use standard load path for modules.
656 =item C<AUG_SAVE_NOOP> = 16
658 Make save a no-op, just record what would have been changed.
660 =item C<AUG_NO_LOAD> = 32
662 Do not load the tree in C<guestfs_aug_init>.
666 To close the handle, you can call C<guestfs_aug_close>.
668 To find out more about Augeas, see L<http://augeas.net/>.");
670 ("aug_close", (RErr, []), 26, [],
671 [], (* XXX Augeas code needs tests. *)
672 "close the current Augeas handle",
674 Close the current Augeas handle and free up any resources
675 used by it. After calling this, you have to call
676 C<guestfs_aug_init> again before you can use any other
679 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
680 [], (* XXX Augeas code needs tests. *)
681 "define an Augeas variable",
683 Defines an Augeas variable C<name> whose value is the result
684 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
687 On success this returns the number of nodes in C<expr>, or
688 C<0> if C<expr> evaluates to something which is not a nodeset.");
690 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
691 [], (* XXX Augeas code needs tests. *)
692 "define an Augeas node",
694 Defines a variable C<name> whose value is the result of
697 If C<expr> evaluates to an empty nodeset, a node is created,
698 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
699 C<name> will be the nodeset containing that single node.
701 On success this returns a pair containing the
702 number of nodes in the nodeset, and a boolean flag
703 if a node was created.");
705 ("aug_get", (RString "val", [String "path"]), 19, [],
706 [], (* XXX Augeas code needs tests. *)
707 "look up the value of an Augeas path",
709 Look up the value associated with C<path>. If C<path>
710 matches exactly one node, the C<value> is returned.");
712 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
713 [], (* XXX Augeas code needs tests. *)
714 "set Augeas path to value",
716 Set the value associated with C<path> to C<value>.");
718 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
719 [], (* XXX Augeas code needs tests. *)
720 "insert a sibling Augeas node",
722 Create a new sibling C<label> for C<path>, inserting it into
723 the tree before or after C<path> (depending on the boolean
726 C<path> must match exactly one existing node in the tree, and
727 C<label> must be a label, ie. not contain C</>, C<*> or end
728 with a bracketed index C<[N]>.");
730 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
731 [], (* XXX Augeas code needs tests. *)
732 "remove an Augeas path",
734 Remove C<path> and all of its children.
736 On success this returns the number of entries which were removed.");
738 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
739 [], (* XXX Augeas code needs tests. *)
742 Move the node C<src> to C<dest>. C<src> must match exactly
743 one node. C<dest> is overwritten if it exists.");
745 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
746 [], (* XXX Augeas code needs tests. *)
747 "return Augeas nodes which match path",
749 Returns a list of paths which match the path expression C<path>.
750 The returned paths are sufficiently qualified so that they match
751 exactly one node in the current tree.");
753 ("aug_save", (RErr, []), 25, [],
754 [], (* XXX Augeas code needs tests. *)
755 "write all pending Augeas changes to disk",
757 This writes all pending changes to disk.
759 The flags which were passed to C<guestfs_aug_init> affect exactly
760 how files are saved.");
762 ("aug_load", (RErr, []), 27, [],
763 [], (* XXX Augeas code needs tests. *)
764 "load files into the tree",
766 Load files into the tree.
768 See C<aug_load> in the Augeas documentation for the full gory
771 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
772 [], (* XXX Augeas code needs tests. *)
773 "list Augeas nodes under a path",
775 This is just a shortcut for listing C<guestfs_aug_match>
776 C<path/*> and sorting the resulting nodes into alphabetical order.");
778 ("rm", (RErr, [String "path"]), 29, [],
779 [InitBasicFS, TestRun
782 InitBasicFS, TestLastFail
784 InitBasicFS, TestLastFail
789 Remove the single file C<path>.");
791 ("rmdir", (RErr, [String "path"]), 30, [],
792 [InitBasicFS, TestRun
795 InitBasicFS, TestLastFail
797 InitBasicFS, TestLastFail
800 "remove a directory",
802 Remove the single directory C<path>.");
804 ("rm_rf", (RErr, [String "path"]), 31, [],
805 [InitBasicFS, TestOutputFalse
807 ["mkdir"; "/new/foo"];
808 ["touch"; "/new/foo/bar"];
810 ["exists"; "/new"]]],
811 "remove a file or directory recursively",
813 Remove the file or directory C<path>, recursively removing the
814 contents if its a directory. This is like the C<rm -rf> shell
817 ("mkdir", (RErr, [String "path"]), 32, [],
818 [InitBasicFS, TestOutputTrue
821 InitBasicFS, TestLastFail
822 [["mkdir"; "/new/foo/bar"]]],
823 "create a directory",
825 Create a directory named C<path>.");
827 ("mkdir_p", (RErr, [String "path"]), 33, [],
828 [InitBasicFS, TestOutputTrue
829 [["mkdir_p"; "/new/foo/bar"];
830 ["is_dir"; "/new/foo/bar"]];
831 InitBasicFS, TestOutputTrue
832 [["mkdir_p"; "/new/foo/bar"];
833 ["is_dir"; "/new/foo"]];
834 InitBasicFS, TestOutputTrue
835 [["mkdir_p"; "/new/foo/bar"];
836 ["is_dir"; "/new"]]],
837 "create a directory and parents",
839 Create a directory named C<path>, creating any parent directories
840 as necessary. This is like the C<mkdir -p> shell command.");
842 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
843 [], (* XXX Need stat command to test *)
846 Change the mode (permissions) of C<path> to C<mode>. Only
847 numeric modes are supported.");
849 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
850 [], (* XXX Need stat command to test *)
851 "change file owner and group",
853 Change the file owner to C<owner> and group to C<group>.
855 Only numeric uid and gid are supported. If you want to use
856 names, you will need to locate and parse the password file
857 yourself (Augeas support makes this relatively easy).");
859 ("exists", (RBool "existsflag", [String "path"]), 36, [],
860 [InitBasicFS, TestOutputTrue (
862 ["exists"; "/new"]]);
863 InitBasicFS, TestOutputTrue (
865 ["exists"; "/new"]])],
866 "test if file or directory exists",
868 This returns C<true> if and only if there is a file, directory
869 (or anything) with the given C<path> name.
871 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
873 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
874 [InitBasicFS, TestOutputTrue (
876 ["is_file"; "/new"]]);
877 InitBasicFS, TestOutputFalse (
879 ["is_file"; "/new"]])],
880 "test if file exists",
882 This returns C<true> if and only if there is a file
883 with the given C<path> name. Note that it returns false for
884 other objects like directories.
886 See also C<guestfs_stat>.");
888 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
889 [InitBasicFS, TestOutputFalse (
891 ["is_dir"; "/new"]]);
892 InitBasicFS, TestOutputTrue (
894 ["is_dir"; "/new"]])],
895 "test if file exists",
897 This returns C<true> if and only if there is a directory
898 with the given C<path> name. Note that it returns false for
899 other objects like files.
901 See also C<guestfs_stat>.");
903 ("pvcreate", (RErr, [String "device"]), 39, [],
904 [InitEmpty, TestOutputList (
905 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
906 ["pvcreate"; "/dev/sda1"];
907 ["pvcreate"; "/dev/sda2"];
908 ["pvcreate"; "/dev/sda3"];
909 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
910 "create an LVM physical volume",
912 This creates an LVM physical volume on the named C<device>,
913 where C<device> should usually be a partition name such
916 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
917 [InitEmpty, TestOutputList (
918 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
919 ["pvcreate"; "/dev/sda1"];
920 ["pvcreate"; "/dev/sda2"];
921 ["pvcreate"; "/dev/sda3"];
922 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
923 ["vgcreate"; "VG2"; "/dev/sda3"];
924 ["vgs"]], ["VG1"; "VG2"])],
925 "create an LVM volume group",
927 This creates an LVM volume group called C<volgroup>
928 from the non-empty list of physical volumes C<physvols>.");
930 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
931 [InitEmpty, TestOutputList (
932 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
933 ["pvcreate"; "/dev/sda1"];
934 ["pvcreate"; "/dev/sda2"];
935 ["pvcreate"; "/dev/sda3"];
936 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
937 ["vgcreate"; "VG2"; "/dev/sda3"];
938 ["lvcreate"; "LV1"; "VG1"; "50"];
939 ["lvcreate"; "LV2"; "VG1"; "50"];
940 ["lvcreate"; "LV3"; "VG2"; "50"];
941 ["lvcreate"; "LV4"; "VG2"; "50"];
942 ["lvcreate"; "LV5"; "VG2"; "50"];
944 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
945 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
946 "create an LVM volume group",
948 This creates an LVM volume group called C<logvol>
949 on the volume group C<volgroup>, with C<size> megabytes.");
951 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
952 [InitEmpty, TestOutput (
953 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
954 ["mkfs"; "ext2"; "/dev/sda1"];
955 ["mount"; "/dev/sda1"; "/"];
956 ["write_file"; "/new"; "new file contents"; "0"];
957 ["cat"; "/new"]], "new file contents")],
960 This creates a filesystem on C<device> (usually a partition
961 of LVM logical volume). The filesystem type is C<fstype>, for
964 ("sfdisk", (RErr, [String "device";
965 Int "cyls"; Int "heads"; Int "sectors";
966 StringList "lines"]), 43, [DangerWillRobinson],
968 "create partitions on a block device",
970 This is a direct interface to the L<sfdisk(8)> program for creating
971 partitions on block devices.
973 C<device> should be a block device, for example C</dev/sda>.
975 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
976 and sectors on the device, which are passed directly to sfdisk as
977 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
978 of these, then the corresponding parameter is omitted. Usually for
979 'large' disks, you can just pass C<0> for these, but for small
980 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
981 out the right geometry and you will need to tell it.
983 C<lines> is a list of lines that we feed to C<sfdisk>. For more
984 information refer to the L<sfdisk(8)> manpage.
986 To create a single partition occupying the whole disk, you would
987 pass C<lines> as a single element list, when the single element being
988 the string C<,> (comma).");
990 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
991 [InitBasicFS, TestOutput (
992 [["write_file"; "/new"; "new file contents"; "0"];
993 ["cat"; "/new"]], "new file contents");
994 InitBasicFS, TestOutput (
995 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
996 ["cat"; "/new"]], "\nnew file contents\n");
997 InitBasicFS, TestOutput (
998 [["write_file"; "/new"; "\n\n"; "0"];
999 ["cat"; "/new"]], "\n\n");
1000 InitBasicFS, TestOutput (
1001 [["write_file"; "/new"; ""; "0"];
1002 ["cat"; "/new"]], "");
1003 InitBasicFS, TestOutput (
1004 [["write_file"; "/new"; "\n\n\n"; "0"];
1005 ["cat"; "/new"]], "\n\n\n");
1006 InitBasicFS, TestOutput (
1007 [["write_file"; "/new"; "\n"; "0"];
1008 ["cat"; "/new"]], "\n")],
1011 This call creates a file called C<path>. The contents of the
1012 file is the string C<content> (which can contain any 8 bit data),
1013 with length C<size>.
1015 As a special case, if C<size> is C<0>
1016 then the length is calculated using C<strlen> (so in this case
1017 the content cannot contain embedded ASCII NULs).");
1019 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1020 [InitEmpty, TestOutputList (
1021 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1022 ["mkfs"; "ext2"; "/dev/sda1"];
1023 ["mount"; "/dev/sda1"; "/"];
1024 ["mounts"]], ["/dev/sda1"]);
1025 InitEmpty, TestOutputList (
1026 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1027 ["mkfs"; "ext2"; "/dev/sda1"];
1028 ["mount"; "/dev/sda1"; "/"];
1031 "unmount a filesystem",
1033 This unmounts the given filesystem. The filesystem may be
1034 specified either by its mountpoint (path) or the device which
1035 contains the filesystem.");
1037 ("mounts", (RStringList "devices", []), 46, [],
1038 [InitBasicFS, TestOutputList (
1039 [["mounts"]], ["/dev/sda1"])],
1040 "show mounted filesystems",
1042 This returns the list of currently mounted filesystems. It returns
1043 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1045 Some internal mounts are not shown.");
1047 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1048 [InitBasicFS, TestOutputList (
1051 "unmount all filesystems",
1053 This unmounts all mounted filesystems.
1055 Some internal mounts are not unmounted by this call.");
1057 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1059 "remove all LVM LVs, VGs and PVs",
1061 This command removes all LVM logical volumes, volume groups
1062 and physical volumes.");
1064 ("file", (RString "description", [String "path"]), 49, [],
1065 [InitBasicFS, TestOutput (
1067 ["file"; "/new"]], "empty");
1068 InitBasicFS, TestOutput (
1069 [["write_file"; "/new"; "some content\n"; "0"];
1070 ["file"; "/new"]], "ASCII text");
1071 InitBasicFS, TestLastFail (
1072 [["file"; "/nofile"]])],
1073 "determine file type",
1075 This call uses the standard L<file(1)> command to determine
1076 the type or contents of the file. This also works on devices,
1077 for example to find out whether a partition contains a filesystem.
1079 The exact command which runs is C<file -bsL path>. Note in
1080 particular that the filename is not prepended to the output
1081 (the C<-b> option).");
1083 ("command", (RString "output", [StringList "arguments"]), 50, [],
1084 [], (* XXX how to test? *)
1085 "run a command from the guest filesystem",
1087 This call runs a command from the guest filesystem. The
1088 filesystem must be mounted, and must contain a compatible
1089 operating system (ie. something Linux, with the same
1090 or compatible processor architecture).
1092 The single parameter is an argv-style list of arguments.
1093 The first element is the name of the program to run.
1094 Subsequent elements are parameters. The list must be
1095 non-empty (ie. must contain a program name).
1097 The C<$PATH> environment variable will contain at least
1098 C</usr/bin> and C</bin>. If you require a program from
1099 another location, you should provide the full path in the
1102 Shared libraries and data files required by the program
1103 must be available on filesystems which are mounted in the
1104 correct places. It is the caller's responsibility to ensure
1105 all filesystems that are needed are mounted at the right
1108 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [],
1109 [], (* XXX how to test? *)
1110 "run a command, returning lines",
1112 This is the same as C<guestfs_command>, but splits the
1113 result into a list of lines.");
1115 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1116 [InitBasicFS, TestOutputStruct (
1118 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1119 "get file information",
1121 Returns file information for the given C<path>.
1123 This is the same as the C<stat(2)> system call.");
1125 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1126 [InitBasicFS, TestOutputStruct (
1128 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1129 "get file information for a symbolic link",
1131 Returns file information for the given C<path>.
1133 This is the same as C<guestfs_stat> except that if C<path>
1134 is a symbolic link, then the link is stat-ed, not the file it
1137 This is the same as the C<lstat(2)> system call.");
1139 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1140 [InitBasicFS, TestOutputStruct (
1141 [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1142 CompareWithInt ("blocks", 490020);
1143 CompareWithInt ("bsize", 1024)])],
1144 "get file system statistics",
1146 Returns file system statistics for any mounted file system.
1147 C<path> should be a file or directory in the mounted file system
1148 (typically it is the mount point itself, but it doesn't need to be).
1150 This is the same as the C<statvfs(2)> system call.");
1152 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1154 "get ext2/ext3 superblock details",
1156 This returns the contents of the ext2 or ext3 filesystem superblock
1159 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1160 manpage for more details. The list of fields returned isn't
1161 clearly defined, and depends on both the version of C<tune2fs>
1162 that libguestfs was built against, and the filesystem itself.");
1164 ("blockdev_setro", (RErr, [String "device"]), 56, [],
1165 [InitEmpty, TestOutputTrue (
1166 [["blockdev_setro"; "/dev/sda"];
1167 ["blockdev_getro"; "/dev/sda"]])],
1168 "set block device to read-only",
1170 Sets the block device named C<device> to read-only.
1172 This uses the L<blockdev(8)> command.");
1174 ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1175 [InitEmpty, TestOutputFalse (
1176 [["blockdev_setrw"; "/dev/sda"];
1177 ["blockdev_getro"; "/dev/sda"]])],
1178 "set block device to read-write",
1180 Sets the block device named C<device> to read-write.
1182 This uses the L<blockdev(8)> command.");
1184 ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1185 [InitEmpty, TestOutputTrue (
1186 [["blockdev_setro"; "/dev/sda"];
1187 ["blockdev_getro"; "/dev/sda"]])],
1188 "is block device set to read-only",
1190 Returns a boolean indicating if the block device is read-only
1191 (true if read-only, false if not).
1193 This uses the L<blockdev(8)> command.");
1195 ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1196 [InitEmpty, TestOutputInt (
1197 [["blockdev_getss"; "/dev/sda"]], 512)],
1198 "get sectorsize of block device",
1200 This returns the size of sectors on a block device.
1201 Usually 512, but can be larger for modern devices.
1203 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1206 This uses the L<blockdev(8)> command.");
1208 ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1209 [InitEmpty, TestOutputInt (
1210 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1211 "get blocksize of block device",
1213 This returns the block size of a device.
1215 (Note this is different from both I<size in blocks> and
1216 I<filesystem block size>).
1218 This uses the L<blockdev(8)> command.");
1220 ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1222 "set blocksize of block device",
1224 This sets the block size of a device.
1226 (Note this is different from both I<size in blocks> and
1227 I<filesystem block size>).
1229 This uses the L<blockdev(8)> command.");
1231 ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1232 [InitEmpty, TestOutputInt (
1233 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1234 "get total size of device in 512-byte sectors",
1236 This returns the size of the device in units of 512-byte sectors
1237 (even if the sectorsize isn't 512 bytes ... weird).
1239 See also C<guestfs_blockdev_getss> for the real sector size of
1240 the device, and C<guestfs_blockdev_getsize64> for the more
1241 useful I<size in bytes>.
1243 This uses the L<blockdev(8)> command.");
1245 ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1246 [InitEmpty, TestOutputInt (
1247 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1248 "get total size of device in bytes",
1250 This returns the size of the device in bytes.
1252 See also C<guestfs_blockdev_getsz>.
1254 This uses the L<blockdev(8)> command.");
1256 ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1258 [["blockdev_flushbufs"; "/dev/sda"]]],
1259 "flush device buffers",
1261 This tells the kernel to flush internal buffers associated
1264 This uses the L<blockdev(8)> command.");
1266 ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1268 [["blockdev_rereadpt"; "/dev/sda"]]],
1269 "reread partition table",
1271 Reread the partition table on C<device>.
1273 This uses the L<blockdev(8)> command.");
1275 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1276 [InitBasicFS, TestOutput (
1277 (* Pick a file from cwd which isn't likely to change. *)
1278 [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
1279 ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1280 "upload a file from the local machine",
1282 Upload local file C<filename> to C<remotefilename> on the
1285 C<filename> can also be a named pipe.
1287 See also C<guestfs_download>.");
1289 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1290 [InitBasicFS, TestOutput (
1291 (* Pick a file from cwd which isn't likely to change. *)
1292 [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
1293 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1294 ["upload"; "testdownload.tmp"; "/upload"];
1295 ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1296 "download a file to the local machine",
1298 Download file C<remotefilename> and save it as C<filename>
1299 on the local machine.
1301 C<filename> can also be a named pipe.
1303 See also C<guestfs_upload>, C<guestfs_cat>.");
1305 ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1306 [InitBasicFS, TestOutput (
1307 [["write_file"; "/new"; "test\n"; "0"];
1308 ["checksum"; "crc"; "/new"]], "935282863");
1309 InitBasicFS, TestLastFail (
1310 [["checksum"; "crc"; "/new"]]);
1311 InitBasicFS, TestOutput (
1312 [["write_file"; "/new"; "test\n"; "0"];
1313 ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1314 InitBasicFS, TestOutput (
1315 [["write_file"; "/new"; "test\n"; "0"];
1316 ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1317 InitBasicFS, TestOutput (
1318 [["write_file"; "/new"; "test\n"; "0"];
1319 ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1320 InitBasicFS, TestOutput (
1321 [["write_file"; "/new"; "test\n"; "0"];
1322 ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1323 InitBasicFS, TestOutput (
1324 [["write_file"; "/new"; "test\n"; "0"];
1325 ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1326 InitBasicFS, TestOutput (
1327 [["write_file"; "/new"; "test\n"; "0"];
1328 ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123")],
1329 "compute MD5, SHAx or CRC checksum of file",
1331 This call computes the MD5, SHAx or CRC checksum of the
1334 The type of checksum to compute is given by the C<csumtype>
1335 parameter which must have one of the following values:
1341 Compute the cyclic redundancy check (CRC) specified by POSIX
1342 for the C<cksum> command.
1346 Compute the MD5 hash (using the C<md5sum> program).
1350 Compute the SHA1 hash (using the C<sha1sum> program).
1354 Compute the SHA224 hash (using the C<sha224sum> program).
1358 Compute the SHA256 hash (using the C<sha256sum> program).
1362 Compute the SHA384 hash (using the C<sha384sum> program).
1366 Compute the SHA512 hash (using the C<sha512sum> program).
1370 The checksum is returned as a printable string.");
1372 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1373 [InitBasicFS, TestOutput (
1374 [["tar_in"; "images/helloworld.tar"; "/"];
1375 ["cat"; "/hello"]], "hello\n")],
1376 "unpack tarfile to directory",
1378 This command uploads and unpacks local file C<tarfile> (an
1379 I<uncompressed> tar file) into C<directory>.
1381 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1383 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1385 "pack directory into tarfile",
1387 This command packs the contents of C<directory> and downloads
1388 it to local file C<tarfile>.
1390 To download a compressed tarball, use C<guestfs_tgz_out>.");
1392 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1393 [InitBasicFS, TestOutput (
1394 [["tgz_in"; "images/helloworld.tar.gz"; "/"];
1395 ["cat"; "/hello"]], "hello\n")],
1396 "unpack compressed tarball to directory",
1398 This command uploads and unpacks local file C<tarball> (a
1399 I<gzip compressed> tar file) into C<directory>.
1401 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1403 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1405 "pack directory into compressed tarball",
1407 This command packs the contents of C<directory> and downloads
1408 it to local file C<tarball>.
1410 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1414 let all_functions = non_daemon_functions @ daemon_functions
1416 (* In some places we want the functions to be displayed sorted
1417 * alphabetically, so this is useful:
1419 let all_functions_sorted =
1420 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
1421 compare n1 n2) all_functions
1423 (* Column names and types from LVM PVs/VGs/LVs. *)
1432 "pv_attr", `String (* XXX *);
1433 "pv_pe_count", `Int;
1434 "pv_pe_alloc_count", `Int;
1437 "pv_mda_count", `Int;
1438 "pv_mda_free", `Bytes;
1439 (* Not in Fedora 10:
1440 "pv_mda_size", `Bytes;
1447 "vg_attr", `String (* XXX *);
1450 "vg_sysid", `String;
1451 "vg_extent_size", `Bytes;
1452 "vg_extent_count", `Int;
1453 "vg_free_count", `Int;
1461 "vg_mda_count", `Int;
1462 "vg_mda_free", `Bytes;
1463 (* Not in Fedora 10:
1464 "vg_mda_size", `Bytes;
1470 "lv_attr", `String (* XXX *);
1473 "lv_kernel_major", `Int;
1474 "lv_kernel_minor", `Int;
1478 "snap_percent", `OptPercent;
1479 "copy_percent", `OptPercent;
1482 "mirror_log", `String;
1486 (* Column names and types from stat structures.
1487 * NB. Can't use things like 'st_atime' because glibc header files
1488 * define some of these as macros. Ugh.
1505 let statvfs_cols = [
1519 (* Useful functions.
1520 * Note we don't want to use any external OCaml libraries which
1521 * makes this a bit harder than it should be.
1523 let failwithf fs = ksprintf failwith fs
1525 let replace_char s c1 c2 =
1526 let s2 = String.copy s in
1527 let r = ref false in
1528 for i = 0 to String.length s2 - 1 do
1529 if String.unsafe_get s2 i = c1 then (
1530 String.unsafe_set s2 i c2;
1534 if not !r then s else s2
1538 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
1540 let triml ?(test = isspace) str =
1542 let n = ref (String.length str) in
1543 while !n > 0 && test str.[!i]; do
1548 else String.sub str !i !n
1550 let trimr ?(test = isspace) str =
1551 let n = ref (String.length str) in
1552 while !n > 0 && test str.[!n-1]; do
1555 if !n = String.length str then str
1556 else String.sub str 0 !n
1558 let trim ?(test = isspace) str =
1559 trimr ~test (triml ~test str)
1561 let rec find s sub =
1562 let len = String.length s in
1563 let sublen = String.length sub in
1565 if i <= len-sublen then (
1567 if j < sublen then (
1568 if s.[i+j] = sub.[j] then loop2 (j+1)
1574 if r = -1 then loop (i+1) else r
1580 let rec replace_str s s1 s2 =
1581 let len = String.length s in
1582 let sublen = String.length s1 in
1583 let i = find s s1 in
1586 let s' = String.sub s 0 i in
1587 let s'' = String.sub s (i+sublen) (len-i-sublen) in
1588 s' ^ s2 ^ replace_str s'' s1 s2
1591 let rec string_split sep str =
1592 let len = String.length str in
1593 let seplen = String.length sep in
1594 let i = find str sep in
1595 if i = -1 then [str]
1597 let s' = String.sub str 0 i in
1598 let s'' = String.sub str (i+seplen) (len-i-seplen) in
1599 s' :: string_split sep s''
1602 let rec find_map f = function
1603 | [] -> raise Not_found
1607 | None -> find_map f xs
1610 let rec loop i = function
1612 | x :: xs -> f i x; loop (i+1) xs
1617 let rec loop i = function
1619 | x :: xs -> let r = f i x in r :: loop (i+1) xs
1623 let name_of_argt = function
1624 | String n | OptString n | StringList n | Bool n | Int n
1625 | FileIn n | FileOut n -> n
1627 let seq_of_test = function
1628 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
1629 | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
1630 | TestOutputLength (s, _) | TestOutputStruct (s, _)
1631 | TestLastFail s -> s
1633 (* Check function names etc. for consistency. *)
1634 let check_functions () =
1635 let contains_uppercase str =
1636 let len = String.length str in
1638 if i >= len then false
1641 if c >= 'A' && c <= 'Z' then true
1648 (* Check function names. *)
1650 fun (name, _, _, _, _, _, _) ->
1651 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
1652 failwithf "function name %s does not need 'guestfs' prefix" name;
1653 if contains_uppercase name then
1654 failwithf "function name %s should not contain uppercase chars" name;
1655 if String.contains name '-' then
1656 failwithf "function name %s should not contain '-', use '_' instead."
1660 (* Check function parameter/return names. *)
1662 fun (name, style, _, _, _, _, _) ->
1663 let check_arg_ret_name n =
1664 if contains_uppercase n then
1665 failwithf "%s param/ret %s should not contain uppercase chars"
1667 if String.contains n '-' || String.contains n '_' then
1668 failwithf "%s param/ret %s should not contain '-' or '_'"
1671 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;
1672 if n = "argv" || n = "args" then
1673 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
1676 (match fst style with
1678 | RInt n | RInt64 n | RBool n | RConstString n | RString n
1679 | RStringList n | RPVList n | RVGList n | RLVList n
1680 | RStat n | RStatVFS n
1682 check_arg_ret_name n
1684 check_arg_ret_name n;
1685 check_arg_ret_name m
1687 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
1690 (* Check short descriptions. *)
1692 fun (name, _, _, _, _, shortdesc, _) ->
1693 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
1694 failwithf "short description of %s should begin with lowercase." name;
1695 let c = shortdesc.[String.length shortdesc-1] in
1696 if c = '\n' || c = '.' then
1697 failwithf "short description of %s should not end with . or \\n." name
1700 (* Check long dscriptions. *)
1702 fun (name, _, _, _, _, _, longdesc) ->
1703 if longdesc.[String.length longdesc-1] = '\n' then
1704 failwithf "long description of %s should not end with \\n." name
1707 (* Check proc_nrs. *)
1709 fun (name, _, proc_nr, _, _, _, _) ->
1710 if proc_nr <= 0 then
1711 failwithf "daemon function %s should have proc_nr > 0" name
1715 fun (name, _, proc_nr, _, _, _, _) ->
1716 if proc_nr <> -1 then
1717 failwithf "non-daemon function %s should have proc_nr -1" name
1718 ) non_daemon_functions;
1721 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
1724 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
1725 let rec loop = function
1728 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
1730 | (name1,nr1) :: (name2,nr2) :: _ ->
1731 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
1739 (* Ignore functions that have no tests. We generate a
1740 * warning when the user does 'make check' instead.
1742 | name, _, _, _, [], _, _ -> ()
1743 | name, _, _, _, tests, _, _ ->
1747 match seq_of_test test with
1749 failwithf "%s has a test containing an empty sequence" name
1750 | cmds -> List.map List.hd cmds
1752 let funcs = List.flatten funcs in
1754 let tested = List.mem name funcs in
1757 failwithf "function %s has tests but does not test itself" name
1760 (* 'pr' prints to the current output file. *)
1761 let chan = ref stdout
1762 let pr fs = ksprintf (output_string !chan) fs
1764 (* Generate a header block in a number of standard styles. *)
1765 type comment_style = CStyle | HashStyle | OCamlStyle
1766 type license = GPLv2 | LGPLv2
1768 let generate_header comment license =
1769 let c = match comment with
1770 | CStyle -> pr "/* "; " *"
1771 | HashStyle -> pr "# "; "#"
1772 | OCamlStyle -> pr "(* "; " *" in
1773 pr "libguestfs generated file\n";
1774 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
1775 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
1777 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
1781 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
1782 pr "%s it under the terms of the GNU General Public License as published by\n" c;
1783 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
1784 pr "%s (at your option) any later version.\n" c;
1786 pr "%s This program is distributed in the hope that it will be useful,\n" c;
1787 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1788 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
1789 pr "%s GNU General Public License for more details.\n" c;
1791 pr "%s You should have received a copy of the GNU General Public License along\n" c;
1792 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
1793 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
1796 pr "%s This library is free software; you can redistribute it and/or\n" c;
1797 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
1798 pr "%s License as published by the Free Software Foundation; either\n" c;
1799 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
1801 pr "%s This library is distributed in the hope that it will be useful,\n" c;
1802 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1803 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
1804 pr "%s Lesser General Public License for more details.\n" c;
1806 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
1807 pr "%s License along with this library; if not, write to the Free Software\n" c;
1808 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
1811 | CStyle -> pr " */\n"
1813 | OCamlStyle -> pr " *)\n"
1817 (* Start of main code generation functions below this line. *)
1819 (* Generate the pod documentation for the C API. *)
1820 let rec generate_actions_pod () =
1822 fun (shortname, style, _, flags, _, _, longdesc) ->
1823 let name = "guestfs_" ^ shortname in
1824 pr "=head2 %s\n\n" name;
1826 generate_prototype ~extern:false ~handle:"handle" name style;
1828 pr "%s\n\n" longdesc;
1829 (match fst style with
1831 pr "This function returns 0 on success or -1 on error.\n\n"
1833 pr "On error this function returns -1.\n\n"
1835 pr "On error this function returns -1.\n\n"
1837 pr "This function returns a C truth value on success or -1 on error.\n\n"
1839 pr "This function returns a string, or NULL on error.
1840 The string is owned by the guest handle and must I<not> be freed.\n\n"
1842 pr "This function returns a string, or NULL on error.
1843 I<The caller must free the returned string after use>.\n\n"
1845 pr "This function returns a NULL-terminated array of strings
1846 (like L<environ(3)>), or NULL if there was an error.
1847 I<The caller must free the strings and the array after use>.\n\n"
1849 pr "This function returns a C<struct guestfs_int_bool *>,
1850 or NULL if there was an error.
1851 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
1853 pr "This function returns a C<struct guestfs_lvm_pv_list *>
1854 (see E<lt>guestfs-structs.hE<gt>),
1855 or NULL if there was an error.
1856 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
1858 pr "This function returns a C<struct guestfs_lvm_vg_list *>
1859 (see E<lt>guestfs-structs.hE<gt>),
1860 or NULL if there was an error.
1861 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
1863 pr "This function returns a C<struct guestfs_lvm_lv_list *>
1864 (see E<lt>guestfs-structs.hE<gt>),
1865 or NULL if there was an error.
1866 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
1868 pr "This function returns a C<struct guestfs_stat *>
1869 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
1870 or NULL if there was an error.
1871 I<The caller must call C<free> after use>.\n\n"
1873 pr "This function returns a C<struct guestfs_statvfs *>
1874 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
1875 or NULL if there was an error.
1876 I<The caller must call C<free> after use>.\n\n"
1878 pr "This function returns a NULL-terminated array of
1879 strings, or NULL if there was an error.
1880 The array of strings will always have length C<2n+1>, where
1881 C<n> keys and values alternate, followed by the trailing NULL entry.
1882 I<The caller must free the strings and the array after use>.\n\n"
1884 if List.mem ProtocolLimitWarning flags then
1885 pr "%s\n\n" protocol_limit_warning;
1886 if List.mem DangerWillRobinson flags then
1887 pr "%s\n\n" danger_will_robinson;
1888 ) all_functions_sorted
1890 and generate_structs_pod () =
1891 (* LVM structs documentation. *)
1894 pr "=head2 guestfs_lvm_%s\n" typ;
1896 pr " struct guestfs_lvm_%s {\n" typ;
1899 | name, `String -> pr " char *%s;\n" name
1901 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
1902 pr " char %s[32];\n" name
1903 | name, `Bytes -> pr " uint64_t %s;\n" name
1904 | name, `Int -> pr " int64_t %s;\n" name
1905 | name, `OptPercent ->
1906 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
1907 pr " float %s;\n" name
1910 pr " struct guestfs_lvm_%s_list {\n" typ;
1911 pr " uint32_t len; /* Number of elements in list. */\n";
1912 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
1915 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
1918 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1920 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
1921 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
1923 * We have to use an underscore instead of a dash because otherwise
1924 * rpcgen generates incorrect code.
1926 * This header is NOT exported to clients, but see also generate_structs_h.
1928 and generate_xdr () =
1929 generate_header CStyle LGPLv2;
1931 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
1932 pr "typedef string str<>;\n";
1935 (* LVM internal structures. *)
1939 pr "struct guestfs_lvm_int_%s {\n" typ;
1941 | name, `String -> pr " string %s<>;\n" name
1942 | name, `UUID -> pr " opaque %s[32];\n" name
1943 | name, `Bytes -> pr " hyper %s;\n" name
1944 | name, `Int -> pr " hyper %s;\n" name
1945 | name, `OptPercent -> pr " float %s;\n" name
1949 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
1951 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1953 (* Stat internal structures. *)
1957 pr "struct guestfs_int_%s {\n" typ;
1959 | name, `Int -> pr " hyper %s;\n" name
1963 ) ["stat", stat_cols; "statvfs", statvfs_cols];
1966 fun (shortname, style, _, _, _, _, _) ->
1967 let name = "guestfs_" ^ shortname in
1969 (match snd style with
1972 pr "struct %s_args {\n" name;
1975 | String n -> pr " string %s<>;\n" n
1976 | OptString n -> pr " str *%s;\n" n
1977 | StringList n -> pr " str %s<>;\n" n
1978 | Bool n -> pr " bool %s;\n" n
1979 | Int n -> pr " int %s;\n" n
1980 | FileIn _ | FileOut _ -> ()
1984 (match fst style with
1987 pr "struct %s_ret {\n" name;
1991 pr "struct %s_ret {\n" name;
1992 pr " hyper %s;\n" n;
1995 pr "struct %s_ret {\n" name;
1999 failwithf "RConstString cannot be returned from a daemon function"
2001 pr "struct %s_ret {\n" name;
2002 pr " string %s<>;\n" n;
2005 pr "struct %s_ret {\n" name;
2006 pr " str %s<>;\n" n;
2009 pr "struct %s_ret {\n" name;
2014 pr "struct %s_ret {\n" name;
2015 pr " guestfs_lvm_int_pv_list %s;\n" n;
2018 pr "struct %s_ret {\n" name;
2019 pr " guestfs_lvm_int_vg_list %s;\n" n;
2022 pr "struct %s_ret {\n" name;
2023 pr " guestfs_lvm_int_lv_list %s;\n" n;
2026 pr "struct %s_ret {\n" name;
2027 pr " guestfs_int_stat %s;\n" n;
2030 pr "struct %s_ret {\n" name;
2031 pr " guestfs_int_statvfs %s;\n" n;
2034 pr "struct %s_ret {\n" name;
2035 pr " str %s<>;\n" n;
2040 (* Table of procedure numbers. *)
2041 pr "enum guestfs_procedure {\n";
2043 fun (shortname, _, proc_nr, _, _, _, _) ->
2044 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
2046 pr " GUESTFS_PROC_NR_PROCS\n";
2050 (* Having to choose a maximum message size is annoying for several
2051 * reasons (it limits what we can do in the API), but it (a) makes
2052 * the protocol a lot simpler, and (b) provides a bound on the size
2053 * of the daemon which operates in limited memory space. For large
2054 * file transfers you should use FTP.
2056 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
2059 (* Message header, etc. *)
2061 /* The communication protocol is now documented in the guestfs(3)
2065 const GUESTFS_PROGRAM = 0x2000F5F5;
2066 const GUESTFS_PROTOCOL_VERSION = 1;
2068 /* These constants must be larger than any possible message length. */
2069 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
2070 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
2072 enum guestfs_message_direction {
2073 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
2074 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
2077 enum guestfs_message_status {
2078 GUESTFS_STATUS_OK = 0,
2079 GUESTFS_STATUS_ERROR = 1
2082 const GUESTFS_ERROR_LEN = 256;
2084 struct guestfs_message_error {
2085 string error_message<GUESTFS_ERROR_LEN>;
2088 struct guestfs_message_header {
2089 unsigned prog; /* GUESTFS_PROGRAM */
2090 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
2091 guestfs_procedure proc; /* GUESTFS_PROC_x */
2092 guestfs_message_direction direction;
2093 unsigned serial; /* message serial number */
2094 guestfs_message_status status;
2097 const GUESTFS_MAX_CHUNK_SIZE = 8192;
2099 struct guestfs_chunk {
2100 int cancel; /* if non-zero, transfer is cancelled */
2101 /* data size is 0 bytes if the transfer has finished successfully */
2102 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
2106 (* Generate the guestfs-structs.h file. *)
2107 and generate_structs_h () =
2108 generate_header CStyle LGPLv2;
2110 (* This is a public exported header file containing various
2111 * structures. The structures are carefully written to have
2112 * exactly the same in-memory format as the XDR structures that
2113 * we use on the wire to the daemon. The reason for creating
2114 * copies of these structures here is just so we don't have to
2115 * export the whole of guestfs_protocol.h (which includes much
2116 * unrelated and XDR-dependent stuff that we don't want to be
2117 * public, or required by clients).
2119 * To reiterate, we will pass these structures to and from the
2120 * client with a simple assignment or memcpy, so the format
2121 * must be identical to what rpcgen / the RFC defines.
2124 (* guestfs_int_bool structure. *)
2125 pr "struct guestfs_int_bool {\n";
2131 (* LVM public structures. *)
2135 pr "struct guestfs_lvm_%s {\n" typ;
2138 | name, `String -> pr " char *%s;\n" name
2139 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
2140 | name, `Bytes -> pr " uint64_t %s;\n" name
2141 | name, `Int -> pr " int64_t %s;\n" name
2142 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
2146 pr "struct guestfs_lvm_%s_list {\n" typ;
2147 pr " uint32_t len;\n";
2148 pr " struct guestfs_lvm_%s *val;\n" typ;
2151 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2153 (* Stat structures. *)
2157 pr "struct guestfs_%s {\n" typ;
2160 | name, `Int -> pr " int64_t %s;\n" name
2164 ) ["stat", stat_cols; "statvfs", statvfs_cols]
2166 (* Generate the guestfs-actions.h file. *)
2167 and generate_actions_h () =
2168 generate_header CStyle LGPLv2;
2170 fun (shortname, style, _, _, _, _, _) ->
2171 let name = "guestfs_" ^ shortname in
2172 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
2176 (* Generate the client-side dispatch stubs. *)
2177 and generate_client_actions () =
2178 generate_header CStyle LGPLv2;
2184 #include \"guestfs.h\"
2185 #include \"guestfs_protocol.h\"
2187 #define error guestfs_error
2188 #define perrorf guestfs_perrorf
2189 #define safe_malloc guestfs_safe_malloc
2190 #define safe_realloc guestfs_safe_realloc
2191 #define safe_strdup guestfs_safe_strdup
2192 #define safe_memdup guestfs_safe_memdup
2194 /* Check the return message from a call for validity. */
2196 check_reply_header (guestfs_h *g,
2197 const struct guestfs_message_header *hdr,
2198 int proc_nr, int serial)
2200 if (hdr->prog != GUESTFS_PROGRAM) {
2201 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
2204 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
2205 error (g, \"wrong protocol version (%%d/%%d)\",
2206 hdr->vers, GUESTFS_PROTOCOL_VERSION);
2209 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
2210 error (g, \"unexpected message direction (%%d/%%d)\",
2211 hdr->direction, GUESTFS_DIRECTION_REPLY);
2214 if (hdr->proc != proc_nr) {
2215 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
2218 if (hdr->serial != serial) {
2219 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
2226 /* Check we are in the right state to run a high-level action. */
2228 check_state (guestfs_h *g, const char *caller)
2230 if (!guestfs_is_ready (g)) {
2231 if (guestfs_is_config (g))
2232 error (g, \"%%s: call launch() before using this function\",
2234 else if (guestfs_is_launching (g))
2235 error (g, \"%%s: call wait_ready() before using this function\",
2238 error (g, \"%%s called from the wrong state, %%d != READY\",
2239 caller, guestfs_get_state (g));
2247 (* Client-side stubs for each function. *)
2249 fun (shortname, style, _, _, _, _, _) ->
2250 let name = "guestfs_" ^ shortname in
2252 (* Generate the context struct which stores the high-level
2253 * state between callback functions.
2255 pr "struct %s_ctx {\n" shortname;
2256 pr " /* This flag is set by the callbacks, so we know we've done\n";
2257 pr " * the callbacks as expected, and in the right sequence.\n";
2258 pr " * 0 = not called, 1 = send called,\n";
2259 pr " * 1001 = reply called.\n";
2261 pr " int cb_sequence;\n";
2262 pr " struct guestfs_message_header hdr;\n";
2263 pr " struct guestfs_message_error err;\n";
2264 (match fst style with
2267 failwithf "RConstString cannot be returned from a daemon function"
2269 | RBool _ | RString _ | RStringList _
2271 | RPVList _ | RVGList _ | RLVList _
2272 | RStat _ | RStatVFS _
2274 pr " struct %s_ret ret;\n" name
2279 (* Generate the reply callback function. *)
2280 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
2282 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2283 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
2285 pr " ml->main_loop_quit (ml, g);\n";
2287 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
2288 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
2291 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
2292 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
2293 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
2300 (match fst style with
2303 failwithf "RConstString cannot be returned from a daemon function"
2305 | RBool _ | RString _ | RStringList _
2307 | RPVList _ | RVGList _ | RLVList _
2308 | RStat _ | RStatVFS _
2310 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
2311 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
2317 pr " ctx->cb_sequence = 1001;\n";
2320 (* Generate the action stub. *)
2321 generate_prototype ~extern:false ~semicolon:false ~newline:true
2322 ~handle:"g" name style;
2325 match fst style with
2326 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
2328 failwithf "RConstString cannot be returned from a daemon function"
2329 | RString _ | RStringList _ | RIntBool _
2330 | RPVList _ | RVGList _ | RLVList _
2331 | RStat _ | RStatVFS _
2337 (match snd style with
2339 | _ -> pr " struct %s_args args;\n" name
2342 pr " struct %s_ctx ctx;\n" shortname;
2343 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2344 pr " int serial;\n";
2346 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
2347 pr " guestfs_set_busy (g);\n";
2349 pr " memset (&ctx, 0, sizeof ctx);\n";
2352 (* Send the main header and arguments. *)
2353 (match snd style with
2355 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
2356 (String.uppercase shortname)
2361 pr " args.%s = (char *) %s;\n" n n
2363 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
2365 pr " args.%s.%s_val = (char **) %s;\n" n n n;
2366 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
2368 pr " args.%s = %s;\n" n n
2370 pr " args.%s = %s;\n" n n
2371 | FileIn _ | FileOut _ -> ()
2373 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
2374 (String.uppercase shortname);
2375 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
2378 pr " if (serial == -1) {\n";
2379 pr " guestfs_set_ready (g);\n";
2380 pr " return %s;\n" error_code;
2384 (* Send any additional files (FileIn) requested. *)
2385 let need_read_reply_label = ref false in
2392 pr " r = guestfs__send_file_sync (g, %s);\n" n;
2393 pr " if (r == -1) {\n";
2394 pr " guestfs_set_ready (g);\n";
2395 pr " return %s;\n" error_code;
2397 pr " if (r == -2) /* daemon cancelled */\n";
2398 pr " goto read_reply;\n";
2399 need_read_reply_label := true;
2405 (* Wait for the reply from the remote end. *)
2406 if !need_read_reply_label then pr " read_reply:\n";
2407 pr " guestfs__switch_to_receiving (g);\n";
2408 pr " ctx.cb_sequence = 0;\n";
2409 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
2410 pr " (void) ml->main_loop_run (ml, g);\n";
2411 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
2412 pr " if (ctx.cb_sequence != 1001) {\n";
2413 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
2414 pr " guestfs_set_ready (g);\n";
2415 pr " return %s;\n" error_code;
2419 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
2420 (String.uppercase shortname);
2421 pr " guestfs_set_ready (g);\n";
2422 pr " return %s;\n" error_code;
2426 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
2427 pr " error (g, \"%%s\", ctx.err.error_message);\n";
2428 pr " guestfs_set_ready (g);\n";
2429 pr " return %s;\n" error_code;
2433 (* Expecting to receive further files (FileOut)? *)
2437 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
2438 pr " guestfs_set_ready (g);\n";
2439 pr " return %s;\n" error_code;
2445 pr " guestfs_set_ready (g);\n";
2447 (match fst style with
2448 | RErr -> pr " return 0;\n"
2449 | RInt n | RInt64 n | RBool n ->
2450 pr " return ctx.ret.%s;\n" n
2452 failwithf "RConstString cannot be returned from a daemon function"
2454 pr " return ctx.ret.%s; /* caller will free */\n" n
2455 | RStringList n | RHashtable n ->
2456 pr " /* caller will free this, but we need to add a NULL entry */\n";
2457 pr " ctx.ret.%s.%s_val =\n" n n;
2458 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
2459 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
2461 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
2462 pr " return ctx.ret.%s.%s_val;\n" n n
2464 pr " /* caller with free this */\n";
2465 pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
2466 | RPVList n | RVGList n | RLVList n
2467 | RStat n | RStatVFS n ->
2468 pr " /* caller will free this */\n";
2469 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
2475 (* Generate daemon/actions.h. *)
2476 and generate_daemon_actions_h () =
2477 generate_header CStyle GPLv2;
2479 pr "#include \"../src/guestfs_protocol.h\"\n";
2483 fun (name, style, _, _, _, _, _) ->
2485 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
2489 (* Generate the server-side stubs. *)
2490 and generate_daemon_actions () =
2491 generate_header CStyle GPLv2;
2493 pr "#define _GNU_SOURCE // for strchrnul\n";
2495 pr "#include <stdio.h>\n";
2496 pr "#include <stdlib.h>\n";
2497 pr "#include <string.h>\n";
2498 pr "#include <inttypes.h>\n";
2499 pr "#include <ctype.h>\n";
2500 pr "#include <rpc/types.h>\n";
2501 pr "#include <rpc/xdr.h>\n";
2503 pr "#include \"daemon.h\"\n";
2504 pr "#include \"../src/guestfs_protocol.h\"\n";
2505 pr "#include \"actions.h\"\n";
2509 fun (name, style, _, _, _, _, _) ->
2510 (* Generate server-side stubs. *)
2511 pr "static void %s_stub (XDR *xdr_in)\n" name;
2514 match fst style with
2515 | RErr | RInt _ -> pr " int r;\n"; "-1"
2516 | RInt64 _ -> pr " int64_t r;\n"; "-1"
2517 | RBool _ -> pr " int r;\n"; "-1"
2519 failwithf "RConstString cannot be returned from a daemon function"
2520 | RString _ -> pr " char *r;\n"; "NULL"
2521 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
2522 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
2523 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
2524 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
2525 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
2526 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
2527 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
2529 (match snd style with
2532 pr " struct guestfs_%s_args args;\n" name;
2536 | OptString n -> pr " const char *%s;\n" n
2537 | StringList n -> pr " char **%s;\n" n
2538 | Bool n -> pr " int %s;\n" n
2539 | Int n -> pr " int %s;\n" n
2540 | FileIn _ | FileOut _ -> ()
2545 (match snd style with
2548 pr " memset (&args, 0, sizeof args);\n";
2550 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
2551 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
2556 | String n -> pr " %s = args.%s;\n" n n
2557 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
2559 pr " args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
2560 pr " args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
2561 pr " %s = args.%s.%s_val;\n" n n n
2562 | Bool n -> pr " %s = args.%s;\n" n n
2563 | Int n -> pr " %s = args.%s;\n" n n
2564 | FileIn _ | FileOut _ -> ()
2569 (* Don't want to call the impl with any FileIn or FileOut
2570 * parameters, since these go "outside" the RPC protocol.
2573 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
2575 pr " r = do_%s " name;
2576 generate_call_args argsnofile;
2579 pr " if (r == %s)\n" error_code;
2580 pr " /* do_%s has already called reply_with_error */\n" name;
2584 (* If there are any FileOut parameters, then the impl must
2585 * send its own reply.
2588 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
2590 pr " /* do_%s has already sent a reply */\n" name
2592 match fst style with
2593 | RErr -> pr " reply (NULL, NULL);\n"
2594 | RInt n | RInt64 n | RBool n ->
2595 pr " struct guestfs_%s_ret ret;\n" name;
2596 pr " ret.%s = r;\n" n;
2597 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2600 failwithf "RConstString cannot be returned from a daemon function"
2602 pr " struct guestfs_%s_ret ret;\n" name;
2603 pr " ret.%s = r;\n" n;
2604 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2607 | RStringList n | RHashtable n ->
2608 pr " struct guestfs_%s_ret ret;\n" name;
2609 pr " ret.%s.%s_len = count_strings (r);\n" n n;
2610 pr " ret.%s.%s_val = r;\n" n n;
2611 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2613 pr " free_strings (r);\n"
2615 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
2617 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2618 | RPVList n | RVGList n | RLVList n
2619 | RStat n | RStatVFS n ->
2620 pr " struct guestfs_%s_ret ret;\n" name;
2621 pr " ret.%s = *r;\n" n;
2622 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2624 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2628 (* Free the args. *)
2629 (match snd style with
2634 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2641 (* Dispatch function. *)
2642 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2644 pr " switch (proc_nr) {\n";
2647 fun (name, style, _, _, _, _, _) ->
2648 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
2649 pr " %s_stub (xdr_in);\n" name;
2654 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2659 (* LVM columns and tokenization functions. *)
2660 (* XXX This generates crap code. We should rethink how we
2666 pr "static const char *lvm_%s_cols = \"%s\";\n"
2667 typ (String.concat "," (List.map fst cols));
2670 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2672 pr " char *tok, *p, *next;\n";
2676 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2679 pr " if (!str) {\n";
2680 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2683 pr " if (!*str || isspace (*str)) {\n";
2684 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2689 fun (name, coltype) ->
2690 pr " if (!tok) {\n";
2691 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2694 pr " p = strchrnul (tok, ',');\n";
2695 pr " if (*p) next = p+1; else next = NULL;\n";
2696 pr " *p = '\\0';\n";
2699 pr " r->%s = strdup (tok);\n" name;
2700 pr " if (r->%s == NULL) {\n" name;
2701 pr " perror (\"strdup\");\n";
2705 pr " for (i = j = 0; i < 32; ++j) {\n";
2706 pr " if (tok[j] == '\\0') {\n";
2707 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2709 pr " } else if (tok[j] != '-')\n";
2710 pr " r->%s[i++] = tok[j];\n" name;
2713 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2714 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2718 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2719 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2723 pr " if (tok[0] == '\\0')\n";
2724 pr " r->%s = -1;\n" name;
2725 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2726 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2730 pr " tok = next;\n";
2733 pr " if (tok != NULL) {\n";
2734 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2741 pr "guestfs_lvm_int_%s_list *\n" typ;
2742 pr "parse_command_line_%ss (void)\n" typ;
2744 pr " char *out, *err;\n";
2745 pr " char *p, *pend;\n";
2747 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
2748 pr " void *newp;\n";
2750 pr " ret = malloc (sizeof *ret);\n";
2751 pr " if (!ret) {\n";
2752 pr " reply_with_perror (\"malloc\");\n";
2753 pr " return NULL;\n";
2756 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2757 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2759 pr " r = command (&out, &err,\n";
2760 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
2761 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2762 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2763 pr " if (r == -1) {\n";
2764 pr " reply_with_error (\"%%s\", err);\n";
2765 pr " free (out);\n";
2766 pr " free (err);\n";
2767 pr " free (ret);\n";
2768 pr " return NULL;\n";
2771 pr " free (err);\n";
2773 pr " /* Tokenize each line of the output. */\n";
2776 pr " while (p) {\n";
2777 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
2778 pr " if (pend) {\n";
2779 pr " *pend = '\\0';\n";
2783 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
2786 pr " if (!*p) { /* Empty line? Skip it. */\n";
2791 pr " /* Allocate some space to store this next entry. */\n";
2792 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2793 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2794 pr " if (newp == NULL) {\n";
2795 pr " reply_with_perror (\"realloc\");\n";
2796 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2797 pr " free (ret);\n";
2798 pr " free (out);\n";
2799 pr " return NULL;\n";
2801 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2803 pr " /* Tokenize the next entry. */\n";
2804 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2805 pr " if (r == -1) {\n";
2806 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2807 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2808 pr " free (ret);\n";
2809 pr " free (out);\n";
2810 pr " return NULL;\n";
2817 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2819 pr " free (out);\n";
2820 pr " return ret;\n";
2823 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2825 (* Generate the tests. *)
2826 and generate_tests () =
2827 generate_header CStyle GPLv2;
2834 #include <sys/types.h>
2837 #include \"guestfs.h\"
2839 static guestfs_h *g;
2840 static int suppress_error = 0;
2842 static void print_error (guestfs_h *g, void *data, const char *msg)
2844 if (!suppress_error)
2845 fprintf (stderr, \"%%s\\n\", msg);
2848 static void print_strings (char * const * const argv)
2852 for (argc = 0; argv[argc] != NULL; ++argc)
2853 printf (\"\\t%%s\\n\", argv[argc]);
2857 static void print_table (char * const * const argv)
2861 for (i = 0; argv[i] != NULL; i += 2)
2862 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
2866 static void no_test_warnings (void)
2872 | name, _, _, _, [], _, _ ->
2873 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
2874 | name, _, _, _, tests, _, _ -> ()
2880 (* Generate the actual tests. Note that we generate the tests
2881 * in reverse order, deliberately, so that (in general) the
2882 * newest tests run first. This makes it quicker and easier to
2887 fun (name, _, _, _, tests, _, _) ->
2888 mapi (generate_one_test name) tests
2889 ) (List.rev all_functions) in
2890 let test_names = List.concat test_names in
2891 let nr_tests = List.length test_names in
2894 int main (int argc, char *argv[])
2899 const char *filename;
2901 int nr_tests, test_num = 0;
2903 no_test_warnings ();
2905 g = guestfs_create ();
2907 printf (\"guestfs_create FAILED\\n\");
2911 guestfs_set_error_handler (g, print_error, NULL);
2913 srcdir = getenv (\"srcdir\");
2914 if (!srcdir) srcdir = \".\";
2916 guestfs_set_path (g, \".\");
2918 filename = \"test1.img\";
2919 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2924 if (lseek (fd, %d, SEEK_SET) == -1) {
2930 if (write (fd, &c, 1) == -1) {
2936 if (close (fd) == -1) {
2941 if (guestfs_add_drive (g, filename) == -1) {
2942 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
2946 filename = \"test2.img\";
2947 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2952 if (lseek (fd, %d, SEEK_SET) == -1) {
2958 if (write (fd, &c, 1) == -1) {
2964 if (close (fd) == -1) {
2969 if (guestfs_add_drive (g, filename) == -1) {
2970 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
2974 filename = \"test3.img\";
2975 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2980 if (lseek (fd, %d, SEEK_SET) == -1) {
2986 if (write (fd, &c, 1) == -1) {
2992 if (close (fd) == -1) {
2997 if (guestfs_add_drive (g, filename) == -1) {
2998 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3002 if (guestfs_launch (g) == -1) {
3003 printf (\"guestfs_launch FAILED\\n\");
3006 if (guestfs_wait_ready (g) == -1) {
3007 printf (\"guestfs_wait_ready FAILED\\n\");
3013 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
3017 pr " test_num++;\n";
3018 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
3019 pr " if (%s () == -1) {\n" test_name;
3020 pr " printf (\"%s FAILED\\n\");\n" test_name;
3026 pr " guestfs_close (g);\n";
3027 pr " unlink (\"test1.img\");\n";
3028 pr " unlink (\"test2.img\");\n";
3029 pr " unlink (\"test3.img\");\n";
3032 pr " if (failed > 0) {\n";
3033 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
3041 and generate_one_test name i (init, test) =
3042 let test_name = sprintf "test_%s_%d" name i in
3044 pr "static int %s (void)\n" test_name;
3050 pr " /* InitEmpty for %s (%d) */\n" name i;
3051 List.iter (generate_test_command_call test_name)
3055 pr " /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
3056 List.iter (generate_test_command_call test_name)
3059 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3060 ["mkfs"; "ext2"; "/dev/sda1"];
3061 ["mount"; "/dev/sda1"; "/"]]
3062 | InitBasicFSonLVM ->
3063 pr " /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
3065 List.iter (generate_test_command_call test_name)
3068 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3069 ["pvcreate"; "/dev/sda1"];
3070 ["vgcreate"; "VG"; "/dev/sda1"];
3071 ["lvcreate"; "LV"; "VG"; "8"];
3072 ["mkfs"; "ext2"; "/dev/VG/LV"];
3073 ["mount"; "/dev/VG/LV"; "/"]]
3076 let get_seq_last = function
3078 failwithf "%s: you cannot use [] (empty list) when expecting a command"
3081 let seq = List.rev seq in
3082 List.rev (List.tl seq), List.hd seq
3087 pr " /* TestRun for %s (%d) */\n" name i;
3088 List.iter (generate_test_command_call test_name) seq
3089 | TestOutput (seq, expected) ->
3090 pr " /* TestOutput for %s (%d) */\n" name i;
3091 let seq, last = get_seq_last seq in
3093 pr " if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
3094 pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
3098 List.iter (generate_test_command_call test_name) seq;
3099 generate_test_command_call ~test test_name last
3100 | TestOutputList (seq, expected) ->
3101 pr " /* TestOutputList for %s (%d) */\n" name i;
3102 let seq, last = get_seq_last seq in
3106 pr " if (!r[%d]) {\n" i;
3107 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
3108 pr " print_strings (r);\n";
3111 pr " if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
3112 pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
3116 pr " if (r[%d] != NULL) {\n" (List.length expected);
3117 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
3119 pr " print_strings (r);\n";
3123 List.iter (generate_test_command_call test_name) seq;
3124 generate_test_command_call ~test test_name last
3125 | TestOutputInt (seq, expected) ->
3126 pr " /* TestOutputInt for %s (%d) */\n" name i;
3127 let seq, last = get_seq_last seq in
3129 pr " if (r != %d) {\n" expected;
3130 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
3136 List.iter (generate_test_command_call test_name) seq;
3137 generate_test_command_call ~test test_name last
3138 | TestOutputTrue seq ->
3139 pr " /* TestOutputTrue for %s (%d) */\n" name i;
3140 let seq, last = get_seq_last seq in
3143 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
3148 List.iter (generate_test_command_call test_name) seq;
3149 generate_test_command_call ~test test_name last
3150 | TestOutputFalse seq ->
3151 pr " /* TestOutputFalse for %s (%d) */\n" name i;
3152 let seq, last = get_seq_last seq in
3155 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
3160 List.iter (generate_test_command_call test_name) seq;
3161 generate_test_command_call ~test test_name last
3162 | TestOutputLength (seq, expected) ->
3163 pr " /* TestOutputLength for %s (%d) */\n" name i;
3164 let seq, last = get_seq_last seq in
3167 pr " for (j = 0; j < %d; ++j)\n" expected;
3168 pr " if (r[j] == NULL) {\n";
3169 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
3171 pr " print_strings (r);\n";
3174 pr " if (r[j] != NULL) {\n";
3175 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
3177 pr " print_strings (r);\n";
3181 List.iter (generate_test_command_call test_name) seq;
3182 generate_test_command_call ~test test_name last
3183 | TestOutputStruct (seq, checks) ->
3184 pr " /* TestOutputStruct for %s (%d) */\n" name i;
3185 let seq, last = get_seq_last seq in
3189 | CompareWithInt (field, expected) ->
3190 pr " if (r->%s != %d) {\n" field expected;
3191 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
3192 test_name field expected;
3193 pr " (int) r->%s);\n" field;
3196 | CompareWithString (field, expected) ->
3197 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
3198 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
3199 test_name field expected;
3200 pr " r->%s);\n" field;
3203 | CompareFieldsIntEq (field1, field2) ->
3204 pr " if (r->%s != r->%s) {\n" field1 field2;
3205 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
3206 test_name field1 field2;
3207 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
3210 | CompareFieldsStrEq (field1, field2) ->
3211 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
3212 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
3213 test_name field1 field2;
3214 pr " r->%s, r->%s);\n" field1 field2;
3219 List.iter (generate_test_command_call test_name) seq;
3220 generate_test_command_call ~test test_name last
3221 | TestLastFail seq ->
3222 pr " /* TestLastFail for %s (%d) */\n" name i;
3223 let seq, last = get_seq_last seq in
3224 List.iter (generate_test_command_call test_name) seq;
3225 generate_test_command_call test_name ~expect_error:true last
3233 (* Generate the code to run a command, leaving the result in 'r'.
3234 * If you expect to get an error then you should set expect_error:true.
3236 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
3238 | [] -> assert false
3240 (* Look up the command to find out what args/ret it has. *)
3243 let _, style, _, _, _, _, _ =
3244 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
3247 failwithf "%s: in test, command %s was not found" test_name name in
3249 if List.length (snd style) <> List.length args then
3250 failwithf "%s: in test, wrong number of args given to %s"
3261 | FileIn _, _ | FileOut _, _ -> ()
3262 | StringList n, arg ->
3263 pr " char *%s[] = {\n" n;
3264 let strs = string_split " " arg in
3266 fun str -> pr " \"%s\",\n" (c_quote str)
3270 ) (List.combine (snd style) args);
3273 match fst style with
3274 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
3275 | RInt64 _ -> pr " int64_t r;\n"; "-1"
3276 | RConstString _ -> pr " const char *r;\n"; "NULL"
3277 | RString _ -> pr " char *r;\n"; "NULL"
3278 | RStringList _ | RHashtable _ ->
3283 pr " struct guestfs_int_bool *r;\n"; "NULL"
3285 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
3287 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
3289 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
3291 pr " struct guestfs_stat *r;\n"; "NULL"
3293 pr " struct guestfs_statvfs *r;\n"; "NULL" in
3295 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
3296 pr " r = guestfs_%s (g" name;
3298 (* Generate the parameters. *)
3302 | FileIn _, arg | FileOut _, arg ->
3303 pr ", \"%s\"" (c_quote arg)
3304 | OptString _, arg ->
3305 if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
3306 | StringList n, _ ->
3310 try int_of_string arg
3311 with Failure "int_of_string" ->
3312 failwithf "%s: expecting an int, but got '%s'" test_name arg in
3315 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
3316 ) (List.combine (snd style) args);
3319 if not expect_error then
3320 pr " if (r == %s)\n" error_code
3322 pr " if (r != %s)\n" error_code;
3325 (* Insert the test code. *)
3331 (match fst style with
3332 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
3333 | RString _ -> pr " free (r);\n"
3334 | RStringList _ | RHashtable _ ->
3335 pr " for (i = 0; r[i] != NULL; ++i)\n";
3336 pr " free (r[i]);\n";
3339 pr " guestfs_free_int_bool (r);\n"
3341 pr " guestfs_free_lvm_pv_list (r);\n"
3343 pr " guestfs_free_lvm_vg_list (r);\n"
3345 pr " guestfs_free_lvm_lv_list (r);\n"
3346 | RStat _ | RStatVFS _ ->
3353 let str = replace_str str "\r" "\\r" in
3354 let str = replace_str str "\n" "\\n" in
3355 let str = replace_str str "\t" "\\t" in
3358 (* Generate a lot of different functions for guestfish. *)
3359 and generate_fish_cmds () =
3360 generate_header CStyle GPLv2;
3364 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3366 let all_functions_sorted =
3368 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3369 ) all_functions_sorted in
3371 pr "#include <stdio.h>\n";
3372 pr "#include <stdlib.h>\n";
3373 pr "#include <string.h>\n";
3374 pr "#include <inttypes.h>\n";
3376 pr "#include <guestfs.h>\n";
3377 pr "#include \"fish.h\"\n";
3380 (* list_commands function, which implements guestfish -h *)
3381 pr "void list_commands (void)\n";
3383 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
3384 pr " list_builtin_commands ();\n";
3386 fun (name, _, _, flags, _, shortdesc, _) ->
3387 let name = replace_char name '_' '-' in
3388 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
3390 ) all_functions_sorted;
3391 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
3395 (* display_command function, which implements guestfish -h cmd *)
3396 pr "void display_command (const char *cmd)\n";
3399 fun (name, style, _, flags, _, shortdesc, longdesc) ->
3400 let name2 = replace_char name '_' '-' in
3402 try find_map (function FishAlias n -> Some n | _ -> None) flags
3403 with Not_found -> name in
3404 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3406 match snd style with
3410 name2 (String.concat "> <" (List.map name_of_argt args)) in
3413 if List.mem ProtocolLimitWarning flags then
3414 ("\n\n" ^ protocol_limit_warning)
3417 (* For DangerWillRobinson commands, we should probably have
3418 * guestfish prompt before allowing you to use them (especially
3419 * in interactive mode). XXX
3423 if List.mem DangerWillRobinson flags then
3424 ("\n\n" ^ danger_will_robinson)
3427 let describe_alias =
3428 if name <> alias then
3429 sprintf "\n\nYou can use '%s' as an alias for this command." alias
3433 pr "strcasecmp (cmd, \"%s\") == 0" name;
3434 if name <> name2 then
3435 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3436 if name <> alias then
3437 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3439 pr " pod2text (\"%s - %s\", %S);\n"
3441 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
3444 pr " display_builtin_command (cmd);\n";
3448 (* print_{pv,vg,lv}_list functions *)
3452 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
3459 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
3461 pr " printf (\"%s: \");\n" name;
3462 pr " for (i = 0; i < 32; ++i)\n";
3463 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
3464 pr " printf (\"\\n\");\n"
3466 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
3468 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3469 | name, `OptPercent ->
3470 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
3471 typ name name typ name;
3472 pr " else printf (\"%s: \\n\");\n" name
3476 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
3481 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
3482 pr " print_%s (&%ss->val[i]);\n" typ typ;
3485 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3487 (* print_{stat,statvfs} functions *)
3491 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
3496 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3500 ) ["stat", stat_cols; "statvfs", statvfs_cols];
3502 (* run_<action> actions *)
3504 fun (name, style, _, flags, _, _, _) ->
3505 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
3507 (match fst style with
3510 | RBool _ -> pr " int r;\n"
3511 | RInt64 _ -> pr " int64_t r;\n"
3512 | RConstString _ -> pr " const char *r;\n"
3513 | RString _ -> pr " char *r;\n"
3514 | RStringList _ | RHashtable _ -> pr " char **r;\n"
3515 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
3516 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
3517 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
3518 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
3519 | RStat _ -> pr " struct guestfs_stat *r;\n"
3520 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
3527 | FileOut n -> pr " const char *%s;\n" n
3528 | StringList n -> pr " char **%s;\n" n
3529 | Bool n -> pr " int %s;\n" n
3530 | Int n -> pr " int %s;\n" n
3533 (* Check and convert parameters. *)
3534 let argc_expected = List.length (snd style) in
3535 pr " if (argc != %d) {\n" argc_expected;
3536 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
3538 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
3544 | String name -> pr " %s = argv[%d];\n" name i
3546 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
3549 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
3552 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
3554 | StringList name ->
3555 pr " %s = parse_string_list (argv[%d]);\n" name i
3557 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
3559 pr " %s = atoi (argv[%d]);\n" name i
3562 (* Call C API function. *)
3564 try find_map (function FishAction n -> Some n | _ -> None) flags
3565 with Not_found -> sprintf "guestfs_%s" name in
3567 generate_call_args ~handle:"g" (snd style);
3570 (* Check return value for errors and display command results. *)
3571 (match fst style with
3572 | RErr -> pr " return r;\n"
3574 pr " if (r == -1) return -1;\n";
3575 pr " printf (\"%%d\\n\", r);\n";
3578 pr " if (r == -1) return -1;\n";
3579 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
3582 pr " if (r == -1) return -1;\n";
3583 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
3586 pr " if (r == NULL) return -1;\n";
3587 pr " printf (\"%%s\\n\", r);\n";
3590 pr " if (r == NULL) return -1;\n";
3591 pr " printf (\"%%s\\n\", r);\n";
3595 pr " if (r == NULL) return -1;\n";
3596 pr " print_strings (r);\n";
3597 pr " free_strings (r);\n";
3600 pr " if (r == NULL) return -1;\n";
3601 pr " printf (\"%%d, %%s\\n\", r->i,\n";
3602 pr " r->b ? \"true\" : \"false\");\n";
3603 pr " guestfs_free_int_bool (r);\n";
3606 pr " if (r == NULL) return -1;\n";
3607 pr " print_pv_list (r);\n";
3608 pr " guestfs_free_lvm_pv_list (r);\n";
3611 pr " if (r == NULL) return -1;\n";
3612 pr " print_vg_list (r);\n";
3613 pr " guestfs_free_lvm_vg_list (r);\n";
3616 pr " if (r == NULL) return -1;\n";
3617 pr " print_lv_list (r);\n";
3618 pr " guestfs_free_lvm_lv_list (r);\n";
3621 pr " if (r == NULL) return -1;\n";
3622 pr " print_stat (r);\n";
3626 pr " if (r == NULL) return -1;\n";
3627 pr " print_statvfs (r);\n";
3631 pr " if (r == NULL) return -1;\n";
3632 pr " print_table (r);\n";
3633 pr " free_strings (r);\n";
3640 (* run_action function *)
3641 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3644 fun (name, _, _, flags, _, _, _) ->
3645 let name2 = replace_char name '_' '-' in
3647 try find_map (function FishAlias n -> Some n | _ -> None) flags
3648 with Not_found -> name in
3650 pr "strcasecmp (cmd, \"%s\") == 0" name;
3651 if name <> name2 then
3652 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3653 if name <> alias then
3654 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3656 pr " return run_%s (cmd, argc, argv);\n" name;
3660 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3667 (* Readline completion for guestfish. *)
3668 and generate_fish_completion () =
3669 generate_header CStyle GPLv2;
3673 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3683 #ifdef HAVE_LIBREADLINE
3684 #include <readline/readline.h>
3689 #ifdef HAVE_LIBREADLINE
3691 static const char *commands[] = {
3694 (* Get the commands and sort them, including the aliases. *)
3697 fun (name, _, _, flags, _, _, _) ->
3698 let name2 = replace_char name '_' '-' in
3700 try find_map (function FishAlias n -> Some n | _ -> None) flags
3701 with Not_found -> name in
3703 if name <> alias then [name2; alias] else [name2]
3705 let commands = List.flatten commands in
3706 let commands = List.sort compare commands in
3708 List.iter (pr " \"%s\",\n") commands;
3714 generator (const char *text, int state)
3716 static int index, len;
3721 len = strlen (text);
3724 while ((name = commands[index]) != NULL) {
3726 if (strncasecmp (name, text, len) == 0)
3727 return strdup (name);
3733 #endif /* HAVE_LIBREADLINE */
3735 char **do_completion (const char *text, int start, int end)
3737 char **matches = NULL;
3739 #ifdef HAVE_LIBREADLINE
3741 matches = rl_completion_matches (text, generator);
3748 (* Generate the POD documentation for guestfish. *)
3749 and generate_fish_actions_pod () =
3750 let all_functions_sorted =
3752 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3753 ) all_functions_sorted in
3756 fun (name, style, _, flags, _, _, longdesc) ->
3757 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3758 let name = replace_char name '_' '-' in
3760 try find_map (function FishAlias n -> Some n | _ -> None) flags
3761 with Not_found -> name in
3763 pr "=head2 %s" name;
3764 if name <> alias then
3771 | String n -> pr " %s" n
3772 | OptString n -> pr " %s" n
3773 | StringList n -> pr " %s,..." n
3774 | Bool _ -> pr " true|false"
3775 | Int n -> pr " %s" n
3776 | FileIn n | FileOut n -> pr " (%s|-)" n
3780 pr "%s\n\n" longdesc;
3782 if List.exists (function FileIn _ | FileOut _ -> true
3783 | _ -> false) (snd style) then
3784 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
3786 if List.mem ProtocolLimitWarning flags then
3787 pr "%s\n\n" protocol_limit_warning;
3789 if List.mem DangerWillRobinson flags then
3790 pr "%s\n\n" danger_will_robinson
3791 ) all_functions_sorted
3793 (* Generate a C function prototype. *)
3794 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3795 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3797 ?handle name style =
3798 if extern then pr "extern ";
3799 if static then pr "static ";
3800 (match fst style with
3802 | RInt _ -> pr "int "
3803 | RInt64 _ -> pr "int64_t "
3804 | RBool _ -> pr "int "
3805 | RConstString _ -> pr "const char *"
3806 | RString _ -> pr "char *"
3807 | RStringList _ | RHashtable _ -> pr "char **"
3809 if not in_daemon then pr "struct guestfs_int_bool *"
3810 else pr "guestfs_%s_ret *" name
3812 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3813 else pr "guestfs_lvm_int_pv_list *"
3815 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3816 else pr "guestfs_lvm_int_vg_list *"
3818 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3819 else pr "guestfs_lvm_int_lv_list *"
3821 if not in_daemon then pr "struct guestfs_stat *"
3822 else pr "guestfs_int_stat *"
3824 if not in_daemon then pr "struct guestfs_statvfs *"
3825 else pr "guestfs_int_statvfs *"
3827 pr "%s%s (" prefix name;
3828 if handle = None && List.length (snd style) = 0 then
3831 let comma = ref false in
3834 | Some handle -> pr "guestfs_h *%s" handle; comma := true
3838 if single_line then pr ", " else pr ",\n\t\t"
3845 | OptString n -> next (); pr "const char *%s" n
3846 | StringList n -> next (); pr "char * const* const %s" n
3847 | Bool n -> next (); pr "int %s" n
3848 | Int n -> next (); pr "int %s" n
3851 if not in_daemon then (next (); pr "const char *%s" n)
3855 if semicolon then pr ";";
3856 if newline then pr "\n"
3858 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3859 and generate_call_args ?handle args =
3861 let comma = ref false in
3864 | Some handle -> pr "%s" handle; comma := true
3868 if !comma then pr ", ";
3870 pr "%s" (name_of_argt arg)
3874 (* Generate the OCaml bindings interface. *)
3875 and generate_ocaml_mli () =
3876 generate_header OCamlStyle LGPLv2;
3879 (** For API documentation you should refer to the C API
3880 in the guestfs(3) manual page. The OCaml API uses almost
3881 exactly the same calls. *)
3884 (** A [guestfs_h] handle. *)
3886 exception Error of string
3887 (** This exception is raised when there is an error. *)
3889 val create : unit -> t
3891 val close : t -> unit
3892 (** Handles are closed by the garbage collector when they become
3893 unreferenced, but callers can also call this in order to
3894 provide predictable cleanup. *)
3897 generate_ocaml_lvm_structure_decls ();
3899 generate_ocaml_stat_structure_decls ();
3903 fun (name, style, _, _, _, shortdesc, _) ->
3904 generate_ocaml_prototype name style;
3905 pr "(** %s *)\n" shortdesc;
3909 (* Generate the OCaml bindings implementation. *)
3910 and generate_ocaml_ml () =
3911 generate_header OCamlStyle LGPLv2;
3915 exception Error of string
3916 external create : unit -> t = \"ocaml_guestfs_create\"
3917 external close : t -> unit = \"ocaml_guestfs_close\"
3920 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3924 generate_ocaml_lvm_structure_decls ();
3926 generate_ocaml_stat_structure_decls ();
3930 fun (name, style, _, _, _, shortdesc, _) ->
3931 generate_ocaml_prototype ~is_external:true name style;
3934 (* Generate the OCaml bindings C implementation. *)
3935 and generate_ocaml_c () =
3936 generate_header CStyle LGPLv2;
3943 #include <caml/config.h>
3944 #include <caml/alloc.h>
3945 #include <caml/callback.h>
3946 #include <caml/fail.h>
3947 #include <caml/memory.h>
3948 #include <caml/mlvalues.h>
3949 #include <caml/signals.h>
3951 #include <guestfs.h>
3953 #include \"guestfs_c.h\"
3955 /* Copy a hashtable of string pairs into an assoc-list. We return
3956 * the list in reverse order, but hashtables aren't supposed to be
3959 static CAMLprim value
3960 copy_table (char * const * argv)
3963 CAMLlocal5 (rv, pairv, kv, vv, cons);
3967 for (i = 0; argv[i] != NULL; i += 2) {
3968 kv = caml_copy_string (argv[i]);
3969 vv = caml_copy_string (argv[i+1]);
3970 pairv = caml_alloc (2, 0);
3971 Store_field (pairv, 0, kv);
3972 Store_field (pairv, 1, vv);
3973 cons = caml_alloc (2, 0);
3974 Store_field (cons, 1, rv);
3976 Store_field (cons, 0, pairv);
3984 (* LVM struct copy functions. *)
3987 let has_optpercent_col =
3988 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
3990 pr "static CAMLprim value\n";
3991 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
3993 pr " CAMLparam0 ();\n";
3994 if has_optpercent_col then
3995 pr " CAMLlocal3 (rv, v, v2);\n"
3997 pr " CAMLlocal2 (rv, v);\n";
3999 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
4004 pr " v = caml_copy_string (%s->%s);\n" typ name
4006 pr " v = caml_alloc_string (32);\n";
4007 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
4010 pr " v = caml_copy_int64 (%s->%s);\n" typ name
4011 | name, `OptPercent ->
4012 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
4013 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
4014 pr " v = caml_alloc (1, 0);\n";
4015 pr " Store_field (v, 0, v2);\n";
4016 pr " } else /* None */\n";
4017 pr " v = Val_int (0);\n";
4019 pr " Store_field (rv, %d, v);\n" i
4021 pr " CAMLreturn (rv);\n";
4025 pr "static CAMLprim value\n";
4026 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
4029 pr " CAMLparam0 ();\n";
4030 pr " CAMLlocal2 (rv, v);\n";
4033 pr " if (%ss->len == 0)\n" typ;
4034 pr " CAMLreturn (Atom (0));\n";
4036 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
4037 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
4038 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
4039 pr " caml_modify (&Field (rv, i), v);\n";
4041 pr " CAMLreturn (rv);\n";
4045 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4047 (* Stat copy functions. *)
4050 pr "static CAMLprim value\n";
4051 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
4053 pr " CAMLparam0 ();\n";
4054 pr " CAMLlocal2 (rv, v);\n";
4056 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
4061 pr " v = caml_copy_int64 (%s->%s);\n" typ name
4063 pr " Store_field (rv, %d, v);\n" i
4065 pr " CAMLreturn (rv);\n";
4068 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4072 fun (name, style, _, _, _, _, _) ->
4074 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
4076 pr "CAMLprim value\n";
4077 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
4078 List.iter (pr ", value %s") (List.tl params);
4083 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
4084 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
4085 pr " CAMLxparam%d (%s);\n"
4086 (List.length rest) (String.concat ", " rest)
4088 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
4090 pr " CAMLlocal1 (rv);\n";
4093 pr " guestfs_h *g = Guestfs_val (gv);\n";
4094 pr " if (g == NULL)\n";
4095 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
4103 pr " const char *%s = String_val (%sv);\n" n n
4105 pr " const char *%s =\n" n;
4106 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
4109 pr " char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
4111 pr " int %s = Bool_val (%sv);\n" n n
4113 pr " int %s = Int_val (%sv);\n" n n
4116 match fst style with
4117 | RErr -> pr " int r;\n"; "-1"
4118 | RInt _ -> pr " int r;\n"; "-1"
4119 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4120 | RBool _ -> pr " int r;\n"; "-1"
4121 | RConstString _ -> pr " const char *r;\n"; "NULL"
4122 | RString _ -> pr " char *r;\n"; "NULL"
4128 pr " struct guestfs_int_bool *r;\n"; "NULL"
4130 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4132 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4134 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4136 pr " struct guestfs_stat *r;\n"; "NULL"
4138 pr " struct guestfs_statvfs *r;\n"; "NULL"
4145 pr " caml_enter_blocking_section ();\n";
4146 pr " r = guestfs_%s " name;
4147 generate_call_args ~handle:"g" (snd style);
4149 pr " caml_leave_blocking_section ();\n";
4154 pr " ocaml_guestfs_free_strings (%s);\n" n;
4155 | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
4158 pr " if (r == %s)\n" error_code;
4159 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
4162 (match fst style with
4163 | RErr -> pr " rv = Val_unit;\n"
4164 | RInt _ -> pr " rv = Val_int (r);\n"
4166 pr " rv = caml_copy_int64 (r);\n"
4167 | RBool _ -> pr " rv = Val_bool (r);\n"
4168 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
4170 pr " rv = caml_copy_string (r);\n";
4173 pr " rv = caml_copy_string_array ((const char **) r);\n";
4174 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4177 pr " rv = caml_alloc (2, 0);\n";
4178 pr " Store_field (rv, 0, Val_int (r->i));\n";
4179 pr " Store_field (rv, 1, Val_bool (r->b));\n";
4180 pr " guestfs_free_int_bool (r);\n";
4182 pr " rv = copy_lvm_pv_list (r);\n";
4183 pr " guestfs_free_lvm_pv_list (r);\n";
4185 pr " rv = copy_lvm_vg_list (r);\n";
4186 pr " guestfs_free_lvm_vg_list (r);\n";
4188 pr " rv = copy_lvm_lv_list (r);\n";
4189 pr " guestfs_free_lvm_lv_list (r);\n";
4191 pr " rv = copy_stat (r);\n";
4194 pr " rv = copy_statvfs (r);\n";
4197 pr " rv = copy_table (r);\n";
4198 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4202 pr " CAMLreturn (rv);\n";
4206 if List.length params > 5 then (
4207 pr "CAMLprim value\n";
4208 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
4210 pr " return ocaml_guestfs_%s (argv[0]" name;
4211 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
4218 and generate_ocaml_lvm_structure_decls () =
4221 pr "type lvm_%s = {\n" typ;
4224 | name, `String -> pr " %s : string;\n" name
4225 | name, `UUID -> pr " %s : string;\n" name
4226 | name, `Bytes -> pr " %s : int64;\n" name
4227 | name, `Int -> pr " %s : int64;\n" name
4228 | name, `OptPercent -> pr " %s : float option;\n" name
4232 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4234 and generate_ocaml_stat_structure_decls () =
4237 pr "type %s = {\n" typ;
4240 | name, `Int -> pr " %s : int64;\n" name
4244 ) ["stat", stat_cols; "statvfs", statvfs_cols]
4246 and generate_ocaml_prototype ?(is_external = false) name style =
4247 if is_external then pr "external " else pr "val ";
4248 pr "%s : t -> " name;
4251 | String _ | FileIn _ | FileOut _ -> pr "string -> "
4252 | OptString _ -> pr "string option -> "
4253 | StringList _ -> pr "string array -> "
4254 | Bool _ -> pr "bool -> "
4255 | Int _ -> pr "int -> "
4257 (match fst style with
4258 | RErr -> pr "unit" (* all errors are turned into exceptions *)
4259 | RInt _ -> pr "int"
4260 | RInt64 _ -> pr "int64"
4261 | RBool _ -> pr "bool"
4262 | RConstString _ -> pr "string"
4263 | RString _ -> pr "string"
4264 | RStringList _ -> pr "string array"
4265 | RIntBool _ -> pr "int * bool"
4266 | RPVList _ -> pr "lvm_pv array"
4267 | RVGList _ -> pr "lvm_vg array"
4268 | RLVList _ -> pr "lvm_lv array"
4269 | RStat _ -> pr "stat"
4270 | RStatVFS _ -> pr "statvfs"
4271 | RHashtable _ -> pr "(string * string) list"
4273 if is_external then (
4275 if List.length (snd style) + 1 > 5 then
4276 pr "\"ocaml_guestfs_%s_byte\" " name;
4277 pr "\"ocaml_guestfs_%s\"" name
4281 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
4282 and generate_perl_xs () =
4283 generate_header CStyle LGPLv2;
4286 #include \"EXTERN.h\"
4290 #include <guestfs.h>
4293 #define PRId64 \"lld\"
4297 my_newSVll(long long val) {
4298 #ifdef USE_64_BIT_ALL
4299 return newSViv(val);
4303 len = snprintf(buf, 100, \"%%\" PRId64, val);
4304 return newSVpv(buf, len);
4309 #define PRIu64 \"llu\"
4313 my_newSVull(unsigned long long val) {
4314 #ifdef USE_64_BIT_ALL
4315 return newSVuv(val);
4319 len = snprintf(buf, 100, \"%%\" PRIu64, val);
4320 return newSVpv(buf, len);
4324 /* http://www.perlmonks.org/?node_id=680842 */
4326 XS_unpack_charPtrPtr (SV *arg) {
4331 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
4332 croak (\"array reference expected\");
4335 av = (AV *)SvRV (arg);
4336 ret = (char **)malloc (av_len (av) + 1 + 1);
4338 for (i = 0; i <= av_len (av); i++) {
4339 SV **elem = av_fetch (av, i, 0);
4341 if (!elem || !*elem)
4342 croak (\"missing element in list\");
4344 ret[i] = SvPV_nolen (*elem);
4352 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
4357 RETVAL = guestfs_create ();
4359 croak (\"could not create guestfs handle\");
4360 guestfs_set_error_handler (RETVAL, NULL, NULL);
4373 fun (name, style, _, _, _, _, _) ->
4374 (match fst style with
4375 | RErr -> pr "void\n"
4376 | RInt _ -> pr "SV *\n"
4377 | RInt64 _ -> pr "SV *\n"
4378 | RBool _ -> pr "SV *\n"
4379 | RConstString _ -> pr "SV *\n"
4380 | RString _ -> pr "SV *\n"
4383 | RPVList _ | RVGList _ | RLVList _
4384 | RStat _ | RStatVFS _
4386 pr "void\n" (* all lists returned implictly on the stack *)
4388 (* Call and arguments. *)
4390 generate_call_args ~handle:"g" (snd style);
4392 pr " guestfs_h *g;\n";
4395 | String n | FileIn n | FileOut n -> pr " char *%s;\n" n
4396 | OptString n -> pr " char *%s;\n" n
4397 | StringList n -> pr " char **%s;\n" n
4398 | Bool n -> pr " int %s;\n" n
4399 | Int n -> pr " int %s;\n" n
4402 let do_cleanups () =
4405 | String _ | OptString _ | Bool _ | Int _
4406 | FileIn _ | FileOut _ -> ()
4407 | StringList n -> pr " free (%s);\n" n
4412 (match fst style with
4417 pr " r = guestfs_%s " name;
4418 generate_call_args ~handle:"g" (snd style);
4421 pr " if (r == -1)\n";
4422 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4428 pr " %s = guestfs_%s " n name;
4429 generate_call_args ~handle:"g" (snd style);
4432 pr " if (%s == -1)\n" n;
4433 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4434 pr " RETVAL = newSViv (%s);\n" n;
4439 pr " int64_t %s;\n" n;
4441 pr " %s = guestfs_%s " n name;
4442 generate_call_args ~handle:"g" (snd style);
4445 pr " if (%s == -1)\n" n;
4446 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4447 pr " RETVAL = my_newSVll (%s);\n" n;
4452 pr " const char *%s;\n" n;
4454 pr " %s = guestfs_%s " n name;
4455 generate_call_args ~handle:"g" (snd style);
4458 pr " if (%s == NULL)\n" n;
4459 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4460 pr " RETVAL = newSVpv (%s, 0);\n" n;
4465 pr " char *%s;\n" n;
4467 pr " %s = guestfs_%s " n name;
4468 generate_call_args ~handle:"g" (snd style);
4471 pr " if (%s == NULL)\n" n;
4472 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4473 pr " RETVAL = newSVpv (%s, 0);\n" n;
4474 pr " free (%s);\n" n;
4477 | RStringList n | RHashtable n ->
4479 pr " char **%s;\n" n;
4482 pr " %s = guestfs_%s " n name;
4483 generate_call_args ~handle:"g" (snd style);
4486 pr " if (%s == NULL)\n" n;
4487 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4488 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
4489 pr " EXTEND (SP, n);\n";
4490 pr " for (i = 0; i < n; ++i) {\n";
4491 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
4492 pr " free (%s[i]);\n" n;
4494 pr " free (%s);\n" n;
4497 pr " struct guestfs_int_bool *r;\n";
4499 pr " r = guestfs_%s " name;
4500 generate_call_args ~handle:"g" (snd style);
4503 pr " if (r == NULL)\n";
4504 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4505 pr " EXTEND (SP, 2);\n";
4506 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
4507 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
4508 pr " guestfs_free_int_bool (r);\n";
4510 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
4512 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
4514 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
4516 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
4518 generate_perl_stat_code
4519 "statvfs" statvfs_cols name style n do_cleanups
4525 and generate_perl_lvm_code typ cols name style n do_cleanups =
4527 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
4531 pr " %s = guestfs_%s " n name;
4532 generate_call_args ~handle:"g" (snd style);
4535 pr " if (%s == NULL)\n" n;
4536 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4537 pr " EXTEND (SP, %s->len);\n" n;
4538 pr " for (i = 0; i < %s->len; ++i) {\n" n;
4539 pr " hv = newHV ();\n";
4543 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
4544 name (String.length name) n name
4546 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
4547 name (String.length name) n name
4549 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
4550 name (String.length name) n name
4552 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
4553 name (String.length name) n name
4554 | name, `OptPercent ->
4555 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
4556 name (String.length name) n name
4558 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
4560 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
4562 and generate_perl_stat_code typ cols name style n do_cleanups =
4564 pr " struct guestfs_%s *%s;\n" typ n;
4566 pr " %s = guestfs_%s " n name;
4567 generate_call_args ~handle:"g" (snd style);
4570 pr " if (%s == NULL)\n" n;
4571 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4572 pr " EXTEND (SP, %d);\n" (List.length cols);
4576 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
4578 pr " free (%s);\n" n
4580 (* Generate Sys/Guestfs.pm. *)
4581 and generate_perl_pm () =
4582 generate_header HashStyle LGPLv2;
4589 Sys::Guestfs - Perl bindings for libguestfs
4595 my $h = Sys::Guestfs->new ();
4596 $h->add_drive ('guest.img');
4599 $h->mount ('/dev/sda1', '/');
4600 $h->touch ('/hello');
4605 The C<Sys::Guestfs> module provides a Perl XS binding to the
4606 libguestfs API for examining and modifying virtual machine
4609 Amongst the things this is good for: making batch configuration
4610 changes to guests, getting disk used/free statistics (see also:
4611 virt-df), migrating between virtualization systems (see also:
4612 virt-p2v), performing partial backups, performing partial guest
4613 clones, cloning guests and changing registry/UUID/hostname info, and
4616 Libguestfs uses Linux kernel and qemu code, and can access any type of
4617 guest filesystem that Linux and qemu can, including but not limited
4618 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
4619 schemes, qcow, qcow2, vmdk.
4621 Libguestfs provides ways to enumerate guest storage (eg. partitions,
4622 LVs, what filesystem is in each LV, etc.). It can also run commands
4623 in the context of the guest. Also you can access filesystems over FTP.
4627 All errors turn into calls to C<croak> (see L<Carp(3)>).
4635 package Sys::Guestfs;
4641 XSLoader::load ('Sys::Guestfs');
4643 =item $h = Sys::Guestfs->new ();
4645 Create a new guestfs handle.
4651 my $class = ref ($proto) || $proto;
4653 my $self = Sys::Guestfs::_create ();
4654 bless $self, $class;
4660 (* Actions. We only need to print documentation for these as
4661 * they are pulled in from the XS code automatically.
4664 fun (name, style, _, flags, _, _, longdesc) ->
4665 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
4667 generate_perl_prototype name style;
4669 pr "%s\n\n" longdesc;
4670 if List.mem ProtocolLimitWarning flags then
4671 pr "%s\n\n" protocol_limit_warning;
4672 if List.mem DangerWillRobinson flags then
4673 pr "%s\n\n" danger_will_robinson
4674 ) all_functions_sorted;
4686 Copyright (C) 2009 Red Hat Inc.
4690 Please see the file COPYING.LIB for the full license.
4694 L<guestfs(3)>, L<guestfish(1)>.
4699 and generate_perl_prototype name style =
4700 (match fst style with
4706 | RString n -> pr "$%s = " n
4707 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4711 | RLVList n -> pr "@%s = " n
4714 | RHashtable n -> pr "%%%s = " n
4717 let comma = ref false in
4720 if !comma then pr ", ";
4723 | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
4730 (* Generate Python C module. *)
4731 and generate_python_c () =
4732 generate_header CStyle LGPLv2;
4741 #include \"guestfs.h\"
4749 get_handle (PyObject *obj)
4752 assert (obj != Py_None);
4753 return ((Pyguestfs_Object *) obj)->g;
4757 put_handle (guestfs_h *g)
4761 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4764 /* This list should be freed (but not the strings) after use. */
4765 static const char **
4766 get_string_list (PyObject *obj)
4773 if (!PyList_Check (obj)) {
4774 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4778 len = PyList_Size (obj);
4779 r = malloc (sizeof (char *) * (len+1));
4781 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4785 for (i = 0; i < len; ++i)
4786 r[i] = PyString_AsString (PyList_GetItem (obj, i));
4793 put_string_list (char * const * const argv)
4798 for (argc = 0; argv[argc] != NULL; ++argc)
4801 list = PyList_New (argc);
4802 for (i = 0; i < argc; ++i)
4803 PyList_SetItem (list, i, PyString_FromString (argv[i]));
4809 put_table (char * const * const argv)
4811 PyObject *list, *item;
4814 for (argc = 0; argv[argc] != NULL; ++argc)
4817 list = PyList_New (argc >> 1);
4818 for (i = 0; i < argc; i += 2) {
4819 item = PyTuple_New (2);
4820 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
4821 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
4822 PyList_SetItem (list, i >> 1, item);
4829 free_strings (char **argv)
4833 for (argc = 0; argv[argc] != NULL; ++argc)
4839 py_guestfs_create (PyObject *self, PyObject *args)
4843 g = guestfs_create ();
4845 PyErr_SetString (PyExc_RuntimeError,
4846 \"guestfs.create: failed to allocate handle\");
4849 guestfs_set_error_handler (g, NULL, NULL);
4850 return put_handle (g);
4854 py_guestfs_close (PyObject *self, PyObject *args)
4859 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4861 g = get_handle (py_g);
4865 Py_INCREF (Py_None);
4871 (* LVM structures, turned into Python dictionaries. *)
4874 pr "static PyObject *\n";
4875 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4877 pr " PyObject *dict;\n";
4879 pr " dict = PyDict_New ();\n";
4883 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4884 pr " PyString_FromString (%s->%s));\n"
4887 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4888 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
4891 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4892 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
4895 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4896 pr " PyLong_FromLongLong (%s->%s));\n"
4898 | name, `OptPercent ->
4899 pr " if (%s->%s >= 0)\n" typ name;
4900 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4901 pr " PyFloat_FromDouble ((double) %s->%s));\n"
4904 pr " Py_INCREF (Py_None);\n";
4905 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
4908 pr " return dict;\n";
4912 pr "static PyObject *\n";
4913 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
4915 pr " PyObject *list;\n";
4918 pr " list = PyList_New (%ss->len);\n" typ;
4919 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4920 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
4921 pr " return list;\n";
4924 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4926 (* Stat structures, turned into Python dictionaries. *)
4929 pr "static PyObject *\n";
4930 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
4932 pr " PyObject *dict;\n";
4934 pr " dict = PyDict_New ();\n";
4938 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4939 pr " PyLong_FromLongLong (%s->%s));\n"
4942 pr " return dict;\n";
4945 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4947 (* Python wrapper functions. *)
4949 fun (name, style, _, _, _, _, _) ->
4950 pr "static PyObject *\n";
4951 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
4954 pr " PyObject *py_g;\n";
4955 pr " guestfs_h *g;\n";
4956 pr " PyObject *py_r;\n";
4959 match fst style with
4960 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4961 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4962 | RConstString _ -> pr " const char *r;\n"; "NULL"
4963 | RString _ -> pr " char *r;\n"; "NULL"
4964 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
4965 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
4966 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4967 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4968 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4969 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
4970 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
4974 | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n
4975 | OptString n -> pr " const char *%s;\n" n
4977 pr " PyObject *py_%s;\n" n;
4978 pr " const char **%s;\n" n
4979 | Bool n -> pr " int %s;\n" n
4980 | Int n -> pr " int %s;\n" n
4985 (* Convert the parameters. *)
4986 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
4989 | String _ | FileIn _ | FileOut _ -> pr "s"
4990 | OptString _ -> pr "z"
4991 | StringList _ -> pr "O"
4992 | Bool _ -> pr "i" (* XXX Python has booleans? *)
4995 pr ":guestfs_%s\",\n" name;
4999 | String n | FileIn n | FileOut n -> pr ", &%s" n
5000 | OptString n -> pr ", &%s" n
5001 | StringList n -> pr ", &py_%s" n
5002 | Bool n -> pr ", &%s" n
5003 | Int n -> pr ", &%s" n
5007 pr " return NULL;\n";
5009 pr " g = get_handle (py_g);\n";
5012 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5014 pr " %s = get_string_list (py_%s);\n" n n;
5015 pr " if (!%s) return NULL;\n" n
5020 pr " r = guestfs_%s " name;
5021 generate_call_args ~handle:"g" (snd style);
5026 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5028 pr " free (%s);\n" n
5031 pr " if (r == %s) {\n" error_code;
5032 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
5033 pr " return NULL;\n";
5037 (match fst style with
5039 pr " Py_INCREF (Py_None);\n";
5040 pr " py_r = Py_None;\n"
5042 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
5043 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
5044 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
5046 pr " py_r = PyString_FromString (r);\n";
5049 pr " py_r = put_string_list (r);\n";
5050 pr " free_strings (r);\n"
5052 pr " py_r = PyTuple_New (2);\n";
5053 pr " PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
5054 pr " PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
5055 pr " guestfs_free_int_bool (r);\n"
5057 pr " py_r = put_lvm_pv_list (r);\n";
5058 pr " guestfs_free_lvm_pv_list (r);\n"
5060 pr " py_r = put_lvm_vg_list (r);\n";
5061 pr " guestfs_free_lvm_vg_list (r);\n"
5063 pr " py_r = put_lvm_lv_list (r);\n";
5064 pr " guestfs_free_lvm_lv_list (r);\n"
5066 pr " py_r = put_stat (r);\n";
5069 pr " py_r = put_statvfs (r);\n";
5072 pr " py_r = put_table (r);\n";
5073 pr " free_strings (r);\n"
5076 pr " return py_r;\n";
5081 (* Table of functions. *)
5082 pr "static PyMethodDef methods[] = {\n";
5083 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
5084 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
5086 fun (name, _, _, _, _, _, _) ->
5087 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
5090 pr " { NULL, NULL, 0, NULL }\n";
5094 (* Init function. *)
5097 initlibguestfsmod (void)
5099 static int initialized = 0;
5101 if (initialized) return;
5102 Py_InitModule ((char *) \"libguestfsmod\", methods);
5107 (* Generate Python module. *)
5108 and generate_python_py () =
5109 generate_header HashStyle LGPLv2;
5112 u\"\"\"Python bindings for libguestfs
5115 g = guestfs.GuestFS ()
5116 g.add_drive (\"guest.img\")
5119 parts = g.list_partitions ()
5121 The guestfs module provides a Python binding to the libguestfs API
5122 for examining and modifying virtual machine disk images.
5124 Amongst the things this is good for: making batch configuration
5125 changes to guests, getting disk used/free statistics (see also:
5126 virt-df), migrating between virtualization systems (see also:
5127 virt-p2v), performing partial backups, performing partial guest
5128 clones, cloning guests and changing registry/UUID/hostname info, and
5131 Libguestfs uses Linux kernel and qemu code, and can access any type of
5132 guest filesystem that Linux and qemu can, including but not limited
5133 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5134 schemes, qcow, qcow2, vmdk.
5136 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5137 LVs, what filesystem is in each LV, etc.). It can also run commands
5138 in the context of the guest. Also you can access filesystems over FTP.
5140 Errors which happen while using the API are turned into Python
5141 RuntimeError exceptions.
5143 To create a guestfs handle you usually have to perform the following
5146 # Create the handle, call add_drive at least once, and possibly
5147 # several times if the guest has multiple block devices:
5148 g = guestfs.GuestFS ()
5149 g.add_drive (\"guest.img\")
5151 # Launch the qemu subprocess and wait for it to become ready:
5155 # Now you can issue commands, for example:
5160 import libguestfsmod
5163 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
5165 def __init__ (self):
5166 \"\"\"Create a new libguestfs handle.\"\"\"
5167 self._o = libguestfsmod.create ()
5170 libguestfsmod.close (self._o)
5175 fun (name, style, _, flags, _, _, longdesc) ->
5176 let doc = replace_str longdesc "C<guestfs_" "C<g." in
5178 match fst style with
5179 | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
5182 doc ^ "\n\nThis function returns a list of strings."
5184 doc ^ "\n\nThis function returns a tuple (int, bool).\n"
5186 doc ^ "\n\nThis function returns a list of PVs. Each PV is represented as a dictionary."
5188 doc ^ "\n\nThis function returns a list of VGs. Each VG is represented as a dictionary."
5190 doc ^ "\n\nThis function returns a list of LVs. Each LV is represented as a dictionary."
5192 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
5194 doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
5196 doc ^ "\n\nThis function returns a dictionary." in
5198 if List.mem ProtocolLimitWarning flags then
5199 doc ^ "\n\n" ^ protocol_limit_warning
5202 if List.mem DangerWillRobinson flags then
5203 doc ^ "\n\n" ^ danger_will_robinson
5205 let doc = pod2text ~width:60 name doc in
5206 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
5207 let doc = String.concat "\n " doc in
5210 generate_call_args ~handle:"self" (snd style);
5212 pr " u\"\"\"%s\"\"\"\n" doc;
5213 pr " return libguestfsmod.%s " name;
5214 generate_call_args ~handle:"self._o" (snd style);
5219 (* Useful if you need the longdesc POD text as plain text. Returns a
5222 and pod2text ~width name longdesc =
5223 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
5224 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
5226 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
5227 let chan = Unix.open_process_in cmd in
5228 let lines = ref [] in
5230 let line = input_line chan in
5231 if i = 1 then (* discard the first line of output *)
5234 let line = triml line in
5235 lines := line :: !lines;
5238 let lines = try loop 1 with End_of_file -> List.rev !lines in
5239 Unix.unlink filename;
5240 match Unix.close_process_in chan with
5241 | Unix.WEXITED 0 -> lines
5243 failwithf "pod2text: process exited with non-zero status (%d)" i
5244 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
5245 failwithf "pod2text: process signalled or stopped by signal %d" i
5247 (* Generate ruby bindings. *)
5248 and generate_ruby_c () =
5249 generate_header CStyle LGPLv2;
5257 #include \"guestfs.h\"
5259 #include \"extconf.h\"
5261 static VALUE m_guestfs; /* guestfs module */
5262 static VALUE c_guestfs; /* guestfs_h handle */
5263 static VALUE e_Error; /* used for all errors */
5265 static void ruby_guestfs_free (void *p)
5268 guestfs_close ((guestfs_h *) p);
5271 static VALUE ruby_guestfs_create (VALUE m)
5275 g = guestfs_create ();
5277 rb_raise (e_Error, \"failed to create guestfs handle\");
5279 /* Don't print error messages to stderr by default. */
5280 guestfs_set_error_handler (g, NULL, NULL);
5282 /* Wrap it, and make sure the close function is called when the
5285 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
5288 static VALUE ruby_guestfs_close (VALUE gv)
5291 Data_Get_Struct (gv, guestfs_h, g);
5293 ruby_guestfs_free (g);
5294 DATA_PTR (gv) = NULL;
5302 fun (name, style, _, _, _, _, _) ->
5303 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
5304 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
5307 pr " guestfs_h *g;\n";
5308 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
5310 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
5316 | String n | FileIn n | FileOut n ->
5317 pr " const char *%s = StringValueCStr (%sv);\n" n n;
5319 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
5320 pr " \"%s\", \"%s\");\n" n name
5322 pr " const char *%s = StringValueCStr (%sv);\n" n n
5326 pr " int i, len;\n";
5327 pr " len = RARRAY_LEN (%sv);\n" n;
5328 pr " %s = malloc (sizeof (char *) * (len+1));\n" n;
5329 pr " for (i = 0; i < len; ++i) {\n";
5330 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
5331 pr " %s[i] = StringValueCStr (v);\n" n;
5336 pr " int %s = NUM2INT (%sv);\n" n n
5341 match fst style with
5342 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
5343 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5344 | RConstString _ -> pr " const char *r;\n"; "NULL"
5345 | RString _ -> pr " char *r;\n"; "NULL"
5346 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
5347 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
5348 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
5349 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
5350 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
5351 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
5352 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
5355 pr " r = guestfs_%s " name;
5356 generate_call_args ~handle:"g" (snd style);
5361 | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5363 pr " free (%s);\n" n
5366 pr " if (r == %s)\n" error_code;
5367 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
5370 (match fst style with
5372 pr " return Qnil;\n"
5373 | RInt _ | RBool _ ->
5374 pr " return INT2NUM (r);\n"
5376 pr " return ULL2NUM (r);\n"
5378 pr " return rb_str_new2 (r);\n";
5380 pr " VALUE rv = rb_str_new2 (r);\n";
5384 pr " int i, len = 0;\n";
5385 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
5386 pr " VALUE rv = rb_ary_new2 (len);\n";
5387 pr " for (i = 0; r[i] != NULL; ++i) {\n";
5388 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
5389 pr " free (r[i]);\n";
5394 pr " VALUE rv = rb_ary_new2 (2);\n";
5395 pr " rb_ary_push (rv, INT2NUM (r->i));\n";
5396 pr " rb_ary_push (rv, INT2NUM (r->b));\n";
5397 pr " guestfs_free_int_bool (r);\n";
5400 generate_ruby_lvm_code "pv" pv_cols
5402 generate_ruby_lvm_code "vg" vg_cols
5404 generate_ruby_lvm_code "lv" lv_cols
5406 pr " VALUE rv = rb_hash_new ();\n";
5410 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5415 pr " VALUE rv = rb_hash_new ();\n";
5419 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5424 pr " VALUE rv = rb_hash_new ();\n";
5426 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
5427 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
5428 pr " free (r[i]);\n";
5429 pr " free (r[i+1]);\n";
5440 /* Initialize the module. */
5441 void Init__guestfs ()
5443 m_guestfs = rb_define_module (\"Guestfs\");
5444 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
5445 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
5447 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
5448 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
5451 (* Define the rest of the methods. *)
5453 fun (name, style, _, _, _, _, _) ->
5454 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
5455 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
5460 (* Ruby code to return an LVM struct list. *)
5461 and generate_ruby_lvm_code typ cols =
5462 pr " VALUE rv = rb_ary_new2 (r->len);\n";
5464 pr " for (i = 0; i < r->len; ++i) {\n";
5465 pr " VALUE hv = rb_hash_new ();\n";
5469 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
5471 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
5474 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
5475 | name, `OptPercent ->
5476 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
5478 pr " rb_ary_push (rv, hv);\n";
5480 pr " guestfs_free_lvm_%s_list (r);\n" typ;
5483 let output_to filename =
5484 let filename_new = filename ^ ".new" in
5485 chan := open_out filename_new;
5489 Unix.rename filename_new filename;
5490 printf "written %s\n%!" filename;
5498 if not (Sys.file_exists "configure.ac") then (
5500 You are probably running this from the wrong directory.
5501 Run it from the top source directory using the command
5507 let close = output_to "src/guestfs_protocol.x" in
5511 let close = output_to "src/guestfs-structs.h" in
5512 generate_structs_h ();
5515 let close = output_to "src/guestfs-actions.h" in
5516 generate_actions_h ();
5519 let close = output_to "src/guestfs-actions.c" in
5520 generate_client_actions ();
5523 let close = output_to "daemon/actions.h" in
5524 generate_daemon_actions_h ();
5527 let close = output_to "daemon/stubs.c" in
5528 generate_daemon_actions ();
5531 let close = output_to "tests.c" in
5535 let close = output_to "fish/cmds.c" in
5536 generate_fish_cmds ();
5539 let close = output_to "fish/completion.c" in
5540 generate_fish_completion ();
5543 let close = output_to "guestfs-structs.pod" in
5544 generate_structs_pod ();
5547 let close = output_to "guestfs-actions.pod" in
5548 generate_actions_pod ();
5551 let close = output_to "guestfish-actions.pod" in
5552 generate_fish_actions_pod ();
5555 let close = output_to "ocaml/guestfs.mli" in
5556 generate_ocaml_mli ();
5559 let close = output_to "ocaml/guestfs.ml" in
5560 generate_ocaml_ml ();
5563 let close = output_to "ocaml/guestfs_c_actions.c" in
5564 generate_ocaml_c ();
5567 let close = output_to "perl/Guestfs.xs" in
5568 generate_perl_xs ();
5571 let close = output_to "perl/lib/Sys/Guestfs.pm" in
5572 generate_perl_pm ();
5575 let close = output_to "python/guestfs-py.c" in
5576 generate_python_c ();
5579 let close = output_to "python/guestfs.py" in
5580 generate_python_py ();
5583 let close = output_to "ruby/ext/guestfs/_guestfs.c" in