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.
49 (* "RBool" is a bool return value which can be true/false or
53 (* "RConstString" is a string that refers to a constant value.
54 * Try to avoid using this. In particular you cannot use this
55 * for values returned from the daemon, because there is no
56 * thread-safe way to return them in the C API.
58 | RConstString of string
59 (* "RString" and "RStringList" are caller-frees. *)
61 | RStringList of string
62 (* Some limited tuples are possible: *)
63 | RIntBool of string * string
64 (* LVM PVs, VGs and LVs. *)
71 and args = argt list (* Function parameters, guestfs handle is implicit. *)
73 (* Note in future we should allow a "variable args" parameter as
74 * the final parameter, to allow commands like
75 * chmod mode file [file(s)...]
76 * This is not implemented yet, but many commands (such as chmod)
77 * are currently defined with the argument order keeping this future
78 * possibility in mind.
81 | String of string (* const char *name, cannot be NULL *)
82 | OptString of string (* const char *name, may be NULL *)
83 | StringList of string(* list of strings (each string cannot be NULL) *)
84 | Bool of string (* boolean *)
85 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
88 | ProtocolLimitWarning (* display warning about protocol size limits *)
89 | DangerWillRobinson (* flags particularly dangerous commands *)
90 | FishAlias of string (* provide an alias for this cmd in guestfish *)
91 | FishAction of string (* call this function in guestfish *)
92 | NotInFish (* do not export via guestfish *)
94 let protocol_limit_warning =
95 "Because of the message protocol, there is a transfer limit
96 of somewhere between 2MB and 4MB. To transfer large files you should use
99 let danger_will_robinson =
100 "B<This command is dangerous. Without careful use you
101 can easily destroy all your data>."
103 (* You can supply zero or as many tests as you want per API call.
105 * Note that the test environment has 3 block devices, of size 500MB,
106 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc).
107 * Note for partitioning purposes, the 500MB device has 63 cylinders.
109 * To be able to run the tests in a reasonable amount of time,
110 * the virtual machine and block devices are reused between tests.
111 * So don't try testing kill_subprocess :-x
113 * Between each test we umount-all and lvm-remove-all (except InitNone).
115 * Don't assume anything about the previous contents of the block
116 * devices. Use 'Init*' to create some initial scenarios.
118 type tests = (test_init * test) list
120 (* Run the command sequence and just expect nothing to fail. *)
122 (* Run the command sequence and expect the output of the final
123 * command to be the string.
125 | TestOutput of seq * string
126 (* Run the command sequence and expect the output of the final
127 * command to be the list of strings.
129 | TestOutputList of seq * string list
130 (* Run the command sequence and expect the output of the final
131 * command to be the integer.
133 | TestOutputInt of seq * int
134 (* Run the command sequence and expect the output of the final
135 * command to be a true value (!= 0 or != NULL).
137 | TestOutputTrue of seq
138 (* Run the command sequence and expect the output of the final
139 * command to be a false value (== 0 or == NULL, but not an error).
141 | TestOutputFalse of seq
142 (* Run the command sequence and expect the output of the final
143 * command to be a list of the given length (but don't care about
146 | TestOutputLength of seq * int
147 (* Run the command sequence and expect the output of the final
148 * command to be a structure.
150 | TestOutputStruct of seq * test_field_compare list
151 (* Run the command sequence and expect the final command (only)
154 | TestLastFail of seq
156 and test_field_compare =
157 | CompareWithInt of string * int
158 | CompareWithString of string * string
159 | CompareFieldsIntEq of string * string
160 | CompareFieldsStrEq of string * string
162 (* Some initial scenarios for testing. *)
164 (* Do nothing, block devices could contain random stuff including
165 * LVM PVs, and some filesystems might be mounted. This is usually
169 (* Block devices are empty and no filesystems are mounted. *)
171 (* /dev/sda contains a single partition /dev/sda1, which is formatted
172 * as ext2, empty [except for lost+found] and mounted on /.
173 * /dev/sdb and /dev/sdc may have random content.
178 * /dev/sda1 (is a PV):
179 * /dev/VG/LV (size 8MB):
180 * formatted as ext2, empty [except for lost+found], mounted on /
181 * /dev/sdb and /dev/sdc may have random content.
185 (* Sequence of commands for testing. *)
187 and cmd = string list
189 (* Note about long descriptions: When referring to another
190 * action, use the format C<guestfs_other> (ie. the full name of
191 * the C function). This will be replaced as appropriate in other
194 * Apart from that, long descriptions are just perldoc paragraphs.
197 let non_daemon_functions = [
198 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
200 "launch the qemu subprocess",
202 Internally libguestfs is implemented by running a virtual machine
205 You should call this after configuring the handle
206 (eg. adding drives) but before performing any actions.");
208 ("wait_ready", (RErr, []), -1, [NotInFish],
210 "wait until the qemu subprocess launches",
212 Internally libguestfs is implemented by running a virtual machine
215 You should call this after C<guestfs_launch> to wait for the launch
218 ("kill_subprocess", (RErr, []), -1, [],
220 "kill the qemu subprocess",
222 This kills the qemu subprocess. You should never need to call this.");
224 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
226 "add an image to examine or modify",
228 This function adds a virtual machine disk image C<filename> to the
229 guest. The first time you call this function, the disk appears as IDE
230 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
233 You don't necessarily need to be root when using libguestfs. However
234 you obviously do need sufficient permissions to access the filename
235 for whatever operations you want to perform (ie. read access if you
236 just want to read the image or write access if you want to modify the
239 This is equivalent to the qemu parameter C<-drive file=filename>.");
241 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
243 "add a CD-ROM disk image to examine",
245 This function adds a virtual CD-ROM disk image to the guest.
247 This is equivalent to the qemu parameter C<-cdrom filename>.");
249 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
251 "add qemu parameters",
253 This can be used to add arbitrary qemu command line parameters
254 of the form C<-param value>. Actually it's not quite arbitrary - we
255 prevent you from setting some parameters which would interfere with
256 parameters that we use.
258 The first character of C<param> string must be a C<-> (dash).
260 C<value> can be NULL.");
262 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
264 "set the search path",
266 Set the path that libguestfs searches for kernel and initrd.img.
268 The default is C<$libdir/guestfs> unless overridden by setting
269 C<LIBGUESTFS_PATH> environment variable.
271 The string C<path> is stashed in the libguestfs handle, so the caller
272 must make sure it remains valid for the lifetime of the handle.
274 Setting C<path> to C<NULL> restores the default path.");
276 ("get_path", (RConstString "path", []), -1, [],
278 "get the search path",
280 Return the current search path.
282 This is always non-NULL. If it wasn't set already, then this will
283 return the default path.");
285 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
289 If C<autosync> is true, this enables autosync. Libguestfs will make a
290 best effort attempt to run C<guestfs_sync> when the handle is closed
291 (also if the program exits without closing handles).");
293 ("get_autosync", (RBool "autosync", []), -1, [],
297 Get the autosync flag.");
299 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
303 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
305 Verbose messages are disabled unless the environment variable
306 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
308 ("get_verbose", (RBool "verbose", []), -1, [],
312 This returns the verbose messages flag.")
315 let daemon_functions = [
316 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
317 [InitEmpty, TestOutput (
318 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
319 ["mkfs"; "ext2"; "/dev/sda1"];
320 ["mount"; "/dev/sda1"; "/"];
321 ["write_file"; "/new"; "new file contents"; "0"];
322 ["cat"; "/new"]], "new file contents")],
323 "mount a guest disk at a position in the filesystem",
325 Mount a guest disk at a position in the filesystem. Block devices
326 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
327 the guest. If those block devices contain partitions, they will have
328 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
331 The rules are the same as for L<mount(2)>: A filesystem must
332 first be mounted on C</> before others can be mounted. Other
333 filesystems can only be mounted on directories which already
336 The mounted filesystem is writable, if we have sufficient permissions
337 on the underlying device.
339 The filesystem options C<sync> and C<noatime> are set with this
340 call, in order to improve reliability.");
342 ("sync", (RErr, []), 2, [],
343 [ InitEmpty, TestRun [["sync"]]],
344 "sync disks, writes are flushed through to the disk image",
346 This syncs the disk, so that any writes are flushed through to the
347 underlying disk image.
349 You should always call this if you have modified a disk image, before
350 closing the handle.");
352 ("touch", (RErr, [String "path"]), 3, [],
353 [InitBasicFS, TestOutputTrue (
355 ["exists"; "/new"]])],
356 "update file timestamps or create a new file",
358 Touch acts like the L<touch(1)> command. It can be used to
359 update the timestamps on a file, or, if the file does not exist,
360 to create a new zero-length file.");
362 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
363 [InitBasicFS, TestOutput (
364 [["write_file"; "/new"; "new file contents"; "0"];
365 ["cat"; "/new"]], "new file contents")],
366 "list the contents of a file",
368 Return the contents of the file named C<path>.
370 Note that this function cannot correctly handle binary files
371 (specifically, files containing C<\\0> character which is treated
372 as end of string). For those you need to use the C<guestfs_read_file>
373 function which has a more complex interface.");
375 ("ll", (RString "listing", [String "directory"]), 5, [],
376 [], (* XXX Tricky to test because it depends on the exact format
377 * of the 'ls -l' command, which changes between F10 and F11.
379 "list the files in a directory (long format)",
381 List the files in C<directory> (relative to the root directory,
382 there is no cwd) in the format of 'ls -la'.
384 This command is mostly useful for interactive sessions. It
385 is I<not> intended that you try to parse the output string.");
387 ("ls", (RStringList "listing", [String "directory"]), 6, [],
388 [InitBasicFS, TestOutputList (
391 ["touch"; "/newest"];
392 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
393 "list the files in a directory",
395 List the files in C<directory> (relative to the root directory,
396 there is no cwd). The '.' and '..' entries are not returned, but
397 hidden files are shown.
399 This command is mostly useful for interactive sessions. Programs
400 should probably use C<guestfs_readdir> instead.");
402 ("list_devices", (RStringList "devices", []), 7, [],
403 [InitEmpty, TestOutputList (
404 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
405 "list the block devices",
407 List all the block devices.
409 The full block device names are returned, eg. C</dev/sda>");
411 ("list_partitions", (RStringList "partitions", []), 8, [],
412 [InitBasicFS, TestOutputList (
413 [["list_partitions"]], ["/dev/sda1"]);
414 InitEmpty, TestOutputList (
415 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
416 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
417 "list the partitions",
419 List all the partitions detected on all block devices.
421 The full partition device names are returned, eg. C</dev/sda1>
423 This does not return logical volumes. For that you will need to
424 call C<guestfs_lvs>.");
426 ("pvs", (RStringList "physvols", []), 9, [],
427 [InitBasicFSonLVM, TestOutputList (
428 [["pvs"]], ["/dev/sda1"]);
429 InitEmpty, TestOutputList (
430 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
431 ["pvcreate"; "/dev/sda1"];
432 ["pvcreate"; "/dev/sda2"];
433 ["pvcreate"; "/dev/sda3"];
434 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
435 "list the LVM physical volumes (PVs)",
437 List all the physical volumes detected. This is the equivalent
438 of the L<pvs(8)> command.
440 This returns a list of just the device names that contain
441 PVs (eg. C</dev/sda2>).
443 See also C<guestfs_pvs_full>.");
445 ("vgs", (RStringList "volgroups", []), 10, [],
446 [InitBasicFSonLVM, TestOutputList (
448 InitEmpty, TestOutputList (
449 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
450 ["pvcreate"; "/dev/sda1"];
451 ["pvcreate"; "/dev/sda2"];
452 ["pvcreate"; "/dev/sda3"];
453 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
454 ["vgcreate"; "VG2"; "/dev/sda3"];
455 ["vgs"]], ["VG1"; "VG2"])],
456 "list the LVM volume groups (VGs)",
458 List all the volumes groups detected. This is the equivalent
459 of the L<vgs(8)> command.
461 This returns a list of just the volume group names that were
462 detected (eg. C<VolGroup00>).
464 See also C<guestfs_vgs_full>.");
466 ("lvs", (RStringList "logvols", []), 11, [],
467 [InitBasicFSonLVM, TestOutputList (
468 [["lvs"]], ["/dev/VG/LV"]);
469 InitEmpty, TestOutputList (
470 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
471 ["pvcreate"; "/dev/sda1"];
472 ["pvcreate"; "/dev/sda2"];
473 ["pvcreate"; "/dev/sda3"];
474 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
475 ["vgcreate"; "VG2"; "/dev/sda3"];
476 ["lvcreate"; "LV1"; "VG1"; "50"];
477 ["lvcreate"; "LV2"; "VG1"; "50"];
478 ["lvcreate"; "LV3"; "VG2"; "50"];
479 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
480 "list the LVM logical volumes (LVs)",
482 List all the logical volumes detected. This is the equivalent
483 of the L<lvs(8)> command.
485 This returns a list of the logical volume device names
486 (eg. C</dev/VolGroup00/LogVol00>).
488 See also C<guestfs_lvs_full>.");
490 ("pvs_full", (RPVList "physvols", []), 12, [],
491 [], (* XXX how to test? *)
492 "list the LVM physical volumes (PVs)",
494 List all the physical volumes detected. This is the equivalent
495 of the L<pvs(8)> command. The \"full\" version includes all fields.");
497 ("vgs_full", (RVGList "volgroups", []), 13, [],
498 [], (* XXX how to test? *)
499 "list the LVM volume groups (VGs)",
501 List all the volumes groups detected. This is the equivalent
502 of the L<vgs(8)> command. The \"full\" version includes all fields.");
504 ("lvs_full", (RLVList "logvols", []), 14, [],
505 [], (* XXX how to test? *)
506 "list the LVM logical volumes (LVs)",
508 List all the logical volumes detected. This is the equivalent
509 of the L<lvs(8)> command. The \"full\" version includes all fields.");
511 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
512 [InitBasicFS, TestOutputList (
513 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
514 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
515 InitBasicFS, TestOutputList (
516 [["write_file"; "/new"; ""; "0"];
517 ["read_lines"; "/new"]], [])],
518 "read file as lines",
520 Return the contents of the file named C<path>.
522 The file contents are returned as a list of lines. Trailing
523 C<LF> and C<CRLF> character sequences are I<not> returned.
525 Note that this function cannot correctly handle binary files
526 (specifically, files containing C<\\0> character which is treated
527 as end of line). For those you need to use the C<guestfs_read_file>
528 function which has a more complex interface.");
530 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
531 [], (* XXX Augeas code needs tests. *)
532 "create a new Augeas handle",
534 Create a new Augeas handle for editing configuration files.
535 If there was any previous Augeas handle associated with this
536 guestfs session, then it is closed.
538 You must call this before using any other C<guestfs_aug_*>
541 C<root> is the filesystem root. C<root> must not be NULL,
544 The flags are the same as the flags defined in
545 E<lt>augeas.hE<gt>, the logical I<or> of the following
550 =item C<AUG_SAVE_BACKUP> = 1
552 Keep the original file with a C<.augsave> extension.
554 =item C<AUG_SAVE_NEWFILE> = 2
556 Save changes into a file with extension C<.augnew>, and
557 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
559 =item C<AUG_TYPE_CHECK> = 4
561 Typecheck lenses (can be expensive).
563 =item C<AUG_NO_STDINC> = 8
565 Do not use standard load path for modules.
567 =item C<AUG_SAVE_NOOP> = 16
569 Make save a no-op, just record what would have been changed.
571 =item C<AUG_NO_LOAD> = 32
573 Do not load the tree in C<guestfs_aug_init>.
577 To close the handle, you can call C<guestfs_aug_close>.
579 To find out more about Augeas, see L<http://augeas.net/>.");
581 ("aug_close", (RErr, []), 26, [],
582 [], (* XXX Augeas code needs tests. *)
583 "close the current Augeas handle",
585 Close the current Augeas handle and free up any resources
586 used by it. After calling this, you have to call
587 C<guestfs_aug_init> again before you can use any other
590 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
591 [], (* XXX Augeas code needs tests. *)
592 "define an Augeas variable",
594 Defines an Augeas variable C<name> whose value is the result
595 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
598 On success this returns the number of nodes in C<expr>, or
599 C<0> if C<expr> evaluates to something which is not a nodeset.");
601 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
602 [], (* XXX Augeas code needs tests. *)
603 "define an Augeas node",
605 Defines a variable C<name> whose value is the result of
608 If C<expr> evaluates to an empty nodeset, a node is created,
609 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
610 C<name> will be the nodeset containing that single node.
612 On success this returns a pair containing the
613 number of nodes in the nodeset, and a boolean flag
614 if a node was created.");
616 ("aug_get", (RString "val", [String "path"]), 19, [],
617 [], (* XXX Augeas code needs tests. *)
618 "look up the value of an Augeas path",
620 Look up the value associated with C<path>. If C<path>
621 matches exactly one node, the C<value> is returned.");
623 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
624 [], (* XXX Augeas code needs tests. *)
625 "set Augeas path to value",
627 Set the value associated with C<path> to C<value>.");
629 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
630 [], (* XXX Augeas code needs tests. *)
631 "insert a sibling Augeas node",
633 Create a new sibling C<label> for C<path>, inserting it into
634 the tree before or after C<path> (depending on the boolean
637 C<path> must match exactly one existing node in the tree, and
638 C<label> must be a label, ie. not contain C</>, C<*> or end
639 with a bracketed index C<[N]>.");
641 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
642 [], (* XXX Augeas code needs tests. *)
643 "remove an Augeas path",
645 Remove C<path> and all of its children.
647 On success this returns the number of entries which were removed.");
649 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
650 [], (* XXX Augeas code needs tests. *)
653 Move the node C<src> to C<dest>. C<src> must match exactly
654 one node. C<dest> is overwritten if it exists.");
656 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
657 [], (* XXX Augeas code needs tests. *)
658 "return Augeas nodes which match path",
660 Returns a list of paths which match the path expression C<path>.
661 The returned paths are sufficiently qualified so that they match
662 exactly one node in the current tree.");
664 ("aug_save", (RErr, []), 25, [],
665 [], (* XXX Augeas code needs tests. *)
666 "write all pending Augeas changes to disk",
668 This writes all pending changes to disk.
670 The flags which were passed to C<guestfs_aug_init> affect exactly
671 how files are saved.");
673 ("aug_load", (RErr, []), 27, [],
674 [], (* XXX Augeas code needs tests. *)
675 "load files into the tree",
677 Load files into the tree.
679 See C<aug_load> in the Augeas documentation for the full gory
682 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
683 [], (* XXX Augeas code needs tests. *)
684 "list Augeas nodes under a path",
686 This is just a shortcut for listing C<guestfs_aug_match>
687 C<path/*> and sorting the resulting nodes into alphabetical order.");
689 ("rm", (RErr, [String "path"]), 29, [],
690 [InitBasicFS, TestRun
693 InitBasicFS, TestLastFail
695 InitBasicFS, TestLastFail
700 Remove the single file C<path>.");
702 ("rmdir", (RErr, [String "path"]), 30, [],
703 [InitBasicFS, TestRun
706 InitBasicFS, TestLastFail
708 InitBasicFS, TestLastFail
711 "remove a directory",
713 Remove the single directory C<path>.");
715 ("rm_rf", (RErr, [String "path"]), 31, [],
716 [InitBasicFS, TestOutputFalse
718 ["mkdir"; "/new/foo"];
719 ["touch"; "/new/foo/bar"];
721 ["exists"; "/new"]]],
722 "remove a file or directory recursively",
724 Remove the file or directory C<path>, recursively removing the
725 contents if its a directory. This is like the C<rm -rf> shell
728 ("mkdir", (RErr, [String "path"]), 32, [],
729 [InitBasicFS, TestOutputTrue
732 InitBasicFS, TestLastFail
733 [["mkdir"; "/new/foo/bar"]]],
734 "create a directory",
736 Create a directory named C<path>.");
738 ("mkdir_p", (RErr, [String "path"]), 33, [],
739 [InitBasicFS, TestOutputTrue
740 [["mkdir_p"; "/new/foo/bar"];
741 ["is_dir"; "/new/foo/bar"]];
742 InitBasicFS, TestOutputTrue
743 [["mkdir_p"; "/new/foo/bar"];
744 ["is_dir"; "/new/foo"]];
745 InitBasicFS, TestOutputTrue
746 [["mkdir_p"; "/new/foo/bar"];
747 ["is_dir"; "/new"]]],
748 "create a directory and parents",
750 Create a directory named C<path>, creating any parent directories
751 as necessary. This is like the C<mkdir -p> shell command.");
753 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
754 [], (* XXX Need stat command to test *)
757 Change the mode (permissions) of C<path> to C<mode>. Only
758 numeric modes are supported.");
760 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
761 [], (* XXX Need stat command to test *)
762 "change file owner and group",
764 Change the file owner to C<owner> and group to C<group>.
766 Only numeric uid and gid are supported. If you want to use
767 names, you will need to locate and parse the password file
768 yourself (Augeas support makes this relatively easy).");
770 ("exists", (RBool "existsflag", [String "path"]), 36, [],
771 [InitBasicFS, TestOutputTrue (
773 ["exists"; "/new"]]);
774 InitBasicFS, TestOutputTrue (
776 ["exists"; "/new"]])],
777 "test if file or directory exists",
779 This returns C<true> if and only if there is a file, directory
780 (or anything) with the given C<path> name.
782 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
784 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
785 [InitBasicFS, TestOutputTrue (
787 ["is_file"; "/new"]]);
788 InitBasicFS, TestOutputFalse (
790 ["is_file"; "/new"]])],
791 "test if file exists",
793 This returns C<true> if and only if there is a file
794 with the given C<path> name. Note that it returns false for
795 other objects like directories.
797 See also C<guestfs_stat>.");
799 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
800 [InitBasicFS, TestOutputFalse (
802 ["is_dir"; "/new"]]);
803 InitBasicFS, TestOutputTrue (
805 ["is_dir"; "/new"]])],
806 "test if file exists",
808 This returns C<true> if and only if there is a directory
809 with the given C<path> name. Note that it returns false for
810 other objects like files.
812 See also C<guestfs_stat>.");
814 ("pvcreate", (RErr, [String "device"]), 39, [],
815 [InitEmpty, TestOutputList (
816 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
817 ["pvcreate"; "/dev/sda1"];
818 ["pvcreate"; "/dev/sda2"];
819 ["pvcreate"; "/dev/sda3"];
820 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
821 "create an LVM physical volume",
823 This creates an LVM physical volume on the named C<device>,
824 where C<device> should usually be a partition name such
827 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
828 [InitEmpty, TestOutputList (
829 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
830 ["pvcreate"; "/dev/sda1"];
831 ["pvcreate"; "/dev/sda2"];
832 ["pvcreate"; "/dev/sda3"];
833 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
834 ["vgcreate"; "VG2"; "/dev/sda3"];
835 ["vgs"]], ["VG1"; "VG2"])],
836 "create an LVM volume group",
838 This creates an LVM volume group called C<volgroup>
839 from the non-empty list of physical volumes C<physvols>.");
841 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
842 [InitEmpty, TestOutputList (
843 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
844 ["pvcreate"; "/dev/sda1"];
845 ["pvcreate"; "/dev/sda2"];
846 ["pvcreate"; "/dev/sda3"];
847 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
848 ["vgcreate"; "VG2"; "/dev/sda3"];
849 ["lvcreate"; "LV1"; "VG1"; "50"];
850 ["lvcreate"; "LV2"; "VG1"; "50"];
851 ["lvcreate"; "LV3"; "VG2"; "50"];
852 ["lvcreate"; "LV4"; "VG2"; "50"];
853 ["lvcreate"; "LV5"; "VG2"; "50"];
855 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
856 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
857 "create an LVM volume group",
859 This creates an LVM volume group called C<logvol>
860 on the volume group C<volgroup>, with C<size> megabytes.");
862 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
863 [InitEmpty, TestOutput (
864 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
865 ["mkfs"; "ext2"; "/dev/sda1"];
866 ["mount"; "/dev/sda1"; "/"];
867 ["write_file"; "/new"; "new file contents"; "0"];
868 ["cat"; "/new"]], "new file contents")],
871 This creates a filesystem on C<device> (usually a partition
872 of LVM logical volume). The filesystem type is C<fstype>, for
875 ("sfdisk", (RErr, [String "device";
876 Int "cyls"; Int "heads"; Int "sectors";
877 StringList "lines"]), 43, [DangerWillRobinson],
879 "create partitions on a block device",
881 This is a direct interface to the L<sfdisk(8)> program for creating
882 partitions on block devices.
884 C<device> should be a block device, for example C</dev/sda>.
886 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
887 and sectors on the device, which are passed directly to sfdisk as
888 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
889 of these, then the corresponding parameter is omitted. Usually for
890 'large' disks, you can just pass C<0> for these, but for small
891 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
892 out the right geometry and you will need to tell it.
894 C<lines> is a list of lines that we feed to C<sfdisk>. For more
895 information refer to the L<sfdisk(8)> manpage.
897 To create a single partition occupying the whole disk, you would
898 pass C<lines> as a single element list, when the single element being
899 the string C<,> (comma).");
901 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
902 [InitEmpty, TestOutput (
903 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
904 ["mkfs"; "ext2"; "/dev/sda1"];
905 ["mount"; "/dev/sda1"; "/"];
906 ["write_file"; "/new"; "new file contents"; "0"];
907 ["cat"; "/new"]], "new file contents")],
910 This call creates a file called C<path>. The contents of the
911 file is the string C<content> (which can contain any 8 bit data),
914 As a special case, if C<size> is C<0>
915 then the length is calculated using C<strlen> (so in this case
916 the content cannot contain embedded ASCII NULs).");
918 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
919 [InitEmpty, TestOutputList (
920 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
921 ["mkfs"; "ext2"; "/dev/sda1"];
922 ["mount"; "/dev/sda1"; "/"];
923 ["mounts"]], ["/dev/sda1"]);
924 InitEmpty, TestOutputList (
925 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
926 ["mkfs"; "ext2"; "/dev/sda1"];
927 ["mount"; "/dev/sda1"; "/"];
930 "unmount a filesystem",
932 This unmounts the given filesystem. The filesystem may be
933 specified either by its mountpoint (path) or the device which
934 contains the filesystem.");
936 ("mounts", (RStringList "devices", []), 46, [],
937 [InitBasicFS, TestOutputList (
938 [["mounts"]], ["/dev/sda1"])],
939 "show mounted filesystems",
941 This returns the list of currently mounted filesystems. It returns
942 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
944 Some internal mounts are not shown.");
946 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
947 [InitBasicFS, TestOutputList (
950 "unmount all filesystems",
952 This unmounts all mounted filesystems.
954 Some internal mounts are not unmounted by this call.");
956 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
958 "remove all LVM LVs, VGs and PVs",
960 This command removes all LVM logical volumes, volume groups
961 and physical volumes.");
963 ("file", (RString "description", [String "path"]), 49, [],
964 [InitBasicFS, TestOutput (
966 ["file"; "/new"]], "empty");
967 InitBasicFS, TestOutput (
968 [["write_file"; "/new"; "some content\n"; "0"];
969 ["file"; "/new"]], "ASCII text");
970 InitBasicFS, TestLastFail (
971 [["file"; "/nofile"]])],
972 "determine file type",
974 This call uses the standard L<file(1)> command to determine
975 the type or contents of the file. This also works on devices,
976 for example to find out whether a partition contains a filesystem.
978 The exact command which runs is C<file -bsL path>. Note in
979 particular that the filename is not prepended to the output
980 (the C<-b> option).");
982 ("command", (RString "output", [StringList "arguments"]), 50, [],
983 [], (* XXX how to test? *)
984 "run a command from the guest filesystem",
986 This call runs a command from the guest filesystem. The
987 filesystem must be mounted, and must contain a compatible
988 operating system (ie. something Linux, with the same
989 or compatible processor architecture).
991 The single parameter is an argv-style list of arguments.
992 The first element is the name of the program to run.
993 Subsequent elements are parameters. The list must be
994 non-empty (ie. must contain a program name).
996 The C<$PATH> environment variable will contain at least
997 C</usr/bin> and C</bin>. If you require a program from
998 another location, you should provide the full path in the
1001 Shared libraries and data files required by the program
1002 must be available on filesystems which are mounted in the
1003 correct places. It is the caller's responsibility to ensure
1004 all filesystems that are needed are mounted at the right
1007 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [],
1008 [], (* XXX how to test? *)
1009 "run a command, returning lines",
1011 This is the same as C<guestfs_command>, but splits the
1012 result into a list of lines.");
1014 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1015 [InitBasicFS, TestOutputStruct (
1017 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1018 "get file information",
1020 Returns file information for the given C<path>.
1022 This is the same as the C<stat(2)> system call.");
1024 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1025 [InitBasicFS, TestOutputStruct (
1027 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1028 "get file information for a symbolic link",
1030 Returns file information for the given C<path>.
1032 This is the same as C<guestfs_stat> except that if C<path>
1033 is a symbolic link, then the link is stat-ed, not the file it
1036 This is the same as the C<lstat(2)> system call.");
1038 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1039 [InitBasicFS, TestOutputStruct (
1040 [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1041 CompareWithInt ("blocks", 490020);
1042 CompareWithInt ("bsize", 1024)])],
1043 "get file system statistics",
1045 Returns file system statistics for any mounted file system.
1046 C<path> should be a file or directory in the mounted file system
1047 (typically it is the mount point itself, but it doesn't need to be).
1049 This is the same as the C<statvfs(2)> system call.");
1053 let all_functions = non_daemon_functions @ daemon_functions
1055 (* In some places we want the functions to be displayed sorted
1056 * alphabetically, so this is useful:
1058 let all_functions_sorted =
1059 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
1060 compare n1 n2) all_functions
1062 (* Column names and types from LVM PVs/VGs/LVs. *)
1071 "pv_attr", `String (* XXX *);
1072 "pv_pe_count", `Int;
1073 "pv_pe_alloc_count", `Int;
1076 "pv_mda_count", `Int;
1077 "pv_mda_free", `Bytes;
1078 (* Not in Fedora 10:
1079 "pv_mda_size", `Bytes;
1086 "vg_attr", `String (* XXX *);
1089 "vg_sysid", `String;
1090 "vg_extent_size", `Bytes;
1091 "vg_extent_count", `Int;
1092 "vg_free_count", `Int;
1100 "vg_mda_count", `Int;
1101 "vg_mda_free", `Bytes;
1102 (* Not in Fedora 10:
1103 "vg_mda_size", `Bytes;
1109 "lv_attr", `String (* XXX *);
1112 "lv_kernel_major", `Int;
1113 "lv_kernel_minor", `Int;
1117 "snap_percent", `OptPercent;
1118 "copy_percent", `OptPercent;
1121 "mirror_log", `String;
1125 (* Column names and types from stat structures.
1126 * NB. Can't use things like 'st_atime' because glibc header files
1127 * define some of these as macros. Ugh.
1144 let statvfs_cols = [
1158 (* Useful functions.
1159 * Note we don't want to use any external OCaml libraries which
1160 * makes this a bit harder than it should be.
1162 let failwithf fs = ksprintf failwith fs
1164 let replace_char s c1 c2 =
1165 let s2 = String.copy s in
1166 let r = ref false in
1167 for i = 0 to String.length s2 - 1 do
1168 if String.unsafe_get s2 i = c1 then (
1169 String.unsafe_set s2 i c2;
1173 if not !r then s else s2
1175 let rec find s sub =
1176 let len = String.length s in
1177 let sublen = String.length sub in
1179 if i <= len-sublen then (
1181 if j < sublen then (
1182 if s.[i+j] = sub.[j] then loop2 (j+1)
1188 if r = -1 then loop (i+1) else r
1194 let rec replace_str s s1 s2 =
1195 let len = String.length s in
1196 let sublen = String.length s1 in
1197 let i = find s s1 in
1200 let s' = String.sub s 0 i in
1201 let s'' = String.sub s (i+sublen) (len-i-sublen) in
1202 s' ^ s2 ^ replace_str s'' s1 s2
1205 let rec string_split sep str =
1206 let len = String.length str in
1207 let seplen = String.length sep in
1208 let i = find str sep in
1209 if i = -1 then [str]
1211 let s' = String.sub str 0 i in
1212 let s'' = String.sub str (i+seplen) (len-i-seplen) in
1213 s' :: string_split sep s''
1216 let rec find_map f = function
1217 | [] -> raise Not_found
1221 | None -> find_map f xs
1224 let rec loop i = function
1226 | x :: xs -> f i x; loop (i+1) xs
1231 let rec loop i = function
1233 | x :: xs -> let r = f i x in r :: loop (i+1) xs
1237 let name_of_argt = function
1238 | String n | OptString n | StringList n | Bool n | Int n -> n
1240 (* Check function names etc. for consistency. *)
1241 let check_functions () =
1242 let contains_uppercase str =
1243 let len = String.length str in
1245 if i >= len then false
1248 if c >= 'A' && c <= 'Z' then true
1255 (* Check function names. *)
1257 fun (name, _, _, _, _, _, _) ->
1258 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
1259 failwithf "function name %s does not need 'guestfs' prefix" name;
1260 if contains_uppercase name then
1261 failwithf "function name %s should not contain uppercase chars" name;
1262 if String.contains name '-' then
1263 failwithf "function name %s should not contain '-', use '_' instead."
1267 (* Check function parameter/return names. *)
1269 fun (name, style, _, _, _, _, _) ->
1270 let check_arg_ret_name n =
1271 if contains_uppercase n then
1272 failwithf "%s param/ret %s should not contain uppercase chars"
1274 if String.contains n '-' || String.contains n '_' then
1275 failwithf "%s param/ret %s should not contain '-' or '_'"
1278 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;
1279 if n = "argv" || n = "args" then
1280 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
1283 (match fst style with
1285 | RInt n | RBool n | RConstString n | RString n
1286 | RStringList n | RPVList n | RVGList n | RLVList n
1287 | RStat n | RStatVFS n ->
1288 check_arg_ret_name n
1290 check_arg_ret_name n;
1291 check_arg_ret_name m
1293 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
1296 (* Check short descriptions. *)
1298 fun (name, _, _, _, _, shortdesc, _) ->
1299 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
1300 failwithf "short description of %s should begin with lowercase." name;
1301 let c = shortdesc.[String.length shortdesc-1] in
1302 if c = '\n' || c = '.' then
1303 failwithf "short description of %s should not end with . or \\n." name
1306 (* Check long dscriptions. *)
1308 fun (name, _, _, _, _, _, longdesc) ->
1309 if longdesc.[String.length longdesc-1] = '\n' then
1310 failwithf "long description of %s should not end with \\n." name
1313 (* Check proc_nrs. *)
1315 fun (name, _, proc_nr, _, _, _, _) ->
1316 if proc_nr <= 0 then
1317 failwithf "daemon function %s should have proc_nr > 0" name
1321 fun (name, _, proc_nr, _, _, _, _) ->
1322 if proc_nr <> -1 then
1323 failwithf "non-daemon function %s should have proc_nr -1" name
1324 ) non_daemon_functions;
1327 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
1330 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
1331 let rec loop = function
1334 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
1336 | (name1,nr1) :: (name2,nr2) :: _ ->
1337 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
1342 (* 'pr' prints to the current output file. *)
1343 let chan = ref stdout
1344 let pr fs = ksprintf (output_string !chan) fs
1346 (* Generate a header block in a number of standard styles. *)
1347 type comment_style = CStyle | HashStyle | OCamlStyle
1348 type license = GPLv2 | LGPLv2
1350 let generate_header comment license =
1351 let c = match comment with
1352 | CStyle -> pr "/* "; " *"
1353 | HashStyle -> pr "# "; "#"
1354 | OCamlStyle -> pr "(* "; " *" in
1355 pr "libguestfs generated file\n";
1356 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
1357 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
1359 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
1363 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
1364 pr "%s it under the terms of the GNU General Public License as published by\n" c;
1365 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
1366 pr "%s (at your option) any later version.\n" c;
1368 pr "%s This program is distributed in the hope that it will be useful,\n" c;
1369 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1370 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
1371 pr "%s GNU General Public License for more details.\n" c;
1373 pr "%s You should have received a copy of the GNU General Public License along\n" c;
1374 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
1375 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
1378 pr "%s This library is free software; you can redistribute it and/or\n" c;
1379 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
1380 pr "%s License as published by the Free Software Foundation; either\n" c;
1381 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
1383 pr "%s This library is distributed in the hope that it will be useful,\n" c;
1384 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1385 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
1386 pr "%s Lesser General Public License for more details.\n" c;
1388 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
1389 pr "%s License along with this library; if not, write to the Free Software\n" c;
1390 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
1393 | CStyle -> pr " */\n"
1395 | OCamlStyle -> pr " *)\n"
1399 (* Start of main code generation functions below this line. *)
1401 (* Generate the pod documentation for the C API. *)
1402 let rec generate_actions_pod () =
1404 fun (shortname, style, _, flags, _, _, longdesc) ->
1405 let name = "guestfs_" ^ shortname in
1406 pr "=head2 %s\n\n" name;
1408 generate_prototype ~extern:false ~handle:"handle" name style;
1410 pr "%s\n\n" longdesc;
1411 (match fst style with
1413 pr "This function returns 0 on success or -1 on error.\n\n"
1415 pr "On error this function returns -1.\n\n"
1417 pr "This function returns a C truth value on success or -1 on error.\n\n"
1419 pr "This function returns a string, or NULL on error.
1420 The string is owned by the guest handle and must I<not> be freed.\n\n"
1422 pr "This function returns a string, or NULL on error.
1423 I<The caller must free the returned string after use>.\n\n"
1425 pr "This function returns a NULL-terminated array of strings
1426 (like L<environ(3)>), or NULL if there was an error.
1427 I<The caller must free the strings and the array after use>.\n\n"
1429 pr "This function returns a C<struct guestfs_int_bool *>,
1430 or NULL if there was an error.
1431 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
1433 pr "This function returns a C<struct guestfs_lvm_pv_list *>
1434 (see E<lt>guestfs-structs.hE<gt>),
1435 or NULL if there was an error.
1436 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
1438 pr "This function returns a C<struct guestfs_lvm_vg_list *>
1439 (see E<lt>guestfs-structs.hE<gt>),
1440 or NULL if there was an error.
1441 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
1443 pr "This function returns a C<struct guestfs_lvm_lv_list *>
1444 (see E<lt>guestfs-structs.hE<gt>),
1445 or NULL if there was an error.
1446 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
1448 pr "This function returns a C<struct guestfs_stat *>
1449 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
1450 or NULL if there was an error.
1451 I<The caller must call C<free> after use>.\n\n"
1453 pr "This function returns a C<struct guestfs_statvfs *>
1454 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
1455 or NULL if there was an error.
1456 I<The caller must call C<free> after use>.\n\n"
1458 if List.mem ProtocolLimitWarning flags then
1459 pr "%s\n\n" protocol_limit_warning;
1460 if List.mem DangerWillRobinson flags then
1461 pr "%s\n\n" danger_will_robinson;
1462 ) all_functions_sorted
1464 and generate_structs_pod () =
1465 (* LVM structs documentation. *)
1468 pr "=head2 guestfs_lvm_%s\n" typ;
1470 pr " struct guestfs_lvm_%s {\n" typ;
1473 | name, `String -> pr " char *%s;\n" name
1475 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
1476 pr " char %s[32];\n" name
1477 | name, `Bytes -> pr " uint64_t %s;\n" name
1478 | name, `Int -> pr " int64_t %s;\n" name
1479 | name, `OptPercent ->
1480 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
1481 pr " float %s;\n" name
1484 pr " struct guestfs_lvm_%s_list {\n" typ;
1485 pr " uint32_t len; /* Number of elements in list. */\n";
1486 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
1489 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
1492 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1494 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
1495 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
1497 * We have to use an underscore instead of a dash because otherwise
1498 * rpcgen generates incorrect code.
1500 * This header is NOT exported to clients, but see also generate_structs_h.
1502 and generate_xdr () =
1503 generate_header CStyle LGPLv2;
1505 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
1506 pr "typedef string str<>;\n";
1509 (* LVM internal structures. *)
1513 pr "struct guestfs_lvm_int_%s {\n" typ;
1515 | name, `String -> pr " string %s<>;\n" name
1516 | name, `UUID -> pr " opaque %s[32];\n" name
1517 | name, `Bytes -> pr " hyper %s;\n" name
1518 | name, `Int -> pr " hyper %s;\n" name
1519 | name, `OptPercent -> pr " float %s;\n" name
1523 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
1525 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1527 (* Stat internal structures. *)
1531 pr "struct guestfs_int_%s {\n" typ;
1533 | name, `Int -> pr " hyper %s;\n" name
1537 ) ["stat", stat_cols; "statvfs", statvfs_cols];
1540 fun (shortname, style, _, _, _, _, _) ->
1541 let name = "guestfs_" ^ shortname in
1543 (match snd style with
1546 pr "struct %s_args {\n" name;
1549 | String n -> pr " string %s<>;\n" n
1550 | OptString n -> pr " str *%s;\n" n
1551 | StringList n -> pr " str %s<>;\n" n
1552 | Bool n -> pr " bool %s;\n" n
1553 | Int n -> pr " int %s;\n" n
1557 (match fst style with
1560 pr "struct %s_ret {\n" name;
1564 pr "struct %s_ret {\n" name;
1568 failwithf "RConstString cannot be returned from a daemon function"
1570 pr "struct %s_ret {\n" name;
1571 pr " string %s<>;\n" n;
1574 pr "struct %s_ret {\n" name;
1575 pr " str %s<>;\n" n;
1578 pr "struct %s_ret {\n" name;
1583 pr "struct %s_ret {\n" name;
1584 pr " guestfs_lvm_int_pv_list %s;\n" n;
1587 pr "struct %s_ret {\n" name;
1588 pr " guestfs_lvm_int_vg_list %s;\n" n;
1591 pr "struct %s_ret {\n" name;
1592 pr " guestfs_lvm_int_lv_list %s;\n" n;
1595 pr "struct %s_ret {\n" name;
1596 pr " guestfs_int_stat %s;\n" n;
1599 pr "struct %s_ret {\n" name;
1600 pr " guestfs_int_statvfs %s;\n" n;
1605 (* Table of procedure numbers. *)
1606 pr "enum guestfs_procedure {\n";
1608 fun (shortname, _, proc_nr, _, _, _, _) ->
1609 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
1611 pr " GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
1615 (* Having to choose a maximum message size is annoying for several
1616 * reasons (it limits what we can do in the API), but it (a) makes
1617 * the protocol a lot simpler, and (b) provides a bound on the size
1618 * of the daemon which operates in limited memory space. For large
1619 * file transfers you should use FTP.
1621 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
1624 (* Message header, etc. *)
1626 const GUESTFS_PROGRAM = 0x2000F5F5;
1627 const GUESTFS_PROTOCOL_VERSION = 1;
1629 enum guestfs_message_direction {
1630 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
1631 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
1634 enum guestfs_message_status {
1635 GUESTFS_STATUS_OK = 0,
1636 GUESTFS_STATUS_ERROR = 1
1639 const GUESTFS_ERROR_LEN = 256;
1641 struct guestfs_message_error {
1642 string error<GUESTFS_ERROR_LEN>; /* error message */
1645 struct guestfs_message_header {
1646 unsigned prog; /* GUESTFS_PROGRAM */
1647 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
1648 guestfs_procedure proc; /* GUESTFS_PROC_x */
1649 guestfs_message_direction direction;
1650 unsigned serial; /* message serial number */
1651 guestfs_message_status status;
1655 (* Generate the guestfs-structs.h file. *)
1656 and generate_structs_h () =
1657 generate_header CStyle LGPLv2;
1659 (* This is a public exported header file containing various
1660 * structures. The structures are carefully written to have
1661 * exactly the same in-memory format as the XDR structures that
1662 * we use on the wire to the daemon. The reason for creating
1663 * copies of these structures here is just so we don't have to
1664 * export the whole of guestfs_protocol.h (which includes much
1665 * unrelated and XDR-dependent stuff that we don't want to be
1666 * public, or required by clients).
1668 * To reiterate, we will pass these structures to and from the
1669 * client with a simple assignment or memcpy, so the format
1670 * must be identical to what rpcgen / the RFC defines.
1673 (* guestfs_int_bool structure. *)
1674 pr "struct guestfs_int_bool {\n";
1680 (* LVM public structures. *)
1684 pr "struct guestfs_lvm_%s {\n" typ;
1687 | name, `String -> pr " char *%s;\n" name
1688 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
1689 | name, `Bytes -> pr " uint64_t %s;\n" name
1690 | name, `Int -> pr " int64_t %s;\n" name
1691 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
1695 pr "struct guestfs_lvm_%s_list {\n" typ;
1696 pr " uint32_t len;\n";
1697 pr " struct guestfs_lvm_%s *val;\n" typ;
1700 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1702 (* Stat structures. *)
1706 pr "struct guestfs_%s {\n" typ;
1709 | name, `Int -> pr " int64_t %s;\n" name
1713 ) ["stat", stat_cols; "statvfs", statvfs_cols]
1715 (* Generate the guestfs-actions.h file. *)
1716 and generate_actions_h () =
1717 generate_header CStyle LGPLv2;
1719 fun (shortname, style, _, _, _, _, _) ->
1720 let name = "guestfs_" ^ shortname in
1721 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
1725 (* Generate the client-side dispatch stubs. *)
1726 and generate_client_actions () =
1727 generate_header CStyle LGPLv2;
1729 (* Client-side stubs for each function. *)
1731 fun (shortname, style, _, _, _, _, _) ->
1732 let name = "guestfs_" ^ shortname in
1734 (* Generate the return value struct. *)
1735 pr "struct %s_rv {\n" shortname;
1736 pr " int cb_done; /* flag to indicate callback was called */\n";
1737 pr " struct guestfs_message_header hdr;\n";
1738 pr " struct guestfs_message_error err;\n";
1739 (match fst style with
1742 failwithf "RConstString cannot be returned from a daemon function"
1744 | RBool _ | RString _ | RStringList _
1746 | RPVList _ | RVGList _ | RLVList _
1747 | RStat _ | RStatVFS _ ->
1748 pr " struct %s_ret ret;\n" name
1752 (* Generate the callback function. *)
1753 pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
1755 pr " struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
1757 pr " if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
1758 pr " error (g, \"%s: failed to parse reply header\");\n" name;
1761 pr " if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
1762 pr " if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
1763 pr " error (g, \"%s: failed to parse reply error\");\n" name;
1769 (match fst style with
1772 failwithf "RConstString cannot be returned from a daemon function"
1774 | RBool _ | RString _ | RStringList _
1776 | RPVList _ | RVGList _ | RLVList _
1777 | RStat _ | RStatVFS _ ->
1778 pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
1779 pr " error (g, \"%s: failed to parse reply\");\n" name;
1785 pr " rv->cb_done = 1;\n";
1786 pr " main_loop.main_loop_quit (g);\n";
1789 (* Generate the action stub. *)
1790 generate_prototype ~extern:false ~semicolon:false ~newline:true
1791 ~handle:"g" name style;
1794 match fst style with
1795 | RErr | RInt _ | RBool _ -> "-1"
1797 failwithf "RConstString cannot be returned from a daemon function"
1798 | RString _ | RStringList _ | RIntBool _
1799 | RPVList _ | RVGList _ | RLVList _
1800 | RStat _ | RStatVFS _ ->
1805 (match snd style with
1807 | _ -> pr " struct %s_args args;\n" name
1810 pr " struct %s_rv rv;\n" shortname;
1811 pr " int serial;\n";
1813 pr " if (g->state != READY) {\n";
1814 pr " error (g, \"%s called from the wrong state, %%d != READY\",\n"
1817 pr " return %s;\n" error_code;
1820 pr " memset (&rv, 0, sizeof rv);\n";
1823 (match snd style with
1825 pr " serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
1826 (String.uppercase shortname)
1831 pr " args.%s = (char *) %s;\n" n n
1833 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
1835 pr " args.%s.%s_val = (char **) %s;\n" n n n;
1836 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
1838 pr " args.%s = %s;\n" n n
1840 pr " args.%s = %s;\n" n n
1842 pr " serial = dispatch (g, GUESTFS_PROC_%s,\n"
1843 (String.uppercase shortname);
1844 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
1847 pr " if (serial == -1)\n";
1848 pr " return %s;\n" error_code;
1851 pr " rv.cb_done = 0;\n";
1852 pr " g->reply_cb_internal = %s_cb;\n" shortname;
1853 pr " g->reply_cb_internal_data = &rv;\n";
1854 pr " main_loop.main_loop_run (g);\n";
1855 pr " g->reply_cb_internal = NULL;\n";
1856 pr " g->reply_cb_internal_data = NULL;\n";
1857 pr " if (!rv.cb_done) {\n";
1858 pr " error (g, \"%s failed, see earlier error messages\");\n" name;
1859 pr " return %s;\n" error_code;
1863 pr " if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
1864 (String.uppercase shortname);
1865 pr " return %s;\n" error_code;
1868 pr " if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
1869 pr " error (g, \"%%s\", rv.err.error);\n";
1870 pr " return %s;\n" error_code;
1874 (match fst style with
1875 | RErr -> pr " return 0;\n"
1877 | RBool n -> pr " return rv.ret.%s;\n" n
1879 failwithf "RConstString cannot be returned from a daemon function"
1881 pr " return rv.ret.%s; /* caller will free */\n" n
1883 pr " /* caller will free this, but we need to add a NULL entry */\n";
1884 pr " rv.ret.%s.%s_val =" n n;
1885 pr " safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
1886 pr " sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
1888 pr " rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
1889 pr " return rv.ret.%s.%s_val;\n" n n
1891 pr " /* caller with free this */\n";
1892 pr " return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
1894 pr " /* caller will free this */\n";
1895 pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1897 pr " /* caller will free this */\n";
1898 pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1900 pr " /* caller will free this */\n";
1901 pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1903 pr " /* caller will free this */\n";
1904 pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1906 pr " /* caller will free this */\n";
1907 pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1913 (* Generate daemon/actions.h. *)
1914 and generate_daemon_actions_h () =
1915 generate_header CStyle GPLv2;
1917 pr "#include \"../src/guestfs_protocol.h\"\n";
1921 fun (name, style, _, _, _, _, _) ->
1923 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
1927 (* Generate the server-side stubs. *)
1928 and generate_daemon_actions () =
1929 generate_header CStyle GPLv2;
1931 pr "#define _GNU_SOURCE // for strchrnul\n";
1933 pr "#include <stdio.h>\n";
1934 pr "#include <stdlib.h>\n";
1935 pr "#include <string.h>\n";
1936 pr "#include <inttypes.h>\n";
1937 pr "#include <ctype.h>\n";
1938 pr "#include <rpc/types.h>\n";
1939 pr "#include <rpc/xdr.h>\n";
1941 pr "#include \"daemon.h\"\n";
1942 pr "#include \"../src/guestfs_protocol.h\"\n";
1943 pr "#include \"actions.h\"\n";
1947 fun (name, style, _, _, _, _, _) ->
1948 (* Generate server-side stubs. *)
1949 pr "static void %s_stub (XDR *xdr_in)\n" name;
1952 match fst style with
1953 | RErr | RInt _ -> pr " int r;\n"; "-1"
1954 | RBool _ -> pr " int r;\n"; "-1"
1956 failwithf "RConstString cannot be returned from a daemon function"
1957 | RString _ -> pr " char *r;\n"; "NULL"
1958 | RStringList _ -> pr " char **r;\n"; "NULL"
1959 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
1960 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
1961 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
1962 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
1963 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
1964 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
1966 (match snd style with
1969 pr " struct guestfs_%s_args args;\n" name;
1973 | OptString n -> pr " const char *%s;\n" n
1974 | StringList n -> pr " char **%s;\n" n
1975 | Bool n -> pr " int %s;\n" n
1976 | Int n -> pr " int %s;\n" n
1981 (match snd style with
1984 pr " memset (&args, 0, sizeof args);\n";
1986 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
1987 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
1992 | String n -> pr " %s = args.%s;\n" n n
1993 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
1995 pr " args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
1996 pr " args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
1997 pr " %s = args.%s.%s_val;\n" n n n
1998 | Bool n -> pr " %s = args.%s;\n" n n
1999 | Int n -> pr " %s = args.%s;\n" n n
2004 pr " r = do_%s " name;
2005 generate_call_args style;
2008 pr " if (r == %s)\n" error_code;
2009 pr " /* do_%s has already called reply_with_error */\n" name;
2013 (match fst style with
2014 | RErr -> pr " reply (NULL, NULL);\n"
2016 pr " struct guestfs_%s_ret ret;\n" name;
2017 pr " ret.%s = r;\n" n;
2018 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
2020 pr " struct guestfs_%s_ret ret;\n" name;
2021 pr " ret.%s = r;\n" n;
2022 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
2024 failwithf "RConstString cannot be returned from a daemon function"
2026 pr " struct guestfs_%s_ret ret;\n" name;
2027 pr " ret.%s = r;\n" n;
2028 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2031 pr " struct guestfs_%s_ret ret;\n" name;
2032 pr " ret.%s.%s_len = count_strings (r);\n" n n;
2033 pr " ret.%s.%s_val = r;\n" n n;
2034 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2035 pr " free_strings (r);\n"
2037 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
2038 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2039 | RPVList n | RVGList n | RLVList n | RStat n | RStatVFS n ->
2040 pr " struct guestfs_%s_ret ret;\n" name;
2041 pr " ret.%s = *r;\n" n;
2042 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2043 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
2046 (* Free the args. *)
2047 (match snd style with
2052 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2059 (* Dispatch function. *)
2060 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2062 pr " switch (proc_nr) {\n";
2065 fun (name, style, _, _, _, _, _) ->
2066 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
2067 pr " %s_stub (xdr_in);\n" name;
2072 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2077 (* LVM columns and tokenization functions. *)
2078 (* XXX This generates crap code. We should rethink how we
2084 pr "static const char *lvm_%s_cols = \"%s\";\n"
2085 typ (String.concat "," (List.map fst cols));
2088 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2090 pr " char *tok, *p, *next;\n";
2094 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2097 pr " if (!str) {\n";
2098 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2101 pr " if (!*str || isspace (*str)) {\n";
2102 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2107 fun (name, coltype) ->
2108 pr " if (!tok) {\n";
2109 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2112 pr " p = strchrnul (tok, ',');\n";
2113 pr " if (*p) next = p+1; else next = NULL;\n";
2114 pr " *p = '\\0';\n";
2117 pr " r->%s = strdup (tok);\n" name;
2118 pr " if (r->%s == NULL) {\n" name;
2119 pr " perror (\"strdup\");\n";
2123 pr " for (i = j = 0; i < 32; ++j) {\n";
2124 pr " if (tok[j] == '\\0') {\n";
2125 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2127 pr " } else if (tok[j] != '-')\n";
2128 pr " r->%s[i++] = tok[j];\n" name;
2131 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2132 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2136 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2137 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2141 pr " if (tok[0] == '\\0')\n";
2142 pr " r->%s = -1;\n" name;
2143 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2144 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2148 pr " tok = next;\n";
2151 pr " if (tok != NULL) {\n";
2152 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2159 pr "guestfs_lvm_int_%s_list *\n" typ;
2160 pr "parse_command_line_%ss (void)\n" typ;
2162 pr " char *out, *err;\n";
2163 pr " char *p, *pend;\n";
2165 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
2166 pr " void *newp;\n";
2168 pr " ret = malloc (sizeof *ret);\n";
2169 pr " if (!ret) {\n";
2170 pr " reply_with_perror (\"malloc\");\n";
2171 pr " return NULL;\n";
2174 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2175 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2177 pr " r = command (&out, &err,\n";
2178 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
2179 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2180 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2181 pr " if (r == -1) {\n";
2182 pr " reply_with_error (\"%%s\", err);\n";
2183 pr " free (out);\n";
2184 pr " free (err);\n";
2185 pr " return NULL;\n";
2188 pr " free (err);\n";
2190 pr " /* Tokenize each line of the output. */\n";
2193 pr " while (p) {\n";
2194 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
2195 pr " if (pend) {\n";
2196 pr " *pend = '\\0';\n";
2200 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
2203 pr " if (!*p) { /* Empty line? Skip it. */\n";
2208 pr " /* Allocate some space to store this next entry. */\n";
2209 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2210 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2211 pr " if (newp == NULL) {\n";
2212 pr " reply_with_perror (\"realloc\");\n";
2213 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2214 pr " free (ret);\n";
2215 pr " free (out);\n";
2216 pr " return NULL;\n";
2218 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2220 pr " /* Tokenize the next entry. */\n";
2221 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2222 pr " if (r == -1) {\n";
2223 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2224 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2225 pr " free (ret);\n";
2226 pr " free (out);\n";
2227 pr " return NULL;\n";
2234 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2236 pr " free (out);\n";
2237 pr " return ret;\n";
2240 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2242 (* Generate the tests. *)
2243 and generate_tests () =
2244 generate_header CStyle GPLv2;
2251 #include <sys/types.h>
2254 #include \"guestfs.h\"
2256 static guestfs_h *g;
2257 static int suppress_error = 0;
2259 static void print_error (guestfs_h *g, void *data, const char *msg)
2261 if (!suppress_error)
2262 fprintf (stderr, \"%%s\\n\", msg);
2265 static void print_strings (char * const * const argv)
2269 for (argc = 0; argv[argc] != NULL; ++argc)
2270 printf (\"\\t%%s\\n\", argv[argc]);
2277 fun (name, _, _, _, tests, _, _) ->
2278 mapi (generate_one_test name) tests
2280 let test_names = List.concat test_names in
2281 let nr_tests = List.length test_names in
2284 int main (int argc, char *argv[])
2293 g = guestfs_create ();
2295 printf (\"guestfs_create FAILED\\n\");
2299 guestfs_set_error_handler (g, print_error, NULL);
2301 srcdir = getenv (\"srcdir\");
2302 if (!srcdir) srcdir = \".\";
2303 guestfs_set_path (g, srcdir);
2305 snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
2306 fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2311 if (lseek (fd, %d, SEEK_SET) == -1) {
2317 if (write (fd, &c, 1) == -1) {
2323 if (close (fd) == -1) {
2328 if (guestfs_add_drive (g, buf) == -1) {
2329 printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2333 snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
2334 fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2339 if (lseek (fd, %d, SEEK_SET) == -1) {
2345 if (write (fd, &c, 1) == -1) {
2351 if (close (fd) == -1) {
2356 if (guestfs_add_drive (g, buf) == -1) {
2357 printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2361 snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
2362 fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2367 if (lseek (fd, %d, SEEK_SET) == -1) {
2373 if (write (fd, &c, 1) == -1) {
2379 if (close (fd) == -1) {
2384 if (guestfs_add_drive (g, buf) == -1) {
2385 printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2389 if (guestfs_launch (g) == -1) {
2390 printf (\"guestfs_launch FAILED\\n\");
2393 if (guestfs_wait_ready (g) == -1) {
2394 printf (\"guestfs_wait_ready FAILED\\n\");
2399 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
2403 pr " printf (\"%3d/%%3d %s\\n\", nr_tests);\n" (i+1) test_name;
2404 pr " if (%s () == -1) {\n" test_name;
2405 pr " printf (\"%s FAILED\\n\");\n" test_name;
2411 pr " guestfs_close (g);\n";
2412 pr " snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
2413 pr " unlink (buf);\n";
2414 pr " snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
2415 pr " unlink (buf);\n";
2416 pr " snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
2417 pr " unlink (buf);\n";
2420 pr " if (failed > 0) {\n";
2421 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
2429 and generate_one_test name i (init, test) =
2430 let test_name = sprintf "test_%s_%d" name i in
2432 pr "static int %s (void)\n" test_name;
2438 pr " /* InitEmpty for %s (%d) */\n" name i;
2439 List.iter (generate_test_command_call test_name)
2443 pr " /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
2444 List.iter (generate_test_command_call test_name)
2447 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2448 ["mkfs"; "ext2"; "/dev/sda1"];
2449 ["mount"; "/dev/sda1"; "/"]]
2450 | InitBasicFSonLVM ->
2451 pr " /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
2453 List.iter (generate_test_command_call test_name)
2456 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2457 ["pvcreate"; "/dev/sda1"];
2458 ["vgcreate"; "VG"; "/dev/sda1"];
2459 ["lvcreate"; "LV"; "VG"; "8"];
2460 ["mkfs"; "ext2"; "/dev/VG/LV"];
2461 ["mount"; "/dev/VG/LV"; "/"]]
2464 let get_seq_last = function
2466 failwithf "%s: you cannot use [] (empty list) when expecting a command"
2469 let seq = List.rev seq in
2470 List.rev (List.tl seq), List.hd seq
2475 pr " /* TestRun for %s (%d) */\n" name i;
2476 List.iter (generate_test_command_call test_name) seq
2477 | TestOutput (seq, expected) ->
2478 pr " /* TestOutput for %s (%d) */\n" name i;
2479 let seq, last = get_seq_last seq in
2481 pr " if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
2482 pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
2486 List.iter (generate_test_command_call test_name) seq;
2487 generate_test_command_call ~test test_name last
2488 | TestOutputList (seq, expected) ->
2489 pr " /* TestOutputList for %s (%d) */\n" name i;
2490 let seq, last = get_seq_last seq in
2494 pr " if (!r[%d]) {\n" i;
2495 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
2496 pr " print_strings (r);\n";
2499 pr " if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
2500 pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
2504 pr " if (r[%d] != NULL) {\n" (List.length expected);
2505 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
2507 pr " print_strings (r);\n";
2511 List.iter (generate_test_command_call test_name) seq;
2512 generate_test_command_call ~test test_name last
2513 | TestOutputInt (seq, expected) ->
2514 pr " /* TestOutputInt for %s (%d) */\n" name i;
2515 let seq, last = get_seq_last seq in
2517 pr " if (r != %d) {\n" expected;
2518 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\", r);\n"
2523 List.iter (generate_test_command_call test_name) seq;
2524 generate_test_command_call ~test test_name last
2525 | TestOutputTrue seq ->
2526 pr " /* TestOutputTrue for %s (%d) */\n" name i;
2527 let seq, last = get_seq_last seq in
2530 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
2535 List.iter (generate_test_command_call test_name) seq;
2536 generate_test_command_call ~test test_name last
2537 | TestOutputFalse seq ->
2538 pr " /* TestOutputFalse for %s (%d) */\n" name i;
2539 let seq, last = get_seq_last seq in
2542 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
2547 List.iter (generate_test_command_call test_name) seq;
2548 generate_test_command_call ~test test_name last
2549 | TestOutputLength (seq, expected) ->
2550 pr " /* TestOutputLength for %s (%d) */\n" name i;
2551 let seq, last = get_seq_last seq in
2554 pr " for (j = 0; j < %d; ++j)\n" expected;
2555 pr " if (r[j] == NULL) {\n";
2556 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
2558 pr " print_strings (r);\n";
2561 pr " if (r[j] != NULL) {\n";
2562 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
2564 pr " print_strings (r);\n";
2568 List.iter (generate_test_command_call test_name) seq;
2569 generate_test_command_call ~test test_name last
2570 | TestOutputStruct (seq, checks) ->
2571 pr " /* TestOutputStruct for %s (%d) */\n" name i;
2572 let seq, last = get_seq_last seq in
2576 | CompareWithInt (field, expected) ->
2577 pr " if (r->%s != %d) {\n" field expected;
2578 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
2579 test_name field expected;
2580 pr " (int) r->%s);\n" field;
2583 | CompareWithString (field, expected) ->
2584 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
2585 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
2586 test_name field expected;
2587 pr " r->%s);\n" field;
2590 | CompareFieldsIntEq (field1, field2) ->
2591 pr " if (r->%s != r->%s) {\n" field1 field2;
2592 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
2593 test_name field1 field2;
2594 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
2597 | CompareFieldsStrEq (field1, field2) ->
2598 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
2599 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
2600 test_name field1 field2;
2601 pr " r->%s, r->%s);\n" field1 field2;
2606 List.iter (generate_test_command_call test_name) seq;
2607 generate_test_command_call ~test test_name last
2608 | TestLastFail seq ->
2609 pr " /* TestLastFail for %s (%d) */\n" name i;
2610 let seq, last = get_seq_last seq in
2611 List.iter (generate_test_command_call test_name) seq;
2612 generate_test_command_call test_name ~expect_error:true last
2620 (* Generate the code to run a command, leaving the result in 'r'.
2621 * If you expect to get an error then you should set expect_error:true.
2623 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
2625 | [] -> assert false
2627 (* Look up the command to find out what args/ret it has. *)
2630 let _, style, _, _, _, _, _ =
2631 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
2634 failwithf "%s: in test, command %s was not found" test_name name in
2636 if List.length (snd style) <> List.length args then
2637 failwithf "%s: in test, wrong number of args given to %s"
2648 | StringList n, arg ->
2649 pr " char *%s[] = {\n" n;
2650 let strs = string_split " " arg in
2652 fun str -> pr " \"%s\",\n" (c_quote str)
2656 ) (List.combine (snd style) args);
2659 match fst style with
2660 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
2661 | RConstString _ -> pr " const char *r;\n"; "NULL"
2662 | RString _ -> pr " char *r;\n"; "NULL"
2668 pr " struct guestfs_int_bool *r;\n"; "NULL"
2670 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
2672 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
2674 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
2676 pr " struct guestfs_stat *r;\n"; "NULL"
2678 pr " struct guestfs_statvfs *r;\n"; "NULL" in
2680 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
2681 pr " r = guestfs_%s (g" name;
2683 (* Generate the parameters. *)
2686 | String _, arg -> pr ", \"%s\"" (c_quote arg)
2687 | OptString _, arg ->
2688 if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
2689 | StringList n, _ ->
2693 try int_of_string arg
2694 with Failure "int_of_string" ->
2695 failwithf "%s: expecting an int, but got '%s'" test_name arg in
2698 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
2699 ) (List.combine (snd style) args);
2702 if not expect_error then
2703 pr " if (r == %s)\n" error_code
2705 pr " if (r != %s)\n" error_code;
2708 (* Insert the test code. *)
2714 (match fst style with
2715 | RErr | RInt _ | RBool _ | RConstString _ -> ()
2716 | RString _ -> pr " free (r);\n"
2718 pr " for (i = 0; r[i] != NULL; ++i)\n";
2719 pr " free (r[i]);\n";
2722 pr " guestfs_free_int_bool (r);\n"
2724 pr " guestfs_free_lvm_pv_list (r);\n"
2726 pr " guestfs_free_lvm_vg_list (r);\n"
2728 pr " guestfs_free_lvm_lv_list (r);\n"
2729 | RStat _ | RStatVFS _ ->
2736 let str = replace_str str "\r" "\\r" in
2737 let str = replace_str str "\n" "\\n" in
2738 let str = replace_str str "\t" "\\t" in
2741 (* Generate a lot of different functions for guestfish. *)
2742 and generate_fish_cmds () =
2743 generate_header CStyle GPLv2;
2747 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
2749 let all_functions_sorted =
2751 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
2752 ) all_functions_sorted in
2754 pr "#include <stdio.h>\n";
2755 pr "#include <stdlib.h>\n";
2756 pr "#include <string.h>\n";
2757 pr "#include <inttypes.h>\n";
2759 pr "#include <guestfs.h>\n";
2760 pr "#include \"fish.h\"\n";
2763 (* list_commands function, which implements guestfish -h *)
2764 pr "void list_commands (void)\n";
2766 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
2767 pr " list_builtin_commands ();\n";
2769 fun (name, _, _, flags, _, shortdesc, _) ->
2770 let name = replace_char name '_' '-' in
2771 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
2773 ) all_functions_sorted;
2774 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
2778 (* display_command function, which implements guestfish -h cmd *)
2779 pr "void display_command (const char *cmd)\n";
2782 fun (name, style, _, flags, _, shortdesc, longdesc) ->
2783 let name2 = replace_char name '_' '-' in
2785 try find_map (function FishAlias n -> Some n | _ -> None) flags
2786 with Not_found -> name in
2787 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
2789 match snd style with
2793 name2 (String.concat "> <" (List.map name_of_argt args)) in
2796 if List.mem ProtocolLimitWarning flags then
2797 ("\n\n" ^ protocol_limit_warning)
2800 (* For DangerWillRobinson commands, we should probably have
2801 * guestfish prompt before allowing you to use them (especially
2802 * in interactive mode). XXX
2806 if List.mem DangerWillRobinson flags then
2807 ("\n\n" ^ danger_will_robinson)
2810 let describe_alias =
2811 if name <> alias then
2812 sprintf "\n\nYou can use '%s' as an alias for this command." alias
2816 pr "strcasecmp (cmd, \"%s\") == 0" name;
2817 if name <> name2 then
2818 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
2819 if name <> alias then
2820 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
2822 pr " pod2text (\"%s - %s\", %S);\n"
2824 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
2827 pr " display_builtin_command (cmd);\n";
2831 (* print_{pv,vg,lv}_list functions *)
2835 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
2842 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
2844 pr " printf (\"%s: \");\n" name;
2845 pr " for (i = 0; i < 32; ++i)\n";
2846 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
2847 pr " printf (\"\\n\");\n"
2849 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
2851 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
2852 | name, `OptPercent ->
2853 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
2854 typ name name typ name;
2855 pr " else printf (\"%s: \\n\");\n" name
2859 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
2864 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
2865 pr " print_%s (&%ss->val[i]);\n" typ typ;
2868 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2870 (* print_{stat,statvfs} functions *)
2874 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
2879 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
2883 ) ["stat", stat_cols; "statvfs", statvfs_cols];
2885 (* run_<action> actions *)
2887 fun (name, style, _, flags, _, _, _) ->
2888 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
2890 (match fst style with
2893 | RBool _ -> pr " int r;\n"
2894 | RConstString _ -> pr " const char *r;\n"
2895 | RString _ -> pr " char *r;\n"
2896 | RStringList _ -> pr " char **r;\n"
2897 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
2898 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
2899 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
2900 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
2901 | RStat _ -> pr " struct guestfs_stat *r;\n"
2902 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
2907 | OptString n -> pr " const char *%s;\n" n
2908 | StringList n -> pr " char **%s;\n" n
2909 | Bool n -> pr " int %s;\n" n
2910 | Int n -> pr " int %s;\n" n
2913 (* Check and convert parameters. *)
2914 let argc_expected = List.length (snd style) in
2915 pr " if (argc != %d) {\n" argc_expected;
2916 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
2918 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
2924 | String name -> pr " %s = argv[%d];\n" name i
2926 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
2928 | StringList name ->
2929 pr " %s = parse_string_list (argv[%d]);\n" name i
2931 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
2933 pr " %s = atoi (argv[%d]);\n" name i
2936 (* Call C API function. *)
2938 try find_map (function FishAction n -> Some n | _ -> None) flags
2939 with Not_found -> sprintf "guestfs_%s" name in
2941 generate_call_args ~handle:"g" style;
2944 (* Check return value for errors and display command results. *)
2945 (match fst style with
2946 | RErr -> pr " return r;\n"
2948 pr " if (r == -1) return -1;\n";
2949 pr " if (r) printf (\"%%d\\n\", r);\n";
2952 pr " if (r == -1) return -1;\n";
2953 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
2956 pr " if (r == NULL) return -1;\n";
2957 pr " printf (\"%%s\\n\", r);\n";
2960 pr " if (r == NULL) return -1;\n";
2961 pr " printf (\"%%s\\n\", r);\n";
2965 pr " if (r == NULL) return -1;\n";
2966 pr " print_strings (r);\n";
2967 pr " free_strings (r);\n";
2970 pr " if (r == NULL) return -1;\n";
2971 pr " printf (\"%%d, %%s\\n\", r->i,\n";
2972 pr " r->b ? \"true\" : \"false\");\n";
2973 pr " guestfs_free_int_bool (r);\n";
2976 pr " if (r == NULL) return -1;\n";
2977 pr " print_pv_list (r);\n";
2978 pr " guestfs_free_lvm_pv_list (r);\n";
2981 pr " if (r == NULL) return -1;\n";
2982 pr " print_vg_list (r);\n";
2983 pr " guestfs_free_lvm_vg_list (r);\n";
2986 pr " if (r == NULL) return -1;\n";
2987 pr " print_lv_list (r);\n";
2988 pr " guestfs_free_lvm_lv_list (r);\n";
2991 pr " if (r == NULL) return -1;\n";
2992 pr " print_stat (r);\n";
2996 pr " if (r == NULL) return -1;\n";
2997 pr " print_statvfs (r);\n";
3005 (* run_action function *)
3006 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3009 fun (name, _, _, flags, _, _, _) ->
3010 let name2 = replace_char name '_' '-' in
3012 try find_map (function FishAlias n -> Some n | _ -> None) flags
3013 with Not_found -> name in
3015 pr "strcasecmp (cmd, \"%s\") == 0" name;
3016 if name <> name2 then
3017 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3018 if name <> alias then
3019 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3021 pr " return run_%s (cmd, argc, argv);\n" name;
3025 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3032 (* Readline completion for guestfish. *)
3033 and generate_fish_completion () =
3034 generate_header CStyle GPLv2;
3038 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3048 #ifdef HAVE_LIBREADLINE
3049 #include <readline/readline.h>
3054 #ifdef HAVE_LIBREADLINE
3056 static const char *commands[] = {
3059 (* Get the commands and sort them, including the aliases. *)
3062 fun (name, _, _, flags, _, _, _) ->
3063 let name2 = replace_char name '_' '-' in
3065 try find_map (function FishAlias n -> Some n | _ -> None) flags
3066 with Not_found -> name in
3068 if name <> alias then [name2; alias] else [name2]
3070 let commands = List.flatten commands in
3071 let commands = List.sort compare commands in
3073 List.iter (pr " \"%s\",\n") commands;
3079 generator (const char *text, int state)
3081 static int index, len;
3086 len = strlen (text);
3089 while ((name = commands[index]) != NULL) {
3091 if (strncasecmp (name, text, len) == 0)
3092 return strdup (name);
3098 #endif /* HAVE_LIBREADLINE */
3100 char **do_completion (const char *text, int start, int end)
3102 char **matches = NULL;
3104 #ifdef HAVE_LIBREADLINE
3106 matches = rl_completion_matches (text, generator);
3113 (* Generate the POD documentation for guestfish. *)
3114 and generate_fish_actions_pod () =
3115 let all_functions_sorted =
3117 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3118 ) all_functions_sorted in
3121 fun (name, style, _, flags, _, _, longdesc) ->
3122 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3123 let name = replace_char name '_' '-' in
3125 try find_map (function FishAlias n -> Some n | _ -> None) flags
3126 with Not_found -> name in
3128 pr "=head2 %s" name;
3129 if name <> alias then
3136 | String n -> pr " %s" n
3137 | OptString n -> pr " %s" n
3138 | StringList n -> pr " %s,..." n
3139 | Bool _ -> pr " true|false"
3140 | Int n -> pr " %s" n
3144 pr "%s\n\n" longdesc;
3146 if List.mem ProtocolLimitWarning flags then
3147 pr "%s\n\n" protocol_limit_warning;
3149 if List.mem DangerWillRobinson flags then
3150 pr "%s\n\n" danger_will_robinson
3151 ) all_functions_sorted
3153 (* Generate a C function prototype. *)
3154 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3155 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3157 ?handle name style =
3158 if extern then pr "extern ";
3159 if static then pr "static ";
3160 (match fst style with
3162 | RInt _ -> pr "int "
3163 | RBool _ -> pr "int "
3164 | RConstString _ -> pr "const char *"
3165 | RString _ -> pr "char *"
3166 | RStringList _ -> pr "char **"
3168 if not in_daemon then pr "struct guestfs_int_bool *"
3169 else pr "guestfs_%s_ret *" name
3171 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3172 else pr "guestfs_lvm_int_pv_list *"
3174 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3175 else pr "guestfs_lvm_int_vg_list *"
3177 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3178 else pr "guestfs_lvm_int_lv_list *"
3180 if not in_daemon then pr "struct guestfs_stat *"
3181 else pr "guestfs_int_stat *"
3183 if not in_daemon then pr "struct guestfs_statvfs *"
3184 else pr "guestfs_int_statvfs *"
3186 pr "%s%s (" prefix name;
3187 if handle = None && List.length (snd style) = 0 then
3190 let comma = ref false in
3193 | Some handle -> pr "guestfs_h *%s" handle; comma := true
3197 if single_line then pr ", " else pr ",\n\t\t"
3203 | String n -> next (); pr "const char *%s" n
3204 | OptString n -> next (); pr "const char *%s" n
3205 | StringList n -> next (); pr "char * const* const %s" n
3206 | Bool n -> next (); pr "int %s" n
3207 | Int n -> next (); pr "int %s" n
3211 if semicolon then pr ";";
3212 if newline then pr "\n"
3214 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3215 and generate_call_args ?handle style =
3217 let comma = ref false in
3220 | Some handle -> pr "%s" handle; comma := true
3224 if !comma then pr ", ";
3231 | Int n -> pr "%s" n
3235 (* Generate the OCaml bindings interface. *)
3236 and generate_ocaml_mli () =
3237 generate_header OCamlStyle LGPLv2;
3240 (** For API documentation you should refer to the C API
3241 in the guestfs(3) manual page. The OCaml API uses almost
3242 exactly the same calls. *)
3245 (** A [guestfs_h] handle. *)
3247 exception Error of string
3248 (** This exception is raised when there is an error. *)
3250 val create : unit -> t
3252 val close : t -> unit
3253 (** Handles are closed by the garbage collector when they become
3254 unreferenced, but callers can also call this in order to
3255 provide predictable cleanup. *)
3258 generate_ocaml_lvm_structure_decls ();
3260 generate_ocaml_stat_structure_decls ();
3264 fun (name, style, _, _, _, shortdesc, _) ->
3265 generate_ocaml_prototype name style;
3266 pr "(** %s *)\n" shortdesc;
3270 (* Generate the OCaml bindings implementation. *)
3271 and generate_ocaml_ml () =
3272 generate_header OCamlStyle LGPLv2;
3276 exception Error of string
3277 external create : unit -> t = \"ocaml_guestfs_create\"
3278 external close : t -> unit = \"ocaml_guestfs_close\"
3281 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3285 generate_ocaml_lvm_structure_decls ();
3287 generate_ocaml_stat_structure_decls ();
3291 fun (name, style, _, _, _, shortdesc, _) ->
3292 generate_ocaml_prototype ~is_external:true name style;
3295 (* Generate the OCaml bindings C implementation. *)
3296 and generate_ocaml_c () =
3297 generate_header CStyle LGPLv2;
3299 pr "#include <stdio.h>\n";
3300 pr "#include <stdlib.h>\n";
3301 pr "#include <string.h>\n";
3303 pr "#include <caml/config.h>\n";
3304 pr "#include <caml/alloc.h>\n";
3305 pr "#include <caml/callback.h>\n";
3306 pr "#include <caml/fail.h>\n";
3307 pr "#include <caml/memory.h>\n";
3308 pr "#include <caml/mlvalues.h>\n";
3309 pr "#include <caml/signals.h>\n";
3311 pr "#include <guestfs.h>\n";
3313 pr "#include \"guestfs_c.h\"\n";
3316 (* LVM struct copy functions. *)
3319 let has_optpercent_col =
3320 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
3322 pr "static CAMLprim value\n";
3323 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
3325 pr " CAMLparam0 ();\n";
3326 if has_optpercent_col then
3327 pr " CAMLlocal3 (rv, v, v2);\n"
3329 pr " CAMLlocal2 (rv, v);\n";
3331 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
3336 pr " v = caml_copy_string (%s->%s);\n" typ name
3338 pr " v = caml_alloc_string (32);\n";
3339 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
3342 pr " v = caml_copy_int64 (%s->%s);\n" typ name
3343 | name, `OptPercent ->
3344 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
3345 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
3346 pr " v = caml_alloc (1, 0);\n";
3347 pr " Store_field (v, 0, v2);\n";
3348 pr " } else /* None */\n";
3349 pr " v = Val_int (0);\n";
3351 pr " Store_field (rv, %d, v);\n" i
3353 pr " CAMLreturn (rv);\n";
3357 pr "static CAMLprim value\n";
3358 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
3361 pr " CAMLparam0 ();\n";
3362 pr " CAMLlocal2 (rv, v);\n";
3365 pr " if (%ss->len == 0)\n" typ;
3366 pr " CAMLreturn (Atom (0));\n";
3368 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
3369 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
3370 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
3371 pr " caml_modify (&Field (rv, i), v);\n";
3373 pr " CAMLreturn (rv);\n";
3377 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3379 (* Stat copy functions. *)
3382 pr "static CAMLprim value\n";
3383 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
3385 pr " CAMLparam0 ();\n";
3386 pr " CAMLlocal2 (rv, v);\n";
3388 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
3393 pr " v = caml_copy_int64 (%s->%s);\n" typ name
3395 pr " Store_field (rv, %d, v);\n" i
3397 pr " CAMLreturn (rv);\n";
3400 ) ["stat", stat_cols; "statvfs", statvfs_cols];
3404 fun (name, style, _, _, _, _, _) ->
3406 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
3408 pr "CAMLprim value\n";
3409 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
3410 List.iter (pr ", value %s") (List.tl params);
3415 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
3416 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
3417 pr " CAMLxparam%d (%s);\n"
3418 (List.length rest) (String.concat ", " rest)
3420 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
3422 pr " CAMLlocal1 (rv);\n";
3425 pr " guestfs_h *g = Guestfs_val (gv);\n";
3426 pr " if (g == NULL)\n";
3427 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
3433 pr " const char *%s = String_val (%sv);\n" n n
3435 pr " const char *%s =\n" n;
3436 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
3439 pr " char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
3441 pr " int %s = Bool_val (%sv);\n" n n
3443 pr " int %s = Int_val (%sv);\n" n n
3446 match fst style with
3447 | RErr -> pr " int r;\n"; "-1"
3448 | RInt _ -> pr " int r;\n"; "-1"
3449 | RBool _ -> pr " int r;\n"; "-1"
3450 | RConstString _ -> pr " const char *r;\n"; "NULL"
3451 | RString _ -> pr " char *r;\n"; "NULL"
3457 pr " struct guestfs_int_bool *r;\n"; "NULL"
3459 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
3461 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
3463 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
3465 pr " struct guestfs_stat *r;\n"; "NULL"
3467 pr " struct guestfs_statvfs *r;\n"; "NULL" in
3470 pr " caml_enter_blocking_section ();\n";
3471 pr " r = guestfs_%s " name;
3472 generate_call_args ~handle:"g" style;
3474 pr " caml_leave_blocking_section ();\n";
3479 pr " ocaml_guestfs_free_strings (%s);\n" n;
3480 | String _ | OptString _ | Bool _ | Int _ -> ()
3483 pr " if (r == %s)\n" error_code;
3484 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
3487 (match fst style with
3488 | RErr -> pr " rv = Val_unit;\n"
3489 | RInt _ -> pr " rv = Val_int (r);\n"
3490 | RBool _ -> pr " rv = Val_bool (r);\n"
3491 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
3493 pr " rv = caml_copy_string (r);\n";
3496 pr " rv = caml_copy_string_array ((const char **) r);\n";
3497 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
3500 pr " rv = caml_alloc (2, 0);\n";
3501 pr " Store_field (rv, 0, Val_int (r->i));\n";
3502 pr " Store_field (rv, 1, Val_bool (r->b));\n";
3503 pr " guestfs_free_int_bool (r);\n";
3505 pr " rv = copy_lvm_pv_list (r);\n";
3506 pr " guestfs_free_lvm_pv_list (r);\n";
3508 pr " rv = copy_lvm_vg_list (r);\n";
3509 pr " guestfs_free_lvm_vg_list (r);\n";
3511 pr " rv = copy_lvm_lv_list (r);\n";
3512 pr " guestfs_free_lvm_lv_list (r);\n";
3514 pr " rv = copy_stat (r);\n";
3517 pr " rv = copy_statvfs (r);\n";
3521 pr " CAMLreturn (rv);\n";
3525 if List.length params > 5 then (
3526 pr "CAMLprim value\n";
3527 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
3529 pr " return ocaml_guestfs_%s (argv[0]" name;
3530 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
3537 and generate_ocaml_lvm_structure_decls () =
3540 pr "type lvm_%s = {\n" typ;
3543 | name, `String -> pr " %s : string;\n" name
3544 | name, `UUID -> pr " %s : string;\n" name
3545 | name, `Bytes -> pr " %s : int64;\n" name
3546 | name, `Int -> pr " %s : int64;\n" name
3547 | name, `OptPercent -> pr " %s : float option;\n" name
3551 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3553 and generate_ocaml_stat_structure_decls () =
3556 pr "type %s = {\n" typ;
3559 | name, `Int -> pr " %s : int64;\n" name
3563 ) ["stat", stat_cols; "statvfs", statvfs_cols]
3565 and generate_ocaml_prototype ?(is_external = false) name style =
3566 if is_external then pr "external " else pr "val ";
3567 pr "%s : t -> " name;
3570 | String _ -> pr "string -> "
3571 | OptString _ -> pr "string option -> "
3572 | StringList _ -> pr "string array -> "
3573 | Bool _ -> pr "bool -> "
3574 | Int _ -> pr "int -> "
3576 (match fst style with
3577 | RErr -> pr "unit" (* all errors are turned into exceptions *)
3578 | RInt _ -> pr "int"
3579 | RBool _ -> pr "bool"
3580 | RConstString _ -> pr "string"
3581 | RString _ -> pr "string"
3582 | RStringList _ -> pr "string array"
3583 | RIntBool _ -> pr "int * bool"
3584 | RPVList _ -> pr "lvm_pv array"
3585 | RVGList _ -> pr "lvm_vg array"
3586 | RLVList _ -> pr "lvm_lv array"
3587 | RStat _ -> pr "stat"
3588 | RStatVFS _ -> pr "statvfs"
3590 if is_external then (
3592 if List.length (snd style) + 1 > 5 then
3593 pr "\"ocaml_guestfs_%s_byte\" " name;
3594 pr "\"ocaml_guestfs_%s\"" name
3598 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
3599 and generate_perl_xs () =
3600 generate_header CStyle LGPLv2;
3603 #include \"EXTERN.h\"
3607 #include <guestfs.h>
3610 #define PRId64 \"lld\"
3614 my_newSVll(long long val) {
3615 #ifdef USE_64_BIT_ALL
3616 return newSViv(val);
3620 len = snprintf(buf, 100, \"%%\" PRId64, val);
3621 return newSVpv(buf, len);
3626 #define PRIu64 \"llu\"
3630 my_newSVull(unsigned long long val) {
3631 #ifdef USE_64_BIT_ALL
3632 return newSVuv(val);
3636 len = snprintf(buf, 100, \"%%\" PRIu64, val);
3637 return newSVpv(buf, len);
3641 /* http://www.perlmonks.org/?node_id=680842 */
3643 XS_unpack_charPtrPtr (SV *arg) {
3648 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
3649 croak (\"array reference expected\");
3652 av = (AV *)SvRV (arg);
3653 ret = (char **)malloc (av_len (av) + 1 + 1);
3655 for (i = 0; i <= av_len (av); i++) {
3656 SV **elem = av_fetch (av, i, 0);
3658 if (!elem || !*elem)
3659 croak (\"missing element in list\");
3661 ret[i] = SvPV_nolen (*elem);
3669 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
3674 RETVAL = guestfs_create ();
3676 croak (\"could not create guestfs handle\");
3677 guestfs_set_error_handler (RETVAL, NULL, NULL);
3690 fun (name, style, _, _, _, _, _) ->
3691 (match fst style with
3692 | RErr -> pr "void\n"
3693 | RInt _ -> pr "SV *\n"
3694 | RBool _ -> pr "SV *\n"
3695 | RConstString _ -> pr "SV *\n"
3696 | RString _ -> pr "SV *\n"
3699 | RPVList _ | RVGList _ | RLVList _
3700 | RStat _ | RStatVFS _ ->
3701 pr "void\n" (* all lists returned implictly on the stack *)
3703 (* Call and arguments. *)
3705 generate_call_args ~handle:"g" style;
3707 pr " guestfs_h *g;\n";
3710 | String n -> pr " char *%s;\n" n
3711 | OptString n -> pr " char *%s;\n" n
3712 | StringList n -> pr " char **%s;\n" n
3713 | Bool n -> pr " int %s;\n" n
3714 | Int n -> pr " int %s;\n" n
3717 let do_cleanups () =
3724 | StringList n -> pr " free (%s);\n" n
3729 (match fst style with
3734 pr " r = guestfs_%s " name;
3735 generate_call_args ~handle:"g" style;
3738 pr " if (r == -1)\n";
3739 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3745 pr " %s = guestfs_%s " n name;
3746 generate_call_args ~handle:"g" style;
3749 pr " if (%s == -1)\n" n;
3750 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3751 pr " RETVAL = newSViv (%s);\n" n;
3756 pr " const char *%s;\n" n;
3758 pr " %s = guestfs_%s " n name;
3759 generate_call_args ~handle:"g" style;
3762 pr " if (%s == NULL)\n" n;
3763 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3764 pr " RETVAL = newSVpv (%s, 0);\n" n;
3769 pr " char *%s;\n" n;
3771 pr " %s = guestfs_%s " n name;
3772 generate_call_args ~handle:"g" style;
3775 pr " if (%s == NULL)\n" n;
3776 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3777 pr " RETVAL = newSVpv (%s, 0);\n" n;
3778 pr " free (%s);\n" n;
3783 pr " char **%s;\n" n;
3786 pr " %s = guestfs_%s " n name;
3787 generate_call_args ~handle:"g" style;
3790 pr " if (%s == NULL)\n" n;
3791 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3792 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
3793 pr " EXTEND (SP, n);\n";
3794 pr " for (i = 0; i < n; ++i) {\n";
3795 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
3796 pr " free (%s[i]);\n" n;
3798 pr " free (%s);\n" n;
3801 pr " struct guestfs_int_bool *r;\n";
3803 pr " r = guestfs_%s " name;
3804 generate_call_args ~handle:"g" style;
3807 pr " if (r == NULL)\n";
3808 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3809 pr " EXTEND (SP, 2);\n";
3810 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
3811 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
3812 pr " guestfs_free_int_bool (r);\n";
3814 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
3816 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
3818 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
3820 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
3822 generate_perl_stat_code
3823 "statvfs" statvfs_cols name style n do_cleanups
3829 and generate_perl_lvm_code typ cols name style n do_cleanups =
3831 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
3835 pr " %s = guestfs_%s " n name;
3836 generate_call_args ~handle:"g" style;
3839 pr " if (%s == NULL)\n" n;
3840 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3841 pr " EXTEND (SP, %s->len);\n" n;
3842 pr " for (i = 0; i < %s->len; ++i) {\n" n;
3843 pr " hv = newHV ();\n";
3847 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
3848 name (String.length name) n name
3850 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
3851 name (String.length name) n name
3853 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
3854 name (String.length name) n name
3856 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
3857 name (String.length name) n name
3858 | name, `OptPercent ->
3859 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
3860 name (String.length name) n name
3862 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
3864 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
3866 and generate_perl_stat_code typ cols name style n do_cleanups =
3868 pr " struct guestfs_%s *%s;\n" typ n;
3870 pr " %s = guestfs_%s " n name;
3871 generate_call_args ~handle:"g" style;
3874 pr " if (%s == NULL)\n" n;
3875 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3876 pr " EXTEND (SP, %d);\n" (List.length cols);
3880 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
3882 pr " free (%s);\n" n
3884 (* Generate Sys/Guestfs.pm. *)
3885 and generate_perl_pm () =
3886 generate_header HashStyle LGPLv2;
3893 Sys::Guestfs - Perl bindings for libguestfs
3899 my $h = Sys::Guestfs->new ();
3900 $h->add_drive ('guest.img');
3903 $h->mount ('/dev/sda1', '/');
3904 $h->touch ('/hello');
3909 The C<Sys::Guestfs> module provides a Perl XS binding to the
3910 libguestfs API for examining and modifying virtual machine
3913 Amongst the things this is good for: making batch configuration
3914 changes to guests, getting disk used/free statistics (see also:
3915 virt-df), migrating between virtualization systems (see also:
3916 virt-p2v), performing partial backups, performing partial guest
3917 clones, cloning guests and changing registry/UUID/hostname info, and
3920 Libguestfs uses Linux kernel and qemu code, and can access any type of
3921 guest filesystem that Linux and qemu can, including but not limited
3922 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
3923 schemes, qcow, qcow2, vmdk.
3925 Libguestfs provides ways to enumerate guest storage (eg. partitions,
3926 LVs, what filesystem is in each LV, etc.). It can also run commands
3927 in the context of the guest. Also you can access filesystems over FTP.
3931 All errors turn into calls to C<croak> (see L<Carp(3)>).
3939 package Sys::Guestfs;
3945 XSLoader::load ('Sys::Guestfs');
3947 =item $h = Sys::Guestfs->new ();
3949 Create a new guestfs handle.
3955 my $class = ref ($proto) || $proto;
3957 my $self = Sys::Guestfs::_create ();
3958 bless $self, $class;
3964 (* Actions. We only need to print documentation for these as
3965 * they are pulled in from the XS code automatically.
3968 fun (name, style, _, flags, _, _, longdesc) ->
3969 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
3971 generate_perl_prototype name style;
3973 pr "%s\n\n" longdesc;
3974 if List.mem ProtocolLimitWarning flags then
3975 pr "%s\n\n" protocol_limit_warning;
3976 if List.mem DangerWillRobinson flags then
3977 pr "%s\n\n" danger_will_robinson
3978 ) all_functions_sorted;
3990 Copyright (C) 2009 Red Hat Inc.
3994 Please see the file COPYING.LIB for the full license.
3998 L<guestfs(3)>, L<guestfish(1)>.
4003 and generate_perl_prototype name style =
4004 (match fst style with
4009 | RString n -> pr "$%s = " n
4010 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4014 | RLVList n -> pr "@%s = " n
4016 | RStatVFS n -> pr "%%%s = " n
4019 let comma = ref false in
4022 if !comma then pr ", ";
4025 | String n | OptString n | Bool n | Int n ->
4032 (* Generate Python C module. *)
4033 and generate_python_c () =
4034 generate_header CStyle LGPLv2;
4043 #include \"guestfs.h\"
4051 get_handle (PyObject *obj)
4054 assert (obj != Py_None);
4055 return ((Pyguestfs_Object *) obj)->g;
4059 put_handle (guestfs_h *g)
4063 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4066 /* This list should be freed (but not the strings) after use. */
4067 static const char **
4068 get_string_list (PyObject *obj)
4075 if (!PyList_Check (obj)) {
4076 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4080 len = PyList_Size (obj);
4081 r = malloc (sizeof (char *) * (len+1));
4083 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4087 for (i = 0; i < len; ++i)
4088 r[i] = PyString_AsString (PyList_GetItem (obj, i));
4095 put_string_list (char * const * const argv)
4100 for (argc = 0; argv[argc] != NULL; ++argc)
4103 list = PyList_New (argc);
4104 for (i = 0; i < argc; ++i)
4105 PyList_SetItem (list, i, PyString_FromString (argv[i]));
4111 free_strings (char **argv)
4115 for (argc = 0; argv[argc] != NULL; ++argc)
4121 py_guestfs_create (PyObject *self, PyObject *args)
4125 g = guestfs_create ();
4127 PyErr_SetString (PyExc_RuntimeError,
4128 \"guestfs.create: failed to allocate handle\");
4131 guestfs_set_error_handler (g, NULL, NULL);
4132 return put_handle (g);
4136 py_guestfs_close (PyObject *self, PyObject *args)
4141 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4143 g = get_handle (py_g);
4147 Py_INCREF (Py_None);
4153 (* LVM structures, turned into Python dictionaries. *)
4156 pr "static PyObject *\n";
4157 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4159 pr " PyObject *dict;\n";
4161 pr " dict = PyDict_New ();\n";
4165 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4166 pr " PyString_FromString (%s->%s));\n"
4169 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4170 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
4173 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4174 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
4177 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4178 pr " PyLong_FromLongLong (%s->%s));\n"
4180 | name, `OptPercent ->
4181 pr " if (%s->%s >= 0)\n" typ name;
4182 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4183 pr " PyFloat_FromDouble ((double) %s->%s));\n"
4186 pr " Py_INCREF (Py_None);\n";
4187 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
4190 pr " return dict;\n";
4194 pr "static PyObject *\n";
4195 pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
4197 pr " PyObject *list;\n";
4200 pr " list = PyList_New (%ss->len);\n" typ;
4201 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
4202 pr " PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
4203 pr " return list;\n";
4206 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4208 (* Stat structures, turned into Python dictionaries. *)
4211 pr "static PyObject *\n";
4212 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
4214 pr " PyObject *dict;\n";
4216 pr " dict = PyDict_New ();\n";
4220 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4221 pr " PyLong_FromLongLong (%s->%s));\n"
4224 pr " return dict;\n";
4227 ) ["stat", stat_cols; "statvfs", statvfs_cols];
4229 (* Python wrapper functions. *)
4231 fun (name, style, _, _, _, _, _) ->
4232 pr "static PyObject *\n";
4233 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
4236 pr " PyObject *py_g;\n";
4237 pr " guestfs_h *g;\n";
4238 pr " PyObject *py_r;\n";
4241 match fst style with
4242 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
4243 | RConstString _ -> pr " const char *r;\n"; "NULL"
4244 | RString _ -> pr " char *r;\n"; "NULL"
4245 | RStringList _ -> pr " char **r;\n"; "NULL"
4246 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
4247 | RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
4248 | RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
4249 | RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
4250 | RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
4251 | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
4255 | String n -> pr " const char *%s;\n" n
4256 | OptString n -> pr " const char *%s;\n" n
4258 pr " PyObject *py_%s;\n" n;
4259 pr " const char **%s;\n" n
4260 | Bool n -> pr " int %s;\n" n
4261 | Int n -> pr " int %s;\n" n