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