Avoid a cast warning on 32 bit.
[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.
22  *
23  * To add a new action there are only two files you need to change,
24  * this one to describe the interface (see the big table below), and
25  * daemon/<somefile>.c to write the implementation.
26  *
27  * After editing this file, run it (./src/generator.ml) to regenerate
28  * all the output files.
29  *
30  * IMPORTANT: This script should NOT print any warnings.  If it prints
31  * warnings, you should treat them as errors.
32  * [Need to add -warn-error to ocaml command line]
33  *)
34
35 #load "unix.cma";;
36
37 open Printf
38
39 type style = ret * args
40 and ret =
41     (* "RErr" as a return value means an int used as a simple error
42      * indication, ie. 0 or -1.
43      *)
44   | RErr
45     (* "RInt" as a return value means an int which is -1 for error
46      * or any value >= 0 on success.  Only use this for smallish
47      * positive ints (0 <= i < 2^30).
48      *)
49   | RInt of string
50     (* "RInt64" is the same as RInt, but is guaranteed to be able
51      * to return a full 64 bit value, _except_ that -1 means error
52      * (so -1 cannot be a valid, non-error return value).
53      *)
54   | RInt64 of string
55     (* "RBool" is a bool return value which can be true/false or
56      * -1 for error.
57      *)
58   | RBool of string
59     (* "RConstString" is a string that refers to a constant value.
60      * Try to avoid using this.  In particular you cannot use this
61      * for values returned from the daemon, because there is no
62      * thread-safe way to return them in the C API.
63      *)
64   | RConstString of string
65     (* "RString" and "RStringList" are caller-frees. *)
66   | RString of string
67   | RStringList of string
68     (* Some limited tuples are possible: *)
69   | RIntBool of string * string
70     (* LVM PVs, VGs and LVs. *)
71   | RPVList of string
72   | RVGList of string
73   | RLVList of string
74     (* Stat buffers. *)
75   | RStat of string
76   | RStatVFS of string
77     (* Key-value pairs of untyped strings.  Turns into a hashtable or
78      * dictionary in languages which support it.  DON'T use this as a
79      * general "bucket" for results.  Prefer a stronger typed return
80      * value if one is available, or write a custom struct.  Don't use
81      * this if the list could potentially be very long, since it is
82      * inefficient.  Keys should be unique.  NULLs are not permitted.
83      *)
84   | RHashtable of string
85
86 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
87
88     (* Note in future we should allow a "variable args" parameter as
89      * the final parameter, to allow commands like
90      *   chmod mode file [file(s)...]
91      * This is not implemented yet, but many commands (such as chmod)
92      * are currently defined with the argument order keeping this future
93      * possibility in mind.
94      *)
95 and argt =
96   | String of string    (* const char *name, cannot be NULL *)
97   | OptString of string (* const char *name, may be NULL *)
98   | StringList of string(* list of strings (each string cannot be NULL) *)
99   | Bool of string      (* boolean *)
100   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
101     (* These are treated as filenames (simple string parameters) in
102      * the C API and bindings.  But in the RPC protocol, we transfer
103      * the actual file content up to or down from the daemon.
104      * FileIn: local machine -> daemon (in request)
105      * FileOut: daemon -> local machine (in reply)
106      * In guestfish (only), the special name "-" means read from
107      * stdin or write to stdout.
108      *)
109   | FileIn of string
110   | FileOut of string
111
112 type flags =
113   | ProtocolLimitWarning  (* display warning about protocol size limits *)
114   | DangerWillRobinson    (* flags particularly dangerous commands *)
115   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
116   | FishAction of string  (* call this function in guestfish *)
117   | NotInFish             (* do not export via guestfish *)
118
119 let protocol_limit_warning =
120   "Because of the message protocol, there is a transfer limit 
121 of somewhere between 2MB and 4MB.  To transfer large files you should use
122 FTP."
123
124 let danger_will_robinson =
125   "B<This command is dangerous.  Without careful use you
126 can easily destroy all your data>."
127
128 (* You can supply zero or as many tests as you want per API call.
129  *
130  * Note that the test environment has 3 block devices, of size 500MB,
131  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc).
132  * Note for partitioning purposes, the 500MB device has 63 cylinders.
133  *
134  * To be able to run the tests in a reasonable amount of time,
135  * the virtual machine and block devices are reused between tests.
136  * So don't try testing kill_subprocess :-x
137  *
138  * Between each test we umount-all and lvm-remove-all (except InitNone).
139  *
140  * Don't assume anything about the previous contents of the block
141  * devices.  Use 'Init*' to create some initial scenarios.
142  *)
143 type tests = (test_init * test) list
144 and test =
145     (* Run the command sequence and just expect nothing to fail. *)
146   | TestRun of seq
147     (* Run the command sequence and expect the output of the final
148      * command to be the string.
149      *)
150   | TestOutput of seq * string
151     (* Run the command sequence and expect the output of the final
152      * command to be the list of strings.
153      *)
154   | TestOutputList of seq * string list
155     (* Run the command sequence and expect the output of the final
156      * command to be the integer.
157      *)
158   | TestOutputInt of seq * int
159     (* Run the command sequence and expect the output of the final
160      * command to be a true value (!= 0 or != NULL).
161      *)
162   | TestOutputTrue of seq
163     (* Run the command sequence and expect the output of the final
164      * command to be a false value (== 0 or == NULL, but not an error).
165      *)
166   | TestOutputFalse of seq
167     (* Run the command sequence and expect the output of the final
168      * command to be a list of the given length (but don't care about
169      * content).
170      *)
171   | TestOutputLength of seq * int
172     (* Run the command sequence and expect the output of the final
173      * command to be a structure.
174      *)
175   | TestOutputStruct of seq * test_field_compare list
176     (* Run the command sequence and expect the final command (only)
177      * to fail.
178      *)
179   | TestLastFail of seq
180
181 and test_field_compare =
182   | CompareWithInt of string * int
183   | CompareWithString of string * string
184   | CompareFieldsIntEq of string * string
185   | CompareFieldsStrEq of string * string
186
187 (* Some initial scenarios for testing. *)
188 and test_init =
189     (* Do nothing, block devices could contain random stuff including
190      * LVM PVs, and some filesystems might be mounted.  This is usually
191      * a bad idea.
192      *)
193   | InitNone
194     (* Block devices are empty and no filesystems are mounted. *)
195   | InitEmpty
196     (* /dev/sda contains a single partition /dev/sda1, which is formatted
197      * as ext2, empty [except for lost+found] and mounted on /.
198      * /dev/sdb and /dev/sdc may have random content.
199      * No LVM.
200      *)
201   | InitBasicFS
202     (* /dev/sda:
203      *   /dev/sda1 (is a PV):
204      *     /dev/VG/LV (size 8MB):
205      *       formatted as ext2, empty [except for lost+found], mounted on /
206      * /dev/sdb and /dev/sdc may have random content.
207      *)
208   | InitBasicFSonLVM
209
210 (* Sequence of commands for testing. *)
211 and seq = cmd list
212 and cmd = string list
213
214 (* Note about long descriptions: When referring to another
215  * action, use the format C<guestfs_other> (ie. the full name of
216  * the C function).  This will be replaced as appropriate in other
217  * language bindings.
218  *
219  * Apart from that, long descriptions are just perldoc paragraphs.
220  *)
221
222 let non_daemon_functions = [
223   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
224    [],
225    "launch the qemu subprocess",
226    "\
227 Internally libguestfs is implemented by running a virtual machine
228 using L<qemu(1)>.
229
230 You should call this after configuring the handle
231 (eg. adding drives) but before performing any actions.");
232
233   ("wait_ready", (RErr, []), -1, [NotInFish],
234    [],
235    "wait until the qemu subprocess launches",
236    "\
237 Internally libguestfs is implemented by running a virtual machine
238 using L<qemu(1)>.
239
240 You should call this after C<guestfs_launch> to wait for the launch
241 to complete.");
242
243   ("kill_subprocess", (RErr, []), -1, [],
244    [],
245    "kill the qemu subprocess",
246    "\
247 This kills the qemu subprocess.  You should never need to call this.");
248
249   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
250    [],
251    "add an image to examine or modify",
252    "\
253 This function adds a virtual machine disk image C<filename> to the
254 guest.  The first time you call this function, the disk appears as IDE
255 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
256 so on.
257
258 You don't necessarily need to be root when using libguestfs.  However
259 you obviously do need sufficient permissions to access the filename
260 for whatever operations you want to perform (ie. read access if you
261 just want to read the image or write access if you want to modify the
262 image).
263
264 This is equivalent to the qemu parameter C<-drive file=filename>.");
265
266   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
267    [],
268    "add a CD-ROM disk image to examine",
269    "\
270 This function adds a virtual CD-ROM disk image to the guest.
271
272 This is equivalent to the qemu parameter C<-cdrom filename>.");
273
274   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
275    [],
276    "add qemu parameters",
277    "\
278 This can be used to add arbitrary qemu command line parameters
279 of the form C<-param value>.  Actually it's not quite arbitrary - we
280 prevent you from setting some parameters which would interfere with
281 parameters that we use.
282
283 The first character of C<param> string must be a C<-> (dash).
284
285 C<value> can be NULL.");
286
287   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
288    [],
289    "set the qemu binary",
290    "\
291 Set the qemu binary that we will use.
292
293 The default is chosen when the library was compiled by the
294 configure script.
295
296 You can also override this by setting the C<LIBGUESTFS_QEMU>
297 environment variable.
298
299 The string C<qemu> is stashed in the libguestfs handle, so the caller
300 must make sure it remains valid for the lifetime of the handle.
301
302 Setting C<qemu> to C<NULL> restores the default qemu binary.");
303
304   ("get_qemu", (RConstString "qemu", []), -1, [],
305    [],
306    "get the qemu binary",
307    "\
308 Return the current qemu binary.
309
310 This is always non-NULL.  If it wasn't set already, then this will
311 return the default qemu binary name.");
312
313   ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
314    [],
315    "set the search path",
316    "\
317 Set the path that libguestfs searches for kernel and initrd.img.
318
319 The default is C<$libdir/guestfs> unless overridden by setting
320 C<LIBGUESTFS_PATH> environment variable.
321
322 The string C<path> is stashed in the libguestfs handle, so the caller
323 must make sure it remains valid for the lifetime of the handle.
324
325 Setting C<path> to C<NULL> restores the default path.");
326
327   ("get_path", (RConstString "path", []), -1, [],
328    [],
329    "get the search path",
330    "\
331 Return the current search path.
332
333 This is always non-NULL.  If it wasn't set already, then this will
334 return the default path.");
335
336   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
337    [],
338    "set autosync mode",
339    "\
340 If C<autosync> is true, this enables autosync.  Libguestfs will make a
341 best effort attempt to run C<guestfs_sync> when the handle is closed
342 (also if the program exits without closing handles).");
343
344   ("get_autosync", (RBool "autosync", []), -1, [],
345    [],
346    "get autosync mode",
347    "\
348 Get the autosync flag.");
349
350   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
351    [],
352    "set verbose mode",
353    "\
354 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
355
356 Verbose messages are disabled unless the environment variable
357 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
358
359   ("get_verbose", (RBool "verbose", []), -1, [],
360    [],
361    "get verbose mode",
362    "\
363 This returns the verbose messages flag.");
364
365   ("is_ready", (RBool "ready", []), -1, [],
366    [],
367    "is ready to accept commands",
368    "\
369 This returns true iff this handle is ready to accept commands
370 (in the C<READY> state).
371
372 For more information on states, see L<guestfs(3)>.");
373
374   ("is_config", (RBool "config", []), -1, [],
375    [],
376    "is in configuration state",
377    "\
378 This returns true iff this handle is being configured
379 (in the C<CONFIG> state).
380
381 For more information on states, see L<guestfs(3)>.");
382
383   ("is_launching", (RBool "launching", []), -1, [],
384    [],
385    "is launching subprocess",
386    "\
387 This returns true iff this handle is launching the subprocess
388 (in the C<LAUNCHING> state).
389
390 For more information on states, see L<guestfs(3)>.");
391
392   ("is_busy", (RBool "busy", []), -1, [],
393    [],
394    "is busy processing a command",
395    "\
396 This returns true iff this handle is busy processing a command
397 (in the C<BUSY> state).
398
399 For more information on states, see L<guestfs(3)>.");
400
401   ("get_state", (RInt "state", []), -1, [],
402    [],
403    "get the current state",
404    "\
405 This returns the current state as an opaque integer.  This is
406 only useful for printing debug and internal error messages.
407
408 For more information on states, see L<guestfs(3)>.");
409
410   ("set_busy", (RErr, []), -1, [NotInFish],
411    [],
412    "set state to busy",
413    "\
414 This sets the state to C<BUSY>.  This is only used when implementing
415 actions using the low-level API.
416
417 For more information on states, see L<guestfs(3)>.");
418
419   ("set_ready", (RErr, []), -1, [NotInFish],
420    [],
421    "set state to ready",
422    "\
423 This sets the state to C<READY>.  This is only used when implementing
424 actions using the low-level API.
425
426 For more information on states, see L<guestfs(3)>.");
427
428 ]
429
430 let daemon_functions = [
431   ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
432    [InitEmpty, TestOutput (
433       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
434        ["mkfs"; "ext2"; "/dev/sda1"];
435        ["mount"; "/dev/sda1"; "/"];
436        ["write_file"; "/new"; "new file contents"; "0"];
437        ["cat"; "/new"]], "new file contents")],
438    "mount a guest disk at a position in the filesystem",
439    "\
440 Mount a guest disk at a position in the filesystem.  Block devices
441 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
442 the guest.  If those block devices contain partitions, they will have
443 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
444 names can be used.
445
446 The rules are the same as for L<mount(2)>:  A filesystem must
447 first be mounted on C</> before others can be mounted.  Other
448 filesystems can only be mounted on directories which already
449 exist.
450
451 The mounted filesystem is writable, if we have sufficient permissions
452 on the underlying device.
453
454 The filesystem options C<sync> and C<noatime> are set with this
455 call, in order to improve reliability.");
456
457   ("sync", (RErr, []), 2, [],
458    [ InitEmpty, TestRun [["sync"]]],
459    "sync disks, writes are flushed through to the disk image",
460    "\
461 This syncs the disk, so that any writes are flushed through to the
462 underlying disk image.
463
464 You should always call this if you have modified a disk image, before
465 closing the handle.");
466
467   ("touch", (RErr, [String "path"]), 3, [],
468    [InitBasicFS, TestOutputTrue (
469       [["touch"; "/new"];
470        ["exists"; "/new"]])],
471    "update file timestamps or create a new file",
472    "\
473 Touch acts like the L<touch(1)> command.  It can be used to
474 update the timestamps on a file, or, if the file does not exist,
475 to create a new zero-length file.");
476
477   ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
478    [InitBasicFS, TestOutput (
479       [["write_file"; "/new"; "new file contents"; "0"];
480        ["cat"; "/new"]], "new file contents")],
481    "list the contents of a file",
482    "\
483 Return the contents of the file named C<path>.
484
485 Note that this function cannot correctly handle binary files
486 (specifically, files containing C<\\0> character which is treated
487 as end of string).  For those you need to use the C<guestfs_download>
488 function which has a more complex interface.");
489
490   ("ll", (RString "listing", [String "directory"]), 5, [],
491    [], (* XXX Tricky to test because it depends on the exact format
492         * of the 'ls -l' command, which changes between F10 and F11.
493         *)
494    "list the files in a directory (long format)",
495    "\
496 List the files in C<directory> (relative to the root directory,
497 there is no cwd) in the format of 'ls -la'.
498
499 This command is mostly useful for interactive sessions.  It
500 is I<not> intended that you try to parse the output string.");
501
502   ("ls", (RStringList "listing", [String "directory"]), 6, [],
503    [InitBasicFS, TestOutputList (
504       [["touch"; "/new"];
505        ["touch"; "/newer"];
506        ["touch"; "/newest"];
507        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
508    "list the files in a directory",
509    "\
510 List the files in C<directory> (relative to the root directory,
511 there is no cwd).  The '.' and '..' entries are not returned, but
512 hidden files are shown.
513
514 This command is mostly useful for interactive sessions.  Programs
515 should probably use C<guestfs_readdir> instead.");
516
517   ("list_devices", (RStringList "devices", []), 7, [],
518    [InitEmpty, TestOutputList (
519       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
520    "list the block devices",
521    "\
522 List all the block devices.
523
524 The full block device names are returned, eg. C</dev/sda>");
525
526   ("list_partitions", (RStringList "partitions", []), 8, [],
527    [InitBasicFS, TestOutputList (
528       [["list_partitions"]], ["/dev/sda1"]);
529     InitEmpty, TestOutputList (
530       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
531        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
532    "list the partitions",
533    "\
534 List all the partitions detected on all block devices.
535
536 The full partition device names are returned, eg. C</dev/sda1>
537
538 This does not return logical volumes.  For that you will need to
539 call C<guestfs_lvs>.");
540
541   ("pvs", (RStringList "physvols", []), 9, [],
542    [InitBasicFSonLVM, TestOutputList (
543       [["pvs"]], ["/dev/sda1"]);
544     InitEmpty, TestOutputList (
545       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
546        ["pvcreate"; "/dev/sda1"];
547        ["pvcreate"; "/dev/sda2"];
548        ["pvcreate"; "/dev/sda3"];
549        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
550    "list the LVM physical volumes (PVs)",
551    "\
552 List all the physical volumes detected.  This is the equivalent
553 of the L<pvs(8)> command.
554
555 This returns a list of just the device names that contain
556 PVs (eg. C</dev/sda2>).
557
558 See also C<guestfs_pvs_full>.");
559
560   ("vgs", (RStringList "volgroups", []), 10, [],
561    [InitBasicFSonLVM, TestOutputList (
562       [["vgs"]], ["VG"]);
563     InitEmpty, TestOutputList (
564       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
565        ["pvcreate"; "/dev/sda1"];
566        ["pvcreate"; "/dev/sda2"];
567        ["pvcreate"; "/dev/sda3"];
568        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
569        ["vgcreate"; "VG2"; "/dev/sda3"];
570        ["vgs"]], ["VG1"; "VG2"])],
571    "list the LVM volume groups (VGs)",
572    "\
573 List all the volumes groups detected.  This is the equivalent
574 of the L<vgs(8)> command.
575
576 This returns a list of just the volume group names that were
577 detected (eg. C<VolGroup00>).
578
579 See also C<guestfs_vgs_full>.");
580
581   ("lvs", (RStringList "logvols", []), 11, [],
582    [InitBasicFSonLVM, TestOutputList (
583       [["lvs"]], ["/dev/VG/LV"]);
584     InitEmpty, TestOutputList (
585       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
586        ["pvcreate"; "/dev/sda1"];
587        ["pvcreate"; "/dev/sda2"];
588        ["pvcreate"; "/dev/sda3"];
589        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
590        ["vgcreate"; "VG2"; "/dev/sda3"];
591        ["lvcreate"; "LV1"; "VG1"; "50"];
592        ["lvcreate"; "LV2"; "VG1"; "50"];
593        ["lvcreate"; "LV3"; "VG2"; "50"];
594        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
595    "list the LVM logical volumes (LVs)",
596    "\
597 List all the logical volumes detected.  This is the equivalent
598 of the L<lvs(8)> command.
599
600 This returns a list of the logical volume device names
601 (eg. C</dev/VolGroup00/LogVol00>).
602
603 See also C<guestfs_lvs_full>.");
604
605   ("pvs_full", (RPVList "physvols", []), 12, [],
606    [], (* XXX how to test? *)
607    "list the LVM physical volumes (PVs)",
608    "\
609 List all the physical volumes detected.  This is the equivalent
610 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
611
612   ("vgs_full", (RVGList "volgroups", []), 13, [],
613    [], (* XXX how to test? *)
614    "list the LVM volume groups (VGs)",
615    "\
616 List all the volumes groups detected.  This is the equivalent
617 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
618
619   ("lvs_full", (RLVList "logvols", []), 14, [],
620    [], (* XXX how to test? *)
621    "list the LVM logical volumes (LVs)",
622    "\
623 List all the logical volumes detected.  This is the equivalent
624 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
625
626   ("read_lines", (RStringList "lines", [String "path"]), 15, [],
627    [InitBasicFS, TestOutputList (
628       [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
629        ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
630     InitBasicFS, TestOutputList (
631       [["write_file"; "/new"; ""; "0"];
632        ["read_lines"; "/new"]], [])],
633    "read file as lines",
634    "\
635 Return the contents of the file named C<path>.
636
637 The file contents are returned as a list of lines.  Trailing
638 C<LF> and C<CRLF> character sequences are I<not> returned.
639
640 Note that this function cannot correctly handle binary files
641 (specifically, files containing C<\\0> character which is treated
642 as end of line).  For those you need to use the C<guestfs_read_file>
643 function which has a more complex interface.");
644
645   ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
646    [], (* XXX Augeas code needs tests. *)
647    "create a new Augeas handle",
648    "\
649 Create a new Augeas handle for editing configuration files.
650 If there was any previous Augeas handle associated with this
651 guestfs session, then it is closed.
652
653 You must call this before using any other C<guestfs_aug_*>
654 commands.
655
656 C<root> is the filesystem root.  C<root> must not be NULL,
657 use C</> instead.
658
659 The flags are the same as the flags defined in
660 E<lt>augeas.hE<gt>, the logical I<or> of the following
661 integers:
662
663 =over 4
664
665 =item C<AUG_SAVE_BACKUP> = 1
666
667 Keep the original file with a C<.augsave> extension.
668
669 =item C<AUG_SAVE_NEWFILE> = 2
670
671 Save changes into a file with extension C<.augnew>, and
672 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
673
674 =item C<AUG_TYPE_CHECK> = 4
675
676 Typecheck lenses (can be expensive).
677
678 =item C<AUG_NO_STDINC> = 8
679
680 Do not use standard load path for modules.
681
682 =item C<AUG_SAVE_NOOP> = 16
683
684 Make save a no-op, just record what would have been changed.
685
686 =item C<AUG_NO_LOAD> = 32
687
688 Do not load the tree in C<guestfs_aug_init>.
689
690 =back
691
692 To close the handle, you can call C<guestfs_aug_close>.
693
694 To find out more about Augeas, see L<http://augeas.net/>.");
695
696   ("aug_close", (RErr, []), 26, [],
697    [], (* XXX Augeas code needs tests. *)
698    "close the current Augeas handle",
699    "\
700 Close the current Augeas handle and free up any resources
701 used by it.  After calling this, you have to call
702 C<guestfs_aug_init> again before you can use any other
703 Augeas functions.");
704
705   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
706    [], (* XXX Augeas code needs tests. *)
707    "define an Augeas variable",
708    "\
709 Defines an Augeas variable C<name> whose value is the result
710 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
711 undefined.
712
713 On success this returns the number of nodes in C<expr>, or
714 C<0> if C<expr> evaluates to something which is not a nodeset.");
715
716   ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
717    [], (* XXX Augeas code needs tests. *)
718    "define an Augeas node",
719    "\
720 Defines a variable C<name> whose value is the result of
721 evaluating C<expr>.
722
723 If C<expr> evaluates to an empty nodeset, a node is created,
724 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
725 C<name> will be the nodeset containing that single node.
726
727 On success this returns a pair containing the
728 number of nodes in the nodeset, and a boolean flag
729 if a node was created.");
730
731   ("aug_get", (RString "val", [String "path"]), 19, [],
732    [], (* XXX Augeas code needs tests. *)
733    "look up the value of an Augeas path",
734    "\
735 Look up the value associated with C<path>.  If C<path>
736 matches exactly one node, the C<value> is returned.");
737
738   ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
739    [], (* XXX Augeas code needs tests. *)
740    "set Augeas path to value",
741    "\
742 Set the value associated with C<path> to C<value>.");
743
744   ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
745    [], (* XXX Augeas code needs tests. *)
746    "insert a sibling Augeas node",
747    "\
748 Create a new sibling C<label> for C<path>, inserting it into
749 the tree before or after C<path> (depending on the boolean
750 flag C<before>).
751
752 C<path> must match exactly one existing node in the tree, and
753 C<label> must be a label, ie. not contain C</>, C<*> or end
754 with a bracketed index C<[N]>.");
755
756   ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
757    [], (* XXX Augeas code needs tests. *)
758    "remove an Augeas path",
759    "\
760 Remove C<path> and all of its children.
761
762 On success this returns the number of entries which were removed.");
763
764   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
765    [], (* XXX Augeas code needs tests. *)
766    "move Augeas node",
767    "\
768 Move the node C<src> to C<dest>.  C<src> must match exactly
769 one node.  C<dest> is overwritten if it exists.");
770
771   ("aug_match", (RStringList "matches", [String "path"]), 24, [],
772    [], (* XXX Augeas code needs tests. *)
773    "return Augeas nodes which match path",
774    "\
775 Returns a list of paths which match the path expression C<path>.
776 The returned paths are sufficiently qualified so that they match
777 exactly one node in the current tree.");
778
779   ("aug_save", (RErr, []), 25, [],
780    [], (* XXX Augeas code needs tests. *)
781    "write all pending Augeas changes to disk",
782    "\
783 This writes all pending changes to disk.
784
785 The flags which were passed to C<guestfs_aug_init> affect exactly
786 how files are saved.");
787
788   ("aug_load", (RErr, []), 27, [],
789    [], (* XXX Augeas code needs tests. *)
790    "load files into the tree",
791    "\
792 Load files into the tree.
793
794 See C<aug_load> in the Augeas documentation for the full gory
795 details.");
796
797   ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
798    [], (* XXX Augeas code needs tests. *)
799    "list Augeas nodes under a path",
800    "\
801 This is just a shortcut for listing C<guestfs_aug_match>
802 C<path/*> and sorting the resulting nodes into alphabetical order.");
803
804   ("rm", (RErr, [String "path"]), 29, [],
805    [InitBasicFS, TestRun
806       [["touch"; "/new"];
807        ["rm"; "/new"]];
808     InitBasicFS, TestLastFail
809       [["rm"; "/new"]];
810     InitBasicFS, TestLastFail
811       [["mkdir"; "/new"];
812        ["rm"; "/new"]]],
813    "remove a file",
814    "\
815 Remove the single file C<path>.");
816
817   ("rmdir", (RErr, [String "path"]), 30, [],
818    [InitBasicFS, TestRun
819       [["mkdir"; "/new"];
820        ["rmdir"; "/new"]];
821     InitBasicFS, TestLastFail
822       [["rmdir"; "/new"]];
823     InitBasicFS, TestLastFail
824       [["touch"; "/new"];
825        ["rmdir"; "/new"]]],
826    "remove a directory",
827    "\
828 Remove the single directory C<path>.");
829
830   ("rm_rf", (RErr, [String "path"]), 31, [],
831    [InitBasicFS, TestOutputFalse
832       [["mkdir"; "/new"];
833        ["mkdir"; "/new/foo"];
834        ["touch"; "/new/foo/bar"];
835        ["rm_rf"; "/new"];
836        ["exists"; "/new"]]],
837    "remove a file or directory recursively",
838    "\
839 Remove the file or directory C<path>, recursively removing the
840 contents if its a directory.  This is like the C<rm -rf> shell
841 command.");
842
843   ("mkdir", (RErr, [String "path"]), 32, [],
844    [InitBasicFS, TestOutputTrue
845       [["mkdir"; "/new"];
846        ["is_dir"; "/new"]];
847     InitBasicFS, TestLastFail
848       [["mkdir"; "/new/foo/bar"]]],
849    "create a directory",
850    "\
851 Create a directory named C<path>.");
852
853   ("mkdir_p", (RErr, [String "path"]), 33, [],
854    [InitBasicFS, TestOutputTrue
855       [["mkdir_p"; "/new/foo/bar"];
856        ["is_dir"; "/new/foo/bar"]];
857     InitBasicFS, TestOutputTrue
858       [["mkdir_p"; "/new/foo/bar"];
859        ["is_dir"; "/new/foo"]];
860     InitBasicFS, TestOutputTrue
861       [["mkdir_p"; "/new/foo/bar"];
862        ["is_dir"; "/new"]]],
863    "create a directory and parents",
864    "\
865 Create a directory named C<path>, creating any parent directories
866 as necessary.  This is like the C<mkdir -p> shell command.");
867
868   ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
869    [], (* XXX Need stat command to test *)
870    "change file mode",
871    "\
872 Change the mode (permissions) of C<path> to C<mode>.  Only
873 numeric modes are supported.");
874
875   ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
876    [], (* XXX Need stat command to test *)
877    "change file owner and group",
878    "\
879 Change the file owner to C<owner> and group to C<group>.
880
881 Only numeric uid and gid are supported.  If you want to use
882 names, you will need to locate and parse the password file
883 yourself (Augeas support makes this relatively easy).");
884
885   ("exists", (RBool "existsflag", [String "path"]), 36, [],
886    [InitBasicFS, TestOutputTrue (
887       [["touch"; "/new"];
888        ["exists"; "/new"]]);
889     InitBasicFS, TestOutputTrue (
890       [["mkdir"; "/new"];
891        ["exists"; "/new"]])],
892    "test if file or directory exists",
893    "\
894 This returns C<true> if and only if there is a file, directory
895 (or anything) with the given C<path> name.
896
897 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
898
899   ("is_file", (RBool "fileflag", [String "path"]), 37, [],
900    [InitBasicFS, TestOutputTrue (
901       [["touch"; "/new"];
902        ["is_file"; "/new"]]);
903     InitBasicFS, TestOutputFalse (
904       [["mkdir"; "/new"];
905        ["is_file"; "/new"]])],
906    "test if file exists",
907    "\
908 This returns C<true> if and only if there is a file
909 with the given C<path> name.  Note that it returns false for
910 other objects like directories.
911
912 See also C<guestfs_stat>.");
913
914   ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
915    [InitBasicFS, TestOutputFalse (
916       [["touch"; "/new"];
917        ["is_dir"; "/new"]]);
918     InitBasicFS, TestOutputTrue (
919       [["mkdir"; "/new"];
920        ["is_dir"; "/new"]])],
921    "test if file exists",
922    "\
923 This returns C<true> if and only if there is a directory
924 with the given C<path> name.  Note that it returns false for
925 other objects like files.
926
927 See also C<guestfs_stat>.");
928
929   ("pvcreate", (RErr, [String "device"]), 39, [],
930    [InitEmpty, TestOutputList (
931       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
932        ["pvcreate"; "/dev/sda1"];
933        ["pvcreate"; "/dev/sda2"];
934        ["pvcreate"; "/dev/sda3"];
935        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
936    "create an LVM physical volume",
937    "\
938 This creates an LVM physical volume on the named C<device>,
939 where C<device> should usually be a partition name such
940 as C</dev/sda1>.");
941
942   ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
943    [InitEmpty, TestOutputList (
944       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
945        ["pvcreate"; "/dev/sda1"];
946        ["pvcreate"; "/dev/sda2"];
947        ["pvcreate"; "/dev/sda3"];
948        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
949        ["vgcreate"; "VG2"; "/dev/sda3"];
950        ["vgs"]], ["VG1"; "VG2"])],
951    "create an LVM volume group",
952    "\
953 This creates an LVM volume group called C<volgroup>
954 from the non-empty list of physical volumes C<physvols>.");
955
956   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
957    [InitEmpty, TestOutputList (
958       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
959        ["pvcreate"; "/dev/sda1"];
960        ["pvcreate"; "/dev/sda2"];
961        ["pvcreate"; "/dev/sda3"];
962        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
963        ["vgcreate"; "VG2"; "/dev/sda3"];
964        ["lvcreate"; "LV1"; "VG1"; "50"];
965        ["lvcreate"; "LV2"; "VG1"; "50"];
966        ["lvcreate"; "LV3"; "VG2"; "50"];
967        ["lvcreate"; "LV4"; "VG2"; "50"];
968        ["lvcreate"; "LV5"; "VG2"; "50"];
969        ["lvs"]],
970       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
971        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
972    "create an LVM volume group",
973    "\
974 This creates an LVM volume group called C<logvol>
975 on the volume group C<volgroup>, with C<size> megabytes.");
976
977   ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
978    [InitEmpty, TestOutput (
979       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
980        ["mkfs"; "ext2"; "/dev/sda1"];
981        ["mount"; "/dev/sda1"; "/"];
982        ["write_file"; "/new"; "new file contents"; "0"];
983        ["cat"; "/new"]], "new file contents")],
984    "make a filesystem",
985    "\
986 This creates a filesystem on C<device> (usually a partition
987 of LVM logical volume).  The filesystem type is C<fstype>, for
988 example C<ext3>.");
989
990   ("sfdisk", (RErr, [String "device";
991                      Int "cyls"; Int "heads"; Int "sectors";
992                      StringList "lines"]), 43, [DangerWillRobinson],
993    [],
994    "create partitions on a block device",
995    "\
996 This is a direct interface to the L<sfdisk(8)> program for creating
997 partitions on block devices.
998
999 C<device> should be a block device, for example C</dev/sda>.
1000
1001 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1002 and sectors on the device, which are passed directly to sfdisk as
1003 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1004 of these, then the corresponding parameter is omitted.  Usually for
1005 'large' disks, you can just pass C<0> for these, but for small
1006 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1007 out the right geometry and you will need to tell it.
1008
1009 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1010 information refer to the L<sfdisk(8)> manpage.
1011
1012 To create a single partition occupying the whole disk, you would
1013 pass C<lines> as a single element list, when the single element being
1014 the string C<,> (comma).");
1015
1016   ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1017    [InitBasicFS, TestOutput (
1018       [["write_file"; "/new"; "new file contents"; "0"];
1019        ["cat"; "/new"]], "new file contents");
1020     InitBasicFS, TestOutput (
1021       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1022        ["cat"; "/new"]], "\nnew file contents\n");
1023     InitBasicFS, TestOutput (
1024       [["write_file"; "/new"; "\n\n"; "0"];
1025        ["cat"; "/new"]], "\n\n");
1026     InitBasicFS, TestOutput (
1027       [["write_file"; "/new"; ""; "0"];
1028        ["cat"; "/new"]], "");
1029     InitBasicFS, TestOutput (
1030       [["write_file"; "/new"; "\n\n\n"; "0"];
1031        ["cat"; "/new"]], "\n\n\n");
1032     InitBasicFS, TestOutput (
1033       [["write_file"; "/new"; "\n"; "0"];
1034        ["cat"; "/new"]], "\n")],
1035    "create a file",
1036    "\
1037 This call creates a file called C<path>.  The contents of the
1038 file is the string C<content> (which can contain any 8 bit data),
1039 with length C<size>.
1040
1041 As a special case, if C<size> is C<0>
1042 then the length is calculated using C<strlen> (so in this case
1043 the content cannot contain embedded ASCII NULs).");
1044
1045   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1046    [InitEmpty, TestOutputList (
1047       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1048        ["mkfs"; "ext2"; "/dev/sda1"];
1049        ["mount"; "/dev/sda1"; "/"];
1050        ["mounts"]], ["/dev/sda1"]);
1051     InitEmpty, TestOutputList (
1052       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1053        ["mkfs"; "ext2"; "/dev/sda1"];
1054        ["mount"; "/dev/sda1"; "/"];
1055        ["umount"; "/"];
1056        ["mounts"]], [])],
1057    "unmount a filesystem",
1058    "\
1059 This unmounts the given filesystem.  The filesystem may be
1060 specified either by its mountpoint (path) or the device which
1061 contains the filesystem.");
1062
1063   ("mounts", (RStringList "devices", []), 46, [],
1064    [InitBasicFS, TestOutputList (
1065       [["mounts"]], ["/dev/sda1"])],
1066    "show mounted filesystems",
1067    "\
1068 This returns the list of currently mounted filesystems.  It returns
1069 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1070
1071 Some internal mounts are not shown.");
1072
1073   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1074    [InitBasicFS, TestOutputList (
1075       [["umount_all"];
1076        ["mounts"]], [])],
1077    "unmount all filesystems",
1078    "\
1079 This unmounts all mounted filesystems.
1080
1081 Some internal mounts are not unmounted by this call.");
1082
1083   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1084    [],
1085    "remove all LVM LVs, VGs and PVs",
1086    "\
1087 This command removes all LVM logical volumes, volume groups
1088 and physical volumes.");
1089
1090   ("file", (RString "description", [String "path"]), 49, [],
1091    [InitBasicFS, TestOutput (
1092       [["touch"; "/new"];
1093        ["file"; "/new"]], "empty");
1094     InitBasicFS, TestOutput (
1095       [["write_file"; "/new"; "some content\n"; "0"];
1096        ["file"; "/new"]], "ASCII text");
1097     InitBasicFS, TestLastFail (
1098       [["file"; "/nofile"]])],
1099    "determine file type",
1100    "\
1101 This call uses the standard L<file(1)> command to determine
1102 the type or contents of the file.  This also works on devices,
1103 for example to find out whether a partition contains a filesystem.
1104
1105 The exact command which runs is C<file -bsL path>.  Note in
1106 particular that the filename is not prepended to the output
1107 (the C<-b> option).");
1108
1109   ("command", (RString "output", [StringList "arguments"]), 50, [],
1110    [], (* XXX how to test? *)
1111    "run a command from the guest filesystem",
1112    "\
1113 This call runs a command from the guest filesystem.  The
1114 filesystem must be mounted, and must contain a compatible
1115 operating system (ie. something Linux, with the same
1116 or compatible processor architecture).
1117
1118 The single parameter is an argv-style list of arguments.
1119 The first element is the name of the program to run.
1120 Subsequent elements are parameters.  The list must be
1121 non-empty (ie. must contain a program name).
1122
1123 The C<$PATH> environment variable will contain at least
1124 C</usr/bin> and C</bin>.  If you require a program from
1125 another location, you should provide the full path in the
1126 first parameter.
1127
1128 Shared libraries and data files required by the program
1129 must be available on filesystems which are mounted in the
1130 correct places.  It is the caller's responsibility to ensure
1131 all filesystems that are needed are mounted at the right
1132 locations.");
1133
1134   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [],
1135    [], (* XXX how to test? *)
1136    "run a command, returning lines",
1137    "\
1138 This is the same as C<guestfs_command>, but splits the
1139 result into a list of lines.");
1140
1141   ("stat", (RStat "statbuf", [String "path"]), 52, [],
1142    [InitBasicFS, TestOutputStruct (
1143       [["touch"; "/new"];
1144        ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1145    "get file information",
1146    "\
1147 Returns file information for the given C<path>.
1148
1149 This is the same as the C<stat(2)> system call.");
1150
1151   ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1152    [InitBasicFS, TestOutputStruct (
1153       [["touch"; "/new"];
1154        ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1155    "get file information for a symbolic link",
1156    "\
1157 Returns file information for the given C<path>.
1158
1159 This is the same as C<guestfs_stat> except that if C<path>
1160 is a symbolic link, then the link is stat-ed, not the file it
1161 refers to.
1162
1163 This is the same as the C<lstat(2)> system call.");
1164
1165   ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1166    [InitBasicFS, TestOutputStruct (
1167       [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1168                            CompareWithInt ("blocks", 490020);
1169                            CompareWithInt ("bsize", 1024)])],
1170    "get file system statistics",
1171    "\
1172 Returns file system statistics for any mounted file system.
1173 C<path> should be a file or directory in the mounted file system
1174 (typically it is the mount point itself, but it doesn't need to be).
1175
1176 This is the same as the C<statvfs(2)> system call.");
1177
1178   ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1179    [], (* XXX test *)
1180    "get ext2/ext3 superblock details",
1181    "\
1182 This returns the contents of the ext2 or ext3 filesystem superblock
1183 on C<device>.
1184
1185 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1186 manpage for more details.  The list of fields returned isn't
1187 clearly defined, and depends on both the version of C<tune2fs>
1188 that libguestfs was built against, and the filesystem itself.");
1189
1190   ("blockdev_setro", (RErr, [String "device"]), 56, [],
1191    [InitEmpty, TestOutputTrue (
1192       [["blockdev_setro"; "/dev/sda"];
1193        ["blockdev_getro"; "/dev/sda"]])],
1194    "set block device to read-only",
1195    "\
1196 Sets the block device named C<device> to read-only.
1197
1198 This uses the L<blockdev(8)> command.");
1199
1200   ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1201    [InitEmpty, TestOutputFalse (
1202       [["blockdev_setrw"; "/dev/sda"];
1203        ["blockdev_getro"; "/dev/sda"]])],
1204    "set block device to read-write",
1205    "\
1206 Sets the block device named C<device> to read-write.
1207
1208 This uses the L<blockdev(8)> command.");
1209
1210   ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1211    [InitEmpty, TestOutputTrue (
1212       [["blockdev_setro"; "/dev/sda"];
1213        ["blockdev_getro"; "/dev/sda"]])],
1214    "is block device set to read-only",
1215    "\
1216 Returns a boolean indicating if the block device is read-only
1217 (true if read-only, false if not).
1218
1219 This uses the L<blockdev(8)> command.");
1220
1221   ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1222    [InitEmpty, TestOutputInt (
1223       [["blockdev_getss"; "/dev/sda"]], 512)],
1224    "get sectorsize of block device",
1225    "\
1226 This returns the size of sectors on a block device.
1227 Usually 512, but can be larger for modern devices.
1228
1229 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1230 for that).
1231
1232 This uses the L<blockdev(8)> command.");
1233
1234   ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1235    [InitEmpty, TestOutputInt (
1236       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1237    "get blocksize of block device",
1238    "\
1239 This returns the block size of a device.
1240
1241 (Note this is different from both I<size in blocks> and
1242 I<filesystem block size>).
1243
1244 This uses the L<blockdev(8)> command.");
1245
1246   ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1247    [], (* XXX test *)
1248    "set blocksize of block device",
1249    "\
1250 This sets the block size of a device.
1251
1252 (Note this is different from both I<size in blocks> and
1253 I<filesystem block size>).
1254
1255 This uses the L<blockdev(8)> command.");
1256
1257   ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1258    [InitEmpty, TestOutputInt (
1259       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1260    "get total size of device in 512-byte sectors",
1261    "\
1262 This returns the size of the device in units of 512-byte sectors
1263 (even if the sectorsize isn't 512 bytes ... weird).
1264
1265 See also C<guestfs_blockdev_getss> for the real sector size of
1266 the device, and C<guestfs_blockdev_getsize64> for the more
1267 useful I<size in bytes>.
1268
1269 This uses the L<blockdev(8)> command.");
1270
1271   ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1272    [InitEmpty, TestOutputInt (
1273       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1274    "get total size of device in bytes",
1275    "\
1276 This returns the size of the device in bytes.
1277
1278 See also C<guestfs_blockdev_getsz>.
1279
1280 This uses the L<blockdev(8)> command.");
1281
1282   ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1283    [InitEmpty, TestRun
1284       [["blockdev_flushbufs"; "/dev/sda"]]],
1285    "flush device buffers",
1286    "\
1287 This tells the kernel to flush internal buffers associated
1288 with C<device>.
1289
1290 This uses the L<blockdev(8)> command.");
1291
1292   ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1293    [InitEmpty, TestRun
1294       [["blockdev_rereadpt"; "/dev/sda"]]],
1295    "reread partition table",
1296    "\
1297 Reread the partition table on C<device>.
1298
1299 This uses the L<blockdev(8)> command.");
1300
1301   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1302    [InitBasicFS, TestOutput (
1303       (* Pick a file from cwd which isn't likely to change. *)
1304     [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
1305      ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1306    "upload a file from the local machine",
1307    "\
1308 Upload local file C<filename> to C<remotefilename> on the
1309 filesystem.
1310
1311 C<filename> can also be a named pipe.
1312
1313 See also C<guestfs_download>.");
1314
1315   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1316    [InitBasicFS, TestOutput (
1317       (* Pick a file from cwd which isn't likely to change. *)
1318     [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
1319      ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1320      ["upload"; "testdownload.tmp"; "/upload"];
1321      ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1322    "download a file to the local machine",
1323    "\
1324 Download file C<remotefilename> and save it as C<filename>
1325 on the local machine.
1326
1327 C<filename> can also be a named pipe.
1328
1329 See also C<guestfs_upload>, C<guestfs_cat>.");
1330
1331   ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1332    [InitBasicFS, TestOutput (
1333       [["write_file"; "/new"; "test\n"; "0"];
1334        ["checksum"; "crc"; "/new"]], "935282863");
1335     InitBasicFS, TestLastFail (
1336       [["checksum"; "crc"; "/new"]]);
1337     InitBasicFS, TestOutput (
1338       [["write_file"; "/new"; "test\n"; "0"];
1339        ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1340     InitBasicFS, TestOutput (
1341       [["write_file"; "/new"; "test\n"; "0"];
1342        ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1343     InitBasicFS, TestOutput (
1344       [["write_file"; "/new"; "test\n"; "0"];
1345        ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1346     InitBasicFS, TestOutput (
1347       [["write_file"; "/new"; "test\n"; "0"];
1348        ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1349     InitBasicFS, TestOutput (
1350       [["write_file"; "/new"; "test\n"; "0"];
1351        ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1352     InitBasicFS, TestOutput (
1353       [["write_file"; "/new"; "test\n"; "0"];
1354        ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123")],
1355    "compute MD5, SHAx or CRC checksum of file",
1356    "\
1357 This call computes the MD5, SHAx or CRC checksum of the
1358 file named C<path>.
1359
1360 The type of checksum to compute is given by the C<csumtype>
1361 parameter which must have one of the following values:
1362
1363 =over 4
1364
1365 =item C<crc>
1366
1367 Compute the cyclic redundancy check (CRC) specified by POSIX
1368 for the C<cksum> command.
1369
1370 =item C<md5>
1371
1372 Compute the MD5 hash (using the C<md5sum> program).
1373
1374 =item C<sha1>
1375
1376 Compute the SHA1 hash (using the C<sha1sum> program).
1377
1378 =item C<sha224>
1379
1380 Compute the SHA224 hash (using the C<sha224sum> program).
1381
1382 =item C<sha256>
1383
1384 Compute the SHA256 hash (using the C<sha256sum> program).
1385
1386 =item C<sha384>
1387
1388 Compute the SHA384 hash (using the C<sha384sum> program).
1389
1390 =item C<sha512>
1391
1392 Compute the SHA512 hash (using the C<sha512sum> program).
1393
1394 =back
1395
1396 The checksum is returned as a printable string.");
1397
1398   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1399    [InitBasicFS, TestOutput (
1400       [["tar_in"; "images/helloworld.tar"; "/"];
1401        ["cat"; "/hello"]], "hello\n")],
1402    "unpack tarfile to directory",
1403    "\
1404 This command uploads and unpacks local file C<tarfile> (an
1405 I<uncompressed> tar file) into C<directory>.
1406
1407 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1408
1409   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1410    [],
1411    "pack directory into tarfile",
1412    "\
1413 This command packs the contents of C<directory> and downloads
1414 it to local file C<tarfile>.
1415
1416 To download a compressed tarball, use C<guestfs_tgz_out>.");
1417
1418   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1419    [InitBasicFS, TestOutput (
1420       [["tgz_in"; "images/helloworld.tar.gz"; "/"];
1421        ["cat"; "/hello"]], "hello\n")],
1422    "unpack compressed tarball to directory",
1423    "\
1424 This command uploads and unpacks local file C<tarball> (a
1425 I<gzip compressed> tar file) into C<directory>.
1426
1427 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1428
1429   ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1430    [],
1431    "pack directory into compressed tarball",
1432    "\
1433 This command packs the contents of C<directory> and downloads
1434 it to local file C<tarball>.
1435
1436 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1437
1438   ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1439    [InitBasicFS, TestLastFail (
1440       [["umount"; "/"];
1441        ["mount_ro"; "/dev/sda1"; "/"];
1442        ["touch"; "/new"]]);
1443     InitBasicFS, TestOutput (
1444       [["write_file"; "/new"; "data"; "0"];
1445        ["umount"; "/"];
1446        ["mount_ro"; "/dev/sda1"; "/"];
1447        ["cat"; "/new"]], "data")],
1448    "mount a guest disk, read-only",
1449    "\
1450 This is the same as the C<guestfs_mount> command, but it
1451 mounts the filesystem with the read-only (I<-o ro>) flag.");
1452
1453   ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1454    [],
1455    "mount a guest disk with mount options",
1456    "\
1457 This is the same as the C<guestfs_mount> command, but it
1458 allows you to set the mount options as for the
1459 L<mount(8)> I<-o> flag.");
1460
1461   ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1462    [],
1463    "mount a guest disk with mount options and vfstype",
1464    "\
1465 This is the same as the C<guestfs_mount> command, but it
1466 allows you to set both the mount options and the vfstype
1467 as for the L<mount(8)> I<-o> and I<-t> flags.");
1468
1469 ]
1470
1471 let all_functions = non_daemon_functions @ daemon_functions
1472
1473 (* In some places we want the functions to be displayed sorted
1474  * alphabetically, so this is useful:
1475  *)
1476 let all_functions_sorted =
1477   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
1478                compare n1 n2) all_functions
1479
1480 (* Column names and types from LVM PVs/VGs/LVs. *)
1481 let pv_cols = [
1482   "pv_name", `String;
1483   "pv_uuid", `UUID;
1484   "pv_fmt", `String;
1485   "pv_size", `Bytes;
1486   "dev_size", `Bytes;
1487   "pv_free", `Bytes;
1488   "pv_used", `Bytes;
1489   "pv_attr", `String (* XXX *);
1490   "pv_pe_count", `Int;
1491   "pv_pe_alloc_count", `Int;
1492   "pv_tags", `String;
1493   "pe_start", `Bytes;
1494   "pv_mda_count", `Int;
1495   "pv_mda_free", `Bytes;
1496 (* Not in Fedora 10:
1497   "pv_mda_size", `Bytes;
1498 *)
1499 ]
1500 let vg_cols = [
1501   "vg_name", `String;
1502   "vg_uuid", `UUID;
1503   "vg_fmt", `String;
1504   "vg_attr", `String (* XXX *);
1505   "vg_size", `Bytes;
1506   "vg_free", `Bytes;
1507   "vg_sysid", `String;
1508   "vg_extent_size", `Bytes;
1509   "vg_extent_count", `Int;
1510   "vg_free_count", `Int;
1511   "max_lv", `Int;
1512   "max_pv", `Int;
1513   "pv_count", `Int;
1514   "lv_count", `Int;
1515   "snap_count", `Int;
1516   "vg_seqno", `Int;
1517   "vg_tags", `String;
1518   "vg_mda_count", `Int;
1519   "vg_mda_free", `Bytes;
1520 (* Not in Fedora 10:
1521   "vg_mda_size", `Bytes;
1522 *)
1523 ]
1524 let lv_cols = [
1525   "lv_name", `String;
1526   "lv_uuid", `UUID;
1527   "lv_attr", `String (* XXX *);
1528   "lv_major", `Int;
1529   "lv_minor", `Int;
1530   "lv_kernel_major", `Int;
1531   "lv_kernel_minor", `Int;
1532   "lv_size", `Bytes;
1533   "seg_count", `Int;
1534   "origin", `String;
1535   "snap_percent", `OptPercent;
1536   "copy_percent", `OptPercent;
1537   "move_pv", `String;
1538   "lv_tags", `String;
1539   "mirror_log", `String;
1540   "modules", `String;
1541 ]
1542
1543 (* Column names and types from stat structures.
1544  * NB. Can't use things like 'st_atime' because glibc header files
1545  * define some of these as macros.  Ugh.
1546  *)
1547 let stat_cols = [
1548   "dev", `Int;
1549   "ino", `Int;
1550   "mode", `Int;
1551   "nlink", `Int;
1552   "uid", `Int;
1553   "gid", `Int;
1554   "rdev", `Int;
1555   "size", `Int;
1556   "blksize", `Int;
1557   "blocks", `Int;
1558   "atime", `Int;
1559   "mtime", `Int;
1560   "ctime", `Int;
1561 ]
1562 let statvfs_cols = [
1563   "bsize", `Int;
1564   "frsize", `Int;
1565   "blocks", `Int;
1566   "bfree", `Int;
1567   "bavail", `Int;
1568   "files", `Int;
1569   "ffree", `Int;
1570   "favail", `Int;
1571   "fsid", `Int;
1572   "flag", `Int;
1573   "namemax", `Int;
1574 ]
1575
1576 (* Useful functions.
1577  * Note we don't want to use any external OCaml libraries which
1578  * makes this a bit harder than it should be.
1579  *)
1580 let failwithf fs = ksprintf failwith fs
1581
1582 let replace_char s c1 c2 =
1583   let s2 = String.copy s in
1584   let r = ref false in
1585   for i = 0 to String.length s2 - 1 do
1586     if String.unsafe_get s2 i = c1 then (
1587       String.unsafe_set s2 i c2;
1588       r := true
1589     )
1590   done;
1591   if not !r then s else s2
1592
1593 let isspace c =
1594   c = ' '
1595   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
1596
1597 let triml ?(test = isspace) str =
1598   let i = ref 0 in
1599   let n = ref (String.length str) in
1600   while !n > 0 && test str.[!i]; do
1601     decr n;
1602     incr i
1603   done;
1604   if !i = 0 then str
1605   else String.sub str !i !n
1606
1607 let trimr ?(test = isspace) str =
1608   let n = ref (String.length str) in
1609   while !n > 0 && test str.[!n-1]; do
1610     decr n
1611   done;
1612   if !n = String.length str then str
1613   else String.sub str 0 !n
1614
1615 let trim ?(test = isspace) str =
1616   trimr ~test (triml ~test str)
1617
1618 let rec find s sub =
1619   let len = String.length s in
1620   let sublen = String.length sub in
1621   let rec loop i =
1622     if i <= len-sublen then (
1623       let rec loop2 j =
1624         if j < sublen then (
1625           if s.[i+j] = sub.[j] then loop2 (j+1)
1626           else -1
1627         ) else
1628           i (* found *)
1629       in
1630       let r = loop2 0 in
1631       if r = -1 then loop (i+1) else r
1632     ) else
1633       -1 (* not found *)
1634   in
1635   loop 0
1636
1637 let rec replace_str s s1 s2 =
1638   let len = String.length s in
1639   let sublen = String.length s1 in
1640   let i = find s s1 in
1641   if i = -1 then s
1642   else (
1643     let s' = String.sub s 0 i in
1644     let s'' = String.sub s (i+sublen) (len-i-sublen) in
1645     s' ^ s2 ^ replace_str s'' s1 s2
1646   )
1647
1648 let rec string_split sep str =
1649   let len = String.length str in
1650   let seplen = String.length sep in
1651   let i = find str sep in
1652   if i = -1 then [str]
1653   else (
1654     let s' = String.sub str 0 i in
1655     let s'' = String.sub str (i+seplen) (len-i-seplen) in
1656     s' :: string_split sep s''
1657   )
1658
1659 let rec find_map f = function
1660   | [] -> raise Not_found
1661   | x :: xs ->
1662       match f x with
1663       | Some y -> y
1664       | None -> find_map f xs
1665
1666 let iteri f xs =
1667   let rec loop i = function
1668     | [] -> ()
1669     | x :: xs -> f i x; loop (i+1) xs
1670   in
1671   loop 0 xs
1672
1673 let mapi f xs =
1674   let rec loop i = function
1675     | [] -> []
1676     | x :: xs -> let r = f i x in r :: loop (i+1) xs
1677   in
1678   loop 0 xs
1679
1680 let name_of_argt = function
1681   | String n | OptString n | StringList n | Bool n | Int n
1682   | FileIn n | FileOut n -> n
1683
1684 let seq_of_test = function
1685   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
1686   | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
1687   | TestOutputLength (s, _) | TestOutputStruct (s, _)
1688   | TestLastFail s -> s
1689
1690 (* Check function names etc. for consistency. *)
1691 let check_functions () =
1692   let contains_uppercase str =
1693     let len = String.length str in
1694     let rec loop i =
1695       if i >= len then false
1696       else (
1697         let c = str.[i] in
1698         if c >= 'A' && c <= 'Z' then true
1699         else loop (i+1)
1700       )
1701     in
1702     loop 0
1703   in
1704
1705   (* Check function names. *)
1706   List.iter (
1707     fun (name, _, _, _, _, _, _) ->
1708       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
1709         failwithf "function name %s does not need 'guestfs' prefix" name;
1710       if contains_uppercase name then
1711         failwithf "function name %s should not contain uppercase chars" name;
1712       if String.contains name '-' then
1713         failwithf "function name %s should not contain '-', use '_' instead."
1714           name
1715   ) all_functions;
1716
1717   (* Check function parameter/return names. *)
1718   List.iter (
1719     fun (name, style, _, _, _, _, _) ->
1720       let check_arg_ret_name n =
1721         if contains_uppercase n then
1722           failwithf "%s param/ret %s should not contain uppercase chars"
1723             name n;
1724         if String.contains n '-' || String.contains n '_' then
1725           failwithf "%s param/ret %s should not contain '-' or '_'"
1726             name n;
1727         if n = "value" then
1728           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;
1729         if n = "argv" || n = "args" then
1730           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
1731       in
1732
1733       (match fst style with
1734        | RErr -> ()
1735        | RInt n | RInt64 n | RBool n | RConstString n | RString n
1736        | RStringList n | RPVList n | RVGList n | RLVList n
1737        | RStat n | RStatVFS n
1738        | RHashtable n ->
1739            check_arg_ret_name n
1740        | RIntBool (n,m) ->
1741            check_arg_ret_name n;
1742            check_arg_ret_name m
1743       );
1744       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
1745   ) all_functions;
1746
1747   (* Check short descriptions. *)
1748   List.iter (
1749     fun (name, _, _, _, _, shortdesc, _) ->
1750       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
1751         failwithf "short description of %s should begin with lowercase." name;
1752       let c = shortdesc.[String.length shortdesc-1] in
1753       if c = '\n' || c = '.' then
1754         failwithf "short description of %s should not end with . or \\n." name
1755   ) all_functions;
1756
1757   (* Check long dscriptions. *)
1758   List.iter (
1759     fun (name, _, _, _, _, _, longdesc) ->
1760       if longdesc.[String.length longdesc-1] = '\n' then
1761         failwithf "long description of %s should not end with \\n." name
1762   ) all_functions;
1763
1764   (* Check proc_nrs. *)
1765   List.iter (
1766     fun (name, _, proc_nr, _, _, _, _) ->
1767       if proc_nr <= 0 then
1768         failwithf "daemon function %s should have proc_nr > 0" name
1769   ) daemon_functions;
1770
1771   List.iter (
1772     fun (name, _, proc_nr, _, _, _, _) ->
1773       if proc_nr <> -1 then
1774         failwithf "non-daemon function %s should have proc_nr -1" name
1775   ) non_daemon_functions;
1776
1777   let proc_nrs =
1778     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
1779       daemon_functions in
1780   let proc_nrs =
1781     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
1782   let rec loop = function
1783     | [] -> ()
1784     | [_] -> ()
1785     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
1786         loop rest
1787     | (name1,nr1) :: (name2,nr2) :: _ ->
1788         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
1789           name1 name2 nr1 nr2
1790   in
1791   loop proc_nrs;
1792
1793   (* Check tests. *)
1794   List.iter (
1795     function
1796       (* Ignore functions that have no tests.  We generate a
1797        * warning when the user does 'make check' instead.
1798        *)
1799     | name, _, _, _, [], _, _ -> ()
1800     | name, _, _, _, tests, _, _ ->
1801         let funcs =
1802           List.map (
1803             fun (_, test) ->
1804               match seq_of_test test with
1805               | [] ->
1806                   failwithf "%s has a test containing an empty sequence" name
1807               | cmds -> List.map List.hd cmds
1808           ) tests in
1809         let funcs = List.flatten funcs in
1810
1811         let tested = List.mem name funcs in
1812
1813         if not tested then
1814           failwithf "function %s has tests but does not test itself" name
1815   ) all_functions
1816
1817 (* 'pr' prints to the current output file. *)
1818 let chan = ref stdout
1819 let pr fs = ksprintf (output_string !chan) fs
1820
1821 (* Generate a header block in a number of standard styles. *)
1822 type comment_style = CStyle | HashStyle | OCamlStyle
1823 type license = GPLv2 | LGPLv2
1824
1825 let generate_header comment license =
1826   let c = match comment with
1827     | CStyle ->     pr "/* "; " *"
1828     | HashStyle ->  pr "# ";  "#"
1829     | OCamlStyle -> pr "(* "; " *" in
1830   pr "libguestfs generated file\n";
1831   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
1832   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
1833   pr "%s\n" c;
1834   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
1835   pr "%s\n" c;
1836   (match license with
1837    | GPLv2 ->
1838        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
1839        pr "%s it under the terms of the GNU General Public License as published by\n" c;
1840        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
1841        pr "%s (at your option) any later version.\n" c;
1842        pr "%s\n" c;
1843        pr "%s This program is distributed in the hope that it will be useful,\n" c;
1844        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1845        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
1846        pr "%s GNU General Public License for more details.\n" c;
1847        pr "%s\n" c;
1848        pr "%s You should have received a copy of the GNU General Public License along\n" c;
1849        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
1850        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
1851
1852    | LGPLv2 ->
1853        pr "%s This library is free software; you can redistribute it and/or\n" c;
1854        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
1855        pr "%s License as published by the Free Software Foundation; either\n" c;
1856        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
1857        pr "%s\n" c;
1858        pr "%s This library is distributed in the hope that it will be useful,\n" c;
1859        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1860        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
1861        pr "%s Lesser General Public License for more details.\n" c;
1862        pr "%s\n" c;
1863        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
1864        pr "%s License along with this library; if not, write to the Free Software\n" c;
1865        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
1866   );
1867   (match comment with
1868    | CStyle -> pr " */\n"
1869    | HashStyle -> ()
1870    | OCamlStyle -> pr " *)\n"
1871   );
1872   pr "\n"
1873
1874 (* Start of main code generation functions below this line. *)
1875
1876 (* Generate the pod documentation for the C API. *)
1877 let rec generate_actions_pod () =
1878   List.iter (
1879     fun (shortname, style, _, flags, _, _, longdesc) ->
1880       let name = "guestfs_" ^ shortname in
1881       pr "=head2 %s\n\n" name;
1882       pr " ";
1883       generate_prototype ~extern:false ~handle:"handle" name style;
1884       pr "\n\n";
1885       pr "%s\n\n" longdesc;
1886       (match fst style with
1887        | RErr ->
1888            pr "This function returns 0 on success or -1 on error.\n\n"
1889        | RInt _ ->
1890            pr "On error this function returns -1.\n\n"
1891        | RInt64 _ ->
1892            pr "On error this function returns -1.\n\n"
1893        | RBool _ ->
1894            pr "This function returns a C truth value on success or -1 on error.\n\n"
1895        | RConstString _ ->
1896            pr "This function returns a string, or NULL on error.
1897 The string is owned by the guest handle and must I<not> be freed.\n\n"
1898        | RString _ ->
1899            pr "This function returns a string, or NULL on error.
1900 I<The caller must free the returned string after use>.\n\n"
1901        | RStringList _ ->
1902            pr "This function returns a NULL-terminated array of strings
1903 (like L<environ(3)>), or NULL if there was an error.
1904 I<The caller must free the strings and the array after use>.\n\n"
1905        | RIntBool _ ->
1906            pr "This function returns a C<struct guestfs_int_bool *>,
1907 or NULL if there was an error.
1908 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
1909        | RPVList _ ->
1910            pr "This function returns a C<struct guestfs_lvm_pv_list *>
1911 (see E<lt>guestfs-structs.hE<gt>),
1912 or NULL if there was an error.
1913 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
1914        | RVGList _ ->
1915            pr "This function returns a C<struct guestfs_lvm_vg_list *>
1916 (see E<lt>guestfs-structs.hE<gt>),
1917 or NULL if there was an error.
1918 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
1919        | RLVList _ ->
1920            pr "This function returns a C<struct guestfs_lvm_lv_list *>
1921 (see E<lt>guestfs-structs.hE<gt>),
1922 or NULL if there was an error.
1923 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
1924        | RStat _ ->
1925            pr "This function returns a C<struct guestfs_stat *>
1926 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
1927 or NULL if there was an error.
1928 I<The caller must call C<free> after use>.\n\n"
1929        | RStatVFS _ ->
1930            pr "This function returns a C<struct guestfs_statvfs *>
1931 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
1932 or NULL if there was an error.
1933 I<The caller must call C<free> after use>.\n\n"
1934        | RHashtable _ ->
1935            pr "This function returns a NULL-terminated array of
1936 strings, or NULL if there was an error.
1937 The array of strings will always have length C<2n+1>, where
1938 C<n> keys and values alternate, followed by the trailing NULL entry.
1939 I<The caller must free the strings and the array after use>.\n\n"
1940       );
1941       if List.mem ProtocolLimitWarning flags then
1942         pr "%s\n\n" protocol_limit_warning;
1943       if List.mem DangerWillRobinson flags then
1944         pr "%s\n\n" danger_will_robinson;
1945   ) all_functions_sorted
1946
1947 and generate_structs_pod () =
1948   (* LVM structs documentation. *)
1949   List.iter (
1950     fun (typ, cols) ->
1951       pr "=head2 guestfs_lvm_%s\n" typ;
1952       pr "\n";
1953       pr " struct guestfs_lvm_%s {\n" typ;
1954       List.iter (
1955         function
1956         | name, `String -> pr "  char *%s;\n" name
1957         | name, `UUID ->
1958             pr "  /* The next field is NOT nul-terminated, be careful when printing it: */\n";
1959             pr "  char %s[32];\n" name
1960         | name, `Bytes -> pr "  uint64_t %s;\n" name
1961         | name, `Int -> pr "  int64_t %s;\n" name
1962         | name, `OptPercent ->
1963             pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
1964             pr "  float %s;\n" name
1965       ) cols;
1966       pr " \n";
1967       pr " struct guestfs_lvm_%s_list {\n" typ;
1968       pr "   uint32_t len; /* Number of elements in list. */\n";
1969       pr "   struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
1970       pr " };\n";
1971       pr " \n";
1972       pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
1973         typ typ;
1974       pr "\n"
1975   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1976
1977 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
1978  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
1979  *
1980  * We have to use an underscore instead of a dash because otherwise
1981  * rpcgen generates incorrect code.
1982  *
1983  * This header is NOT exported to clients, but see also generate_structs_h.
1984  *)
1985 and generate_xdr () =
1986   generate_header CStyle LGPLv2;
1987
1988   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
1989   pr "typedef string str<>;\n";
1990   pr "\n";
1991
1992   (* LVM internal structures. *)
1993   List.iter (
1994     function
1995     | typ, cols ->
1996         pr "struct guestfs_lvm_int_%s {\n" typ;
1997         List.iter (function
1998                    | name, `String -> pr "  string %s<>;\n" name
1999                    | name, `UUID -> pr "  opaque %s[32];\n" name
2000                    | name, `Bytes -> pr "  hyper %s;\n" name
2001                    | name, `Int -> pr "  hyper %s;\n" name
2002                    | name, `OptPercent -> pr "  float %s;\n" name
2003                   ) cols;
2004         pr "};\n";
2005         pr "\n";
2006         pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
2007         pr "\n";
2008   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2009
2010   (* Stat internal structures. *)
2011   List.iter (
2012     function
2013     | typ, cols ->
2014         pr "struct guestfs_int_%s {\n" typ;
2015         List.iter (function
2016                    | name, `Int -> pr "  hyper %s;\n" name
2017                   ) cols;
2018         pr "};\n";
2019         pr "\n";
2020   ) ["stat", stat_cols; "statvfs", statvfs_cols];
2021
2022   List.iter (
2023     fun (shortname, style, _, _, _, _, _) ->
2024       let name = "guestfs_" ^ shortname in
2025
2026       (match snd style with
2027        | [] -> ()
2028        | args ->
2029            pr "struct %s_args {\n" name;
2030            List.iter (
2031              function
2032              | String n -> pr "  string %s<>;\n" n
2033              | OptString n -> pr "  str *%s;\n" n
2034              | StringList n -> pr "  str %s<>;\n" n
2035              | Bool n -> pr "  bool %s;\n" n
2036              | Int n -> pr "  int %s;\n" n
2037              | FileIn _ | FileOut _ -> ()
2038            ) args;
2039            pr "};\n\n"
2040       );
2041       (match fst style with
2042        | RErr -> ()
2043        | RInt n ->
2044            pr "struct %s_ret {\n" name;
2045            pr "  int %s;\n" n;
2046            pr "};\n\n"
2047        | RInt64 n ->
2048            pr "struct %s_ret {\n" name;
2049            pr "  hyper %s;\n" n;
2050            pr "};\n\n"
2051        | RBool n ->
2052            pr "struct %s_ret {\n" name;
2053            pr "  bool %s;\n" n;
2054            pr "};\n\n"
2055        | RConstString _ ->
2056            failwithf "RConstString cannot be returned from a daemon function"
2057        | RString n ->
2058            pr "struct %s_ret {\n" name;
2059            pr "  string %s<>;\n" n;
2060            pr "};\n\n"
2061        | RStringList n ->
2062            pr "struct %s_ret {\n" name;
2063            pr "  str %s<>;\n" n;
2064            pr "};\n\n"
2065        | RIntBool (n,m) ->
2066            pr "struct %s_ret {\n" name;
2067            pr "  int %s;\n" n;
2068            pr "  bool %s;\n" m;
2069            pr "};\n\n"
2070        | RPVList n ->
2071            pr "struct %s_ret {\n" name;
2072            pr "  guestfs_lvm_int_pv_list %s;\n" n;
2073            pr "};\n\n"
2074        | RVGList n ->
2075            pr "struct %s_ret {\n" name;
2076            pr "  guestfs_lvm_int_vg_list %s;\n" n;
2077            pr "};\n\n"
2078        | RLVList n ->
2079            pr "struct %s_ret {\n" name;
2080            pr "  guestfs_lvm_int_lv_list %s;\n" n;
2081            pr "};\n\n"
2082        | RStat n ->
2083            pr "struct %s_ret {\n" name;
2084            pr "  guestfs_int_stat %s;\n" n;
2085            pr "};\n\n"
2086        | RStatVFS n ->
2087            pr "struct %s_ret {\n" name;
2088            pr "  guestfs_int_statvfs %s;\n" n;
2089            pr "};\n\n"
2090        | RHashtable n ->
2091            pr "struct %s_ret {\n" name;
2092            pr "  str %s<>;\n" n;
2093            pr "};\n\n"
2094       );
2095   ) daemon_functions;
2096
2097   (* Table of procedure numbers. *)
2098   pr "enum guestfs_procedure {\n";
2099   List.iter (
2100     fun (shortname, _, proc_nr, _, _, _, _) ->
2101       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
2102   ) daemon_functions;
2103   pr "  GUESTFS_PROC_NR_PROCS\n";
2104   pr "};\n";
2105   pr "\n";
2106
2107   (* Having to choose a maximum message size is annoying for several
2108    * reasons (it limits what we can do in the API), but it (a) makes
2109    * the protocol a lot simpler, and (b) provides a bound on the size
2110    * of the daemon which operates in limited memory space.  For large
2111    * file transfers you should use FTP.
2112    *)
2113   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
2114   pr "\n";
2115
2116   (* Message header, etc. *)
2117   pr "\
2118 /* The communication protocol is now documented in the guestfs(3)
2119  * manpage.
2120  */
2121
2122 const GUESTFS_PROGRAM = 0x2000F5F5;
2123 const GUESTFS_PROTOCOL_VERSION = 1;
2124
2125 /* These constants must be larger than any possible message length. */
2126 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
2127 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
2128
2129 enum guestfs_message_direction {
2130   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
2131   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
2132 };
2133
2134 enum guestfs_message_status {
2135   GUESTFS_STATUS_OK = 0,
2136   GUESTFS_STATUS_ERROR = 1
2137 };
2138
2139 const GUESTFS_ERROR_LEN = 256;
2140
2141 struct guestfs_message_error {
2142   string error_message<GUESTFS_ERROR_LEN>;
2143 };
2144
2145 struct guestfs_message_header {
2146   unsigned prog;                     /* GUESTFS_PROGRAM */
2147   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
2148   guestfs_procedure proc;            /* GUESTFS_PROC_x */
2149   guestfs_message_direction direction;
2150   unsigned serial;                   /* message serial number */
2151   guestfs_message_status status;
2152 };
2153
2154 const GUESTFS_MAX_CHUNK_SIZE = 8192;
2155
2156 struct guestfs_chunk {
2157   int cancel;                        /* if non-zero, transfer is cancelled */
2158   /* data size is 0 bytes if the transfer has finished successfully */
2159   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
2160 };
2161 "
2162
2163 (* Generate the guestfs-structs.h file. *)
2164 and generate_structs_h () =
2165   generate_header CStyle LGPLv2;
2166
2167   (* This is a public exported header file containing various
2168    * structures.  The structures are carefully written to have
2169    * exactly the same in-memory format as the XDR structures that
2170    * we use on the wire to the daemon.  The reason for creating
2171    * copies of these structures here is just so we don't have to
2172    * export the whole of guestfs_protocol.h (which includes much
2173    * unrelated and XDR-dependent stuff that we don't want to be
2174    * public, or required by clients).
2175    *
2176    * To reiterate, we will pass these structures to and from the
2177    * client with a simple assignment or memcpy, so the format
2178    * must be identical to what rpcgen / the RFC defines.
2179    *)
2180
2181   (* guestfs_int_bool structure. *)
2182   pr "struct guestfs_int_bool {\n";
2183   pr "  int32_t i;\n";
2184   pr "  int32_t b;\n";
2185   pr "};\n";
2186   pr "\n";
2187
2188   (* LVM public structures. *)
2189   List.iter (
2190     function
2191     | typ, cols ->
2192         pr "struct guestfs_lvm_%s {\n" typ;
2193         List.iter (
2194           function
2195           | name, `String -> pr "  char *%s;\n" name
2196           | name, `UUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
2197           | name, `Bytes -> pr "  uint64_t %s;\n" name
2198           | name, `Int -> pr "  int64_t %s;\n" name
2199           | name, `OptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
2200         ) cols;
2201         pr "};\n";
2202         pr "\n";
2203         pr "struct guestfs_lvm_%s_list {\n" typ;
2204         pr "  uint32_t len;\n";
2205         pr "  struct guestfs_lvm_%s *val;\n" typ;
2206         pr "};\n";
2207         pr "\n"
2208   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2209
2210   (* Stat structures. *)
2211   List.iter (
2212     function
2213     | typ, cols ->
2214         pr "struct guestfs_%s {\n" typ;
2215         List.iter (
2216           function
2217           | name, `Int -> pr "  int64_t %s;\n" name
2218         ) cols;
2219         pr "};\n";
2220         pr "\n"
2221   ) ["stat", stat_cols; "statvfs", statvfs_cols]
2222
2223 (* Generate the guestfs-actions.h file. *)
2224 and generate_actions_h () =
2225   generate_header CStyle LGPLv2;
2226   List.iter (
2227     fun (shortname, style, _, _, _, _, _) ->
2228       let name = "guestfs_" ^ shortname in
2229       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
2230         name style
2231   ) all_functions
2232
2233 (* Generate the client-side dispatch stubs. *)
2234 and generate_client_actions () =
2235   generate_header CStyle LGPLv2;
2236
2237   pr "\
2238 #include <stdio.h>
2239 #include <stdlib.h>
2240
2241 #include \"guestfs.h\"
2242 #include \"guestfs_protocol.h\"
2243
2244 #define error guestfs_error
2245 #define perrorf guestfs_perrorf
2246 #define safe_malloc guestfs_safe_malloc
2247 #define safe_realloc guestfs_safe_realloc
2248 #define safe_strdup guestfs_safe_strdup
2249 #define safe_memdup guestfs_safe_memdup
2250
2251 /* Check the return message from a call for validity. */
2252 static int
2253 check_reply_header (guestfs_h *g,
2254                     const struct guestfs_message_header *hdr,
2255                     int proc_nr, int serial)
2256 {
2257   if (hdr->prog != GUESTFS_PROGRAM) {
2258     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
2259     return -1;
2260   }
2261   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
2262     error (g, \"wrong protocol version (%%d/%%d)\",
2263            hdr->vers, GUESTFS_PROTOCOL_VERSION);
2264     return -1;
2265   }
2266   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
2267     error (g, \"unexpected message direction (%%d/%%d)\",
2268            hdr->direction, GUESTFS_DIRECTION_REPLY);
2269     return -1;
2270   }
2271   if (hdr->proc != proc_nr) {
2272     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
2273     return -1;
2274   }
2275   if (hdr->serial != serial) {
2276     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
2277     return -1;
2278   }
2279
2280   return 0;
2281 }
2282
2283 /* Check we are in the right state to run a high-level action. */
2284 static int
2285 check_state (guestfs_h *g, const char *caller)
2286 {
2287   if (!guestfs_is_ready (g)) {
2288     if (guestfs_is_config (g))
2289       error (g, \"%%s: call launch() before using this function\",
2290         caller);
2291     else if (guestfs_is_launching (g))
2292       error (g, \"%%s: call wait_ready() before using this function\",
2293         caller);
2294     else
2295       error (g, \"%%s called from the wrong state, %%d != READY\",
2296         caller, guestfs_get_state (g));
2297     return -1;
2298   }
2299   return 0;
2300 }
2301
2302 ";
2303
2304   (* Client-side stubs for each function. *)
2305   List.iter (
2306     fun (shortname, style, _, _, _, _, _) ->
2307       let name = "guestfs_" ^ shortname in
2308
2309       (* Generate the context struct which stores the high-level
2310        * state between callback functions.
2311        *)
2312       pr "struct %s_ctx {\n" shortname;
2313       pr "  /* This flag is set by the callbacks, so we know we've done\n";
2314       pr "   * the callbacks as expected, and in the right sequence.\n";
2315       pr "   * 0 = not called, 1 = send called,\n";
2316       pr "   * 1001 = reply called.\n";
2317       pr "   */\n";
2318       pr "  int cb_sequence;\n";
2319       pr "  struct guestfs_message_header hdr;\n";
2320       pr "  struct guestfs_message_error err;\n";
2321       (match fst style with
2322        | RErr -> ()
2323        | RConstString _ ->
2324            failwithf "RConstString cannot be returned from a daemon function"
2325        | RInt _ | RInt64 _
2326        | RBool _ | RString _ | RStringList _
2327        | RIntBool _
2328        | RPVList _ | RVGList _ | RLVList _
2329        | RStat _ | RStatVFS _
2330        | RHashtable _ ->
2331            pr "  struct %s_ret ret;\n" name
2332       );
2333       pr "};\n";
2334       pr "\n";
2335
2336       (* Generate the reply callback function. *)
2337       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
2338       pr "{\n";
2339       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2340       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
2341       pr "\n";
2342       pr "  ml->main_loop_quit (ml, g);\n";
2343       pr "\n";
2344       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
2345       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
2346       pr "    return;\n";
2347       pr "  }\n";
2348       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
2349       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
2350       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
2351         name;
2352       pr "      return;\n";
2353       pr "    }\n";
2354       pr "    goto done;\n";
2355       pr "  }\n";
2356
2357       (match fst style with
2358        | RErr -> ()
2359        | RConstString _ ->
2360            failwithf "RConstString cannot be returned from a daemon function"
2361        | RInt _ | RInt64 _
2362        | RBool _ | RString _ | RStringList _
2363        | RIntBool _
2364        | RPVList _ | RVGList _ | RLVList _
2365        | RStat _ | RStatVFS _
2366        | RHashtable _ ->
2367             pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
2368             pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
2369             pr "    return;\n";
2370             pr "  }\n";
2371       );
2372
2373       pr " done:\n";
2374       pr "  ctx->cb_sequence = 1001;\n";
2375       pr "}\n\n";
2376
2377       (* Generate the action stub. *)
2378       generate_prototype ~extern:false ~semicolon:false ~newline:true
2379         ~handle:"g" name style;
2380
2381       let error_code =
2382         match fst style with
2383         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
2384         | RConstString _ ->
2385             failwithf "RConstString cannot be returned from a daemon function"
2386         | RString _ | RStringList _ | RIntBool _
2387         | RPVList _ | RVGList _ | RLVList _
2388         | RStat _ | RStatVFS _
2389         | RHashtable _ ->
2390             "NULL" in
2391
2392       pr "{\n";
2393
2394       (match snd style with
2395        | [] -> ()
2396        | _ -> pr "  struct %s_args args;\n" name
2397       );
2398
2399       pr "  struct %s_ctx ctx;\n" shortname;
2400       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2401       pr "  int serial;\n";
2402       pr "\n";
2403       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
2404       pr "  guestfs_set_busy (g);\n";
2405       pr "\n";
2406       pr "  memset (&ctx, 0, sizeof ctx);\n";
2407       pr "\n";
2408
2409       (* Send the main header and arguments. *)
2410       (match snd style with
2411        | [] ->
2412            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
2413              (String.uppercase shortname)
2414        | args ->
2415            List.iter (
2416              function
2417              | String n ->
2418                  pr "  args.%s = (char *) %s;\n" n n
2419              | OptString n ->
2420                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
2421              | StringList n ->
2422                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
2423                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
2424              | Bool n ->
2425                  pr "  args.%s = %s;\n" n n
2426              | Int n ->
2427                  pr "  args.%s = %s;\n" n n
2428              | FileIn _ | FileOut _ -> ()
2429            ) args;
2430            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
2431              (String.uppercase shortname);
2432            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
2433              name;
2434       );
2435       pr "  if (serial == -1) {\n";
2436       pr "    guestfs_set_ready (g);\n";
2437       pr "    return %s;\n" error_code;
2438       pr "  }\n";
2439       pr "\n";
2440
2441       (* Send any additional files (FileIn) requested. *)
2442       let need_read_reply_label = ref false in
2443       List.iter (
2444         function
2445         | FileIn n ->
2446             pr "  {\n";
2447             pr "    int r;\n";
2448             pr "\n";
2449             pr "    r = guestfs__send_file_sync (g, %s);\n" n;
2450             pr "    if (r == -1) {\n";
2451             pr "      guestfs_set_ready (g);\n";
2452             pr "      return %s;\n" error_code;
2453             pr "    }\n";
2454             pr "    if (r == -2) /* daemon cancelled */\n";
2455             pr "      goto read_reply;\n";
2456             need_read_reply_label := true;
2457             pr "  }\n";
2458             pr "\n";
2459         | _ -> ()
2460       ) (snd style);
2461
2462       (* Wait for the reply from the remote end. *)
2463       if !need_read_reply_label then pr " read_reply:\n";
2464       pr "  guestfs__switch_to_receiving (g);\n";
2465       pr "  ctx.cb_sequence = 0;\n";
2466       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
2467       pr "  (void) ml->main_loop_run (ml, g);\n";
2468       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
2469       pr "  if (ctx.cb_sequence != 1001) {\n";
2470       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
2471       pr "    guestfs_set_ready (g);\n";
2472       pr "    return %s;\n" error_code;
2473       pr "  }\n";
2474       pr "\n";
2475
2476       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
2477         (String.uppercase shortname);
2478       pr "    guestfs_set_ready (g);\n";
2479       pr "    return %s;\n" error_code;
2480       pr "  }\n";
2481       pr "\n";
2482
2483       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
2484       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
2485       pr "    guestfs_set_ready (g);\n";
2486       pr "    return %s;\n" error_code;
2487       pr "  }\n";
2488       pr "\n";
2489
2490       (* Expecting to receive further files (FileOut)? *)
2491       List.iter (
2492         function
2493         | FileOut n ->
2494             pr "  if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
2495             pr "    guestfs_set_ready (g);\n";
2496             pr "    return %s;\n" error_code;
2497             pr "  }\n";
2498             pr "\n";
2499         | _ -> ()
2500       ) (snd style);
2501
2502       pr "  guestfs_set_ready (g);\n";
2503
2504       (match fst style with
2505        | RErr -> pr "  return 0;\n"
2506        | RInt n | RInt64 n | RBool n ->
2507            pr "  return ctx.ret.%s;\n" n
2508        | RConstString _ ->
2509            failwithf "RConstString cannot be returned from a daemon function"
2510        | RString n ->
2511            pr "  return ctx.ret.%s; /* caller will free */\n" n
2512        | RStringList n | RHashtable n ->
2513            pr "  /* caller will free this, but we need to add a NULL entry */\n";
2514            pr "  ctx.ret.%s.%s_val =\n" n n;
2515            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
2516            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
2517              n n;
2518            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
2519            pr "  return ctx.ret.%s.%s_val;\n" n n
2520        | RIntBool _ ->
2521            pr "  /* caller with free this */\n";
2522            pr "  return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
2523        | RPVList n | RVGList n | RLVList n
2524        | RStat n | RStatVFS n ->
2525            pr "  /* caller will free this */\n";
2526            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
2527       );
2528
2529       pr "}\n\n"
2530   ) daemon_functions
2531
2532 (* Generate daemon/actions.h. *)
2533 and generate_daemon_actions_h () =
2534   generate_header CStyle GPLv2;
2535
2536   pr "#include \"../src/guestfs_protocol.h\"\n";
2537   pr "\n";
2538
2539   List.iter (
2540     fun (name, style, _, _, _, _, _) ->
2541         generate_prototype
2542           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
2543           name style;
2544   ) daemon_functions
2545
2546 (* Generate the server-side stubs. *)
2547 and generate_daemon_actions () =
2548   generate_header CStyle GPLv2;
2549
2550   pr "#define _GNU_SOURCE // for strchrnul\n";
2551   pr "\n";
2552   pr "#include <stdio.h>\n";
2553   pr "#include <stdlib.h>\n";
2554   pr "#include <string.h>\n";
2555   pr "#include <inttypes.h>\n";
2556   pr "#include <ctype.h>\n";
2557   pr "#include <rpc/types.h>\n";
2558   pr "#include <rpc/xdr.h>\n";
2559   pr "\n";
2560   pr "#include \"daemon.h\"\n";
2561   pr "#include \"../src/guestfs_protocol.h\"\n";
2562   pr "#include \"actions.h\"\n";
2563   pr "\n";
2564
2565   List.iter (
2566     fun (name, style, _, _, _, _, _) ->
2567       (* Generate server-side stubs. *)
2568       pr "static void %s_stub (XDR *xdr_in)\n" name;
2569       pr "{\n";
2570       let error_code =
2571         match fst style with
2572         | RErr | RInt _ -> pr "  int r;\n"; "-1"
2573         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
2574         | RBool _ -> pr "  int r;\n"; "-1"
2575         | RConstString _ ->
2576             failwithf "RConstString cannot be returned from a daemon function"
2577         | RString _ -> pr "  char *r;\n"; "NULL"
2578         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
2579         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
2580         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
2581         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
2582         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL"
2583         | RStat _ -> pr "  guestfs_int_stat *r;\n"; "NULL"
2584         | RStatVFS _ -> pr "  guestfs_int_statvfs *r;\n"; "NULL" in
2585
2586       (match snd style with
2587        | [] -> ()
2588        | args ->
2589            pr "  struct guestfs_%s_args args;\n" name;
2590            List.iter (
2591              function
2592              | String n
2593              | OptString n -> pr "  const char *%s;\n" n
2594              | StringList n -> pr "  char **%s;\n" n
2595              | Bool n -> pr "  int %s;\n" n
2596              | Int n -> pr "  int %s;\n" n
2597              | FileIn _ | FileOut _ -> ()
2598            ) args
2599       );
2600       pr "\n";
2601
2602       (match snd style with
2603        | [] -> ()
2604        | args ->
2605            pr "  memset (&args, 0, sizeof args);\n";
2606            pr "\n";
2607            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
2608            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
2609            pr "    return;\n";
2610            pr "  }\n";
2611            List.iter (
2612              function
2613              | String n -> pr "  %s = args.%s;\n" n n
2614              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
2615              | StringList n ->
2616                  pr "  args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
2617                  pr "  args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
2618                  pr "  %s = args.%s.%s_val;\n" n n n
2619              | Bool n -> pr "  %s = args.%s;\n" n n
2620              | Int n -> pr "  %s = args.%s;\n" n n
2621              | FileIn _ | FileOut _ -> ()
2622            ) args;
2623            pr "\n"
2624       );
2625
2626       (* Don't want to call the impl with any FileIn or FileOut
2627        * parameters, since these go "outside" the RPC protocol.
2628        *)
2629       let argsnofile =
2630         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
2631           (snd style) in
2632       pr "  r = do_%s " name;
2633       generate_call_args argsnofile;
2634       pr ";\n";
2635
2636       pr "  if (r == %s)\n" error_code;
2637       pr "    /* do_%s has already called reply_with_error */\n" name;
2638       pr "    goto done;\n";
2639       pr "\n";
2640
2641       (* If there are any FileOut parameters, then the impl must
2642        * send its own reply.
2643        *)
2644       let no_reply =
2645         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
2646       if no_reply then
2647         pr "  /* do_%s has already sent a reply */\n" name
2648       else (
2649         match fst style with
2650         | RErr -> pr "  reply (NULL, NULL);\n"
2651         | RInt n | RInt64 n | RBool n ->
2652             pr "  struct guestfs_%s_ret ret;\n" name;
2653             pr "  ret.%s = r;\n" n;
2654             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2655               name
2656         | RConstString _ ->
2657             failwithf "RConstString cannot be returned from a daemon function"
2658         | RString n ->
2659             pr "  struct guestfs_%s_ret ret;\n" name;
2660             pr "  ret.%s = r;\n" n;
2661             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2662               name;
2663             pr "  free (r);\n"
2664         | RStringList n | RHashtable n ->
2665             pr "  struct guestfs_%s_ret ret;\n" name;
2666             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
2667             pr "  ret.%s.%s_val = r;\n" n n;
2668             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2669               name;
2670             pr "  free_strings (r);\n"
2671         | RIntBool _ ->
2672             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
2673               name;
2674             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2675         | RPVList n | RVGList n | RLVList n
2676         | RStat n | RStatVFS n ->
2677             pr "  struct guestfs_%s_ret ret;\n" name;
2678             pr "  ret.%s = *r;\n" n;
2679             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2680               name;
2681             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2682               name
2683       );
2684
2685       (* Free the args. *)
2686       (match snd style with
2687        | [] ->
2688            pr "done: ;\n";
2689        | _ ->
2690            pr "done:\n";
2691            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2692              name
2693       );
2694
2695       pr "}\n\n";
2696   ) daemon_functions;
2697
2698   (* Dispatch function. *)
2699   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2700   pr "{\n";
2701   pr "  switch (proc_nr) {\n";
2702
2703   List.iter (
2704     fun (name, style, _, _, _, _, _) ->
2705         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
2706         pr "      %s_stub (xdr_in);\n" name;
2707         pr "      break;\n"
2708   ) daemon_functions;
2709
2710   pr "    default:\n";
2711   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2712   pr "  }\n";
2713   pr "}\n";
2714   pr "\n";
2715
2716   (* LVM columns and tokenization functions. *)
2717   (* XXX This generates crap code.  We should rethink how we
2718    * do this parsing.
2719    *)
2720   List.iter (
2721     function
2722     | typ, cols ->
2723         pr "static const char *lvm_%s_cols = \"%s\";\n"
2724           typ (String.concat "," (List.map fst cols));
2725         pr "\n";
2726
2727         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2728         pr "{\n";
2729         pr "  char *tok, *p, *next;\n";
2730         pr "  int i, j;\n";
2731         pr "\n";
2732         (*
2733         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2734         pr "\n";
2735         *)
2736         pr "  if (!str) {\n";
2737         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2738         pr "    return -1;\n";
2739         pr "  }\n";
2740         pr "  if (!*str || isspace (*str)) {\n";
2741         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2742         pr "    return -1;\n";
2743         pr "  }\n";
2744         pr "  tok = str;\n";
2745         List.iter (
2746           fun (name, coltype) ->
2747             pr "  if (!tok) {\n";
2748             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2749             pr "    return -1;\n";
2750             pr "  }\n";
2751             pr "  p = strchrnul (tok, ',');\n";
2752             pr "  if (*p) next = p+1; else next = NULL;\n";
2753             pr "  *p = '\\0';\n";
2754             (match coltype with
2755              | `String ->
2756                  pr "  r->%s = strdup (tok);\n" name;
2757                  pr "  if (r->%s == NULL) {\n" name;
2758                  pr "    perror (\"strdup\");\n";
2759                  pr "    return -1;\n";
2760                  pr "  }\n"
2761              | `UUID ->
2762                  pr "  for (i = j = 0; i < 32; ++j) {\n";
2763                  pr "    if (tok[j] == '\\0') {\n";
2764                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2765                  pr "      return -1;\n";
2766                  pr "    } else if (tok[j] != '-')\n";
2767                  pr "      r->%s[i++] = tok[j];\n" name;
2768                  pr "  }\n";
2769              | `Bytes ->
2770                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2771                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2772                  pr "    return -1;\n";
2773                  pr "  }\n";
2774              | `Int ->
2775                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2776                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2777                  pr "    return -1;\n";
2778                  pr "  }\n";
2779              | `OptPercent ->
2780                  pr "  if (tok[0] == '\\0')\n";
2781                  pr "    r->%s = -1;\n" name;
2782                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2783                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2784                  pr "    return -1;\n";
2785                  pr "  }\n";
2786             );
2787             pr "  tok = next;\n";
2788         ) cols;
2789
2790         pr "  if (tok != NULL) {\n";
2791         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2792         pr "    return -1;\n";
2793         pr "  }\n";
2794         pr "  return 0;\n";
2795         pr "}\n";
2796         pr "\n";
2797
2798         pr "guestfs_lvm_int_%s_list *\n" typ;
2799         pr "parse_command_line_%ss (void)\n" typ;
2800         pr "{\n";
2801         pr "  char *out, *err;\n";
2802         pr "  char *p, *pend;\n";
2803         pr "  int r, i;\n";
2804         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
2805         pr "  void *newp;\n";
2806         pr "\n";
2807         pr "  ret = malloc (sizeof *ret);\n";
2808         pr "  if (!ret) {\n";
2809         pr "    reply_with_perror (\"malloc\");\n";
2810         pr "    return NULL;\n";
2811         pr "  }\n";
2812         pr "\n";
2813         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2814         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2815         pr "\n";
2816         pr "  r = command (&out, &err,\n";
2817         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
2818         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2819         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2820         pr "  if (r == -1) {\n";
2821         pr "    reply_with_error (\"%%s\", err);\n";
2822         pr "    free (out);\n";
2823         pr "    free (err);\n";
2824         pr "    free (ret);\n";
2825         pr "    return NULL;\n";
2826         pr "  }\n";
2827         pr "\n";
2828         pr "  free (err);\n";
2829         pr "\n";
2830         pr "  /* Tokenize each line of the output. */\n";
2831         pr "  p = out;\n";
2832         pr "  i = 0;\n";
2833         pr "  while (p) {\n";
2834         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
2835         pr "    if (pend) {\n";
2836         pr "      *pend = '\\0';\n";
2837         pr "      pend++;\n";
2838         pr "    }\n";
2839         pr "\n";
2840         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
2841         pr "      p++;\n";
2842         pr "\n";
2843         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
2844         pr "      p = pend;\n";
2845         pr "      continue;\n";
2846         pr "    }\n";
2847         pr "\n";
2848         pr "    /* Allocate some space to store this next entry. */\n";
2849         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2850         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2851         pr "    if (newp == NULL) {\n";
2852         pr "      reply_with_perror (\"realloc\");\n";
2853         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2854         pr "      free (ret);\n";
2855         pr "      free (out);\n";
2856         pr "      return NULL;\n";
2857         pr "    }\n";
2858         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2859         pr "\n";
2860         pr "    /* Tokenize the next entry. */\n";
2861         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2862         pr "    if (r == -1) {\n";
2863         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2864         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2865         pr "      free (ret);\n";
2866         pr "      free (out);\n";
2867         pr "      return NULL;\n";
2868         pr "    }\n";
2869         pr "\n";
2870         pr "    ++i;\n";
2871         pr "    p = pend;\n";
2872         pr "  }\n";
2873         pr "\n";
2874         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2875         pr "\n";
2876         pr "  free (out);\n";
2877         pr "  return ret;\n";
2878         pr "}\n"
2879
2880   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2881
2882 (* Generate the tests. *)
2883 and generate_tests () =
2884   generate_header CStyle GPLv2;
2885
2886   pr "\
2887 #include <stdio.h>
2888 #include <stdlib.h>
2889 #include <string.h>
2890 #include <unistd.h>
2891 #include <sys/types.h>
2892 #include <fcntl.h>
2893
2894 #include \"guestfs.h\"
2895
2896 static guestfs_h *g;
2897 static int suppress_error = 0;
2898
2899 static void print_error (guestfs_h *g, void *data, const char *msg)
2900 {
2901   if (!suppress_error)
2902     fprintf (stderr, \"%%s\\n\", msg);
2903 }
2904
2905 static void print_strings (char * const * const argv)
2906 {
2907   int argc;
2908
2909   for (argc = 0; argv[argc] != NULL; ++argc)
2910     printf (\"\\t%%s\\n\", argv[argc]);
2911 }
2912
2913 /*
2914 static void print_table (char * const * const argv)
2915 {
2916   int i;
2917
2918   for (i = 0; argv[i] != NULL; i += 2)
2919     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
2920 }
2921 */
2922
2923 static void no_test_warnings (void)
2924 {
2925 ";
2926
2927   List.iter (
2928     function
2929     | name, _, _, _, [], _, _ ->
2930         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
2931     | name, _, _, _, tests, _, _ -> ()
2932   ) all_functions;
2933
2934   pr "}\n";
2935   pr "\n";
2936
2937   (* Generate the actual tests.  Note that we generate the tests
2938    * in reverse order, deliberately, so that (in general) the
2939    * newest tests run first.  This makes it quicker and easier to
2940    * debug them.
2941    *)
2942   let test_names =
2943     List.map (
2944       fun (name, _, _, _, tests, _, _) ->
2945         mapi (generate_one_test name) tests
2946     ) (List.rev all_functions) in
2947   let test_names = List.concat test_names in
2948   let nr_tests = List.length test_names in
2949
2950   pr "\
2951 int main (int argc, char *argv[])
2952 {
2953   char c = 0;
2954   int failed = 0;
2955   const char *srcdir;
2956   const char *filename;
2957   int fd;
2958   int nr_tests, test_num = 0;
2959
2960   no_test_warnings ();
2961
2962   g = guestfs_create ();
2963   if (g == NULL) {
2964     printf (\"guestfs_create FAILED\\n\");
2965     exit (1);
2966   }
2967
2968   guestfs_set_error_handler (g, print_error, NULL);
2969
2970   srcdir = getenv (\"srcdir\");
2971   if (!srcdir) srcdir = \".\";
2972   chdir (srcdir);
2973   guestfs_set_path (g, \".\");
2974
2975   filename = \"test1.img\";
2976   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2977   if (fd == -1) {
2978     perror (filename);
2979     exit (1);
2980   }
2981   if (lseek (fd, %d, SEEK_SET) == -1) {
2982     perror (\"lseek\");
2983     close (fd);
2984     unlink (filename);
2985     exit (1);
2986   }
2987   if (write (fd, &c, 1) == -1) {
2988     perror (\"write\");
2989     close (fd);
2990     unlink (filename);
2991     exit (1);
2992   }
2993   if (close (fd) == -1) {
2994     perror (filename);
2995     unlink (filename);
2996     exit (1);
2997   }
2998   if (guestfs_add_drive (g, filename) == -1) {
2999     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3000     exit (1);
3001   }
3002
3003   filename = \"test2.img\";
3004   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3005   if (fd == -1) {
3006     perror (filename);
3007     exit (1);
3008   }
3009   if (lseek (fd, %d, SEEK_SET) == -1) {
3010     perror (\"lseek\");
3011     close (fd);
3012     unlink (filename);
3013     exit (1);
3014   }
3015   if (write (fd, &c, 1) == -1) {
3016     perror (\"write\");
3017     close (fd);
3018     unlink (filename);
3019     exit (1);
3020   }
3021   if (close (fd) == -1) {
3022     perror (filename);
3023     unlink (filename);
3024     exit (1);
3025   }
3026   if (guestfs_add_drive (g, filename) == -1) {
3027     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3028     exit (1);
3029   }
3030
3031   filename = \"test3.img\";
3032   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
3033   if (fd == -1) {
3034     perror (filename);
3035     exit (1);
3036   }
3037   if (lseek (fd, %d, SEEK_SET) == -1) {
3038     perror (\"lseek\");
3039     close (fd);
3040     unlink (filename);
3041     exit (1);
3042   }
3043   if (write (fd, &c, 1) == -1) {
3044     perror (\"write\");
3045     close (fd);
3046     unlink (filename);
3047     exit (1);
3048   }
3049   if (close (fd) == -1) {
3050     perror (filename);
3051     unlink (filename);
3052     exit (1);
3053   }
3054   if (guestfs_add_drive (g, filename) == -1) {
3055     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
3056     exit (1);
3057   }
3058
3059   if (guestfs_launch (g) == -1) {
3060     printf (\"guestfs_launch FAILED\\n\");
3061     exit (1);
3062   }
3063   if (guestfs_wait_ready (g) == -1) {
3064     printf (\"guestfs_wait_ready FAILED\\n\");
3065     exit (1);
3066   }
3067
3068   nr_tests = %d;
3069
3070 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
3071
3072   iteri (
3073     fun i test_name ->
3074       pr "  test_num++;\n";
3075       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
3076       pr "  if (%s () == -1) {\n" test_name;
3077       pr "    printf (\"%s FAILED\\n\");\n" test_name;
3078       pr "    failed++;\n";
3079       pr "  }\n";
3080   ) test_names;
3081   pr "\n";
3082
3083   pr "  guestfs_close (g);\n";
3084   pr "  unlink (\"test1.img\");\n";
3085   pr "  unlink (\"test2.img\");\n";
3086   pr "  unlink (\"test3.img\");\n";
3087   pr "\n";
3088
3089   pr "  if (failed > 0) {\n";
3090   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
3091   pr "    exit (1);\n";
3092   pr "  }\n";
3093   pr "\n";
3094
3095   pr "  exit (0);\n";
3096   pr "}\n"
3097
3098 and generate_one_test name i (init, test) =
3099   let test_name = sprintf "test_%s_%d" name i in
3100
3101   pr "static int %s (void)\n" test_name;
3102   pr "{\n";
3103
3104   (match init with
3105    | InitNone -> ()
3106    | InitEmpty ->
3107        pr "  /* InitEmpty for %s (%d) */\n" name i;
3108        List.iter (generate_test_command_call test_name)
3109          [["umount_all"];
3110           ["lvm_remove_all"]]
3111    | InitBasicFS ->
3112        pr "  /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
3113        List.iter (generate_test_command_call test_name)
3114          [["umount_all"];
3115           ["lvm_remove_all"];
3116           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3117           ["mkfs"; "ext2"; "/dev/sda1"];
3118           ["mount"; "/dev/sda1"; "/"]]
3119    | InitBasicFSonLVM ->
3120        pr "  /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
3121          name i;
3122        List.iter (generate_test_command_call test_name)
3123          [["umount_all"];
3124           ["lvm_remove_all"];
3125           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
3126           ["pvcreate"; "/dev/sda1"];
3127           ["vgcreate"; "VG"; "/dev/sda1"];
3128           ["lvcreate"; "LV"; "VG"; "8"];
3129           ["mkfs"; "ext2"; "/dev/VG/LV"];
3130           ["mount"; "/dev/VG/LV"; "/"]]
3131   );
3132
3133   let get_seq_last = function
3134     | [] ->
3135         failwithf "%s: you cannot use [] (empty list) when expecting a command"
3136           test_name
3137     | seq ->
3138         let seq = List.rev seq in
3139         List.rev (List.tl seq), List.hd seq
3140   in
3141
3142   (match test with
3143    | TestRun seq ->
3144        pr "  /* TestRun for %s (%d) */\n" name i;
3145        List.iter (generate_test_command_call test_name) seq
3146    | TestOutput (seq, expected) ->
3147        pr "  /* TestOutput for %s (%d) */\n" name i;
3148        let seq, last = get_seq_last seq in
3149        let test () =
3150          pr "    if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
3151          pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
3152          pr "      return -1;\n";
3153          pr "    }\n"
3154        in
3155        List.iter (generate_test_command_call test_name) seq;
3156        generate_test_command_call ~test test_name last
3157    | TestOutputList (seq, expected) ->
3158        pr "  /* TestOutputList for %s (%d) */\n" name i;
3159        let seq, last = get_seq_last seq in
3160        let test () =
3161          iteri (
3162            fun i str ->
3163              pr "    if (!r[%d]) {\n" i;
3164              pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
3165              pr "      print_strings (r);\n";
3166              pr "      return -1;\n";
3167              pr "    }\n";
3168              pr "    if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
3169              pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
3170              pr "      return -1;\n";
3171              pr "    }\n"
3172          ) expected;
3173          pr "    if (r[%d] != NULL) {\n" (List.length expected);
3174          pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
3175            test_name;
3176          pr "      print_strings (r);\n";
3177          pr "      return -1;\n";
3178          pr "    }\n"
3179        in
3180        List.iter (generate_test_command_call test_name) seq;
3181        generate_test_command_call ~test test_name last
3182    | TestOutputInt (seq, expected) ->
3183        pr "  /* TestOutputInt for %s (%d) */\n" name i;
3184        let seq, last = get_seq_last seq in
3185        let test () =
3186          pr "    if (r != %d) {\n" expected;
3187          pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
3188            test_name expected;
3189          pr "               (int) r);\n";
3190          pr "      return -1;\n";
3191          pr "    }\n"
3192        in
3193        List.iter (generate_test_command_call test_name) seq;
3194        generate_test_command_call ~test test_name last
3195    | TestOutputTrue seq ->
3196        pr "  /* TestOutputTrue for %s (%d) */\n" name i;
3197        let seq, last = get_seq_last seq in
3198        let test () =
3199          pr "    if (!r) {\n";
3200          pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
3201            test_name;
3202          pr "      return -1;\n";
3203          pr "    }\n"
3204        in
3205        List.iter (generate_test_command_call test_name) seq;
3206        generate_test_command_call ~test test_name last
3207    | TestOutputFalse seq ->
3208        pr "  /* TestOutputFalse for %s (%d) */\n" name i;
3209        let seq, last = get_seq_last seq in
3210        let test () =
3211          pr "    if (r) {\n";
3212          pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
3213            test_name;
3214          pr "      return -1;\n";
3215          pr "    }\n"
3216        in
3217        List.iter (generate_test_command_call test_name) seq;
3218        generate_test_command_call ~test test_name last
3219    | TestOutputLength (seq, expected) ->
3220        pr "  /* TestOutputLength for %s (%d) */\n" name i;
3221        let seq, last = get_seq_last seq in
3222        let test () =
3223          pr "    int j;\n";
3224          pr "    for (j = 0; j < %d; ++j)\n" expected;
3225          pr "      if (r[j] == NULL) {\n";
3226          pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
3227            test_name;
3228          pr "        print_strings (r);\n";
3229          pr "        return -1;\n";
3230          pr "      }\n";
3231          pr "    if (r[j] != NULL) {\n";
3232          pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
3233            test_name;
3234          pr "      print_strings (r);\n";
3235          pr "      return -1;\n";
3236          pr "    }\n"
3237        in
3238        List.iter (generate_test_command_call test_name) seq;
3239        generate_test_command_call ~test test_name last
3240    | TestOutputStruct (seq, checks) ->
3241        pr "  /* TestOutputStruct for %s (%d) */\n" name i;
3242        let seq, last = get_seq_last seq in
3243        let test () =
3244          List.iter (
3245            function
3246            | CompareWithInt (field, expected) ->
3247                pr "    if (r->%s != %d) {\n" field expected;
3248                pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
3249                  test_name field expected;
3250                pr "               (int) r->%s);\n" field;
3251                pr "      return -1;\n";
3252                pr "    }\n"
3253            | CompareWithString (field, expected) ->
3254                pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
3255                pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
3256                  test_name field expected;
3257                pr "               r->%s);\n" field;
3258                pr "      return -1;\n";
3259                pr "    }\n"
3260            | CompareFieldsIntEq (field1, field2) ->
3261                pr "    if (r->%s != r->%s) {\n" field1 field2;
3262                pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
3263                  test_name field1 field2;
3264                pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
3265                pr "      return -1;\n";
3266                pr "    }\n"
3267            | CompareFieldsStrEq (field1, field2) ->
3268                pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
3269                pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
3270                  test_name field1 field2;
3271                pr "               r->%s, r->%s);\n" field1 field2;
3272                pr "      return -1;\n";
3273                pr "    }\n"
3274          ) checks
3275        in
3276        List.iter (generate_test_command_call test_name) seq;
3277        generate_test_command_call ~test test_name last
3278    | TestLastFail seq ->
3279        pr "  /* TestLastFail for %s (%d) */\n" name i;
3280        let seq, last = get_seq_last seq in
3281        List.iter (generate_test_command_call test_name) seq;
3282        generate_test_command_call test_name ~expect_error:true last
3283   );
3284
3285   pr "  return 0;\n";
3286   pr "}\n";
3287   pr "\n";
3288   test_name
3289
3290 (* Generate the code to run a command, leaving the result in 'r'.
3291  * If you expect to get an error then you should set expect_error:true.
3292  *)
3293 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
3294   match cmd with
3295   | [] -> assert false
3296   | name :: args ->
3297       (* Look up the command to find out what args/ret it has. *)
3298       let style =
3299         try
3300           let _, style, _, _, _, _, _ =
3301             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
3302           style
3303         with Not_found ->
3304           failwithf "%s: in test, command %s was not found" test_name name in
3305
3306       if List.length (snd style) <> List.length args then
3307         failwithf "%s: in test, wrong number of args given to %s"
3308           test_name name;
3309
3310       pr "  {\n";
3311
3312       List.iter (
3313         function
3314         | String _, _
3315         | OptString _, _
3316         | Int _, _
3317         | Bool _, _ -> ()
3318         | FileIn _, _ | FileOut _, _ -> ()
3319         | StringList n, arg ->
3320             pr "    char *%s[] = {\n" n;
3321             let strs = string_split " " arg in
3322             List.iter (
3323               fun str -> pr "      \"%s\",\n" (c_quote str)
3324             ) strs;
3325             pr "      NULL\n";
3326             pr "    };\n";
3327       ) (List.combine (snd style) args);
3328
3329       let error_code =
3330         match fst style with
3331         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
3332         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
3333         | RConstString _ -> pr "    const char *r;\n"; "NULL"
3334         | RString _ -> pr "    char *r;\n"; "NULL"
3335         | RStringList _ | RHashtable _ ->
3336             pr "    char **r;\n";
3337             pr "    int i;\n";
3338             "NULL"
3339         | RIntBool _ ->
3340             pr "    struct guestfs_int_bool *r;\n"; "NULL"
3341         | RPVList _ ->
3342             pr "    struct guestfs_lvm_pv_list *r;\n"; "NULL"
3343         | RVGList _ ->
3344             pr "    struct guestfs_lvm_vg_list *r;\n"; "NULL"
3345         | RLVList _ ->
3346             pr "    struct guestfs_lvm_lv_list *r;\n"; "NULL"
3347         | RStat _ ->
3348             pr "    struct guestfs_stat *r;\n"; "NULL"
3349         | RStatVFS _ ->
3350             pr "    struct guestfs_statvfs *r;\n"; "NULL" in
3351
3352       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
3353       pr "    r = guestfs_%s (g" name;
3354
3355       (* Generate the parameters. *)
3356       List.iter (
3357         function
3358         | String _, arg
3359         | FileIn _, arg | FileOut _, arg ->
3360             pr ", \"%s\"" (c_quote arg)
3361         | OptString _, arg ->
3362             if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
3363         | StringList n, _ ->
3364             pr ", %s" n
3365         | Int _, arg ->
3366             let i =
3367               try int_of_string arg
3368               with Failure "int_of_string" ->
3369                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
3370             pr ", %d" i
3371         | Bool _, arg ->
3372             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
3373       ) (List.combine (snd style) args);
3374
3375       pr ");\n";
3376       if not expect_error then
3377         pr "    if (r == %s)\n" error_code
3378       else
3379         pr "    if (r != %s)\n" error_code;
3380       pr "      return -1;\n";
3381
3382       (* Insert the test code. *)
3383       (match test with
3384        | None -> ()
3385        | Some f -> f ()
3386       );
3387
3388       (match fst style with
3389        | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
3390        | RString _ -> pr "    free (r);\n"
3391        | RStringList _ | RHashtable _ ->
3392            pr "    for (i = 0; r[i] != NULL; ++i)\n";
3393            pr "      free (r[i]);\n";
3394            pr "    free (r);\n"
3395        | RIntBool _ ->
3396            pr "    guestfs_free_int_bool (r);\n"
3397        | RPVList _ ->
3398            pr "    guestfs_free_lvm_pv_list (r);\n"
3399        | RVGList _ ->
3400            pr "    guestfs_free_lvm_vg_list (r);\n"
3401        | RLVList _ ->
3402            pr "    guestfs_free_lvm_lv_list (r);\n"
3403        | RStat _ | RStatVFS _ ->
3404            pr "    free (r);\n"
3405       );
3406
3407       pr "  }\n"
3408
3409 and c_quote str =
3410   let str = replace_str str "\r" "\\r" in
3411   let str = replace_str str "\n" "\\n" in
3412   let str = replace_str str "\t" "\\t" in
3413   str
3414
3415 (* Generate a lot of different functions for guestfish. *)
3416 and generate_fish_cmds () =
3417   generate_header CStyle GPLv2;
3418
3419   let all_functions =
3420     List.filter (
3421       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3422     ) all_functions in
3423   let all_functions_sorted =
3424     List.filter (
3425       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3426     ) all_functions_sorted in
3427
3428   pr "#include <stdio.h>\n";
3429   pr "#include <stdlib.h>\n";
3430   pr "#include <string.h>\n";
3431   pr "#include <inttypes.h>\n";
3432   pr "\n";
3433   pr "#include <guestfs.h>\n";
3434   pr "#include \"fish.h\"\n";
3435   pr "\n";
3436
3437   (* list_commands function, which implements guestfish -h *)
3438   pr "void list_commands (void)\n";
3439   pr "{\n";
3440   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
3441   pr "  list_builtin_commands ();\n";
3442   List.iter (
3443     fun (name, _, _, flags, _, shortdesc, _) ->
3444       let name = replace_char name '_' '-' in
3445       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
3446         name shortdesc
3447   ) all_functions_sorted;
3448   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
3449   pr "}\n";
3450   pr "\n";
3451
3452   (* display_command function, which implements guestfish -h cmd *)
3453   pr "void display_command (const char *cmd)\n";
3454   pr "{\n";
3455   List.iter (
3456     fun (name, style, _, flags, _, shortdesc, longdesc) ->
3457       let name2 = replace_char name '_' '-' in
3458       let alias =
3459         try find_map (function FishAlias n -> Some n | _ -> None) flags
3460         with Not_found -> name in
3461       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3462       let synopsis =
3463         match snd style with
3464         | [] -> name2
3465         | args ->
3466             sprintf "%s <%s>"
3467               name2 (String.concat "> <" (List.map name_of_argt args)) in
3468
3469       let warnings =
3470         if List.mem ProtocolLimitWarning flags then
3471           ("\n\n" ^ protocol_limit_warning)
3472         else "" in
3473
3474       (* For DangerWillRobinson commands, we should probably have
3475        * guestfish prompt before allowing you to use them (especially
3476        * in interactive mode). XXX
3477        *)
3478       let warnings =
3479         warnings ^
3480           if List.mem DangerWillRobinson flags then
3481             ("\n\n" ^ danger_will_robinson)
3482           else "" in
3483
3484       let describe_alias =
3485         if name <> alias then
3486           sprintf "\n\nYou can use '%s' as an alias for this command." alias
3487         else "" in
3488
3489       pr "  if (";
3490       pr "strcasecmp (cmd, \"%s\") == 0" name;
3491       if name <> name2 then
3492         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3493       if name <> alias then
3494         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3495       pr ")\n";
3496       pr "    pod2text (\"%s - %s\", %S);\n"
3497         name2 shortdesc
3498         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
3499       pr "  else\n"
3500   ) all_functions;
3501   pr "    display_builtin_command (cmd);\n";
3502   pr "}\n";
3503   pr "\n";
3504
3505   (* print_{pv,vg,lv}_list functions *)
3506   List.iter (
3507     function
3508     | typ, cols ->
3509         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
3510         pr "{\n";
3511         pr "  int i;\n";
3512         pr "\n";
3513         List.iter (
3514           function
3515           | name, `String ->
3516               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
3517           | name, `UUID ->
3518               pr "  printf (\"%s: \");\n" name;
3519               pr "  for (i = 0; i < 32; ++i)\n";
3520               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
3521               pr "  printf (\"\\n\");\n"
3522           | name, `Bytes ->
3523               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
3524           | name, `Int ->
3525               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3526           | name, `OptPercent ->
3527               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
3528                 typ name name typ name;
3529               pr "  else printf (\"%s: \\n\");\n" name
3530         ) cols;
3531         pr "}\n";
3532         pr "\n";
3533         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
3534           typ typ typ;
3535         pr "{\n";
3536         pr "  int i;\n";
3537         pr "\n";
3538         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
3539         pr "    print_%s (&%ss->val[i]);\n" typ typ;
3540         pr "}\n";
3541         pr "\n";
3542   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3543
3544   (* print_{stat,statvfs} functions *)
3545   List.iter (
3546     function
3547     | typ, cols ->
3548         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
3549         pr "{\n";
3550         List.iter (
3551           function
3552           | name, `Int ->
3553               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3554         ) cols;
3555         pr "}\n";
3556         pr "\n";
3557   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3558
3559   (* run_<action> actions *)
3560   List.iter (
3561     fun (name, style, _, flags, _, _, _) ->
3562       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
3563       pr "{\n";
3564       (match fst style with
3565        | RErr
3566        | RInt _
3567        | RBool _ -> pr "  int r;\n"
3568        | RInt64 _ -> pr "  int64_t r;\n"
3569        | RConstString _ -> pr "  const char *r;\n"
3570        | RString _ -> pr "  char *r;\n"
3571        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
3572        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
3573        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
3574        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
3575        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
3576        | RStat _ -> pr "  struct guestfs_stat *r;\n"
3577        | RStatVFS _ -> pr "  struct guestfs_statvfs *r;\n"
3578       );
3579       List.iter (
3580         function
3581         | String n
3582         | OptString n
3583         | FileIn n
3584         | FileOut n -> pr "  const char *%s;\n" n
3585         | StringList n -> pr "  char **%s;\n" n
3586         | Bool n -> pr "  int %s;\n" n
3587         | Int n -> pr "  int %s;\n" n
3588       ) (snd style);
3589
3590       (* Check and convert parameters. *)
3591       let argc_expected = List.length (snd style) in
3592       pr "  if (argc != %d) {\n" argc_expected;
3593       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
3594         argc_expected;
3595       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
3596       pr "    return -1;\n";
3597       pr "  }\n";
3598       iteri (
3599         fun i ->
3600           function
3601           | String name -> pr "  %s = argv[%d];\n" name i
3602           | OptString name ->
3603               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
3604                 name i i
3605           | FileIn name ->
3606               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
3607                 name i i
3608           | FileOut name ->
3609               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
3610                 name i i
3611           | StringList name ->
3612               pr "  %s = parse_string_list (argv[%d]);\n" name i
3613           | Bool name ->
3614               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
3615           | Int name ->
3616               pr "  %s = atoi (argv[%d]);\n" name i
3617       ) (snd style);
3618
3619       (* Call C API function. *)
3620       let fn =
3621         try find_map (function FishAction n -> Some n | _ -> None) flags
3622         with Not_found -> sprintf "guestfs_%s" name in
3623       pr "  r = %s " fn;
3624       generate_call_args ~handle:"g" (snd style);
3625       pr ";\n";
3626
3627       (* Check return value for errors and display command results. *)
3628       (match fst style with
3629        | RErr -> pr "  return r;\n"
3630        | RInt _ ->
3631            pr "  if (r == -1) return -1;\n";
3632            pr "  printf (\"%%d\\n\", r);\n";
3633            pr "  return 0;\n"
3634        | RInt64 _ ->
3635            pr "  if (r == -1) return -1;\n";
3636            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
3637            pr "  return 0;\n"
3638        | RBool _ ->
3639            pr "  if (r == -1) return -1;\n";
3640            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
3641            pr "  return 0;\n"
3642        | RConstString _ ->
3643            pr "  if (r == NULL) return -1;\n";
3644            pr "  printf (\"%%s\\n\", r);\n";
3645            pr "  return 0;\n"
3646        | RString _ ->
3647            pr "  if (r == NULL) return -1;\n";
3648            pr "  printf (\"%%s\\n\", r);\n";
3649            pr "  free (r);\n";
3650            pr "  return 0;\n"
3651        | RStringList _ ->
3652            pr "  if (r == NULL) return -1;\n";
3653            pr "  print_strings (r);\n";
3654            pr "  free_strings (r);\n";
3655            pr "  return 0;\n"
3656        | RIntBool _ ->
3657            pr "  if (r == NULL) return -1;\n";
3658            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
3659            pr "    r->b ? \"true\" : \"false\");\n";
3660            pr "  guestfs_free_int_bool (r);\n";
3661            pr "  return 0;\n"
3662        | RPVList _ ->
3663            pr "  if (r == NULL) return -1;\n";
3664            pr "  print_pv_list (r);\n";
3665            pr "  guestfs_free_lvm_pv_list (r);\n";
3666            pr "  return 0;\n"
3667        | RVGList _ ->
3668            pr "  if (r == NULL) return -1;\n";
3669            pr "  print_vg_list (r);\n";
3670            pr "  guestfs_free_lvm_vg_list (r);\n";
3671            pr "  return 0;\n"
3672        | RLVList _ ->
3673            pr "  if (r == NULL) return -1;\n";
3674            pr "  print_lv_list (r);\n";
3675            pr "  guestfs_free_lvm_lv_list (r);\n";
3676            pr "  return 0;\n"
3677        | RStat _ ->
3678            pr "  if (r == NULL) return -1;\n";
3679            pr "  print_stat (r);\n";
3680            pr "  free (r);\n";
3681            pr "  return 0;\n"
3682        | RStatVFS _ ->
3683            pr "  if (r == NULL) return -1;\n";
3684            pr "  print_statvfs (r);\n";
3685            pr "  free (r);\n";
3686            pr "  return 0;\n"
3687        | RHashtable _ ->
3688            pr "  if (r == NULL) return -1;\n";
3689            pr "  print_table (r);\n";
3690            pr "  free_strings (r);\n";
3691            pr "  return 0;\n"
3692       );
3693       pr "}\n";
3694       pr "\n"
3695   ) all_functions;
3696
3697   (* run_action function *)
3698   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3699   pr "{\n";
3700   List.iter (
3701     fun (name, _, _, flags, _, _, _) ->
3702       let name2 = replace_char name '_' '-' in
3703       let alias =
3704         try find_map (function FishAlias n -> Some n | _ -> None) flags
3705         with Not_found -> name in
3706       pr "  if (";
3707       pr "strcasecmp (cmd, \"%s\") == 0" name;
3708       if name <> name2 then
3709         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3710       if name <> alias then
3711         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3712       pr ")\n";
3713       pr "    return run_%s (cmd, argc, argv);\n" name;
3714       pr "  else\n";
3715   ) all_functions;
3716   pr "    {\n";
3717   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3718   pr "      return -1;\n";
3719   pr "    }\n";
3720   pr "  return 0;\n";
3721   pr "}\n";
3722   pr "\n"
3723
3724 (* Readline completion for guestfish. *)
3725 and generate_fish_completion () =
3726   generate_header CStyle GPLv2;
3727
3728   let all_functions =
3729     List.filter (
3730       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3731     ) all_functions in
3732
3733   pr "\
3734 #include <config.h>
3735
3736 #include <stdio.h>
3737 #include <stdlib.h>
3738 #include <string.h>
3739
3740 #ifdef HAVE_LIBREADLINE
3741 #include <readline/readline.h>
3742 #endif
3743
3744 #include \"fish.h\"
3745
3746 #ifdef HAVE_LIBREADLINE
3747
3748 static const char *commands[] = {
3749 ";
3750
3751   (* Get the commands and sort them, including the aliases. *)
3752   let commands =
3753     List.map (
3754       fun (name, _, _, flags, _, _, _) ->
3755         let name2 = replace_char name '_' '-' in
3756         let alias =
3757           try find_map (function FishAlias n -> Some n | _ -> None) flags
3758           with Not_found -> name in
3759
3760         if name <> alias then [name2; alias] else [name2]
3761     ) all_functions in
3762   let commands = List.flatten commands in
3763   let commands = List.sort compare commands in
3764
3765   List.iter (pr "  \"%s\",\n") commands;
3766
3767   pr "  NULL
3768 };
3769
3770 static char *
3771 generator (const char *text, int state)
3772 {
3773   static int index, len;
3774   const char *name;
3775
3776   if (!state) {
3777     index = 0;
3778     len = strlen (text);
3779   }
3780
3781   while ((name = commands[index]) != NULL) {
3782     index++;
3783     if (strncasecmp (name, text, len) == 0)
3784       return strdup (name);
3785   }
3786
3787   return NULL;
3788 }
3789
3790 #endif /* HAVE_LIBREADLINE */
3791
3792 char **do_completion (const char *text, int start, int end)
3793 {
3794   char **matches = NULL;
3795
3796 #ifdef HAVE_LIBREADLINE
3797   if (start == 0)
3798     matches = rl_completion_matches (text, generator);
3799 #endif
3800
3801   return matches;
3802 }
3803 ";
3804
3805 (* Generate the POD documentation for guestfish. *)
3806 and generate_fish_actions_pod () =
3807   let all_functions_sorted =
3808     List.filter (
3809       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3810     ) all_functions_sorted in
3811
3812   List.iter (
3813     fun (name, style, _, flags, _, _, longdesc) ->
3814       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3815       let name = replace_char name '_' '-' in
3816       let alias =
3817         try find_map (function FishAlias n -> Some n | _ -> None) flags
3818         with Not_found -> name in
3819
3820       pr "=head2 %s" name;
3821       if name <> alias then
3822         pr " | %s" alias;
3823       pr "\n";
3824       pr "\n";
3825       pr " %s" name;
3826       List.iter (
3827         function
3828         | String n -> pr " %s" n
3829         | OptString n -> pr " %s" n
3830         | StringList n -> pr " '%s ...'" n
3831         | Bool _ -> pr " true|false"
3832         | Int n -> pr " %s" n
3833         | FileIn n | FileOut n -> pr " (%s|-)" n
3834       ) (snd style);
3835       pr "\n";
3836       pr "\n";
3837       pr "%s\n\n" longdesc;
3838
3839       if List.exists (function FileIn _ | FileOut _ -> true
3840                       | _ -> false) (snd style) then
3841         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
3842
3843       if List.mem ProtocolLimitWarning flags then
3844         pr "%s\n\n" protocol_limit_warning;
3845
3846       if List.mem DangerWillRobinson flags then
3847         pr "%s\n\n" danger_will_robinson
3848   ) all_functions_sorted
3849
3850 (* Generate a C function prototype. *)
3851 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3852     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3853     ?(prefix = "")
3854     ?handle name style =
3855   if extern then pr "extern ";
3856   if static then pr "static ";
3857   (match fst style with
3858    | RErr -> pr "int "
3859    | RInt _ -> pr "int "
3860    | RInt64 _ -> pr "int64_t "
3861    | RBool _ -> pr "int "
3862    | RConstString _ -> pr "const char *"
3863    | RString _ -> pr "char *"
3864    | RStringList _ | RHashtable _ -> pr "char **"
3865    | RIntBool _ ->
3866        if not in_daemon then pr "struct guestfs_int_bool *"
3867        else pr "guestfs_%s_ret *" name
3868    | RPVList _ ->
3869        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3870        else pr "guestfs_lvm_int_pv_list *"
3871    | RVGList _ ->
3872        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3873        else pr "guestfs_lvm_int_vg_list *"
3874    | RLVList _ ->
3875        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3876        else pr "guestfs_lvm_int_lv_list *"
3877    | RStat _ ->
3878        if not in_daemon then pr "struct guestfs_stat *"
3879        else pr "guestfs_int_stat *"
3880    | RStatVFS _ ->
3881        if not in_daemon then pr "struct guestfs_statvfs *"
3882        else pr "guestfs_int_statvfs *"
3883   );
3884   pr "%s%s (" prefix name;
3885   if handle = None && List.length (snd style) = 0 then
3886     pr "void"
3887   else (
3888     let comma = ref false in
3889     (match handle with
3890      | None -> ()
3891      | Some handle -> pr "guestfs_h *%s" handle; comma := true
3892     );
3893     let next () =
3894       if !comma then (
3895         if single_line then pr ", " else pr ",\n\t\t"
3896       );
3897       comma := true
3898     in
3899     List.iter (
3900       function
3901       | String n
3902       | OptString n -> next (); pr "const char *%s" n
3903       | StringList n -> next (); pr "char * const* const %s" n
3904       | Bool n -> next (); pr "int %s" n
3905       | Int n -> next (); pr "int %s" n
3906       | FileIn n
3907       | FileOut n ->
3908           if not in_daemon then (next (); pr "const char *%s" n)
3909     ) (snd style);
3910   );
3911   pr ")";
3912   if semicolon then pr ";";
3913   if newline then pr "\n"
3914
3915 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3916 and generate_call_args ?handle args =
3917   pr "(";
3918   let comma = ref false in
3919   (match handle with
3920    | None -> ()
3921    | Some handle -> pr "%s" handle; comma := true
3922   );
3923   List.iter (
3924     fun arg ->
3925       if !comma then pr ", ";
3926       comma := true;
3927       pr "%s" (name_of_argt arg)
3928   ) args;
3929   pr ")"
3930
3931 (* Generate the OCaml bindings interface. *)
3932 and generate_ocaml_mli () =
3933   generate_header OCamlStyle LGPLv2;
3934
3935   pr "\
3936 (** For API documentation you should refer to the C API
3937     in the guestfs(3) manual page.  The OCaml API uses almost
3938     exactly the same calls. *)
3939
3940 type t
3941 (** A [guestfs_h] handle. *)
3942
3943 exception Error of string
3944 (** This exception is raised when there is an error. *)
3945
3946 val create : unit -> t
3947
3948 val close : t -> unit
3949 (** Handles are closed by the garbage collector when they become
3950     unreferenced, but callers can also call this in order to
3951     provide predictable cleanup. *)
3952
3953 ";
3954   generate_ocaml_lvm_structure_decls ();
3955
3956   generate_ocaml_stat_structure_decls ();
3957
3958   (* The actions. *)
3959   List.iter (
3960     fun (name, style, _, _, _, shortdesc, _) ->
3961       generate_ocaml_prototype name style;
3962       pr "(** %s *)\n" shortdesc;
3963       pr "\n"
3964   ) all_functions
3965
3966 (* Generate the OCaml bindings implementation. *)
3967 and generate_ocaml_ml () =
3968   generate_header OCamlStyle LGPLv2;
3969
3970   pr "\
3971 type t
3972 exception Error of string
3973 external create : unit -> t = \"ocaml_guestfs_create\"
3974 external close : t -> unit = \"ocaml_guestfs_close\"
3975
3976 let () =
3977   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3978
3979 ";
3980
3981   generate_ocaml_lvm_structure_decls ();
3982
3983   generate_ocaml_stat_structure_decls ();
3984
3985   (* The actions. *)
3986   List.iter (
3987     fun (name, style, _, _, _, shortdesc, _) ->
3988       generate_ocaml_prototype ~is_external:true name style;
3989   ) all_functions
3990
3991 (* Generate the OCaml bindings C implementation. *)
3992 and generate_ocaml_c () =
3993   generate_header CStyle LGPLv2;
3994
3995   pr "\
3996 #include <stdio.h>
3997 #include <stdlib.h>
3998 #include <string.h>
3999
4000 #include <caml/config.h>
4001 #include <caml/alloc.h>
4002 #include <caml/callback.h>
4003 #include <caml/fail.h>
4004 #include <caml/memory.h>
4005 #include <caml/mlvalues.h>
4006 #include <caml/signals.h>
4007
4008 #include <guestfs.h>
4009
4010 #include \"guestfs_c.h\"
4011
4012 /* Copy a hashtable of string pairs into an assoc-list.  We return
4013  * the list in reverse order, but hashtables aren't supposed to be
4014  * ordered anyway.
4015  */
4016 static CAMLprim value
4017 copy_table (char * const * argv)
4018 {
4019   CAMLparam0 ();
4020   CAMLlocal5 (rv, pairv, kv, vv, cons);
4021   int i;
4022
4023   rv = Val_int (0);
4024   for (i = 0; argv[i] != NULL; i += 2) {
4025     kv = caml_copy_string (argv[i]);
4026     vv = caml_copy_string (argv[i+1]);
4027     pairv = caml_alloc (2, 0);
4028     Store_field (pairv, 0, kv);
4029     Store_field (pairv, 1, vv);
4030     cons = caml_alloc (2, 0);
4031     Store_field (cons, 1, rv);
4032     rv = cons;
4033     Store_field (cons, 0, pairv);
4034   }
4035
4036   CAMLreturn (rv);
4037 }
4038
4039 ";
4040
4041   (* LVM struct copy functions. *)
4042   List.iter (
4043     fun (typ, cols) ->
4044       let has_optpercent_col =
4045         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
4046
4047       pr "static CAMLprim value\n";
4048       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
4049       pr "{\n";
4050       pr "  CAMLparam0 ();\n";
4051       if has_optpercent_col then
4052         pr "  CAMLlocal3 (rv, v, v2);\n"
4053       else
4054         pr "  CAMLlocal2 (rv, v);\n";
4055       pr "\n";
4056       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
4057       iteri (
4058         fun i col ->
4059           (match col with
4060            | name, `String ->
4061                pr "  v = caml_copy_string (%s->%s);\n" typ name
4062            | name, `UUID ->
4063                pr "  v = caml_alloc_string (32);\n";
4064                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
4065            | name, `Bytes
4066            | name, `Int ->
4067                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
4068            | name, `OptPercent ->
4069                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
4070                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
4071                pr "    v = caml_alloc (1, 0);\n";
4072                pr "    Store_field (v, 0, v2);\n";
4073                pr "  } else /* None */\n";
4074                pr "    v = Val_int (0);\n";
4075           );
4076           pr "  Store_field (rv, %d, v);\n" i
4077       ) cols;
4078       pr "  CAMLreturn (rv);\n";
4079       pr "}\n";
4080       pr "\n";
4081
4082       pr "static CAMLprim value\n";
4083       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
4084         typ typ typ;
4085       pr "{\n";
4086       pr "  CAMLparam0 ();\n";
4087       pr "  CAMLlocal2 (rv, v);\n";
4088       pr "  int i;\n";
4089       pr "\n";
4090       pr "  if (%ss->len == 0)\n" typ;
4091       pr "    CAMLreturn (Atom (0));\n";
4092       pr "  else {\n";
4093       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
4094       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
4095       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
4096       pr "      caml_modify (&Field (rv, i), v);\n";
4097       pr "    }\n";
4098       pr "    CAMLreturn (rv);\n";
4099       pr "  }\n";
4100       pr "}\n";
4101       pr "\n";
4102   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4103
4104   (* Stat copy functions. *)
4105   List.iter (
4106     fun (typ, cols) ->
4107       pr "static CAMLprim value\n";
4108       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
4109       pr "{\n";
4110       pr "  CAMLparam0 ();\n";
4111       pr "  CAMLlocal2 (rv, v);\n";
4112       pr "\n";
4113       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
4114       iteri (
4115         fun i col ->
4116           (match col with
4117            | name, `Int ->
4118                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
4119           );
4120           pr "  Store_field (rv, %d, v);\n" i
4121       ) cols;
4122       pr "  CAMLreturn (rv);\n";
4123       pr "}\n";
4124       pr "\n";
4125   ) ["stat", stat_cols; "statvfs", statvfs_cols];
4126
4127   (* The wrappers. *)
4128   List.iter (
4129     fun (name, style, _, _, _, _, _) ->
4130       let params =
4131         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
4132
4133       pr "CAMLprim value\n";
4134       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
4135       List.iter (pr ", value %s") (List.tl params);
4136       pr ")\n";
4137       pr "{\n";
4138
4139       (match params with
4140        | [p1; p2; p3; p4; p5] ->
4141            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
4142        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
4143            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
4144            pr "  CAMLxparam%d (%s);\n"
4145              (List.length rest) (String.concat ", " rest)
4146        | ps ->
4147            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
4148       );
4149       pr "  CAMLlocal1 (rv);\n";
4150       pr "\n";
4151
4152       pr "  guestfs_h *g = Guestfs_val (gv);\n";
4153       pr "  if (g == NULL)\n";
4154       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
4155       pr "\n";
4156
4157       List.iter (
4158         function
4159         | String n
4160         | FileIn n
4161         | FileOut n ->
4162             pr "  const char *%s = String_val (%sv);\n" n n
4163         | OptString n ->
4164             pr "  const char *%s =\n" n;
4165             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
4166               n n
4167         | StringList n ->
4168             pr "  char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
4169         | Bool n ->
4170             pr "  int %s = Bool_val (%sv);\n" n n
4171         | Int n ->
4172             pr "  int %s = Int_val (%sv);\n" n n
4173       ) (snd style);
4174       let error_code =
4175         match fst style with
4176         | RErr -> pr "  int r;\n"; "-1"
4177         | RInt _ -> pr "  int r;\n"; "-1"
4178         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4179         | RBool _ -> pr "  int r;\n"; "-1"
4180         | RConstString _ -> pr "  const char *r;\n"; "NULL"
4181         | RString _ -> pr "  char *r;\n"; "NULL"
4182         | RStringList _ ->
4183             pr "  int i;\n";
4184             pr "  char **r;\n";
4185             "NULL"
4186         | RIntBool _ ->
4187             pr "  struct guestfs_int_bool *r;\n"; "NULL"
4188         | RPVList _ ->
4189             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
4190         | RVGList _ ->
4191             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
4192         | RLVList _ ->
4193             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
4194         | RStat _ ->
4195             pr "  struct guestfs_stat *r;\n"; "NULL"
4196         | RStatVFS _ ->
4197             pr "  struct guestfs_statvfs *r;\n"; "NULL"
4198         | RHashtable _ ->
4199             pr "  int i;\n";
4200             pr "  char **r;\n";
4201             "NULL" in
4202       pr "\n";
4203
4204       pr "  caml_enter_blocking_section ();\n";
4205       pr "  r = guestfs_%s " name;
4206       generate_call_args ~handle:"g" (snd style);
4207       pr ";\n";
4208       pr "  caml_leave_blocking_section ();\n";
4209
4210       List.iter (
4211         function
4212         | StringList n ->
4213             pr "  ocaml_guestfs_free_strings (%s);\n" n;
4214         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
4215       ) (snd style);
4216
4217       pr "  if (r == %s)\n" error_code;
4218       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
4219       pr "\n";
4220
4221       (match fst style with
4222        | RErr -> pr "  rv = Val_unit;\n"
4223        | RInt _ -> pr "  rv = Val_int (r);\n"
4224        | RInt64 _ ->
4225            pr "  rv = caml_copy_int64 (r);\n"
4226        | RBool _ -> pr "  rv = Val_bool (r);\n"
4227        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
4228        | RString _ ->
4229            pr "  rv = caml_copy_string (r);\n";
4230            pr "  free (r);\n"
4231        | RStringList _ ->
4232            pr "  rv = caml_copy_string_array ((const char **) r);\n";
4233            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4234            pr "  free (r);\n"
4235        | RIntBool _ ->
4236            pr "  rv = caml_alloc (2, 0);\n";
4237            pr "  Store_field (rv, 0, Val_int (r->i));\n";
4238            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
4239            pr "  guestfs_free_int_bool (r);\n";
4240        | RPVList _ ->
4241            pr "  rv = copy_lvm_pv_list (r);\n";
4242            pr "  guestfs_free_lvm_pv_list (r);\n";
4243        | RVGList _ ->
4244            pr "  rv = copy_lvm_vg_list (r);\n";
4245            pr "  guestfs_free_lvm_vg_list (r);\n";
4246        | RLVList _ ->
4247            pr "  rv = copy_lvm_lv_list (r);\n";
4248            pr "  guestfs_free_lvm_lv_list (r);\n";
4249        | RStat _ ->
4250            pr "  rv = copy_stat (r);\n";
4251            pr "  free (r);\n";
4252        | RStatVFS _ ->
4253            pr "  rv = copy_statvfs (r);\n";
4254            pr "  free (r);\n";
4255        | RHashtable _ ->
4256            pr "  rv = copy_table (r);\n";
4257            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4258            pr "  free (r);\n";
4259       );
4260
4261       pr "  CAMLreturn (rv);\n";
4262       pr "}\n";
4263       pr "\n";
4264
4265       if List.length params > 5 then (
4266         pr "CAMLprim value\n";
4267         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
4268         pr "{\n";
4269         pr "  return ocaml_guestfs_%s (argv[0]" name;
4270         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
4271         pr ");\n";
4272         pr "}\n";
4273         pr "\n"
4274       )
4275   ) all_functions
4276
4277 and generate_ocaml_lvm_structure_decls () =
4278   List.iter (
4279     fun (typ, cols) ->
4280       pr "type lvm_%s = {\n" typ;
4281       List.iter (
4282         function
4283         | name, `String -> pr "  %s : string;\n" name
4284         | name, `UUID -> pr "  %s : string;\n" name
4285         | name, `Bytes -> pr "  %s : int64;\n" name
4286         | name, `Int -> pr "  %s : int64;\n" name
4287         | name, `OptPercent -> pr "  %s : float option;\n" name
4288       ) cols;
4289       pr "}\n";
4290       pr "\n"
4291   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4292
4293 and generate_ocaml_stat_structure_decls () =
4294   List.iter (
4295     fun (typ, cols) ->
4296       pr "type %s = {\n" typ;
4297       List.iter (
4298         function
4299         | name, `Int -> pr "  %s : int64;\n" name
4300       ) cols;
4301       pr "}\n";
4302       pr "\n"
4303   ) ["stat", stat_cols; "statvfs", statvfs_cols]
4304
4305 and generate_ocaml_prototype ?(is_external = false) name style =
4306   if is_external then pr "external " else pr "val ";
4307   pr "%s : t -> " name;
4308   List.iter (
4309     function
4310     | String _ | FileIn _ | FileOut _ -> pr "string -> "
4311     | OptString _ -> pr "string option -> "
4312     | StringList _ -> pr "string array -> "
4313     | Bool _ -> pr "bool -> "
4314     | Int _ -> pr "int -> "
4315   ) (snd style);
4316   (match fst style with
4317    | RErr -> pr "unit" (* all errors are turned into exceptions *)
4318    | RInt _ -> pr "int"
4319    | RInt64 _ -> pr "int64"
4320    | RBool _ -> pr "bool"
4321    | RConstString _ -> pr "string"
4322    | RString _ -> pr "string"
4323    | RStringList _ -> pr "string array"
4324    | RIntBool _ -> pr "int * bool"
4325    | RPVList _ -> pr "lvm_pv array"
4326    | RVGList _ -> pr "lvm_vg array"
4327    | RLVList _ -> pr "lvm_lv array"
4328    | RStat _ -> pr "stat"
4329    | RStatVFS _ -> pr "statvfs"
4330    | RHashtable _ -> pr "(string * string) list"
4331   );
4332   if is_external then (
4333     pr " = ";
4334     if List.length (snd style) + 1 > 5 then
4335       pr "\"ocaml_guestfs_%s_byte\" " name;
4336     pr "\"ocaml_guestfs_%s\"" name
4337   );
4338   pr "\n"
4339
4340 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
4341 and generate_perl_xs () =
4342   generate_header CStyle LGPLv2;
4343
4344   pr "\
4345 #include \"EXTERN.h\"
4346 #include \"perl.h\"
4347 #include \"XSUB.h\"
4348
4349 #include <guestfs.h>
4350
4351 #ifndef PRId64
4352 #define PRId64 \"lld\"
4353 #endif
4354
4355 static SV *
4356 my_newSVll(long long val) {
4357 #ifdef USE_64_BIT_ALL
4358   return newSViv(val);
4359 #else
4360   char buf[100];
4361   int len;
4362   len = snprintf(buf, 100, \"%%\" PRId64, val);
4363   return newSVpv(buf, len);
4364 #endif
4365 }
4366
4367 #ifndef PRIu64
4368 #define PRIu64 \"llu\"
4369 #endif
4370
4371 static SV *
4372 my_newSVull(unsigned long long val) {
4373 #ifdef USE_64_BIT_ALL
4374   return newSVuv(val);
4375 #else
4376   char buf[100];
4377   int len;
4378   len = snprintf(buf, 100, \"%%\" PRIu64, val);
4379   return newSVpv(buf, len);
4380 #endif
4381 }
4382
4383 /* http://www.perlmonks.org/?node_id=680842 */
4384 static char **
4385 XS_unpack_charPtrPtr (SV *arg) {
4386   char **ret;
4387   AV *av;
4388   I32 i;
4389
4390   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
4391     croak (\"array reference expected\");
4392   }
4393
4394   av = (AV *)SvRV (arg);
4395   ret = (char **)malloc (av_len (av) + 1 + 1);
4396
4397   for (i = 0; i <= av_len (av); i++) {
4398     SV **elem = av_fetch (av, i, 0);
4399
4400     if (!elem || !*elem)
4401       croak (\"missing element in list\");
4402
4403     ret[i] = SvPV_nolen (*elem);
4404   }
4405
4406   ret[i] = NULL;
4407
4408   return ret;
4409 }
4410
4411 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
4412
4413 guestfs_h *
4414 _create ()
4415    CODE:
4416       RETVAL = guestfs_create ();
4417       if (!RETVAL)
4418         croak (\"could not create guestfs handle\");
4419       guestfs_set_error_handler (RETVAL, NULL, NULL);
4420  OUTPUT:
4421       RETVAL
4422
4423 void
4424 DESTROY (g)
4425       guestfs_h *g;
4426  PPCODE:
4427       guestfs_close (g);
4428
4429 ";
4430
4431   List.iter (
4432     fun (name, style, _, _, _, _, _) ->
4433       (match fst style with
4434        | RErr -> pr "void\n"
4435        | RInt _ -> pr "SV *\n"
4436        | RInt64 _ -> pr "SV *\n"
4437        | RBool _ -> pr "SV *\n"
4438        | RConstString _ -> pr "SV *\n"
4439        | RString _ -> pr "SV *\n"
4440        | RStringList _
4441        | RIntBool _
4442        | RPVList _ | RVGList _ | RLVList _
4443        | RStat _ | RStatVFS _
4444        | RHashtable _ ->
4445            pr "void\n" (* all lists returned implictly on the stack *)
4446       );
4447       (* Call and arguments. *)
4448       pr "%s " name;
4449       generate_call_args ~handle:"g" (snd style);
4450       pr "\n";
4451       pr "      guestfs_h *g;\n";
4452       List.iter (
4453         function
4454         | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
4455         | OptString n -> pr "      char *%s;\n" n
4456         | StringList n -> pr "      char **%s;\n" n
4457         | Bool n -> pr "      int %s;\n" n
4458         | Int n -> pr "      int %s;\n" n
4459       ) (snd style);
4460
4461       let do_cleanups () =
4462         List.iter (
4463           function
4464           | String _ | OptString _ | Bool _ | Int _
4465           | FileIn _ | FileOut _ -> ()
4466           | StringList n -> pr "      free (%s);\n" n
4467         ) (snd style)
4468       in
4469
4470       (* Code. *)
4471       (match fst style with
4472        | RErr ->
4473            pr "PREINIT:\n";
4474            pr "      int r;\n";
4475            pr " PPCODE:\n";
4476            pr "      r = guestfs_%s " name;
4477            generate_call_args ~handle:"g" (snd style);
4478            pr ";\n";
4479            do_cleanups ();
4480            pr "      if (r == -1)\n";
4481            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4482        | RInt n
4483        | RBool n ->
4484            pr "PREINIT:\n";
4485            pr "      int %s;\n" n;
4486            pr "   CODE:\n";
4487            pr "      %s = guestfs_%s " n name;
4488            generate_call_args ~handle:"g" (snd style);
4489            pr ";\n";
4490            do_cleanups ();
4491            pr "      if (%s == -1)\n" n;
4492            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4493            pr "      RETVAL = newSViv (%s);\n" n;
4494            pr " OUTPUT:\n";
4495            pr "      RETVAL\n"
4496        | RInt64 n ->
4497            pr "PREINIT:\n";
4498            pr "      int64_t %s;\n" n;
4499            pr "   CODE:\n";
4500            pr "      %s = guestfs_%s " n name;
4501            generate_call_args ~handle:"g" (snd style);
4502            pr ";\n";
4503            do_cleanups ();
4504            pr "      if (%s == -1)\n" n;
4505            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4506            pr "      RETVAL = my_newSVll (%s);\n" n;
4507            pr " OUTPUT:\n";
4508            pr "      RETVAL\n"
4509        | RConstString n ->
4510            pr "PREINIT:\n";
4511            pr "      const char *%s;\n" n;
4512            pr "   CODE:\n";
4513            pr "      %s = guestfs_%s " n name;
4514            generate_call_args ~handle:"g" (snd style);
4515            pr ";\n";
4516            do_cleanups ();
4517            pr "      if (%s == NULL)\n" n;
4518            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4519            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4520            pr " OUTPUT:\n";
4521            pr "      RETVAL\n"
4522        | RString n ->
4523            pr "PREINIT:\n";
4524            pr "      char *%s;\n" n;
4525            pr "   CODE:\n";
4526            pr "      %s = guestfs_%s " n name;
4527            generate_call_args ~handle:"g" (snd style);
4528            pr ";\n";
4529            do_cleanups ();
4530            pr "      if (%s == NULL)\n" n;
4531            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4532            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4533            pr "      free (%s);\n" n;
4534            pr " OUTPUT:\n";
4535            pr "      RETVAL\n"
4536        | RStringList n | RHashtable n ->
4537            pr "PREINIT:\n";
4538            pr "      char **%s;\n" n;
4539            pr "      int i, n;\n";
4540            pr " PPCODE:\n";
4541            pr "      %s = guestfs_%s " n name;
4542            generate_call_args ~handle:"g" (snd style);
4543            pr ";\n";
4544            do_cleanups ();
4545            pr "      if (%s == NULL)\n" n;
4546            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4547            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
4548            pr "      EXTEND (SP, n);\n";
4549            pr "      for (i = 0; i < n; ++i) {\n";
4550            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
4551            pr "        free (%s[i]);\n" n;
4552            pr "      }\n";
4553            pr "      free (%s);\n" n;
4554        | RIntBool _ ->
4555            pr "PREINIT:\n";
4556            pr "      struct guestfs_int_bool *r;\n";
4557            pr " PPCODE:\n";
4558            pr "      r = guestfs_%s " name;
4559            generate_call_args ~handle:"g" (snd style);
4560            pr ";\n";
4561            do_cleanups ();
4562            pr "      if (r == NULL)\n";
4563            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4564            pr "      EXTEND (SP, 2);\n";
4565            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
4566            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
4567            pr "      guestfs_free_int_bool (r);\n";
4568        | RPVList n ->
4569            generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
4570        | RVGList n ->
4571            generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
4572        | RLVList n ->
4573            generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
4574        | RStat n ->
4575            generate_perl_stat_code "stat" stat_cols name style n do_cleanups
4576        | RStatVFS n ->
4577            generate_perl_stat_code
4578              "statvfs" statvfs_cols name style n do_cleanups
4579       );
4580
4581       pr "\n"
4582   ) all_functions
4583
4584 and generate_perl_lvm_code typ cols name style n do_cleanups =
4585   pr "PREINIT:\n";
4586   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
4587   pr "      int i;\n";
4588   pr "      HV *hv;\n";
4589   pr " PPCODE:\n";
4590   pr "      %s = guestfs_%s " n name;
4591   generate_call_args ~handle:"g" (snd style);
4592   pr ";\n";
4593   do_cleanups ();
4594   pr "      if (%s == NULL)\n" n;
4595   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4596   pr "      EXTEND (SP, %s->len);\n" n;
4597   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
4598   pr "        hv = newHV ();\n";
4599   List.iter (
4600     function
4601     | name, `String ->
4602         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
4603           name (String.length name) n name
4604     | name, `UUID ->
4605         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
4606           name (String.length name) n name
4607     | name, `Bytes ->
4608         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
4609           name (String.length name) n name
4610     | name, `Int ->
4611         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
4612           name (String.length name) n name
4613     | name, `OptPercent ->
4614         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
4615           name (String.length name) n name
4616   ) cols;
4617   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
4618   pr "      }\n";
4619   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
4620
4621 and generate_perl_stat_code typ cols name style n do_cleanups =
4622   pr "PREINIT:\n";
4623   pr "      struct guestfs_%s *%s;\n" typ n;
4624   pr " PPCODE:\n";
4625   pr "      %s = guestfs_%s " n name;
4626   generate_call_args ~handle:"g" (snd style);
4627   pr ";\n";
4628   do_cleanups ();
4629   pr "      if (%s == NULL)\n" n;
4630   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4631   pr "      EXTEND (SP, %d);\n" (List.length cols);
4632   List.iter (
4633     function
4634     | name, `Int ->
4635         pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
4636   ) cols;
4637   pr "      free (%s);\n" n
4638
4639 (* Generate Sys/Guestfs.pm. *)
4640 and generate_perl_pm () =
4641   generate_header HashStyle LGPLv2;
4642
4643   pr "\
4644 =pod
4645
4646 =head1 NAME
4647
4648 Sys::Guestfs - Perl bindings for libguestfs
4649
4650 =head1 SYNOPSIS
4651
4652  use Sys::Guestfs;
4653  
4654  my $h = Sys::Guestfs->new ();
4655  $h->add_drive ('guest.img');
4656  $h->launch ();
4657  $h->wait_ready ();
4658  $h->mount ('/dev/sda1', '/');
4659  $h->touch ('/hello');
4660  $h->sync ();
4661
4662 =head1 DESCRIPTION
4663
4664 The C<Sys::Guestfs> module provides a Perl XS binding to the
4665 libguestfs API for examining and modifying virtual machine
4666 disk images.
4667
4668 Amongst the things this is good for: making batch configuration
4669 changes to guests, getting disk used/free statistics (see also:
4670 virt-df), migrating between virtualization systems (see also:
4671 virt-p2v), performing partial backups, performing partial guest
4672 clones, cloning guests and changing registry/UUID/hostname info, and
4673 much else besides.
4674
4675 Libguestfs uses Linux kernel and qemu code, and can access any type of
4676 guest filesystem that Linux and qemu can, including but not limited
4677 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
4678 schemes, qcow, qcow2, vmdk.
4679
4680 Libguestfs provides ways to enumerate guest storage (eg. partitions,
4681 LVs, what filesystem is in each LV, etc.).  It can also run commands
4682 in the context of the guest.  Also you can access filesystems over FTP.
4683
4684 =head1 ERRORS
4685
4686 All errors turn into calls to C<croak> (see L<Carp(3)>).
4687
4688 =head1 METHODS
4689
4690 =over 4
4691
4692 =cut
4693
4694 package Sys::Guestfs;
4695
4696 use strict;
4697 use warnings;
4698
4699 require XSLoader;
4700 XSLoader::load ('Sys::Guestfs');
4701
4702 =item $h = Sys::Guestfs->new ();
4703
4704 Create a new guestfs handle.
4705
4706 =cut
4707
4708 sub new {
4709   my $proto = shift;
4710   my $class = ref ($proto) || $proto;
4711
4712   my $self = Sys::Guestfs::_create ();
4713   bless $self, $class;
4714   return $self;
4715 }
4716
4717 ";
4718
4719   (* Actions.  We only need to print documentation for these as
4720    * they are pulled in from the XS code automatically.
4721    *)
4722   List.iter (
4723     fun (name, style, _, flags, _, _, longdesc) ->
4724       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
4725       pr "=item ";
4726       generate_perl_prototype name style;
4727       pr "\n\n";
4728       pr "%s\n\n" longdesc;
4729       if List.mem ProtocolLimitWarning flags then
4730         pr "%s\n\n" protocol_limit_warning;
4731       if List.mem DangerWillRobinson flags then
4732         pr "%s\n\n" danger_will_robinson
4733   ) all_functions_sorted;
4734
4735   (* End of file. *)
4736   pr "\
4737 =cut
4738
4739 1;
4740
4741 =back
4742
4743 =head1 COPYRIGHT
4744
4745 Copyright (C) 2009 Red Hat Inc.
4746
4747 =head1 LICENSE
4748
4749 Please see the file COPYING.LIB for the full license.
4750
4751 =head1 SEE ALSO
4752
4753 L<guestfs(3)>, L<guestfish(1)>.
4754
4755 =cut
4756 "
4757
4758 and generate_perl_prototype name style =
4759   (match fst style with
4760    | RErr -> ()
4761    | RBool n
4762    | RInt n
4763    | RInt64 n
4764    | RConstString n
4765    | RString n -> pr "$%s = " n
4766    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4767    | RStringList n
4768    | RPVList n
4769    | RVGList n
4770    | RLVList n -> pr "@%s = " n
4771    | RStat n
4772    | RStatVFS n
4773    | RHashtable n -> pr "%%%s = " n
4774   );
4775   pr "$h->%s (" name;
4776   let comma = ref false in
4777   List.iter (
4778     fun arg ->
4779       if !comma then pr ", ";
4780       comma := true;
4781       match arg with
4782       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
4783           pr "$%s" n
4784       | StringList n ->
4785           pr "\\@%s" n
4786   ) (snd style);
4787   pr ");"
4788
4789 (* Generate Python C module. *)
4790 and generate_python_c () =
4791   generate_header CStyle LGPLv2;
4792
4793   pr "\
4794 #include <stdio.h>
4795 #include <stdlib.h>
4796 #include <assert.h>
4797
4798 #include <Python.h>
4799
4800 #include \"guestfs.h\"
4801
4802 typedef struct {
4803   PyObject_HEAD
4804   guestfs_h *g;
4805 } Pyguestfs_Object;
4806
4807 static guestfs_h *
4808 get_handle (PyObject *obj)
4809 {
4810   assert (obj);
4811   assert (obj != Py_None);
4812   return ((Pyguestfs_Object *) obj)->g;
4813 }
4814
4815 static PyObject *
4816 put_handle (guestfs_h *g)
4817 {
4818   assert (g);
4819   return
4820     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4821 }
4822
4823 /* This list should be freed (but not the strings) after use. */
4824 static const char **
4825 get_string_list (PyObject *obj)
4826 {
4827   int i, len;
4828   const char **r;
4829
4830   assert (obj);
4831
4832   if (!PyList_Check (obj)) {
4833     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4834     return NULL;
4835   }
4836
4837   len = PyList_Size (obj);
4838   r = malloc (sizeof (char *) * (len+1));
4839   if (r == NULL) {
4840     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4841     return NULL;
4842   }
4843
4844   for (i = 0; i < len; ++i)
4845     r[i] = PyString_AsString (PyList_GetItem (obj, i));
4846   r[len] = NULL;
4847
4848   return r;
4849 }
4850
4851 static PyObject *
4852 put_string_list (char * const * const argv)
4853 {
4854   PyObject *list;
4855   int argc, i;
4856
4857   for (argc = 0; argv[argc] != NULL; ++argc)
4858     ;
4859
4860   list = PyList_New (argc);
4861   for (i = 0; i < argc; ++i)
4862     PyList_SetItem (list, i, PyString_FromString (argv[i]));
4863
4864   return list;
4865 }
4866
4867 static PyObject *
4868 put_table (char * const * const argv)
4869 {
4870   PyObject *list, *item;
4871   int argc, i;
4872
4873   for (argc = 0; argv[argc] != NULL; ++argc)
4874     ;
4875
4876   list = PyList_New (argc >> 1);
4877   for (i = 0; i < argc; i += 2) {
4878     item = PyTuple_New (2);
4879     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
4880     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
4881     PyList_SetItem (list, i >> 1, item);
4882   }
4883
4884   return list;
4885 }
4886
4887 static void
4888 free_strings (char **argv)
4889 {
4890   int argc;
4891
4892   for (argc = 0; argv[argc] != NULL; ++argc)
4893     free (argv[argc]);
4894   free (argv);
4895 }
4896
4897 static PyObject *
4898 py_guestfs_create (PyObject *self, PyObject *args)
4899 {
4900   guestfs_h *g;
4901
4902   g = guestfs_create ();
4903   if (g == NULL) {
4904     PyErr_SetString (PyExc_RuntimeError,
4905                      \"guestfs.create: failed to allocate handle\");
4906     return NULL;
4907   }
4908   guestfs_set_error_handler (g, NULL, NULL);
4909   return put_handle (g);
4910 }
4911
4912 static PyObject *
4913 py_guestfs_close (PyObject *self, PyObject *args)
4914 {
4915   PyObject *py_g;
4916   guestfs_h *g;
4917
4918   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4919     return NULL;
4920   g = get_handle (py_g);
4921
4922   guestfs_close (g);
4923
4924   Py_INCREF (Py_None);
4925   return Py_None;
4926 }
4927
4928 ";
4929
4930   (* LVM structures, turned into Python dictionaries. *)
4931   List.iter (
4932     fun (typ, cols) ->
4933       pr "static PyObject *\n";
4934       pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4935       pr "{\n";
4936       pr "  PyObject *dict;\n";
4937       pr "\n";
4938       pr "  dict = PyDict_New ();\n";
4939       List.iter (
4940         function
4941         | name, `String ->
4942             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4943             pr "                        PyString_FromString (%s->%s));\n"
4944               typ name
4945         | name, `UUID ->
4946             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4947             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
4948               typ name
4949         | name, `Bytes ->
4950             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4951             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
4952               typ name
4953         | name, `Int ->
4954             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4955             pr "                        PyLong_FromLongLong (%s->%s));\n"
4956               typ name
4957         | name, `OptPercent ->
4958             pr "  if (%s->%s >= 0)\n" typ name;
4959             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
4960             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
4961               typ name;
4962             pr "  else {\n";
4963             pr "    Py_INCREF (Py_None);\n";
4964             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
4965             pr "  }\n"
4966       ) cols;
4967       pr "  return dict;\n";
4968       pr "};\n";
4969       pr "\n";
4970
4971       pr "static PyObject *\n";
4972       pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
4973       pr "{\n";
4974       pr "  PyObject *list;\n";
4975       pr "  int i;\n";
4976       pr "\n";
4977       pr "  list = PyList_New (%ss->len);\n" typ;
4978       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
4979       pr "    PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
4980       pr "  return list;\n";
4981       pr "};\n";
4982       pr "\n"
4983   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4984
4985   (* Stat structures, turned into Python dictionaries. *)
4986   List.iter (
4987     fun (typ, cols) ->
4988       pr "static PyObject *\n";
4989       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
4990       pr "{\n";
4991       pr "  PyObject *dict;\n";
4992       pr "\n";
4993       pr "  dict = PyDict_New ();\n";
4994       List.iter (
4995         function
4996         | name, `Int ->
4997             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4998             pr "                        PyLong_FromLongLong (%s->%s));\n"
4999               typ name
5000       ) cols;
5001       pr "  return dict;\n";
5002       pr "};\n";
5003       pr "\n";
5004   ) ["stat", stat_cols; "statvfs", statvfs_cols];
5005
5006   (* Python wrapper functions. *)
5007   List.iter (
5008     fun (name, style, _, _, _, _, _) ->
5009       pr "static PyObject *\n";
5010       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
5011       pr "{\n";
5012
5013       pr "  PyObject *py_g;\n";
5014       pr "  guestfs_h *g;\n";
5015       pr "  PyObject *py_r;\n";
5016
5017       let error_code =
5018         match fst style with
5019         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
5020         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5021         | RConstString _ -> pr "  const char *r;\n"; "NULL"
5022         | RString _ -> pr "  char *r;\n"; "NULL"
5023         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5024         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
5025         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
5026         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
5027         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
5028         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
5029         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
5030
5031       List.iter (
5032         function
5033         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
5034         | OptString n -> pr "  const char *%s;\n" n
5035         | StringList n ->
5036             pr "  PyObject *py_%s;\n" n;
5037             pr "  const char **%s;\n" n
5038         | Bool n -> pr "  int %s;\n" n
5039         | Int n -> pr "  int %s;\n" n
5040       ) (snd style);
5041
5042       pr "\n";
5043
5044       (* Convert the parameters. *)
5045       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
5046       List.iter (
5047         function
5048         | String _ | FileIn _ | FileOut _ -> pr "s"
5049         | OptString _ -> pr "z"
5050         | StringList _ -> pr "O"
5051         | Bool _ -> pr "i" (* XXX Python has booleans? *)
5052         | Int _ -> pr "i"
5053       ) (snd style);
5054       pr ":guestfs_%s\",\n" name;
5055       pr "                         &py_g";
5056       List.iter (
5057         function
5058         | String n | FileIn n | FileOut n -> pr ", &%s" n
5059         | OptString n -> pr ", &%s" n
5060         | StringList n -> pr ", &py_%s" n
5061         | Bool n -> pr ", &%s" n
5062         | Int n -> pr ", &%s" n
5063       ) (snd style);
5064
5065       pr "))\n";
5066       pr "    return NULL;\n";
5067
5068       pr "  g = get_handle (py_g);\n";
5069       List.iter (
5070         function
5071         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5072         | StringList n ->
5073             pr "  %s = get_string_list (py_%s);\n" n n;
5074             pr "  if (!%s) return NULL;\n" n
5075       ) (snd style);
5076
5077       pr "\n";
5078
5079       pr "  r = guestfs_%s " name;
5080       generate_call_args ~handle:"g" (snd style);
5081       pr ";\n";
5082
5083       List.iter (
5084         function
5085         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5086         | StringList n ->
5087             pr "  free (%s);\n" n
5088       ) (snd style);
5089
5090       pr "  if (r == %s) {\n" error_code;
5091       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
5092       pr "    return NULL;\n";
5093       pr "  }\n";
5094       pr "\n";
5095
5096       (match fst style with
5097        | RErr ->
5098            pr "  Py_INCREF (Py_None);\n";
5099            pr "  py_r = Py_None;\n"
5100        | RInt _
5101        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
5102        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
5103        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
5104        | RString _ ->
5105            pr "  py_r = PyString_FromString (r);\n";
5106            pr "  free (r);\n"
5107        | RStringList _ ->
5108            pr "  py_r = put_string_list (r);\n";
5109            pr "  free_strings (r);\n"
5110        | RIntBool _ ->
5111            pr "  py_r = PyTuple_New (2);\n";
5112            pr "  PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
5113            pr "  PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
5114            pr "  guestfs_free_int_bool (r);\n"
5115        | RPVList n ->
5116            pr "  py_r = put_lvm_pv_list (r);\n";
5117            pr "  guestfs_free_lvm_pv_list (r);\n"
5118        | RVGList n ->
5119            pr "  py_r = put_lvm_vg_list (r);\n";
5120            pr "  guestfs_free_lvm_vg_list (r);\n"
5121        | RLVList n ->
5122            pr "  py_r = put_lvm_lv_list (r);\n";
5123            pr "  guestfs_free_lvm_lv_list (r);\n"
5124        | RStat n ->
5125            pr "  py_r = put_stat (r);\n";
5126            pr "  free (r);\n"
5127        | RStatVFS n ->
5128            pr "  py_r = put_statvfs (r);\n";
5129            pr "  free (r);\n"
5130        | RHashtable n ->
5131            pr "  py_r = put_table (r);\n";
5132            pr "  free_strings (r);\n"
5133       );
5134
5135       pr "  return py_r;\n";
5136       pr "}\n";
5137       pr "\n"
5138   ) all_functions;
5139
5140   (* Table of functions. *)
5141   pr "static PyMethodDef methods[] = {\n";
5142   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
5143   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
5144   List.iter (
5145     fun (name, _, _, _, _, _, _) ->
5146       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
5147         name name
5148   ) all_functions;
5149   pr "  { NULL, NULL, 0, NULL }\n";
5150   pr "};\n";
5151   pr "\n";
5152
5153   (* Init function. *)
5154   pr "\
5155 void
5156 initlibguestfsmod (void)
5157 {
5158   static int initialized = 0;
5159
5160   if (initialized) return;
5161   Py_InitModule ((char *) \"libguestfsmod\", methods);
5162   initialized = 1;
5163 }
5164 "
5165
5166 (* Generate Python module. *)
5167 and generate_python_py () =
5168   generate_header HashStyle LGPLv2;
5169
5170   pr "\
5171 u\"\"\"Python bindings for libguestfs
5172
5173 import guestfs
5174 g = guestfs.GuestFS ()
5175 g.add_drive (\"guest.img\")
5176 g.launch ()
5177 g.wait_ready ()
5178 parts = g.list_partitions ()
5179
5180 The guestfs module provides a Python binding to the libguestfs API
5181 for examining and modifying virtual machine disk images.
5182
5183 Amongst the things this is good for: making batch configuration
5184 changes to guests, getting disk used/free statistics (see also:
5185 virt-df), migrating between virtualization systems (see also:
5186 virt-p2v), performing partial backups, performing partial guest
5187 clones, cloning guests and changing registry/UUID/hostname info, and
5188 much else besides.
5189
5190 Libguestfs uses Linux kernel and qemu code, and can access any type of
5191 guest filesystem that Linux and qemu can, including but not limited
5192 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5193 schemes, qcow, qcow2, vmdk.
5194
5195 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5196 LVs, what filesystem is in each LV, etc.).  It can also run commands
5197 in the context of the guest.  Also you can access filesystems over FTP.
5198
5199 Errors which happen while using the API are turned into Python
5200 RuntimeError exceptions.
5201
5202 To create a guestfs handle you usually have to perform the following
5203 sequence of calls:
5204
5205 # Create the handle, call add_drive at least once, and possibly
5206 # several times if the guest has multiple block devices:
5207 g = guestfs.GuestFS ()
5208 g.add_drive (\"guest.img\")
5209
5210 # Launch the qemu subprocess and wait for it to become ready:
5211 g.launch ()
5212 g.wait_ready ()
5213
5214 # Now you can issue commands, for example:
5215 logvols = g.lvs ()
5216
5217 \"\"\"
5218
5219 import libguestfsmod
5220
5221 class GuestFS:
5222     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
5223
5224     def __init__ (self):
5225         \"\"\"Create a new libguestfs handle.\"\"\"
5226         self._o = libguestfsmod.create ()
5227
5228     def __del__ (self):
5229         libguestfsmod.close (self._o)
5230
5231 ";
5232
5233   List.iter (
5234     fun (name, style, _, flags, _, _, longdesc) ->
5235       let doc = replace_str longdesc "C<guestfs_" "C<g." in
5236       let doc =
5237         match fst style with
5238         | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
5239         | RString _ -> doc
5240         | RStringList _ ->
5241             doc ^ "\n\nThis function returns a list of strings."
5242         | RIntBool _ ->
5243             doc ^ "\n\nThis function returns a tuple (int, bool).\n"
5244         | RPVList _ ->
5245             doc ^ "\n\nThis function returns a list of PVs.  Each PV is represented as a dictionary."
5246         | RVGList _ ->
5247             doc ^ "\n\nThis function returns a list of VGs.  Each VG is represented as a dictionary."
5248         | RLVList _ ->
5249             doc ^ "\n\nThis function returns a list of LVs.  Each LV is represented as a dictionary."
5250         | RStat _ ->
5251             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
5252        | RStatVFS _ ->
5253             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
5254        | RHashtable _ ->
5255             doc ^ "\n\nThis function returns a dictionary." in
5256       let doc =
5257         if List.mem ProtocolLimitWarning flags then
5258           doc ^ "\n\n" ^ protocol_limit_warning
5259         else doc in
5260       let doc =
5261         if List.mem DangerWillRobinson flags then
5262           doc ^ "\n\n" ^ danger_will_robinson
5263         else doc in
5264       let doc = pod2text ~width:60 name doc in
5265       let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
5266       let doc = String.concat "\n        " doc in
5267
5268       pr "    def %s " name;
5269       generate_call_args ~handle:"self" (snd style);
5270       pr ":\n";
5271       pr "        u\"\"\"%s\"\"\"\n" doc;
5272       pr "        return libguestfsmod.%s " name;
5273       generate_call_args ~handle:"self._o" (snd style);
5274       pr "\n";
5275       pr "\n";
5276   ) all_functions
5277
5278 (* Useful if you need the longdesc POD text as plain text.  Returns a
5279  * list of lines.
5280  *
5281  * This is the slowest thing about autogeneration.
5282  *)
5283 and pod2text ~width name longdesc =
5284   let filename, chan = Filename.open_temp_file "gen" ".tmp" in
5285   fprintf chan "=head1 %s\n\n%s\n" name longdesc;
5286   close_out chan;
5287   let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
5288   let chan = Unix.open_process_in cmd in
5289   let lines = ref [] in
5290   let rec loop i =
5291     let line = input_line chan in
5292     if i = 1 then               (* discard the first line of output *)
5293       loop (i+1)
5294     else (
5295       let line = triml line in
5296       lines := line :: !lines;
5297       loop (i+1)
5298     ) in
5299   let lines = try loop 1 with End_of_file -> List.rev !lines in
5300   Unix.unlink filename;
5301   match Unix.close_process_in chan with
5302   | Unix.WEXITED 0 -> lines
5303   | Unix.WEXITED i ->
5304       failwithf "pod2text: process exited with non-zero status (%d)" i
5305   | Unix.WSIGNALED i | Unix.WSTOPPED i ->
5306       failwithf "pod2text: process signalled or stopped by signal %d" i
5307
5308 (* Generate ruby bindings. *)
5309 and generate_ruby_c () =
5310   generate_header CStyle LGPLv2;
5311
5312   pr "\
5313 #include <stdio.h>
5314 #include <stdlib.h>
5315
5316 #include <ruby.h>
5317
5318 #include \"guestfs.h\"
5319
5320 #include \"extconf.h\"
5321
5322 static VALUE m_guestfs;                 /* guestfs module */
5323 static VALUE c_guestfs;                 /* guestfs_h handle */
5324 static VALUE e_Error;                   /* used for all errors */
5325
5326 static void ruby_guestfs_free (void *p)
5327 {
5328   if (!p) return;
5329   guestfs_close ((guestfs_h *) p);
5330 }
5331
5332 static VALUE ruby_guestfs_create (VALUE m)
5333 {
5334   guestfs_h *g;
5335
5336   g = guestfs_create ();
5337   if (!g)
5338     rb_raise (e_Error, \"failed to create guestfs handle\");
5339
5340   /* Don't print error messages to stderr by default. */
5341   guestfs_set_error_handler (g, NULL, NULL);
5342
5343   /* Wrap it, and make sure the close function is called when the
5344    * handle goes away.
5345    */
5346   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
5347 }
5348
5349 static VALUE ruby_guestfs_close (VALUE gv)
5350 {
5351   guestfs_h *g;
5352   Data_Get_Struct (gv, guestfs_h, g);
5353
5354   ruby_guestfs_free (g);
5355   DATA_PTR (gv) = NULL;
5356
5357   return Qnil;
5358 }
5359
5360 ";
5361
5362   List.iter (
5363     fun (name, style, _, _, _, _, _) ->
5364       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
5365       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
5366       pr ")\n";
5367       pr "{\n";
5368       pr "  guestfs_h *g;\n";
5369       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
5370       pr "  if (!g)\n";
5371       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
5372         name;
5373       pr "\n";
5374
5375       List.iter (
5376         function
5377         | String n | FileIn n | FileOut n ->
5378             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
5379             pr "  if (!%s)\n" n;
5380             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
5381             pr "              \"%s\", \"%s\");\n" n name
5382         | OptString n ->
5383             pr "  const char *%s = StringValueCStr (%sv);\n" n n
5384         | StringList n ->
5385             pr "  char **%s;" n;
5386             pr "  {\n";
5387             pr "    int i, len;\n";
5388             pr "    len = RARRAY_LEN (%sv);\n" n;
5389             pr "    %s = malloc (sizeof (char *) * (len+1));\n" n;
5390             pr "    for (i = 0; i < len; ++i) {\n";
5391             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
5392             pr "      %s[i] = StringValueCStr (v);\n" n;
5393             pr "    }\n";
5394             pr "  }\n";
5395         | Bool n
5396         | Int n ->
5397             pr "  int %s = NUM2INT (%sv);\n" n n
5398       ) (snd style);
5399       pr "\n";
5400
5401       let error_code =
5402         match fst style with
5403         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
5404         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5405         | RConstString _ -> pr "  const char *r;\n"; "NULL"
5406         | RString _ -> pr "  char *r;\n"; "NULL"
5407         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5408         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
5409         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
5410         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
5411         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
5412         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
5413         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
5414       pr "\n";
5415
5416       pr "  r = guestfs_%s " name;
5417       generate_call_args ~handle:"g" (snd style);
5418       pr ";\n";
5419
5420       List.iter (
5421         function
5422         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5423         | StringList n ->
5424             pr "  free (%s);\n" n
5425       ) (snd style);
5426
5427       pr "  if (r == %s)\n" error_code;
5428       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
5429       pr "\n";
5430
5431       (match fst style with
5432        | RErr ->
5433            pr "  return Qnil;\n"
5434        | RInt _ | RBool _ ->
5435            pr "  return INT2NUM (r);\n"
5436        | RInt64 _ ->
5437            pr "  return ULL2NUM (r);\n"
5438        | RConstString _ ->
5439            pr "  return rb_str_new2 (r);\n";
5440        | RString _ ->
5441            pr "  VALUE rv = rb_str_new2 (r);\n";
5442            pr "  free (r);\n";
5443            pr "  return rv;\n";
5444        | RStringList _ ->
5445            pr "  int i, len = 0;\n";
5446            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
5447            pr "  VALUE rv = rb_ary_new2 (len);\n";
5448            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
5449            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
5450            pr "    free (r[i]);\n";
5451            pr "  }\n";
5452            pr "  free (r);\n";
5453            pr "  return rv;\n"
5454        | RIntBool _ ->
5455            pr "  VALUE rv = rb_ary_new2 (2);\n";
5456            pr "  rb_ary_push (rv, INT2NUM (r->i));\n";
5457            pr "  rb_ary_push (rv, INT2NUM (r->b));\n";
5458            pr "  guestfs_free_int_bool (r);\n";
5459            pr "  return rv;\n"
5460        | RPVList n ->
5461            generate_ruby_lvm_code "pv" pv_cols
5462        | RVGList n ->
5463            generate_ruby_lvm_code "vg" vg_cols
5464        | RLVList n ->
5465            generate_ruby_lvm_code "lv" lv_cols
5466        | RStat n ->
5467            pr "  VALUE rv = rb_hash_new ();\n";
5468            List.iter (
5469              function
5470              | name, `Int ->
5471                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5472            ) stat_cols;
5473            pr "  free (r);\n";
5474            pr "  return rv;\n"
5475        | RStatVFS n ->
5476            pr "  VALUE rv = rb_hash_new ();\n";
5477            List.iter (
5478              function
5479              | name, `Int ->
5480                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5481            ) statvfs_cols;
5482            pr "  free (r);\n";
5483            pr "  return rv;\n"
5484        | RHashtable _ ->
5485            pr "  VALUE rv = rb_hash_new ();\n";
5486            pr "  int i;\n";
5487            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
5488            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
5489            pr "    free (r[i]);\n";
5490            pr "    free (r[i+1]);\n";
5491            pr "  }\n";
5492            pr "  free (r);\n";
5493            pr "  return rv;\n"
5494       );
5495
5496       pr "}\n";
5497       pr "\n"
5498   ) all_functions;
5499
5500   pr "\
5501 /* Initialize the module. */
5502 void Init__guestfs ()
5503 {
5504   m_guestfs = rb_define_module (\"Guestfs\");
5505   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
5506   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
5507
5508   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
5509   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
5510
5511 ";
5512   (* Define the rest of the methods. *)
5513   List.iter (
5514     fun (name, style, _, _, _, _, _) ->
5515       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
5516       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
5517   ) all_functions;
5518
5519   pr "}\n"
5520
5521 (* Ruby code to return an LVM struct list. *)
5522 and generate_ruby_lvm_code typ cols =
5523   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
5524   pr "  int i;\n";
5525   pr "  for (i = 0; i < r->len; ++i) {\n";
5526   pr "    VALUE hv = rb_hash_new ();\n";
5527   List.iter (
5528     function
5529     | name, `String ->
5530         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
5531     | name, `UUID ->
5532         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
5533     | name, `Bytes
5534     | name, `Int ->
5535         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
5536     | name, `OptPercent ->
5537         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
5538   ) cols;
5539   pr "    rb_ary_push (rv, hv);\n";
5540   pr "  }\n";
5541   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
5542   pr "  return rv;\n"
5543
5544 (* Generate Java bindings GuestFS.java file. *)
5545 and generate_java_java () =
5546   generate_header CStyle LGPLv2;
5547
5548   pr "\
5549 package com.redhat.et.libguestfs;
5550
5551 import java.util.HashMap;
5552 import com.redhat.et.libguestfs.LibGuestFSException;
5553 import com.redhat.et.libguestfs.PV;
5554 import com.redhat.et.libguestfs.VG;
5555 import com.redhat.et.libguestfs.LV;
5556 import com.redhat.et.libguestfs.Stat;
5557 import com.redhat.et.libguestfs.StatVFS;
5558 import com.redhat.et.libguestfs.IntBool;
5559
5560 /**
5561  * The GuestFS object is a libguestfs handle.
5562  *
5563  * @author rjones
5564  */
5565 public class GuestFS {
5566   // Load the native code.
5567   static {
5568     System.loadLibrary (\"guestfs_jni\");
5569   }
5570
5571   /**
5572    * The native guestfs_h pointer.
5573    */
5574   long g;
5575
5576   /**
5577    * Create a libguestfs handle.
5578    *
5579    * @throws LibGuestFSException
5580    */
5581   public GuestFS () throws LibGuestFSException
5582   {
5583     g = _create ();
5584   }
5585   private native long _create () throws LibGuestFSException;
5586
5587   /**
5588    * Close a libguestfs handle.
5589    *
5590    * You can also leave handles to be collected by the garbage
5591    * collector, but this method ensures that the resources used
5592    * by the handle are freed up immediately.  If you call any
5593    * other methods after closing the handle, you will get an
5594    * exception.
5595    *
5596    * @throws LibGuestFSException
5597    */
5598   public void close () throws LibGuestFSException
5599   {
5600     if (g != 0)
5601       _close (g);
5602     g = 0;
5603   }
5604   private native void _close (long g) throws LibGuestFSException;
5605
5606   public void finalize () throws LibGuestFSException
5607   {
5608     close ();
5609   }
5610
5611 ";
5612
5613   List.iter (
5614     fun (name, style, _, flags, _, shortdesc, longdesc) ->
5615       let doc = replace_str longdesc "C<guestfs_" "C<g." in
5616       let doc =
5617         if List.mem ProtocolLimitWarning flags then
5618           doc ^ "\n\n" ^ protocol_limit_warning
5619         else doc in
5620       let doc =
5621         if List.mem DangerWillRobinson flags then
5622           doc ^ "\n\n" ^ danger_will_robinson
5623         else doc in
5624       let doc = pod2text ~width:60 name doc in
5625       let doc = String.concat "\n   * " doc in
5626
5627       pr "  /**\n";
5628       pr "   * %s\n" shortdesc;
5629       pr "   *\n";
5630       pr "   * %s\n" doc;
5631       pr "   * @throws LibGuestFSException\n";
5632       pr "   */\n";
5633       pr "  ";
5634       generate_java_prototype ~public:true ~semicolon:false name style;
5635       pr "\n";
5636       pr "  {\n";
5637       pr "    if (g == 0)\n";
5638       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
5639         name;
5640       pr "    ";
5641       if fst style <> RErr then pr "return ";
5642       pr "_%s " name;
5643       generate_call_args ~handle:"g" (snd style);
5644       pr ";\n";
5645       pr "  }\n";
5646       pr "  ";
5647       generate_java_prototype ~privat:true ~native:true name style;
5648       pr "\n";
5649       pr "\n";
5650   ) all_functions;
5651
5652   pr "}\n"
5653
5654 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
5655     ?(semicolon=true) name style =
5656   if privat then pr "private ";
5657   if public then pr "public ";
5658   if native then pr "native ";
5659
5660   (* return type *)
5661   (match fst style with
5662    | RErr -> pr "void ";
5663    | RInt _ -> pr "int ";
5664    | RInt64 _ -> pr "long ";
5665    | RBool _ -> pr "boolean ";
5666    | RConstString _ | RString _ -> pr "String ";
5667    | RStringList _ -> pr "String[] ";
5668    | RIntBool _ -> pr "IntBool ";
5669    | RPVList _ -> pr "PV[] ";
5670    | RVGList _ -> pr "VG[] ";
5671    | RLVList _ -> pr "LV[] ";
5672    | RStat _ -> pr "Stat ";
5673    | RStatVFS _ -> pr "StatVFS ";
5674    | RHashtable _ -> pr "HashMap<String,String> ";
5675   );
5676
5677   if native then pr "_%s " name else pr "%s " name;
5678   pr "(";
5679   let needs_comma = ref false in
5680   if native then (
5681     pr "long g";
5682     needs_comma := true
5683   );
5684
5685   (* args *)
5686   List.iter (
5687     fun arg ->
5688       if !needs_comma then pr ", ";
5689       needs_comma := true;
5690
5691       match arg with
5692       | String n
5693       | OptString n
5694       | FileIn n
5695       | FileOut n ->
5696           pr "String %s" n
5697       | StringList n ->
5698           pr "String[] %s" n
5699       | Bool n ->
5700           pr "boolean %s" n
5701       | Int n ->
5702           pr "int %s" n
5703   ) (snd style);
5704
5705   pr ")\n";
5706   pr "    throws LibGuestFSException";
5707   if semicolon then pr ";"
5708
5709 and generate_java_struct typ cols =
5710   generate_header CStyle LGPLv2;
5711
5712   pr "\
5713 package com.redhat.et.libguestfs;
5714
5715 /**
5716  * Libguestfs %s structure.
5717  *
5718  * @author rjones
5719  * @see GuestFS
5720  */
5721 public class %s {
5722 " typ typ;
5723
5724   List.iter (
5725     function
5726     | name, `String
5727     | name, `UUID -> pr "  public String %s;\n" name
5728     | name, `Bytes
5729     | name, `Int -> pr "  public long %s;\n" name
5730     | name, `OptPercent ->
5731         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
5732         pr "  public float %s;\n" name
5733   ) cols;
5734
5735   pr "}\n"
5736
5737 and generate_java_c () =
5738   generate_header CStyle LGPLv2;
5739
5740   pr "\
5741 #include <stdio.h>
5742 #include <stdlib.h>
5743 #include <string.h>
5744
5745 #include \"com_redhat_et_libguestfs_GuestFS.h\"
5746 #include \"guestfs.h\"
5747
5748 /* Note that this function returns.  The exception is not thrown
5749  * until after the wrapper function returns.
5750  */
5751 static void
5752 throw_exception (JNIEnv *env, const char *msg)
5753 {
5754   jclass cl;
5755   cl = (*env)->FindClass (env,
5756                           \"com/redhat/et/libguestfs/LibGuestFSException\");
5757   (*env)->ThrowNew (env, cl, msg);
5758 }
5759
5760 JNIEXPORT jlong JNICALL
5761 Java_com_redhat_et_libguestfs_GuestFS__1create
5762   (JNIEnv *env, jobject obj)
5763 {
5764   guestfs_h *g;
5765
5766   g = guestfs_create ();
5767   if (g == NULL) {
5768     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
5769     return 0;
5770   }
5771   guestfs_set_error_handler (g, NULL, NULL);
5772   return (jlong) (long) g;
5773 }
5774
5775 JNIEXPORT void JNICALL
5776 Java_com_redhat_et_libguestfs_GuestFS__1close
5777   (JNIEnv *env, jobject obj, jlong jg)
5778 {
5779   guestfs_h *g = (guestfs_h *) (long) jg;
5780   guestfs_close (g);
5781 }
5782
5783 ";
5784
5785   List.iter (
5786     fun (name, style, _, _, _, _, _) ->
5787       pr "JNIEXPORT ";
5788       (match fst style with
5789        | RErr -> pr "void ";
5790        | RInt _ -> pr "jint ";
5791        | RInt64 _ -> pr "jlong ";
5792        | RBool _ -> pr "jboolean ";
5793        | RConstString _ | RString _ -> pr "jstring ";
5794        | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
5795            pr "jobject ";
5796        | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
5797            pr "jobjectArray ";
5798       );
5799       pr "JNICALL\n";
5800       pr "Java_com_redhat_et_libguestfs_GuestFS_";
5801       pr "%s" (replace_str ("_" ^ name) "_" "_1");
5802       pr "\n";
5803       pr "  (JNIEnv *env, jobject obj, jlong jg";
5804       List.iter (
5805         function
5806         | String n
5807         | OptString n
5808         | FileIn n
5809         | FileOut n ->
5810             pr ", jstring j%s" n
5811         | StringList n ->
5812             pr ", jobjectArray j%s" n
5813         | Bool n ->
5814             pr ", jboolean j%s" n
5815         | Int n ->
5816             pr ", jint j%s" n
5817       ) (snd style);
5818       pr ")\n";
5819       pr "{\n";
5820       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
5821       let error_code, no_ret =
5822         match fst style with
5823         | RErr -> pr "  int r;\n"; "-1", ""
5824         | RBool _
5825         | RInt _ -> pr "  int r;\n"; "-1", "0"
5826         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
5827         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
5828         | RString _ ->
5829             pr "  jstring jr;\n";
5830             pr "  char *r;\n"; "NULL", "NULL"
5831         | RStringList _ ->
5832             pr "  jobjectArray jr;\n";
5833             pr "  int r_len;\n";
5834             pr "  jclass cl;\n";
5835             pr "  jstring jstr;\n";
5836             pr "  char **r;\n"; "NULL", "NULL"
5837         | RIntBool _ ->
5838             pr "  jobject jr;\n";
5839             pr "  jclass cl;\n";
5840             pr "  jfieldID fl;\n";
5841             pr "  struct guestfs_int_bool *r;\n"; "NULL", "NULL"
5842         | RStat _ ->
5843             pr "  jobject jr;\n";
5844             pr "  jclass cl;\n";
5845             pr "  jfieldID fl;\n";
5846             pr "  struct guestfs_stat *r;\n"; "NULL", "NULL"
5847         | RStatVFS _ ->
5848             pr "  jobject jr;\n";
5849             pr "  jclass cl;\n";
5850             pr "  jfieldID fl;\n";
5851             pr "  struct guestfs_statvfs *r;\n"; "NULL", "NULL"
5852         | RPVList _ ->
5853             pr "  jobjectArray jr;\n";
5854             pr "  jclass cl;\n";
5855             pr "  jfieldID fl;\n";
5856             pr "  jobject jfl;\n";
5857             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
5858         | RVGList _ ->
5859             pr "  jobjectArray jr;\n";
5860             pr "  jclass cl;\n";
5861             pr "  jfieldID fl;\n";
5862             pr "  jobject jfl;\n";
5863             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
5864         | RLVList _ ->
5865             pr "  jobjectArray jr;\n";
5866             pr "  jclass cl;\n";
5867             pr "  jfieldID fl;\n";
5868             pr "  jobject jfl;\n";
5869             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
5870         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL" in
5871       List.iter (
5872         function
5873         | String n
5874         | OptString n
5875         | FileIn n
5876         | FileOut n ->
5877             pr "  const char *%s;\n" n
5878         | StringList n ->
5879             pr "  int %s_len;\n" n;
5880             pr "  const char **%s;\n" n
5881         | Bool n
5882         | Int n ->
5883             pr "  int %s;\n" n
5884       ) (snd style);
5885
5886       let needs_i =
5887         (match fst style with
5888          | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
5889          | RErr _ | RBool _ | RInt _ | RInt64 _ | RConstString _
5890          | RString _ | RIntBool _ | RStat _ | RStatVFS _
5891          | RHashtable _ -> false) ||
5892         List.exists (function StringList _ -> true | _ -> false) (snd style) in
5893       if needs_i then
5894         pr "  int i;\n";
5895
5896       pr "\n";
5897
5898       (* Get the parameters. *)
5899       List.iter (
5900         function
5901         | String n
5902         | OptString n
5903         | FileIn n
5904         | FileOut n ->
5905             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
5906         | StringList n ->
5907             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
5908             pr "  %s = malloc (sizeof (char *) * (%s_len+1));\n" n n;
5909             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
5910             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
5911               n;
5912             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
5913             pr "  }\n";
5914             pr "  %s[%s_len] = NULL;\n" n n;
5915         | Bool n
5916         | Int n ->
5917             pr "  %s = j%s;\n" n n
5918       ) (snd style);
5919
5920       (* Make the call. *)
5921       pr "  r = guestfs_%s " name;
5922       generate_call_args ~handle:"g" (snd style);
5923       pr ";\n";
5924
5925       (* Release the parameters. *)
5926       List.iter (
5927         function
5928         | String n
5929         | OptString n
5930         | FileIn n
5931         | FileOut n ->
5932             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
5933         | StringList n ->
5934             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
5935             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
5936               n;
5937             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
5938             pr "  }\n";
5939             pr "  free (%s);\n" n
5940         | Bool n
5941         | Int n -> ()
5942       ) (snd style);
5943
5944       (* Check for errors. *)
5945       pr "  if (r == %s) {\n" error_code;
5946       pr "    throw_exception (env, guestfs_last_error (g));\n";
5947       pr "    return %s;\n" no_ret;
5948       pr "  }\n";
5949
5950       (* Return value. *)
5951       (match fst style with
5952        | RErr -> ()
5953        | RInt _ -> pr "  return (jint) r;\n"
5954        | RBool _ -> pr "  return (jboolean) r;\n"
5955        | RInt64 _ -> pr "  return (jlong) r;\n"
5956        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
5957        | RString _ ->
5958            pr "  jr = (*env)->NewStringUTF (env, r);\n";
5959            pr "  free (r);\n";
5960            pr "  return jr;\n"
5961        | RStringList _ ->
5962            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
5963            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
5964            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
5965            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
5966            pr "  for (i = 0; i < r_len; ++i) {\n";
5967            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
5968            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
5969            pr "    free (r[i]);\n";
5970            pr "  }\n";
5971            pr "  free (r);\n";
5972            pr "  return jr;\n"
5973        | RIntBool _ ->
5974            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
5975            pr "  jr = (*env)->AllocObject (env, cl);\n";
5976            pr "  fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
5977            pr "  (*env)->SetIntField (env, jr, fl, r->i);\n";
5978            pr "  fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
5979            pr "  (*env)->SetBooleanField (env, jr, fl, r->b);\n";
5980            pr "  guestfs_free_int_bool (r);\n";
5981            pr "  return jr;\n"
5982        | RStat _ ->
5983            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
5984            pr "  jr = (*env)->AllocObject (env, cl);\n";
5985            List.iter (
5986              function
5987              | name, `Int ->
5988                  pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
5989                    name;
5990                  pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
5991            ) stat_cols;
5992            pr "  free (r);\n";
5993            pr "  return jr;\n"
5994        | RStatVFS _ ->
5995            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
5996            pr "  jr = (*env)->AllocObject (env, cl);\n";
5997            List.iter (
5998              function
5999              | name, `Int ->
6000                  pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
6001                    name;
6002                  pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
6003            ) statvfs_cols;
6004            pr "  free (r);\n";
6005            pr "  return jr;\n"
6006        | RPVList _ ->
6007            generate_java_lvm_return "pv" "PV" pv_cols
6008        | RVGList _ ->
6009            generate_java_lvm_return "vg" "VG" vg_cols
6010        | RLVList _ ->
6011            generate_java_lvm_return "lv" "LV" lv_cols
6012        | RHashtable _ ->
6013            (* XXX *)
6014            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
6015            pr "  return NULL;\n"
6016       );
6017
6018       pr "}\n";
6019       pr "\n"
6020   ) all_functions
6021
6022 and generate_java_lvm_return typ jtyp cols =
6023   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
6024   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
6025   pr "  for (i = 0; i < r->len; ++i) {\n";
6026   pr "    jfl = (*env)->AllocObject (env, cl);\n";
6027   List.iter (
6028     function
6029     | name, `String ->
6030         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
6031         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
6032     | name, `UUID ->
6033         pr "    {\n";
6034         pr "      char s[33];\n";
6035         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
6036         pr "      s[32] = 0;\n";
6037         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
6038         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
6039         pr "    }\n";
6040     | name, (`Bytes|`Int) ->
6041         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
6042         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
6043     | name, `OptPercent ->
6044         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
6045         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
6046   ) cols;
6047   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
6048   pr "  }\n";
6049   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
6050   pr "  return jr;\n"
6051
6052 let output_to filename =
6053   let filename_new = filename ^ ".new" in
6054   chan := open_out filename_new;
6055   let close () =
6056     close_out !chan;
6057     chan := stdout;
6058     Unix.rename filename_new filename;
6059     printf "written %s\n%!" filename;
6060   in
6061   close
6062
6063 (* Main program. *)
6064 let () =
6065   check_functions ();
6066
6067   if not (Sys.file_exists "configure.ac") then (
6068     eprintf "\
6069 You are probably running this from the wrong directory.
6070 Run it from the top source directory using the command
6071   src/generator.ml
6072 ";
6073     exit 1
6074   );
6075
6076   let close = output_to "src/guestfs_protocol.x" in
6077   generate_xdr ();
6078   close ();
6079
6080   let close = output_to "src/guestfs-structs.h" in
6081   generate_structs_h ();
6082   close ();
6083
6084   let close = output_to "src/guestfs-actions.h" in
6085   generate_actions_h ();
6086   close ();
6087
6088   let close = output_to "src/guestfs-actions.c" in
6089   generate_client_actions ();
6090   close ();
6091
6092   let close = output_to "daemon/actions.h" in
6093   generate_daemon_actions_h ();
6094   close ();
6095
6096   let close = output_to "daemon/stubs.c" in
6097   generate_daemon_actions ();
6098   close ();
6099
6100   let close = output_to "tests.c" in
6101   generate_tests ();
6102   close ();
6103
6104   let close = output_to "fish/cmds.c" in
6105   generate_fish_cmds ();
6106   close ();
6107
6108   let close = output_to "fish/completion.c" in
6109   generate_fish_completion ();
6110   close ();
6111
6112   let close = output_to "guestfs-structs.pod" in
6113   generate_structs_pod ();
6114   close ();
6115
6116   let close = output_to "guestfs-actions.pod" in
6117   generate_actions_pod ();
6118   close ();
6119
6120   let close = output_to "guestfish-actions.pod" in
6121   generate_fish_actions_pod ();
6122   close ();
6123
6124   let close = output_to "ocaml/guestfs.mli" in
6125   generate_ocaml_mli ();
6126   close ();
6127
6128   let close = output_to "ocaml/guestfs.ml" in
6129   generate_ocaml_ml ();
6130   close ();
6131
6132   let close = output_to "ocaml/guestfs_c_actions.c" in
6133   generate_ocaml_c ();
6134   close ();
6135
6136   let close = output_to "perl/Guestfs.xs" in
6137   generate_perl_xs ();
6138   close ();
6139
6140   let close = output_to "perl/lib/Sys/Guestfs.pm" in
6141   generate_perl_pm ();
6142   close ();
6143
6144   let close = output_to "python/guestfs-py.c" in
6145   generate_python_c ();
6146   close ();
6147
6148   let close = output_to "python/guestfs.py" in
6149   generate_python_py ();
6150   close ();
6151
6152   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
6153   generate_ruby_c ();
6154   close ();
6155
6156   let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
6157   generate_java_java ();
6158   close ();
6159
6160   let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
6161   generate_java_struct "PV" pv_cols;
6162   close ();
6163
6164   let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
6165   generate_java_struct "VG" vg_cols;
6166   close ();
6167
6168   let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
6169   generate_java_struct "LV" lv_cols;
6170   close ();
6171
6172   let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
6173   generate_java_struct "Stat" stat_cols;
6174   close ();
6175
6176   let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
6177   generate_java_struct "StatVFS" statvfs_cols;
6178   close ();
6179
6180   let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
6181   generate_java_c ();
6182   close ();