253a1e0b80efcf92de383493c8a9876467b87a4f
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009 Red Hat Inc.
4  *
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.
9  *
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.
14  *
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
18  *)
19
20 (* This script generates a large amount of code and documentation for
21  * all the daemon actions.  To add a new action there are only two
22  * files you need to change, this one to describe the interface, and
23  * daemon/<somefile>.c to write the implementation.
24  *
25  * After editing this file, run it (./src/generator.ml) to regenerate
26  * all the output files.
27  *
28  * IMPORTANT: This script should NOT print any warnings.  If it prints
29  * warnings, you should treat them as errors.
30  * [Need to add -warn-error to ocaml command line]
31  *)
32
33 #load "unix.cma";;
34
35 open Printf
36
37 type style = ret * args
38 and ret =
39     (* "RErr" as a return value means an int used as a simple error
40      * indication, ie. 0 or -1.
41      *)
42   | RErr
43     (* "RInt" as a return value means an int which is -1 for error
44      * or any value >= 0 on success.
45      *)
46   | RInt of string
47     (* "RBool" is a bool return value which can be true/false or
48      * -1 for error.
49      *)
50   | RBool of string
51     (* "RConstString" is a string that refers to a constant value.
52      * Try to avoid using this.  In particular you cannot use this
53      * for values returned from the daemon, because there is no
54      * thread-safe way to return them in the C API.
55      *)
56   | RConstString of string
57     (* "RString" and "RStringList" are caller-frees. *)
58   | RString of string
59   | RStringList of string
60     (* Some limited tuples are possible: *)
61   | RIntBool of string * string
62     (* LVM PVs, VGs and LVs. *)
63   | RPVList of string
64   | RVGList of string
65   | RLVList of string
66 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
67
68     (* Note in future we should allow a "variable args" parameter as
69      * the final parameter, to allow commands like
70      *   chmod mode file [file(s)...]
71      * This is not implemented yet, but many commands (such as chmod)
72      * are currently defined with the argument order keeping this future
73      * possibility in mind.
74      *)
75 and argt =
76   | String of string    (* const char *name, cannot be NULL *)
77   | OptString of string (* const char *name, may be NULL *)
78   | Bool of string      (* boolean *)
79   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
80
81 type flags =
82   | ProtocolLimitWarning  (* display warning about protocol size limits *)
83   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
84   | FishAction of string  (* call this function in guestfish *)
85   | NotInFish             (* do not export via guestfish *)
86
87 (* Note about long descriptions: When referring to another
88  * action, use the format C<guestfs_other> (ie. the full name of
89  * the C function).  This will be replaced as appropriate in other
90  * language bindings.
91  *
92  * Apart from that, long descriptions are just perldoc paragraphs.
93  *)
94
95 let non_daemon_functions = [
96   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
97    "launch the qemu subprocess",
98    "\
99 Internally libguestfs is implemented by running a virtual machine
100 using L<qemu(1)>.
101
102 You should call this after configuring the handle
103 (eg. adding drives) but before performing any actions.");
104
105   ("wait_ready", (RErr, []), -1, [NotInFish],
106    "wait until the qemu subprocess launches",
107    "\
108 Internally libguestfs is implemented by running a virtual machine
109 using L<qemu(1)>.
110
111 You should call this after C<guestfs_launch> to wait for the launch
112 to complete.");
113
114   ("kill_subprocess", (RErr, []), -1, [],
115    "kill the qemu subprocess",
116    "\
117 This kills the qemu subprocess.  You should never need to call this.");
118
119   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
120    "add an image to examine or modify",
121    "\
122 This function adds a virtual machine disk image C<filename> to the
123 guest.  The first time you call this function, the disk appears as IDE
124 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
125 so on.
126
127 You don't necessarily need to be root when using libguestfs.  However
128 you obviously do need sufficient permissions to access the filename
129 for whatever operations you want to perform (ie. read access if you
130 just want to read the image or write access if you want to modify the
131 image).
132
133 This is equivalent to the qemu parameter C<-drive file=filename>.");
134
135   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
136    "add a CD-ROM disk image to examine",
137    "\
138 This function adds a virtual CD-ROM disk image to the guest.
139
140 This is equivalent to the qemu parameter C<-cdrom filename>.");
141
142   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
143    "add qemu parameters",
144    "\
145 This can be used to add arbitrary qemu command line parameters
146 of the form C<-param value>.  Actually it's not quite arbitrary - we
147 prevent you from setting some parameters which would interfere with
148 parameters that we use.
149
150 The first character of C<param> string must be a C<-> (dash).
151
152 C<value> can be NULL.");
153
154   ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
155    "set the search path",
156    "\
157 Set the path that libguestfs searches for kernel and initrd.img.
158
159 The default is C<$libdir/guestfs> unless overridden by setting
160 C<LIBGUESTFS_PATH> environment variable.
161
162 The string C<path> is stashed in the libguestfs handle, so the caller
163 must make sure it remains valid for the lifetime of the handle.
164
165 Setting C<path> to C<NULL> restores the default path.");
166
167   ("get_path", (RConstString "path", []), -1, [],
168    "get the search path",
169    "\
170 Return the current search path.
171
172 This is always non-NULL.  If it wasn't set already, then this will
173 return the default path.");
174
175   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
176    "set autosync mode",
177    "\
178 If C<autosync> is true, this enables autosync.  Libguestfs will make a
179 best effort attempt to run C<guestfs_sync> when the handle is closed
180 (also if the program exits without closing handles).");
181
182   ("get_autosync", (RBool "autosync", []), -1, [],
183    "get autosync mode",
184    "\
185 Get the autosync flag.");
186
187   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
188    "set verbose mode",
189    "\
190 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
191
192 Verbose messages are disabled unless the environment variable
193 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
194
195   ("get_verbose", (RBool "verbose", []), -1, [],
196    "get verbose mode",
197    "\
198 This returns the verbose messages flag.")
199 ]
200
201 let daemon_functions = [
202   ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
203    "mount a guest disk at a position in the filesystem",
204    "\
205 Mount a guest disk at a position in the filesystem.  Block devices
206 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
207 the guest.  If those block devices contain partitions, they will have
208 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
209 names can be used.
210
211 The rules are the same as for L<mount(2)>:  A filesystem must
212 first be mounted on C</> before others can be mounted.  Other
213 filesystems can only be mounted on directories which already
214 exist.
215
216 The mounted filesystem is writable, if we have sufficient permissions
217 on the underlying device.
218
219 The filesystem options C<sync> and C<noatime> are set with this
220 call, in order to improve reliability.");
221
222   ("sync", (RErr, []), 2, [],
223    "sync disks, writes are flushed through to the disk image",
224    "\
225 This syncs the disk, so that any writes are flushed through to the
226 underlying disk image.
227
228 You should always call this if you have modified a disk image, before
229 closing the handle.");
230
231   ("touch", (RErr, [String "path"]), 3, [],
232    "update file timestamps or create a new file",
233    "\
234 Touch acts like the L<touch(1)> command.  It can be used to
235 update the timestamps on a file, or, if the file does not exist,
236 to create a new zero-length file.");
237
238   ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
239    "list the contents of a file",
240    "\
241 Return the contents of the file named C<path>.
242
243 Note that this function cannot correctly handle binary files
244 (specifically, files containing C<\\0> character which is treated
245 as end of string).  For those you need to use the C<guestfs_read_file>
246 function which has a more complex interface.");
247
248   ("ll", (RString "listing", [String "directory"]), 5, [],
249    "list the files in a directory (long format)",
250    "\
251 List the files in C<directory> (relative to the root directory,
252 there is no cwd) in the format of 'ls -la'.
253
254 This command is mostly useful for interactive sessions.  It
255 is I<not> intended that you try to parse the output string.");
256
257   ("ls", (RStringList "listing", [String "directory"]), 6, [],
258    "list the files in a directory",
259    "\
260 List the files in C<directory> (relative to the root directory,
261 there is no cwd).  The '.' and '..' entries are not returned, but
262 hidden files are shown.
263
264 This command is mostly useful for interactive sessions.  Programs
265 should probably use C<guestfs_readdir> instead.");
266
267   ("list_devices", (RStringList "devices", []), 7, [],
268    "list the block devices",
269    "\
270 List all the block devices.
271
272 The full block device names are returned, eg. C</dev/sda>");
273
274   ("list_partitions", (RStringList "partitions", []), 8, [],
275    "list the partitions",
276    "\
277 List all the partitions detected on all block devices.
278
279 The full partition device names are returned, eg. C</dev/sda1>
280
281 This does not return logical volumes.  For that you will need to
282 call C<guestfs_lvs>.");
283
284   ("pvs", (RStringList "physvols", []), 9, [],
285    "list the LVM physical volumes (PVs)",
286    "\
287 List all the physical volumes detected.  This is the equivalent
288 of the L<pvs(8)> command.
289
290 This returns a list of just the device names that contain
291 PVs (eg. C</dev/sda2>).
292
293 See also C<guestfs_pvs_full>.");
294
295   ("vgs", (RStringList "volgroups", []), 10, [],
296    "list the LVM volume groups (VGs)",
297    "\
298 List all the volumes groups detected.  This is the equivalent
299 of the L<vgs(8)> command.
300
301 This returns a list of just the volume group names that were
302 detected (eg. C<VolGroup00>).
303
304 See also C<guestfs_vgs_full>.");
305
306   ("lvs", (RStringList "logvols", []), 11, [],
307    "list the LVM logical volumes (LVs)",
308    "\
309 List all the logical volumes detected.  This is the equivalent
310 of the L<lvs(8)> command.
311
312 This returns a list of the logical volume device names
313 (eg. C</dev/VolGroup00/LogVol00>).
314
315 See also C<guestfs_lvs_full>.");
316
317   ("pvs_full", (RPVList "physvols", []), 12, [],
318    "list the LVM physical volumes (PVs)",
319    "\
320 List all the physical volumes detected.  This is the equivalent
321 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
322
323   ("vgs_full", (RVGList "volgroups", []), 13, [],
324    "list the LVM volume groups (VGs)",
325    "\
326 List all the volumes groups detected.  This is the equivalent
327 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
328
329   ("lvs_full", (RLVList "logvols", []), 14, [],
330    "list the LVM logical volumes (LVs)",
331    "\
332 List all the logical volumes detected.  This is the equivalent
333 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
334
335   ("read_lines", (RStringList "lines", [String "path"]), 15, [],
336    "read file as lines",
337    "\
338 Return the contents of the file named C<path>.
339
340 The file contents are returned as a list of lines.  Trailing
341 C<LF> and C<CRLF> character sequences are I<not> returned.
342
343 Note that this function cannot correctly handle binary files
344 (specifically, files containing C<\\0> character which is treated
345 as end of line).  For those you need to use the C<guestfs_read_file>
346 function which has a more complex interface.");
347
348   ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
349    "create a new Augeas handle",
350    "\
351 Create a new Augeas handle for editing configuration files.
352 If there was any previous Augeas handle associated with this
353 guestfs session, then it is closed.
354
355 You must call this before using any other C<guestfs_aug_*>
356 commands.
357
358 C<root> is the filesystem root.  C<root> must not be NULL,
359 use C</> instead.
360
361 The flags are the same as the flags defined in
362 E<lt>augeas.hE<gt>, the logical I<or> of the following
363 integers:
364
365 =over 4
366
367 =item C<AUG_SAVE_BACKUP> = 1
368
369 Keep the original file with a C<.augsave> extension.
370
371 =item C<AUG_SAVE_NEWFILE> = 2
372
373 Save changes into a file with extension C<.augnew>, and
374 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
375
376 =item C<AUG_TYPE_CHECK> = 4
377
378 Typecheck lenses (can be expensive).
379
380 =item C<AUG_NO_STDINC> = 8
381
382 Do not use standard load path for modules.
383
384 =item C<AUG_SAVE_NOOP> = 16
385
386 Make save a no-op, just record what would have been changed.
387
388 =item C<AUG_NO_LOAD> = 32
389
390 Do not load the tree in C<guestfs_aug_init>.
391
392 =back
393
394 To close the handle, you can call C<guestfs_aug_close>.
395
396 To find out more about Augeas, see L<http://augeas.net/>.");
397
398   ("aug_close", (RErr, []), 26, [],
399    "close the current Augeas handle",
400    "\
401 Close the current Augeas handle and free up any resources
402 used by it.  After calling this, you have to call
403 C<guestfs_aug_init> again before you can use any other
404 Augeas functions.");
405
406   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
407    "define an Augeas variable",
408    "\
409 Defines an Augeas variable C<name> whose value is the result
410 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
411 undefined.
412
413 On success this returns the number of nodes in C<expr>, or
414 C<0> if C<expr> evaluates to something which is not a nodeset.");
415
416   ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
417    "define an Augeas node",
418    "\
419 Defines a variable C<name> whose value is the result of
420 evaluating C<expr>.
421
422 If C<expr> evaluates to an empty nodeset, a node is created,
423 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
424 C<name> will be the nodeset containing that single node.
425
426 On success this returns a pair containing the
427 number of nodes in the nodeset, and a boolean flag
428 if a node was created.");
429
430   ("aug_get", (RString "val", [String "path"]), 19, [],
431    "look up the value of an Augeas path",
432    "\
433 Look up the value associated with C<path>.  If C<path>
434 matches exactly one node, the C<value> is returned.");
435
436   ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
437    "set Augeas path to value",
438    "\
439 Set the value associated with C<path> to C<value>.");
440
441   ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
442    "insert a sibling Augeas node",
443    "\
444 Create a new sibling C<label> for C<path>, inserting it into
445 the tree before or after C<path> (depending on the boolean
446 flag C<before>).
447
448 C<path> must match exactly one existing node in the tree, and
449 C<label> must be a label, ie. not contain C</>, C<*> or end
450 with a bracketed index C<[N]>.");
451
452   ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
453    "remove an Augeas path",
454    "\
455 Remove C<path> and all of its children.
456
457 On success this returns the number of entries which were removed.");
458
459   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
460    "move Augeas node",
461    "\
462 Move the node C<src> to C<dest>.  C<src> must match exactly
463 one node.  C<dest> is overwritten if it exists.");
464
465   ("aug_match", (RStringList "matches", [String "path"]), 24, [],
466    "return Augeas nodes which match path",
467    "\
468 Returns a list of paths which match the path expression C<path>.
469 The returned paths are sufficiently qualified so that they match
470 exactly one node in the current tree.");
471
472   ("aug_save", (RErr, []), 25, [],
473    "write all pending Augeas changes to disk",
474    "\
475 This writes all pending changes to disk.
476
477 The flags which were passed to C<guestfs_aug_init> affect exactly
478 how files are saved.");
479
480   ("aug_load", (RErr, []), 27, [],
481    "load files into the tree",
482    "\
483 Load files into the tree.
484
485 See C<aug_load> in the Augeas documentation for the full gory
486 details.");
487
488   ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
489    "list Augeas nodes under a path",
490    "\
491 This is just a shortcut for listing C<guestfs_aug_match>
492 C<path/*> and sorting the resulting nodes into alphabetical order.");
493
494   ("rm", (RErr, [String "path"]), 29, [],
495    "remove a file",
496    "\
497 Remove the single file C<path>.");
498
499   ("rmdir", (RErr, [String "path"]), 30, [],
500    "remove a directory",
501    "\
502 Remove the single directory C<path>.");
503
504   ("rm_rf", (RErr, [String "path"]), 31, [],
505    "remove a file or directory recursively",
506    "\
507 Remove the file or directory C<path>, recursively removing the
508 contents if its a directory.  This is like the C<rm -rf> shell
509 command.");
510
511   ("mkdir", (RErr, [String "path"]), 32, [],
512    "create a directory",
513    "\
514 Create a directory named C<path>.");
515
516   ("mkdir_p", (RErr, [String "path"]), 33, [],
517    "create a directory and parents",
518    "\
519 Create a directory named C<path>, creating any parent directories
520 as necessary.  This is like the C<mkdir -p> shell command.");
521
522   ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
523    "change file mode",
524    "\
525 Change the mode (permissions) of C<path> to C<mode>.  Only
526 numeric modes are supported.");
527
528   ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
529    "change file owner and group",
530    "\
531 Change the file owner to C<owner> and group to C<group>.
532
533 Only numeric uid and gid are supported.  If you want to use
534 names, you will need to locate and parse the password file
535 yourself (Augeas support makes this relatively easy).");
536 ]
537
538 let all_functions = non_daemon_functions @ daemon_functions
539
540 (* In some places we want the functions to be displayed sorted
541  * alphabetically, so this is useful:
542  *)
543 let all_functions_sorted =
544   List.sort (fun (n1,_,_,_,_,_) (n2,_,_,_,_,_) -> compare n1 n2) all_functions
545
546 (* Column names and types from LVM PVs/VGs/LVs. *)
547 let pv_cols = [
548   "pv_name", `String;
549   "pv_uuid", `UUID;
550   "pv_fmt", `String;
551   "pv_size", `Bytes;
552   "dev_size", `Bytes;
553   "pv_free", `Bytes;
554   "pv_used", `Bytes;
555   "pv_attr", `String (* XXX *);
556   "pv_pe_count", `Int;
557   "pv_pe_alloc_count", `Int;
558   "pv_tags", `String;
559   "pe_start", `Bytes;
560   "pv_mda_count", `Int;
561   "pv_mda_free", `Bytes;
562 (* Not in Fedora 10:
563   "pv_mda_size", `Bytes;
564 *)
565 ]
566 let vg_cols = [
567   "vg_name", `String;
568   "vg_uuid", `UUID;
569   "vg_fmt", `String;
570   "vg_attr", `String (* XXX *);
571   "vg_size", `Bytes;
572   "vg_free", `Bytes;
573   "vg_sysid", `String;
574   "vg_extent_size", `Bytes;
575   "vg_extent_count", `Int;
576   "vg_free_count", `Int;
577   "max_lv", `Int;
578   "max_pv", `Int;
579   "pv_count", `Int;
580   "lv_count", `Int;
581   "snap_count", `Int;
582   "vg_seqno", `Int;
583   "vg_tags", `String;
584   "vg_mda_count", `Int;
585   "vg_mda_free", `Bytes;
586 (* Not in Fedora 10:
587   "vg_mda_size", `Bytes;
588 *)
589 ]
590 let lv_cols = [
591   "lv_name", `String;
592   "lv_uuid", `UUID;
593   "lv_attr", `String (* XXX *);
594   "lv_major", `Int;
595   "lv_minor", `Int;
596   "lv_kernel_major", `Int;
597   "lv_kernel_minor", `Int;
598   "lv_size", `Bytes;
599   "seg_count", `Int;
600   "origin", `String;
601   "snap_percent", `OptPercent;
602   "copy_percent", `OptPercent;
603   "move_pv", `String;
604   "lv_tags", `String;
605   "mirror_log", `String;
606   "modules", `String;
607 ]
608
609 (* Useful functions.
610  * Note we don't want to use any external OCaml libraries which
611  * makes this a bit harder than it should be.
612  *)
613 let failwithf fs = ksprintf failwith fs
614
615 let replace_char s c1 c2 =
616   let s2 = String.copy s in
617   let r = ref false in
618   for i = 0 to String.length s2 - 1 do
619     if String.unsafe_get s2 i = c1 then (
620       String.unsafe_set s2 i c2;
621       r := true
622     )
623   done;
624   if not !r then s else s2
625
626 let rec find s sub =
627   let len = String.length s in
628   let sublen = String.length sub in
629   let rec loop i =
630     if i <= len-sublen then (
631       let rec loop2 j =
632         if j < sublen then (
633           if s.[i+j] = sub.[j] then loop2 (j+1)
634           else -1
635         ) else
636           i (* found *)
637       in
638       let r = loop2 0 in
639       if r = -1 then loop (i+1) else r
640     ) else
641       -1 (* not found *)
642   in
643   loop 0
644
645 let rec replace_str s s1 s2 =
646   let len = String.length s in
647   let sublen = String.length s1 in
648   let i = find s s1 in
649   if i = -1 then s
650   else (
651     let s' = String.sub s 0 i in
652     let s'' = String.sub s (i+sublen) (len-i-sublen) in
653     s' ^ s2 ^ replace_str s'' s1 s2
654   )
655
656 let rec find_map f = function
657   | [] -> raise Not_found
658   | x :: xs ->
659       match f x with
660       | Some y -> y
661       | None -> find_map f xs
662
663 let iteri f xs =
664   let rec loop i = function
665     | [] -> ()
666     | x :: xs -> f i x; loop (i+1) xs
667   in
668   loop 0 xs
669
670 let name_of_argt = function String n | OptString n | Bool n | Int n -> n
671
672 (* Check function names etc. for consistency. *)
673 let check_functions () =
674   let contains_uppercase str =
675     let len = String.length str in
676     let rec loop i =
677       if i >= len then false
678       else (
679         let c = str.[i] in
680         if c >= 'A' && c <= 'Z' then true
681         else loop (i+1)
682       )
683     in
684     loop 0
685   in
686
687   (* Check function names. *)
688   List.iter (
689     fun (name, _, _, _, _, _) ->
690       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
691         failwithf "function name %s does not need 'guestfs' prefix" name;
692       if contains_uppercase name then
693         failwithf "function name %s should not contain uppercase chars" name;
694       if String.contains name '-' then
695         failwithf "function name %s should not contain '-', use '_' instead."
696           name
697   ) all_functions;
698
699   (* Check function parameter/return names. *)
700   List.iter (
701     fun (name, style, _, _, _, _) ->
702       let check_arg_ret_name n =
703         if contains_uppercase n then
704           failwithf "%s param/ret %s should not contain uppercase chars"
705             name n;
706         if String.contains n '-' || String.contains n '_' then
707           failwithf "%s param/ret %s should not contain '-' or '_'"
708             name n;
709         if n = "value" then
710           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
711       in
712
713       (match fst style with
714        | RErr -> ()
715        | RInt n | RBool n | RConstString n | RString n
716        | RStringList n | RPVList n | RVGList n | RLVList n ->
717            check_arg_ret_name n
718        | RIntBool (n,m) ->
719            check_arg_ret_name n;
720            check_arg_ret_name m
721       );
722       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
723   ) all_functions;
724
725   (* Check long dscriptions. *)
726   List.iter (
727     fun (name, _, _, _, _, longdesc) ->
728       if longdesc.[String.length longdesc-1] = '\n' then
729         failwithf "long description of %s should not end with \\n." name
730   ) all_functions;
731
732   (* Check proc_nrs. *)
733   List.iter (
734     fun (name, _, proc_nr, _, _, _) ->
735       if proc_nr <= 0 then
736         failwithf "daemon function %s should have proc_nr > 0" name
737   ) daemon_functions;
738
739   List.iter (
740     fun (name, _, proc_nr, _, _, _) ->
741       if proc_nr <> -1 then
742         failwithf "non-daemon function %s should have proc_nr -1" name
743   ) non_daemon_functions;
744
745   let proc_nrs =
746     List.map (fun (name, _, proc_nr, _, _, _) -> name, proc_nr)
747       daemon_functions in
748   let proc_nrs =
749     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
750   let rec loop = function
751     | [] -> ()
752     | [_] -> ()
753     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
754         loop rest
755     | (name1,nr1) :: (name2,nr2) :: _ ->
756         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
757           name1 name2 nr1 nr2
758   in
759   loop proc_nrs
760
761 (* 'pr' prints to the current output file. *)
762 let chan = ref stdout
763 let pr fs = ksprintf (output_string !chan) fs
764
765 (* Generate a header block in a number of standard styles. *)
766 type comment_style = CStyle | HashStyle | OCamlStyle
767 type license = GPLv2 | LGPLv2
768
769 let generate_header comment license =
770   let c = match comment with
771     | CStyle ->     pr "/* "; " *"
772     | HashStyle ->  pr "# ";  "#"
773     | OCamlStyle -> pr "(* "; " *" in
774   pr "libguestfs generated file\n";
775   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
776   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
777   pr "%s\n" c;
778   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
779   pr "%s\n" c;
780   (match license with
781    | GPLv2 ->
782        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
783        pr "%s it under the terms of the GNU General Public License as published by\n" c;
784        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
785        pr "%s (at your option) any later version.\n" c;
786        pr "%s\n" c;
787        pr "%s This program is distributed in the hope that it will be useful,\n" c;
788        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
789        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
790        pr "%s GNU General Public License for more details.\n" c;
791        pr "%s\n" c;
792        pr "%s You should have received a copy of the GNU General Public License along\n" c;
793        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
794        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
795
796    | LGPLv2 ->
797        pr "%s This library is free software; you can redistribute it and/or\n" c;
798        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
799        pr "%s License as published by the Free Software Foundation; either\n" c;
800        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
801        pr "%s\n" c;
802        pr "%s This library is distributed in the hope that it will be useful,\n" c;
803        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
804        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
805        pr "%s Lesser General Public License for more details.\n" c;
806        pr "%s\n" c;
807        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
808        pr "%s License along with this library; if not, write to the Free Software\n" c;
809        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
810   );
811   (match comment with
812    | CStyle -> pr " */\n"
813    | HashStyle -> ()
814    | OCamlStyle -> pr " *)\n"
815   );
816   pr "\n"
817
818 (* Start of main code generation functions below this line. *)
819
820 (* Generate the pod documentation for the C API. *)
821 let rec generate_actions_pod () =
822   List.iter (
823     fun (shortname, style, _, flags, _, longdesc) ->
824       let name = "guestfs_" ^ shortname in
825       pr "=head2 %s\n\n" name;
826       pr " ";
827       generate_prototype ~extern:false ~handle:"handle" name style;
828       pr "\n\n";
829       pr "%s\n\n" longdesc;
830       (match fst style with
831        | RErr ->
832            pr "This function returns 0 on success or -1 on error.\n\n"
833        | RInt _ ->
834            pr "On error this function returns -1.\n\n"
835        | RBool _ ->
836            pr "This function returns a C truth value on success or -1 on error.\n\n"
837        | RConstString _ ->
838            pr "This function returns a string or NULL on error.
839 The string is owned by the guest handle and must I<not> be freed.\n\n"
840        | RString _ ->
841            pr "This function returns a string or NULL on error.
842 I<The caller must free the returned string after use>.\n\n"
843        | RStringList _ ->
844            pr "This function returns a NULL-terminated array of strings
845 (like L<environ(3)>), or NULL if there was an error.
846 I<The caller must free the strings and the array after use>.\n\n"
847        | RIntBool _ ->
848            pr "This function returns a C<struct guestfs_int_bool *>.
849 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
850        | RPVList _ ->
851            pr "This function returns a C<struct guestfs_lvm_pv_list *>.
852 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
853        | RVGList _ ->
854            pr "This function returns a C<struct guestfs_lvm_vg_list *>.
855 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
856        | RLVList _ ->
857            pr "This function returns a C<struct guestfs_lvm_lv_list *>.
858 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
859       );
860       if List.mem ProtocolLimitWarning flags then
861         pr "Because of the message protocol, there is a transfer limit 
862 of somewhere between 2MB and 4MB.  To transfer large files you should use
863 FTP.\n\n";
864   ) all_functions_sorted
865
866 and generate_structs_pod () =
867   (* LVM structs documentation. *)
868   List.iter (
869     fun (typ, cols) ->
870       pr "=head2 guestfs_lvm_%s\n" typ;
871       pr "\n";
872       pr " struct guestfs_lvm_%s {\n" typ;
873       List.iter (
874         function
875         | name, `String -> pr "  char *%s;\n" name
876         | name, `UUID ->
877             pr "  /* The next field is NOT nul-terminated, be careful when printing it: */\n";
878             pr "  char %s[32];\n" name
879         | name, `Bytes -> pr "  uint64_t %s;\n" name
880         | name, `Int -> pr "  int64_t %s;\n" name
881         | name, `OptPercent ->
882             pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
883             pr "  float %s;\n" name
884       ) cols;
885       pr " \n";
886       pr " struct guestfs_lvm_%s_list {\n" typ;
887       pr "   uint32_t len; /* Number of elements in list. */\n";
888       pr "   struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
889       pr " };\n";
890       pr " \n";
891       pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
892         typ typ;
893       pr "\n"
894   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
895
896 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
897  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
898  *
899  * We have to use an underscore instead of a dash because otherwise
900  * rpcgen generates incorrect code.
901  *
902  * This header is NOT exported to clients, but see also generate_structs_h.
903  *)
904 and generate_xdr () =
905   generate_header CStyle LGPLv2;
906
907   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
908   pr "typedef string str<>;\n";
909   pr "\n";
910
911   (* LVM internal structures. *)
912   List.iter (
913     function
914     | typ, cols ->
915         pr "struct guestfs_lvm_int_%s {\n" typ;
916         List.iter (function
917                    | name, `String -> pr "  string %s<>;\n" name
918                    | name, `UUID -> pr "  opaque %s[32];\n" name
919                    | name, `Bytes -> pr "  hyper %s;\n" name
920                    | name, `Int -> pr "  hyper %s;\n" name
921                    | name, `OptPercent -> pr "  float %s;\n" name
922                   ) cols;
923         pr "};\n";
924         pr "\n";
925         pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
926         pr "\n";
927   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
928
929   List.iter (
930     fun(shortname, style, _, _, _, _) ->
931       let name = "guestfs_" ^ shortname in
932
933       (match snd style with
934        | [] -> ()
935        | args ->
936            pr "struct %s_args {\n" name;
937            List.iter (
938              function
939              | String n -> pr "  string %s<>;\n" n
940              | OptString n -> pr "  str *%s;\n" n
941              | Bool n -> pr "  bool %s;\n" n
942              | Int n -> pr "  int %s;\n" n
943            ) args;
944            pr "};\n\n"
945       );
946       (match fst style with
947        | RErr -> ()
948        | RInt n ->
949            pr "struct %s_ret {\n" name;
950            pr "  int %s;\n" n;
951            pr "};\n\n"
952        | RBool n ->
953            pr "struct %s_ret {\n" name;
954            pr "  bool %s;\n" n;
955            pr "};\n\n"
956        | RConstString _ ->
957            failwithf "RConstString cannot be returned from a daemon function"
958        | RString n ->
959            pr "struct %s_ret {\n" name;
960            pr "  string %s<>;\n" n;
961            pr "};\n\n"
962        | RStringList n ->
963            pr "struct %s_ret {\n" name;
964            pr "  str %s<>;\n" n;
965            pr "};\n\n"
966        | RIntBool (n,m) ->
967            pr "struct %s_ret {\n" name;
968            pr "  int %s;\n" n;
969            pr "  bool %s;\n" m;
970            pr "};\n\n"
971        | RPVList n ->
972            pr "struct %s_ret {\n" name;
973            pr "  guestfs_lvm_int_pv_list %s;\n" n;
974            pr "};\n\n"
975        | RVGList n ->
976            pr "struct %s_ret {\n" name;
977            pr "  guestfs_lvm_int_vg_list %s;\n" n;
978            pr "};\n\n"
979        | RLVList n ->
980            pr "struct %s_ret {\n" name;
981            pr "  guestfs_lvm_int_lv_list %s;\n" n;
982            pr "};\n\n"
983       );
984   ) daemon_functions;
985
986   (* Table of procedure numbers. *)
987   pr "enum guestfs_procedure {\n";
988   List.iter (
989     fun (shortname, _, proc_nr, _, _, _) ->
990       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
991   ) daemon_functions;
992   pr "  GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
993   pr "};\n";
994   pr "\n";
995
996   (* Having to choose a maximum message size is annoying for several
997    * reasons (it limits what we can do in the API), but it (a) makes
998    * the protocol a lot simpler, and (b) provides a bound on the size
999    * of the daemon which operates in limited memory space.  For large
1000    * file transfers you should use FTP.
1001    *)
1002   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
1003   pr "\n";
1004
1005   (* Message header, etc. *)
1006   pr "\
1007 const GUESTFS_PROGRAM = 0x2000F5F5;
1008 const GUESTFS_PROTOCOL_VERSION = 1;
1009
1010 enum guestfs_message_direction {
1011   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
1012   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
1013 };
1014
1015 enum guestfs_message_status {
1016   GUESTFS_STATUS_OK = 0,
1017   GUESTFS_STATUS_ERROR = 1
1018 };
1019
1020 const GUESTFS_ERROR_LEN = 256;
1021
1022 struct guestfs_message_error {
1023   string error<GUESTFS_ERROR_LEN>;   /* error message */
1024 };
1025
1026 struct guestfs_message_header {
1027   unsigned prog;                     /* GUESTFS_PROGRAM */
1028   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
1029   guestfs_procedure proc;            /* GUESTFS_PROC_x */
1030   guestfs_message_direction direction;
1031   unsigned serial;                   /* message serial number */
1032   guestfs_message_status status;
1033 };
1034 "
1035
1036 (* Generate the guestfs-structs.h file. *)
1037 and generate_structs_h () =
1038   generate_header CStyle LGPLv2;
1039
1040   (* This is a public exported header file containing various
1041    * structures.  The structures are carefully written to have
1042    * exactly the same in-memory format as the XDR structures that
1043    * we use on the wire to the daemon.  The reason for creating
1044    * copies of these structures here is just so we don't have to
1045    * export the whole of guestfs_protocol.h (which includes much
1046    * unrelated and XDR-dependent stuff that we don't want to be
1047    * public, or required by clients).
1048    *
1049    * To reiterate, we will pass these structures to and from the
1050    * client with a simple assignment or memcpy, so the format
1051    * must be identical to what rpcgen / the RFC defines.
1052    *)
1053
1054   (* guestfs_int_bool structure. *)
1055   pr "struct guestfs_int_bool {\n";
1056   pr "  int32_t i;\n";
1057   pr "  int32_t b;\n";
1058   pr "};\n";
1059   pr "\n";
1060
1061   (* LVM public structures. *)
1062   List.iter (
1063     function
1064     | typ, cols ->
1065         pr "struct guestfs_lvm_%s {\n" typ;
1066         List.iter (
1067           function
1068           | name, `String -> pr "  char *%s;\n" name
1069           | name, `UUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
1070           | name, `Bytes -> pr "  uint64_t %s;\n" name
1071           | name, `Int -> pr "  int64_t %s;\n" name
1072           | name, `OptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
1073         ) cols;
1074         pr "};\n";
1075         pr "\n";
1076         pr "struct guestfs_lvm_%s_list {\n" typ;
1077         pr "  uint32_t len;\n";
1078         pr "  struct guestfs_lvm_%s *val;\n" typ;
1079         pr "};\n";
1080         pr "\n"
1081   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1082
1083 (* Generate the guestfs-actions.h file. *)
1084 and generate_actions_h () =
1085   generate_header CStyle LGPLv2;
1086   List.iter (
1087     fun (shortname, style, _, _, _, _) ->
1088       let name = "guestfs_" ^ shortname in
1089       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
1090         name style
1091   ) all_functions
1092
1093 (* Generate the client-side dispatch stubs. *)
1094 and generate_client_actions () =
1095   generate_header CStyle LGPLv2;
1096
1097   (* Client-side stubs for each function. *)
1098   List.iter (
1099     fun (shortname, style, _, _, _, _) ->
1100       let name = "guestfs_" ^ shortname in
1101
1102       (* Generate the return value struct. *)
1103       pr "struct %s_rv {\n" shortname;
1104       pr "  int cb_done;  /* flag to indicate callback was called */\n";
1105       pr "  struct guestfs_message_header hdr;\n";
1106       pr "  struct guestfs_message_error err;\n";
1107       (match fst style with
1108        | RErr -> ()
1109        | RConstString _ ->
1110            failwithf "RConstString cannot be returned from a daemon function"
1111        | RInt _
1112        | RBool _ | RString _ | RStringList _
1113        | RIntBool _
1114        | RPVList _ | RVGList _ | RLVList _ ->
1115            pr "  struct %s_ret ret;\n" name
1116       );
1117       pr "};\n\n";
1118
1119       (* Generate the callback function. *)
1120       pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
1121       pr "{\n";
1122       pr "  struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
1123       pr "\n";
1124       pr "  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
1125       pr "    error (g, \"%s: failed to parse reply header\");\n" name;
1126       pr "    return;\n";
1127       pr "  }\n";
1128       pr "  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
1129       pr "    if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
1130       pr "      error (g, \"%s: failed to parse reply error\");\n" name;
1131       pr "      return;\n";
1132       pr "    }\n";
1133       pr "    goto done;\n";
1134       pr "  }\n";
1135
1136       (match fst style with
1137        | RErr -> ()
1138        | RConstString _ ->
1139            failwithf "RConstString cannot be returned from a daemon function"
1140        | RInt _
1141        | RBool _ | RString _ | RStringList _
1142        | RIntBool _
1143        | RPVList _ | RVGList _ | RLVList _ ->
1144             pr "  if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
1145             pr "    error (g, \"%s: failed to parse reply\");\n" name;
1146             pr "    return;\n";
1147             pr "  }\n";
1148       );
1149
1150       pr " done:\n";
1151       pr "  rv->cb_done = 1;\n";
1152       pr "  main_loop.main_loop_quit (g);\n";
1153       pr "}\n\n";
1154
1155       (* Generate the action stub. *)
1156       generate_prototype ~extern:false ~semicolon:false ~newline:true
1157         ~handle:"g" name style;
1158
1159       let error_code =
1160         match fst style with
1161         | RErr | RInt _ | RBool _ -> "-1"
1162         | RConstString _ ->
1163             failwithf "RConstString cannot be returned from a daemon function"
1164         | RString _ | RStringList _ | RIntBool _
1165         | RPVList _ | RVGList _ | RLVList _ ->
1166             "NULL" in
1167
1168       pr "{\n";
1169
1170       (match snd style with
1171        | [] -> ()
1172        | _ -> pr "  struct %s_args args;\n" name
1173       );
1174
1175       pr "  struct %s_rv rv;\n" shortname;
1176       pr "  int serial;\n";
1177       pr "\n";
1178       pr "  if (g->state != READY) {\n";
1179       pr "    error (g, \"%s called from the wrong state, %%d != READY\",\n"
1180         name;
1181       pr "      g->state);\n";
1182       pr "    return %s;\n" error_code;
1183       pr "  }\n";
1184       pr "\n";
1185       pr "  memset (&rv, 0, sizeof rv);\n";
1186       pr "\n";
1187
1188       (match snd style with
1189        | [] ->
1190            pr "  serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
1191              (String.uppercase shortname)
1192        | args ->
1193            List.iter (
1194              function
1195              | String n ->
1196                  pr "  args.%s = (char *) %s;\n" n n
1197              | OptString n ->
1198                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
1199              | Bool n ->
1200                  pr "  args.%s = %s;\n" n n
1201              | Int n ->
1202                  pr "  args.%s = %s;\n" n n
1203            ) args;
1204            pr "  serial = dispatch (g, GUESTFS_PROC_%s,\n"
1205              (String.uppercase shortname);
1206            pr "                     (xdrproc_t) xdr_%s_args, (char *) &args);\n"
1207              name;
1208       );
1209       pr "  if (serial == -1)\n";
1210       pr "    return %s;\n" error_code;
1211       pr "\n";
1212
1213       pr "  rv.cb_done = 0;\n";
1214       pr "  g->reply_cb_internal = %s_cb;\n" shortname;
1215       pr "  g->reply_cb_internal_data = &rv;\n";
1216       pr "  main_loop.main_loop_run (g);\n";
1217       pr "  g->reply_cb_internal = NULL;\n";
1218       pr "  g->reply_cb_internal_data = NULL;\n";
1219       pr "  if (!rv.cb_done) {\n";
1220       pr "    error (g, \"%s failed, see earlier error messages\");\n" name;
1221       pr "    return %s;\n" error_code;
1222       pr "  }\n";
1223       pr "\n";
1224
1225       pr "  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
1226         (String.uppercase shortname);
1227       pr "    return %s;\n" error_code;
1228       pr "\n";
1229
1230       pr "  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
1231       pr "    error (g, \"%%s\", rv.err.error);\n";
1232       pr "    return %s;\n" error_code;
1233       pr "  }\n";
1234       pr "\n";
1235
1236       (match fst style with
1237        | RErr -> pr "  return 0;\n"
1238        | RInt n
1239        | RBool n -> pr "  return rv.ret.%s;\n" n
1240        | RConstString _ ->
1241            failwithf "RConstString cannot be returned from a daemon function"
1242        | RString n ->
1243            pr "  return rv.ret.%s; /* caller will free */\n" n
1244        | RStringList n ->
1245            pr "  /* caller will free this, but we need to add a NULL entry */\n";
1246            pr "  rv.ret.%s.%s_val =" n n;
1247            pr "    safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
1248            pr "                  sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
1249              n n;
1250            pr "  rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
1251            pr "  return rv.ret.%s.%s_val;\n" n n
1252        | RIntBool _ ->
1253            pr "  /* caller with free this */\n";
1254            pr "  return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
1255        | RPVList n ->
1256            pr "  /* caller will free this */\n";
1257            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1258        | RVGList n ->
1259            pr "  /* caller will free this */\n";
1260            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1261        | RLVList n ->
1262            pr "  /* caller will free this */\n";
1263            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1264       );
1265
1266       pr "}\n\n"
1267   ) daemon_functions
1268
1269 (* Generate daemon/actions.h. *)
1270 and generate_daemon_actions_h () =
1271   generate_header CStyle GPLv2;
1272
1273   pr "#include \"../src/guestfs_protocol.h\"\n";
1274   pr "\n";
1275
1276   List.iter (
1277     fun (name, style, _, _, _, _) ->
1278         generate_prototype
1279           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
1280           name style;
1281   ) daemon_functions
1282
1283 (* Generate the server-side stubs. *)
1284 and generate_daemon_actions () =
1285   generate_header CStyle GPLv2;
1286
1287   pr "#define _GNU_SOURCE // for strchrnul\n";
1288   pr "\n";
1289   pr "#include <stdio.h>\n";
1290   pr "#include <stdlib.h>\n";
1291   pr "#include <string.h>\n";
1292   pr "#include <inttypes.h>\n";
1293   pr "#include <ctype.h>\n";
1294   pr "#include <rpc/types.h>\n";
1295   pr "#include <rpc/xdr.h>\n";
1296   pr "\n";
1297   pr "#include \"daemon.h\"\n";
1298   pr "#include \"../src/guestfs_protocol.h\"\n";
1299   pr "#include \"actions.h\"\n";
1300   pr "\n";
1301
1302   List.iter (
1303     fun (name, style, _, _, _, _) ->
1304       (* Generate server-side stubs. *)
1305       pr "static void %s_stub (XDR *xdr_in)\n" name;
1306       pr "{\n";
1307       let error_code =
1308         match fst style with
1309         | RErr | RInt _ -> pr "  int r;\n"; "-1"
1310         | RBool _ -> pr "  int r;\n"; "-1"
1311         | RConstString _ ->
1312             failwithf "RConstString cannot be returned from a daemon function"
1313         | RString _ -> pr "  char *r;\n"; "NULL"
1314         | RStringList _ -> pr "  char **r;\n"; "NULL"
1315         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
1316         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
1317         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
1318         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL" in
1319
1320       (match snd style with
1321        | [] -> ()
1322        | args ->
1323            pr "  struct guestfs_%s_args args;\n" name;
1324            List.iter (
1325              function
1326              | String n
1327              | OptString n -> pr "  const char *%s;\n" n
1328              | Bool n -> pr "  int %s;\n" n
1329              | Int n -> pr "  int %s;\n" n
1330            ) args
1331       );
1332       pr "\n";
1333
1334       (match snd style with
1335        | [] -> ()
1336        | args ->
1337            pr "  memset (&args, 0, sizeof args);\n";
1338            pr "\n";
1339            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
1340            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
1341            pr "    return;\n";
1342            pr "  }\n";
1343            List.iter (
1344              function
1345              | String n -> pr "  %s = args.%s;\n" n n
1346              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
1347              | Bool n -> pr "  %s = args.%s;\n" n n
1348              | Int n -> pr "  %s = args.%s;\n" n n
1349            ) args;
1350            pr "\n"
1351       );
1352
1353       pr "  r = do_%s " name;
1354       generate_call_args style;
1355       pr ";\n";
1356
1357       pr "  if (r == %s)\n" error_code;
1358       pr "    /* do_%s has already called reply_with_error, so just return */\n" name;
1359       pr "    return;\n";
1360       pr "\n";
1361
1362       (match fst style with
1363        | RErr -> pr "  reply (NULL, NULL);\n"
1364        | RInt n ->
1365            pr "  struct guestfs_%s_ret ret;\n" name;
1366            pr "  ret.%s = r;\n" n;
1367            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
1368        | RBool n ->
1369            pr "  struct guestfs_%s_ret ret;\n" name;
1370            pr "  ret.%s = r;\n" n;
1371            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
1372        | RConstString _ ->
1373            failwithf "RConstString cannot be returned from a daemon function"
1374        | RString n ->
1375            pr "  struct guestfs_%s_ret ret;\n" name;
1376            pr "  ret.%s = r;\n" n;
1377            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1378            pr "  free (r);\n"
1379        | RStringList n ->
1380            pr "  struct guestfs_%s_ret ret;\n" name;
1381            pr "  ret.%s.%s_len = count_strings (r);\n" n n;
1382            pr "  ret.%s.%s_val = r;\n" n n;
1383            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1384            pr "  free_strings (r);\n"
1385        | RIntBool _ ->
1386            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
1387            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
1388        | RPVList n ->
1389            pr "  struct guestfs_%s_ret ret;\n" name;
1390            pr "  ret.%s = *r;\n" n;
1391            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1392            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
1393        | RVGList n ->
1394            pr "  struct guestfs_%s_ret ret;\n" name;
1395            pr "  ret.%s = *r;\n" n;
1396            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1397            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
1398        | RLVList n ->
1399            pr "  struct guestfs_%s_ret ret;\n" name;
1400            pr "  ret.%s = *r;\n" n;
1401            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1402            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
1403       );
1404
1405       pr "}\n\n";
1406   ) daemon_functions;
1407
1408   (* Dispatch function. *)
1409   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
1410   pr "{\n";
1411   pr "  switch (proc_nr) {\n";
1412
1413   List.iter (
1414     fun (name, style, _, _, _, _) ->
1415         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
1416         pr "      %s_stub (xdr_in);\n" name;
1417         pr "      break;\n"
1418   ) daemon_functions;
1419
1420   pr "    default:\n";
1421   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
1422   pr "  }\n";
1423   pr "}\n";
1424   pr "\n";
1425
1426   (* LVM columns and tokenization functions. *)
1427   (* XXX This generates crap code.  We should rethink how we
1428    * do this parsing.
1429    *)
1430   List.iter (
1431     function
1432     | typ, cols ->
1433         pr "static const char *lvm_%s_cols = \"%s\";\n"
1434           typ (String.concat "," (List.map fst cols));
1435         pr "\n";
1436
1437         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
1438         pr "{\n";
1439         pr "  char *tok, *p, *next;\n";
1440         pr "  int i, j;\n";
1441         pr "\n";
1442         (*
1443         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
1444         pr "\n";
1445         *)
1446         pr "  if (!str) {\n";
1447         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
1448         pr "    return -1;\n";
1449         pr "  }\n";
1450         pr "  if (!*str || isspace (*str)) {\n";
1451         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
1452         pr "    return -1;\n";
1453         pr "  }\n";
1454         pr "  tok = str;\n";
1455         List.iter (
1456           fun (name, coltype) ->
1457             pr "  if (!tok) {\n";
1458             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
1459             pr "    return -1;\n";
1460             pr "  }\n";
1461             pr "  p = strchrnul (tok, ',');\n";
1462             pr "  if (*p) next = p+1; else next = NULL;\n";
1463             pr "  *p = '\\0';\n";
1464             (match coltype with
1465              | `String ->
1466                  pr "  r->%s = strdup (tok);\n" name;
1467                  pr "  if (r->%s == NULL) {\n" name;
1468                  pr "    perror (\"strdup\");\n";
1469                  pr "    return -1;\n";
1470                  pr "  }\n"
1471              | `UUID ->
1472                  pr "  for (i = j = 0; i < 32; ++j) {\n";
1473                  pr "    if (tok[j] == '\\0') {\n";
1474                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
1475                  pr "      return -1;\n";
1476                  pr "    } else if (tok[j] != '-')\n";
1477                  pr "      r->%s[i++] = tok[j];\n" name;
1478                  pr "  }\n";
1479              | `Bytes ->
1480                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
1481                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
1482                  pr "    return -1;\n";
1483                  pr "  }\n";
1484              | `Int ->
1485                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
1486                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
1487                  pr "    return -1;\n";
1488                  pr "  }\n";
1489              | `OptPercent ->
1490                  pr "  if (tok[0] == '\\0')\n";
1491                  pr "    r->%s = -1;\n" name;
1492                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
1493                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
1494                  pr "    return -1;\n";
1495                  pr "  }\n";
1496             );
1497             pr "  tok = next;\n";
1498         ) cols;
1499
1500         pr "  if (tok != NULL) {\n";
1501         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
1502         pr "    return -1;\n";
1503         pr "  }\n";
1504         pr "  return 0;\n";
1505         pr "}\n";
1506         pr "\n";
1507
1508         pr "guestfs_lvm_int_%s_list *\n" typ;
1509         pr "parse_command_line_%ss (void)\n" typ;
1510         pr "{\n";
1511         pr "  char *out, *err;\n";
1512         pr "  char *p, *pend;\n";
1513         pr "  int r, i;\n";
1514         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
1515         pr "  void *newp;\n";
1516         pr "\n";
1517         pr "  ret = malloc (sizeof *ret);\n";
1518         pr "  if (!ret) {\n";
1519         pr "    reply_with_perror (\"malloc\");\n";
1520         pr "    return NULL;\n";
1521         pr "  }\n";
1522         pr "\n";
1523         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
1524         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
1525         pr "\n";
1526         pr "  r = command (&out, &err,\n";
1527         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
1528         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
1529         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
1530         pr "  if (r == -1) {\n";
1531         pr "    reply_with_error (\"%%s\", err);\n";
1532         pr "    free (out);\n";
1533         pr "    free (err);\n";
1534         pr "    return NULL;\n";
1535         pr "  }\n";
1536         pr "\n";
1537         pr "  free (err);\n";
1538         pr "\n";
1539         pr "  /* Tokenize each line of the output. */\n";
1540         pr "  p = out;\n";
1541         pr "  i = 0;\n";
1542         pr "  while (p) {\n";
1543         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
1544         pr "    if (pend) {\n";
1545         pr "      *pend = '\\0';\n";
1546         pr "      pend++;\n";
1547         pr "    }\n";
1548         pr "\n";
1549         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
1550         pr "      p++;\n";
1551         pr "\n";
1552         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
1553         pr "      p = pend;\n";
1554         pr "      continue;\n";
1555         pr "    }\n";
1556         pr "\n";
1557         pr "    /* Allocate some space to store this next entry. */\n";
1558         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
1559         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
1560         pr "    if (newp == NULL) {\n";
1561         pr "      reply_with_perror (\"realloc\");\n";
1562         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
1563         pr "      free (ret);\n";
1564         pr "      free (out);\n";
1565         pr "      return NULL;\n";
1566         pr "    }\n";
1567         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
1568         pr "\n";
1569         pr "    /* Tokenize the next entry. */\n";
1570         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
1571         pr "    if (r == -1) {\n";
1572         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
1573         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
1574         pr "      free (ret);\n";
1575         pr "      free (out);\n";
1576         pr "      return NULL;\n";
1577         pr "    }\n";
1578         pr "\n";
1579         pr "    ++i;\n";
1580         pr "    p = pend;\n";
1581         pr "  }\n";
1582         pr "\n";
1583         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
1584         pr "\n";
1585         pr "  free (out);\n";
1586         pr "  return ret;\n";
1587         pr "}\n"
1588
1589   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1590
1591 (* Generate a lot of different functions for guestfish. *)
1592 and generate_fish_cmds () =
1593   generate_header CStyle GPLv2;
1594
1595   let all_functions =
1596     List.filter (
1597       fun (_, _, _, flags, _, _) -> not (List.mem NotInFish flags)
1598     ) all_functions in
1599   let all_functions_sorted =
1600     List.filter (
1601       fun (_, _, _, flags, _, _) -> not (List.mem NotInFish flags)
1602     ) all_functions_sorted in
1603
1604   pr "#include <stdio.h>\n";
1605   pr "#include <stdlib.h>\n";
1606   pr "#include <string.h>\n";
1607   pr "#include <inttypes.h>\n";
1608   pr "\n";
1609   pr "#include <guestfs.h>\n";
1610   pr "#include \"fish.h\"\n";
1611   pr "\n";
1612
1613   (* list_commands function, which implements guestfish -h *)
1614   pr "void list_commands (void)\n";
1615   pr "{\n";
1616   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
1617   pr "  list_builtin_commands ();\n";
1618   List.iter (
1619     fun (name, _, _, flags, shortdesc, _) ->
1620       let name = replace_char name '_' '-' in
1621       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
1622         name shortdesc
1623   ) all_functions_sorted;
1624   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
1625   pr "}\n";
1626   pr "\n";
1627
1628   (* display_command function, which implements guestfish -h cmd *)
1629   pr "void display_command (const char *cmd)\n";
1630   pr "{\n";
1631   List.iter (
1632     fun (name, style, _, flags, shortdesc, longdesc) ->
1633       let name2 = replace_char name '_' '-' in
1634       let alias =
1635         try find_map (function FishAlias n -> Some n | _ -> None) flags
1636         with Not_found -> name in
1637       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
1638       let synopsis =
1639         match snd style with
1640         | [] -> name2
1641         | args ->
1642             sprintf "%s <%s>"
1643               name2 (String.concat "> <" (List.map name_of_argt args)) in
1644
1645       let warnings =
1646         if List.mem ProtocolLimitWarning flags then
1647           "\n\nBecause of the message protocol, there is a transfer limit 
1648 of somewhere between 2MB and 4MB.  To transfer large files you should use
1649 FTP."
1650         else "" in
1651
1652       let describe_alias =
1653         if name <> alias then
1654           sprintf "\n\nYou can use '%s' as an alias for this command." alias
1655         else "" in
1656
1657       pr "  if (";
1658       pr "strcasecmp (cmd, \"%s\") == 0" name;
1659       if name <> name2 then
1660         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
1661       if name <> alias then
1662         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
1663       pr ")\n";
1664       pr "    pod2text (\"%s - %s\", %S);\n"
1665         name2 shortdesc
1666         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
1667       pr "  else\n"
1668   ) all_functions;
1669   pr "    display_builtin_command (cmd);\n";
1670   pr "}\n";
1671   pr "\n";
1672
1673   (* print_{pv,vg,lv}_list functions *)
1674   List.iter (
1675     function
1676     | typ, cols ->
1677         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
1678         pr "{\n";
1679         pr "  int i;\n";
1680         pr "\n";
1681         List.iter (
1682           function
1683           | name, `String ->
1684               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
1685           | name, `UUID ->
1686               pr "  printf (\"%s: \");\n" name;
1687               pr "  for (i = 0; i < 32; ++i)\n";
1688               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
1689               pr "  printf (\"\\n\");\n"
1690           | name, `Bytes ->
1691               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
1692           | name, `Int ->
1693               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
1694           | name, `OptPercent ->
1695               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
1696                 typ name name typ name;
1697               pr "  else printf (\"%s: \\n\");\n" name
1698         ) cols;
1699         pr "}\n";
1700         pr "\n";
1701         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
1702           typ typ typ;
1703         pr "{\n";
1704         pr "  int i;\n";
1705         pr "\n";
1706         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
1707         pr "    print_%s (&%ss->val[i]);\n" typ typ;
1708         pr "}\n";
1709         pr "\n";
1710   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1711
1712   (* run_<action> actions *)
1713   List.iter (
1714     fun (name, style, _, flags, _, _) ->
1715       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
1716       pr "{\n";
1717       (match fst style with
1718        | RErr
1719        | RInt _
1720        | RBool _ -> pr "  int r;\n"
1721        | RConstString _ -> pr "  const char *r;\n"
1722        | RString _ -> pr "  char *r;\n"
1723        | RStringList _ -> pr "  char **r;\n"
1724        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
1725        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
1726        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
1727        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
1728       );
1729       List.iter (
1730         function
1731         | String n -> pr "  const char *%s;\n" n
1732         | OptString n -> pr "  const char *%s;\n" n
1733         | Bool n -> pr "  int %s;\n" n
1734         | Int n -> pr "  int %s;\n" n
1735       ) (snd style);
1736
1737       (* Check and convert parameters. *)
1738       let argc_expected = List.length (snd style) in
1739       pr "  if (argc != %d) {\n" argc_expected;
1740       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
1741         argc_expected;
1742       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
1743       pr "    return -1;\n";
1744       pr "  }\n";
1745       iteri (
1746         fun i ->
1747           function
1748           | String name -> pr "  %s = argv[%d];\n" name i
1749           | OptString name ->
1750               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
1751                 name i i
1752           | Bool name ->
1753               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
1754           | Int name ->
1755               pr "  %s = atoi (argv[%d]);\n" name i
1756       ) (snd style);
1757
1758       (* Call C API function. *)
1759       let fn =
1760         try find_map (function FishAction n -> Some n | _ -> None) flags
1761         with Not_found -> sprintf "guestfs_%s" name in
1762       pr "  r = %s " fn;
1763       generate_call_args ~handle:"g" style;
1764       pr ";\n";
1765
1766       (* Check return value for errors and display command results. *)
1767       (match fst style with
1768        | RErr -> pr "  return r;\n"
1769        | RInt _ ->
1770            pr "  if (r == -1) return -1;\n";
1771            pr "  if (r) printf (\"%%d\\n\", r);\n";
1772            pr "  return 0;\n"
1773        | RBool _ ->
1774            pr "  if (r == -1) return -1;\n";
1775            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
1776            pr "  return 0;\n"
1777        | RConstString _ ->
1778            pr "  if (r == NULL) return -1;\n";
1779            pr "  printf (\"%%s\\n\", r);\n";
1780            pr "  return 0;\n"
1781        | RString _ ->
1782            pr "  if (r == NULL) return -1;\n";
1783            pr "  printf (\"%%s\\n\", r);\n";
1784            pr "  free (r);\n";
1785            pr "  return 0;\n"
1786        | RStringList _ ->
1787            pr "  if (r == NULL) return -1;\n";
1788            pr "  print_strings (r);\n";
1789            pr "  free_strings (r);\n";
1790            pr "  return 0;\n"
1791        | RIntBool _ ->
1792            pr "  if (r == NULL) return -1;\n";
1793            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
1794            pr "    r->b ? \"true\" : \"false\");\n";
1795            pr "  guestfs_free_int_bool (r);\n";
1796            pr "  return 0;\n"
1797        | RPVList _ ->
1798            pr "  if (r == NULL) return -1;\n";
1799            pr "  print_pv_list (r);\n";
1800            pr "  guestfs_free_lvm_pv_list (r);\n";
1801            pr "  return 0;\n"
1802        | RVGList _ ->
1803            pr "  if (r == NULL) return -1;\n";
1804            pr "  print_vg_list (r);\n";
1805            pr "  guestfs_free_lvm_vg_list (r);\n";
1806            pr "  return 0;\n"
1807        | RLVList _ ->
1808            pr "  if (r == NULL) return -1;\n";
1809            pr "  print_lv_list (r);\n";
1810            pr "  guestfs_free_lvm_lv_list (r);\n";
1811            pr "  return 0;\n"
1812       );
1813       pr "}\n";
1814       pr "\n"
1815   ) all_functions;
1816
1817   (* run_action function *)
1818   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
1819   pr "{\n";
1820   List.iter (
1821     fun (name, _, _, flags, _, _) ->
1822       let name2 = replace_char name '_' '-' in
1823       let alias =
1824         try find_map (function FishAlias n -> Some n | _ -> None) flags
1825         with Not_found -> name in
1826       pr "  if (";
1827       pr "strcasecmp (cmd, \"%s\") == 0" name;
1828       if name <> name2 then
1829         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
1830       if name <> alias then
1831         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
1832       pr ")\n";
1833       pr "    return run_%s (cmd, argc, argv);\n" name;
1834       pr "  else\n";
1835   ) all_functions;
1836   pr "    {\n";
1837   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
1838   pr "      return -1;\n";
1839   pr "    }\n";
1840   pr "  return 0;\n";
1841   pr "}\n";
1842   pr "\n"
1843
1844 (* Generate the POD documentation for guestfish. *)
1845 and generate_fish_actions_pod () =
1846   let all_functions_sorted =
1847     List.filter (
1848       fun (_, _, _, flags, _, _) -> not (List.mem NotInFish flags)
1849     ) all_functions_sorted in
1850
1851   List.iter (
1852     fun (name, style, _, flags, _, longdesc) ->
1853       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
1854       let name = replace_char name '_' '-' in
1855       let alias =
1856         try find_map (function FishAlias n -> Some n | _ -> None) flags
1857         with Not_found -> name in
1858
1859       pr "=head2 %s" name;
1860       if name <> alias then
1861         pr " | %s" alias;
1862       pr "\n";
1863       pr "\n";
1864       pr " %s" name;
1865       List.iter (
1866         function
1867         | String n -> pr " %s" n
1868         | OptString n -> pr " %s" n
1869         | Bool _ -> pr " true|false"
1870         | Int n -> pr " %s" n
1871       ) (snd style);
1872       pr "\n";
1873       pr "\n";
1874       pr "%s\n\n" longdesc
1875   ) all_functions_sorted
1876
1877 (* Generate a C function prototype. *)
1878 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
1879     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
1880     ?(prefix = "")
1881     ?handle name style =
1882   if extern then pr "extern ";
1883   if static then pr "static ";
1884   (match fst style with
1885    | RErr -> pr "int "
1886    | RInt _ -> pr "int "
1887    | RBool _ -> pr "int "
1888    | RConstString _ -> pr "const char *"
1889    | RString _ -> pr "char *"
1890    | RStringList _ -> pr "char **"
1891    | RIntBool _ ->
1892        if not in_daemon then pr "struct guestfs_int_bool *"
1893        else pr "guestfs_%s_ret *" name
1894    | RPVList _ ->
1895        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
1896        else pr "guestfs_lvm_int_pv_list *"
1897    | RVGList _ ->
1898        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
1899        else pr "guestfs_lvm_int_vg_list *"
1900    | RLVList _ ->
1901        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
1902        else pr "guestfs_lvm_int_lv_list *"
1903   );
1904   pr "%s%s (" prefix name;
1905   if handle = None && List.length (snd style) = 0 then
1906     pr "void"
1907   else (
1908     let comma = ref false in
1909     (match handle with
1910      | None -> ()
1911      | Some handle -> pr "guestfs_h *%s" handle; comma := true
1912     );
1913     let next () =
1914       if !comma then (
1915         if single_line then pr ", " else pr ",\n\t\t"
1916       );
1917       comma := true
1918     in
1919     List.iter (
1920       function
1921       | String n -> next (); pr "const char *%s" n
1922       | OptString n -> next (); pr "const char *%s" n
1923       | Bool n -> next (); pr "int %s" n
1924       | Int n -> next (); pr "int %s" n
1925     ) (snd style);
1926   );
1927   pr ")";
1928   if semicolon then pr ";";
1929   if newline then pr "\n"
1930
1931 (* Generate C call arguments, eg "(handle, foo, bar)" *)
1932 and generate_call_args ?handle style =
1933   pr "(";
1934   let comma = ref false in
1935   (match handle with
1936    | None -> ()
1937    | Some handle -> pr "%s" handle; comma := true
1938   );
1939   List.iter (
1940     fun arg ->
1941       if !comma then pr ", ";
1942       comma := true;
1943       match arg with
1944       | String n -> pr "%s" n
1945       | OptString n -> pr "%s" n
1946       | Bool n -> pr "%s" n
1947       | Int n -> pr "%s" n
1948   ) (snd style);
1949   pr ")"
1950
1951 (* Generate the OCaml bindings interface. *)
1952 and generate_ocaml_mli () =
1953   generate_header OCamlStyle LGPLv2;
1954
1955   pr "\
1956 (** For API documentation you should refer to the C API
1957     in the guestfs(3) manual page.  The OCaml API uses almost
1958     exactly the same calls. *)
1959
1960 type t
1961 (** A [guestfs_h] handle. *)
1962
1963 exception Error of string
1964 (** This exception is raised when there is an error. *)
1965
1966 val create : unit -> t
1967
1968 val close : t -> unit
1969 (** Handles are closed by the garbage collector when they become
1970     unreferenced, but callers can also call this in order to
1971     provide predictable cleanup. *)
1972
1973 ";
1974   generate_ocaml_lvm_structure_decls ();
1975
1976   (* The actions. *)
1977   List.iter (
1978     fun (name, style, _, _, shortdesc, _) ->
1979       generate_ocaml_prototype name style;
1980       pr "(** %s *)\n" shortdesc;
1981       pr "\n"
1982   ) all_functions
1983
1984 (* Generate the OCaml bindings implementation. *)
1985 and generate_ocaml_ml () =
1986   generate_header OCamlStyle LGPLv2;
1987
1988   pr "\
1989 type t
1990 exception Error of string
1991 external create : unit -> t = \"ocaml_guestfs_create\"
1992 external close : t -> unit = \"ocaml_guestfs_close\"
1993
1994 let () =
1995   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
1996
1997 ";
1998
1999   generate_ocaml_lvm_structure_decls ();
2000
2001   (* The actions. *)
2002   List.iter (
2003     fun (name, style, _, _, shortdesc, _) ->
2004       generate_ocaml_prototype ~is_external:true name style;
2005   ) all_functions
2006
2007 (* Generate the OCaml bindings C implementation. *)
2008 and generate_ocaml_c () =
2009   generate_header CStyle LGPLv2;
2010
2011   pr "#include <stdio.h>\n";
2012   pr "#include <stdlib.h>\n";
2013   pr "#include <string.h>\n";
2014   pr "\n";
2015   pr "#include <caml/config.h>\n";
2016   pr "#include <caml/alloc.h>\n";
2017   pr "#include <caml/callback.h>\n";
2018   pr "#include <caml/fail.h>\n";
2019   pr "#include <caml/memory.h>\n";
2020   pr "#include <caml/mlvalues.h>\n";
2021   pr "#include <caml/signals.h>\n";
2022   pr "\n";
2023   pr "#include <guestfs.h>\n";
2024   pr "\n";
2025   pr "#include \"guestfs_c.h\"\n";
2026   pr "\n";
2027
2028   (* LVM struct copy functions. *)
2029   List.iter (
2030     fun (typ, cols) ->
2031       let has_optpercent_col =
2032         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
2033
2034       pr "static CAMLprim value\n";
2035       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
2036       pr "{\n";
2037       pr "  CAMLparam0 ();\n";
2038       if has_optpercent_col then
2039         pr "  CAMLlocal3 (rv, v, v2);\n"
2040       else
2041         pr "  CAMLlocal2 (rv, v);\n";
2042       pr "\n";
2043       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
2044       iteri (
2045         fun i col ->
2046           (match col with
2047            | name, `String ->
2048                pr "  v = caml_copy_string (%s->%s);\n" typ name
2049            | name, `UUID ->
2050                pr "  v = caml_alloc_string (32);\n";
2051                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
2052            | name, `Bytes
2053            | name, `Int ->
2054                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
2055            | name, `OptPercent ->
2056                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
2057                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
2058                pr "    v = caml_alloc (1, 0);\n";
2059                pr "    Store_field (v, 0, v2);\n";
2060                pr "  } else /* None */\n";
2061                pr "    v = Val_int (0);\n";
2062           );
2063           pr "  Store_field (rv, %d, v);\n" i
2064       ) cols;
2065       pr "  CAMLreturn (rv);\n";
2066       pr "}\n";
2067       pr "\n";
2068
2069       pr "static CAMLprim value\n";
2070       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
2071         typ typ typ;
2072       pr "{\n";
2073       pr "  CAMLparam0 ();\n";
2074       pr "  CAMLlocal2 (rv, v);\n";
2075       pr "  int i;\n";
2076       pr "\n";
2077       pr "  if (%ss->len == 0)\n" typ;
2078       pr "    CAMLreturn (Atom (0));\n";
2079       pr "  else {\n";
2080       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
2081       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
2082       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
2083       pr "      caml_modify (&Field (rv, i), v);\n";
2084       pr "    }\n";
2085       pr "    CAMLreturn (rv);\n";
2086       pr "  }\n";
2087       pr "}\n";
2088       pr "\n";
2089   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2090
2091   List.iter (
2092     fun (name, style, _, _, _, _) ->
2093       pr "CAMLprim value\n";
2094       pr "ocaml_guestfs_%s (value gv" name;
2095       List.iter (
2096         fun arg -> pr ", value %sv" (name_of_argt arg)
2097       ) (snd style);
2098       pr ")\n";
2099       pr "{\n";
2100       pr "  CAMLparam%d (gv" (1 + (List.length (snd style)));
2101       List.iter (
2102         fun arg -> pr ", %sv" (name_of_argt arg)
2103       ) (snd style);
2104       pr ");\n";
2105       pr "  CAMLlocal1 (rv);\n";
2106       pr "\n";
2107
2108       pr "  guestfs_h *g = Guestfs_val (gv);\n";
2109       pr "  if (g == NULL)\n";
2110       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
2111       pr "\n";
2112
2113       List.iter (
2114         function
2115         | String n ->
2116             pr "  const char *%s = String_val (%sv);\n" n n
2117         | OptString n ->
2118             pr "  const char *%s =\n" n;
2119             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
2120               n n
2121         | Bool n ->
2122             pr "  int %s = Bool_val (%sv);\n" n n
2123         | Int n ->
2124             pr "  int %s = Int_val (%sv);\n" n n
2125       ) (snd style);
2126       let error_code =
2127         match fst style with
2128         | RErr -> pr "  int r;\n"; "-1"
2129         | RInt _ -> pr "  int r;\n"; "-1"
2130         | RBool _ -> pr "  int r;\n"; "-1"
2131         | RConstString _ -> pr "  const char *r;\n"; "NULL"
2132         | RString _ -> pr "  char *r;\n"; "NULL"
2133         | RStringList _ ->
2134             pr "  int i;\n";
2135             pr "  char **r;\n";
2136             "NULL"
2137         | RIntBool _ ->
2138             pr "  struct guestfs_int_bool *r;\n";
2139             "NULL"
2140         | RPVList _ ->
2141             pr "  struct guestfs_lvm_pv_list *r;\n";
2142             "NULL"
2143         | RVGList _ ->
2144             pr "  struct guestfs_lvm_vg_list *r;\n";
2145             "NULL"
2146         | RLVList _ ->
2147             pr "  struct guestfs_lvm_lv_list *r;\n";
2148             "NULL" in
2149       pr "\n";
2150
2151       pr "  caml_enter_blocking_section ();\n";
2152       pr "  r = guestfs_%s " name;
2153       generate_call_args ~handle:"g" style;
2154       pr ";\n";
2155       pr "  caml_leave_blocking_section ();\n";
2156       pr "  if (r == %s)\n" error_code;
2157       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
2158       pr "\n";
2159
2160       (match fst style with
2161        | RErr -> pr "  rv = Val_unit;\n"
2162        | RInt _ -> pr "  rv = Val_int (r);\n"
2163        | RBool _ -> pr "  rv = Val_bool (r);\n"
2164        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
2165        | RString _ ->
2166            pr "  rv = caml_copy_string (r);\n";
2167            pr "  free (r);\n"
2168        | RStringList _ ->
2169            pr "  rv = caml_copy_string_array ((const char **) r);\n";
2170            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
2171            pr "  free (r);\n"
2172        | RIntBool _ ->
2173            pr "  rv = caml_alloc (2, 0);\n";
2174            pr "  Store_field (rv, 0, Val_int (r->i));\n";
2175            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
2176            pr "  guestfs_free_int_bool (r);\n";
2177        | RPVList _ ->
2178            pr "  rv = copy_lvm_pv_list (r);\n";
2179            pr "  guestfs_free_lvm_pv_list (r);\n";
2180        | RVGList _ ->
2181            pr "  rv = copy_lvm_vg_list (r);\n";
2182            pr "  guestfs_free_lvm_vg_list (r);\n";
2183        | RLVList _ ->
2184            pr "  rv = copy_lvm_lv_list (r);\n";
2185            pr "  guestfs_free_lvm_lv_list (r);\n";
2186       );
2187
2188       pr "  CAMLreturn (rv);\n";
2189       pr "}\n";
2190       pr "\n"
2191   ) all_functions
2192
2193 and generate_ocaml_lvm_structure_decls () =
2194   List.iter (
2195     fun (typ, cols) ->
2196       pr "type lvm_%s = {\n" typ;
2197       List.iter (
2198         function
2199         | name, `String -> pr "  %s : string;\n" name
2200         | name, `UUID -> pr "  %s : string;\n" name
2201         | name, `Bytes -> pr "  %s : int64;\n" name
2202         | name, `Int -> pr "  %s : int64;\n" name
2203         | name, `OptPercent -> pr "  %s : float option;\n" name
2204       ) cols;
2205       pr "}\n";
2206       pr "\n"
2207   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2208
2209 and generate_ocaml_prototype ?(is_external = false) name style =
2210   if is_external then pr "external " else pr "val ";
2211   pr "%s : t -> " name;
2212   List.iter (
2213     function
2214     | String _ -> pr "string -> "
2215     | OptString _ -> pr "string option -> "
2216     | Bool _ -> pr "bool -> "
2217     | Int _ -> pr "int -> "
2218   ) (snd style);
2219   (match fst style with
2220    | RErr -> pr "unit" (* all errors are turned into exceptions *)
2221    | RInt _ -> pr "int"
2222    | RBool _ -> pr "bool"
2223    | RConstString _ -> pr "string"
2224    | RString _ -> pr "string"
2225    | RStringList _ -> pr "string array"
2226    | RIntBool _ -> pr "int * bool"
2227    | RPVList _ -> pr "lvm_pv array"
2228    | RVGList _ -> pr "lvm_vg array"
2229    | RLVList _ -> pr "lvm_lv array"
2230   );
2231   if is_external then pr " = \"ocaml_guestfs_%s\"" name;
2232   pr "\n"
2233
2234 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
2235 and generate_perl_xs () =
2236   generate_header CStyle LGPLv2;
2237
2238   pr "\
2239 #include \"EXTERN.h\"
2240 #include \"perl.h\"
2241 #include \"XSUB.h\"
2242
2243 #include <guestfs.h>
2244
2245 #ifndef PRId64
2246 #define PRId64 \"lld\"
2247 #endif
2248
2249 static SV *
2250 my_newSVll(long long val) {
2251 #ifdef USE_64_BIT_ALL
2252   return newSViv(val);
2253 #else
2254   char buf[100];
2255   int len;
2256   len = snprintf(buf, 100, \"%%\" PRId64, val);
2257   return newSVpv(buf, len);
2258 #endif
2259 }
2260
2261 #ifndef PRIu64
2262 #define PRIu64 \"llu\"
2263 #endif
2264
2265 static SV *
2266 my_newSVull(unsigned long long val) {
2267 #ifdef USE_64_BIT_ALL
2268   return newSVuv(val);
2269 #else
2270   char buf[100];
2271   int len;
2272   len = snprintf(buf, 100, \"%%\" PRIu64, val);
2273   return newSVpv(buf, len);
2274 #endif
2275 }
2276
2277 /* XXX Not thread-safe, and in general not safe if the caller is
2278  * issuing multiple requests in parallel (on different guestfs
2279  * handles).  We should use the guestfs_h handle passed to the
2280  * error handle to distinguish these cases.
2281  */
2282 static char *last_error = NULL;
2283
2284 static void
2285 error_handler (guestfs_h *g,
2286                void *data,
2287                const char *msg)
2288 {
2289   if (last_error != NULL) free (last_error);
2290   last_error = strdup (msg);
2291 }
2292
2293 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
2294
2295 guestfs_h *
2296 _create ()
2297    CODE:
2298       RETVAL = guestfs_create ();
2299       if (!RETVAL)
2300         croak (\"could not create guestfs handle\");
2301       guestfs_set_error_handler (RETVAL, error_handler, NULL);
2302  OUTPUT:
2303       RETVAL
2304
2305 void
2306 DESTROY (g)
2307       guestfs_h *g;
2308  PPCODE:
2309       guestfs_close (g);
2310
2311 ";
2312
2313   List.iter (
2314     fun (name, style, _, _, _, _) ->
2315       (match fst style with
2316        | RErr -> pr "void\n"
2317        | RInt _ -> pr "SV *\n"
2318        | RBool _ -> pr "SV *\n"
2319        | RConstString _ -> pr "SV *\n"
2320        | RString _ -> pr "SV *\n"
2321        | RStringList _
2322        | RIntBool _
2323        | RPVList _ | RVGList _ | RLVList _ ->
2324            pr "void\n" (* all lists returned implictly on the stack *)
2325       );
2326       (* Call and arguments. *)
2327       pr "%s " name;
2328       generate_call_args ~handle:"g" style;
2329       pr "\n";
2330       pr "      guestfs_h *g;\n";
2331       List.iter (
2332         function
2333         | String n -> pr "      char *%s;\n" n
2334         | OptString n -> pr "      char *%s;\n" n
2335         | Bool n -> pr "      int %s;\n" n
2336         | Int n -> pr "      int %s;\n" n
2337       ) (snd style);
2338       (* Code. *)
2339       (match fst style with
2340        | RErr ->
2341            pr " PPCODE:\n";
2342            pr "      if (guestfs_%s " name;
2343            generate_call_args ~handle:"g" style;
2344            pr " == -1)\n";
2345            pr "        croak (\"%s: %%s\", last_error);\n" name
2346        | RInt n
2347        | RBool n ->
2348            pr "PREINIT:\n";
2349            pr "      int %s;\n" n;
2350            pr "   CODE:\n";
2351            pr "      %s = guestfs_%s " n name;
2352            generate_call_args ~handle:"g" style;
2353            pr ";\n";
2354            pr "      if (%s == -1)\n" n;
2355            pr "        croak (\"%s: %%s\", last_error);\n" name;
2356            pr "      RETVAL = newSViv (%s);\n" n;
2357            pr " OUTPUT:\n";
2358            pr "      RETVAL\n"
2359        | RConstString n ->
2360            pr "PREINIT:\n";
2361            pr "      const char *%s;\n" n;
2362            pr "   CODE:\n";
2363            pr "      %s = guestfs_%s " n name;
2364            generate_call_args ~handle:"g" style;
2365            pr ";\n";
2366            pr "      if (%s == NULL)\n" n;
2367            pr "        croak (\"%s: %%s\", last_error);\n" name;
2368            pr "      RETVAL = newSVpv (%s, 0);\n" n;
2369            pr " OUTPUT:\n";
2370            pr "      RETVAL\n"
2371        | RString n ->
2372            pr "PREINIT:\n";
2373            pr "      char *%s;\n" n;
2374            pr "   CODE:\n";
2375            pr "      %s = guestfs_%s " n name;
2376            generate_call_args ~handle:"g" style;
2377            pr ";\n";
2378            pr "      if (%s == NULL)\n" n;
2379            pr "        croak (\"%s: %%s\", last_error);\n" name;
2380            pr "      RETVAL = newSVpv (%s, 0);\n" n;
2381            pr "      free (%s);\n" n;
2382            pr " OUTPUT:\n";
2383            pr "      RETVAL\n"
2384        | RStringList n ->
2385            pr "PREINIT:\n";
2386            pr "      char **%s;\n" n;
2387            pr "      int i, n;\n";
2388            pr " PPCODE:\n";
2389            pr "      %s = guestfs_%s " n name;
2390            generate_call_args ~handle:"g" style;
2391            pr ";\n";
2392            pr "      if (%s == NULL)\n" n;
2393            pr "        croak (\"%s: %%s\", last_error);\n" name;
2394            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
2395            pr "      EXTEND (SP, n);\n";
2396            pr "      for (i = 0; i < n; ++i) {\n";
2397            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
2398            pr "        free (%s[i]);\n" n;
2399            pr "      }\n";
2400            pr "      free (%s);\n" n;
2401        | RIntBool _ ->
2402            pr "PREINIT:\n";
2403            pr "      struct guestfs_int_bool *r;\n";
2404            pr " PPCODE:\n";
2405            pr "      r = guestfs_%s " name;
2406            generate_call_args ~handle:"g" style;
2407            pr ";\n";
2408            pr "      if (r == NULL)\n";
2409            pr "        croak (\"%s: %%s\", last_error);\n" name;
2410            pr "      EXTEND (SP, 2);\n";
2411            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
2412            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
2413            pr "      guestfs_free_int_bool (r);\n";
2414        | RPVList n ->
2415            generate_perl_lvm_code "pv" pv_cols name style n;
2416        | RVGList n ->
2417            generate_perl_lvm_code "vg" vg_cols name style n;
2418        | RLVList n ->
2419            generate_perl_lvm_code "lv" lv_cols name style n;
2420       );
2421       pr "\n"
2422   ) all_functions
2423
2424 and generate_perl_lvm_code typ cols name style n =
2425   pr "PREINIT:\n";
2426   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
2427   pr "      int i;\n";
2428   pr "      HV *hv;\n";
2429   pr " PPCODE:\n";
2430   pr "      %s = guestfs_%s " n name;
2431   generate_call_args ~handle:"g" style;
2432   pr ";\n";
2433   pr "      if (%s == NULL)\n" n;
2434   pr "        croak (\"%s: %%s\", last_error);\n" name;
2435   pr "      EXTEND (SP, %s->len);\n" n;
2436   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
2437   pr "        hv = newHV ();\n";
2438   List.iter (
2439     function
2440     | name, `String ->
2441         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
2442           name (String.length name) n name
2443     | name, `UUID ->
2444         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
2445           name (String.length name) n name
2446     | name, `Bytes ->
2447         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
2448           name (String.length name) n name
2449     | name, `Int ->
2450         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
2451           name (String.length name) n name
2452     | name, `OptPercent ->
2453         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
2454           name (String.length name) n name
2455   ) cols;
2456   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
2457   pr "      }\n";
2458   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
2459
2460 (* Generate Sys/Guestfs.pm. *)
2461 and generate_perl_pm () =
2462   generate_header HashStyle LGPLv2;
2463
2464   pr "\
2465 =pod
2466
2467 =head1 NAME
2468
2469 Sys::Guestfs - Perl bindings for libguestfs
2470
2471 =head1 SYNOPSIS
2472
2473  use Sys::Guestfs;
2474  
2475  my $h = Sys::Guestfs->new ();
2476  $h->add_drive ('guest.img');
2477  $h->launch ();
2478  $h->wait_ready ();
2479  $h->mount ('/dev/sda1', '/');
2480  $h->touch ('/hello');
2481  $h->sync ();
2482
2483 =head1 DESCRIPTION
2484
2485 The C<Sys::Guestfs> module provides a Perl XS binding to the
2486 libguestfs API for examining and modifying virtual machine
2487 disk images.
2488
2489 Amongst the things this is good for: making batch configuration
2490 changes to guests, getting disk used/free statistics (see also:
2491 virt-df), migrating between virtualization systems (see also:
2492 virt-p2v), performing partial backups, performing partial guest
2493 clones, cloning guests and changing registry/UUID/hostname info, and
2494 much else besides.
2495
2496 Libguestfs uses Linux kernel and qemu code, and can access any type of
2497 guest filesystem that Linux and qemu can, including but not limited
2498 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
2499 schemes, qcow, qcow2, vmdk.
2500
2501 Libguestfs provides ways to enumerate guest storage (eg. partitions,
2502 LVs, what filesystem is in each LV, etc.).  It can also run commands
2503 in the context of the guest.  Also you can access filesystems over FTP.
2504
2505 =head1 ERRORS
2506
2507 All errors turn into calls to C<croak> (see L<Carp(3)>).
2508
2509 =head1 METHODS
2510
2511 =over 4
2512
2513 =cut
2514
2515 package Sys::Guestfs;
2516
2517 use strict;
2518 use warnings;
2519
2520 require XSLoader;
2521 XSLoader::load ('Sys::Guestfs');
2522
2523 =item $h = Sys::Guestfs->new ();
2524
2525 Create a new guestfs handle.
2526
2527 =cut
2528
2529 sub new {
2530   my $proto = shift;
2531   my $class = ref ($proto) || $proto;
2532
2533   my $self = Sys::Guestfs::_create ();
2534   bless $self, $class;
2535   return $self;
2536 }
2537
2538 ";
2539
2540   (* Actions.  We only need to print documentation for these as
2541    * they are pulled in from the XS code automatically.
2542    *)
2543   List.iter (
2544     fun (name, style, _, flags, _, longdesc) ->
2545       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
2546       pr "=item ";
2547       generate_perl_prototype name style;
2548       pr "\n\n";
2549       pr "%s\n\n" longdesc;
2550       if List.mem ProtocolLimitWarning flags then
2551         pr "Because of the message protocol, there is a transfer limit 
2552 of somewhere between 2MB and 4MB.  To transfer large files you should use
2553 FTP.\n\n";
2554   ) all_functions_sorted;
2555
2556   (* End of file. *)
2557   pr "\
2558 =cut
2559
2560 1;
2561
2562 =back
2563
2564 =head1 COPYRIGHT
2565
2566 Copyright (C) 2009 Red Hat Inc.
2567
2568 =head1 LICENSE
2569
2570 Please see the file COPYING.LIB for the full license.
2571
2572 =head1 SEE ALSO
2573
2574 L<guestfs(3)>, L<guestfish(1)>.
2575
2576 =cut
2577 "
2578
2579 and generate_perl_prototype name style =
2580   (match fst style with
2581    | RErr -> ()
2582    | RBool n
2583    | RInt n
2584    | RConstString n
2585    | RString n -> pr "$%s = " n
2586    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
2587    | RStringList n
2588    | RPVList n
2589    | RVGList n
2590    | RLVList n -> pr "@%s = " n
2591   );
2592   pr "$h->%s (" name;
2593   let comma = ref false in
2594   List.iter (
2595     fun arg ->
2596       if !comma then pr ", ";
2597       comma := true;
2598       pr "%s" (name_of_argt arg)
2599   ) (snd style);
2600   pr ");"
2601
2602 let output_to filename =
2603   let filename_new = filename ^ ".new" in
2604   chan := open_out filename_new;
2605   let close () =
2606     close_out !chan;
2607     chan := stdout;
2608     Unix.rename filename_new filename;
2609     printf "written %s\n%!" filename;
2610   in
2611   close
2612
2613 (* Main program. *)
2614 let () =
2615   check_functions ();
2616
2617   if not (Sys.file_exists "configure.ac") then (
2618     eprintf "\
2619 You are probably running this from the wrong directory.
2620 Run it from the top source directory using the command
2621   src/generator.ml
2622 ";
2623     exit 1
2624   );
2625
2626   let close = output_to "src/guestfs_protocol.x" in
2627   generate_xdr ();
2628   close ();
2629
2630   let close = output_to "src/guestfs-structs.h" in
2631   generate_structs_h ();
2632   close ();
2633
2634   let close = output_to "src/guestfs-actions.h" in
2635   generate_actions_h ();
2636   close ();
2637
2638   let close = output_to "src/guestfs-actions.c" in
2639   generate_client_actions ();
2640   close ();
2641
2642   let close = output_to "daemon/actions.h" in
2643   generate_daemon_actions_h ();
2644   close ();
2645
2646   let close = output_to "daemon/stubs.c" in
2647   generate_daemon_actions ();
2648   close ();
2649
2650   let close = output_to "fish/cmds.c" in
2651   generate_fish_cmds ();
2652   close ();
2653
2654   let close = output_to "guestfs-structs.pod" in
2655   generate_structs_pod ();
2656   close ();
2657
2658   let close = output_to "guestfs-actions.pod" in
2659   generate_actions_pod ();
2660   close ();
2661
2662   let close = output_to "guestfish-actions.pod" in
2663   generate_fish_actions_pod ();
2664   close ();
2665
2666   let close = output_to "ocaml/guestfs.mli" in
2667   generate_ocaml_mli ();
2668   close ();
2669
2670   let close = output_to "ocaml/guestfs.ml" in
2671   generate_ocaml_ml ();
2672   close ();
2673
2674   let close = output_to "ocaml/guestfs_c_actions.c" in
2675   generate_ocaml_c ();
2676   close ();
2677
2678   let close = output_to "perl/Guestfs.xs" in
2679   generate_perl_xs ();
2680   close ();
2681
2682   let close = output_to "perl/lib/Sys/Guestfs.pm" in
2683   generate_perl_pm ();
2684   close ();