Add more function checking.
[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 (* 'pr' prints to the current output file. *)
621 let chan = ref stdout
622 let pr fs = ksprintf (output_string !chan) fs
623
624 let name_of_argt = function String n | OptString n | Bool n | Int n -> n
625
626 (* Check function names etc. for consistency. *)
627 let check_functions () =
628   let contains_uppercase str =
629     let len = String.length str in
630     let rec loop i =
631       if i >= len then false
632       else (
633         let c = str.[i] in
634         if c >= 'A' && c <= 'Z' then true
635         else loop (i+1)
636       )
637     in
638     loop 0
639   in
640
641   (* Check function names. *)
642   List.iter (
643     fun (name, _, _, _, _, _) ->
644       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
645         failwithf "function name %s does not need 'guestfs' prefix" name;
646       if contains_uppercase name then
647         failwithf "function name %s should not contain uppercase chars" name;
648       if String.contains name '-' then
649         failwithf "function name %s should not contain '-', use '_' instead."
650           name
651   ) all_functions;
652
653   (* Check function parameter/return names. *)
654   List.iter (
655     fun (name, style, _, _, _, _) ->
656       let check_arg_ret_name n =
657         if contains_uppercase n then
658           failwithf "%s param/ret %s should not contain uppercase chars"
659             name n;
660         if String.contains n '-' || String.contains n '_' then
661           failwithf "%s param/ret %s should not contain '-' or '_'"
662             name n;
663         if n = "value" then
664           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
665       in
666
667       (match fst style with
668        | Err -> ()
669        | RInt n | RBool n | RConstString n | RString n
670        | RStringList n | RPVList n | RVGList n | RLVList n ->
671            check_arg_ret_name n
672        | RIntBool (n,m) ->
673            check_arg_ret_name n;
674            check_arg_ret_name m
675       );
676       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
677   ) all_functions;
678
679   (* Check long dscriptions. *)
680   List.iter (
681     fun (name, _, _, _, _, longdesc) ->
682       if longdesc.[String.length longdesc-1] = '\n' then
683         failwithf "long description of %s should not end with \\n." name
684   ) all_functions;
685
686   (* Check proc_nrs. *)
687   List.iter (
688     fun (name, _, proc_nr, _, _, _) ->
689       if proc_nr <= 0 then
690         failwithf "daemon function %s should have proc_nr > 0" name
691   ) daemon_functions;
692
693   List.iter (
694     fun (name, _, proc_nr, _, _, _) ->
695       if proc_nr <> -1 then
696         failwithf "non-daemon function %s should have proc_nr -1" name
697   ) non_daemon_functions;
698
699   let proc_nrs =
700     List.map (fun (name, _, proc_nr, _, _, _) -> name, proc_nr)
701       daemon_functions in
702   let proc_nrs =
703     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
704   let rec loop = function
705     | [] -> ()
706     | [_] -> ()
707     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
708         loop rest
709     | (name1,nr1) :: (name2,nr2) :: _ ->
710         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
711           name1 name2 nr1 nr2
712   in
713   loop proc_nrs
714
715 type comment_style = CStyle | HashStyle | OCamlStyle
716 type license = GPLv2 | LGPLv2
717
718 (* Generate a header block in a number of standard styles. *)
719 let rec 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 (* Generate the pod documentation for the C API. *)
769 and generate_actions_pod () =
770   List.iter (
771     fun (shortname, style, _, flags, _, longdesc) ->
772       let name = "guestfs_" ^ shortname in
773       pr "=head2 %s\n\n" name;
774       pr " ";
775       generate_prototype ~extern:false ~handle:"handle" name style;
776       pr "\n\n";
777       pr "%s\n\n" longdesc;
778       (match fst style with
779        | Err ->
780            pr "This function returns 0 on success or -1 on error.\n\n"
781        | RInt _ ->
782            pr "On error this function returns -1.\n\n"
783        | RBool _ ->
784            pr "This function returns a C truth value on success or -1 on error.\n\n"
785        | RConstString _ ->
786            pr "This function returns a string or NULL on error.
787 The string is owned by the guest handle and must I<not> be freed.\n\n"
788        | RString _ ->
789            pr "This function returns a string or NULL on error.
790 I<The caller must free the returned string after use>.\n\n"
791        | RStringList _ ->
792            pr "This function returns a NULL-terminated array of strings
793 (like L<environ(3)>), or NULL if there was an error.
794 I<The caller must free the strings and the array after use>.\n\n"
795        | RIntBool _ ->
796            pr "This function returns a C<struct guestfs_int_bool *>.
797 I<The caller must call C<guestfs_free_int_bool> after use.>.\n\n"
798        | RPVList _ ->
799            pr "This function returns a C<struct guestfs_lvm_pv_list *>.
800 I<The caller must call C<guestfs_free_lvm_pv_list> after use.>.\n\n"
801        | RVGList _ ->
802            pr "This function returns a C<struct guestfs_lvm_vg_list *>.
803 I<The caller must call C<guestfs_free_lvm_vg_list> after use.>.\n\n"
804        | RLVList _ ->
805            pr "This function returns a C<struct guestfs_lvm_lv_list *>.
806 I<The caller must call C<guestfs_free_lvm_lv_list> after use.>.\n\n"
807       );
808       if List.mem ProtocolLimitWarning flags then
809         pr "Because of the message protocol, there is a transfer limit 
810 of somewhere between 2MB and 4MB.  To transfer large files you should use
811 FTP.\n\n";
812   ) all_functions_sorted
813
814 and generate_structs_pod () =
815   (* LVM structs documentation. *)
816   List.iter (
817     fun (typ, cols) ->
818       pr "=head2 guestfs_lvm_%s\n" typ;
819       pr "\n";
820       pr " struct guestfs_lvm_%s {\n" typ;
821       List.iter (
822         function
823         | name, `String -> pr "  char *%s;\n" name
824         | name, `UUID ->
825             pr "  /* The next field is NOT nul-terminated, be careful when printing it: */\n";
826             pr "  char %s[32];\n" name
827         | name, `Bytes -> pr "  uint64_t %s;\n" name
828         | name, `Int -> pr "  int64_t %s;\n" name
829         | name, `OptPercent ->
830             pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
831             pr "  float %s;\n" name
832       ) cols;
833       pr " \n";
834       pr " struct guestfs_lvm_%s_list {\n" typ;
835       pr "   uint32_t len; /* Number of elements in list. */\n";
836       pr "   struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
837       pr " };\n";
838       pr " \n";
839       pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
840         typ typ;
841       pr "\n"
842   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
843
844 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
845  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.  We
846  * have to use an underscore instead of a dash because otherwise
847  * rpcgen generates incorrect code.
848  *
849  * This header is NOT exported to clients, but see also generate_structs_h.
850  *)
851 and generate_xdr () =
852   generate_header CStyle LGPLv2;
853
854   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
855   pr "typedef string str<>;\n";
856   pr "\n";
857
858   (* LVM internal structures. *)
859   List.iter (
860     function
861     | typ, cols ->
862         pr "struct guestfs_lvm_int_%s {\n" typ;
863         List.iter (function
864                    | name, `String -> pr "  string %s<>;\n" name
865                    | name, `UUID -> pr "  opaque %s[32];\n" name
866                    | name, `Bytes -> pr "  hyper %s;\n" name
867                    | name, `Int -> pr "  hyper %s;\n" name
868                    | name, `OptPercent -> pr "  float %s;\n" name
869                   ) cols;
870         pr "};\n";
871         pr "\n";
872         pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
873         pr "\n";
874   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
875
876   List.iter (
877     fun(shortname, style, _, _, _, _) ->
878       let name = "guestfs_" ^ shortname in
879
880       (match snd style with
881        | [] -> ()
882        | args ->
883            pr "struct %s_args {\n" name;
884            List.iter (
885              function
886              | String n -> pr "  string %s<>;\n" n
887              | OptString n -> pr "  str *%s;\n" n
888              | Bool n -> pr "  bool %s;\n" n
889              | Int n -> pr "  int %s;\n" n
890            ) args;
891            pr "};\n\n"
892       );
893       (match fst style with
894        | Err -> ()
895        | RInt n ->
896            pr "struct %s_ret {\n" name;
897            pr "  int %s;\n" n;
898            pr "};\n\n"
899        | RBool n ->
900            pr "struct %s_ret {\n" name;
901            pr "  bool %s;\n" n;
902            pr "};\n\n"
903        | RConstString _ ->
904            failwithf "RConstString cannot be returned from a daemon function"
905        | RString n ->
906            pr "struct %s_ret {\n" name;
907            pr "  string %s<>;\n" n;
908            pr "};\n\n"
909        | RStringList n ->
910            pr "struct %s_ret {\n" name;
911            pr "  str %s<>;\n" n;
912            pr "};\n\n"
913        | RIntBool (n,m) ->
914            pr "struct %s_ret {\n" name;
915            pr "  int %s;\n" n;
916            pr "  bool %s;\n" m;
917            pr "};\n\n"
918        | RPVList n ->
919            pr "struct %s_ret {\n" name;
920            pr "  guestfs_lvm_int_pv_list %s;\n" n;
921            pr "};\n\n"
922        | RVGList n ->
923            pr "struct %s_ret {\n" name;
924            pr "  guestfs_lvm_int_vg_list %s;\n" n;
925            pr "};\n\n"
926        | RLVList n ->
927            pr "struct %s_ret {\n" name;
928            pr "  guestfs_lvm_int_lv_list %s;\n" n;
929            pr "};\n\n"
930       );
931   ) daemon_functions;
932
933   (* Table of procedure numbers. *)
934   pr "enum guestfs_procedure {\n";
935   List.iter (
936     fun (shortname, _, proc_nr, _, _, _) ->
937       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
938   ) daemon_functions;
939   pr "  GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
940   pr "};\n";
941   pr "\n";
942
943   (* Having to choose a maximum message size is annoying for several
944    * reasons (it limits what we can do in the API), but it (a) makes
945    * the protocol a lot simpler, and (b) provides a bound on the size
946    * of the daemon which operates in limited memory space.  For large
947    * file transfers you should use FTP.
948    *)
949   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
950   pr "\n";
951
952   (* Message header, etc. *)
953   pr "\
954 const GUESTFS_PROGRAM = 0x2000F5F5;
955 const GUESTFS_PROTOCOL_VERSION = 1;
956
957 enum guestfs_message_direction {
958   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
959   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
960 };
961
962 enum guestfs_message_status {
963   GUESTFS_STATUS_OK = 0,
964   GUESTFS_STATUS_ERROR = 1
965 };
966
967 const GUESTFS_ERROR_LEN = 256;
968
969 struct guestfs_message_error {
970   string error<GUESTFS_ERROR_LEN>;   /* error message */
971 };
972
973 struct guestfs_message_header {
974   unsigned prog;                     /* GUESTFS_PROGRAM */
975   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
976   guestfs_procedure proc;            /* GUESTFS_PROC_x */
977   guestfs_message_direction direction;
978   unsigned serial;                   /* message serial number */
979   guestfs_message_status status;
980 };
981 "
982
983 (* Generate the guestfs-structs.h file. *)
984 and generate_structs_h () =
985   generate_header CStyle LGPLv2;
986
987   (* This is a public exported header file containing various
988    * structures.  The structures are carefully written to have
989    * exactly the same in-memory format as the XDR structures that
990    * we use on the wire to the daemon.  The reason for creating
991    * copies of these structures here is just so we don't have to
992    * export the whole of guestfs_protocol.h (which includes much
993    * unrelated and XDR-dependent stuff that we don't want to be
994    * public, or required by clients).
995    *
996    * To reiterate, we will pass these structures to and from the
997    * client with a simple assignment or memcpy, so the format
998    * must be identical to what rpcgen / the RFC defines.
999    *)
1000
1001   (* guestfs_int_bool structure. *)
1002   pr "struct guestfs_int_bool {\n";
1003   pr "  int32_t i;\n";
1004   pr "  int32_t b;\n";
1005   pr "};\n";
1006   pr "\n";
1007
1008   (* LVM public structures. *)
1009   List.iter (
1010     function
1011     | typ, cols ->
1012         pr "struct guestfs_lvm_%s {\n" typ;
1013         List.iter (
1014           function
1015           | name, `String -> pr "  char *%s;\n" name
1016           | name, `UUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
1017           | name, `Bytes -> pr "  uint64_t %s;\n" name
1018           | name, `Int -> pr "  int64_t %s;\n" name
1019           | name, `OptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
1020         ) cols;
1021         pr "};\n";
1022         pr "\n";
1023         pr "struct guestfs_lvm_%s_list {\n" typ;
1024         pr "  uint32_t len;\n";
1025         pr "  struct guestfs_lvm_%s *val;\n" typ;
1026         pr "};\n";
1027         pr "\n"
1028   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1029
1030 (* Generate the guestfs-actions.h file. *)
1031 and generate_actions_h () =
1032   generate_header CStyle LGPLv2;
1033   List.iter (
1034     fun (shortname, style, _, _, _, _) ->
1035       let name = "guestfs_" ^ shortname in
1036       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
1037         name style
1038   ) all_functions
1039
1040 (* Generate the client-side dispatch stubs. *)
1041 and generate_client_actions () =
1042   generate_header CStyle LGPLv2;
1043
1044   (* Client-side stubs for each function. *)
1045   List.iter (
1046     fun (shortname, style, _, _, _, _) ->
1047       let name = "guestfs_" ^ shortname in
1048
1049       (* Generate the return value struct. *)
1050       pr "struct %s_rv {\n" shortname;
1051       pr "  int cb_done;  /* flag to indicate callback was called */\n";
1052       pr "  struct guestfs_message_header hdr;\n";
1053       pr "  struct guestfs_message_error err;\n";
1054       (match fst style with
1055        | Err -> ()
1056        | RConstString _ ->
1057            failwithf "RConstString cannot be returned from a daemon function"
1058        | RInt _
1059        | RBool _ | RString _ | RStringList _
1060        | RIntBool _
1061        | RPVList _ | RVGList _ | RLVList _ ->
1062            pr "  struct %s_ret ret;\n" name
1063       );
1064       pr "};\n\n";
1065
1066       (* Generate the callback function. *)
1067       pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
1068       pr "{\n";
1069       pr "  struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
1070       pr "\n";
1071       pr "  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
1072       pr "    error (g, \"%s: failed to parse reply header\");\n" name;
1073       pr "    return;\n";
1074       pr "  }\n";
1075       pr "  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
1076       pr "    if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
1077       pr "      error (g, \"%s: failed to parse reply error\");\n" name;
1078       pr "      return;\n";
1079       pr "    }\n";
1080       pr "    goto done;\n";
1081       pr "  }\n";
1082
1083       (match fst style with
1084        | Err -> ()
1085        | RConstString _ ->
1086            failwithf "RConstString cannot be returned from a daemon function"
1087        | RInt _
1088        | RBool _ | RString _ | RStringList _
1089        | RIntBool _
1090        | RPVList _ | RVGList _ | RLVList _ ->
1091             pr "  if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
1092             pr "    error (g, \"%s: failed to parse reply\");\n" name;
1093             pr "    return;\n";
1094             pr "  }\n";
1095       );
1096
1097       pr " done:\n";
1098       pr "  rv->cb_done = 1;\n";
1099       pr "  main_loop.main_loop_quit (g);\n";
1100       pr "}\n\n";
1101
1102       (* Generate the action stub. *)
1103       generate_prototype ~extern:false ~semicolon:false ~newline:true
1104         ~handle:"g" name style;
1105
1106       let error_code =
1107         match fst style with
1108         | Err | RInt _ | RBool _ -> "-1"
1109         | RConstString _ ->
1110             failwithf "RConstString cannot be returned from a daemon function"
1111         | RString _ | RStringList _ | RIntBool _
1112         | RPVList _ | RVGList _ | RLVList _ ->
1113             "NULL" in
1114
1115       pr "{\n";
1116
1117       (match snd style with
1118        | [] -> ()
1119        | _ -> pr "  struct %s_args args;\n" name
1120       );
1121
1122       pr "  struct %s_rv rv;\n" shortname;
1123       pr "  int serial;\n";
1124       pr "\n";
1125       pr "  if (g->state != READY) {\n";
1126       pr "    error (g, \"%s called from the wrong state, %%d != READY\",\n"
1127         name;
1128       pr "      g->state);\n";
1129       pr "    return %s;\n" error_code;
1130       pr "  }\n";
1131       pr "\n";
1132       pr "  memset (&rv, 0, sizeof rv);\n";
1133       pr "\n";
1134
1135       (match snd style with
1136        | [] ->
1137            pr "  serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
1138              (String.uppercase shortname)
1139        | args ->
1140            List.iter (
1141              function
1142              | String n ->
1143                  pr "  args.%s = (char *) %s;\n" n n
1144              | OptString n ->
1145                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
1146              | Bool n ->
1147                  pr "  args.%s = %s;\n" n n
1148              | Int n ->
1149                  pr "  args.%s = %s;\n" n n
1150            ) args;
1151            pr "  serial = dispatch (g, GUESTFS_PROC_%s,\n"
1152              (String.uppercase shortname);
1153            pr "                     (xdrproc_t) xdr_%s_args, (char *) &args);\n"
1154              name;
1155       );
1156       pr "  if (serial == -1)\n";
1157       pr "    return %s;\n" error_code;
1158       pr "\n";
1159
1160       pr "  rv.cb_done = 0;\n";
1161       pr "  g->reply_cb_internal = %s_cb;\n" shortname;
1162       pr "  g->reply_cb_internal_data = &rv;\n";
1163       pr "  main_loop.main_loop_run (g);\n";
1164       pr "  g->reply_cb_internal = NULL;\n";
1165       pr "  g->reply_cb_internal_data = NULL;\n";
1166       pr "  if (!rv.cb_done) {\n";
1167       pr "    error (g, \"%s failed, see earlier error messages\");\n" name;
1168       pr "    return %s;\n" error_code;
1169       pr "  }\n";
1170       pr "\n";
1171
1172       pr "  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
1173         (String.uppercase shortname);
1174       pr "    return %s;\n" error_code;
1175       pr "\n";
1176
1177       pr "  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
1178       pr "    error (g, \"%%s\", rv.err.error);\n";
1179       pr "    return %s;\n" error_code;
1180       pr "  }\n";
1181       pr "\n";
1182
1183       (match fst style with
1184        | Err -> pr "  return 0;\n"
1185        | RInt n
1186        | RBool n -> pr "  return rv.ret.%s;\n" n
1187        | RConstString _ ->
1188            failwithf "RConstString cannot be returned from a daemon function"
1189        | RString n ->
1190            pr "  return rv.ret.%s; /* caller will free */\n" n
1191        | RStringList n ->
1192            pr "  /* caller will free this, but we need to add a NULL entry */\n";
1193            pr "  rv.ret.%s.%s_val =" n n;
1194            pr "    safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
1195            pr "                  sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
1196              n n;
1197            pr "  rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
1198            pr "  return rv.ret.%s.%s_val;\n" n n
1199        | RIntBool _ ->
1200            pr "  /* caller with free this */\n";
1201            pr "  return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
1202        | RPVList n ->
1203            pr "  /* caller will free this */\n";
1204            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1205        | RVGList 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        | RLVList 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       );
1212
1213       pr "}\n\n"
1214   ) daemon_functions
1215
1216 (* Generate daemon/actions.h. *)
1217 and generate_daemon_actions_h () =
1218   generate_header CStyle GPLv2;
1219
1220   pr "#include \"../src/guestfs_protocol.h\"\n";
1221   pr "\n";
1222
1223   List.iter (
1224     fun (name, style, _, _, _, _) ->
1225         generate_prototype
1226           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
1227           name style;
1228   ) daemon_functions
1229
1230 (* Generate the server-side stubs. *)
1231 and generate_daemon_actions () =
1232   generate_header CStyle GPLv2;
1233
1234   pr "#define _GNU_SOURCE // for strchrnul\n";
1235   pr "\n";
1236   pr "#include <stdio.h>\n";
1237   pr "#include <stdlib.h>\n";
1238   pr "#include <string.h>\n";
1239   pr "#include <inttypes.h>\n";
1240   pr "#include <ctype.h>\n";
1241   pr "#include <rpc/types.h>\n";
1242   pr "#include <rpc/xdr.h>\n";
1243   pr "\n";
1244   pr "#include \"daemon.h\"\n";
1245   pr "#include \"../src/guestfs_protocol.h\"\n";
1246   pr "#include \"actions.h\"\n";
1247   pr "\n";
1248
1249   List.iter (
1250     fun (name, style, _, _, _, _) ->
1251       (* Generate server-side stubs. *)
1252       pr "static void %s_stub (XDR *xdr_in)\n" name;
1253       pr "{\n";
1254       let error_code =
1255         match fst style with
1256         | Err | RInt _ -> pr "  int r;\n"; "-1"
1257         | RBool _ -> pr "  int r;\n"; "-1"
1258         | RConstString _ ->
1259             failwithf "RConstString cannot be returned from a daemon function"
1260         | RString _ -> pr "  char *r;\n"; "NULL"
1261         | RStringList _ -> pr "  char **r;\n"; "NULL"
1262         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
1263         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
1264         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
1265         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL" in
1266
1267       (match snd style with
1268        | [] -> ()
1269        | args ->
1270            pr "  struct guestfs_%s_args args;\n" name;
1271            List.iter (
1272              function
1273              | String n
1274              | OptString n -> pr "  const char *%s;\n" n
1275              | Bool n -> pr "  int %s;\n" n
1276              | Int n -> pr "  int %s;\n" n
1277            ) args
1278       );
1279       pr "\n";
1280
1281       (match snd style with
1282        | [] -> ()
1283        | args ->
1284            pr "  memset (&args, 0, sizeof args);\n";
1285            pr "\n";
1286            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
1287            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
1288            pr "    return;\n";
1289            pr "  }\n";
1290            List.iter (
1291              function
1292              | String n -> pr "  %s = args.%s;\n" n n
1293              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
1294              | Bool n -> pr "  %s = args.%s;\n" n n
1295              | Int n -> pr "  %s = args.%s;\n" n n
1296            ) args;
1297            pr "\n"
1298       );
1299
1300       pr "  r = do_%s " name;
1301       generate_call_args style;
1302       pr ";\n";
1303
1304       pr "  if (r == %s)\n" error_code;
1305       pr "    /* do_%s has already called reply_with_error, so just return */\n" name;
1306       pr "    return;\n";
1307       pr "\n";
1308
1309       (match fst style with
1310        | Err -> pr "  reply (NULL, NULL);\n"
1311        | RInt n ->
1312            pr "  struct guestfs_%s_ret ret;\n" name;
1313            pr "  ret.%s = r;\n" n;
1314            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
1315        | RBool n ->
1316            pr "  struct guestfs_%s_ret ret;\n" name;
1317            pr "  ret.%s = r;\n" n;
1318            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
1319        | RConstString _ ->
1320            failwithf "RConstString cannot be returned from a daemon function"
1321        | RString n ->
1322            pr "  struct guestfs_%s_ret ret;\n" name;
1323            pr "  ret.%s = r;\n" n;
1324            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1325            pr "  free (r);\n"
1326        | RStringList n ->
1327            pr "  struct guestfs_%s_ret ret;\n" name;
1328            pr "  ret.%s.%s_len = count_strings (r);\n" n n;
1329            pr "  ret.%s.%s_val = r;\n" n n;
1330            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1331            pr "  free_strings (r);\n"
1332        | RIntBool _ ->
1333            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
1334            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
1335        | RPVList n ->
1336            pr "  struct guestfs_%s_ret ret;\n" name;
1337            pr "  ret.%s = *r;\n" n;
1338            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1339            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
1340        | RVGList n ->
1341            pr "  struct guestfs_%s_ret ret;\n" name;
1342            pr "  ret.%s = *r;\n" n;
1343            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1344            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
1345        | RLVList n ->
1346            pr "  struct guestfs_%s_ret ret;\n" name;
1347            pr "  ret.%s = *r;\n" n;
1348            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
1349            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
1350       );
1351
1352       pr "}\n\n";
1353   ) daemon_functions;
1354
1355   (* Dispatch function. *)
1356   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
1357   pr "{\n";
1358   pr "  switch (proc_nr) {\n";
1359
1360   List.iter (
1361     fun (name, style, _, _, _, _) ->
1362         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
1363         pr "      %s_stub (xdr_in);\n" name;
1364         pr "      break;\n"
1365   ) daemon_functions;
1366
1367   pr "    default:\n";
1368   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
1369   pr "  }\n";
1370   pr "}\n";
1371   pr "\n";
1372
1373   (* LVM columns and tokenization functions. *)
1374   (* XXX This generates crap code.  We should rethink how we
1375    * do this parsing.
1376    *)
1377   List.iter (
1378     function
1379     | typ, cols ->
1380         pr "static const char *lvm_%s_cols = \"%s\";\n"
1381           typ (String.concat "," (List.map fst cols));
1382         pr "\n";
1383
1384         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
1385         pr "{\n";
1386         pr "  char *tok, *p, *next;\n";
1387         pr "  int i, j;\n";
1388         pr "\n";
1389         (*
1390         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
1391         pr "\n";
1392         *)
1393         pr "  if (!str) {\n";
1394         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
1395         pr "    return -1;\n";
1396         pr "  }\n";
1397         pr "  if (!*str || isspace (*str)) {\n";
1398         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
1399         pr "    return -1;\n";
1400         pr "  }\n";
1401         pr "  tok = str;\n";
1402         List.iter (
1403           fun (name, coltype) ->
1404             pr "  if (!tok) {\n";
1405             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
1406             pr "    return -1;\n";
1407             pr "  }\n";
1408             pr "  p = strchrnul (tok, ',');\n";
1409             pr "  if (*p) next = p+1; else next = NULL;\n";
1410             pr "  *p = '\\0';\n";
1411             (match coltype with
1412              | `String ->
1413                  pr "  r->%s = strdup (tok);\n" name;
1414                  pr "  if (r->%s == NULL) {\n" name;
1415                  pr "    perror (\"strdup\");\n";
1416                  pr "    return -1;\n";
1417                  pr "  }\n"
1418              | `UUID ->
1419                  pr "  for (i = j = 0; i < 32; ++j) {\n";
1420                  pr "    if (tok[j] == '\\0') {\n";
1421                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
1422                  pr "      return -1;\n";
1423                  pr "    } else if (tok[j] != '-')\n";
1424                  pr "      r->%s[i++] = tok[j];\n" name;
1425                  pr "  }\n";
1426              | `Bytes ->
1427                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
1428                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
1429                  pr "    return -1;\n";
1430                  pr "  }\n";
1431              | `Int ->
1432                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
1433                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
1434                  pr "    return -1;\n";
1435                  pr "  }\n";
1436              | `OptPercent ->
1437                  pr "  if (tok[0] == '\\0')\n";
1438                  pr "    r->%s = -1;\n" name;
1439                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
1440                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
1441                  pr "    return -1;\n";
1442                  pr "  }\n";
1443             );
1444             pr "  tok = next;\n";
1445         ) cols;
1446
1447         pr "  if (tok != NULL) {\n";
1448         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
1449         pr "    return -1;\n";
1450         pr "  }\n";
1451         pr "  return 0;\n";
1452         pr "}\n";
1453         pr "\n";
1454
1455         pr "guestfs_lvm_int_%s_list *\n" typ;
1456         pr "parse_command_line_%ss (void)\n" typ;
1457         pr "{\n";
1458         pr "  char *out, *err;\n";
1459         pr "  char *p, *pend;\n";
1460         pr "  int r, i;\n";
1461         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
1462         pr "  void *newp;\n";
1463         pr "\n";
1464         pr "  ret = malloc (sizeof *ret);\n";
1465         pr "  if (!ret) {\n";
1466         pr "    reply_with_perror (\"malloc\");\n";
1467         pr "    return NULL;\n";
1468         pr "  }\n";
1469         pr "\n";
1470         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
1471         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
1472         pr "\n";
1473         pr "  r = command (&out, &err,\n";
1474         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
1475         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
1476         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
1477         pr "  if (r == -1) {\n";
1478         pr "    reply_with_error (\"%%s\", err);\n";
1479         pr "    free (out);\n";
1480         pr "    free (err);\n";
1481         pr "    return NULL;\n";
1482         pr "  }\n";
1483         pr "\n";
1484         pr "  free (err);\n";
1485         pr "\n";
1486         pr "  /* Tokenize each line of the output. */\n";
1487         pr "  p = out;\n";
1488         pr "  i = 0;\n";
1489         pr "  while (p) {\n";
1490         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
1491         pr "    if (pend) {\n";
1492         pr "      *pend = '\\0';\n";
1493         pr "      pend++;\n";
1494         pr "    }\n";
1495         pr "\n";
1496         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
1497         pr "      p++;\n";
1498         pr "\n";
1499         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
1500         pr "      p = pend;\n";
1501         pr "      continue;\n";
1502         pr "    }\n";
1503         pr "\n";
1504         pr "    /* Allocate some space to store this next entry. */\n";
1505         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
1506         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
1507         pr "    if (newp == NULL) {\n";
1508         pr "      reply_with_perror (\"realloc\");\n";
1509         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
1510         pr "      free (ret);\n";
1511         pr "      free (out);\n";
1512         pr "      return NULL;\n";
1513         pr "    }\n";
1514         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
1515         pr "\n";
1516         pr "    /* Tokenize the next entry. */\n";
1517         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
1518         pr "    if (r == -1) {\n";
1519         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
1520         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
1521         pr "      free (ret);\n";
1522         pr "      free (out);\n";
1523         pr "      return NULL;\n";
1524         pr "    }\n";
1525         pr "\n";
1526         pr "    ++i;\n";
1527         pr "    p = pend;\n";
1528         pr "  }\n";
1529         pr "\n";
1530         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
1531         pr "\n";
1532         pr "  free (out);\n";
1533         pr "  return ret;\n";
1534         pr "}\n"
1535
1536   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1537
1538 (* Generate a lot of different functions for guestfish. *)
1539 and generate_fish_cmds () =
1540   generate_header CStyle GPLv2;
1541
1542   let all_functions =
1543     List.filter (
1544       fun (_, _, _, flags, _, _) -> not (List.mem NotInFish flags)
1545     ) all_functions in
1546   let all_functions_sorted =
1547     List.filter (
1548       fun (_, _, _, flags, _, _) -> not (List.mem NotInFish flags)
1549     ) all_functions_sorted in
1550
1551   pr "#include <stdio.h>\n";
1552   pr "#include <stdlib.h>\n";
1553   pr "#include <string.h>\n";
1554   pr "#include <inttypes.h>\n";
1555   pr "\n";
1556   pr "#include <guestfs.h>\n";
1557   pr "#include \"fish.h\"\n";
1558   pr "\n";
1559
1560   (* list_commands function, which implements guestfish -h *)
1561   pr "void list_commands (void)\n";
1562   pr "{\n";
1563   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
1564   pr "  list_builtin_commands ();\n";
1565   List.iter (
1566     fun (name, _, _, flags, shortdesc, _) ->
1567       let name = replace_char name '_' '-' in
1568       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
1569         name shortdesc
1570   ) all_functions_sorted;
1571   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
1572   pr "}\n";
1573   pr "\n";
1574
1575   (* display_command function, which implements guestfish -h cmd *)
1576   pr "void display_command (const char *cmd)\n";
1577   pr "{\n";
1578   List.iter (
1579     fun (name, style, _, flags, shortdesc, longdesc) ->
1580       let name2 = replace_char name '_' '-' in
1581       let alias =
1582         try find_map (function FishAlias n -> Some n | _ -> None) flags
1583         with Not_found -> name in
1584       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
1585       let synopsis =
1586         match snd style with
1587         | [] -> name2
1588         | args ->
1589             sprintf "%s <%s>"
1590               name2 (String.concat "> <" (List.map name_of_argt args)) in
1591
1592       let warnings =
1593         if List.mem ProtocolLimitWarning flags then
1594           "\n\nBecause of the message protocol, there is a transfer limit 
1595 of somewhere between 2MB and 4MB.  To transfer large files you should use
1596 FTP."
1597         else "" in
1598
1599       let describe_alias =
1600         if name <> alias then
1601           sprintf "\n\nYou can use '%s' as an alias for this command." alias
1602         else "" in
1603
1604       pr "  if (";
1605       pr "strcasecmp (cmd, \"%s\") == 0" name;
1606       if name <> name2 then
1607         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
1608       if name <> alias then
1609         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
1610       pr ")\n";
1611       pr "    pod2text (\"%s - %s\", %S);\n"
1612         name2 shortdesc
1613         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
1614       pr "  else\n"
1615   ) all_functions;
1616   pr "    display_builtin_command (cmd);\n";
1617   pr "}\n";
1618   pr "\n";
1619
1620   (* print_{pv,vg,lv}_list functions *)
1621   List.iter (
1622     function
1623     | typ, cols ->
1624         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
1625         pr "{\n";
1626         pr "  int i;\n";
1627         pr "\n";
1628         List.iter (
1629           function
1630           | name, `String ->
1631               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
1632           | name, `UUID ->
1633               pr "  printf (\"%s: \");\n" name;
1634               pr "  for (i = 0; i < 32; ++i)\n";
1635               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
1636               pr "  printf (\"\\n\");\n"
1637           | name, `Bytes ->
1638               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
1639           | name, `Int ->
1640               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
1641           | name, `OptPercent ->
1642               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
1643                 typ name name typ name;
1644               pr "  else printf (\"%s: \\n\");\n" name
1645         ) cols;
1646         pr "}\n";
1647         pr "\n";
1648         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
1649           typ typ typ;
1650         pr "{\n";
1651         pr "  int i;\n";
1652         pr "\n";
1653         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
1654         pr "    print_%s (&%ss->val[i]);\n" typ typ;
1655         pr "}\n";
1656         pr "\n";
1657   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1658
1659   (* run_<action> actions *)
1660   List.iter (
1661     fun (name, style, _, flags, _, _) ->
1662       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
1663       pr "{\n";
1664       (match fst style with
1665        | Err
1666        | RInt _
1667        | RBool _ -> pr "  int r;\n"
1668        | RConstString _ -> pr "  const char *r;\n"
1669        | RString _ -> pr "  char *r;\n"
1670        | RStringList _ -> pr "  char **r;\n"
1671        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
1672        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
1673        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
1674        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
1675       );
1676       List.iter (
1677         function
1678         | String n -> pr "  const char *%s;\n" n
1679         | OptString n -> pr "  const char *%s;\n" n
1680         | Bool n -> pr "  int %s;\n" n
1681         | Int n -> pr "  int %s;\n" n
1682       ) (snd style);
1683
1684       (* Check and convert parameters. *)
1685       let argc_expected = List.length (snd style) in
1686       pr "  if (argc != %d) {\n" argc_expected;
1687       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
1688         argc_expected;
1689       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
1690       pr "    return -1;\n";
1691       pr "  }\n";
1692       iteri (
1693         fun i ->
1694           function
1695           | String name -> pr "  %s = argv[%d];\n" name i
1696           | OptString name ->
1697               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
1698                 name i i
1699           | Bool name ->
1700               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
1701           | Int name ->
1702               pr "  %s = atoi (argv[%d]);\n" name i
1703       ) (snd style);
1704
1705       (* Call C API function. *)
1706       let fn =
1707         try find_map (function FishAction n -> Some n | _ -> None) flags
1708         with Not_found -> sprintf "guestfs_%s" name in
1709       pr "  r = %s " fn;
1710       generate_call_args ~handle:"g" style;
1711       pr ";\n";
1712
1713       (* Check return value for errors and display command results. *)
1714       (match fst style with
1715        | Err -> pr "  return r;\n"
1716        | RInt _ ->
1717            pr "  if (r == -1) return -1;\n";
1718            pr "  if (r) printf (\"%%d\\n\", r);\n";
1719            pr "  return 0;\n"
1720        | RBool _ ->
1721            pr "  if (r == -1) return -1;\n";
1722            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
1723            pr "  return 0;\n"
1724        | RConstString _ ->
1725            pr "  if (r == NULL) return -1;\n";
1726            pr "  printf (\"%%s\\n\", r);\n";
1727            pr "  return 0;\n"
1728        | RString _ ->
1729            pr "  if (r == NULL) return -1;\n";
1730            pr "  printf (\"%%s\\n\", r);\n";
1731            pr "  free (r);\n";
1732            pr "  return 0;\n"
1733        | RStringList _ ->
1734            pr "  if (r == NULL) return -1;\n";
1735            pr "  print_strings (r);\n";
1736            pr "  free_strings (r);\n";
1737            pr "  return 0;\n"
1738        | RIntBool _ ->
1739            pr "  if (r == NULL) return -1;\n";
1740            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
1741            pr "    r->b ? \"true\" : \"false\");\n";
1742            pr "  guestfs_free_int_bool (r);\n";
1743            pr "  return 0;\n"
1744        | RPVList _ ->
1745            pr "  if (r == NULL) return -1;\n";
1746            pr "  print_pv_list (r);\n";
1747            pr "  guestfs_free_lvm_pv_list (r);\n";
1748            pr "  return 0;\n"
1749        | RVGList _ ->
1750            pr "  if (r == NULL) return -1;\n";
1751            pr "  print_vg_list (r);\n";
1752            pr "  guestfs_free_lvm_vg_list (r);\n";
1753            pr "  return 0;\n"
1754        | RLVList _ ->
1755            pr "  if (r == NULL) return -1;\n";
1756            pr "  print_lv_list (r);\n";
1757            pr "  guestfs_free_lvm_lv_list (r);\n";
1758            pr "  return 0;\n"
1759       );
1760       pr "}\n";
1761       pr "\n"
1762   ) all_functions;
1763
1764   (* run_action function *)
1765   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
1766   pr "{\n";
1767   List.iter (
1768     fun (name, _, _, flags, _, _) ->
1769       let name2 = replace_char name '_' '-' in
1770       let alias =
1771         try find_map (function FishAlias n -> Some n | _ -> None) flags
1772         with Not_found -> name in
1773       pr "  if (";
1774       pr "strcasecmp (cmd, \"%s\") == 0" name;
1775       if name <> name2 then
1776         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
1777       if name <> alias then
1778         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
1779       pr ")\n";
1780       pr "    return run_%s (cmd, argc, argv);\n" name;
1781       pr "  else\n";
1782   ) all_functions;
1783   pr "    {\n";
1784   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
1785   pr "      return -1;\n";
1786   pr "    }\n";
1787   pr "  return 0;\n";
1788   pr "}\n";
1789   pr "\n"
1790
1791 (* Generate the POD documentation for guestfish. *)
1792 and generate_fish_actions_pod () =
1793   let all_functions_sorted =
1794     List.filter (
1795       fun (_, _, _, flags, _, _) -> not (List.mem NotInFish flags)
1796     ) all_functions_sorted in
1797
1798   List.iter (
1799     fun (name, style, _, flags, _, longdesc) ->
1800       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
1801       let name = replace_char name '_' '-' in
1802       let alias =
1803         try find_map (function FishAlias n -> Some n | _ -> None) flags
1804         with Not_found -> name in
1805
1806       pr "=head2 %s" name;
1807       if name <> alias then
1808         pr " | %s" alias;
1809       pr "\n";
1810       pr "\n";
1811       pr " %s" name;
1812       List.iter (
1813         function
1814         | String n -> pr " %s" n
1815         | OptString n -> pr " %s" n
1816         | Bool _ -> pr " true|false"
1817         | Int n -> pr " %s" n
1818       ) (snd style);
1819       pr "\n";
1820       pr "\n";
1821       pr "%s\n\n" longdesc
1822   ) all_functions_sorted
1823
1824 (* Generate a C function prototype. *)
1825 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
1826     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
1827     ?(prefix = "")
1828     ?handle name style =
1829   if extern then pr "extern ";
1830   if static then pr "static ";
1831   (match fst style with
1832    | Err -> pr "int "
1833    | RInt _ -> pr "int "
1834    | RBool _ -> pr "int "
1835    | RConstString _ -> pr "const char *"
1836    | RString _ -> pr "char *"
1837    | RStringList _ -> pr "char **"
1838    | RIntBool _ ->
1839        if not in_daemon then pr "struct guestfs_int_bool *"
1840        else pr "guestfs_%s_ret *" name
1841    | RPVList _ ->
1842        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
1843        else pr "guestfs_lvm_int_pv_list *"
1844    | RVGList _ ->
1845        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
1846        else pr "guestfs_lvm_int_vg_list *"
1847    | RLVList _ ->
1848        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
1849        else pr "guestfs_lvm_int_lv_list *"
1850   );
1851   pr "%s%s (" prefix name;
1852   if handle = None && List.length (snd style) = 0 then
1853     pr "void"
1854   else (
1855     let comma = ref false in
1856     (match handle with
1857      | None -> ()
1858      | Some handle -> pr "guestfs_h *%s" handle; comma := true
1859     );
1860     let next () =
1861       if !comma then (
1862         if single_line then pr ", " else pr ",\n\t\t"
1863       );
1864       comma := true
1865     in
1866     List.iter (
1867       function
1868       | String n -> next (); pr "const char *%s" n
1869       | OptString n -> next (); pr "const char *%s" n
1870       | Bool n -> next (); pr "int %s" n
1871       | Int n -> next (); pr "int %s" n
1872     ) (snd style);
1873   );
1874   pr ")";
1875   if semicolon then pr ";";
1876   if newline then pr "\n"
1877
1878 (* Generate C call arguments, eg "(handle, foo, bar)" *)
1879 and generate_call_args ?handle style =
1880   pr "(";
1881   let comma = ref false in
1882   (match handle with
1883    | None -> ()
1884    | Some handle -> pr "%s" handle; comma := true
1885   );
1886   List.iter (
1887     fun arg ->
1888       if !comma then pr ", ";
1889       comma := true;
1890       match arg with
1891       | String n -> pr "%s" n
1892       | OptString n -> pr "%s" n
1893       | Bool n -> pr "%s" n
1894       | Int n -> pr "%s" n
1895   ) (snd style);
1896   pr ")"
1897
1898 (* Generate the OCaml bindings interface. *)
1899 and generate_ocaml_mli () =
1900   generate_header OCamlStyle LGPLv2;
1901
1902   pr "\
1903 (** For API documentation you should refer to the C API
1904     in the guestfs(3) manual page.  The OCaml API uses almost
1905     exactly the same calls. *)
1906
1907 type t
1908 (** A [guestfs_h] handle. *)
1909
1910 exception Error of string
1911 (** This exception is raised when there is an error. *)
1912
1913 val create : unit -> t
1914
1915 val close : t -> unit
1916 (** Handles are closed by the garbage collector when they become
1917     unreferenced, but callers can also call this in order to
1918     provide predictable cleanup. *)
1919
1920 ";
1921   generate_ocaml_lvm_structure_decls ();
1922
1923   (* The actions. *)
1924   List.iter (
1925     fun (name, style, _, _, shortdesc, _) ->
1926       generate_ocaml_prototype name style;
1927       pr "(** %s *)\n" shortdesc;
1928       pr "\n"
1929   ) all_functions
1930
1931 (* Generate the OCaml bindings implementation. *)
1932 and generate_ocaml_ml () =
1933   generate_header OCamlStyle LGPLv2;
1934
1935   pr "\
1936 type t
1937 exception Error of string
1938 external create : unit -> t = \"ocaml_guestfs_create\"
1939 external close : t -> unit = \"ocaml_guestfs_close\"
1940
1941 let () =
1942   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
1943
1944 ";
1945
1946   generate_ocaml_lvm_structure_decls ();
1947
1948   (* The actions. *)
1949   List.iter (
1950     fun (name, style, _, _, shortdesc, _) ->
1951       generate_ocaml_prototype ~is_external:true name style;
1952   ) all_functions
1953
1954 (* Generate the OCaml bindings C implementation. *)
1955 and generate_ocaml_c () =
1956   generate_header CStyle LGPLv2;
1957
1958   pr "#include <stdio.h>\n";
1959   pr "#include <stdlib.h>\n";
1960   pr "#include <string.h>\n";
1961   pr "\n";
1962   pr "#include <caml/config.h>\n";
1963   pr "#include <caml/alloc.h>\n";
1964   pr "#include <caml/callback.h>\n";
1965   pr "#include <caml/fail.h>\n";
1966   pr "#include <caml/memory.h>\n";
1967   pr "#include <caml/mlvalues.h>\n";
1968   pr "#include <caml/signals.h>\n";
1969   pr "\n";
1970   pr "#include <guestfs.h>\n";
1971   pr "\n";
1972   pr "#include \"guestfs_c.h\"\n";
1973   pr "\n";
1974
1975   (* LVM struct copy functions. *)
1976   List.iter (
1977     fun (typ, cols) ->
1978       let has_optpercent_col =
1979         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
1980
1981       pr "static CAMLprim value\n";
1982       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
1983       pr "{\n";
1984       pr "  CAMLparam0 ();\n";
1985       if has_optpercent_col then
1986         pr "  CAMLlocal3 (rv, v, v2);\n"
1987       else
1988         pr "  CAMLlocal2 (rv, v);\n";
1989       pr "\n";
1990       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
1991       iteri (
1992         fun i col ->
1993           (match col with
1994            | name, `String ->
1995                pr "  v = caml_copy_string (%s->%s);\n" typ name
1996            | name, `UUID ->
1997                pr "  v = caml_alloc_string (32);\n";
1998                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
1999            | name, `Bytes
2000            | name, `Int ->
2001                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
2002            | name, `OptPercent ->
2003                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
2004                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
2005                pr "    v = caml_alloc (1, 0);\n";
2006                pr "    Store_field (v, 0, v2);\n";
2007                pr "  } else /* None */\n";
2008                pr "    v = Val_int (0);\n";
2009           );
2010           pr "  Store_field (rv, %d, v);\n" i
2011       ) cols;
2012       pr "  CAMLreturn (rv);\n";
2013       pr "}\n";
2014       pr "\n";
2015
2016       pr "static CAMLprim value\n";
2017       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
2018         typ typ typ;
2019       pr "{\n";
2020       pr "  CAMLparam0 ();\n";
2021       pr "  CAMLlocal2 (rv, v);\n";
2022       pr "  int i;\n";
2023       pr "\n";
2024       pr "  if (%ss->len == 0)\n" typ;
2025       pr "    CAMLreturn (Atom (0));\n";
2026       pr "  else {\n";
2027       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
2028       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
2029       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
2030       pr "      caml_modify (&Field (rv, i), v);\n";
2031       pr "    }\n";
2032       pr "    CAMLreturn (rv);\n";
2033       pr "  }\n";
2034       pr "}\n";
2035       pr "\n";
2036   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2037
2038   List.iter (
2039     fun (name, style, _, _, _, _) ->
2040       pr "CAMLprim value\n";
2041       pr "ocaml_guestfs_%s (value gv" name;
2042       List.iter (
2043         fun arg -> pr ", value %sv" (name_of_argt arg)
2044       ) (snd style);
2045       pr ")\n";
2046       pr "{\n";
2047       pr "  CAMLparam%d (gv" (1 + (List.length (snd style)));
2048       List.iter (
2049         fun arg -> pr ", %sv" (name_of_argt arg)
2050       ) (snd style);
2051       pr ");\n";
2052       pr "  CAMLlocal1 (rv);\n";
2053       pr "\n";
2054
2055       pr "  guestfs_h *g = Guestfs_val (gv);\n";
2056       pr "  if (g == NULL)\n";
2057       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
2058       pr "\n";
2059
2060       List.iter (
2061         function
2062         | String n ->
2063             pr "  const char *%s = String_val (%sv);\n" n n
2064         | OptString n ->
2065             pr "  const char *%s =\n" n;
2066             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
2067               n n
2068         | Bool n ->
2069             pr "  int %s = Bool_val (%sv);\n" n n
2070         | Int n ->
2071             pr "  int %s = Int_val (%sv);\n" n n
2072       ) (snd style);
2073       let error_code =
2074         match fst style with
2075         | Err -> pr "  int r;\n"; "-1"
2076         | RInt _ -> pr "  int r;\n"; "-1"
2077         | RBool _ -> pr "  int r;\n"; "-1"
2078         | RConstString _ -> pr "  const char *r;\n"; "NULL"
2079         | RString _ -> pr "  char *r;\n"; "NULL"
2080         | RStringList _ ->
2081             pr "  int i;\n";
2082             pr "  char **r;\n";
2083             "NULL"
2084         | RIntBool _ ->
2085             pr "  struct guestfs_int_bool *r;\n";
2086             "NULL"
2087         | RPVList _ ->
2088             pr "  struct guestfs_lvm_pv_list *r;\n";
2089             "NULL"
2090         | RVGList _ ->
2091             pr "  struct guestfs_lvm_vg_list *r;\n";
2092             "NULL"
2093         | RLVList _ ->
2094             pr "  struct guestfs_lvm_lv_list *r;\n";
2095             "NULL" in
2096       pr "\n";
2097
2098       pr "  caml_enter_blocking_section ();\n";
2099       pr "  r = guestfs_%s " name;
2100       generate_call_args ~handle:"g" style;
2101       pr ";\n";
2102       pr "  caml_leave_blocking_section ();\n";
2103       pr "  if (r == %s)\n" error_code;
2104       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
2105       pr "\n";
2106
2107       (match fst style with
2108        | Err -> pr "  rv = Val_unit;\n"
2109        | RInt _ -> pr "  rv = Val_int (r);\n"
2110        | RBool _ -> pr "  rv = Val_bool (r);\n"
2111        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
2112        | RString _ ->
2113            pr "  rv = caml_copy_string (r);\n";
2114            pr "  free (r);\n"
2115        | RStringList _ ->
2116            pr "  rv = caml_copy_string_array ((const char **) r);\n";
2117            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
2118            pr "  free (r);\n"
2119        | RIntBool _ ->
2120            pr "  rv = caml_alloc (2, 0);\n";
2121            pr "  Store_field (rv, 0, Val_int (r->i));\n";
2122            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
2123            pr "  guestfs_free_int_bool (r);\n";
2124        | RPVList _ ->
2125            pr "  rv = copy_lvm_pv_list (r);\n";
2126            pr "  guestfs_free_lvm_pv_list (r);\n";
2127        | RVGList _ ->
2128            pr "  rv = copy_lvm_vg_list (r);\n";
2129            pr "  guestfs_free_lvm_vg_list (r);\n";
2130        | RLVList _ ->
2131            pr "  rv = copy_lvm_lv_list (r);\n";
2132            pr "  guestfs_free_lvm_lv_list (r);\n";
2133       );
2134
2135       pr "  CAMLreturn (rv);\n";
2136       pr "}\n";
2137       pr "\n"
2138   ) all_functions
2139
2140 and generate_ocaml_lvm_structure_decls () =
2141   List.iter (
2142     fun (typ, cols) ->
2143       pr "type lvm_%s = {\n" typ;
2144       List.iter (
2145         function
2146         | name, `String -> pr "  %s : string;\n" name
2147         | name, `UUID -> pr "  %s : string;\n" name
2148         | name, `Bytes -> pr "  %s : int64;\n" name
2149         | name, `Int -> pr "  %s : int64;\n" name
2150         | name, `OptPercent -> pr "  %s : float option;\n" name
2151       ) cols;
2152       pr "}\n";
2153       pr "\n"
2154   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2155
2156 and generate_ocaml_prototype ?(is_external = false) name style =
2157   if is_external then pr "external " else pr "val ";
2158   pr "%s : t -> " name;
2159   List.iter (
2160     function
2161     | String _ -> pr "string -> "
2162     | OptString _ -> pr "string option -> "
2163     | Bool _ -> pr "bool -> "
2164     | Int _ -> pr "int -> "
2165   ) (snd style);
2166   (match fst style with
2167    | Err -> pr "unit" (* all errors are turned into exceptions *)
2168    | RInt _ -> pr "int"
2169    | RBool _ -> pr "bool"
2170    | RConstString _ -> pr "string"
2171    | RString _ -> pr "string"
2172    | RStringList _ -> pr "string array"
2173    | RIntBool _ -> pr "int * bool"
2174    | RPVList _ -> pr "lvm_pv array"
2175    | RVGList _ -> pr "lvm_vg array"
2176    | RLVList _ -> pr "lvm_lv array"
2177   );
2178   if is_external then pr " = \"ocaml_guestfs_%s\"" name;
2179   pr "\n"
2180
2181 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
2182 and generate_perl_xs () =
2183   generate_header CStyle LGPLv2;
2184
2185   pr "\
2186 #include \"EXTERN.h\"
2187 #include \"perl.h\"
2188 #include \"XSUB.h\"
2189
2190 #include <guestfs.h>
2191
2192 #ifndef PRId64
2193 #define PRId64 \"lld\"
2194 #endif
2195
2196 static SV *
2197 my_newSVll(long long val) {
2198 #ifdef USE_64_BIT_ALL
2199   return newSViv(val);
2200 #else
2201   char buf[100];
2202   int len;
2203   len = snprintf(buf, 100, \"%%\" PRId64, val);
2204   return newSVpv(buf, len);
2205 #endif
2206 }
2207
2208 #ifndef PRIu64
2209 #define PRIu64 \"llu\"
2210 #endif
2211
2212 static SV *
2213 my_newSVull(unsigned long long val) {
2214 #ifdef USE_64_BIT_ALL
2215   return newSVuv(val);
2216 #else
2217   char buf[100];
2218   int len;
2219   len = snprintf(buf, 100, \"%%\" PRIu64, val);
2220   return newSVpv(buf, len);
2221 #endif
2222 }
2223
2224 /* XXX Not thread-safe, and in general not safe if the caller is
2225  * issuing multiple requests in parallel (on different guestfs
2226  * handles).  We should use the guestfs_h handle passed to the
2227  * error handle to distinguish these cases.
2228  */
2229 static char *last_error = NULL;
2230
2231 static void
2232 error_handler (guestfs_h *g,
2233                void *data,
2234                const char *msg)
2235 {
2236   if (last_error != NULL) free (last_error);
2237   last_error = strdup (msg);
2238 }
2239
2240 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
2241
2242 guestfs_h *
2243 _create ()
2244    CODE:
2245       RETVAL = guestfs_create ();
2246       if (!RETVAL)
2247         croak (\"could not create guestfs handle\");
2248       guestfs_set_error_handler (RETVAL, error_handler, NULL);
2249  OUTPUT:
2250       RETVAL
2251
2252 void
2253 DESTROY (g)
2254       guestfs_h *g;
2255  PPCODE:
2256       guestfs_close (g);
2257
2258 ";
2259
2260   List.iter (
2261     fun (name, style, _, _, _, _) ->
2262       (match fst style with
2263        | Err -> pr "void\n"
2264        | RInt _ -> pr "SV *\n"
2265        | RBool _ -> pr "SV *\n"
2266        | RConstString _ -> pr "SV *\n"
2267        | RString _ -> pr "SV *\n"
2268        | RStringList _
2269        | RIntBool _
2270        | RPVList _ | RVGList _ | RLVList _ ->
2271            pr "void\n" (* all lists returned implictly on the stack *)
2272       );
2273       (* Call and arguments. *)
2274       pr "%s " name;
2275       generate_call_args ~handle:"g" style;
2276       pr "\n";
2277       pr "      guestfs_h *g;\n";
2278       List.iter (
2279         function
2280         | String n -> pr "      char *%s;\n" n
2281         | OptString n -> pr "      char *%s;\n" n
2282         | Bool n -> pr "      int %s;\n" n
2283         | Int n -> pr "      int %s;\n" n
2284       ) (snd style);
2285       (* Code. *)
2286       (match fst style with
2287        | Err ->
2288            pr " PPCODE:\n";
2289            pr "      if (guestfs_%s " name;
2290            generate_call_args ~handle:"g" style;
2291            pr " == -1)\n";
2292            pr "        croak (\"%s: %%s\", last_error);\n" name
2293        | RInt n
2294        | RBool n ->
2295            pr "PREINIT:\n";
2296            pr "      int %s;\n" n;
2297            pr "   CODE:\n";
2298            pr "      %s = guestfs_%s " n name;
2299            generate_call_args ~handle:"g" style;
2300            pr ";\n";
2301            pr "      if (%s == -1)\n" n;
2302            pr "        croak (\"%s: %%s\", last_error);\n" name;
2303            pr "      RETVAL = newSViv (%s);\n" n;
2304            pr " OUTPUT:\n";
2305            pr "      RETVAL\n"
2306        | RConstString n ->
2307            pr "PREINIT:\n";
2308            pr "      const char *%s;\n" n;
2309            pr "   CODE:\n";
2310            pr "      %s = guestfs_%s " n name;
2311            generate_call_args ~handle:"g" style;
2312            pr ";\n";
2313            pr "      if (%s == NULL)\n" n;
2314            pr "        croak (\"%s: %%s\", last_error);\n" name;
2315            pr "      RETVAL = newSVpv (%s, 0);\n" n;
2316            pr " OUTPUT:\n";
2317            pr "      RETVAL\n"
2318        | RString n ->
2319            pr "PREINIT:\n";
2320            pr "      char *%s;\n" n;
2321            pr "   CODE:\n";
2322            pr "      %s = guestfs_%s " n name;
2323            generate_call_args ~handle:"g" style;
2324            pr ";\n";
2325            pr "      if (%s == NULL)\n" n;
2326            pr "        croak (\"%s: %%s\", last_error);\n" name;
2327            pr "      RETVAL = newSVpv (%s, 0);\n" n;
2328            pr "      free (%s);\n" n;
2329            pr " OUTPUT:\n";
2330            pr "      RETVAL\n"
2331        | RStringList n ->
2332            pr "PREINIT:\n";
2333            pr "      char **%s;\n" n;
2334            pr "      int i, n;\n";
2335            pr " PPCODE:\n";
2336            pr "      %s = guestfs_%s " n name;
2337            generate_call_args ~handle:"g" style;
2338            pr ";\n";
2339            pr "      if (%s == NULL)\n" n;
2340            pr "        croak (\"%s: %%s\", last_error);\n" name;
2341            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
2342            pr "      EXTEND (SP, n);\n";
2343            pr "      for (i = 0; i < n; ++i) {\n";
2344            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
2345            pr "        free (%s[i]);\n" n;
2346            pr "      }\n";
2347            pr "      free (%s);\n" n;
2348        | RIntBool _ ->
2349            pr "PREINIT:\n";
2350            pr "      struct guestfs_int_bool *r;\n";
2351            pr " PPCODE:\n";
2352            pr "      r = guestfs_%s " name;
2353            generate_call_args ~handle:"g" style;
2354            pr ";\n";
2355            pr "      if (r == NULL)\n";
2356            pr "        croak (\"%s: %%s\", last_error);\n" name;
2357            pr "      EXTEND (SP, 2);\n";
2358            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
2359            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
2360            pr "      guestfs_free_int_bool (r);\n";
2361        | RPVList n ->
2362            generate_perl_lvm_code "pv" pv_cols name style n;
2363        | RVGList n ->
2364            generate_perl_lvm_code "vg" vg_cols name style n;
2365        | RLVList n ->
2366            generate_perl_lvm_code "lv" lv_cols name style n;
2367       );
2368       pr "\n"
2369   ) all_functions
2370
2371 and generate_perl_lvm_code typ cols name style n =
2372   pr "PREINIT:\n";
2373   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
2374   pr "      int i;\n";
2375   pr "      HV *hv;\n";
2376   pr " PPCODE:\n";
2377   pr "      %s = guestfs_%s " n name;
2378   generate_call_args ~handle:"g" style;
2379   pr ";\n";
2380   pr "      if (%s == NULL)\n" n;
2381   pr "        croak (\"%s: %%s\", last_error);\n" name;
2382   pr "      EXTEND (SP, %s->len);\n" n;
2383   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
2384   pr "        hv = newHV ();\n";
2385   List.iter (
2386     function
2387     | name, `String ->
2388         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
2389           name (String.length name) n name
2390     | name, `UUID ->
2391         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
2392           name (String.length name) n name
2393     | name, `Bytes ->
2394         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
2395           name (String.length name) n name
2396     | name, `Int ->
2397         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
2398           name (String.length name) n name
2399     | name, `OptPercent ->
2400         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
2401           name (String.length name) n name
2402   ) cols;
2403   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
2404   pr "      }\n";
2405   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
2406
2407 (* Generate Sys/Guestfs.pm. *)
2408 and generate_perl_pm () =
2409   generate_header HashStyle LGPLv2;
2410
2411   pr "\
2412 =pod
2413
2414 =head1 NAME
2415
2416 Sys::Guestfs - Perl bindings for libguestfs
2417
2418 =head1 SYNOPSIS
2419
2420  use Sys::Guestfs;
2421  
2422  my $h = Sys::Guestfs->new ();
2423  $h->add_drive ('guest.img');
2424  $h->launch ();
2425  $h->wait_ready ();
2426  $h->mount ('/dev/sda1', '/');
2427  $h->touch ('/hello');
2428  $h->sync ();
2429
2430 =head1 DESCRIPTION
2431
2432 The C<Sys::Guestfs> module provides a Perl XS binding to the
2433 libguestfs API for examining and modifying virtual machine
2434 disk images.
2435
2436 Amongst the things this is good for: making batch configuration
2437 changes to guests, getting disk used/free statistics (see also:
2438 virt-df), migrating between virtualization systems (see also:
2439 virt-p2v), performing partial backups, performing partial guest
2440 clones, cloning guests and changing registry/UUID/hostname info, and
2441 much else besides.
2442
2443 Libguestfs uses Linux kernel and qemu code, and can access any type of
2444 guest filesystem that Linux and qemu can, including but not limited
2445 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
2446 schemes, qcow, qcow2, vmdk.
2447
2448 Libguestfs provides ways to enumerate guest storage (eg. partitions,
2449 LVs, what filesystem is in each LV, etc.).  It can also run commands
2450 in the context of the guest.  Also you can access filesystems over FTP.
2451
2452 =head1 ERRORS
2453
2454 All errors turn into calls to C<croak> (see L<Carp(3)>).
2455
2456 =head1 METHODS
2457
2458 =over 4
2459
2460 =cut
2461
2462 package Sys::Guestfs;
2463
2464 use strict;
2465 use warnings;
2466
2467 require XSLoader;
2468 XSLoader::load ('Sys::Guestfs');
2469
2470 =item $h = Sys::Guestfs->new ();
2471
2472 Create a new guestfs handle.
2473
2474 =cut
2475
2476 sub new {
2477   my $proto = shift;
2478   my $class = ref ($proto) || $proto;
2479
2480   my $self = Sys::Guestfs::_create ();
2481   bless $self, $class;
2482   return $self;
2483 }
2484
2485 ";
2486
2487   (* Actions.  We only need to print documentation for these as
2488    * they are pulled in from the XS code automatically.
2489    *)
2490   List.iter (
2491     fun (name, style, _, flags, _, longdesc) ->
2492       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
2493       pr "=item ";
2494       generate_perl_prototype name style;
2495       pr "\n\n";
2496       pr "%s\n\n" longdesc;
2497       if List.mem ProtocolLimitWarning flags then
2498         pr "Because of the message protocol, there is a transfer limit 
2499 of somewhere between 2MB and 4MB.  To transfer large files you should use
2500 FTP.\n\n";
2501   ) all_functions_sorted;
2502
2503   (* End of file. *)
2504   pr "\
2505 =cut
2506
2507 1;
2508
2509 =back
2510
2511 =head1 COPYRIGHT
2512
2513 Copyright (C) 2009 Red Hat Inc.
2514
2515 =head1 LICENSE
2516
2517 Please see the file COPYING.LIB for the full license.
2518
2519 =head1 SEE ALSO
2520
2521 L<guestfs(3)>, L<guestfish(1)>.
2522
2523 =cut
2524 "
2525
2526 and generate_perl_prototype name style =
2527   (match fst style with
2528    | Err -> ()
2529    | RBool n
2530    | RInt n
2531    | RConstString n
2532    | RString n -> pr "$%s = " n
2533    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
2534    | RStringList n
2535    | RPVList n
2536    | RVGList n
2537    | RLVList n -> pr "@%s = " n
2538   );
2539   pr "$h->%s (" name;
2540   let comma = ref false in
2541   List.iter (
2542     fun arg ->
2543       if !comma then pr ", ";
2544       comma := true;
2545       pr "%s" (name_of_argt arg)
2546   ) (snd style);
2547   pr ");"
2548
2549 let output_to filename =
2550   let filename_new = filename ^ ".new" in
2551   chan := open_out filename_new;
2552   let close () =
2553     close_out !chan;
2554     chan := stdout;
2555     Unix.rename filename_new filename;
2556     printf "written %s\n%!" filename;
2557   in
2558   close
2559
2560 (* Main program. *)
2561 let () =
2562   check_functions ();
2563
2564   let close = output_to "src/guestfs_protocol.x" in
2565   generate_xdr ();
2566   close ();
2567
2568   let close = output_to "src/guestfs-structs.h" in
2569   generate_structs_h ();
2570   close ();
2571
2572   let close = output_to "src/guestfs-actions.h" in
2573   generate_actions_h ();
2574   close ();
2575
2576   let close = output_to "src/guestfs-actions.c" in
2577   generate_client_actions ();
2578   close ();
2579
2580   let close = output_to "daemon/actions.h" in
2581   generate_daemon_actions_h ();
2582   close ();
2583
2584   let close = output_to "daemon/stubs.c" in
2585   generate_daemon_actions ();
2586   close ();
2587
2588   let close = output_to "fish/cmds.c" in
2589   generate_fish_cmds ();
2590   close ();
2591
2592   let close = output_to "guestfs-structs.pod" in
2593   generate_structs_pod ();
2594   close ();
2595
2596   let close = output_to "guestfs-actions.pod" in
2597   generate_actions_pod ();
2598   close ();
2599
2600   let close = output_to "guestfish-actions.pod" in
2601   generate_fish_actions_pod ();
2602   close ();
2603
2604   let close = output_to "ocaml/guestfs.mli" in
2605   generate_ocaml_mli ();
2606   close ();
2607
2608   let close = output_to "ocaml/guestfs.ml" in
2609   generate_ocaml_ml ();
2610   close ();
2611
2612   let close = output_to "ocaml/guestfs_c_actions.c" in
2613   generate_ocaml_c ();
2614   close ();
2615
2616   let close = output_to "perl/Guestfs.xs" in
2617   generate_perl_xs ();
2618   close ();
2619
2620   let close = output_to "perl/lib/Sys/Guestfs.pm" in
2621   generate_perl_pm ();
2622   close ();