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