Split out send and reply operations into separate callbacks.
[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 context struct which stores the high-level
2143        * state between callback functions.
2144        *)
2145       pr "struct %s_ctx {\n" shortname;
2146       pr "  /* This flag is set by the callbacks, so we know we've done\n";
2147       pr "   * the callbacks as expected, and in the right sequence.\n";
2148       pr "   * 0 = not called, 1 = send called,\n";
2149       pr "   * 2.. = send_file called,\n";
2150       pr "   * 1000 = reply called.\n";
2151       pr "   */\n";
2152       pr "  int cb_sequence;\n";
2153       pr "  struct guestfs_message_header hdr;\n";
2154       pr "  struct guestfs_message_error err;\n";
2155       (match fst style with
2156        | RErr -> ()
2157        | RConstString _ ->
2158            failwithf "RConstString cannot be returned from a daemon function"
2159        | RInt _ | RInt64 _
2160        | RBool _ | RString _ | RStringList _
2161        | RIntBool _
2162        | RPVList _ | RVGList _ | RLVList _
2163        | RStat _ | RStatVFS _
2164        | RHashtable _ ->
2165            pr "  struct %s_ret ret;\n" name
2166       );
2167       pr "};\n";
2168       pr "\n";
2169
2170       (* Generate the send callback function. *)
2171       pr "static void %s_send_cb (guestfs_h *g, void *data)\n" shortname;
2172       pr "{\n";
2173       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2174       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
2175       pr "\n";
2176       pr "  guestfs__switch_to_receiving (g);\n";
2177       pr "  ctx->cb_sequence = 1;\n";
2178       pr "  ml->main_loop_quit (ml, g);\n";
2179       pr "}\n";
2180       pr "\n";
2181
2182       (* Generate the reply callback function. *)
2183       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
2184       pr "{\n";
2185       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2186       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
2187       pr "\n";
2188       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
2189       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
2190       pr "    return;\n";
2191       pr "  }\n";
2192       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
2193       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
2194       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
2195         name;
2196       pr "      return;\n";
2197       pr "    }\n";
2198       pr "    goto done;\n";
2199       pr "  }\n";
2200
2201       (match fst style with
2202        | RErr -> ()
2203        | RConstString _ ->
2204            failwithf "RConstString cannot be returned from a daemon function"
2205        | RInt _ | RInt64 _
2206        | RBool _ | RString _ | RStringList _
2207        | RIntBool _
2208        | RPVList _ | RVGList _ | RLVList _
2209        | RStat _ | RStatVFS _
2210        | RHashtable _ ->
2211             pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
2212             pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
2213             pr "    return;\n";
2214             pr "  }\n";
2215       );
2216
2217       pr " done:\n";
2218       pr "  ctx->cb_sequence = 1000;\n";
2219       pr "  ml->main_loop_quit (ml, g);\n";
2220       pr "}\n\n";
2221
2222       (* Generate the action stub. *)
2223       generate_prototype ~extern:false ~semicolon:false ~newline:true
2224         ~handle:"g" name style;
2225
2226       let error_code =
2227         match fst style with
2228         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
2229         | RConstString _ ->
2230             failwithf "RConstString cannot be returned from a daemon function"
2231         | RString _ | RStringList _ | RIntBool _
2232         | RPVList _ | RVGList _ | RLVList _
2233         | RStat _ | RStatVFS _
2234         | RHashtable _ ->
2235             "NULL" in
2236
2237       pr "{\n";
2238
2239       (match snd style with
2240        | [] -> ()
2241        | _ -> pr "  struct %s_args args;\n" name
2242       );
2243
2244       pr "  struct %s_ctx ctx;\n" shortname;
2245       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2246       pr "  int serial;\n";
2247       pr "\n";
2248       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
2249       pr "\n";
2250       pr "  memset (&ctx, 0, sizeof ctx);\n";
2251       pr "\n";
2252
2253       (* Dispatch the main header and arguments. *)
2254       (match snd style with
2255        | [] ->
2256            pr "  serial = guestfs__send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
2257              (String.uppercase shortname)
2258        | args ->
2259            List.iter (
2260              function
2261              | String n ->
2262                  pr "  args.%s = (char *) %s;\n" n n
2263              | OptString n ->
2264                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
2265              | StringList n ->
2266                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
2267                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
2268              | Bool n ->
2269                  pr "  args.%s = %s;\n" n n
2270              | Int n ->
2271                  pr "  args.%s = %s;\n" n n
2272              | FileIn _ | FileOut _ -> ()
2273            ) args;
2274            pr "  serial = guestfs__send (g, GUESTFS_PROC_%s,\n"
2275              (String.uppercase shortname);
2276            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
2277              name;
2278       );
2279       pr "  if (serial == -1)\n";
2280       pr "    return %s;\n" error_code;
2281       pr "\n";
2282
2283       (* Send the request. *)
2284       pr "  ctx.cb_sequence = 0;\n";
2285       pr "  guestfs_set_send_callback (g, %s_send_cb, &ctx);\n" shortname;
2286       pr "  (void) ml->main_loop_run (ml, g);\n";
2287       pr "  guestfs_set_send_callback (g, NULL, NULL);\n";
2288       pr "  if (ctx.cb_sequence != 1) {\n";
2289       pr "    error (g, \"%%s send failed, see earlier error messages\", \"%s\");\n" name;
2290       pr "    return %s;\n" error_code;
2291       pr "  }\n";
2292       pr "\n";
2293
2294       (* Send any additional files requested. *)
2295       List.iter (
2296         function
2297         | FileIn n ->
2298             pr "  if (send_file (g, %s) == -1)\n" n;
2299             pr "    return %s;\n" error_code;
2300             pr "\n";
2301         | _ -> ()
2302       ) (snd style);
2303
2304       (* Wait for the reply from the remote end. *)
2305       pr "  ctx.cb_sequence = 0;\n";
2306       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
2307       pr "  (void) ml->main_loop_run (ml, g);\n";
2308       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
2309       pr "  if (ctx.cb_sequence != 1000) {\n";
2310       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
2311       pr "    return %s;\n" error_code;
2312       pr "  }\n";
2313       pr "\n";
2314
2315       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
2316         (String.uppercase shortname);
2317       pr "    return %s;\n" error_code;
2318       pr "\n";
2319
2320       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
2321       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
2322       pr "    return %s;\n" error_code;
2323       pr "  }\n";
2324       pr "\n";
2325
2326       (* Expecting to receive further files (FileOut)? *)
2327       List.iter (
2328         function
2329         | FileOut n ->
2330             pr "  if (receive_file (g, %s) == -1)\n" n;
2331             pr "    return %s;\n" error_code;
2332             pr "\n";
2333         | _ -> ()
2334       ) (snd style);
2335
2336       (match fst style with
2337        | RErr -> pr "  return 0;\n"
2338        | RInt n | RInt64 n | RBool n ->
2339            pr "  return ctx.ret.%s;\n" n
2340        | RConstString _ ->
2341            failwithf "RConstString cannot be returned from a daemon function"
2342        | RString n ->
2343            pr "  return ctx.ret.%s; /* caller will free */\n" n
2344        | RStringList n | RHashtable n ->
2345            pr "  /* caller will free this, but we need to add a NULL entry */\n";
2346            pr "  ctx.ret.%s.%s_val =\n" n n;
2347            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
2348            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
2349              n n;
2350            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
2351            pr "  return ctx.ret.%s.%s_val;\n" n n
2352        | RIntBool _ ->
2353            pr "  /* caller with free this */\n";
2354            pr "  return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
2355        | RPVList n | RVGList n | RLVList n
2356        | RStat n | RStatVFS n ->
2357            pr "  /* caller will free this */\n";
2358            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
2359       );
2360
2361       pr "}\n\n"
2362   ) daemon_functions
2363
2364 (* Generate daemon/actions.h. *)
2365 and generate_daemon_actions_h () =
2366   generate_header CStyle GPLv2;
2367
2368   pr "#include \"../src/guestfs_protocol.h\"\n";
2369   pr "\n";
2370
2371   List.iter (
2372     fun (name, style, _, _, _, _, _) ->
2373         generate_prototype
2374           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
2375           name style;
2376   ) daemon_functions
2377
2378 (* Generate the server-side stubs. *)
2379 and generate_daemon_actions () =
2380   generate_header CStyle GPLv2;
2381
2382   pr "#define _GNU_SOURCE // for strchrnul\n";
2383   pr "\n";
2384   pr "#include <stdio.h>\n";
2385   pr "#include <stdlib.h>\n";
2386   pr "#include <string.h>\n";
2387   pr "#include <inttypes.h>\n";
2388   pr "#include <ctype.h>\n";
2389   pr "#include <rpc/types.h>\n";
2390   pr "#include <rpc/xdr.h>\n";
2391   pr "\n";
2392   pr "#include \"daemon.h\"\n";
2393   pr "#include \"../src/guestfs_protocol.h\"\n";
2394   pr "#include \"actions.h\"\n";
2395   pr "\n";
2396
2397   List.iter (
2398     fun (name, style, _, _, _, _, _) ->
2399       (* Generate server-side stubs. *)
2400       pr "static void %s_stub (XDR *xdr_in)\n" name;
2401       pr "{\n";
2402       let error_code =
2403         match fst style with
2404         | RErr | RInt _ -> pr "  int r;\n"; "-1"
2405         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
2406         | RBool _ -> pr "  int r;\n"; "-1"
2407         | RConstString _ ->
2408             failwithf "RConstString cannot be returned from a daemon function"
2409         | RString _ -> pr "  char *r;\n"; "NULL"
2410         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
2411         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
2412         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
2413         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
2414         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL"
2415         | RStat _ -> pr "  guestfs_int_stat *r;\n"; "NULL"
2416         | RStatVFS _ -> pr "  guestfs_int_statvfs *r;\n"; "NULL" in
2417
2418       (match snd style with
2419        | [] -> ()
2420        | args ->
2421            pr "  struct guestfs_%s_args args;\n" name;
2422            List.iter (
2423              function
2424              | String n
2425              | OptString n -> pr "  const char *%s;\n" n
2426              | StringList n -> pr "  char **%s;\n" n
2427              | Bool n -> pr "  int %s;\n" n
2428              | Int n -> pr "  int %s;\n" n
2429              | FileIn _ | FileOut _ -> ()
2430            ) args
2431       );
2432       pr "\n";
2433
2434       (match snd style with
2435        | [] -> ()
2436        | args ->
2437            pr "  memset (&args, 0, sizeof args);\n";
2438            pr "\n";
2439            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
2440            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
2441            pr "    return;\n";
2442            pr "  }\n";
2443            List.iter (
2444              function
2445              | String n -> pr "  %s = args.%s;\n" n n
2446              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
2447              | StringList n ->
2448                  pr "  args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
2449                  pr "  args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
2450                  pr "  %s = args.%s.%s_val;\n" n n n
2451              | Bool n -> pr "  %s = args.%s;\n" n n
2452              | Int n -> pr "  %s = args.%s;\n" n n
2453              | FileIn _ | FileOut _ -> ()
2454            ) args;
2455            pr "\n"
2456       );
2457
2458       (* Don't want to call the impl with any FileIn or FileOut
2459        * parameters, since these go "outside" the RPC protocol.
2460        *)
2461       let argsnofile =
2462         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
2463           (snd style) in
2464       pr "  r = do_%s " name;
2465       generate_call_args argsnofile;
2466       pr ";\n";
2467
2468       pr "  if (r == %s)\n" error_code;
2469       pr "    /* do_%s has already called reply_with_error */\n" name;
2470       pr "    goto done;\n";
2471       pr "\n";
2472
2473       (* If there are any FileOut parameters, then the impl must
2474        * send its own reply.
2475        *)
2476       let no_reply =
2477         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
2478       if no_reply then
2479         pr "  /* do_%s has already sent a reply */\n" name
2480       else (
2481         match fst style with
2482         | RErr -> pr "  reply (NULL, NULL);\n"
2483         | RInt n | RInt64 n | RBool n ->
2484             pr "  struct guestfs_%s_ret ret;\n" name;
2485             pr "  ret.%s = r;\n" n;
2486             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2487               name
2488         | RConstString _ ->
2489             failwithf "RConstString cannot be returned from a daemon function"
2490         | RString n ->
2491             pr "  struct guestfs_%s_ret ret;\n" name;
2492             pr "  ret.%s = r;\n" n;
2493             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2494               name;
2495             pr "  free (r);\n"
2496         | RStringList n | RHashtable n ->
2497             pr "  struct guestfs_%s_ret ret;\n" name;
2498             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
2499             pr "  ret.%s.%s_val = r;\n" n n;
2500             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2501               name;
2502             pr "  free_strings (r);\n"
2503         | RIntBool _ ->
2504             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
2505               name;
2506             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2507         | RPVList n | RVGList n | RLVList n
2508         | RStat n | RStatVFS n ->
2509             pr "  struct guestfs_%s_ret ret;\n" name;
2510             pr "  ret.%s = *r;\n" n;
2511             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2512               name;
2513             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2514               name
2515       );
2516
2517       (* Free the args. *)
2518       (match snd style with
2519        | [] ->
2520            pr "done: ;\n";
2521        | _ ->
2522            pr "done:\n";
2523            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2524              name
2525       );
2526
2527       pr "}\n\n";
2528   ) daemon_functions;
2529
2530   (* Dispatch function. *)
2531   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2532   pr "{\n";
2533   pr "  switch (proc_nr) {\n";
2534
2535   List.iter (
2536     fun (name, style, _, _, _, _, _) ->
2537         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
2538         pr "      %s_stub (xdr_in);\n" name;
2539         pr "      break;\n"
2540   ) daemon_functions;
2541
2542   pr "    default:\n";
2543   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2544   pr "  }\n";
2545   pr "}\n";
2546   pr "\n";
2547
2548   (* LVM columns and tokenization functions. *)
2549   (* XXX This generates crap code.  We should rethink how we
2550    * do this parsing.
2551    *)
2552   List.iter (
2553     function
2554     | typ, cols ->
2555         pr "static const char *lvm_%s_cols = \"%s\";\n"
2556           typ (String.concat "," (List.map fst cols));
2557         pr "\n";
2558
2559         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2560         pr "{\n";
2561         pr "  char *tok, *p, *next;\n";
2562         pr "  int i, j;\n";
2563         pr "\n";
2564         (*
2565         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2566         pr "\n";
2567         *)
2568         pr "  if (!str) {\n";
2569         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2570         pr "    return -1;\n";
2571         pr "  }\n";
2572         pr "  if (!*str || isspace (*str)) {\n";
2573         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2574         pr "    return -1;\n";
2575         pr "  }\n";
2576         pr "  tok = str;\n";
2577         List.iter (
2578           fun (name, coltype) ->
2579             pr "  if (!tok) {\n";
2580             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2581             pr "    return -1;\n";
2582             pr "  }\n";
2583             pr "  p = strchrnul (tok, ',');\n";
2584             pr "  if (*p) next = p+1; else next = NULL;\n";
2585             pr "  *p = '\\0';\n";
2586             (match coltype with
2587              | `String ->
2588                  pr "  r->%s = strdup (tok);\n" name;
2589                  pr "  if (r->%s == NULL) {\n" name;
2590                  pr "    perror (\"strdup\");\n";
2591                  pr "    return -1;\n";
2592                  pr "  }\n"
2593              | `UUID ->
2594                  pr "  for (i = j = 0; i < 32; ++j) {\n";
2595                  pr "    if (tok[j] == '\\0') {\n";
2596                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2597                  pr "      return -1;\n";
2598                  pr "    } else if (tok[j] != '-')\n";
2599                  pr "      r->%s[i++] = tok[j];\n" name;
2600                  pr "  }\n";
2601              | `Bytes ->
2602                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2603                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2604                  pr "    return -1;\n";
2605                  pr "  }\n";
2606              | `Int ->
2607                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2608                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2609                  pr "    return -1;\n";
2610                  pr "  }\n";
2611              | `OptPercent ->
2612                  pr "  if (tok[0] == '\\0')\n";
2613                  pr "    r->%s = -1;\n" name;
2614                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2615                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2616                  pr "    return -1;\n";
2617                  pr "  }\n";
2618             );
2619             pr "  tok = next;\n";
2620         ) cols;
2621
2622         pr "  if (tok != NULL) {\n";
2623         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2624         pr "    return -1;\n";
2625         pr "  }\n";
2626         pr "  return 0;\n";
2627         pr "}\n";
2628         pr "\n";
2629
2630         pr "guestfs_lvm_int_%s_list *\n" typ;
2631         pr "parse_command_line_%ss (void)\n" typ;
2632         pr "{\n";
2633         pr "  char *out, *err;\n";
2634         pr "  char *p, *pend;\n";
2635         pr "  int r, i;\n";
2636         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
2637         pr "  void *newp;\n";
2638         pr "\n";
2639         pr "  ret = malloc (sizeof *ret);\n";
2640         pr "  if (!ret) {\n";
2641         pr "    reply_with_perror (\"malloc\");\n";
2642         pr "    return NULL;\n";
2643         pr "  }\n";
2644         pr "\n";
2645         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2646         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2647         pr "\n";
2648         pr "  r = command (&out, &err,\n";
2649         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
2650         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2651         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2652         pr "  if (r == -1) {\n";
2653         pr "    reply_with_error (\"%%s\", err);\n";
2654         pr "    free (out);\n";
2655         pr "    free (err);\n";
2656         pr "    free (ret);\n";
2657         pr "    return NULL;\n";
2658         pr "  }\n";
2659         pr "\n";
2660         pr "  free (err);\n";
2661         pr "\n";
2662         pr "  /* Tokenize each line of the output. */\n";
2663         pr "  p = out;\n";
2664         pr "  i = 0;\n";
2665         pr "  while (p) {\n";
2666         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
2667         pr "    if (pend) {\n";
2668         pr "      *pend = '\\0';\n";
2669         pr "      pend++;\n";
2670         pr "    }\n";
2671         pr "\n";
2672         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
2673         pr "      p++;\n";
2674         pr "\n";
2675         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
2676         pr "      p = pend;\n";
2677         pr "      continue;\n";
2678         pr "    }\n";
2679         pr "\n";
2680         pr "    /* Allocate some space to store this next entry. */\n";
2681         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2682         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2683         pr "    if (newp == NULL) {\n";
2684         pr "      reply_with_perror (\"realloc\");\n";
2685         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2686         pr "      free (ret);\n";
2687         pr "      free (out);\n";
2688         pr "      return NULL;\n";
2689         pr "    }\n";
2690         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2691         pr "\n";
2692         pr "    /* Tokenize the next entry. */\n";
2693         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2694         pr "    if (r == -1) {\n";
2695         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2696         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2697         pr "      free (ret);\n";
2698         pr "      free (out);\n";
2699         pr "      return NULL;\n";
2700         pr "    }\n";
2701         pr "\n";
2702         pr "    ++i;\n";
2703         pr "    p = pend;\n";
2704         pr "  }\n";
2705         pr "\n";
2706         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2707         pr "\n";
2708         pr "  free (out);\n";
2709         pr "  return ret;\n";
2710         pr "}\n"
2711
2712   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2713
2714 (* Generate the tests. *)
2715 and generate_tests () =
2716   generate_header CStyle GPLv2;
2717
2718   pr "\
2719 #include <stdio.h>
2720 #include <stdlib.h>
2721 #include <string.h>
2722 #include <unistd.h>
2723 #include <sys/types.h>
2724 #include <fcntl.h>
2725
2726 #include \"guestfs.h\"
2727
2728 static guestfs_h *g;
2729 static int suppress_error = 0;
2730
2731 static void print_error (guestfs_h *g, void *data, const char *msg)
2732 {
2733   if (!suppress_error)
2734     fprintf (stderr, \"%%s\\n\", msg);
2735 }
2736
2737 static void print_strings (char * const * const argv)
2738 {
2739   int argc;
2740
2741   for (argc = 0; argv[argc] != NULL; ++argc)
2742     printf (\"\\t%%s\\n\", argv[argc]);
2743 }
2744
2745 /*
2746 static void print_table (char * const * const argv)
2747 {
2748   int i;
2749
2750   for (i = 0; argv[i] != NULL; i += 2)
2751     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
2752 }
2753 */
2754
2755 static void no_test_warnings (void)
2756 {
2757 ";
2758
2759   List.iter (
2760     function
2761     | name, _, _, _, [], _, _ ->
2762         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
2763     | name, _, _, _, tests, _, _ -> ()
2764   ) all_functions;
2765
2766   pr "}\n";
2767   pr "\n";
2768
2769   (* Generate the actual tests.  Note that we generate the tests
2770    * in reverse order, deliberately, so that (in general) the
2771    * newest tests run first.  This makes it quicker and easier to
2772    * debug them.
2773    *)
2774   let test_names =
2775     List.map (
2776       fun (name, _, _, _, tests, _, _) ->
2777         mapi (generate_one_test name) tests
2778     ) (List.rev all_functions) in
2779   let test_names = List.concat test_names in
2780   let nr_tests = List.length test_names in
2781
2782   pr "\
2783 int main (int argc, char *argv[])
2784 {
2785   char c = 0;
2786   int failed = 0;
2787   const char *srcdir;
2788   int fd;
2789   char buf[256];
2790   int nr_tests, test_num = 0;
2791
2792   no_test_warnings ();
2793
2794   g = guestfs_create ();
2795   if (g == NULL) {
2796     printf (\"guestfs_create FAILED\\n\");
2797     exit (1);
2798   }
2799
2800   guestfs_set_error_handler (g, print_error, NULL);
2801
2802   srcdir = getenv (\"srcdir\");
2803   if (!srcdir) srcdir = \".\";
2804   guestfs_set_path (g, srcdir);
2805
2806   snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
2807   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2808   if (fd == -1) {
2809     perror (buf);
2810     exit (1);
2811   }
2812   if (lseek (fd, %d, SEEK_SET) == -1) {
2813     perror (\"lseek\");
2814     close (fd);
2815     unlink (buf);
2816     exit (1);
2817   }
2818   if (write (fd, &c, 1) == -1) {
2819     perror (\"write\");
2820     close (fd);
2821     unlink (buf);
2822     exit (1);
2823   }
2824   if (close (fd) == -1) {
2825     perror (buf);
2826     unlink (buf);
2827     exit (1);
2828   }
2829   if (guestfs_add_drive (g, buf) == -1) {
2830     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2831     exit (1);
2832   }
2833
2834   snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
2835   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2836   if (fd == -1) {
2837     perror (buf);
2838     exit (1);
2839   }
2840   if (lseek (fd, %d, SEEK_SET) == -1) {
2841     perror (\"lseek\");
2842     close (fd);
2843     unlink (buf);
2844     exit (1);
2845   }
2846   if (write (fd, &c, 1) == -1) {
2847     perror (\"write\");
2848     close (fd);
2849     unlink (buf);
2850     exit (1);
2851   }
2852   if (close (fd) == -1) {
2853     perror (buf);
2854     unlink (buf);
2855     exit (1);
2856   }
2857   if (guestfs_add_drive (g, buf) == -1) {
2858     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2859     exit (1);
2860   }
2861
2862   snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
2863   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2864   if (fd == -1) {
2865     perror (buf);
2866     exit (1);
2867   }
2868   if (lseek (fd, %d, SEEK_SET) == -1) {
2869     perror (\"lseek\");
2870     close (fd);
2871     unlink (buf);
2872     exit (1);
2873   }
2874   if (write (fd, &c, 1) == -1) {
2875     perror (\"write\");
2876     close (fd);
2877     unlink (buf);
2878     exit (1);
2879   }
2880   if (close (fd) == -1) {
2881     perror (buf);
2882     unlink (buf);
2883     exit (1);
2884   }
2885   if (guestfs_add_drive (g, buf) == -1) {
2886     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2887     exit (1);
2888   }
2889
2890   if (guestfs_launch (g) == -1) {
2891     printf (\"guestfs_launch FAILED\\n\");
2892     exit (1);
2893   }
2894   if (guestfs_wait_ready (g) == -1) {
2895     printf (\"guestfs_wait_ready FAILED\\n\");
2896     exit (1);
2897   }
2898
2899   nr_tests = %d;
2900
2901 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
2902
2903   iteri (
2904     fun i test_name ->
2905       pr "  test_num++;\n";
2906       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
2907       pr "  if (%s () == -1) {\n" test_name;
2908       pr "    printf (\"%s FAILED\\n\");\n" test_name;
2909       pr "    failed++;\n";
2910       pr "  }\n";
2911   ) test_names;
2912   pr "\n";
2913
2914   pr "  guestfs_close (g);\n";
2915   pr "  snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
2916   pr "  unlink (buf);\n";
2917   pr "  snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
2918   pr "  unlink (buf);\n";
2919   pr "  snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
2920   pr "  unlink (buf);\n";
2921   pr "\n";
2922
2923   pr "  if (failed > 0) {\n";
2924   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
2925   pr "    exit (1);\n";
2926   pr "  }\n";
2927   pr "\n";
2928
2929   pr "  exit (0);\n";
2930   pr "}\n"
2931
2932 and generate_one_test name i (init, test) =
2933   let test_name = sprintf "test_%s_%d" name i in
2934
2935   pr "static int %s (void)\n" test_name;
2936   pr "{\n";
2937
2938   (match init with
2939    | InitNone -> ()
2940    | InitEmpty ->
2941        pr "  /* InitEmpty for %s (%d) */\n" name i;
2942        List.iter (generate_test_command_call test_name)
2943          [["umount_all"];
2944           ["lvm_remove_all"]]
2945    | InitBasicFS ->
2946        pr "  /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
2947        List.iter (generate_test_command_call test_name)
2948          [["umount_all"];
2949           ["lvm_remove_all"];
2950           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2951           ["mkfs"; "ext2"; "/dev/sda1"];
2952           ["mount"; "/dev/sda1"; "/"]]
2953    | InitBasicFSonLVM ->
2954        pr "  /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
2955          name i;
2956        List.iter (generate_test_command_call test_name)
2957          [["umount_all"];
2958           ["lvm_remove_all"];
2959           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2960           ["pvcreate"; "/dev/sda1"];
2961           ["vgcreate"; "VG"; "/dev/sda1"];
2962           ["lvcreate"; "LV"; "VG"; "8"];
2963           ["mkfs"; "ext2"; "/dev/VG/LV"];
2964           ["mount"; "/dev/VG/LV"; "/"]]
2965   );
2966
2967   let get_seq_last = function
2968     | [] ->
2969         failwithf "%s: you cannot use [] (empty list) when expecting a command"
2970           test_name
2971     | seq ->
2972         let seq = List.rev seq in
2973         List.rev (List.tl seq), List.hd seq
2974   in
2975
2976   (match test with
2977    | TestRun seq ->
2978        pr "  /* TestRun for %s (%d) */\n" name i;
2979        List.iter (generate_test_command_call test_name) seq
2980    | TestOutput (seq, expected) ->
2981        pr "  /* TestOutput for %s (%d) */\n" name i;
2982        let seq, last = get_seq_last seq in
2983        let test () =
2984          pr "    if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
2985          pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
2986          pr "      return -1;\n";
2987          pr "    }\n"
2988        in
2989        List.iter (generate_test_command_call test_name) seq;
2990        generate_test_command_call ~test test_name last
2991    | TestOutputList (seq, expected) ->
2992        pr "  /* TestOutputList for %s (%d) */\n" name i;
2993        let seq, last = get_seq_last seq in
2994        let test () =
2995          iteri (
2996            fun i str ->
2997              pr "    if (!r[%d]) {\n" i;
2998              pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
2999              pr "      print_strings (r);\n";
3000              pr "      return -1;\n";
3001              pr "    }\n";
3002              pr "    if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
3003              pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
3004              pr "      return -1;\n";
3005              pr "    }\n"
3006          ) expected;
3007          pr "    if (r[%d] != NULL) {\n" (List.length expected);
3008          pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
3009            test_name;
3010          pr "      print_strings (r);\n";
3011          pr "      return -1;\n";
3012          pr "    }\n"
3013        in
3014        List.iter (generate_test_command_call test_name) seq;
3015        generate_test_command_call ~test test_name last
3016    | TestOutputInt (seq, expected) ->
3017        pr "  /* TestOutputInt for %s (%d) */\n" name i;
3018        let seq, last = get_seq_last seq in
3019        let test () =
3020          pr "    if (r != %d) {\n" expected;
3021          pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
3022            test_name expected;
3023          pr "               (int) r);\n";
3024          pr "      return -1;\n";
3025          pr "    }\n"
3026        in
3027        List.iter (generate_test_command_call test_name) seq;
3028        generate_test_command_call ~test test_name last
3029    | TestOutputTrue seq ->
3030        pr "  /* TestOutputTrue for %s (%d) */\n" name i;
3031        let seq, last = get_seq_last seq in
3032        let test () =
3033          pr "    if (!r) {\n";
3034          pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
3035            test_name;
3036          pr "      return -1;\n";
3037          pr "    }\n"
3038        in
3039        List.iter (generate_test_command_call test_name) seq;
3040        generate_test_command_call ~test test_name last
3041    | TestOutputFalse seq ->
3042        pr "  /* TestOutputFalse for %s (%d) */\n" name i;
3043        let seq, last = get_seq_last seq in
3044        let test () =
3045          pr "    if (r) {\n";
3046          pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
3047            test_name;
3048          pr "      return -1;\n";
3049          pr "    }\n"
3050        in
3051        List.iter (generate_test_command_call test_name) seq;
3052        generate_test_command_call ~test test_name last
3053    | TestOutputLength (seq, expected) ->
3054        pr "  /* TestOutputLength for %s (%d) */\n" name i;
3055        let seq, last = get_seq_last seq in
3056        let test () =
3057          pr "    int j;\n";
3058          pr "    for (j = 0; j < %d; ++j)\n" expected;
3059          pr "      if (r[j] == NULL) {\n";
3060          pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
3061            test_name;
3062          pr "        print_strings (r);\n";
3063          pr "        return -1;\n";
3064          pr "      }\n";
3065          pr "    if (r[j] != NULL) {\n";
3066          pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
3067            test_name;
3068          pr "      print_strings (r);\n";
3069          pr "      return -1;\n";
3070          pr "    }\n"
3071        in
3072        List.iter (generate_test_command_call test_name) seq;
3073        generate_test_command_call ~test test_name last
3074    | TestOutputStruct (seq, checks) ->
3075        pr "  /* TestOutputStruct for %s (%d) */\n" name i;
3076        let seq, last = get_seq_last seq in
3077        let test () =
3078          List.iter (
3079            function
3080            | CompareWithInt (field, expected) ->
3081                pr "    if (r->%s != %d) {\n" field expected;
3082                pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
3083                  test_name field expected;
3084                pr "               (int) r->%s);\n" field;
3085                pr "      return -1;\n";
3086                pr "    }\n"
3087            | CompareWithString (field, expected) ->
3088                pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
3089                pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
3090                  test_name field expected;
3091                pr "               r->%s);\n" field;
3092                pr "      return -1;\n";
3093                pr "    }\n"
3094            | CompareFieldsIntEq (field1, field2) ->
3095                pr "    if (r->%s != r->%s) {\n" field1 field2;
3096                pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
3097                  test_name field1 field2;
3098                pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
3099                pr "      return -1;\n";
3100                pr "    }\n"
3101            | CompareFieldsStrEq (field1, field2) ->
3102                pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
3103                pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
3104                  test_name field1 field2;
3105                pr "               r->%s, r->%s);\n" field1 field2;
3106                pr "      return -1;\n";
3107                pr "    }\n"
3108          ) checks
3109        in
3110        List.iter (generate_test_command_call test_name) seq;
3111        generate_test_command_call ~test test_name last
3112    | TestLastFail seq ->
3113        pr "  /* TestLastFail for %s (%d) */\n" name i;
3114        let seq, last = get_seq_last seq in
3115        List.iter (generate_test_command_call test_name) seq;
3116        generate_test_command_call test_name ~expect_error:true last
3117   );
3118
3119   pr "  return 0;\n";
3120   pr "}\n";
3121   pr "\n";
3122   test_name
3123
3124 (* Generate the code to run a command, leaving the result in 'r'.
3125  * If you expect to get an error then you should set expect_error:true.
3126  *)
3127 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
3128   match cmd with
3129   | [] -> assert false
3130   | name :: args ->
3131       (* Look up the command to find out what args/ret it has. *)
3132       let style =
3133         try
3134           let _, style, _, _, _, _, _ =
3135             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
3136           style
3137         with Not_found ->
3138           failwithf "%s: in test, command %s was not found" test_name name in
3139
3140       if List.length (snd style) <> List.length args then
3141         failwithf "%s: in test, wrong number of args given to %s"
3142           test_name name;
3143
3144       pr "  {\n";
3145
3146       List.iter (
3147         function
3148         | String _, _
3149         | OptString _, _
3150         | Int _, _
3151         | Bool _, _ -> ()
3152         | FileIn _, _ | FileOut _, _ -> ()
3153         | StringList n, arg ->
3154             pr "    char *%s[] = {\n" n;
3155             let strs = string_split " " arg in
3156             List.iter (
3157               fun str -> pr "      \"%s\",\n" (c_quote str)
3158             ) strs;
3159             pr "      NULL\n";
3160             pr "    };\n";
3161       ) (List.combine (snd style) args);
3162
3163       let error_code =
3164         match fst style with
3165         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
3166         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
3167         | RConstString _ -> pr "    const char *r;\n"; "NULL"
3168         | RString _ -> pr "    char *r;\n"; "NULL"
3169         | RStringList _ | RHashtable _ ->
3170             pr "    char **r;\n";
3171             pr "    int i;\n";
3172             "NULL"
3173         | RIntBool _ ->
3174             pr "    struct guestfs_int_bool *r;\n"; "NULL"
3175         | RPVList _ ->
3176             pr "    struct guestfs_lvm_pv_list *r;\n"; "NULL"
3177         | RVGList _ ->
3178             pr "    struct guestfs_lvm_vg_list *r;\n"; "NULL"
3179         | RLVList _ ->
3180             pr "    struct guestfs_lvm_lv_list *r;\n"; "NULL"
3181         | RStat _ ->
3182             pr "    struct guestfs_stat *r;\n"; "NULL"
3183         | RStatVFS _ ->
3184             pr "    struct guestfs_statvfs *r;\n"; "NULL" in
3185
3186       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
3187       pr "    r = guestfs_%s (g" name;
3188
3189       (* Generate the parameters. *)
3190       List.iter (
3191         function
3192         | String _, arg
3193         | FileIn _, arg | FileOut _, arg ->
3194             pr ", \"%s\"" (c_quote arg)
3195         | OptString _, arg ->
3196             if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
3197         | StringList n, _ ->
3198             pr ", %s" n
3199         | Int _, arg ->
3200             let i =
3201               try int_of_string arg
3202               with Failure "int_of_string" ->
3203                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
3204             pr ", %d" i
3205         | Bool _, arg ->
3206             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
3207       ) (List.combine (snd style) args);
3208
3209       pr ");\n";
3210       if not expect_error then
3211         pr "    if (r == %s)\n" error_code
3212       else
3213         pr "    if (r != %s)\n" error_code;
3214       pr "      return -1;\n";
3215
3216       (* Insert the test code. *)
3217       (match test with
3218        | None -> ()
3219        | Some f -> f ()
3220       );
3221
3222       (match fst style with
3223        | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
3224        | RString _ -> pr "    free (r);\n"
3225        | RStringList _ | RHashtable _ ->
3226            pr "    for (i = 0; r[i] != NULL; ++i)\n";
3227            pr "      free (r[i]);\n";
3228            pr "    free (r);\n"
3229        | RIntBool _ ->
3230            pr "    guestfs_free_int_bool (r);\n"
3231        | RPVList _ ->
3232            pr "    guestfs_free_lvm_pv_list (r);\n"
3233        | RVGList _ ->
3234            pr "    guestfs_free_lvm_vg_list (r);\n"
3235        | RLVList _ ->
3236            pr "    guestfs_free_lvm_lv_list (r);\n"
3237        | RStat _ | RStatVFS _ ->
3238            pr "    free (r);\n"
3239       );
3240
3241       pr "  }\n"
3242
3243 and c_quote str =
3244   let str = replace_str str "\r" "\\r" in
3245   let str = replace_str str "\n" "\\n" in
3246   let str = replace_str str "\t" "\\t" in
3247   str
3248
3249 (* Generate a lot of different functions for guestfish. *)
3250 and generate_fish_cmds () =
3251   generate_header CStyle GPLv2;
3252
3253   let all_functions =
3254     List.filter (
3255       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3256     ) all_functions in
3257   let all_functions_sorted =
3258     List.filter (
3259       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3260     ) all_functions_sorted in
3261
3262   pr "#include <stdio.h>\n";
3263   pr "#include <stdlib.h>\n";
3264   pr "#include <string.h>\n";
3265   pr "#include <inttypes.h>\n";
3266   pr "\n";
3267   pr "#include <guestfs.h>\n";
3268   pr "#include \"fish.h\"\n";
3269   pr "\n";
3270
3271   (* list_commands function, which implements guestfish -h *)
3272   pr "void list_commands (void)\n";
3273   pr "{\n";
3274   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
3275   pr "  list_builtin_commands ();\n";
3276   List.iter (
3277     fun (name, _, _, flags, _, shortdesc, _) ->
3278       let name = replace_char name '_' '-' in
3279       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
3280         name shortdesc
3281   ) all_functions_sorted;
3282   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
3283   pr "}\n";
3284   pr "\n";
3285
3286   (* display_command function, which implements guestfish -h cmd *)
3287   pr "void display_command (const char *cmd)\n";
3288   pr "{\n";
3289   List.iter (
3290     fun (name, style, _, flags, _, shortdesc, longdesc) ->
3291       let name2 = replace_char name '_' '-' in
3292       let alias =
3293         try find_map (function FishAlias n -> Some n | _ -> None) flags
3294         with Not_found -> name in
3295       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3296       let synopsis =
3297         match snd style with
3298         | [] -> name2
3299         | args ->
3300             sprintf "%s <%s>"
3301               name2 (String.concat "> <" (List.map name_of_argt args)) in
3302
3303       let warnings =
3304         if List.mem ProtocolLimitWarning flags then
3305           ("\n\n" ^ protocol_limit_warning)
3306         else "" in
3307
3308       (* For DangerWillRobinson commands, we should probably have
3309        * guestfish prompt before allowing you to use them (especially
3310        * in interactive mode). XXX
3311        *)
3312       let warnings =
3313         warnings ^
3314           if List.mem DangerWillRobinson flags then
3315             ("\n\n" ^ danger_will_robinson)
3316           else "" in
3317
3318       let describe_alias =
3319         if name <> alias then
3320           sprintf "\n\nYou can use '%s' as an alias for this command." alias
3321         else "" in
3322
3323       pr "  if (";
3324       pr "strcasecmp (cmd, \"%s\") == 0" name;
3325       if name <> name2 then
3326         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3327       if name <> alias then
3328         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3329       pr ")\n";
3330       pr "    pod2text (\"%s - %s\", %S);\n"
3331         name2 shortdesc
3332         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
3333       pr "  else\n"
3334   ) all_functions;
3335   pr "    display_builtin_command (cmd);\n";
3336   pr "}\n";
3337   pr "\n";
3338
3339   (* print_{pv,vg,lv}_list functions *)
3340   List.iter (
3341     function
3342     | typ, cols ->
3343         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
3344         pr "{\n";
3345         pr "  int i;\n";
3346         pr "\n";
3347         List.iter (
3348           function
3349           | name, `String ->
3350               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
3351           | name, `UUID ->
3352               pr "  printf (\"%s: \");\n" name;
3353               pr "  for (i = 0; i < 32; ++i)\n";
3354               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
3355               pr "  printf (\"\\n\");\n"
3356           | name, `Bytes ->
3357               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
3358           | name, `Int ->
3359               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3360           | name, `OptPercent ->
3361               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
3362                 typ name name typ name;
3363               pr "  else printf (\"%s: \\n\");\n" name
3364         ) cols;
3365         pr "}\n";
3366         pr "\n";
3367         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
3368           typ typ typ;
3369         pr "{\n";
3370         pr "  int i;\n";
3371         pr "\n";
3372         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
3373         pr "    print_%s (&%ss->val[i]);\n" typ typ;
3374         pr "}\n";
3375         pr "\n";
3376   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3377
3378   (* print_{stat,statvfs} functions *)
3379   List.iter (
3380     function
3381     | typ, cols ->
3382         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
3383         pr "{\n";
3384         List.iter (
3385           function
3386           | name, `Int ->
3387               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3388         ) cols;
3389         pr "}\n";
3390         pr "\n";
3391   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3392
3393   (* run_<action> actions *)
3394   List.iter (
3395     fun (name, style, _, flags, _, _, _) ->
3396       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
3397       pr "{\n";
3398       (match fst style with
3399        | RErr
3400        | RInt _
3401        | RBool _ -> pr "  int r;\n"
3402        | RInt64 _ -> pr "  int64_t r;\n"
3403        | RConstString _ -> pr "  const char *r;\n"
3404        | RString _ -> pr "  char *r;\n"
3405        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
3406        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
3407        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
3408        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
3409        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
3410        | RStat _ -> pr "  struct guestfs_stat *r;\n"
3411        | RStatVFS _ -> pr "  struct guestfs_statvfs *r;\n"
3412       );
3413       List.iter (
3414         function
3415         | String n
3416         | OptString n
3417         | FileIn n
3418         | FileOut n -> pr "  const char *%s;\n" n
3419         | StringList n -> pr "  char **%s;\n" n
3420         | Bool n -> pr "  int %s;\n" n
3421         | Int n -> pr "  int %s;\n" n
3422       ) (snd style);
3423
3424       (* Check and convert parameters. *)
3425       let argc_expected = List.length (snd style) in
3426       pr "  if (argc != %d) {\n" argc_expected;
3427       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
3428         argc_expected;
3429       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
3430       pr "    return -1;\n";
3431       pr "  }\n";
3432       iteri (
3433         fun i ->
3434           function
3435           | String name -> pr "  %s = argv[%d];\n" name i
3436           | OptString name ->
3437               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
3438                 name i i
3439           | FileIn name ->
3440               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
3441                 name i i
3442           | FileOut name ->
3443               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
3444                 name i i
3445           | StringList name ->
3446               pr "  %s = parse_string_list (argv[%d]);\n" name i
3447           | Bool name ->
3448               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
3449           | Int name ->
3450               pr "  %s = atoi (argv[%d]);\n" name i
3451       ) (snd style);
3452
3453       (* Call C API function. *)
3454       let fn =
3455         try find_map (function FishAction n -> Some n | _ -> None) flags
3456         with Not_found -> sprintf "guestfs_%s" name in
3457       pr "  r = %s " fn;
3458       generate_call_args ~handle:"g" (snd style);
3459       pr ";\n";
3460
3461       (* Check return value for errors and display command results. *)
3462       (match fst style with
3463        | RErr -> pr "  return r;\n"
3464        | RInt _ ->
3465            pr "  if (r == -1) return -1;\n";
3466            pr "  printf (\"%%d\\n\", r);\n";
3467            pr "  return 0;\n"
3468        | RInt64 _ ->
3469            pr "  if (r == -1) return -1;\n";
3470            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
3471            pr "  return 0;\n"
3472        | RBool _ ->
3473            pr "  if (r == -1) return -1;\n";
3474            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
3475            pr "  return 0;\n"
3476        | RConstString _ ->
3477            pr "  if (r == NULL) return -1;\n";
3478            pr "  printf (\"%%s\\n\", r);\n";
3479            pr "  return 0;\n"
3480        | RString _ ->
3481            pr "  if (r == NULL) return -1;\n";
3482            pr "  printf (\"%%s\\n\", r);\n";
3483            pr "  free (r);\n";
3484            pr "  return 0;\n"
3485        | RStringList _ ->
3486            pr "  if (r == NULL) return -1;\n";
3487            pr "  print_strings (r);\n";
3488            pr "  free_strings (r);\n";
3489            pr "  return 0;\n"
3490        | RIntBool _ ->
3491            pr "  if (r == NULL) return -1;\n";
3492            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
3493            pr "    r->b ? \"true\" : \"false\");\n";
3494            pr "  guestfs_free_int_bool (r);\n";
3495            pr "  return 0;\n"
3496        | RPVList _ ->
3497            pr "  if (r == NULL) return -1;\n";
3498            pr "  print_pv_list (r);\n";
3499            pr "  guestfs_free_lvm_pv_list (r);\n";
3500            pr "  return 0;\n"
3501        | RVGList _ ->
3502            pr "  if (r == NULL) return -1;\n";
3503            pr "  print_vg_list (r);\n";
3504            pr "  guestfs_free_lvm_vg_list (r);\n";
3505            pr "  return 0;\n"
3506        | RLVList _ ->
3507            pr "  if (r == NULL) return -1;\n";
3508            pr "  print_lv_list (r);\n";
3509            pr "  guestfs_free_lvm_lv_list (r);\n";
3510            pr "  return 0;\n"
3511        | RStat _ ->
3512            pr "  if (r == NULL) return -1;\n";
3513            pr "  print_stat (r);\n";
3514            pr "  free (r);\n";
3515            pr "  return 0;\n"
3516        | RStatVFS _ ->
3517            pr "  if (r == NULL) return -1;\n";
3518            pr "  print_statvfs (r);\n";
3519            pr "  free (r);\n";
3520            pr "  return 0;\n"
3521        | RHashtable _ ->
3522            pr "  if (r == NULL) return -1;\n";
3523            pr "  print_table (r);\n";
3524            pr "  free_strings (r);\n";
3525            pr "  return 0;\n"
3526       );
3527       pr "}\n";
3528       pr "\n"
3529   ) all_functions;
3530
3531   (* run_action function *)
3532   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3533   pr "{\n";
3534   List.iter (
3535     fun (name, _, _, flags, _, _, _) ->
3536       let name2 = replace_char name '_' '-' in
3537       let alias =
3538         try find_map (function FishAlias n -> Some n | _ -> None) flags
3539         with Not_found -> name in
3540       pr "  if (";
3541       pr "strcasecmp (cmd, \"%s\") == 0" name;
3542       if name <> name2 then
3543         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3544       if name <> alias then
3545         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3546       pr ")\n";
3547       pr "    return run_%s (cmd, argc, argv);\n" name;
3548       pr "  else\n";
3549   ) all_functions;
3550   pr "    {\n";
3551   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3552   pr "      return -1;\n";
3553   pr "    }\n";
3554   pr "  return 0;\n";
3555   pr "}\n";
3556   pr "\n"
3557
3558 (* Readline completion for guestfish. *)
3559 and generate_fish_completion () =
3560   generate_header CStyle GPLv2;
3561
3562   let all_functions =
3563     List.filter (
3564       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3565     ) all_functions in
3566
3567   pr "\
3568 #include <config.h>
3569
3570 #include <stdio.h>
3571 #include <stdlib.h>
3572 #include <string.h>
3573
3574 #ifdef HAVE_LIBREADLINE
3575 #include <readline/readline.h>
3576 #endif
3577
3578 #include \"fish.h\"
3579
3580 #ifdef HAVE_LIBREADLINE
3581
3582 static const char *commands[] = {
3583 ";
3584
3585   (* Get the commands and sort them, including the aliases. *)
3586   let commands =
3587     List.map (
3588       fun (name, _, _, flags, _, _, _) ->
3589         let name2 = replace_char name '_' '-' in
3590         let alias =
3591           try find_map (function FishAlias n -> Some n | _ -> None) flags
3592           with Not_found -> name in
3593
3594         if name <> alias then [name2; alias] else [name2]
3595     ) all_functions in
3596   let commands = List.flatten commands in
3597   let commands = List.sort compare commands in
3598
3599   List.iter (pr "  \"%s\",\n") commands;
3600
3601   pr "  NULL
3602 };
3603
3604 static char *
3605 generator (const char *text, int state)
3606 {
3607   static int index, len;
3608   const char *name;
3609
3610   if (!state) {
3611     index = 0;
3612     len = strlen (text);
3613   }
3614
3615   while ((name = commands[index]) != NULL) {
3616     index++;
3617     if (strncasecmp (name, text, len) == 0)
3618       return strdup (name);
3619   }
3620
3621   return NULL;
3622 }
3623
3624 #endif /* HAVE_LIBREADLINE */
3625
3626 char **do_completion (const char *text, int start, int end)
3627 {
3628   char **matches = NULL;
3629
3630 #ifdef HAVE_LIBREADLINE
3631   if (start == 0)
3632     matches = rl_completion_matches (text, generator);
3633 #endif
3634
3635   return matches;
3636 }
3637 ";
3638
3639 (* Generate the POD documentation for guestfish. *)
3640 and generate_fish_actions_pod () =
3641   let all_functions_sorted =
3642     List.filter (
3643       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3644     ) all_functions_sorted in
3645
3646   List.iter (
3647     fun (name, style, _, flags, _, _, longdesc) ->
3648       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3649       let name = replace_char name '_' '-' in
3650       let alias =
3651         try find_map (function FishAlias n -> Some n | _ -> None) flags
3652         with Not_found -> name in
3653
3654       pr "=head2 %s" name;
3655       if name <> alias then
3656         pr " | %s" alias;
3657       pr "\n";
3658       pr "\n";
3659       pr " %s" name;
3660       List.iter (
3661         function
3662         | String n -> pr " %s" n
3663         | OptString n -> pr " %s" n
3664         | StringList n -> pr " %s,..." n
3665         | Bool _ -> pr " true|false"
3666         | Int n -> pr " %s" n
3667         | FileIn n | FileOut n -> pr " (%s|-)" n
3668       ) (snd style);
3669       pr "\n";
3670       pr "\n";
3671       pr "%s\n\n" longdesc;
3672
3673       if List.exists (function FileIn _ | FileOut _ -> true
3674                       | _ -> false) (snd style) then
3675         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
3676
3677       if List.mem ProtocolLimitWarning flags then
3678         pr "%s\n\n" protocol_limit_warning;
3679
3680       if List.mem DangerWillRobinson flags then
3681         pr "%s\n\n" danger_will_robinson
3682   ) all_functions_sorted
3683
3684 (* Generate a C function prototype. *)
3685 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3686     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3687     ?(prefix = "")
3688     ?handle name style =
3689   if extern then pr "extern ";
3690   if static then pr "static ";
3691   (match fst style with
3692    | RErr -> pr "int "
3693    | RInt _ -> pr "int "
3694    | RInt64 _ -> pr "int64_t "
3695    | RBool _ -> pr "int "
3696    | RConstString _ -> pr "const char *"
3697    | RString _ -> pr "char *"
3698    | RStringList _ | RHashtable _ -> pr "char **"
3699    | RIntBool _ ->
3700        if not in_daemon then pr "struct guestfs_int_bool *"
3701        else pr "guestfs_%s_ret *" name
3702    | RPVList _ ->
3703        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3704        else pr "guestfs_lvm_int_pv_list *"
3705    | RVGList _ ->
3706        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3707        else pr "guestfs_lvm_int_vg_list *"
3708    | RLVList _ ->
3709        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3710        else pr "guestfs_lvm_int_lv_list *"
3711    | RStat _ ->
3712        if not in_daemon then pr "struct guestfs_stat *"
3713        else pr "guestfs_int_stat *"
3714    | RStatVFS _ ->
3715        if not in_daemon then pr "struct guestfs_statvfs *"
3716        else pr "guestfs_int_statvfs *"
3717   );
3718   pr "%s%s (" prefix name;
3719   if handle = None && List.length (snd style) = 0 then
3720     pr "void"
3721   else (
3722     let comma = ref false in
3723     (match handle with
3724      | None -> ()
3725      | Some handle -> pr "guestfs_h *%s" handle; comma := true
3726     );
3727     let next () =
3728       if !comma then (
3729         if single_line then pr ", " else pr ",\n\t\t"
3730       );
3731       comma := true
3732     in
3733     List.iter (
3734       function
3735       | String n
3736       | OptString n -> next (); pr "const char *%s" n
3737       | StringList n -> next (); pr "char * const* const %s" n
3738       | Bool n -> next (); pr "int %s" n
3739       | Int n -> next (); pr "int %s" n
3740       | FileIn n
3741       | FileOut n ->
3742           if not in_daemon then (next (); pr "const char *%s" n)
3743     ) (snd style);
3744   );
3745   pr ")";
3746   if semicolon then pr ";";
3747   if newline then pr "\n"
3748
3749 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3750 and generate_call_args ?handle args =
3751   pr "(";
3752   let comma = ref false in
3753   (match handle with
3754    | None -> ()
3755    | Some handle -> pr "%s" handle; comma := true
3756   );
3757   List.iter (
3758     fun arg ->
3759       if !comma then pr ", ";
3760       comma := true;
3761       pr "%s" (name_of_argt arg)
3762   ) args;
3763   pr ")"
3764
3765 (* Generate the OCaml bindings interface. *)
3766 and generate_ocaml_mli () =
3767   generate_header OCamlStyle LGPLv2;
3768
3769   pr "\
3770 (** For API documentation you should refer to the C API
3771     in the guestfs(3) manual page.  The OCaml API uses almost
3772     exactly the same calls. *)
3773
3774 type t
3775 (** A [guestfs_h] handle. *)
3776
3777 exception Error of string
3778 (** This exception is raised when there is an error. *)
3779
3780 val create : unit -> t
3781
3782 val close : t -> unit
3783 (** Handles are closed by the garbage collector when they become
3784     unreferenced, but callers can also call this in order to
3785     provide predictable cleanup. *)
3786
3787 ";
3788   generate_ocaml_lvm_structure_decls ();
3789
3790   generate_ocaml_stat_structure_decls ();
3791
3792   (* The actions. *)
3793   List.iter (
3794     fun (name, style, _, _, _, shortdesc, _) ->
3795       generate_ocaml_prototype name style;
3796       pr "(** %s *)\n" shortdesc;
3797       pr "\n"
3798   ) all_functions
3799
3800 (* Generate the OCaml bindings implementation. *)
3801 and generate_ocaml_ml () =
3802   generate_header OCamlStyle LGPLv2;
3803
3804   pr "\
3805 type t
3806 exception Error of string
3807 external create : unit -> t = \"ocaml_guestfs_create\"
3808 external close : t -> unit = \"ocaml_guestfs_close\"
3809
3810 let () =
3811   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3812
3813 ";
3814
3815   generate_ocaml_lvm_structure_decls ();
3816
3817   generate_ocaml_stat_structure_decls ();
3818
3819   (* The actions. *)
3820   List.iter (
3821     fun (name, style, _, _, _, shortdesc, _) ->
3822       generate_ocaml_prototype ~is_external:true name style;
3823   ) all_functions
3824
3825 (* Generate the OCaml bindings C implementation. *)
3826 and generate_ocaml_c () =
3827   generate_header CStyle LGPLv2;
3828
3829   pr "\
3830 #include <stdio.h>
3831 #include <stdlib.h>
3832 #include <string.h>
3833
3834 #include <caml/config.h>
3835 #include <caml/alloc.h>
3836 #include <caml/callback.h>
3837 #include <caml/fail.h>
3838 #include <caml/memory.h>
3839 #include <caml/mlvalues.h>
3840 #include <caml/signals.h>
3841
3842 #include <guestfs.h>
3843
3844 #include \"guestfs_c.h\"
3845
3846 /* Copy a hashtable of string pairs into an assoc-list.  We return
3847  * the list in reverse order, but hashtables aren't supposed to be
3848  * ordered anyway.
3849  */
3850 static CAMLprim value
3851 copy_table (char * const * argv)
3852 {
3853   CAMLparam0 ();
3854   CAMLlocal5 (rv, pairv, kv, vv, cons);
3855   int i;
3856
3857   rv = Val_int (0);
3858   for (i = 0; argv[i] != NULL; i += 2) {
3859     kv = caml_copy_string (argv[i]);
3860     vv = caml_copy_string (argv[i+1]);
3861     pairv = caml_alloc (2, 0);
3862     Store_field (pairv, 0, kv);
3863     Store_field (pairv, 1, vv);
3864     cons = caml_alloc (2, 0);
3865     Store_field (cons, 1, rv);
3866     rv = cons;
3867     Store_field (cons, 0, pairv);
3868   }
3869
3870   CAMLreturn (rv);
3871 }
3872
3873 ";
3874
3875   (* LVM struct copy functions. *)
3876   List.iter (
3877     fun (typ, cols) ->
3878       let has_optpercent_col =
3879         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
3880
3881       pr "static CAMLprim value\n";
3882       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
3883       pr "{\n";
3884       pr "  CAMLparam0 ();\n";
3885       if has_optpercent_col then
3886         pr "  CAMLlocal3 (rv, v, v2);\n"
3887       else
3888         pr "  CAMLlocal2 (rv, v);\n";
3889       pr "\n";
3890       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3891       iteri (
3892         fun i col ->
3893           (match col with
3894            | name, `String ->
3895                pr "  v = caml_copy_string (%s->%s);\n" typ name
3896            | name, `UUID ->
3897                pr "  v = caml_alloc_string (32);\n";
3898                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
3899            | name, `Bytes
3900            | name, `Int ->
3901                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3902            | name, `OptPercent ->
3903                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
3904                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
3905                pr "    v = caml_alloc (1, 0);\n";
3906                pr "    Store_field (v, 0, v2);\n";
3907                pr "  } else /* None */\n";
3908                pr "    v = Val_int (0);\n";
3909           );
3910           pr "  Store_field (rv, %d, v);\n" i
3911       ) cols;
3912       pr "  CAMLreturn (rv);\n";
3913       pr "}\n";
3914       pr "\n";
3915
3916       pr "static CAMLprim value\n";
3917       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
3918         typ typ typ;
3919       pr "{\n";
3920       pr "  CAMLparam0 ();\n";
3921       pr "  CAMLlocal2 (rv, v);\n";
3922       pr "  int i;\n";
3923       pr "\n";
3924       pr "  if (%ss->len == 0)\n" typ;
3925       pr "    CAMLreturn (Atom (0));\n";
3926       pr "  else {\n";
3927       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
3928       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
3929       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
3930       pr "      caml_modify (&Field (rv, i), v);\n";
3931       pr "    }\n";
3932       pr "    CAMLreturn (rv);\n";
3933       pr "  }\n";
3934       pr "}\n";
3935       pr "\n";
3936   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3937
3938   (* Stat copy functions. *)
3939   List.iter (
3940     fun (typ, cols) ->
3941       pr "static CAMLprim value\n";
3942       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
3943       pr "{\n";
3944       pr "  CAMLparam0 ();\n";
3945       pr "  CAMLlocal2 (rv, v);\n";
3946       pr "\n";
3947       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3948       iteri (
3949         fun i col ->
3950           (match col with
3951            | name, `Int ->
3952                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3953           );
3954           pr "  Store_field (rv, %d, v);\n" i
3955       ) cols;
3956       pr "  CAMLreturn (rv);\n";
3957       pr "}\n";
3958       pr "\n";
3959   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3960
3961   (* The wrappers. *)
3962   List.iter (
3963     fun (name, style, _, _, _, _, _) ->
3964       let params =
3965         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
3966
3967       pr "CAMLprim value\n";
3968       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
3969       List.iter (pr ", value %s") (List.tl params);
3970       pr ")\n";
3971       pr "{\n";
3972
3973       (match params with
3974        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
3975            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
3976            pr "  CAMLxparam%d (%s);\n"
3977              (List.length rest) (String.concat ", " rest)
3978        | ps ->
3979            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
3980       );
3981       pr "  CAMLlocal1 (rv);\n";
3982       pr "\n";
3983
3984       pr "  guestfs_h *g = Guestfs_val (gv);\n";
3985       pr "  if (g == NULL)\n";
3986       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
3987       pr "\n";
3988
3989       List.iter (
3990         function
3991         | String n
3992         | FileIn n
3993         | FileOut n ->
3994             pr "  const char *%s = String_val (%sv);\n" n n
3995         | OptString n ->
3996             pr "  const char *%s =\n" n;
3997             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
3998               n n
3999         | StringList n ->
4000             pr "  char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
4001         | Bool n ->
4002             pr "  int %s = Bool_val (%sv);\n" n n
4003         | Int n ->
4004             pr "  int %s = Int_val (%sv);\n" n n
4005       ) (snd style);
4006       let error_code =
4007         match fst style with
4008         | RErr -> pr "  int r;\n"; "-1"
4009         | RInt _ -> pr "  int r;\n"; "-1"
4010         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4011         | RBool _ -> pr "  int r;\n"; "-1"
4012         | RConstString _ -> pr "  const char *r;\n"; "NULL"
4013         | RString _ -> pr "  char *r;\n"; "NULL"
4014         | RStringList _ ->
4015             pr "  int i;\n";
4016             pr "  char **r;\n";
4017             "NULL"
4018         | RIntBool _ ->
4019             pr "  struct guestfs_int_bool *r;\n"; "NULL"
4020         | RPVList _ ->
4021             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
4022         | RVGList _ ->
4023             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
4024         | RLVList _ ->
4025             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
4026         | RStat _ ->
4027             pr "  struct guestfs_stat *r;\n"; "NULL"
4028         | RStatVFS _ ->
4029             pr "  struct guestfs_statvfs *r;\n"; "NULL"
4030         | RHashtable _ ->
4031             pr "  int i;\n";
4032             pr "  char **r;\n";
4033             "NULL" in
4034       pr "\n";
4035
4036       pr "  caml_enter_blocking_section ();\n";
4037       pr "  r = guestfs_%s " name;
4038       generate_call_args ~handle:"g" (snd style);
4039       pr ";\n";
4040       pr "  caml_leave_blocking_section ();\n";
4041
4042       List.iter (
4043         function
4044         | StringList n ->
4045             pr "  ocaml_guestfs_free_strings (%s);\n" n;
4046         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
4047       ) (snd style);
4048
4049       pr "  if (r == %s)\n" error_code;
4050       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
4051       pr "\n";
4052
4053       (match fst style with
4054        | RErr -> pr "  rv = Val_unit;\n"
4055        | RInt _ -> pr "  rv = Val_int (r);\n"
4056        | RInt64 _ ->
4057            pr "  rv = caml_copy_int64 (r);\n"
4058        | RBool _ -> pr "  rv = Val_bool (r);\n"
4059        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
4060        | RString _ ->
4061            pr "  rv = caml_copy_string (r);\n";
4062            pr "  free (r);\n"
4063        | RStringList _ ->
4064            pr "  rv = caml_copy_string_array ((const char **) r);\n";
4065            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4066            pr "  free (r);\n"
4067        | RIntBool _ ->
4068            pr "  rv = caml_alloc (2, 0);\n";
4069            pr "  Store_field (rv, 0, Val_int (r->i));\n";
4070            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
4071            pr "  guestfs_free_int_bool (r);\n";
4072        | RPVList _ ->
4073            pr "  rv = copy_lvm_pv_list (r);\n";
4074            pr "  guestfs_free_lvm_pv_list (r);\n";
4075        | RVGList _ ->
4076            pr "  rv = copy_lvm_vg_list (r);\n";
4077            pr "  guestfs_free_lvm_vg_list (r);\n";
4078        | RLVList _ ->
4079            pr "  rv = copy_lvm_lv_list (r);\n";
4080            pr "  guestfs_free_lvm_lv_list (r);\n";
4081        | RStat _ ->
4082            pr "  rv = copy_stat (r);\n";
4083            pr "  free (r);\n";
4084        | RStatVFS _ ->
4085            pr "  rv = copy_statvfs (r);\n";
4086            pr "  free (r);\n";
4087        | RHashtable _ ->
4088            pr "  rv = copy_table (r);\n";
4089            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4090            pr "  free (r);\n";
4091       );
4092
4093       pr "  CAMLreturn (rv);\n";
4094       pr "}\n";
4095       pr "\n";
4096
4097       if List.length params > 5 then (
4098         pr "CAMLprim value\n";
4099         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
4100         pr "{\n";
4101         pr "  return ocaml_guestfs_%s (argv[0]" name;
4102         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
4103         pr ");\n";
4104         pr "}\n";
4105         pr "\n"
4106       )
4107   ) all_functions
4108
4109 and generate_ocaml_lvm_structure_decls () =
4110   List.iter (
4111     fun (typ, cols) ->
4112       pr "type lvm_%s = {\n" typ;
4113       List.iter (
4114         function
4115         | name, `String -> pr "  %s : string;\n" name
4116         | name, `UUID -> pr "  %s : string;\n" name
4117         | name, `Bytes -> pr "  %s : int64;\n" name
4118         | name, `Int -> pr "  %s : int64;\n" name
4119         | name, `OptPercent -> pr "  %s : float option;\n" name
4120       ) cols;
4121       pr "}\n";
4122       pr "\n"
4123   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4124
4125 and generate_ocaml_stat_structure_decls () =
4126   List.iter (
4127     fun (typ, cols) ->
4128       pr "type %s = {\n" typ;
4129       List.iter (
4130         function
4131         | name, `Int -> pr "  %s : int64;\n" name
4132       ) cols;
4133       pr "}\n";
4134       pr "\n"
4135   ) ["stat", stat_cols; "statvfs", statvfs_cols]
4136
4137 and generate_ocaml_prototype ?(is_external = false) name style =
4138   if is_external then pr "external " else pr "val ";
4139   pr "%s : t -> " name;
4140   List.iter (
4141     function
4142     | String _ | FileIn _ | FileOut _ -> pr "string -> "
4143     | OptString _ -> pr "string option -> "
4144     | StringList _ -> pr "string array -> "
4145     | Bool _ -> pr "bool -> "
4146     | Int _ -> pr "int -> "
4147   ) (snd style);
4148   (match fst style with
4149    | RErr -> pr "unit" (* all errors are turned into exceptions *)
4150    | RInt _ -> pr "int"
4151    | RInt64 _ -> pr "int64"
4152    | RBool _ -> pr "bool"
4153    | RConstString _ -> pr "string"
4154    | RString _ -> pr "string"
4155    | RStringList _ -> pr "string array"
4156    | RIntBool _ -> pr "int * bool"
4157    | RPVList _ -> pr "lvm_pv array"
4158    | RVGList _ -> pr "lvm_vg array"
4159    | RLVList _ -> pr "lvm_lv array"
4160    | RStat _ -> pr "stat"
4161    | RStatVFS _ -> pr "statvfs"
4162    | RHashtable _ -> pr "(string * string) list"
4163   );
4164   if is_external then (
4165     pr " = ";
4166     if List.length (snd style) + 1 > 5 then
4167       pr "\"ocaml_guestfs_%s_byte\" " name;
4168     pr "\"ocaml_guestfs_%s\"" name
4169   );
4170   pr "\n"
4171
4172 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
4173 and generate_perl_xs () =
4174   generate_header CStyle LGPLv2;
4175
4176   pr "\
4177 #include \"EXTERN.h\"
4178 #include \"perl.h\"
4179 #include \"XSUB.h\"
4180
4181 #include <guestfs.h>
4182
4183 #ifndef PRId64
4184 #define PRId64 \"lld\"
4185 #endif
4186
4187 static SV *
4188 my_newSVll(long long val) {
4189 #ifdef USE_64_BIT_ALL
4190   return newSViv(val);
4191 #else
4192   char buf[100];
4193   int len;
4194   len = snprintf(buf, 100, \"%%\" PRId64, val);
4195   return newSVpv(buf, len);
4196 #endif
4197 }
4198
4199 #ifndef PRIu64
4200 #define PRIu64 \"llu\"
4201 #endif
4202
4203 static SV *
4204 my_newSVull(unsigned long long val) {
4205 #ifdef USE_64_BIT_ALL
4206   return newSVuv(val);
4207 #else
4208   char buf[100];
4209   int len;
4210   len = snprintf(buf, 100, \"%%\" PRIu64, val);
4211   return newSVpv(buf, len);
4212 #endif
4213 }
4214
4215 /* http://www.perlmonks.org/?node_id=680842 */
4216 static char **
4217 XS_unpack_charPtrPtr (SV *arg) {
4218   char **ret;
4219   AV *av;
4220   I32 i;
4221
4222   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
4223     croak (\"array reference expected\");
4224   }
4225
4226   av = (AV *)SvRV (arg);
4227   ret = (char **)malloc (av_len (av) + 1 + 1);
4228
4229   for (i = 0; i <= av_len (av); i++) {
4230     SV **elem = av_fetch (av, i, 0);
4231
4232     if (!elem || !*elem)
4233       croak (\"missing element in list\");
4234
4235     ret[i] = SvPV_nolen (*elem);
4236   }
4237
4238   ret[i] = NULL;
4239
4240   return ret;
4241 }
4242
4243 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
4244
4245 guestfs_h *
4246 _create ()
4247    CODE:
4248       RETVAL = guestfs_create ();
4249       if (!RETVAL)
4250         croak (\"could not create guestfs handle\");
4251       guestfs_set_error_handler (RETVAL, NULL, NULL);
4252  OUTPUT:
4253       RETVAL
4254
4255 void
4256 DESTROY (g)
4257       guestfs_h *g;
4258  PPCODE:
4259       guestfs_close (g);
4260
4261 ";
4262
4263   List.iter (
4264     fun (name, style, _, _, _, _, _) ->
4265       (match fst style with
4266        | RErr -> pr "void\n"
4267        | RInt _ -> pr "SV *\n"
4268        | RInt64 _ -> pr "SV *\n"
4269        | RBool _ -> pr "SV *\n"
4270        | RConstString _ -> pr "SV *\n"
4271        | RString _ -> pr "SV *\n"
4272        | RStringList _
4273        | RIntBool _
4274        | RPVList _ | RVGList _ | RLVList _
4275        | RStat _ | RStatVFS _
4276        | RHashtable _ ->
4277            pr "void\n" (* all lists returned implictly on the stack *)
4278       );
4279       (* Call and arguments. *)
4280       pr "%s " name;
4281       generate_call_args ~handle:"g" (snd style);
4282       pr "\n";
4283       pr "      guestfs_h *g;\n";
4284       List.iter (
4285         function
4286         | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
4287         | OptString n -> pr "      char *%s;\n" n
4288         | StringList n -> pr "      char **%s;\n" n
4289         | Bool n -> pr "      int %s;\n" n
4290         | Int n -> pr "      int %s;\n" n
4291       ) (snd style);
4292
4293       let do_cleanups () =
4294         List.iter (
4295           function
4296           | String _ | OptString _ | Bool _ | Int _
4297           | FileIn _ | FileOut _ -> ()
4298           | StringList n -> pr "      free (%s);\n" n
4299         ) (snd style)
4300       in
4301
4302       (* Code. *)
4303       (match fst style with
4304        | RErr ->
4305            pr "PREINIT:\n";
4306            pr "      int r;\n";
4307            pr " PPCODE:\n";
4308            pr "      r = guestfs_%s " name;
4309            generate_call_args ~handle:"g" (snd style);
4310            pr ";\n";
4311            do_cleanups ();
4312            pr "      if (r == -1)\n";
4313            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4314        | RInt n
4315        | RBool n ->
4316            pr "PREINIT:\n";
4317            pr "      int %s;\n" n;
4318            pr "   CODE:\n";
4319            pr "      %s = guestfs_%s " n name;
4320            generate_call_args ~handle:"g" (snd style);
4321            pr ";\n";
4322            do_cleanups ();
4323            pr "      if (%s == -1)\n" n;
4324            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4325            pr "      RETVAL = newSViv (%s);\n" n;
4326            pr " OUTPUT:\n";
4327            pr "      RETVAL\n"
4328        | RInt64 n ->
4329            pr "PREINIT:\n";
4330            pr "      int64_t %s;\n" n;
4331            pr "   CODE:\n";
4332            pr "      %s = guestfs_%s " n name;
4333            generate_call_args ~handle:"g" (snd style);
4334            pr ";\n";
4335            do_cleanups ();
4336            pr "      if (%s == -1)\n" n;
4337            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4338            pr "      RETVAL = my_newSVll (%s);\n" n;
4339            pr " OUTPUT:\n";
4340            pr "      RETVAL\n"
4341        | RConstString n ->
4342            pr "PREINIT:\n";
4343            pr "      const char *%s;\n" n;
4344            pr "   CODE:\n";
4345            pr "      %s = guestfs_%s " n name;
4346            generate_call_args ~handle:"g" (snd style);
4347            pr ";\n";
4348            do_cleanups ();
4349            pr "      if (%s == NULL)\n" n;
4350            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4351            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4352            pr " OUTPUT:\n";
4353            pr "      RETVAL\n"
4354        | RString n ->
4355            pr "PREINIT:\n";
4356            pr "      char *%s;\n" n;
4357            pr "   CODE:\n";
4358            pr "      %s = guestfs_%s " n name;
4359            generate_call_args ~handle:"g" (snd style);
4360            pr ";\n";
4361            do_cleanups ();
4362            pr "      if (%s == NULL)\n" n;
4363            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4364            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4365            pr "      free (%s);\n" n;
4366            pr " OUTPUT:\n";
4367            pr "      RETVAL\n"
4368        | RStringList n | RHashtable n ->
4369            pr "PREINIT:\n";
4370            pr "      char **%s;\n" n;
4371            pr "      int i, n;\n";
4372            pr " PPCODE:\n";
4373            pr "      %s = guestfs_%s " n name;
4374            generate_call_args ~handle:"g" (snd style);
4375            pr ";\n";
4376            do_cleanups ();
4377            pr "      if (%s == NULL)\n" n;
4378            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4379            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
4380            pr "      EXTEND (SP, n);\n";
4381            pr "      for (i = 0; i < n; ++i) {\n";
4382            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
4383            pr "        free (%s[i]);\n" n;
4384            pr "      }\n";
4385            pr "      free (%s);\n" n;
4386        | RIntBool _ ->
4387            pr "PREINIT:\n";
4388            pr "      struct guestfs_int_bool *r;\n";
4389            pr " PPCODE:\n";
4390            pr "      r = guestfs_%s " name;
4391            generate_call_args ~handle:"g" (snd style);
4392            pr ";\n";
4393            do_cleanups ();
4394            pr "      if (r == NULL)\n";
4395            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4396            pr "      EXTEND (SP, 2);\n";
4397            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
4398            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
4399            pr "      guestfs_free_int_bool (r);\n";
4400        | RPVList n ->
4401            generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
4402        | RVGList n ->
4403            generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
4404        | RLVList n ->
4405            generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
4406        | RStat n ->
4407            generate_perl_stat_code "stat" stat_cols name style n do_cleanups
4408        | RStatVFS n ->
4409            generate_perl_stat_code
4410              "statvfs" statvfs_cols name style n do_cleanups
4411       );
4412
4413       pr "\n"
4414   ) all_functions
4415
4416 and generate_perl_lvm_code typ cols name style n do_cleanups =
4417   pr "PREINIT:\n";
4418   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
4419   pr "      int i;\n";
4420   pr "      HV *hv;\n";
4421   pr " PPCODE:\n";
4422   pr "      %s = guestfs_%s " n name;
4423   generate_call_args ~handle:"g" (snd style);
4424   pr ";\n";
4425   do_cleanups ();
4426   pr "      if (%s == NULL)\n" n;
4427   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4428   pr "      EXTEND (SP, %s->len);\n" n;
4429   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
4430   pr "        hv = newHV ();\n";
4431   List.iter (
4432     function
4433     | name, `String ->
4434         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
4435           name (String.length name) n name
4436     | name, `UUID ->
4437         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
4438           name (String.length name) n name
4439     | name, `Bytes ->
4440         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
4441           name (String.length name) n name
4442     | name, `Int ->
4443         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
4444           name (String.length name) n name
4445     | name, `OptPercent ->
4446         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
4447           name (String.length name) n name
4448   ) cols;
4449   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
4450   pr "      }\n";
4451   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
4452
4453 and generate_perl_stat_code typ cols name style n do_cleanups =
4454   pr "PREINIT:\n";
4455   pr "      struct guestfs_%s *%s;\n" typ n;
4456   pr " PPCODE:\n";
4457   pr "      %s = guestfs_%s " n name;
4458   generate_call_args ~handle:"g" (snd style);
4459   pr ";\n";
4460   do_cleanups ();
4461   pr "      if (%s == NULL)\n" n;
4462   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4463   pr "      EXTEND (SP, %d);\n" (List.length cols);
4464   List.iter (
4465     function
4466     | name, `Int ->
4467         pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
4468   ) cols;
4469   pr "      free (%s);\n" n
4470
4471 (* Generate Sys/Guestfs.pm. *)
4472 and generate_perl_pm () =
4473   generate_header HashStyle LGPLv2;
4474
4475   pr "\
4476 =pod
4477
4478 =head1 NAME
4479
4480 Sys::Guestfs - Perl bindings for libguestfs
4481
4482 =head1 SYNOPSIS
4483
4484  use Sys::Guestfs;
4485  
4486  my $h = Sys::Guestfs->new ();
4487  $h->add_drive ('guest.img');
4488  $h->launch ();
4489  $h->wait_ready ();
4490  $h->mount ('/dev/sda1', '/');
4491  $h->touch ('/hello');
4492  $h->sync ();
4493
4494 =head1 DESCRIPTION
4495
4496 The C<Sys::Guestfs> module provides a Perl XS binding to the
4497 libguestfs API for examining and modifying virtual machine
4498 disk images.
4499
4500 Amongst the things this is good for: making batch configuration
4501 changes to guests, getting disk used/free statistics (see also:
4502 virt-df), migrating between virtualization systems (see also:
4503 virt-p2v), performing partial backups, performing partial guest
4504 clones, cloning guests and changing registry/UUID/hostname info, and
4505 much else besides.
4506
4507 Libguestfs uses Linux kernel and qemu code, and can access any type of
4508 guest filesystem that Linux and qemu can, including but not limited
4509 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
4510 schemes, qcow, qcow2, vmdk.
4511
4512 Libguestfs provides ways to enumerate guest storage (eg. partitions,
4513 LVs, what filesystem is in each LV, etc.).  It can also run commands
4514 in the context of the guest.  Also you can access filesystems over FTP.
4515
4516 =head1 ERRORS
4517
4518 All errors turn into calls to C<croak> (see L<Carp(3)>).
4519
4520 =head1 METHODS
4521
4522 =over 4
4523
4524 =cut
4525
4526 package Sys::Guestfs;
4527
4528 use strict;
4529 use warnings;
4530
4531 require XSLoader;
4532 XSLoader::load ('Sys::Guestfs');
4533
4534 =item $h = Sys::Guestfs->new ();
4535
4536 Create a new guestfs handle.
4537
4538 =cut
4539
4540 sub new {
4541   my $proto = shift;
4542   my $class = ref ($proto) || $proto;
4543
4544   my $self = Sys::Guestfs::_create ();
4545   bless $self, $class;
4546   return $self;
4547 }
4548
4549 ";
4550
4551   (* Actions.  We only need to print documentation for these as
4552    * they are pulled in from the XS code automatically.
4553    *)
4554   List.iter (
4555     fun (name, style, _, flags, _, _, longdesc) ->
4556       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
4557       pr "=item ";
4558       generate_perl_prototype name style;
4559       pr "\n\n";
4560       pr "%s\n\n" longdesc;
4561       if List.mem ProtocolLimitWarning flags then
4562         pr "%s\n\n" protocol_limit_warning;
4563       if List.mem DangerWillRobinson flags then
4564         pr "%s\n\n" danger_will_robinson
4565   ) all_functions_sorted;
4566
4567   (* End of file. *)
4568   pr "\
4569 =cut
4570
4571 1;
4572
4573 =back
4574
4575 =head1 COPYRIGHT
4576
4577 Copyright (C) 2009 Red Hat Inc.
4578
4579 =head1 LICENSE
4580
4581 Please see the file COPYING.LIB for the full license.
4582
4583 =head1 SEE ALSO
4584
4585 L<guestfs(3)>, L<guestfish(1)>.
4586
4587 =cut
4588 "
4589
4590 and generate_perl_prototype name style =
4591   (match fst style with
4592    | RErr -> ()
4593    | RBool n
4594    | RInt n
4595    | RInt64 n
4596    | RConstString n
4597    | RString n -> pr "$%s = " n
4598    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4599    | RStringList n
4600    | RPVList n
4601    | RVGList n
4602    | RLVList n -> pr "@%s = " n
4603    | RStat n
4604    | RStatVFS n
4605    | RHashtable n -> pr "%%%s = " n
4606   );
4607   pr "$h->%s (" name;
4608   let comma = ref false in
4609   List.iter (
4610     fun arg ->
4611       if !comma then pr ", ";
4612       comma := true;
4613       match arg with
4614       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
4615           pr "$%s" n
4616       | StringList n ->
4617           pr "\\@%s" n
4618   ) (snd style);
4619   pr ");"
4620
4621 (* Generate Python C module. *)
4622 and generate_python_c () =
4623   generate_header CStyle LGPLv2;
4624
4625   pr "\
4626 #include <stdio.h>
4627 #include <stdlib.h>
4628 #include <assert.h>
4629
4630 #include <Python.h>
4631
4632 #include \"guestfs.h\"
4633
4634 typedef struct {
4635   PyObject_HEAD
4636   guestfs_h *g;
4637 } Pyguestfs_Object;
4638
4639 static guestfs_h *
4640 get_handle (PyObject *obj)
4641 {
4642   assert (obj);
4643   assert (obj != Py_None);
4644   return ((Pyguestfs_Object *) obj)->g;
4645 }
4646
4647 static PyObject *
4648 put_handle (guestfs_h *g)
4649 {
4650   assert (g);
4651   return
4652     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4653 }
4654
4655 /* This list should be freed (but not the strings) after use. */
4656 static const char **
4657 get_string_list (PyObject *obj)
4658 {
4659   int i, len;
4660   const char **r;
4661
4662   assert (obj);
4663
4664   if (!PyList_Check (obj)) {
4665     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4666     return NULL;
4667   }
4668
4669   len = PyList_Size (obj);
4670   r = malloc (sizeof (char *) * (len+1));
4671   if (r == NULL) {
4672     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4673     return NULL;
4674   }
4675
4676   for (i = 0; i < len; ++i)
4677     r[i] = PyString_AsString (PyList_GetItem (obj, i));
4678   r[len] = NULL;
4679
4680   return r;
4681 }
4682
4683 static PyObject *
4684 put_string_list (char * const * const argv)
4685 {
4686   PyObject *list;
4687   int argc, i;
4688
4689   for (argc = 0; argv[argc] != NULL; ++argc)
4690     ;
4691
4692   list = PyList_New (argc);
4693   for (i = 0; i < argc; ++i)
4694     PyList_SetItem (list, i, PyString_FromString (argv[i]));
4695
4696   return list;
4697 }
4698
4699 static PyObject *
4700 put_table (char * const * const argv)
4701 {
4702   PyObject *list, *item;
4703   int argc, i;
4704
4705   for (argc = 0; argv[argc] != NULL; ++argc)
4706     ;
4707
4708   list = PyList_New (argc >> 1);
4709   for (i = 0; i < argc; i += 2) {
4710     item = PyTuple_New (2);
4711     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
4712     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
4713     PyList_SetItem (list, i >> 1, item);
4714   }
4715
4716   return list;
4717 }
4718
4719 static void
4720 free_strings (char **argv)
4721 {
4722   int argc;
4723
4724   for (argc = 0; argv[argc] != NULL; ++argc)
4725     free (argv[argc]);
4726   free (argv);
4727 }
4728
4729 static PyObject *
4730 py_guestfs_create (PyObject *self, PyObject *args)
4731 {
4732   guestfs_h *g;
4733
4734   g = guestfs_create ();
4735   if (g == NULL) {
4736     PyErr_SetString (PyExc_RuntimeError,
4737                      \"guestfs.create: failed to allocate handle\");
4738     return NULL;
4739   }
4740   guestfs_set_error_handler (g, NULL, NULL);
4741   return put_handle (g);
4742 }
4743
4744 static PyObject *
4745 py_guestfs_close (PyObject *self, PyObject *args)
4746 {
4747   PyObject *py_g;
4748   guestfs_h *g;
4749
4750   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4751     return NULL;
4752   g = get_handle (py_g);
4753
4754   guestfs_close (g);
4755
4756   Py_INCREF (Py_None);
4757   return Py_None;
4758 }
4759
4760 ";
4761
4762   (* LVM structures, turned into Python dictionaries. *)
4763   List.iter (
4764     fun (typ, cols) ->
4765       pr "static PyObject *\n";
4766       pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4767       pr "{\n";
4768       pr "  PyObject *dict;\n";
4769       pr "\n";
4770       pr "  dict = PyDict_New ();\n";
4771       List.iter (
4772         function
4773         | name, `String ->
4774             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4775             pr "                        PyString_FromString (%s->%s));\n"
4776               typ name
4777         | name, `UUID ->
4778             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4779             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
4780               typ name
4781         | name, `Bytes ->
4782             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4783             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
4784               typ name
4785         | name, `Int ->
4786             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4787             pr "                        PyLong_FromLongLong (%s->%s));\n"
4788               typ name
4789         | name, `OptPercent ->
4790             pr "  if (%s->%s >= 0)\n" typ name;
4791             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
4792             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
4793               typ name;
4794             pr "  else {\n";
4795             pr "    Py_INCREF (Py_None);\n";
4796             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
4797             pr "  }\n"
4798       ) cols;
4799       pr "  return dict;\n";
4800       pr "};\n";
4801       pr "\n";
4802
4803       pr "static PyObject *\n";
4804       pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
4805       pr "{\n";
4806       pr "  PyObject *list;\n";
4807       pr "  int i;\n";
4808       pr "\n";
4809       pr "  list = PyList_New (%ss->len);\n" typ;
4810       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
4811       pr "    PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
4812       pr "  return list;\n";
4813       pr "};\n";
4814       pr "\n"
4815   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4816
4817   (* Stat structures, turned into Python dictionaries. *)
4818   List.iter (
4819     fun (typ, cols) ->
4820       pr "static PyObject *\n";
4821       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
4822       pr "{\n";
4823       pr "  PyObject *dict;\n";
4824       pr "\n";
4825       pr "  dict = PyDict_New ();\n";
4826       List.iter (
4827         function
4828         | name, `Int ->
4829             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4830             pr "                        PyLong_FromLongLong (%s->%s));\n"
4831               typ name
4832       ) cols;
4833       pr "  return dict;\n";
4834       pr "};\n";
4835       pr "\n";
4836   ) ["stat", stat_cols; "statvfs", statvfs_cols];
4837
4838   (* Python wrapper functions. *)
4839   List.iter (
4840     fun (name, style, _, _, _, _, _) ->
4841       pr "static PyObject *\n";
4842       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
4843       pr "{\n";
4844
4845       pr "  PyObject *py_g;\n";
4846       pr "  guestfs_h *g;\n";
4847       pr "  PyObject *py_r;\n";
4848
4849       let error_code =
4850         match fst style with
4851         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
4852         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4853         | RConstString _ -> pr "  const char *r;\n"; "NULL"
4854         | RString _ -> pr "  char *r;\n"; "NULL"
4855         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
4856         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
4857         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
4858         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
4859         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
4860         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
4861         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
4862
4863       List.iter (
4864         function
4865         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
4866         | OptString n -> pr "  const char *%s;\n" n
4867         | StringList n ->
4868             pr "  PyObject *py_%s;\n" n;
4869             pr "  const char **%s;\n" n
4870         | Bool n -> pr "  int %s;\n" n
4871         | Int n -> pr "  int %s;\n" n
4872       ) (snd style);
4873
4874       pr "\n";
4875
4876       (* Convert the parameters. *)
4877       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
4878       List.iter (
4879         function
4880         | String _ | FileIn _ | FileOut _ -> pr "s"
4881         | OptString _ -> pr "z"
4882         | StringList _ -> pr "O"
4883         | Bool _ -> pr "i" (* XXX Python has booleans? *)
4884         | Int _ -> pr "i"
4885       ) (snd style);
4886       pr ":guestfs_%s\",\n" name;
4887       pr "                         &py_g";
4888       List.iter (
4889         function
4890         | String n | FileIn n | FileOut n -> pr ", &%s" n
4891         | OptString n -> pr ", &%s" n
4892         | StringList n -> pr ", &py_%s" n
4893         | Bool n -> pr ", &%s" n
4894         | Int n -> pr ", &%s" n
4895       ) (snd style);
4896
4897       pr "))\n";
4898       pr "    return NULL;\n";
4899
4900       pr "  g = get_handle (py_g);\n";
4901       List.iter (
4902         function
4903         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
4904         | StringList n ->
4905             pr "  %s = get_string_list (py_%s);\n" n n;
4906             pr "  if (!%s) return NULL;\n" n
4907       ) (snd style);
4908
4909       pr "\n";
4910
4911       pr "  r = guestfs_%s " name;
4912       generate_call_args ~handle:"g" (snd style);
4913       pr ";\n";
4914
4915       List.iter (
4916         function
4917         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
4918         | StringList n ->
4919             pr "  free (%s);\n" n
4920       ) (snd style);
4921
4922       pr "  if (r == %s) {\n" error_code;
4923       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
4924       pr "    return NULL;\n";
4925       pr "  }\n";
4926       pr "\n";
4927
4928       (match fst style with
4929        | RErr ->
4930            pr "  Py_INCREF (Py_None);\n";
4931            pr "  py_r = Py_None;\n"
4932        | RInt _
4933        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
4934        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
4935        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
4936        | RString _ ->
4937            pr "  py_r = PyString_FromString (r);\n";
4938            pr "  free (r);\n"
4939        | RStringList _ ->
4940            pr "  py_r = put_string_list (r);\n";
4941            pr "  free_strings (r);\n"
4942        | RIntBool _ ->
4943            pr "  py_r = PyTuple_New (2);\n";
4944            pr "  PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
4945            pr "  PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
4946            pr "  guestfs_free_int_bool (r);\n"
4947        | RPVList n ->
4948            pr "  py_r = put_lvm_pv_list (r);\n";
4949            pr "  guestfs_free_lvm_pv_list (r);\n"
4950        | RVGList n ->
4951            pr "  py_r = put_lvm_vg_list (r);\n";
4952            pr "  guestfs_free_lvm_vg_list (r);\n"
4953        | RLVList n ->
4954            pr "  py_r = put_lvm_lv_list (r);\n";
4955            pr "  guestfs_free_lvm_lv_list (r);\n"
4956        | RStat n ->
4957            pr "  py_r = put_stat (r);\n";
4958            pr "  free (r);\n"
4959        | RStatVFS n ->
4960            pr "  py_r = put_statvfs (r);\n";
4961            pr "  free (r);\n"
4962        | RHashtable n ->
4963            pr "  py_r = put_table (r);\n";
4964            pr "  free_strings (r);\n"
4965       );
4966
4967       pr "  return py_r;\n";
4968       pr "}\n";
4969       pr "\n"
4970   ) all_functions;
4971
4972   (* Table of functions. *)
4973   pr "static PyMethodDef methods[] = {\n";
4974   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
4975   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
4976   List.iter (
4977     fun (name, _, _, _, _, _, _) ->
4978       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
4979         name name
4980   ) all_functions;
4981   pr "  { NULL, NULL, 0, NULL }\n";
4982   pr "};\n";
4983   pr "\n";
4984
4985   (* Init function. *)
4986   pr "\
4987 void
4988 initlibguestfsmod (void)
4989 {
4990   static int initialized = 0;
4991
4992   if (initialized) return;
4993   Py_InitModule ((char *) \"libguestfsmod\", methods);
4994   initialized = 1;
4995 }
4996 "
4997
4998 (* Generate Python module. *)
4999 and generate_python_py () =
5000   generate_header HashStyle LGPLv2;
5001
5002   pr "\
5003 u\"\"\"Python bindings for libguestfs
5004
5005 import guestfs
5006 g = guestfs.GuestFS ()
5007 g.add_drive (\"guest.img\")
5008 g.launch ()
5009 g.wait_ready ()
5010 parts = g.list_partitions ()
5011
5012 The guestfs module provides a Python binding to the libguestfs API
5013 for examining and modifying virtual machine disk images.
5014
5015 Amongst the things this is good for: making batch configuration
5016 changes to guests, getting disk used/free statistics (see also:
5017 virt-df), migrating between virtualization systems (see also:
5018 virt-p2v), performing partial backups, performing partial guest
5019 clones, cloning guests and changing registry/UUID/hostname info, and
5020 much else besides.
5021
5022 Libguestfs uses Linux kernel and qemu code, and can access any type of
5023 guest filesystem that Linux and qemu can, including but not limited
5024 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5025 schemes, qcow, qcow2, vmdk.
5026
5027 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5028 LVs, what filesystem is in each LV, etc.).  It can also run commands
5029 in the context of the guest.  Also you can access filesystems over FTP.
5030
5031 Errors which happen while using the API are turned into Python
5032 RuntimeError exceptions.
5033
5034 To create a guestfs handle you usually have to perform the following
5035 sequence of calls:
5036
5037 # Create the handle, call add_drive at least once, and possibly
5038 # several times if the guest has multiple block devices:
5039 g = guestfs.GuestFS ()
5040 g.add_drive (\"guest.img\")
5041
5042 # Launch the qemu subprocess and wait for it to become ready:
5043 g.launch ()
5044 g.wait_ready ()
5045
5046 # Now you can issue commands, for example:
5047 logvols = g.lvs ()
5048
5049 \"\"\"
5050
5051 import libguestfsmod
5052
5053 class GuestFS:
5054     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
5055
5056     def __init__ (self):
5057         \"\"\"Create a new libguestfs handle.\"\"\"
5058         self._o = libguestfsmod.create ()
5059
5060     def __del__ (self):
5061         libguestfsmod.close (self._o)
5062
5063 ";
5064
5065   List.iter (
5066     fun (name, style, _, flags, _, _, longdesc) ->
5067       let doc = replace_str longdesc "C<guestfs_" "C<g." in
5068       let doc =
5069         match fst style with
5070         | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
5071         | RString _ -> doc
5072         | RStringList _ ->
5073             doc ^ "\n\nThis function returns a list of strings."
5074         | RIntBool _ ->
5075             doc ^ "\n\nThis function returns a tuple (int, bool).\n"
5076         | RPVList _ ->
5077             doc ^ "\n\nThis function returns a list of PVs.  Each PV is represented as a dictionary."
5078         | RVGList _ ->
5079             doc ^ "\n\nThis function returns a list of VGs.  Each VG is represented as a dictionary."
5080         | RLVList _ ->
5081             doc ^ "\n\nThis function returns a list of LVs.  Each LV is represented as a dictionary."
5082         | RStat _ ->
5083             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
5084        | RStatVFS _ ->
5085             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
5086        | RHashtable _ ->
5087             doc ^ "\n\nThis function returns a dictionary." in
5088       let doc =
5089         if List.mem ProtocolLimitWarning flags then
5090           doc ^ "\n\n" ^ protocol_limit_warning
5091         else doc in
5092       let doc =
5093         if List.mem DangerWillRobinson flags then
5094           doc ^ "\n\n" ^ danger_will_robinson
5095         else doc in
5096       let doc = pod2text ~width:60 name doc in
5097       let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
5098       let doc = String.concat "\n        " doc in
5099
5100       pr "    def %s " name;
5101       generate_call_args ~handle:"self" (snd style);
5102       pr ":\n";
5103       pr "        u\"\"\"%s\"\"\"\n" doc;
5104       pr "        return libguestfsmod.%s " name;
5105       generate_call_args ~handle:"self._o" (snd style);
5106       pr "\n";
5107       pr "\n";
5108   ) all_functions
5109
5110 (* Useful if you need the longdesc POD text as plain text.  Returns a
5111  * list of lines.
5112  *)
5113 and pod2text ~width name longdesc =
5114   let filename, chan = Filename.open_temp_file "gen" ".tmp" in
5115   fprintf chan "=head1 %s\n\n%s\n" name longdesc;
5116   close_out chan;
5117   let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
5118   let chan = Unix.open_process_in cmd in
5119   let lines = ref [] in
5120   let rec loop i =
5121     let line = input_line chan in
5122     if i = 1 then               (* discard the first line of output *)
5123       loop (i+1)
5124     else (
5125       let line = triml line in
5126       lines := line :: !lines;
5127       loop (i+1)
5128     ) in
5129   let lines = try loop 1 with End_of_file -> List.rev !lines in
5130   Unix.unlink filename;
5131   match Unix.close_process_in chan with
5132   | Unix.WEXITED 0 -> lines
5133   | Unix.WEXITED i ->
5134       failwithf "pod2text: process exited with non-zero status (%d)" i
5135   | Unix.WSIGNALED i | Unix.WSTOPPED i ->
5136       failwithf "pod2text: process signalled or stopped by signal %d" i
5137
5138 (* Generate ruby bindings. *)
5139 and generate_ruby_c () =
5140   generate_header CStyle LGPLv2;
5141
5142   pr "\
5143 #include <stdio.h>
5144 #include <stdlib.h>
5145
5146 #include <ruby.h>
5147
5148 #include \"guestfs.h\"
5149
5150 #include \"extconf.h\"
5151
5152 static VALUE m_guestfs;                 /* guestfs module */
5153 static VALUE c_guestfs;                 /* guestfs_h handle */
5154 static VALUE e_Error;                   /* used for all errors */
5155
5156 static void ruby_guestfs_free (void *p)
5157 {
5158   if (!p) return;
5159   guestfs_close ((guestfs_h *) p);
5160 }
5161
5162 static VALUE ruby_guestfs_create (VALUE m)
5163 {
5164   guestfs_h *g;
5165
5166   g = guestfs_create ();
5167   if (!g)
5168     rb_raise (e_Error, \"failed to create guestfs handle\");
5169
5170   /* Don't print error messages to stderr by default. */
5171   guestfs_set_error_handler (g, NULL, NULL);
5172
5173   /* Wrap it, and make sure the close function is called when the
5174    * handle goes away.
5175    */
5176   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
5177 }
5178
5179 static VALUE ruby_guestfs_close (VALUE gv)
5180 {
5181   guestfs_h *g;
5182   Data_Get_Struct (gv, guestfs_h, g);
5183
5184   ruby_guestfs_free (g);
5185   DATA_PTR (gv) = NULL;
5186
5187   return Qnil;
5188 }
5189
5190 ";
5191
5192   List.iter (
5193     fun (name, style, _, _, _, _, _) ->
5194       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
5195       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
5196       pr ")\n";
5197       pr "{\n";
5198       pr "  guestfs_h *g;\n";
5199       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
5200       pr "  if (!g)\n";
5201       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
5202         name;
5203       pr "\n";
5204
5205       List.iter (
5206         function
5207         | String n | FileIn n | FileOut n ->
5208             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
5209             pr "  if (!%s)\n" n;
5210             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
5211             pr "              \"%s\", \"%s\");\n" n name
5212         | OptString n ->
5213             pr "  const char *%s = StringValueCStr (%sv);\n" n n
5214         | StringList n ->
5215             pr "  char **%s;" n;
5216             pr "  {\n";
5217             pr "    int i, len;\n";
5218             pr "    len = RARRAY_LEN (%sv);\n" n;
5219             pr "    %s = malloc (sizeof (char *) * (len+1));\n" n;
5220             pr "    for (i = 0; i < len; ++i) {\n";
5221             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
5222             pr "      %s[i] = StringValueCStr (v);\n" n;
5223             pr "    }\n";
5224             pr "  }\n";
5225         | Bool n
5226         | Int n ->
5227             pr "  int %s = NUM2INT (%sv);\n" n n
5228       ) (snd style);
5229       pr "\n";
5230
5231       let error_code =
5232         match fst style with
5233         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
5234         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5235         | RConstString _ -> pr "  const char *r;\n"; "NULL"
5236         | RString _ -> pr "  char *r;\n"; "NULL"
5237         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5238         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
5239         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
5240         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
5241         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
5242         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
5243         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
5244       pr "\n";
5245
5246       pr "  r = guestfs_%s " name;
5247       generate_call_args ~handle:"g" (snd style);
5248       pr ";\n";
5249
5250       List.iter (
5251         function
5252         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5253         | StringList n ->
5254             pr "  free (%s);\n" n
5255       ) (snd style);
5256
5257       pr "  if (r == %s)\n" error_code;
5258       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
5259       pr "\n";
5260
5261       (match fst style with
5262        | RErr ->
5263            pr "  return Qnil;\n"
5264        | RInt _ | RBool _ ->
5265            pr "  return INT2NUM (r);\n"
5266        | RInt64 _ ->
5267            pr "  return ULL2NUM (r);\n"
5268        | RConstString _ ->
5269            pr "  return rb_str_new2 (r);\n";
5270        | RString _ ->
5271            pr "  VALUE rv = rb_str_new2 (r);\n";
5272            pr "  free (r);\n";
5273            pr "  return rv;\n";
5274        | RStringList _ ->
5275            pr "  int i, len = 0;\n";
5276            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
5277            pr "  VALUE rv = rb_ary_new2 (len);\n";
5278            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
5279            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
5280            pr "    free (r[i]);\n";
5281            pr "  }\n";
5282            pr "  free (r);\n";
5283            pr "  return rv;\n"
5284        | RIntBool _ ->
5285            pr "  VALUE rv = rb_ary_new2 (2);\n";
5286            pr "  rb_ary_push (rv, INT2NUM (r->i));\n";
5287            pr "  rb_ary_push (rv, INT2NUM (r->b));\n";
5288            pr "  guestfs_free_int_bool (r);\n";
5289            pr "  return rv;\n"
5290        | RPVList n ->
5291            generate_ruby_lvm_code "pv" pv_cols
5292        | RVGList n ->
5293            generate_ruby_lvm_code "vg" vg_cols
5294        | RLVList n ->
5295            generate_ruby_lvm_code "lv" lv_cols
5296        | RStat n ->
5297            pr "  VALUE rv = rb_hash_new ();\n";
5298            List.iter (
5299              function
5300              | name, `Int ->
5301                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5302            ) stat_cols;
5303            pr "  free (r);\n";
5304            pr "  return rv;\n"
5305        | RStatVFS n ->
5306            pr "  VALUE rv = rb_hash_new ();\n";
5307            List.iter (
5308              function
5309              | name, `Int ->
5310                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5311            ) statvfs_cols;
5312            pr "  free (r);\n";
5313            pr "  return rv;\n"
5314        | RHashtable _ ->
5315            pr "  VALUE rv = rb_hash_new ();\n";
5316            pr "  int i;\n";
5317            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
5318            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
5319            pr "    free (r[i]);\n";
5320            pr "    free (r[i+1]);\n";
5321            pr "  }\n";
5322            pr "  free (r);\n";
5323            pr "  return rv;\n"
5324       );
5325
5326       pr "}\n";
5327       pr "\n"
5328   ) all_functions;
5329
5330   pr "\
5331 /* Initialize the module. */
5332 void Init__guestfs ()
5333 {
5334   m_guestfs = rb_define_module (\"Guestfs\");
5335   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
5336   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
5337
5338   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
5339   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
5340
5341 ";
5342   (* Define the rest of the methods. *)
5343   List.iter (
5344     fun (name, style, _, _, _, _, _) ->
5345       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
5346       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
5347   ) all_functions;
5348
5349   pr "}\n"
5350
5351 (* Ruby code to return an LVM struct list. *)
5352 and generate_ruby_lvm_code typ cols =
5353   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
5354   pr "  int i;\n";
5355   pr "  for (i = 0; i < r->len; ++i) {\n";
5356   pr "    VALUE hv = rb_hash_new ();\n";
5357   List.iter (
5358     function
5359     | name, `String ->
5360         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
5361     | name, `UUID ->
5362         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
5363     | name, `Bytes
5364     | name, `Int ->
5365         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
5366     | name, `OptPercent ->
5367         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
5368   ) cols;
5369   pr "    rb_ary_push (rv, hv);\n";
5370   pr "  }\n";
5371   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
5372   pr "  return rv;\n"
5373
5374 let output_to filename =
5375   let filename_new = filename ^ ".new" in
5376   chan := open_out filename_new;
5377   let close () =
5378     close_out !chan;
5379     chan := stdout;
5380     Unix.rename filename_new filename;
5381     printf "written %s\n%!" filename;
5382   in
5383   close
5384
5385 (* Main program. *)
5386 let () =
5387   check_functions ();
5388
5389   if not (Sys.file_exists "configure.ac") then (
5390     eprintf "\
5391 You are probably running this from the wrong directory.
5392 Run it from the top source directory using the command
5393   src/generator.ml
5394 ";
5395     exit 1
5396   );
5397
5398   let close = output_to "src/guestfs_protocol.x" in
5399   generate_xdr ();
5400   close ();
5401
5402   let close = output_to "src/guestfs-structs.h" in
5403   generate_structs_h ();
5404   close ();
5405
5406   let close = output_to "src/guestfs-actions.h" in
5407   generate_actions_h ();
5408   close ();
5409
5410   let close = output_to "src/guestfs-actions.c" in
5411   generate_client_actions ();
5412   close ();
5413
5414   let close = output_to "daemon/actions.h" in
5415   generate_daemon_actions_h ();
5416   close ();
5417
5418   let close = output_to "daemon/stubs.c" in
5419   generate_daemon_actions ();
5420   close ();
5421
5422   let close = output_to "tests.c" in
5423   generate_tests ();
5424   close ();
5425
5426   let close = output_to "fish/cmds.c" in
5427   generate_fish_cmds ();
5428   close ();
5429
5430   let close = output_to "fish/completion.c" in
5431   generate_fish_completion ();
5432   close ();
5433
5434   let close = output_to "guestfs-structs.pod" in
5435   generate_structs_pod ();
5436   close ();
5437
5438   let close = output_to "guestfs-actions.pod" in
5439   generate_actions_pod ();
5440   close ();
5441
5442   let close = output_to "guestfish-actions.pod" in
5443   generate_fish_actions_pod ();
5444   close ();
5445
5446   let close = output_to "ocaml/guestfs.mli" in
5447   generate_ocaml_mli ();
5448   close ();
5449
5450   let close = output_to "ocaml/guestfs.ml" in
5451   generate_ocaml_ml ();
5452   close ();
5453
5454   let close = output_to "ocaml/guestfs_c_actions.c" in
5455   generate_ocaml_c ();
5456   close ();
5457
5458   let close = output_to "perl/Guestfs.xs" in
5459   generate_perl_xs ();
5460   close ();
5461
5462   let close = output_to "perl/lib/Sys/Guestfs.pm" in
5463   generate_perl_pm ();
5464   close ();
5465
5466   let close = output_to "python/guestfs-py.c" in
5467   generate_python_c ();
5468   close ();
5469
5470   let close = output_to "python/guestfs.py" in
5471   generate_python_py ();
5472   close ();
5473
5474   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
5475   generate_ruby_c ();
5476   close ();