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 (* Key-value pairs of untyped strings. Turns into a hashtable or
72 * dictionary in languages which support it. DON'T use this as a
73 * general "bucket" for results. Prefer a stronger typed return
74 * value if one is available, or write a custom struct. Don't use
75 * this if the list could potentially be very long, since it is
76 * inefficient. Keys should be unique. NULLs are not permitted.
78 | RHashtable of string
80 and args = argt list (* Function parameters, guestfs handle is implicit. *)
82 (* Note in future we should allow a "variable args" parameter as
83 * the final parameter, to allow commands like
84 * chmod mode file [file(s)...]
85 * This is not implemented yet, but many commands (such as chmod)
86 * are currently defined with the argument order keeping this future
87 * possibility in mind.
90 | String of string (* const char *name, cannot be NULL *)
91 | OptString of string (* const char *name, may be NULL *)
92 | StringList of string(* list of strings (each string cannot be NULL) *)
93 | Bool of string (* boolean *)
94 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
97 | ProtocolLimitWarning (* display warning about protocol size limits *)
98 | DangerWillRobinson (* flags particularly dangerous commands *)
99 | FishAlias of string (* provide an alias for this cmd in guestfish *)
100 | FishAction of string (* call this function in guestfish *)
101 | NotInFish (* do not export via guestfish *)
103 let protocol_limit_warning =
104 "Because of the message protocol, there is a transfer limit
105 of somewhere between 2MB and 4MB. To transfer large files you should use
108 let danger_will_robinson =
109 "B<This command is dangerous. Without careful use you
110 can easily destroy all your data>."
112 (* You can supply zero or as many tests as you want per API call.
114 * Note that the test environment has 3 block devices, of size 500MB,
115 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc).
116 * Note for partitioning purposes, the 500MB device has 63 cylinders.
118 * To be able to run the tests in a reasonable amount of time,
119 * the virtual machine and block devices are reused between tests.
120 * So don't try testing kill_subprocess :-x
122 * Between each test we umount-all and lvm-remove-all (except InitNone).
124 * Don't assume anything about the previous contents of the block
125 * devices. Use 'Init*' to create some initial scenarios.
127 type tests = (test_init * test) list
129 (* Run the command sequence and just expect nothing to fail. *)
131 (* Run the command sequence and expect the output of the final
132 * command to be the string.
134 | TestOutput of seq * string
135 (* Run the command sequence and expect the output of the final
136 * command to be the list of strings.
138 | TestOutputList of seq * string list
139 (* Run the command sequence and expect the output of the final
140 * command to be the integer.
142 | TestOutputInt of seq * int
143 (* Run the command sequence and expect the output of the final
144 * command to be a true value (!= 0 or != NULL).
146 | TestOutputTrue of seq
147 (* Run the command sequence and expect the output of the final
148 * command to be a false value (== 0 or == NULL, but not an error).
150 | TestOutputFalse of seq
151 (* Run the command sequence and expect the output of the final
152 * command to be a list of the given length (but don't care about
155 | TestOutputLength of seq * int
156 (* Run the command sequence and expect the output of the final
157 * command to be a structure.
159 | TestOutputStruct of seq * test_field_compare list
160 (* Run the command sequence and expect the final command (only)
163 | TestLastFail of seq
165 and test_field_compare =
166 | CompareWithInt of string * int
167 | CompareWithString of string * string
168 | CompareFieldsIntEq of string * string
169 | CompareFieldsStrEq of string * string
171 (* Some initial scenarios for testing. *)
173 (* Do nothing, block devices could contain random stuff including
174 * LVM PVs, and some filesystems might be mounted. This is usually
178 (* Block devices are empty and no filesystems are mounted. *)
180 (* /dev/sda contains a single partition /dev/sda1, which is formatted
181 * as ext2, empty [except for lost+found] and mounted on /.
182 * /dev/sdb and /dev/sdc may have random content.
187 * /dev/sda1 (is a PV):
188 * /dev/VG/LV (size 8MB):
189 * formatted as ext2, empty [except for lost+found], mounted on /
190 * /dev/sdb and /dev/sdc may have random content.
194 (* Sequence of commands for testing. *)
196 and cmd = string list
198 (* Note about long descriptions: When referring to another
199 * action, use the format C<guestfs_other> (ie. the full name of
200 * the C function). This will be replaced as appropriate in other
203 * Apart from that, long descriptions are just perldoc paragraphs.
206 let non_daemon_functions = [
207 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
209 "launch the qemu subprocess",
211 Internally libguestfs is implemented by running a virtual machine
214 You should call this after configuring the handle
215 (eg. adding drives) but before performing any actions.");
217 ("wait_ready", (RErr, []), -1, [NotInFish],
219 "wait until the qemu subprocess launches",
221 Internally libguestfs is implemented by running a virtual machine
224 You should call this after C<guestfs_launch> to wait for the launch
227 ("kill_subprocess", (RErr, []), -1, [],
229 "kill the qemu subprocess",
231 This kills the qemu subprocess. You should never need to call this.");
233 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
235 "add an image to examine or modify",
237 This function adds a virtual machine disk image C<filename> to the
238 guest. The first time you call this function, the disk appears as IDE
239 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
242 You don't necessarily need to be root when using libguestfs. However
243 you obviously do need sufficient permissions to access the filename
244 for whatever operations you want to perform (ie. read access if you
245 just want to read the image or write access if you want to modify the
248 This is equivalent to the qemu parameter C<-drive file=filename>.");
250 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
252 "add a CD-ROM disk image to examine",
254 This function adds a virtual CD-ROM disk image to the guest.
256 This is equivalent to the qemu parameter C<-cdrom filename>.");
258 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
260 "add qemu parameters",
262 This can be used to add arbitrary qemu command line parameters
263 of the form C<-param value>. Actually it's not quite arbitrary - we
264 prevent you from setting some parameters which would interfere with
265 parameters that we use.
267 The first character of C<param> string must be a C<-> (dash).
269 C<value> can be NULL.");
271 ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
273 "set the search path",
275 Set the path that libguestfs searches for kernel and initrd.img.
277 The default is C<$libdir/guestfs> unless overridden by setting
278 C<LIBGUESTFS_PATH> environment variable.
280 The string C<path> is stashed in the libguestfs handle, so the caller
281 must make sure it remains valid for the lifetime of the handle.
283 Setting C<path> to C<NULL> restores the default path.");
285 ("get_path", (RConstString "path", []), -1, [],
287 "get the search path",
289 Return the current search path.
291 This is always non-NULL. If it wasn't set already, then this will
292 return the default path.");
294 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
298 If C<autosync> is true, this enables autosync. Libguestfs will make a
299 best effort attempt to run C<guestfs_sync> when the handle is closed
300 (also if the program exits without closing handles).");
302 ("get_autosync", (RBool "autosync", []), -1, [],
306 Get the autosync flag.");
308 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
312 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
314 Verbose messages are disabled unless the environment variable
315 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
317 ("get_verbose", (RBool "verbose", []), -1, [],
321 This returns the verbose messages flag.")
324 let daemon_functions = [
325 ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
326 [InitEmpty, TestOutput (
327 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
328 ["mkfs"; "ext2"; "/dev/sda1"];
329 ["mount"; "/dev/sda1"; "/"];
330 ["write_file"; "/new"; "new file contents"; "0"];
331 ["cat"; "/new"]], "new file contents")],
332 "mount a guest disk at a position in the filesystem",
334 Mount a guest disk at a position in the filesystem. Block devices
335 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
336 the guest. If those block devices contain partitions, they will have
337 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
340 The rules are the same as for L<mount(2)>: A filesystem must
341 first be mounted on C</> before others can be mounted. Other
342 filesystems can only be mounted on directories which already
345 The mounted filesystem is writable, if we have sufficient permissions
346 on the underlying device.
348 The filesystem options C<sync> and C<noatime> are set with this
349 call, in order to improve reliability.");
351 ("sync", (RErr, []), 2, [],
352 [ InitEmpty, TestRun [["sync"]]],
353 "sync disks, writes are flushed through to the disk image",
355 This syncs the disk, so that any writes are flushed through to the
356 underlying disk image.
358 You should always call this if you have modified a disk image, before
359 closing the handle.");
361 ("touch", (RErr, [String "path"]), 3, [],
362 [InitBasicFS, TestOutputTrue (
364 ["exists"; "/new"]])],
365 "update file timestamps or create a new file",
367 Touch acts like the L<touch(1)> command. It can be used to
368 update the timestamps on a file, or, if the file does not exist,
369 to create a new zero-length file.");
371 ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
372 [InitBasicFS, TestOutput (
373 [["write_file"; "/new"; "new file contents"; "0"];
374 ["cat"; "/new"]], "new file contents")],
375 "list the contents of a file",
377 Return the contents of the file named C<path>.
379 Note that this function cannot correctly handle binary files
380 (specifically, files containing C<\\0> character which is treated
381 as end of string). For those you need to use the C<guestfs_read_file>
382 function which has a more complex interface.");
384 ("ll", (RString "listing", [String "directory"]), 5, [],
385 [], (* XXX Tricky to test because it depends on the exact format
386 * of the 'ls -l' command, which changes between F10 and F11.
388 "list the files in a directory (long format)",
390 List the files in C<directory> (relative to the root directory,
391 there is no cwd) in the format of 'ls -la'.
393 This command is mostly useful for interactive sessions. It
394 is I<not> intended that you try to parse the output string.");
396 ("ls", (RStringList "listing", [String "directory"]), 6, [],
397 [InitBasicFS, TestOutputList (
400 ["touch"; "/newest"];
401 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
402 "list the files in a directory",
404 List the files in C<directory> (relative to the root directory,
405 there is no cwd). The '.' and '..' entries are not returned, but
406 hidden files are shown.
408 This command is mostly useful for interactive sessions. Programs
409 should probably use C<guestfs_readdir> instead.");
411 ("list_devices", (RStringList "devices", []), 7, [],
412 [InitEmpty, TestOutputList (
413 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
414 "list the block devices",
416 List all the block devices.
418 The full block device names are returned, eg. C</dev/sda>");
420 ("list_partitions", (RStringList "partitions", []), 8, [],
421 [InitBasicFS, TestOutputList (
422 [["list_partitions"]], ["/dev/sda1"]);
423 InitEmpty, TestOutputList (
424 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
425 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
426 "list the partitions",
428 List all the partitions detected on all block devices.
430 The full partition device names are returned, eg. C</dev/sda1>
432 This does not return logical volumes. For that you will need to
433 call C<guestfs_lvs>.");
435 ("pvs", (RStringList "physvols", []), 9, [],
436 [InitBasicFSonLVM, TestOutputList (
437 [["pvs"]], ["/dev/sda1"]);
438 InitEmpty, TestOutputList (
439 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
440 ["pvcreate"; "/dev/sda1"];
441 ["pvcreate"; "/dev/sda2"];
442 ["pvcreate"; "/dev/sda3"];
443 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
444 "list the LVM physical volumes (PVs)",
446 List all the physical volumes detected. This is the equivalent
447 of the L<pvs(8)> command.
449 This returns a list of just the device names that contain
450 PVs (eg. C</dev/sda2>).
452 See also C<guestfs_pvs_full>.");
454 ("vgs", (RStringList "volgroups", []), 10, [],
455 [InitBasicFSonLVM, TestOutputList (
457 InitEmpty, TestOutputList (
458 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
459 ["pvcreate"; "/dev/sda1"];
460 ["pvcreate"; "/dev/sda2"];
461 ["pvcreate"; "/dev/sda3"];
462 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
463 ["vgcreate"; "VG2"; "/dev/sda3"];
464 ["vgs"]], ["VG1"; "VG2"])],
465 "list the LVM volume groups (VGs)",
467 List all the volumes groups detected. This is the equivalent
468 of the L<vgs(8)> command.
470 This returns a list of just the volume group names that were
471 detected (eg. C<VolGroup00>).
473 See also C<guestfs_vgs_full>.");
475 ("lvs", (RStringList "logvols", []), 11, [],
476 [InitBasicFSonLVM, TestOutputList (
477 [["lvs"]], ["/dev/VG/LV"]);
478 InitEmpty, TestOutputList (
479 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
480 ["pvcreate"; "/dev/sda1"];
481 ["pvcreate"; "/dev/sda2"];
482 ["pvcreate"; "/dev/sda3"];
483 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
484 ["vgcreate"; "VG2"; "/dev/sda3"];
485 ["lvcreate"; "LV1"; "VG1"; "50"];
486 ["lvcreate"; "LV2"; "VG1"; "50"];
487 ["lvcreate"; "LV3"; "VG2"; "50"];
488 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
489 "list the LVM logical volumes (LVs)",
491 List all the logical volumes detected. This is the equivalent
492 of the L<lvs(8)> command.
494 This returns a list of the logical volume device names
495 (eg. C</dev/VolGroup00/LogVol00>).
497 See also C<guestfs_lvs_full>.");
499 ("pvs_full", (RPVList "physvols", []), 12, [],
500 [], (* XXX how to test? *)
501 "list the LVM physical volumes (PVs)",
503 List all the physical volumes detected. This is the equivalent
504 of the L<pvs(8)> command. The \"full\" version includes all fields.");
506 ("vgs_full", (RVGList "volgroups", []), 13, [],
507 [], (* XXX how to test? *)
508 "list the LVM volume groups (VGs)",
510 List all the volumes groups detected. This is the equivalent
511 of the L<vgs(8)> command. The \"full\" version includes all fields.");
513 ("lvs_full", (RLVList "logvols", []), 14, [],
514 [], (* XXX how to test? *)
515 "list the LVM logical volumes (LVs)",
517 List all the logical volumes detected. This is the equivalent
518 of the L<lvs(8)> command. The \"full\" version includes all fields.");
520 ("read_lines", (RStringList "lines", [String "path"]), 15, [],
521 [InitBasicFS, TestOutputList (
522 [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
523 ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
524 InitBasicFS, TestOutputList (
525 [["write_file"; "/new"; ""; "0"];
526 ["read_lines"; "/new"]], [])],
527 "read file as lines",
529 Return the contents of the file named C<path>.
531 The file contents are returned as a list of lines. Trailing
532 C<LF> and C<CRLF> character sequences are I<not> returned.
534 Note that this function cannot correctly handle binary files
535 (specifically, files containing C<\\0> character which is treated
536 as end of line). For those you need to use the C<guestfs_read_file>
537 function which has a more complex interface.");
539 ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
540 [], (* XXX Augeas code needs tests. *)
541 "create a new Augeas handle",
543 Create a new Augeas handle for editing configuration files.
544 If there was any previous Augeas handle associated with this
545 guestfs session, then it is closed.
547 You must call this before using any other C<guestfs_aug_*>
550 C<root> is the filesystem root. C<root> must not be NULL,
553 The flags are the same as the flags defined in
554 E<lt>augeas.hE<gt>, the logical I<or> of the following
559 =item C<AUG_SAVE_BACKUP> = 1
561 Keep the original file with a C<.augsave> extension.
563 =item C<AUG_SAVE_NEWFILE> = 2
565 Save changes into a file with extension C<.augnew>, and
566 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
568 =item C<AUG_TYPE_CHECK> = 4
570 Typecheck lenses (can be expensive).
572 =item C<AUG_NO_STDINC> = 8
574 Do not use standard load path for modules.
576 =item C<AUG_SAVE_NOOP> = 16
578 Make save a no-op, just record what would have been changed.
580 =item C<AUG_NO_LOAD> = 32
582 Do not load the tree in C<guestfs_aug_init>.
586 To close the handle, you can call C<guestfs_aug_close>.
588 To find out more about Augeas, see L<http://augeas.net/>.");
590 ("aug_close", (RErr, []), 26, [],
591 [], (* XXX Augeas code needs tests. *)
592 "close the current Augeas handle",
594 Close the current Augeas handle and free up any resources
595 used by it. After calling this, you have to call
596 C<guestfs_aug_init> again before you can use any other
599 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
600 [], (* XXX Augeas code needs tests. *)
601 "define an Augeas variable",
603 Defines an Augeas variable C<name> whose value is the result
604 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
607 On success this returns the number of nodes in C<expr>, or
608 C<0> if C<expr> evaluates to something which is not a nodeset.");
610 ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
611 [], (* XXX Augeas code needs tests. *)
612 "define an Augeas node",
614 Defines a variable C<name> whose value is the result of
617 If C<expr> evaluates to an empty nodeset, a node is created,
618 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
619 C<name> will be the nodeset containing that single node.
621 On success this returns a pair containing the
622 number of nodes in the nodeset, and a boolean flag
623 if a node was created.");
625 ("aug_get", (RString "val", [String "path"]), 19, [],
626 [], (* XXX Augeas code needs tests. *)
627 "look up the value of an Augeas path",
629 Look up the value associated with C<path>. If C<path>
630 matches exactly one node, the C<value> is returned.");
632 ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
633 [], (* XXX Augeas code needs tests. *)
634 "set Augeas path to value",
636 Set the value associated with C<path> to C<value>.");
638 ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
639 [], (* XXX Augeas code needs tests. *)
640 "insert a sibling Augeas node",
642 Create a new sibling C<label> for C<path>, inserting it into
643 the tree before or after C<path> (depending on the boolean
646 C<path> must match exactly one existing node in the tree, and
647 C<label> must be a label, ie. not contain C</>, C<*> or end
648 with a bracketed index C<[N]>.");
650 ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
651 [], (* XXX Augeas code needs tests. *)
652 "remove an Augeas path",
654 Remove C<path> and all of its children.
656 On success this returns the number of entries which were removed.");
658 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
659 [], (* XXX Augeas code needs tests. *)
662 Move the node C<src> to C<dest>. C<src> must match exactly
663 one node. C<dest> is overwritten if it exists.");
665 ("aug_match", (RStringList "matches", [String "path"]), 24, [],
666 [], (* XXX Augeas code needs tests. *)
667 "return Augeas nodes which match path",
669 Returns a list of paths which match the path expression C<path>.
670 The returned paths are sufficiently qualified so that they match
671 exactly one node in the current tree.");
673 ("aug_save", (RErr, []), 25, [],
674 [], (* XXX Augeas code needs tests. *)
675 "write all pending Augeas changes to disk",
677 This writes all pending changes to disk.
679 The flags which were passed to C<guestfs_aug_init> affect exactly
680 how files are saved.");
682 ("aug_load", (RErr, []), 27, [],
683 [], (* XXX Augeas code needs tests. *)
684 "load files into the tree",
686 Load files into the tree.
688 See C<aug_load> in the Augeas documentation for the full gory
691 ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
692 [], (* XXX Augeas code needs tests. *)
693 "list Augeas nodes under a path",
695 This is just a shortcut for listing C<guestfs_aug_match>
696 C<path/*> and sorting the resulting nodes into alphabetical order.");
698 ("rm", (RErr, [String "path"]), 29, [],
699 [InitBasicFS, TestRun
702 InitBasicFS, TestLastFail
704 InitBasicFS, TestLastFail
709 Remove the single file C<path>.");
711 ("rmdir", (RErr, [String "path"]), 30, [],
712 [InitBasicFS, TestRun
715 InitBasicFS, TestLastFail
717 InitBasicFS, TestLastFail
720 "remove a directory",
722 Remove the single directory C<path>.");
724 ("rm_rf", (RErr, [String "path"]), 31, [],
725 [InitBasicFS, TestOutputFalse
727 ["mkdir"; "/new/foo"];
728 ["touch"; "/new/foo/bar"];
730 ["exists"; "/new"]]],
731 "remove a file or directory recursively",
733 Remove the file or directory C<path>, recursively removing the
734 contents if its a directory. This is like the C<rm -rf> shell
737 ("mkdir", (RErr, [String "path"]), 32, [],
738 [InitBasicFS, TestOutputTrue
741 InitBasicFS, TestLastFail
742 [["mkdir"; "/new/foo/bar"]]],
743 "create a directory",
745 Create a directory named C<path>.");
747 ("mkdir_p", (RErr, [String "path"]), 33, [],
748 [InitBasicFS, TestOutputTrue
749 [["mkdir_p"; "/new/foo/bar"];
750 ["is_dir"; "/new/foo/bar"]];
751 InitBasicFS, TestOutputTrue
752 [["mkdir_p"; "/new/foo/bar"];
753 ["is_dir"; "/new/foo"]];
754 InitBasicFS, TestOutputTrue
755 [["mkdir_p"; "/new/foo/bar"];
756 ["is_dir"; "/new"]]],
757 "create a directory and parents",
759 Create a directory named C<path>, creating any parent directories
760 as necessary. This is like the C<mkdir -p> shell command.");
762 ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
763 [], (* XXX Need stat command to test *)
766 Change the mode (permissions) of C<path> to C<mode>. Only
767 numeric modes are supported.");
769 ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
770 [], (* XXX Need stat command to test *)
771 "change file owner and group",
773 Change the file owner to C<owner> and group to C<group>.
775 Only numeric uid and gid are supported. If you want to use
776 names, you will need to locate and parse the password file
777 yourself (Augeas support makes this relatively easy).");
779 ("exists", (RBool "existsflag", [String "path"]), 36, [],
780 [InitBasicFS, TestOutputTrue (
782 ["exists"; "/new"]]);
783 InitBasicFS, TestOutputTrue (
785 ["exists"; "/new"]])],
786 "test if file or directory exists",
788 This returns C<true> if and only if there is a file, directory
789 (or anything) with the given C<path> name.
791 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
793 ("is_file", (RBool "fileflag", [String "path"]), 37, [],
794 [InitBasicFS, TestOutputTrue (
796 ["is_file"; "/new"]]);
797 InitBasicFS, TestOutputFalse (
799 ["is_file"; "/new"]])],
800 "test if file exists",
802 This returns C<true> if and only if there is a file
803 with the given C<path> name. Note that it returns false for
804 other objects like directories.
806 See also C<guestfs_stat>.");
808 ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
809 [InitBasicFS, TestOutputFalse (
811 ["is_dir"; "/new"]]);
812 InitBasicFS, TestOutputTrue (
814 ["is_dir"; "/new"]])],
815 "test if file exists",
817 This returns C<true> if and only if there is a directory
818 with the given C<path> name. Note that it returns false for
819 other objects like files.
821 See also C<guestfs_stat>.");
823 ("pvcreate", (RErr, [String "device"]), 39, [],
824 [InitEmpty, TestOutputList (
825 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
826 ["pvcreate"; "/dev/sda1"];
827 ["pvcreate"; "/dev/sda2"];
828 ["pvcreate"; "/dev/sda3"];
829 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
830 "create an LVM physical volume",
832 This creates an LVM physical volume on the named C<device>,
833 where C<device> should usually be a partition name such
836 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
837 [InitEmpty, TestOutputList (
838 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
839 ["pvcreate"; "/dev/sda1"];
840 ["pvcreate"; "/dev/sda2"];
841 ["pvcreate"; "/dev/sda3"];
842 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
843 ["vgcreate"; "VG2"; "/dev/sda3"];
844 ["vgs"]], ["VG1"; "VG2"])],
845 "create an LVM volume group",
847 This creates an LVM volume group called C<volgroup>
848 from the non-empty list of physical volumes C<physvols>.");
850 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
851 [InitEmpty, TestOutputList (
852 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
853 ["pvcreate"; "/dev/sda1"];
854 ["pvcreate"; "/dev/sda2"];
855 ["pvcreate"; "/dev/sda3"];
856 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
857 ["vgcreate"; "VG2"; "/dev/sda3"];
858 ["lvcreate"; "LV1"; "VG1"; "50"];
859 ["lvcreate"; "LV2"; "VG1"; "50"];
860 ["lvcreate"; "LV3"; "VG2"; "50"];
861 ["lvcreate"; "LV4"; "VG2"; "50"];
862 ["lvcreate"; "LV5"; "VG2"; "50"];
864 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
865 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
866 "create an LVM volume group",
868 This creates an LVM volume group called C<logvol>
869 on the volume group C<volgroup>, with C<size> megabytes.");
871 ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
872 [InitEmpty, TestOutput (
873 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
874 ["mkfs"; "ext2"; "/dev/sda1"];
875 ["mount"; "/dev/sda1"; "/"];
876 ["write_file"; "/new"; "new file contents"; "0"];
877 ["cat"; "/new"]], "new file contents")],
880 This creates a filesystem on C<device> (usually a partition
881 of LVM logical volume). The filesystem type is C<fstype>, for
884 ("sfdisk", (RErr, [String "device";
885 Int "cyls"; Int "heads"; Int "sectors";
886 StringList "lines"]), 43, [DangerWillRobinson],
888 "create partitions on a block device",
890 This is a direct interface to the L<sfdisk(8)> program for creating
891 partitions on block devices.
893 C<device> should be a block device, for example C</dev/sda>.
895 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
896 and sectors on the device, which are passed directly to sfdisk as
897 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
898 of these, then the corresponding parameter is omitted. Usually for
899 'large' disks, you can just pass C<0> for these, but for small
900 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
901 out the right geometry and you will need to tell it.
903 C<lines> is a list of lines that we feed to C<sfdisk>. For more
904 information refer to the L<sfdisk(8)> manpage.
906 To create a single partition occupying the whole disk, you would
907 pass C<lines> as a single element list, when the single element being
908 the string C<,> (comma).");
910 ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
911 [InitEmpty, TestOutput (
912 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
913 ["mkfs"; "ext2"; "/dev/sda1"];
914 ["mount"; "/dev/sda1"; "/"];
915 ["write_file"; "/new"; "new file contents"; "0"];
916 ["cat"; "/new"]], "new file contents")],
919 This call creates a file called C<path>. The contents of the
920 file is the string C<content> (which can contain any 8 bit data),
923 As a special case, if C<size> is C<0>
924 then the length is calculated using C<strlen> (so in this case
925 the content cannot contain embedded ASCII NULs).");
927 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
928 [InitEmpty, TestOutputList (
929 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
930 ["mkfs"; "ext2"; "/dev/sda1"];
931 ["mount"; "/dev/sda1"; "/"];
932 ["mounts"]], ["/dev/sda1"]);
933 InitEmpty, TestOutputList (
934 [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
935 ["mkfs"; "ext2"; "/dev/sda1"];
936 ["mount"; "/dev/sda1"; "/"];
939 "unmount a filesystem",
941 This unmounts the given filesystem. The filesystem may be
942 specified either by its mountpoint (path) or the device which
943 contains the filesystem.");
945 ("mounts", (RStringList "devices", []), 46, [],
946 [InitBasicFS, TestOutputList (
947 [["mounts"]], ["/dev/sda1"])],
948 "show mounted filesystems",
950 This returns the list of currently mounted filesystems. It returns
951 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
953 Some internal mounts are not shown.");
955 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
956 [InitBasicFS, TestOutputList (
959 "unmount all filesystems",
961 This unmounts all mounted filesystems.
963 Some internal mounts are not unmounted by this call.");
965 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
967 "remove all LVM LVs, VGs and PVs",
969 This command removes all LVM logical volumes, volume groups
970 and physical volumes.");
972 ("file", (RString "description", [String "path"]), 49, [],
973 [InitBasicFS, TestOutput (
975 ["file"; "/new"]], "empty");
976 InitBasicFS, TestOutput (
977 [["write_file"; "/new"; "some content\n"; "0"];
978 ["file"; "/new"]], "ASCII text");
979 InitBasicFS, TestLastFail (
980 [["file"; "/nofile"]])],
981 "determine file type",
983 This call uses the standard L<file(1)> command to determine
984 the type or contents of the file. This also works on devices,
985 for example to find out whether a partition contains a filesystem.
987 The exact command which runs is C<file -bsL path>. Note in
988 particular that the filename is not prepended to the output
989 (the C<-b> option).");
991 ("command", (RString "output", [StringList "arguments"]), 50, [],
992 [], (* XXX how to test? *)
993 "run a command from the guest filesystem",
995 This call runs a command from the guest filesystem. The
996 filesystem must be mounted, and must contain a compatible
997 operating system (ie. something Linux, with the same
998 or compatible processor architecture).
1000 The single parameter is an argv-style list of arguments.
1001 The first element is the name of the program to run.
1002 Subsequent elements are parameters. The list must be
1003 non-empty (ie. must contain a program name).
1005 The C<$PATH> environment variable will contain at least
1006 C</usr/bin> and C</bin>. If you require a program from
1007 another location, you should provide the full path in the
1010 Shared libraries and data files required by the program
1011 must be available on filesystems which are mounted in the
1012 correct places. It is the caller's responsibility to ensure
1013 all filesystems that are needed are mounted at the right
1016 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [],
1017 [], (* XXX how to test? *)
1018 "run a command, returning lines",
1020 This is the same as C<guestfs_command>, but splits the
1021 result into a list of lines.");
1023 ("stat", (RStat "statbuf", [String "path"]), 52, [],
1024 [InitBasicFS, TestOutputStruct (
1026 ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1027 "get file information",
1029 Returns file information for the given C<path>.
1031 This is the same as the C<stat(2)> system call.");
1033 ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1034 [InitBasicFS, TestOutputStruct (
1036 ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1037 "get file information for a symbolic link",
1039 Returns file information for the given C<path>.
1041 This is the same as C<guestfs_stat> except that if C<path>
1042 is a symbolic link, then the link is stat-ed, not the file it
1045 This is the same as the C<lstat(2)> system call.");
1047 ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1048 [InitBasicFS, TestOutputStruct (
1049 [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1050 CompareWithInt ("blocks", 490020);
1051 CompareWithInt ("bsize", 1024)])],
1052 "get file system statistics",
1054 Returns file system statistics for any mounted file system.
1055 C<path> should be a file or directory in the mounted file system
1056 (typically it is the mount point itself, but it doesn't need to be).
1058 This is the same as the C<statvfs(2)> system call.");
1060 ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1062 "get ext2/ext3 superblock details",
1064 This returns the contents of the ext2 or ext3 filesystem superblock
1067 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1068 manpage for more details. The list of fields returned isn't
1069 clearly defined, and depends on both the version of C<tune2fs>
1070 that libguestfs was built against, and the filesystem itself.");
1074 let all_functions = non_daemon_functions @ daemon_functions
1076 (* In some places we want the functions to be displayed sorted
1077 * alphabetically, so this is useful:
1079 let all_functions_sorted =
1080 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
1081 compare n1 n2) all_functions
1083 (* Column names and types from LVM PVs/VGs/LVs. *)
1092 "pv_attr", `String (* XXX *);
1093 "pv_pe_count", `Int;
1094 "pv_pe_alloc_count", `Int;
1097 "pv_mda_count", `Int;
1098 "pv_mda_free", `Bytes;
1099 (* Not in Fedora 10:
1100 "pv_mda_size", `Bytes;
1107 "vg_attr", `String (* XXX *);
1110 "vg_sysid", `String;
1111 "vg_extent_size", `Bytes;
1112 "vg_extent_count", `Int;
1113 "vg_free_count", `Int;
1121 "vg_mda_count", `Int;
1122 "vg_mda_free", `Bytes;
1123 (* Not in Fedora 10:
1124 "vg_mda_size", `Bytes;
1130 "lv_attr", `String (* XXX *);
1133 "lv_kernel_major", `Int;
1134 "lv_kernel_minor", `Int;
1138 "snap_percent", `OptPercent;
1139 "copy_percent", `OptPercent;
1142 "mirror_log", `String;
1146 (* Column names and types from stat structures.
1147 * NB. Can't use things like 'st_atime' because glibc header files
1148 * define some of these as macros. Ugh.
1165 let statvfs_cols = [
1179 (* Useful functions.
1180 * Note we don't want to use any external OCaml libraries which
1181 * makes this a bit harder than it should be.
1183 let failwithf fs = ksprintf failwith fs
1185 let replace_char s c1 c2 =
1186 let s2 = String.copy s in
1187 let r = ref false in
1188 for i = 0 to String.length s2 - 1 do
1189 if String.unsafe_get s2 i = c1 then (
1190 String.unsafe_set s2 i c2;
1194 if not !r then s else s2
1196 let rec find s sub =
1197 let len = String.length s in
1198 let sublen = String.length sub in
1200 if i <= len-sublen then (
1202 if j < sublen then (
1203 if s.[i+j] = sub.[j] then loop2 (j+1)
1209 if r = -1 then loop (i+1) else r
1215 let rec replace_str s s1 s2 =
1216 let len = String.length s in
1217 let sublen = String.length s1 in
1218 let i = find s s1 in
1221 let s' = String.sub s 0 i in
1222 let s'' = String.sub s (i+sublen) (len-i-sublen) in
1223 s' ^ s2 ^ replace_str s'' s1 s2
1226 let rec string_split sep str =
1227 let len = String.length str in
1228 let seplen = String.length sep in
1229 let i = find str sep in
1230 if i = -1 then [str]
1232 let s' = String.sub str 0 i in
1233 let s'' = String.sub str (i+seplen) (len-i-seplen) in
1234 s' :: string_split sep s''
1237 let rec find_map f = function
1238 | [] -> raise Not_found
1242 | None -> find_map f xs
1245 let rec loop i = function
1247 | x :: xs -> f i x; loop (i+1) xs
1252 let rec loop i = function
1254 | x :: xs -> let r = f i x in r :: loop (i+1) xs
1258 let name_of_argt = function
1259 | String n | OptString n | StringList n | Bool n | Int n -> n
1261 (* Check function names etc. for consistency. *)
1262 let check_functions () =
1263 let contains_uppercase str =
1264 let len = String.length str in
1266 if i >= len then false
1269 if c >= 'A' && c <= 'Z' then true
1276 (* Check function names. *)
1278 fun (name, _, _, _, _, _, _) ->
1279 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
1280 failwithf "function name %s does not need 'guestfs' prefix" name;
1281 if contains_uppercase name then
1282 failwithf "function name %s should not contain uppercase chars" name;
1283 if String.contains name '-' then
1284 failwithf "function name %s should not contain '-', use '_' instead."
1288 (* Check function parameter/return names. *)
1290 fun (name, style, _, _, _, _, _) ->
1291 let check_arg_ret_name n =
1292 if contains_uppercase n then
1293 failwithf "%s param/ret %s should not contain uppercase chars"
1295 if String.contains n '-' || String.contains n '_' then
1296 failwithf "%s param/ret %s should not contain '-' or '_'"
1299 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;
1300 if n = "argv" || n = "args" then
1301 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
1304 (match fst style with
1306 | RInt n | RBool n | RConstString n | RString n
1307 | RStringList n | RPVList n | RVGList n | RLVList n
1308 | RStat n | RStatVFS n
1310 check_arg_ret_name n
1312 check_arg_ret_name n;
1313 check_arg_ret_name m
1315 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
1318 (* Check short descriptions. *)
1320 fun (name, _, _, _, _, shortdesc, _) ->
1321 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
1322 failwithf "short description of %s should begin with lowercase." name;
1323 let c = shortdesc.[String.length shortdesc-1] in
1324 if c = '\n' || c = '.' then
1325 failwithf "short description of %s should not end with . or \\n." name
1328 (* Check long dscriptions. *)
1330 fun (name, _, _, _, _, _, longdesc) ->
1331 if longdesc.[String.length longdesc-1] = '\n' then
1332 failwithf "long description of %s should not end with \\n." name
1335 (* Check proc_nrs. *)
1337 fun (name, _, proc_nr, _, _, _, _) ->
1338 if proc_nr <= 0 then
1339 failwithf "daemon function %s should have proc_nr > 0" name
1343 fun (name, _, proc_nr, _, _, _, _) ->
1344 if proc_nr <> -1 then
1345 failwithf "non-daemon function %s should have proc_nr -1" name
1346 ) non_daemon_functions;
1349 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
1352 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
1353 let rec loop = function
1356 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
1358 | (name1,nr1) :: (name2,nr2) :: _ ->
1359 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
1364 (* 'pr' prints to the current output file. *)
1365 let chan = ref stdout
1366 let pr fs = ksprintf (output_string !chan) fs
1368 (* Generate a header block in a number of standard styles. *)
1369 type comment_style = CStyle | HashStyle | OCamlStyle
1370 type license = GPLv2 | LGPLv2
1372 let generate_header comment license =
1373 let c = match comment with
1374 | CStyle -> pr "/* "; " *"
1375 | HashStyle -> pr "# "; "#"
1376 | OCamlStyle -> pr "(* "; " *" in
1377 pr "libguestfs generated file\n";
1378 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
1379 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
1381 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
1385 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
1386 pr "%s it under the terms of the GNU General Public License as published by\n" c;
1387 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
1388 pr "%s (at your option) any later version.\n" c;
1390 pr "%s This program is distributed in the hope that it will be useful,\n" c;
1391 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1392 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
1393 pr "%s GNU General Public License for more details.\n" c;
1395 pr "%s You should have received a copy of the GNU General Public License along\n" c;
1396 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
1397 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
1400 pr "%s This library is free software; you can redistribute it and/or\n" c;
1401 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
1402 pr "%s License as published by the Free Software Foundation; either\n" c;
1403 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
1405 pr "%s This library is distributed in the hope that it will be useful,\n" c;
1406 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1407 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
1408 pr "%s Lesser General Public License for more details.\n" c;
1410 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
1411 pr "%s License along with this library; if not, write to the Free Software\n" c;
1412 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
1415 | CStyle -> pr " */\n"
1417 | OCamlStyle -> pr " *)\n"
1421 (* Start of main code generation functions below this line. *)
1423 (* Generate the pod documentation for the C API. *)
1424 let rec generate_actions_pod () =
1426 fun (shortname, style, _, flags, _, _, longdesc) ->
1427 let name = "guestfs_" ^ shortname in
1428 pr "=head2 %s\n\n" name;
1430 generate_prototype ~extern:false ~handle:"handle" name style;
1432 pr "%s\n\n" longdesc;
1433 (match fst style with
1435 pr "This function returns 0 on success or -1 on error.\n\n"
1437 pr "On error this function returns -1.\n\n"
1439 pr "This function returns a C truth value on success or -1 on error.\n\n"
1441 pr "This function returns a string, or NULL on error.
1442 The string is owned by the guest handle and must I<not> be freed.\n\n"
1444 pr "This function returns a string, or NULL on error.
1445 I<The caller must free the returned string after use>.\n\n"
1447 pr "This function returns a NULL-terminated array of strings
1448 (like L<environ(3)>), or NULL if there was an error.
1449 I<The caller must free the strings and the array after use>.\n\n"
1451 pr "This function returns a C<struct guestfs_int_bool *>,
1452 or NULL if there was an error.
1453 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
1455 pr "This function returns a C<struct guestfs_lvm_pv_list *>
1456 (see E<lt>guestfs-structs.hE<gt>),
1457 or NULL if there was an error.
1458 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
1460 pr "This function returns a C<struct guestfs_lvm_vg_list *>
1461 (see E<lt>guestfs-structs.hE<gt>),
1462 or NULL if there was an error.
1463 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
1465 pr "This function returns a C<struct guestfs_lvm_lv_list *>
1466 (see E<lt>guestfs-structs.hE<gt>),
1467 or NULL if there was an error.
1468 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
1470 pr "This function returns a C<struct guestfs_stat *>
1471 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
1472 or NULL if there was an error.
1473 I<The caller must call C<free> after use>.\n\n"
1475 pr "This function returns a C<struct guestfs_statvfs *>
1476 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
1477 or NULL if there was an error.
1478 I<The caller must call C<free> after use>.\n\n"
1480 pr "This function returns a NULL-terminated array of
1481 strings, or NULL if there was an error.
1482 The array of strings will always have length C<2n+1>, where
1483 C<n> keys and values alternate, followed by the trailing NULL entry.
1484 I<The caller must free the strings and the array after use>.\n\n"
1486 if List.mem ProtocolLimitWarning flags then
1487 pr "%s\n\n" protocol_limit_warning;
1488 if List.mem DangerWillRobinson flags then
1489 pr "%s\n\n" danger_will_robinson;
1490 ) all_functions_sorted
1492 and generate_structs_pod () =
1493 (* LVM structs documentation. *)
1496 pr "=head2 guestfs_lvm_%s\n" typ;
1498 pr " struct guestfs_lvm_%s {\n" typ;
1501 | name, `String -> pr " char *%s;\n" name
1503 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
1504 pr " char %s[32];\n" name
1505 | name, `Bytes -> pr " uint64_t %s;\n" name
1506 | name, `Int -> pr " int64_t %s;\n" name
1507 | name, `OptPercent ->
1508 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
1509 pr " float %s;\n" name
1512 pr " struct guestfs_lvm_%s_list {\n" typ;
1513 pr " uint32_t len; /* Number of elements in list. */\n";
1514 pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
1517 pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
1520 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1522 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
1523 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
1525 * We have to use an underscore instead of a dash because otherwise
1526 * rpcgen generates incorrect code.
1528 * This header is NOT exported to clients, but see also generate_structs_h.
1530 and generate_xdr () =
1531 generate_header CStyle LGPLv2;
1533 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
1534 pr "typedef string str<>;\n";
1537 (* LVM internal structures. *)
1541 pr "struct guestfs_lvm_int_%s {\n" typ;
1543 | name, `String -> pr " string %s<>;\n" name
1544 | name, `UUID -> pr " opaque %s[32];\n" name
1545 | name, `Bytes -> pr " hyper %s;\n" name
1546 | name, `Int -> pr " hyper %s;\n" name
1547 | name, `OptPercent -> pr " float %s;\n" name
1551 pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
1553 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1555 (* Stat internal structures. *)
1559 pr "struct guestfs_int_%s {\n" typ;
1561 | name, `Int -> pr " hyper %s;\n" name
1565 ) ["stat", stat_cols; "statvfs", statvfs_cols];
1568 fun (shortname, style, _, _, _, _, _) ->
1569 let name = "guestfs_" ^ shortname in
1571 (match snd style with
1574 pr "struct %s_args {\n" name;
1577 | String n -> pr " string %s<>;\n" n
1578 | OptString n -> pr " str *%s;\n" n
1579 | StringList n -> pr " str %s<>;\n" n
1580 | Bool n -> pr " bool %s;\n" n
1581 | Int n -> pr " int %s;\n" n
1585 (match fst style with
1588 pr "struct %s_ret {\n" name;
1592 pr "struct %s_ret {\n" name;
1596 failwithf "RConstString cannot be returned from a daemon function"
1598 pr "struct %s_ret {\n" name;
1599 pr " string %s<>;\n" n;
1602 pr "struct %s_ret {\n" name;
1603 pr " str %s<>;\n" n;
1606 pr "struct %s_ret {\n" name;
1611 pr "struct %s_ret {\n" name;
1612 pr " guestfs_lvm_int_pv_list %s;\n" n;
1615 pr "struct %s_ret {\n" name;
1616 pr " guestfs_lvm_int_vg_list %s;\n" n;
1619 pr "struct %s_ret {\n" name;
1620 pr " guestfs_lvm_int_lv_list %s;\n" n;
1623 pr "struct %s_ret {\n" name;
1624 pr " guestfs_int_stat %s;\n" n;
1627 pr "struct %s_ret {\n" name;
1628 pr " guestfs_int_statvfs %s;\n" n;
1631 pr "struct %s_ret {\n" name;
1632 pr " str %s<>;\n" n;
1637 (* Table of procedure numbers. *)
1638 pr "enum guestfs_procedure {\n";
1640 fun (shortname, _, proc_nr, _, _, _, _) ->
1641 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
1643 pr " GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
1647 (* Having to choose a maximum message size is annoying for several
1648 * reasons (it limits what we can do in the API), but it (a) makes
1649 * the protocol a lot simpler, and (b) provides a bound on the size
1650 * of the daemon which operates in limited memory space. For large
1651 * file transfers you should use FTP.
1653 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
1656 (* Message header, etc. *)
1658 const GUESTFS_PROGRAM = 0x2000F5F5;
1659 const GUESTFS_PROTOCOL_VERSION = 1;
1661 enum guestfs_message_direction {
1662 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
1663 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
1666 enum guestfs_message_status {
1667 GUESTFS_STATUS_OK = 0,
1668 GUESTFS_STATUS_ERROR = 1
1671 const GUESTFS_ERROR_LEN = 256;
1673 struct guestfs_message_error {
1674 string error<GUESTFS_ERROR_LEN>; /* error message */
1677 struct guestfs_message_header {
1678 unsigned prog; /* GUESTFS_PROGRAM */
1679 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
1680 guestfs_procedure proc; /* GUESTFS_PROC_x */
1681 guestfs_message_direction direction;
1682 unsigned serial; /* message serial number */
1683 guestfs_message_status status;
1687 (* Generate the guestfs-structs.h file. *)
1688 and generate_structs_h () =
1689 generate_header CStyle LGPLv2;
1691 (* This is a public exported header file containing various
1692 * structures. The structures are carefully written to have
1693 * exactly the same in-memory format as the XDR structures that
1694 * we use on the wire to the daemon. The reason for creating
1695 * copies of these structures here is just so we don't have to
1696 * export the whole of guestfs_protocol.h (which includes much
1697 * unrelated and XDR-dependent stuff that we don't want to be
1698 * public, or required by clients).
1700 * To reiterate, we will pass these structures to and from the
1701 * client with a simple assignment or memcpy, so the format
1702 * must be identical to what rpcgen / the RFC defines.
1705 (* guestfs_int_bool structure. *)
1706 pr "struct guestfs_int_bool {\n";
1712 (* LVM public structures. *)
1716 pr "struct guestfs_lvm_%s {\n" typ;
1719 | name, `String -> pr " char *%s;\n" name
1720 | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
1721 | name, `Bytes -> pr " uint64_t %s;\n" name
1722 | name, `Int -> pr " int64_t %s;\n" name
1723 | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
1727 pr "struct guestfs_lvm_%s_list {\n" typ;
1728 pr " uint32_t len;\n";
1729 pr " struct guestfs_lvm_%s *val;\n" typ;
1732 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1734 (* Stat structures. *)
1738 pr "struct guestfs_%s {\n" typ;
1741 | name, `Int -> pr " int64_t %s;\n" name
1745 ) ["stat", stat_cols; "statvfs", statvfs_cols]
1747 (* Generate the guestfs-actions.h file. *)
1748 and generate_actions_h () =
1749 generate_header CStyle LGPLv2;
1751 fun (shortname, style, _, _, _, _, _) ->
1752 let name = "guestfs_" ^ shortname in
1753 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
1757 (* Generate the client-side dispatch stubs. *)
1758 and generate_client_actions () =
1759 generate_header CStyle LGPLv2;
1761 (* Client-side stubs for each function. *)
1763 fun (shortname, style, _, _, _, _, _) ->
1764 let name = "guestfs_" ^ shortname in
1766 (* Generate the return value struct. *)
1767 pr "struct %s_rv {\n" shortname;
1768 pr " int cb_done; /* flag to indicate callback was called */\n";
1769 pr " struct guestfs_message_header hdr;\n";
1770 pr " struct guestfs_message_error err;\n";
1771 (match fst style with
1774 failwithf "RConstString cannot be returned from a daemon function"
1776 | RBool _ | RString _ | RStringList _
1778 | RPVList _ | RVGList _ | RLVList _
1779 | RStat _ | RStatVFS _
1781 pr " struct %s_ret ret;\n" name
1785 (* Generate the callback function. *)
1786 pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
1788 pr " struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
1790 pr " if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
1791 pr " error (g, \"%s: failed to parse reply header\");\n" name;
1794 pr " if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
1795 pr " if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
1796 pr " error (g, \"%s: failed to parse reply error\");\n" name;
1802 (match fst style with
1805 failwithf "RConstString cannot be returned from a daemon function"
1807 | RBool _ | RString _ | RStringList _
1809 | RPVList _ | RVGList _ | RLVList _
1810 | RStat _ | RStatVFS _
1812 pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
1813 pr " error (g, \"%s: failed to parse reply\");\n" name;
1819 pr " rv->cb_done = 1;\n";
1820 pr " main_loop.main_loop_quit (g);\n";
1823 (* Generate the action stub. *)
1824 generate_prototype ~extern:false ~semicolon:false ~newline:true
1825 ~handle:"g" name style;
1828 match fst style with
1829 | RErr | RInt _ | RBool _ -> "-1"
1831 failwithf "RConstString cannot be returned from a daemon function"
1832 | RString _ | RStringList _ | RIntBool _
1833 | RPVList _ | RVGList _ | RLVList _
1834 | RStat _ | RStatVFS _
1840 (match snd style with
1842 | _ -> pr " struct %s_args args;\n" name
1845 pr " struct %s_rv rv;\n" shortname;
1846 pr " int serial;\n";
1848 pr " if (g->state != READY) {\n";
1849 pr " error (g, \"%s called from the wrong state, %%d != READY\",\n"
1852 pr " return %s;\n" error_code;
1855 pr " memset (&rv, 0, sizeof rv);\n";
1858 (match snd style with
1860 pr " serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
1861 (String.uppercase shortname)
1866 pr " args.%s = (char *) %s;\n" n n
1868 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
1870 pr " args.%s.%s_val = (char **) %s;\n" n n n;
1871 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
1873 pr " args.%s = %s;\n" n n
1875 pr " args.%s = %s;\n" n n
1877 pr " serial = dispatch (g, GUESTFS_PROC_%s,\n"
1878 (String.uppercase shortname);
1879 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
1882 pr " if (serial == -1)\n";
1883 pr " return %s;\n" error_code;
1886 pr " rv.cb_done = 0;\n";
1887 pr " g->reply_cb_internal = %s_cb;\n" shortname;
1888 pr " g->reply_cb_internal_data = &rv;\n";
1889 pr " main_loop.main_loop_run (g);\n";
1890 pr " g->reply_cb_internal = NULL;\n";
1891 pr " g->reply_cb_internal_data = NULL;\n";
1892 pr " if (!rv.cb_done) {\n";
1893 pr " error (g, \"%s failed, see earlier error messages\");\n" name;
1894 pr " return %s;\n" error_code;
1898 pr " if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
1899 (String.uppercase shortname);
1900 pr " return %s;\n" error_code;
1903 pr " if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
1904 pr " error (g, \"%%s\", rv.err.error);\n";
1905 pr " return %s;\n" error_code;
1909 (match fst style with
1910 | RErr -> pr " return 0;\n"
1912 | RBool n -> pr " return rv.ret.%s;\n" n
1914 failwithf "RConstString cannot be returned from a daemon function"
1916 pr " return rv.ret.%s; /* caller will free */\n" n
1917 | RStringList n | RHashtable n ->
1918 pr " /* caller will free this, but we need to add a NULL entry */\n";
1919 pr " rv.ret.%s.%s_val =" n n;
1920 pr " safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
1921 pr " sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
1923 pr " rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
1924 pr " return rv.ret.%s.%s_val;\n" n n
1926 pr " /* caller with free this */\n";
1927 pr " return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
1928 | RPVList n | RVGList n | RLVList n
1929 | RStat n | RStatVFS n ->
1930 pr " /* caller will free this */\n";
1931 pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1937 (* Generate daemon/actions.h. *)
1938 and generate_daemon_actions_h () =
1939 generate_header CStyle GPLv2;
1941 pr "#include \"../src/guestfs_protocol.h\"\n";
1945 fun (name, style, _, _, _, _, _) ->
1947 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
1951 (* Generate the server-side stubs. *)
1952 and generate_daemon_actions () =
1953 generate_header CStyle GPLv2;
1955 pr "#define _GNU_SOURCE // for strchrnul\n";
1957 pr "#include <stdio.h>\n";
1958 pr "#include <stdlib.h>\n";
1959 pr "#include <string.h>\n";
1960 pr "#include <inttypes.h>\n";
1961 pr "#include <ctype.h>\n";
1962 pr "#include <rpc/types.h>\n";
1963 pr "#include <rpc/xdr.h>\n";
1965 pr "#include \"daemon.h\"\n";
1966 pr "#include \"../src/guestfs_protocol.h\"\n";
1967 pr "#include \"actions.h\"\n";
1971 fun (name, style, _, _, _, _, _) ->
1972 (* Generate server-side stubs. *)
1973 pr "static void %s_stub (XDR *xdr_in)\n" name;
1976 match fst style with
1977 | RErr | RInt _ -> pr " int r;\n"; "-1"
1978 | RBool _ -> pr " int r;\n"; "-1"
1980 failwithf "RConstString cannot be returned from a daemon function"
1981 | RString _ -> pr " char *r;\n"; "NULL"
1982 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
1983 | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
1984 | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
1985 | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
1986 | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
1987 | RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
1988 | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
1990 (match snd style with
1993 pr " struct guestfs_%s_args args;\n" name;
1997 | OptString n -> pr " const char *%s;\n" n
1998 | StringList n -> pr " char **%s;\n" n
1999 | Bool n -> pr " int %s;\n" n
2000 | Int n -> pr " int %s;\n" n
2005 (match snd style with
2008 pr " memset (&args, 0, sizeof args);\n";
2010 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
2011 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
2016 | String n -> pr " %s = args.%s;\n" n n
2017 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
2019 pr " args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
2020 pr " args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
2021 pr " %s = args.%s.%s_val;\n" n n n
2022 | Bool n -> pr " %s = args.%s;\n" n n
2023 | Int n -> pr " %s = args.%s;\n" n n
2028 pr " r = do_%s " name;
2029 generate_call_args style;
2032 pr " if (r == %s)\n" error_code;
2033 pr " /* do_%s has already called reply_with_error */\n" name;
2037 (match fst style with
2038 | RErr -> pr " reply (NULL, NULL);\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
2044 pr " struct guestfs_%s_ret ret;\n" name;
2045 pr " ret.%s = r;\n" n;
2046 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
2048 failwithf "RConstString cannot be returned from a daemon function"
2050 pr " struct guestfs_%s_ret ret;\n" name;
2051 pr " ret.%s = r;\n" n;
2052 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2054 | RStringList n | RHashtable n ->
2055 pr " struct guestfs_%s_ret ret;\n" name;
2056 pr " ret.%s.%s_len = count_strings (r);\n" n n;
2057 pr " ret.%s.%s_val = r;\n" n n;
2058 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2059 pr " free_strings (r);\n"
2061 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
2062 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2063 | RPVList n | RVGList n | RLVList n
2064 | RStat n | RStatVFS n ->
2065 pr " struct guestfs_%s_ret ret;\n" name;
2066 pr " ret.%s = *r;\n" n;
2067 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2068 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
2071 (* Free the args. *)
2072 (match snd style with
2077 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2084 (* Dispatch function. *)
2085 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2087 pr " switch (proc_nr) {\n";
2090 fun (name, style, _, _, _, _, _) ->
2091 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
2092 pr " %s_stub (xdr_in);\n" name;
2097 pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2102 (* LVM columns and tokenization functions. *)
2103 (* XXX This generates crap code. We should rethink how we
2109 pr "static const char *lvm_%s_cols = \"%s\";\n"
2110 typ (String.concat "," (List.map fst cols));
2113 pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2115 pr " char *tok, *p, *next;\n";
2119 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2122 pr " if (!str) {\n";
2123 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2126 pr " if (!*str || isspace (*str)) {\n";
2127 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2132 fun (name, coltype) ->
2133 pr " if (!tok) {\n";
2134 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2137 pr " p = strchrnul (tok, ',');\n";
2138 pr " if (*p) next = p+1; else next = NULL;\n";
2139 pr " *p = '\\0';\n";
2142 pr " r->%s = strdup (tok);\n" name;
2143 pr " if (r->%s == NULL) {\n" name;
2144 pr " perror (\"strdup\");\n";
2148 pr " for (i = j = 0; i < 32; ++j) {\n";
2149 pr " if (tok[j] == '\\0') {\n";
2150 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2152 pr " } else if (tok[j] != '-')\n";
2153 pr " r->%s[i++] = tok[j];\n" name;
2156 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2157 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2161 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2162 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2166 pr " if (tok[0] == '\\0')\n";
2167 pr " r->%s = -1;\n" name;
2168 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2169 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2173 pr " tok = next;\n";
2176 pr " if (tok != NULL) {\n";
2177 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2184 pr "guestfs_lvm_int_%s_list *\n" typ;
2185 pr "parse_command_line_%ss (void)\n" typ;
2187 pr " char *out, *err;\n";
2188 pr " char *p, *pend;\n";
2190 pr " guestfs_lvm_int_%s_list *ret;\n" typ;
2191 pr " void *newp;\n";
2193 pr " ret = malloc (sizeof *ret);\n";
2194 pr " if (!ret) {\n";
2195 pr " reply_with_perror (\"malloc\");\n";
2196 pr " return NULL;\n";
2199 pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2200 pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2202 pr " r = command (&out, &err,\n";
2203 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
2204 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2205 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2206 pr " if (r == -1) {\n";
2207 pr " reply_with_error (\"%%s\", err);\n";
2208 pr " free (out);\n";
2209 pr " free (err);\n";
2210 pr " return NULL;\n";
2213 pr " free (err);\n";
2215 pr " /* Tokenize each line of the output. */\n";
2218 pr " while (p) {\n";
2219 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
2220 pr " if (pend) {\n";
2221 pr " *pend = '\\0';\n";
2225 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
2228 pr " if (!*p) { /* Empty line? Skip it. */\n";
2233 pr " /* Allocate some space to store this next entry. */\n";
2234 pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2235 pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2236 pr " if (newp == NULL) {\n";
2237 pr " reply_with_perror (\"realloc\");\n";
2238 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2239 pr " free (ret);\n";
2240 pr " free (out);\n";
2241 pr " return NULL;\n";
2243 pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2245 pr " /* Tokenize the next entry. */\n";
2246 pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2247 pr " if (r == -1) {\n";
2248 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2249 pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2250 pr " free (ret);\n";
2251 pr " free (out);\n";
2252 pr " return NULL;\n";
2259 pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2261 pr " free (out);\n";
2262 pr " return ret;\n";
2265 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2267 (* Generate the tests. *)
2268 and generate_tests () =
2269 generate_header CStyle GPLv2;
2276 #include <sys/types.h>
2279 #include \"guestfs.h\"
2281 static guestfs_h *g;
2282 static int suppress_error = 0;
2284 static void print_error (guestfs_h *g, void *data, const char *msg)
2286 if (!suppress_error)
2287 fprintf (stderr, \"%%s\\n\", msg);
2290 static void print_strings (char * const * const argv)
2294 for (argc = 0; argv[argc] != NULL; ++argc)
2295 printf (\"\\t%%s\\n\", argv[argc]);
2298 static void print_table (char * const * const argv)
2302 for (i = 0; argv[i] != NULL; i += 2)
2303 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
2310 fun (name, _, _, _, tests, _, _) ->
2311 mapi (generate_one_test name) tests
2313 let test_names = List.concat test_names in
2314 let nr_tests = List.length test_names in
2317 int main (int argc, char *argv[])
2326 g = guestfs_create ();
2328 printf (\"guestfs_create FAILED\\n\");
2332 guestfs_set_error_handler (g, print_error, NULL);
2334 srcdir = getenv (\"srcdir\");
2335 if (!srcdir) srcdir = \".\";
2336 guestfs_set_path (g, srcdir);
2338 snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
2339 fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2344 if (lseek (fd, %d, SEEK_SET) == -1) {
2350 if (write (fd, &c, 1) == -1) {
2356 if (close (fd) == -1) {
2361 if (guestfs_add_drive (g, buf) == -1) {
2362 printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2366 snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
2367 fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2372 if (lseek (fd, %d, SEEK_SET) == -1) {
2378 if (write (fd, &c, 1) == -1) {
2384 if (close (fd) == -1) {
2389 if (guestfs_add_drive (g, buf) == -1) {
2390 printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2394 snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
2395 fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2400 if (lseek (fd, %d, SEEK_SET) == -1) {
2406 if (write (fd, &c, 1) == -1) {
2412 if (close (fd) == -1) {
2417 if (guestfs_add_drive (g, buf) == -1) {
2418 printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2422 if (guestfs_launch (g) == -1) {
2423 printf (\"guestfs_launch FAILED\\n\");
2426 if (guestfs_wait_ready (g) == -1) {
2427 printf (\"guestfs_wait_ready FAILED\\n\");
2432 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
2436 pr " printf (\"%3d/%%3d %s\\n\", nr_tests);\n" (i+1) test_name;
2437 pr " if (%s () == -1) {\n" test_name;
2438 pr " printf (\"%s FAILED\\n\");\n" test_name;
2444 pr " guestfs_close (g);\n";
2445 pr " snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
2446 pr " unlink (buf);\n";
2447 pr " snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
2448 pr " unlink (buf);\n";
2449 pr " snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
2450 pr " unlink (buf);\n";
2453 pr " if (failed > 0) {\n";
2454 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
2462 and generate_one_test name i (init, test) =
2463 let test_name = sprintf "test_%s_%d" name i in
2465 pr "static int %s (void)\n" test_name;
2471 pr " /* InitEmpty for %s (%d) */\n" name i;
2472 List.iter (generate_test_command_call test_name)
2476 pr " /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
2477 List.iter (generate_test_command_call test_name)
2480 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2481 ["mkfs"; "ext2"; "/dev/sda1"];
2482 ["mount"; "/dev/sda1"; "/"]]
2483 | InitBasicFSonLVM ->
2484 pr " /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
2486 List.iter (generate_test_command_call test_name)
2489 ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2490 ["pvcreate"; "/dev/sda1"];
2491 ["vgcreate"; "VG"; "/dev/sda1"];
2492 ["lvcreate"; "LV"; "VG"; "8"];
2493 ["mkfs"; "ext2"; "/dev/VG/LV"];
2494 ["mount"; "/dev/VG/LV"; "/"]]
2497 let get_seq_last = function
2499 failwithf "%s: you cannot use [] (empty list) when expecting a command"
2502 let seq = List.rev seq in
2503 List.rev (List.tl seq), List.hd seq
2508 pr " /* TestRun for %s (%d) */\n" name i;
2509 List.iter (generate_test_command_call test_name) seq
2510 | TestOutput (seq, expected) ->
2511 pr " /* TestOutput for %s (%d) */\n" name i;
2512 let seq, last = get_seq_last seq in
2514 pr " if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
2515 pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
2519 List.iter (generate_test_command_call test_name) seq;
2520 generate_test_command_call ~test test_name last
2521 | TestOutputList (seq, expected) ->
2522 pr " /* TestOutputList for %s (%d) */\n" name i;
2523 let seq, last = get_seq_last seq in
2527 pr " if (!r[%d]) {\n" i;
2528 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
2529 pr " print_strings (r);\n";
2532 pr " if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
2533 pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
2537 pr " if (r[%d] != NULL) {\n" (List.length expected);
2538 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
2540 pr " print_strings (r);\n";
2544 List.iter (generate_test_command_call test_name) seq;
2545 generate_test_command_call ~test test_name last
2546 | TestOutputInt (seq, expected) ->
2547 pr " /* TestOutputInt for %s (%d) */\n" name i;
2548 let seq, last = get_seq_last seq in
2550 pr " if (r != %d) {\n" expected;
2551 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\", r);\n"
2556 List.iter (generate_test_command_call test_name) seq;
2557 generate_test_command_call ~test test_name last
2558 | TestOutputTrue seq ->
2559 pr " /* TestOutputTrue for %s (%d) */\n" name i;
2560 let seq, last = get_seq_last seq in
2563 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
2568 List.iter (generate_test_command_call test_name) seq;
2569 generate_test_command_call ~test test_name last
2570 | TestOutputFalse seq ->
2571 pr " /* TestOutputFalse for %s (%d) */\n" name i;
2572 let seq, last = get_seq_last seq in
2575 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
2580 List.iter (generate_test_command_call test_name) seq;
2581 generate_test_command_call ~test test_name last
2582 | TestOutputLength (seq, expected) ->
2583 pr " /* TestOutputLength for %s (%d) */\n" name i;
2584 let seq, last = get_seq_last seq in
2587 pr " for (j = 0; j < %d; ++j)\n" expected;
2588 pr " if (r[j] == NULL) {\n";
2589 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
2591 pr " print_strings (r);\n";
2594 pr " if (r[j] != NULL) {\n";
2595 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
2597 pr " print_strings (r);\n";
2601 List.iter (generate_test_command_call test_name) seq;
2602 generate_test_command_call ~test test_name last
2603 | TestOutputStruct (seq, checks) ->
2604 pr " /* TestOutputStruct for %s (%d) */\n" name i;
2605 let seq, last = get_seq_last seq in
2609 | CompareWithInt (field, expected) ->
2610 pr " if (r->%s != %d) {\n" field expected;
2611 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
2612 test_name field expected;
2613 pr " (int) r->%s);\n" field;
2616 | CompareWithString (field, expected) ->
2617 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
2618 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
2619 test_name field expected;
2620 pr " r->%s);\n" field;
2623 | CompareFieldsIntEq (field1, field2) ->
2624 pr " if (r->%s != r->%s) {\n" field1 field2;
2625 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
2626 test_name field1 field2;
2627 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
2630 | CompareFieldsStrEq (field1, field2) ->
2631 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
2632 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
2633 test_name field1 field2;
2634 pr " r->%s, r->%s);\n" field1 field2;
2639 List.iter (generate_test_command_call test_name) seq;
2640 generate_test_command_call ~test test_name last
2641 | TestLastFail seq ->
2642 pr " /* TestLastFail for %s (%d) */\n" name i;
2643 let seq, last = get_seq_last seq in
2644 List.iter (generate_test_command_call test_name) seq;
2645 generate_test_command_call test_name ~expect_error:true last
2653 (* Generate the code to run a command, leaving the result in 'r'.
2654 * If you expect to get an error then you should set expect_error:true.
2656 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
2658 | [] -> assert false
2660 (* Look up the command to find out what args/ret it has. *)
2663 let _, style, _, _, _, _, _ =
2664 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
2667 failwithf "%s: in test, command %s was not found" test_name name in
2669 if List.length (snd style) <> List.length args then
2670 failwithf "%s: in test, wrong number of args given to %s"
2681 | StringList n, arg ->
2682 pr " char *%s[] = {\n" n;
2683 let strs = string_split " " arg in
2685 fun str -> pr " \"%s\",\n" (c_quote str)
2689 ) (List.combine (snd style) args);
2692 match fst style with
2693 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
2694 | RConstString _ -> pr " const char *r;\n"; "NULL"
2695 | RString _ -> pr " char *r;\n"; "NULL"
2696 | RStringList _ | RHashtable _ ->
2701 pr " struct guestfs_int_bool *r;\n"; "NULL"
2703 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
2705 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
2707 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
2709 pr " struct guestfs_stat *r;\n"; "NULL"
2711 pr " struct guestfs_statvfs *r;\n"; "NULL" in
2713 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
2714 pr " r = guestfs_%s (g" name;
2716 (* Generate the parameters. *)
2719 | String _, arg -> pr ", \"%s\"" (c_quote arg)
2720 | OptString _, arg ->
2721 if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
2722 | StringList n, _ ->
2726 try int_of_string arg
2727 with Failure "int_of_string" ->
2728 failwithf "%s: expecting an int, but got '%s'" test_name arg in
2731 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
2732 ) (List.combine (snd style) args);
2735 if not expect_error then
2736 pr " if (r == %s)\n" error_code
2738 pr " if (r != %s)\n" error_code;
2741 (* Insert the test code. *)
2747 (match fst style with
2748 | RErr | RInt _ | RBool _ | RConstString _ -> ()
2749 | RString _ -> pr " free (r);\n"
2750 | RStringList _ | RHashtable _ ->
2751 pr " for (i = 0; r[i] != NULL; ++i)\n";
2752 pr " free (r[i]);\n";
2755 pr " guestfs_free_int_bool (r);\n"
2757 pr " guestfs_free_lvm_pv_list (r);\n"
2759 pr " guestfs_free_lvm_vg_list (r);\n"
2761 pr " guestfs_free_lvm_lv_list (r);\n"
2762 | RStat _ | RStatVFS _ ->
2769 let str = replace_str str "\r" "\\r" in
2770 let str = replace_str str "\n" "\\n" in
2771 let str = replace_str str "\t" "\\t" in
2774 (* Generate a lot of different functions for guestfish. *)
2775 and generate_fish_cmds () =
2776 generate_header CStyle GPLv2;
2780 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
2782 let all_functions_sorted =
2784 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
2785 ) all_functions_sorted in
2787 pr "#include <stdio.h>\n";
2788 pr "#include <stdlib.h>\n";
2789 pr "#include <string.h>\n";
2790 pr "#include <inttypes.h>\n";
2792 pr "#include <guestfs.h>\n";
2793 pr "#include \"fish.h\"\n";
2796 (* list_commands function, which implements guestfish -h *)
2797 pr "void list_commands (void)\n";
2799 pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
2800 pr " list_builtin_commands ();\n";
2802 fun (name, _, _, flags, _, shortdesc, _) ->
2803 let name = replace_char name '_' '-' in
2804 pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
2806 ) all_functions_sorted;
2807 pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
2811 (* display_command function, which implements guestfish -h cmd *)
2812 pr "void display_command (const char *cmd)\n";
2815 fun (name, style, _, flags, _, shortdesc, longdesc) ->
2816 let name2 = replace_char name '_' '-' in
2818 try find_map (function FishAlias n -> Some n | _ -> None) flags
2819 with Not_found -> name in
2820 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
2822 match snd style with
2826 name2 (String.concat "> <" (List.map name_of_argt args)) in
2829 if List.mem ProtocolLimitWarning flags then
2830 ("\n\n" ^ protocol_limit_warning)
2833 (* For DangerWillRobinson commands, we should probably have
2834 * guestfish prompt before allowing you to use them (especially
2835 * in interactive mode). XXX
2839 if List.mem DangerWillRobinson flags then
2840 ("\n\n" ^ danger_will_robinson)
2843 let describe_alias =
2844 if name <> alias then
2845 sprintf "\n\nYou can use '%s' as an alias for this command." alias
2849 pr "strcasecmp (cmd, \"%s\") == 0" name;
2850 if name <> name2 then
2851 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
2852 if name <> alias then
2853 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
2855 pr " pod2text (\"%s - %s\", %S);\n"
2857 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
2860 pr " display_builtin_command (cmd);\n";
2864 (* print_{pv,vg,lv}_list functions *)
2868 pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
2875 pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
2877 pr " printf (\"%s: \");\n" name;
2878 pr " for (i = 0; i < 32; ++i)\n";
2879 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
2880 pr " printf (\"\\n\");\n"
2882 pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
2884 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
2885 | name, `OptPercent ->
2886 pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
2887 typ name name typ name;
2888 pr " else printf (\"%s: \\n\");\n" name
2892 pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
2897 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
2898 pr " print_%s (&%ss->val[i]);\n" typ typ;
2901 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2903 (* print_{stat,statvfs} functions *)
2907 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
2912 pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
2916 ) ["stat", stat_cols; "statvfs", statvfs_cols];
2918 (* run_<action> actions *)
2920 fun (name, style, _, flags, _, _, _) ->
2921 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
2923 (match fst style with
2926 | RBool _ -> pr " int r;\n"
2927 | RConstString _ -> pr " const char *r;\n"
2928 | RString _ -> pr " char *r;\n"
2929 | RStringList _ | RHashtable _ -> pr " char **r;\n"
2930 | RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
2931 | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
2932 | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
2933 | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
2934 | RStat _ -> pr " struct guestfs_stat *r;\n"
2935 | RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
2940 | OptString n -> pr " const char *%s;\n" n
2941 | StringList n -> pr " char **%s;\n" n
2942 | Bool n -> pr " int %s;\n" n
2943 | Int n -> pr " int %s;\n" n
2946 (* Check and convert parameters. *)
2947 let argc_expected = List.length (snd style) in
2948 pr " if (argc != %d) {\n" argc_expected;
2949 pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
2951 pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
2957 | String name -> pr " %s = argv[%d];\n" name i
2959 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
2961 | StringList name ->
2962 pr " %s = parse_string_list (argv[%d]);\n" name i
2964 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
2966 pr " %s = atoi (argv[%d]);\n" name i
2969 (* Call C API function. *)
2971 try find_map (function FishAction n -> Some n | _ -> None) flags
2972 with Not_found -> sprintf "guestfs_%s" name in
2974 generate_call_args ~handle:"g" style;
2977 (* Check return value for errors and display command results. *)
2978 (match fst style with
2979 | RErr -> pr " return r;\n"
2981 pr " if (r == -1) return -1;\n";
2982 pr " if (r) printf (\"%%d\\n\", r);\n";
2985 pr " if (r == -1) return -1;\n";
2986 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
2989 pr " if (r == NULL) return -1;\n";
2990 pr " printf (\"%%s\\n\", r);\n";
2993 pr " if (r == NULL) return -1;\n";
2994 pr " printf (\"%%s\\n\", r);\n";
2998 pr " if (r == NULL) return -1;\n";
2999 pr " print_strings (r);\n";
3000 pr " free_strings (r);\n";
3003 pr " if (r == NULL) return -1;\n";
3004 pr " printf (\"%%d, %%s\\n\", r->i,\n";
3005 pr " r->b ? \"true\" : \"false\");\n";
3006 pr " guestfs_free_int_bool (r);\n";
3009 pr " if (r == NULL) return -1;\n";
3010 pr " print_pv_list (r);\n";
3011 pr " guestfs_free_lvm_pv_list (r);\n";
3014 pr " if (r == NULL) return -1;\n";
3015 pr " print_vg_list (r);\n";
3016 pr " guestfs_free_lvm_vg_list (r);\n";
3019 pr " if (r == NULL) return -1;\n";
3020 pr " print_lv_list (r);\n";
3021 pr " guestfs_free_lvm_lv_list (r);\n";
3024 pr " if (r == NULL) return -1;\n";
3025 pr " print_stat (r);\n";
3029 pr " if (r == NULL) return -1;\n";
3030 pr " print_statvfs (r);\n";
3034 pr " if (r == NULL) return -1;\n";
3035 pr " print_table (r);\n";
3036 pr " free_strings (r);\n";
3043 (* run_action function *)
3044 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3047 fun (name, _, _, flags, _, _, _) ->
3048 let name2 = replace_char name '_' '-' in
3050 try find_map (function FishAlias n -> Some n | _ -> None) flags
3051 with Not_found -> name in
3053 pr "strcasecmp (cmd, \"%s\") == 0" name;
3054 if name <> name2 then
3055 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3056 if name <> alias then
3057 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3059 pr " return run_%s (cmd, argc, argv);\n" name;
3063 pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3070 (* Readline completion for guestfish. *)
3071 and generate_fish_completion () =
3072 generate_header CStyle GPLv2;
3076 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3086 #ifdef HAVE_LIBREADLINE
3087 #include <readline/readline.h>
3092 #ifdef HAVE_LIBREADLINE
3094 static const char *commands[] = {
3097 (* Get the commands and sort them, including the aliases. *)
3100 fun (name, _, _, flags, _, _, _) ->
3101 let name2 = replace_char name '_' '-' in
3103 try find_map (function FishAlias n -> Some n | _ -> None) flags
3104 with Not_found -> name in
3106 if name <> alias then [name2; alias] else [name2]
3108 let commands = List.flatten commands in
3109 let commands = List.sort compare commands in
3111 List.iter (pr " \"%s\",\n") commands;
3117 generator (const char *text, int state)
3119 static int index, len;
3124 len = strlen (text);
3127 while ((name = commands[index]) != NULL) {
3129 if (strncasecmp (name, text, len) == 0)
3130 return strdup (name);
3136 #endif /* HAVE_LIBREADLINE */
3138 char **do_completion (const char *text, int start, int end)
3140 char **matches = NULL;
3142 #ifdef HAVE_LIBREADLINE
3144 matches = rl_completion_matches (text, generator);
3151 (* Generate the POD documentation for guestfish. *)
3152 and generate_fish_actions_pod () =
3153 let all_functions_sorted =
3155 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3156 ) all_functions_sorted in
3159 fun (name, style, _, flags, _, _, longdesc) ->
3160 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3161 let name = replace_char name '_' '-' in
3163 try find_map (function FishAlias n -> Some n | _ -> None) flags
3164 with Not_found -> name in
3166 pr "=head2 %s" name;
3167 if name <> alias then
3174 | String n -> pr " %s" n
3175 | OptString n -> pr " %s" n
3176 | StringList n -> pr " %s,..." n
3177 | Bool _ -> pr " true|false"
3178 | Int n -> pr " %s" n
3182 pr "%s\n\n" longdesc;
3184 if List.mem ProtocolLimitWarning flags then
3185 pr "%s\n\n" protocol_limit_warning;
3187 if List.mem DangerWillRobinson flags then
3188 pr "%s\n\n" danger_will_robinson
3189 ) all_functions_sorted
3191 (* Generate a C function prototype. *)
3192 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3193 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3195 ?handle name style =
3196 if extern then pr "extern ";
3197 if static then pr "static ";
3198 (match fst style with
3200 | RInt _ -> pr "int "
3201 | RBool _ -> pr "int "
3202 | RConstString _ -> pr "const char *"
3203 | RString _ -> pr "char *"
3204 | RStringList _ | RHashtable _ -> pr "char **"
3206 if not in_daemon then pr "struct guestfs_int_bool *"
3207 else pr "guestfs_%s_ret *" name
3209 if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3210 else pr "guestfs_lvm_int_pv_list *"
3212 if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3213 else pr "guestfs_lvm_int_vg_list *"
3215 if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3216 else pr "guestfs_lvm_int_lv_list *"
3218 if not in_daemon then pr "struct guestfs_stat *"
3219 else pr "guestfs_int_stat *"
3221 if not in_daemon then pr "struct guestfs_statvfs *"
3222 else pr "guestfs_int_statvfs *"
3224 pr "%s%s (" prefix name;
3225 if handle = None && List.length (snd style) = 0 then
3228 let comma = ref false in
3231 | Some handle -> pr "guestfs_h *%s" handle; comma := true
3235 if single_line then pr ", " else pr ",\n\t\t"
3241 | String n -> next (); pr "const char *%s" n
3242 | OptString n -> next (); pr "const char *%s" n
3243 | StringList n -> next (); pr "char * const* const %s" n
3244 | Bool n -> next (); pr "int %s" n
3245 | Int n -> next (); pr "int %s" n
3249 if semicolon then pr ";";
3250 if newline then pr "\n"
3252 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3253 and generate_call_args ?handle style =
3255 let comma = ref false in
3258 | Some handle -> pr "%s" handle; comma := true
3262 if !comma then pr ", ";
3269 | Int n -> pr "%s" n
3273 (* Generate the OCaml bindings interface. *)
3274 and generate_ocaml_mli () =
3275 generate_header OCamlStyle LGPLv2;
3278 (** For API documentation you should refer to the C API
3279 in the guestfs(3) manual page. The OCaml API uses almost
3280 exactly the same calls. *)
3283 (** A [guestfs_h] handle. *)
3285 exception Error of string
3286 (** This exception is raised when there is an error. *)
3288 val create : unit -> t
3290 val close : t -> unit
3291 (** Handles are closed by the garbage collector when they become
3292 unreferenced, but callers can also call this in order to
3293 provide predictable cleanup. *)
3296 generate_ocaml_lvm_structure_decls ();
3298 generate_ocaml_stat_structure_decls ();
3302 fun (name, style, _, _, _, shortdesc, _) ->
3303 generate_ocaml_prototype name style;
3304 pr "(** %s *)\n" shortdesc;
3308 (* Generate the OCaml bindings implementation. *)
3309 and generate_ocaml_ml () =
3310 generate_header OCamlStyle LGPLv2;
3314 exception Error of string
3315 external create : unit -> t = \"ocaml_guestfs_create\"
3316 external close : t -> unit = \"ocaml_guestfs_close\"
3319 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3323 generate_ocaml_lvm_structure_decls ();
3325 generate_ocaml_stat_structure_decls ();
3329 fun (name, style, _, _, _, shortdesc, _) ->
3330 generate_ocaml_prototype ~is_external:true name style;
3333 (* Generate the OCaml bindings C implementation. *)
3334 and generate_ocaml_c () =
3335 generate_header CStyle LGPLv2;
3342 #include <caml/config.h>
3343 #include <caml/alloc.h>
3344 #include <caml/callback.h>
3345 #include <caml/fail.h>
3346 #include <caml/memory.h>
3347 #include <caml/mlvalues.h>
3348 #include <caml/signals.h>
3350 #include <guestfs.h>
3352 #include \"guestfs_c.h\"
3354 /* Copy a hashtable of string pairs into an assoc-list. We return
3355 * the list in reverse order, but hashtables aren't supposed to be
3358 static CAMLprim value
3359 copy_table (char * const * argv)
3362 CAMLlocal5 (rv, pairv, kv, vv, cons);
3366 for (i = 0; argv[i] != NULL; i += 2) {
3367 kv = caml_copy_string (argv[i]);
3368 vv = caml_copy_string (argv[i+1]);
3369 pairv = caml_alloc (2, 0);
3370 Store_field (pairv, 0, kv);
3371 Store_field (pairv, 1, vv);
3372 cons = caml_alloc (2, 0);
3373 Store_field (cons, 1, rv);
3375 Store_field (cons, 0, pairv);
3383 (* LVM struct copy functions. *)
3386 let has_optpercent_col =
3387 List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
3389 pr "static CAMLprim value\n";
3390 pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
3392 pr " CAMLparam0 ();\n";
3393 if has_optpercent_col then
3394 pr " CAMLlocal3 (rv, v, v2);\n"
3396 pr " CAMLlocal2 (rv, v);\n";
3398 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
3403 pr " v = caml_copy_string (%s->%s);\n" typ name
3405 pr " v = caml_alloc_string (32);\n";
3406 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
3409 pr " v = caml_copy_int64 (%s->%s);\n" typ name
3410 | name, `OptPercent ->
3411 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
3412 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
3413 pr " v = caml_alloc (1, 0);\n";
3414 pr " Store_field (v, 0, v2);\n";
3415 pr " } else /* None */\n";
3416 pr " v = Val_int (0);\n";
3418 pr " Store_field (rv, %d, v);\n" i
3420 pr " CAMLreturn (rv);\n";
3424 pr "static CAMLprim value\n";
3425 pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
3428 pr " CAMLparam0 ();\n";
3429 pr " CAMLlocal2 (rv, v);\n";
3432 pr " if (%ss->len == 0)\n" typ;
3433 pr " CAMLreturn (Atom (0));\n";
3435 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
3436 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
3437 pr " v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
3438 pr " caml_modify (&Field (rv, i), v);\n";
3440 pr " CAMLreturn (rv);\n";
3444 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3446 (* Stat copy functions. *)
3449 pr "static CAMLprim value\n";
3450 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
3452 pr " CAMLparam0 ();\n";
3453 pr " CAMLlocal2 (rv, v);\n";
3455 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
3460 pr " v = caml_copy_int64 (%s->%s);\n" typ name
3462 pr " Store_field (rv, %d, v);\n" i
3464 pr " CAMLreturn (rv);\n";
3467 ) ["stat", stat_cols; "statvfs", statvfs_cols];
3471 fun (name, style, _, _, _, _, _) ->
3473 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
3475 pr "CAMLprim value\n";
3476 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
3477 List.iter (pr ", value %s") (List.tl params);
3482 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
3483 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
3484 pr " CAMLxparam%d (%s);\n"
3485 (List.length rest) (String.concat ", " rest)
3487 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
3489 pr " CAMLlocal1 (rv);\n";
3492 pr " guestfs_h *g = Guestfs_val (gv);\n";
3493 pr " if (g == NULL)\n";
3494 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
3500 pr " const char *%s = String_val (%sv);\n" n n
3502 pr " const char *%s =\n" n;
3503 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
3506 pr " char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
3508 pr " int %s = Bool_val (%sv);\n" n n
3510 pr " int %s = Int_val (%sv);\n" n n
3513 match fst style with
3514 | RErr -> pr " int r;\n"; "-1"
3515 | RInt _ -> pr " int r;\n"; "-1"
3516 | RBool _ -> pr " int r;\n"; "-1"
3517 | RConstString _ -> pr " const char *r;\n"; "NULL"
3518 | RString _ -> pr " char *r;\n"; "NULL"
3524 pr " struct guestfs_int_bool *r;\n"; "NULL"
3526 pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
3528 pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
3530 pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
3532 pr " struct guestfs_stat *r;\n"; "NULL"
3534 pr " struct guestfs_statvfs *r;\n"; "NULL"
3541 pr " caml_enter_blocking_section ();\n";
3542 pr " r = guestfs_%s " name;
3543 generate_call_args ~handle:"g" style;
3545 pr " caml_leave_blocking_section ();\n";
3550 pr " ocaml_guestfs_free_strings (%s);\n" n;
3551 | String _ | OptString _ | Bool _ | Int _ -> ()
3554 pr " if (r == %s)\n" error_code;
3555 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
3558 (match fst style with
3559 | RErr -> pr " rv = Val_unit;\n"
3560 | RInt _ -> pr " rv = Val_int (r);\n"
3561 | RBool _ -> pr " rv = Val_bool (r);\n"
3562 | RConstString _ -> pr " rv = caml_copy_string (r);\n"
3564 pr " rv = caml_copy_string (r);\n";
3567 pr " rv = caml_copy_string_array ((const char **) r);\n";
3568 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
3571 pr " rv = caml_alloc (2, 0);\n";
3572 pr " Store_field (rv, 0, Val_int (r->i));\n";
3573 pr " Store_field (rv, 1, Val_bool (r->b));\n";
3574 pr " guestfs_free_int_bool (r);\n";
3576 pr " rv = copy_lvm_pv_list (r);\n";
3577 pr " guestfs_free_lvm_pv_list (r);\n";
3579 pr " rv = copy_lvm_vg_list (r);\n";
3580 pr " guestfs_free_lvm_vg_list (r);\n";
3582 pr " rv = copy_lvm_lv_list (r);\n";
3583 pr " guestfs_free_lvm_lv_list (r);\n";
3585 pr " rv = copy_stat (r);\n";
3588 pr " rv = copy_statvfs (r);\n";
3591 pr " rv = copy_table (r);\n";
3592 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
3596 pr " CAMLreturn (rv);\n";
3600 if List.length params > 5 then (
3601 pr "CAMLprim value\n";
3602 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
3604 pr " return ocaml_guestfs_%s (argv[0]" name;
3605 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
3612 and generate_ocaml_lvm_structure_decls () =
3615 pr "type lvm_%s = {\n" typ;
3618 | name, `String -> pr " %s : string;\n" name
3619 | name, `UUID -> pr " %s : string;\n" name
3620 | name, `Bytes -> pr " %s : int64;\n" name
3621 | name, `Int -> pr " %s : int64;\n" name
3622 | name, `OptPercent -> pr " %s : float option;\n" name
3626 ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3628 and generate_ocaml_stat_structure_decls () =
3631 pr "type %s = {\n" typ;
3634 | name, `Int -> pr " %s : int64;\n" name
3638 ) ["stat", stat_cols; "statvfs", statvfs_cols]
3640 and generate_ocaml_prototype ?(is_external = false) name style =
3641 if is_external then pr "external " else pr "val ";
3642 pr "%s : t -> " name;
3645 | String _ -> pr "string -> "
3646 | OptString _ -> pr "string option -> "
3647 | StringList _ -> pr "string array -> "
3648 | Bool _ -> pr "bool -> "
3649 | Int _ -> pr "int -> "
3651 (match fst style with
3652 | RErr -> pr "unit" (* all errors are turned into exceptions *)
3653 | RInt _ -> pr "int"
3654 | RBool _ -> pr "bool"
3655 | RConstString _ -> pr "string"
3656 | RString _ -> pr "string"
3657 | RStringList _ -> pr "string array"
3658 | RIntBool _ -> pr "int * bool"
3659 | RPVList _ -> pr "lvm_pv array"
3660 | RVGList _ -> pr "lvm_vg array"
3661 | RLVList _ -> pr "lvm_lv array"
3662 | RStat _ -> pr "stat"
3663 | RStatVFS _ -> pr "statvfs"
3664 | RHashtable _ -> pr "(string * string) list"
3666 if is_external then (
3668 if List.length (snd style) + 1 > 5 then
3669 pr "\"ocaml_guestfs_%s_byte\" " name;
3670 pr "\"ocaml_guestfs_%s\"" name
3674 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
3675 and generate_perl_xs () =
3676 generate_header CStyle LGPLv2;
3679 #include \"EXTERN.h\"
3683 #include <guestfs.h>
3686 #define PRId64 \"lld\"
3690 my_newSVll(long long val) {
3691 #ifdef USE_64_BIT_ALL
3692 return newSViv(val);
3696 len = snprintf(buf, 100, \"%%\" PRId64, val);
3697 return newSVpv(buf, len);
3702 #define PRIu64 \"llu\"
3706 my_newSVull(unsigned long long val) {
3707 #ifdef USE_64_BIT_ALL
3708 return newSVuv(val);
3712 len = snprintf(buf, 100, \"%%\" PRIu64, val);
3713 return newSVpv(buf, len);
3717 /* http://www.perlmonks.org/?node_id=680842 */
3719 XS_unpack_charPtrPtr (SV *arg) {
3724 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
3725 croak (\"array reference expected\");
3728 av = (AV *)SvRV (arg);
3729 ret = (char **)malloc (av_len (av) + 1 + 1);
3731 for (i = 0; i <= av_len (av); i++) {
3732 SV **elem = av_fetch (av, i, 0);
3734 if (!elem || !*elem)
3735 croak (\"missing element in list\");
3737 ret[i] = SvPV_nolen (*elem);
3745 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
3750 RETVAL = guestfs_create ();
3752 croak (\"could not create guestfs handle\");
3753 guestfs_set_error_handler (RETVAL, NULL, NULL);
3766 fun (name, style, _, _, _, _, _) ->
3767 (match fst style with
3768 | RErr -> pr "void\n"
3769 | RInt _ -> pr "SV *\n"
3770 | RBool _ -> pr "SV *\n"
3771 | RConstString _ -> pr "SV *\n"
3772 | RString _ -> pr "SV *\n"
3775 | RPVList _ | RVGList _ | RLVList _
3776 | RStat _ | RStatVFS _
3778 pr "void\n" (* all lists returned implictly on the stack *)
3780 (* Call and arguments. *)
3782 generate_call_args ~handle:"g" style;
3784 pr " guestfs_h *g;\n";
3787 | String n -> pr " char *%s;\n" n
3788 | OptString n -> pr " char *%s;\n" n
3789 | StringList n -> pr " char **%s;\n" n
3790 | Bool n -> pr " int %s;\n" n
3791 | Int n -> pr " int %s;\n" n
3794 let do_cleanups () =
3801 | StringList n -> pr " free (%s);\n" n
3806 (match fst style with
3811 pr " r = guestfs_%s " name;
3812 generate_call_args ~handle:"g" style;
3815 pr " if (r == -1)\n";
3816 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3822 pr " %s = guestfs_%s " n name;
3823 generate_call_args ~handle:"g" style;
3826 pr " if (%s == -1)\n" n;
3827 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3828 pr " RETVAL = newSViv (%s);\n" n;
3833 pr " const char *%s;\n" 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 " RETVAL = newSVpv (%s, 0);\n" n;
3846 pr " char *%s;\n" n;
3848 pr " %s = guestfs_%s " n name;
3849 generate_call_args ~handle:"g" style;
3852 pr " if (%s == NULL)\n" n;
3853 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3854 pr " RETVAL = newSVpv (%s, 0);\n" n;
3855 pr " free (%s);\n" n;
3858 | RStringList n | RHashtable n ->
3860 pr " char **%s;\n" n;
3863 pr " %s = guestfs_%s " n name;
3864 generate_call_args ~handle:"g" style;
3867 pr " if (%s == NULL)\n" n;
3868 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3869 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
3870 pr " EXTEND (SP, n);\n";
3871 pr " for (i = 0; i < n; ++i) {\n";
3872 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
3873 pr " free (%s[i]);\n" n;
3875 pr " free (%s);\n" n;
3878 pr " struct guestfs_int_bool *r;\n";
3880 pr " r = guestfs_%s " name;
3881 generate_call_args ~handle:"g" style;
3884 pr " if (r == NULL)\n";
3885 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3886 pr " EXTEND (SP, 2);\n";
3887 pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
3888 pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
3889 pr " guestfs_free_int_bool (r);\n";
3891 generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
3893 generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
3895 generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
3897 generate_perl_stat_code "stat" stat_cols name style n do_cleanups
3899 generate_perl_stat_code
3900 "statvfs" statvfs_cols name style n do_cleanups
3906 and generate_perl_lvm_code typ cols name style n do_cleanups =
3908 pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
3912 pr " %s = guestfs_%s " n name;
3913 generate_call_args ~handle:"g" style;
3916 pr " if (%s == NULL)\n" n;
3917 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3918 pr " EXTEND (SP, %s->len);\n" n;
3919 pr " for (i = 0; i < %s->len; ++i) {\n" n;
3920 pr " hv = newHV ();\n";
3924 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
3925 name (String.length name) n name
3927 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
3928 name (String.length name) n name
3930 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
3931 name (String.length name) n name
3933 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
3934 name (String.length name) n name
3935 | name, `OptPercent ->
3936 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
3937 name (String.length name) n name
3939 pr " PUSHs (sv_2mortal ((SV *) hv));\n";
3941 pr " guestfs_free_lvm_%s_list (%s);\n" typ n
3943 and generate_perl_stat_code typ cols name style n do_cleanups =
3945 pr " struct guestfs_%s *%s;\n" typ n;
3947 pr " %s = guestfs_%s " n name;
3948 generate_call_args ~handle:"g" style;
3951 pr " if (%s == NULL)\n" n;
3952 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3953 pr " EXTEND (SP, %d);\n" (List.length cols);
3957 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
3959 pr " free (%s);\n" n
3961 (* Generate Sys/Guestfs.pm. *)
3962 and generate_perl_pm () =
3963 generate_header HashStyle LGPLv2;
3970 Sys::Guestfs - Perl bindings for libguestfs
3976 my $h = Sys::Guestfs->new ();
3977 $h->add_drive ('guest.img');
3980 $h->mount ('/dev/sda1', '/');
3981 $h->touch ('/hello');
3986 The C<Sys::Guestfs> module provides a Perl XS binding to the
3987 libguestfs API for examining and modifying virtual machine
3990 Amongst the things this is good for: making batch configuration
3991 changes to guests, getting disk used/free statistics (see also:
3992 virt-df), migrating between virtualization systems (see also:
3993 virt-p2v), performing partial backups, performing partial guest
3994 clones, cloning guests and changing registry/UUID/hostname info, and
3997 Libguestfs uses Linux kernel and qemu code, and can access any type of
3998 guest filesystem that Linux and qemu can, including but not limited
3999 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
4000 schemes, qcow, qcow2, vmdk.
4002 Libguestfs provides ways to enumerate guest storage (eg. partitions,
4003 LVs, what filesystem is in each LV, etc.). It can also run commands
4004 in the context of the guest. Also you can access filesystems over FTP.
4008 All errors turn into calls to C<croak> (see L<Carp(3)>).
4016 package Sys::Guestfs;
4022 XSLoader::load ('Sys::Guestfs');
4024 =item $h = Sys::Guestfs->new ();
4026 Create a new guestfs handle.
4032 my $class = ref ($proto) || $proto;
4034 my $self = Sys::Guestfs::_create ();
4035 bless $self, $class;
4041 (* Actions. We only need to print documentation for these as
4042 * they are pulled in from the XS code automatically.
4045 fun (name, style, _, flags, _, _, longdesc) ->
4046 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
4048 generate_perl_prototype name style;
4050 pr "%s\n\n" longdesc;
4051 if List.mem ProtocolLimitWarning flags then
4052 pr "%s\n\n" protocol_limit_warning;
4053 if List.mem DangerWillRobinson flags then
4054 pr "%s\n\n" danger_will_robinson
4055 ) all_functions_sorted;
4067 Copyright (C) 2009 Red Hat Inc.
4071 Please see the file COPYING.LIB for the full license.
4075 L<guestfs(3)>, L<guestfish(1)>.
4080 and generate_perl_prototype name style =
4081 (match fst style with
4086 | RString n -> pr "$%s = " n
4087 | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4091 | RLVList n -> pr "@%s = " n
4094 | RHashtable n -> pr "%%%s = " n
4097 let comma = ref false in
4100 if !comma then pr ", ";
4103 | String n | OptString n | Bool n | Int n ->
4110 (* Generate Python C module. *)
4111 and generate_python_c () =
4112 generate_header CStyle LGPLv2;
4121 #include \"guestfs.h\"
4129 get_handle (PyObject *obj)
4132 assert (obj != Py_None);
4133 return ((Pyguestfs_Object *) obj)->g;
4137 put_handle (guestfs_h *g)
4141 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4144 /* This list should be freed (but not the strings) after use. */
4145 static const char **
4146 get_string_list (PyObject *obj)
4153 if (!PyList_Check (obj)) {
4154 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4158 len = PyList_Size (obj);
4159 r = malloc (sizeof (char *) * (len+1));
4161 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4165 for (i = 0; i < len; ++i)
4166 r[i] = PyString_AsString (PyList_GetItem (obj, i));
4173 put_string_list (char * const * const argv)
4178 for (argc = 0; argv[argc] != NULL; ++argc)
4181 list = PyList_New (argc);
4182 for (i = 0; i < argc; ++i)
4183 PyList_SetItem (list, i, PyString_FromString (argv[i]));
4189 put_table (char * const * const argv)
4191 PyObject *list, *item;
4194 for (argc = 0; argv[argc] != NULL; ++argc)
4197 list = PyList_New (argc >> 1);
4198 for (i = 0; i < argc; i += 2) {
4200 item = PyTuple_New (2);
4201 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
4202 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
4203 PyList_SetItem (list, i >> 1, item);
4210 free_strings (char **argv)
4214 for (argc = 0; argv[argc] != NULL; ++argc)
4220 py_guestfs_create (PyObject *self, PyObject *args)
4224 g = guestfs_create ();
4226 PyErr_SetString (PyExc_RuntimeError,
4227 \"guestfs.create: failed to allocate handle\");
4230 guestfs_set_error_handler (g, NULL, NULL);
4231 return put_handle (g);
4235 py_guestfs_close (PyObject *self, PyObject *args)
4240 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4242 g = get_handle (py_g);
4246 Py_INCREF (Py_None);
4252 (* LVM structures, turned into Python dictionaries. *)
4255 pr "static PyObject *\n";
4256 pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4258 pr " PyObject *dict;\n";
4260 pr " dict = PyDict_New ();\n";
4264 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4265 pr " PyString_FromString (%s->%s));\n"
4268 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4269 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
4272 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4273 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
4276 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
4277 pr " PyLong_FromLongLong (%s->%s));\n"
4279 | name, `OptPercent ->
4280 pr " if (%s->%s >= 0)\n" typ name;
4281 pr " PyDict_SetItemString (dict, \"%s\",\n" name;