Document the internal protocol.
[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   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1257    [],
1258    "upload a file from the local machine",
1259    "\
1260 Upload local file C<filename> to C<remotefilename> on the
1261 filesystem.
1262
1263 C<filename> can also be a named pipe.
1264
1265 See also C<guestfs_download>.");
1266
1267   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1268    [],
1269    "download a file to the local machine",
1270    "\
1271 Download file C<remotefilename> and save it as C<filename>
1272 on the local machine.
1273
1274 C<filename> can also be a named pipe.
1275
1276 See also C<guestfs_upload>, C<guestfs_cat>.");
1277
1278 ]
1279
1280 let all_functions = non_daemon_functions @ daemon_functions
1281
1282 (* In some places we want the functions to be displayed sorted
1283  * alphabetically, so this is useful:
1284  *)
1285 let all_functions_sorted =
1286   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
1287                compare n1 n2) all_functions
1288
1289 (* Column names and types from LVM PVs/VGs/LVs. *)
1290 let pv_cols = [
1291   "pv_name", `String;
1292   "pv_uuid", `UUID;
1293   "pv_fmt", `String;
1294   "pv_size", `Bytes;
1295   "dev_size", `Bytes;
1296   "pv_free", `Bytes;
1297   "pv_used", `Bytes;
1298   "pv_attr", `String (* XXX *);
1299   "pv_pe_count", `Int;
1300   "pv_pe_alloc_count", `Int;
1301   "pv_tags", `String;
1302   "pe_start", `Bytes;
1303   "pv_mda_count", `Int;
1304   "pv_mda_free", `Bytes;
1305 (* Not in Fedora 10:
1306   "pv_mda_size", `Bytes;
1307 *)
1308 ]
1309 let vg_cols = [
1310   "vg_name", `String;
1311   "vg_uuid", `UUID;
1312   "vg_fmt", `String;
1313   "vg_attr", `String (* XXX *);
1314   "vg_size", `Bytes;
1315   "vg_free", `Bytes;
1316   "vg_sysid", `String;
1317   "vg_extent_size", `Bytes;
1318   "vg_extent_count", `Int;
1319   "vg_free_count", `Int;
1320   "max_lv", `Int;
1321   "max_pv", `Int;
1322   "pv_count", `Int;
1323   "lv_count", `Int;
1324   "snap_count", `Int;
1325   "vg_seqno", `Int;
1326   "vg_tags", `String;
1327   "vg_mda_count", `Int;
1328   "vg_mda_free", `Bytes;
1329 (* Not in Fedora 10:
1330   "vg_mda_size", `Bytes;
1331 *)
1332 ]
1333 let lv_cols = [
1334   "lv_name", `String;
1335   "lv_uuid", `UUID;
1336   "lv_attr", `String (* XXX *);
1337   "lv_major", `Int;
1338   "lv_minor", `Int;
1339   "lv_kernel_major", `Int;
1340   "lv_kernel_minor", `Int;
1341   "lv_size", `Bytes;
1342   "seg_count", `Int;
1343   "origin", `String;
1344   "snap_percent", `OptPercent;
1345   "copy_percent", `OptPercent;
1346   "move_pv", `String;
1347   "lv_tags", `String;
1348   "mirror_log", `String;
1349   "modules", `String;
1350 ]
1351
1352 (* Column names and types from stat structures.
1353  * NB. Can't use things like 'st_atime' because glibc header files
1354  * define some of these as macros.  Ugh.
1355  *)
1356 let stat_cols = [
1357   "dev", `Int;
1358   "ino", `Int;
1359   "mode", `Int;
1360   "nlink", `Int;
1361   "uid", `Int;
1362   "gid", `Int;
1363   "rdev", `Int;
1364   "size", `Int;
1365   "blksize", `Int;
1366   "blocks", `Int;
1367   "atime", `Int;
1368   "mtime", `Int;
1369   "ctime", `Int;
1370 ]
1371 let statvfs_cols = [
1372   "bsize", `Int;
1373   "frsize", `Int;
1374   "blocks", `Int;
1375   "bfree", `Int;
1376   "bavail", `Int;
1377   "files", `Int;
1378   "ffree", `Int;
1379   "favail", `Int;
1380   "fsid", `Int;
1381   "flag", `Int;
1382   "namemax", `Int;
1383 ]
1384
1385 (* Useful functions.
1386  * Note we don't want to use any external OCaml libraries which
1387  * makes this a bit harder than it should be.
1388  *)
1389 let failwithf fs = ksprintf failwith fs
1390
1391 let replace_char s c1 c2 =
1392   let s2 = String.copy s in
1393   let r = ref false in
1394   for i = 0 to String.length s2 - 1 do
1395     if String.unsafe_get s2 i = c1 then (
1396       String.unsafe_set s2 i c2;
1397       r := true
1398     )
1399   done;
1400   if not !r then s else s2
1401
1402 let isspace c =
1403   c = ' '
1404   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
1405
1406 let triml ?(test = isspace) str =
1407   let i = ref 0 in
1408   let n = ref (String.length str) in
1409   while !n > 0 && test str.[!i]; do
1410     decr n;
1411     incr i
1412   done;
1413   if !i = 0 then str
1414   else String.sub str !i !n
1415
1416 let trimr ?(test = isspace) str =
1417   let n = ref (String.length str) in
1418   while !n > 0 && test str.[!n-1]; do
1419     decr n
1420   done;
1421   if !n = String.length str then str
1422   else String.sub str 0 !n
1423
1424 let trim ?(test = isspace) str =
1425   trimr ~test (triml ~test str)
1426
1427 let rec find s sub =
1428   let len = String.length s in
1429   let sublen = String.length sub in
1430   let rec loop i =
1431     if i <= len-sublen then (
1432       let rec loop2 j =
1433         if j < sublen then (
1434           if s.[i+j] = sub.[j] then loop2 (j+1)
1435           else -1
1436         ) else
1437           i (* found *)
1438       in
1439       let r = loop2 0 in
1440       if r = -1 then loop (i+1) else r
1441     ) else
1442       -1 (* not found *)
1443   in
1444   loop 0
1445
1446 let rec replace_str s s1 s2 =
1447   let len = String.length s in
1448   let sublen = String.length s1 in
1449   let i = find s s1 in
1450   if i = -1 then s
1451   else (
1452     let s' = String.sub s 0 i in
1453     let s'' = String.sub s (i+sublen) (len-i-sublen) in
1454     s' ^ s2 ^ replace_str s'' s1 s2
1455   )
1456
1457 let rec string_split sep str =
1458   let len = String.length str in
1459   let seplen = String.length sep in
1460   let i = find str sep in
1461   if i = -1 then [str]
1462   else (
1463     let s' = String.sub str 0 i in
1464     let s'' = String.sub str (i+seplen) (len-i-seplen) in
1465     s' :: string_split sep s''
1466   )
1467
1468 let rec find_map f = function
1469   | [] -> raise Not_found
1470   | x :: xs ->
1471       match f x with
1472       | Some y -> y
1473       | None -> find_map f xs
1474
1475 let iteri f xs =
1476   let rec loop i = function
1477     | [] -> ()
1478     | x :: xs -> f i x; loop (i+1) xs
1479   in
1480   loop 0 xs
1481
1482 let mapi f xs =
1483   let rec loop i = function
1484     | [] -> []
1485     | x :: xs -> let r = f i x in r :: loop (i+1) xs
1486   in
1487   loop 0 xs
1488
1489 let name_of_argt = function
1490   | String n | OptString n | StringList n | Bool n | Int n
1491   | FileIn n | FileOut n -> n
1492
1493 let seq_of_test = function
1494   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
1495   | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
1496   | TestOutputLength (s, _) | TestOutputStruct (s, _)
1497   | TestLastFail s -> s
1498
1499 (* Check function names etc. for consistency. *)
1500 let check_functions () =
1501   let contains_uppercase str =
1502     let len = String.length str in
1503     let rec loop i =
1504       if i >= len then false
1505       else (
1506         let c = str.[i] in
1507         if c >= 'A' && c <= 'Z' then true
1508         else loop (i+1)
1509       )
1510     in
1511     loop 0
1512   in
1513
1514   (* Check function names. *)
1515   List.iter (
1516     fun (name, _, _, _, _, _, _) ->
1517       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
1518         failwithf "function name %s does not need 'guestfs' prefix" name;
1519       if contains_uppercase name then
1520         failwithf "function name %s should not contain uppercase chars" name;
1521       if String.contains name '-' then
1522         failwithf "function name %s should not contain '-', use '_' instead."
1523           name
1524   ) all_functions;
1525
1526   (* Check function parameter/return names. *)
1527   List.iter (
1528     fun (name, style, _, _, _, _, _) ->
1529       let check_arg_ret_name n =
1530         if contains_uppercase n then
1531           failwithf "%s param/ret %s should not contain uppercase chars"
1532             name n;
1533         if String.contains n '-' || String.contains n '_' then
1534           failwithf "%s param/ret %s should not contain '-' or '_'"
1535             name n;
1536         if n = "value" then
1537           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;
1538         if n = "argv" || n = "args" then
1539           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
1540       in
1541
1542       (match fst style with
1543        | RErr -> ()
1544        | RInt n | RInt64 n | RBool n | RConstString n | RString n
1545        | RStringList n | RPVList n | RVGList n | RLVList n
1546        | RStat n | RStatVFS n
1547        | RHashtable n ->
1548            check_arg_ret_name n
1549        | RIntBool (n,m) ->
1550            check_arg_ret_name n;
1551            check_arg_ret_name m
1552       );
1553       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
1554   ) all_functions;
1555
1556   (* Check short descriptions. *)
1557   List.iter (
1558     fun (name, _, _, _, _, shortdesc, _) ->
1559       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
1560         failwithf "short description of %s should begin with lowercase." name;
1561       let c = shortdesc.[String.length shortdesc-1] in
1562       if c = '\n' || c = '.' then
1563         failwithf "short description of %s should not end with . or \\n." name
1564   ) all_functions;
1565
1566   (* Check long dscriptions. *)
1567   List.iter (
1568     fun (name, _, _, _, _, _, longdesc) ->
1569       if longdesc.[String.length longdesc-1] = '\n' then
1570         failwithf "long description of %s should not end with \\n." name
1571   ) all_functions;
1572
1573   (* Check proc_nrs. *)
1574   List.iter (
1575     fun (name, _, proc_nr, _, _, _, _) ->
1576       if proc_nr <= 0 then
1577         failwithf "daemon function %s should have proc_nr > 0" name
1578   ) daemon_functions;
1579
1580   List.iter (
1581     fun (name, _, proc_nr, _, _, _, _) ->
1582       if proc_nr <> -1 then
1583         failwithf "non-daemon function %s should have proc_nr -1" name
1584   ) non_daemon_functions;
1585
1586   let proc_nrs =
1587     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
1588       daemon_functions in
1589   let proc_nrs =
1590     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
1591   let rec loop = function
1592     | [] -> ()
1593     | [_] -> ()
1594     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
1595         loop rest
1596     | (name1,nr1) :: (name2,nr2) :: _ ->
1597         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
1598           name1 name2 nr1 nr2
1599   in
1600   loop proc_nrs;
1601
1602   (* Check tests. *)
1603   List.iter (
1604     function
1605       (* Ignore functions that have no tests.  We generate a
1606        * warning when the user does 'make check' instead.
1607        *)
1608     | name, _, _, _, [], _, _ -> ()
1609     | name, _, _, _, tests, _, _ ->
1610         let funcs =
1611           List.map (
1612             fun (_, test) ->
1613               match seq_of_test test with
1614               | [] ->
1615                   failwithf "%s has a test containing an empty sequence" name
1616               | cmds -> List.map List.hd cmds
1617           ) tests in
1618         let funcs = List.flatten funcs in
1619
1620         let tested = List.mem name funcs in
1621
1622         if not tested then
1623           failwithf "function %s has tests but does not test itself" name
1624   ) all_functions
1625
1626 (* 'pr' prints to the current output file. *)
1627 let chan = ref stdout
1628 let pr fs = ksprintf (output_string !chan) fs
1629
1630 (* Generate a header block in a number of standard styles. *)
1631 type comment_style = CStyle | HashStyle | OCamlStyle
1632 type license = GPLv2 | LGPLv2
1633
1634 let generate_header comment license =
1635   let c = match comment with
1636     | CStyle ->     pr "/* "; " *"
1637     | HashStyle ->  pr "# ";  "#"
1638     | OCamlStyle -> pr "(* "; " *" in
1639   pr "libguestfs generated file\n";
1640   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
1641   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
1642   pr "%s\n" c;
1643   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
1644   pr "%s\n" c;
1645   (match license with
1646    | GPLv2 ->
1647        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
1648        pr "%s it under the terms of the GNU General Public License as published by\n" c;
1649        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
1650        pr "%s (at your option) any later version.\n" c;
1651        pr "%s\n" c;
1652        pr "%s This program is distributed in the hope that it will be useful,\n" c;
1653        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1654        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
1655        pr "%s GNU General Public License for more details.\n" c;
1656        pr "%s\n" c;
1657        pr "%s You should have received a copy of the GNU General Public License along\n" c;
1658        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
1659        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
1660
1661    | LGPLv2 ->
1662        pr "%s This library is free software; you can redistribute it and/or\n" c;
1663        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
1664        pr "%s License as published by the Free Software Foundation; either\n" c;
1665        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
1666        pr "%s\n" c;
1667        pr "%s This library is distributed in the hope that it will be useful,\n" c;
1668        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1669        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
1670        pr "%s Lesser General Public License for more details.\n" c;
1671        pr "%s\n" c;
1672        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
1673        pr "%s License along with this library; if not, write to the Free Software\n" c;
1674        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
1675   );
1676   (match comment with
1677    | CStyle -> pr " */\n"
1678    | HashStyle -> ()
1679    | OCamlStyle -> pr " *)\n"
1680   );
1681   pr "\n"
1682
1683 (* Start of main code generation functions below this line. *)
1684
1685 (* Generate the pod documentation for the C API. *)
1686 let rec generate_actions_pod () =
1687   List.iter (
1688     fun (shortname, style, _, flags, _, _, longdesc) ->
1689       let name = "guestfs_" ^ shortname in
1690       pr "=head2 %s\n\n" name;
1691       pr " ";
1692       generate_prototype ~extern:false ~handle:"handle" name style;
1693       pr "\n\n";
1694       pr "%s\n\n" longdesc;
1695       (match fst style with
1696        | RErr ->
1697            pr "This function returns 0 on success or -1 on error.\n\n"
1698        | RInt _ ->
1699            pr "On error this function returns -1.\n\n"
1700        | RInt64 _ ->
1701            pr "On error this function returns -1.\n\n"
1702        | RBool _ ->
1703            pr "This function returns a C truth value on success or -1 on error.\n\n"
1704        | RConstString _ ->
1705            pr "This function returns a string, or NULL on error.
1706 The string is owned by the guest handle and must I<not> be freed.\n\n"
1707        | RString _ ->
1708            pr "This function returns a string, or NULL on error.
1709 I<The caller must free the returned string after use>.\n\n"
1710        | RStringList _ ->
1711            pr "This function returns a NULL-terminated array of strings
1712 (like L<environ(3)>), or NULL if there was an error.
1713 I<The caller must free the strings and the array after use>.\n\n"
1714        | RIntBool _ ->
1715            pr "This function returns a C<struct guestfs_int_bool *>,
1716 or NULL if there was an error.
1717 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
1718        | RPVList _ ->
1719            pr "This function returns a C<struct guestfs_lvm_pv_list *>
1720 (see E<lt>guestfs-structs.hE<gt>),
1721 or NULL if there was an error.
1722 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
1723        | RVGList _ ->
1724            pr "This function returns a C<struct guestfs_lvm_vg_list *>
1725 (see E<lt>guestfs-structs.hE<gt>),
1726 or NULL if there was an error.
1727 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
1728        | RLVList _ ->
1729            pr "This function returns a C<struct guestfs_lvm_lv_list *>
1730 (see E<lt>guestfs-structs.hE<gt>),
1731 or NULL if there was an error.
1732 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
1733        | RStat _ ->
1734            pr "This function returns a C<struct guestfs_stat *>
1735 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
1736 or NULL if there was an error.
1737 I<The caller must call C<free> after use>.\n\n"
1738        | RStatVFS _ ->
1739            pr "This function returns a C<struct guestfs_statvfs *>
1740 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
1741 or NULL if there was an error.
1742 I<The caller must call C<free> after use>.\n\n"
1743        | RHashtable _ ->
1744            pr "This function returns a NULL-terminated array of
1745 strings, or NULL if there was an error.
1746 The array of strings will always have length C<2n+1>, where
1747 C<n> keys and values alternate, followed by the trailing NULL entry.
1748 I<The caller must free the strings and the array after use>.\n\n"
1749       );
1750       if List.mem ProtocolLimitWarning flags then
1751         pr "%s\n\n" protocol_limit_warning;
1752       if List.mem DangerWillRobinson flags then
1753         pr "%s\n\n" danger_will_robinson;
1754   ) all_functions_sorted
1755
1756 and generate_structs_pod () =
1757   (* LVM structs documentation. *)
1758   List.iter (
1759     fun (typ, cols) ->
1760       pr "=head2 guestfs_lvm_%s\n" typ;
1761       pr "\n";
1762       pr " struct guestfs_lvm_%s {\n" typ;
1763       List.iter (
1764         function
1765         | name, `String -> pr "  char *%s;\n" name
1766         | name, `UUID ->
1767             pr "  /* The next field is NOT nul-terminated, be careful when printing it: */\n";
1768             pr "  char %s[32];\n" name
1769         | name, `Bytes -> pr "  uint64_t %s;\n" name
1770         | name, `Int -> pr "  int64_t %s;\n" name
1771         | name, `OptPercent ->
1772             pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
1773             pr "  float %s;\n" name
1774       ) cols;
1775       pr " \n";
1776       pr " struct guestfs_lvm_%s_list {\n" typ;
1777       pr "   uint32_t len; /* Number of elements in list. */\n";
1778       pr "   struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
1779       pr " };\n";
1780       pr " \n";
1781       pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
1782         typ typ;
1783       pr "\n"
1784   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1785
1786 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
1787  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
1788  *
1789  * We have to use an underscore instead of a dash because otherwise
1790  * rpcgen generates incorrect code.
1791  *
1792  * This header is NOT exported to clients, but see also generate_structs_h.
1793  *)
1794 and generate_xdr () =
1795   generate_header CStyle LGPLv2;
1796
1797   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
1798   pr "typedef string str<>;\n";
1799   pr "\n";
1800
1801   (* LVM internal structures. *)
1802   List.iter (
1803     function
1804     | typ, cols ->
1805         pr "struct guestfs_lvm_int_%s {\n" typ;
1806         List.iter (function
1807                    | name, `String -> pr "  string %s<>;\n" name
1808                    | name, `UUID -> pr "  opaque %s[32];\n" name
1809                    | name, `Bytes -> pr "  hyper %s;\n" name
1810                    | name, `Int -> pr "  hyper %s;\n" name
1811                    | name, `OptPercent -> pr "  float %s;\n" name
1812                   ) cols;
1813         pr "};\n";
1814         pr "\n";
1815         pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
1816         pr "\n";
1817   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1818
1819   (* Stat internal structures. *)
1820   List.iter (
1821     function
1822     | typ, cols ->
1823         pr "struct guestfs_int_%s {\n" typ;
1824         List.iter (function
1825                    | name, `Int -> pr "  hyper %s;\n" name
1826                   ) cols;
1827         pr "};\n";
1828         pr "\n";
1829   ) ["stat", stat_cols; "statvfs", statvfs_cols];
1830
1831   List.iter (
1832     fun (shortname, style, _, _, _, _, _) ->
1833       let name = "guestfs_" ^ shortname in
1834
1835       (match snd style with
1836        | [] -> ()
1837        | args ->
1838            pr "struct %s_args {\n" name;
1839            List.iter (
1840              function
1841              | String n -> pr "  string %s<>;\n" n
1842              | OptString n -> pr "  str *%s;\n" n
1843              | StringList n -> pr "  str %s<>;\n" n
1844              | Bool n -> pr "  bool %s;\n" n
1845              | Int n -> pr "  int %s;\n" n
1846              | FileIn _ | FileOut _ -> ()
1847            ) args;
1848            pr "};\n\n"
1849       );
1850       (match fst style with
1851        | RErr -> ()
1852        | RInt n ->
1853            pr "struct %s_ret {\n" name;
1854            pr "  int %s;\n" n;
1855            pr "};\n\n"
1856        | RInt64 n ->
1857            pr "struct %s_ret {\n" name;
1858            pr "  hyper %s;\n" n;
1859            pr "};\n\n"
1860        | RBool n ->
1861            pr "struct %s_ret {\n" name;
1862            pr "  bool %s;\n" n;
1863            pr "};\n\n"
1864        | RConstString _ ->
1865            failwithf "RConstString cannot be returned from a daemon function"
1866        | RString n ->
1867            pr "struct %s_ret {\n" name;
1868            pr "  string %s<>;\n" n;
1869            pr "};\n\n"
1870        | RStringList n ->
1871            pr "struct %s_ret {\n" name;
1872            pr "  str %s<>;\n" n;
1873            pr "};\n\n"
1874        | RIntBool (n,m) ->
1875            pr "struct %s_ret {\n" name;
1876            pr "  int %s;\n" n;
1877            pr "  bool %s;\n" m;
1878            pr "};\n\n"
1879        | RPVList n ->
1880            pr "struct %s_ret {\n" name;
1881            pr "  guestfs_lvm_int_pv_list %s;\n" n;
1882            pr "};\n\n"
1883        | RVGList n ->
1884            pr "struct %s_ret {\n" name;
1885            pr "  guestfs_lvm_int_vg_list %s;\n" n;
1886            pr "};\n\n"
1887        | RLVList n ->
1888            pr "struct %s_ret {\n" name;
1889            pr "  guestfs_lvm_int_lv_list %s;\n" n;
1890            pr "};\n\n"
1891        | RStat n ->
1892            pr "struct %s_ret {\n" name;
1893            pr "  guestfs_int_stat %s;\n" n;
1894            pr "};\n\n"
1895        | RStatVFS n ->
1896            pr "struct %s_ret {\n" name;
1897            pr "  guestfs_int_statvfs %s;\n" n;
1898            pr "};\n\n"
1899        | RHashtable n ->
1900            pr "struct %s_ret {\n" name;
1901            pr "  str %s<>;\n" n;
1902            pr "};\n\n"
1903       );
1904   ) daemon_functions;
1905
1906   (* Table of procedure numbers. *)
1907   pr "enum guestfs_procedure {\n";
1908   List.iter (
1909     fun (shortname, _, proc_nr, _, _, _, _) ->
1910       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
1911   ) daemon_functions;
1912   pr "  GUESTFS_PROC_NR_PROCS\n";
1913   pr "};\n";
1914   pr "\n";
1915
1916   (* Having to choose a maximum message size is annoying for several
1917    * reasons (it limits what we can do in the API), but it (a) makes
1918    * the protocol a lot simpler, and (b) provides a bound on the size
1919    * of the daemon which operates in limited memory space.  For large
1920    * file transfers you should use FTP.
1921    *)
1922   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
1923   pr "\n";
1924
1925   (* Message header, etc. *)
1926   pr "\
1927 /* The communication protocol is now documented in the guestfs(3)
1928  * manpage.
1929  */
1930
1931 const GUESTFS_PROGRAM = 0x2000F5F5;
1932 const GUESTFS_PROTOCOL_VERSION = 1;
1933
1934 /* These constants must be larger than any possible message length. */
1935 const GUESTFS_LAUNCH_FLAG = 0xf5f55f5f;
1936 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
1937
1938 enum guestfs_message_direction {
1939   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
1940   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
1941 };
1942
1943 enum guestfs_message_status {
1944   GUESTFS_STATUS_OK = 0,
1945   GUESTFS_STATUS_ERROR = 1
1946 };
1947
1948 const GUESTFS_ERROR_LEN = 256;
1949
1950 struct guestfs_message_error {
1951   string error_message<GUESTFS_ERROR_LEN>;
1952 };
1953
1954 struct guestfs_message_header {
1955   unsigned prog;                     /* GUESTFS_PROGRAM */
1956   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
1957   guestfs_procedure proc;            /* GUESTFS_PROC_x */
1958   guestfs_message_direction direction;
1959   unsigned serial;                   /* message serial number */
1960   guestfs_message_status status;
1961 };
1962
1963 const GUESTFS_MAX_CHUNK_SIZE = 8192;
1964
1965 struct guestfs_chunk {
1966   int cancel;                        /* if non-zero, transfer is cancelled */
1967   /* data size is 0 bytes if the transfer has finished successfully */
1968   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
1969 };
1970 "
1971
1972 (* Generate the guestfs-structs.h file. *)
1973 and generate_structs_h () =
1974   generate_header CStyle LGPLv2;
1975
1976   (* This is a public exported header file containing various
1977    * structures.  The structures are carefully written to have
1978    * exactly the same in-memory format as the XDR structures that
1979    * we use on the wire to the daemon.  The reason for creating
1980    * copies of these structures here is just so we don't have to
1981    * export the whole of guestfs_protocol.h (which includes much
1982    * unrelated and XDR-dependent stuff that we don't want to be
1983    * public, or required by clients).
1984    *
1985    * To reiterate, we will pass these structures to and from the
1986    * client with a simple assignment or memcpy, so the format
1987    * must be identical to what rpcgen / the RFC defines.
1988    *)
1989
1990   (* guestfs_int_bool structure. *)
1991   pr "struct guestfs_int_bool {\n";
1992   pr "  int32_t i;\n";
1993   pr "  int32_t b;\n";
1994   pr "};\n";
1995   pr "\n";
1996
1997   (* LVM public structures. *)
1998   List.iter (
1999     function
2000     | typ, cols ->
2001         pr "struct guestfs_lvm_%s {\n" typ;
2002         List.iter (
2003           function
2004           | name, `String -> pr "  char *%s;\n" name
2005           | name, `UUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
2006           | name, `Bytes -> pr "  uint64_t %s;\n" name
2007           | name, `Int -> pr "  int64_t %s;\n" name
2008           | name, `OptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
2009         ) cols;
2010         pr "};\n";
2011         pr "\n";
2012         pr "struct guestfs_lvm_%s_list {\n" typ;
2013         pr "  uint32_t len;\n";
2014         pr "  struct guestfs_lvm_%s *val;\n" typ;
2015         pr "};\n";
2016         pr "\n"
2017   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2018
2019   (* Stat structures. *)
2020   List.iter (
2021     function
2022     | typ, cols ->
2023         pr "struct guestfs_%s {\n" typ;
2024         List.iter (
2025           function
2026           | name, `Int -> pr "  int64_t %s;\n" name
2027         ) cols;
2028         pr "};\n";
2029         pr "\n"
2030   ) ["stat", stat_cols; "statvfs", statvfs_cols]
2031
2032 (* Generate the guestfs-actions.h file. *)
2033 and generate_actions_h () =
2034   generate_header CStyle LGPLv2;
2035   List.iter (
2036     fun (shortname, style, _, _, _, _, _) ->
2037       let name = "guestfs_" ^ shortname in
2038       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
2039         name style
2040   ) all_functions
2041
2042 (* Generate the client-side dispatch stubs. *)
2043 and generate_client_actions () =
2044   generate_header CStyle LGPLv2;
2045
2046   pr "\
2047 #include <stdio.h>
2048 #include <stdlib.h>
2049
2050 #include \"guestfs.h\"
2051 #include \"guestfs_protocol.h\"
2052
2053 #define error guestfs_error
2054 #define perrorf guestfs_perrorf
2055 #define safe_malloc guestfs_safe_malloc
2056 #define safe_realloc guestfs_safe_realloc
2057 #define safe_strdup guestfs_safe_strdup
2058 #define safe_memdup guestfs_safe_memdup
2059
2060 /* Check the return message from a call for validity. */
2061 static int
2062 check_reply_header (guestfs_h *g,
2063                     const struct guestfs_message_header *hdr,
2064                     int proc_nr, int serial)
2065 {
2066   if (hdr->prog != GUESTFS_PROGRAM) {
2067     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
2068     return -1;
2069   }
2070   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
2071     error (g, \"wrong protocol version (%%d/%%d)\",
2072            hdr->vers, GUESTFS_PROTOCOL_VERSION);
2073     return -1;
2074   }
2075   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
2076     error (g, \"unexpected message direction (%%d/%%d)\",
2077            hdr->direction, GUESTFS_DIRECTION_REPLY);
2078     return -1;
2079   }
2080   if (hdr->proc != proc_nr) {
2081     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
2082     return -1;
2083   }
2084   if (hdr->serial != serial) {
2085     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
2086     return -1;
2087   }
2088
2089   return 0;
2090 }
2091
2092 /* Check we are in the right state to run a high-level action. */
2093 static int
2094 check_state (guestfs_h *g, const char *caller)
2095 {
2096   if (!guestfs_is_ready (g)) {
2097     if (guestfs_is_config (g))
2098       error (g, \"%%s: call launch() before using this function\",
2099         caller);
2100     else if (guestfs_is_launching (g))
2101       error (g, \"%%s: call wait_ready() before using this function\",
2102         caller);
2103     else
2104       error (g, \"%%s called from the wrong state, %%d != READY\",
2105         caller, guestfs_get_state (g));
2106     return -1;
2107   }
2108   return 0;
2109 }
2110
2111 ";
2112
2113   (* Client-side stubs for each function. *)
2114   List.iter (
2115     fun (shortname, style, _, _, _, _, _) ->
2116       let name = "guestfs_" ^ shortname in
2117
2118       (* Generate the context struct which stores the high-level
2119        * state between callback functions.
2120        *)
2121       pr "struct %s_ctx {\n" shortname;
2122       pr "  /* This flag is set by the callbacks, so we know we've done\n";
2123       pr "   * the callbacks as expected, and in the right sequence.\n";
2124       pr "   * 0 = not called, 1 = send called,\n";
2125       pr "   * 1001 = reply called.\n";
2126       pr "   */\n";
2127       pr "  int cb_sequence;\n";
2128       pr "  struct guestfs_message_header hdr;\n";
2129       pr "  struct guestfs_message_error err;\n";
2130       (match fst style with
2131        | RErr -> ()
2132        | RConstString _ ->
2133            failwithf "RConstString cannot be returned from a daemon function"
2134        | RInt _ | RInt64 _
2135        | RBool _ | RString _ | RStringList _
2136        | RIntBool _
2137        | RPVList _ | RVGList _ | RLVList _
2138        | RStat _ | RStatVFS _
2139        | RHashtable _ ->
2140            pr "  struct %s_ret ret;\n" name
2141       );
2142       pr "};\n";
2143       pr "\n";
2144
2145       (* Generate the reply callback function. *)
2146       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
2147       pr "{\n";
2148       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2149       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
2150       pr "\n";
2151       pr "  ml->main_loop_quit (ml, g);\n";
2152       pr "\n";
2153       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
2154       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
2155       pr "    return;\n";
2156       pr "  }\n";
2157       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
2158       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
2159       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
2160         name;
2161       pr "      return;\n";
2162       pr "    }\n";
2163       pr "    goto done;\n";
2164       pr "  }\n";
2165
2166       (match fst style with
2167        | RErr -> ()
2168        | RConstString _ ->
2169            failwithf "RConstString cannot be returned from a daemon function"
2170        | RInt _ | RInt64 _
2171        | RBool _ | RString _ | RStringList _
2172        | RIntBool _
2173        | RPVList _ | RVGList _ | RLVList _
2174        | RStat _ | RStatVFS _
2175        | RHashtable _ ->
2176             pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
2177             pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
2178             pr "    return;\n";
2179             pr "  }\n";
2180       );
2181
2182       pr " done:\n";
2183       pr "  ctx->cb_sequence = 1001;\n";
2184       pr "}\n\n";
2185
2186       (* Generate the action stub. *)
2187       generate_prototype ~extern:false ~semicolon:false ~newline:true
2188         ~handle:"g" name style;
2189
2190       let error_code =
2191         match fst style with
2192         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
2193         | RConstString _ ->
2194             failwithf "RConstString cannot be returned from a daemon function"
2195         | RString _ | RStringList _ | RIntBool _
2196         | RPVList _ | RVGList _ | RLVList _
2197         | RStat _ | RStatVFS _
2198         | RHashtable _ ->
2199             "NULL" in
2200
2201       pr "{\n";
2202
2203       (match snd style with
2204        | [] -> ()
2205        | _ -> pr "  struct %s_args args;\n" name
2206       );
2207
2208       pr "  struct %s_ctx ctx;\n" shortname;
2209       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2210       pr "  int serial;\n";
2211       pr "\n";
2212       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
2213       pr "\n";
2214       pr "  memset (&ctx, 0, sizeof ctx);\n";
2215       pr "\n";
2216
2217       (* Send the main header and arguments. *)
2218       (match snd style with
2219        | [] ->
2220            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
2221              (String.uppercase shortname)
2222        | args ->
2223            List.iter (
2224              function
2225              | String n ->
2226                  pr "  args.%s = (char *) %s;\n" n n
2227              | OptString n ->
2228                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
2229              | StringList n ->
2230                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
2231                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
2232              | Bool n ->
2233                  pr "  args.%s = %s;\n" n n
2234              | Int n ->
2235                  pr "  args.%s = %s;\n" n n
2236              | FileIn _ | FileOut _ -> ()
2237            ) args;
2238            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
2239              (String.uppercase shortname);
2240            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
2241              name;
2242       );
2243       pr "  if (serial == -1)\n";
2244       pr "    return %s;\n" error_code;
2245       pr "\n";
2246
2247       (* Send any additional files (FileIn) requested. *)
2248       List.iter (
2249         function
2250         | FileIn n ->
2251             pr "  if (guestfs__send_file_sync (g, %s) == -1)\n" n;
2252             pr "    return %s;\n" error_code;
2253             pr "\n";
2254         | _ -> ()
2255       ) (snd style);
2256
2257       (* Wait for the reply from the remote end. *)
2258       pr "  guestfs__switch_to_receiving (g);\n";
2259       pr "  ctx.cb_sequence = 0;\n";
2260       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
2261       pr "  (void) ml->main_loop_run (ml, g);\n";
2262       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
2263       pr "  if (ctx.cb_sequence != 1001) {\n";
2264       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
2265       pr "    return %s;\n" error_code;
2266       pr "  }\n";
2267       pr "\n";
2268
2269       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
2270         (String.uppercase shortname);
2271       pr "    return %s;\n" error_code;
2272       pr "\n";
2273
2274       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
2275       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
2276       pr "    return %s;\n" error_code;
2277       pr "  }\n";
2278       pr "\n";
2279
2280       (* Expecting to receive further files (FileOut)? *)
2281       List.iter (
2282         function
2283         | FileOut n ->
2284             pr "  if (guestfs__receive_file_sync (g, %s) == -1)\n" n;
2285             pr "    return %s;\n" error_code;
2286             pr "\n";
2287         | _ -> ()
2288       ) (snd style);
2289
2290       (match fst style with
2291        | RErr -> pr "  return 0;\n"
2292        | RInt n | RInt64 n | RBool n ->
2293            pr "  return ctx.ret.%s;\n" n
2294        | RConstString _ ->
2295            failwithf "RConstString cannot be returned from a daemon function"
2296        | RString n ->
2297            pr "  return ctx.ret.%s; /* caller will free */\n" n
2298        | RStringList n | RHashtable n ->
2299            pr "  /* caller will free this, but we need to add a NULL entry */\n";
2300            pr "  ctx.ret.%s.%s_val =\n" n n;
2301            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
2302            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
2303              n n;
2304            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
2305            pr "  return ctx.ret.%s.%s_val;\n" n n
2306        | RIntBool _ ->
2307            pr "  /* caller with free this */\n";
2308            pr "  return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
2309        | RPVList n | RVGList n | RLVList n
2310        | RStat n | RStatVFS n ->
2311            pr "  /* caller will free this */\n";
2312            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
2313       );
2314
2315       pr "}\n\n"
2316   ) daemon_functions
2317
2318 (* Generate daemon/actions.h. *)
2319 and generate_daemon_actions_h () =
2320   generate_header CStyle GPLv2;
2321
2322   pr "#include \"../src/guestfs_protocol.h\"\n";
2323   pr "\n";
2324
2325   List.iter (
2326     fun (name, style, _, _, _, _, _) ->
2327         generate_prototype
2328           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
2329           name style;
2330   ) daemon_functions
2331
2332 (* Generate the server-side stubs. *)
2333 and generate_daemon_actions () =
2334   generate_header CStyle GPLv2;
2335
2336   pr "#define _GNU_SOURCE // for strchrnul\n";
2337   pr "\n";
2338   pr "#include <stdio.h>\n";
2339   pr "#include <stdlib.h>\n";
2340   pr "#include <string.h>\n";
2341   pr "#include <inttypes.h>\n";
2342   pr "#include <ctype.h>\n";
2343   pr "#include <rpc/types.h>\n";
2344   pr "#include <rpc/xdr.h>\n";
2345   pr "\n";
2346   pr "#include \"daemon.h\"\n";
2347   pr "#include \"../src/guestfs_protocol.h\"\n";
2348   pr "#include \"actions.h\"\n";
2349   pr "\n";
2350
2351   List.iter (
2352     fun (name, style, _, _, _, _, _) ->
2353       (* Generate server-side stubs. *)
2354       pr "static void %s_stub (XDR *xdr_in)\n" name;
2355       pr "{\n";
2356       let error_code =
2357         match fst style with
2358         | RErr | RInt _ -> pr "  int r;\n"; "-1"
2359         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
2360         | RBool _ -> pr "  int r;\n"; "-1"
2361         | RConstString _ ->
2362             failwithf "RConstString cannot be returned from a daemon function"
2363         | RString _ -> pr "  char *r;\n"; "NULL"
2364         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
2365         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
2366         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
2367         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
2368         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL"
2369         | RStat _ -> pr "  guestfs_int_stat *r;\n"; "NULL"
2370         | RStatVFS _ -> pr "  guestfs_int_statvfs *r;\n"; "NULL" in
2371
2372       (match snd style with
2373        | [] -> ()
2374        | args ->
2375            pr "  struct guestfs_%s_args args;\n" name;
2376            List.iter (
2377              function
2378              | String n
2379              | OptString n -> pr "  const char *%s;\n" n
2380              | StringList n -> pr "  char **%s;\n" n
2381              | Bool n -> pr "  int %s;\n" n
2382              | Int n -> pr "  int %s;\n" n
2383              | FileIn _ | FileOut _ -> ()
2384            ) args
2385       );
2386       pr "\n";
2387
2388       (match snd style with
2389        | [] -> ()
2390        | args ->
2391            pr "  memset (&args, 0, sizeof args);\n";
2392            pr "\n";
2393            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
2394            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
2395            pr "    return;\n";
2396            pr "  }\n";
2397            List.iter (
2398              function
2399              | String n -> pr "  %s = args.%s;\n" n n
2400              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
2401              | StringList n ->
2402                  pr "  args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
2403                  pr "  args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
2404                  pr "  %s = args.%s.%s_val;\n" n n n
2405              | Bool n -> pr "  %s = args.%s;\n" n n
2406              | Int n -> pr "  %s = args.%s;\n" n n
2407              | FileIn _ | FileOut _ -> ()
2408            ) args;
2409            pr "\n"
2410       );
2411
2412       (* Don't want to call the impl with any FileIn or FileOut
2413        * parameters, since these go "outside" the RPC protocol.
2414        *)
2415       let argsnofile =
2416         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
2417           (snd style) in
2418       pr "  r = do_%s " name;
2419       generate_call_args argsnofile;
2420       pr ";\n";
2421
2422       pr "  if (r == %s)\n" error_code;
2423       pr "    /* do_%s has already called reply_with_error */\n" name;
2424       pr "    goto done;\n";
2425       pr "\n";
2426
2427       (* If there are any FileOut parameters, then the impl must
2428        * send its own reply.
2429        *)
2430       let no_reply =
2431         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
2432       if no_reply then
2433         pr "  /* do_%s has already sent a reply */\n" name
2434       else (
2435         match fst style with
2436         | RErr -> pr "  reply (NULL, NULL);\n"
2437         | RInt n | RInt64 n | RBool n ->
2438             pr "  struct guestfs_%s_ret ret;\n" name;
2439             pr "  ret.%s = r;\n" n;
2440             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2441               name
2442         | RConstString _ ->
2443             failwithf "RConstString cannot be returned from a daemon function"
2444         | RString n ->
2445             pr "  struct guestfs_%s_ret ret;\n" name;
2446             pr "  ret.%s = r;\n" n;
2447             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2448               name;
2449             pr "  free (r);\n"
2450         | RStringList n | RHashtable n ->
2451             pr "  struct guestfs_%s_ret ret;\n" name;
2452             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
2453             pr "  ret.%s.%s_val = r;\n" n n;
2454             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2455               name;
2456             pr "  free_strings (r);\n"
2457         | RIntBool _ ->
2458             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
2459               name;
2460             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2461         | RPVList n | RVGList n | RLVList n
2462         | RStat n | RStatVFS n ->
2463             pr "  struct guestfs_%s_ret ret;\n" name;
2464             pr "  ret.%s = *r;\n" n;
2465             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2466               name;
2467             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2468               name
2469       );
2470
2471       (* Free the args. *)
2472       (match snd style with
2473        | [] ->
2474            pr "done: ;\n";
2475        | _ ->
2476            pr "done:\n";
2477            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2478              name
2479       );
2480
2481       pr "}\n\n";
2482   ) daemon_functions;
2483
2484   (* Dispatch function. *)
2485   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2486   pr "{\n";
2487   pr "  switch (proc_nr) {\n";
2488
2489   List.iter (
2490     fun (name, style, _, _, _, _, _) ->
2491         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
2492         pr "      %s_stub (xdr_in);\n" name;
2493         pr "      break;\n"
2494   ) daemon_functions;
2495
2496   pr "    default:\n";
2497   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2498   pr "  }\n";
2499   pr "}\n";
2500   pr "\n";
2501
2502   (* LVM columns and tokenization functions. *)
2503   (* XXX This generates crap code.  We should rethink how we
2504    * do this parsing.
2505    *)
2506   List.iter (
2507     function
2508     | typ, cols ->
2509         pr "static const char *lvm_%s_cols = \"%s\";\n"
2510           typ (String.concat "," (List.map fst cols));
2511         pr "\n";
2512
2513         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2514         pr "{\n";
2515         pr "  char *tok, *p, *next;\n";
2516         pr "  int i, j;\n";
2517         pr "\n";
2518         (*
2519         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2520         pr "\n";
2521         *)
2522         pr "  if (!str) {\n";
2523         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2524         pr "    return -1;\n";
2525         pr "  }\n";
2526         pr "  if (!*str || isspace (*str)) {\n";
2527         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2528         pr "    return -1;\n";
2529         pr "  }\n";
2530         pr "  tok = str;\n";
2531         List.iter (
2532           fun (name, coltype) ->
2533             pr "  if (!tok) {\n";
2534             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2535             pr "    return -1;\n";
2536             pr "  }\n";
2537             pr "  p = strchrnul (tok, ',');\n";
2538             pr "  if (*p) next = p+1; else next = NULL;\n";
2539             pr "  *p = '\\0';\n";
2540             (match coltype with
2541              | `String ->
2542                  pr "  r->%s = strdup (tok);\n" name;
2543                  pr "  if (r->%s == NULL) {\n" name;
2544                  pr "    perror (\"strdup\");\n";
2545                  pr "    return -1;\n";
2546                  pr "  }\n"
2547              | `UUID ->
2548                  pr "  for (i = j = 0; i < 32; ++j) {\n";
2549                  pr "    if (tok[j] == '\\0') {\n";
2550                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2551                  pr "      return -1;\n";
2552                  pr "    } else if (tok[j] != '-')\n";
2553                  pr "      r->%s[i++] = tok[j];\n" name;
2554                  pr "  }\n";
2555              | `Bytes ->
2556                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2557                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2558                  pr "    return -1;\n";
2559                  pr "  }\n";
2560              | `Int ->
2561                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2562                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2563                  pr "    return -1;\n";
2564                  pr "  }\n";
2565              | `OptPercent ->
2566                  pr "  if (tok[0] == '\\0')\n";
2567                  pr "    r->%s = -1;\n" name;
2568                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2569                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2570                  pr "    return -1;\n";
2571                  pr "  }\n";
2572             );
2573             pr "  tok = next;\n";
2574         ) cols;
2575
2576         pr "  if (tok != NULL) {\n";
2577         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2578         pr "    return -1;\n";
2579         pr "  }\n";
2580         pr "  return 0;\n";
2581         pr "}\n";
2582         pr "\n";
2583
2584         pr "guestfs_lvm_int_%s_list *\n" typ;
2585         pr "parse_command_line_%ss (void)\n" typ;
2586         pr "{\n";
2587         pr "  char *out, *err;\n";
2588         pr "  char *p, *pend;\n";
2589         pr "  int r, i;\n";
2590         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
2591         pr "  void *newp;\n";
2592         pr "\n";
2593         pr "  ret = malloc (sizeof *ret);\n";
2594         pr "  if (!ret) {\n";
2595         pr "    reply_with_perror (\"malloc\");\n";
2596         pr "    return NULL;\n";
2597         pr "  }\n";
2598         pr "\n";
2599         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2600         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2601         pr "\n";
2602         pr "  r = command (&out, &err,\n";
2603         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
2604         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2605         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2606         pr "  if (r == -1) {\n";
2607         pr "    reply_with_error (\"%%s\", err);\n";
2608         pr "    free (out);\n";
2609         pr "    free (err);\n";
2610         pr "    free (ret);\n";
2611         pr "    return NULL;\n";
2612         pr "  }\n";
2613         pr "\n";
2614         pr "  free (err);\n";
2615         pr "\n";
2616         pr "  /* Tokenize each line of the output. */\n";
2617         pr "  p = out;\n";
2618         pr "  i = 0;\n";
2619         pr "  while (p) {\n";
2620         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
2621         pr "    if (pend) {\n";
2622         pr "      *pend = '\\0';\n";
2623         pr "      pend++;\n";
2624         pr "    }\n";
2625         pr "\n";
2626         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
2627         pr "      p++;\n";
2628         pr "\n";
2629         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
2630         pr "      p = pend;\n";
2631         pr "      continue;\n";
2632         pr "    }\n";
2633         pr "\n";
2634         pr "    /* Allocate some space to store this next entry. */\n";
2635         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2636         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2637         pr "    if (newp == NULL) {\n";
2638         pr "      reply_with_perror (\"realloc\");\n";
2639         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2640         pr "      free (ret);\n";
2641         pr "      free (out);\n";
2642         pr "      return NULL;\n";
2643         pr "    }\n";
2644         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2645         pr "\n";
2646         pr "    /* Tokenize the next entry. */\n";
2647         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2648         pr "    if (r == -1) {\n";
2649         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2650         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2651         pr "      free (ret);\n";
2652         pr "      free (out);\n";
2653         pr "      return NULL;\n";
2654         pr "    }\n";
2655         pr "\n";
2656         pr "    ++i;\n";
2657         pr "    p = pend;\n";
2658         pr "  }\n";
2659         pr "\n";
2660         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2661         pr "\n";
2662         pr "  free (out);\n";
2663         pr "  return ret;\n";
2664         pr "}\n"
2665
2666   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2667
2668 (* Generate the tests. *)
2669 and generate_tests () =
2670   generate_header CStyle GPLv2;
2671
2672   pr "\
2673 #include <stdio.h>
2674 #include <stdlib.h>
2675 #include <string.h>
2676 #include <unistd.h>
2677 #include <sys/types.h>
2678 #include <fcntl.h>
2679
2680 #include \"guestfs.h\"
2681
2682 static guestfs_h *g;
2683 static int suppress_error = 0;
2684
2685 static void print_error (guestfs_h *g, void *data, const char *msg)
2686 {
2687   if (!suppress_error)
2688     fprintf (stderr, \"%%s\\n\", msg);
2689 }
2690
2691 static void print_strings (char * const * const argv)
2692 {
2693   int argc;
2694
2695   for (argc = 0; argv[argc] != NULL; ++argc)
2696     printf (\"\\t%%s\\n\", argv[argc]);
2697 }
2698
2699 /*
2700 static void print_table (char * const * const argv)
2701 {
2702   int i;
2703
2704   for (i = 0; argv[i] != NULL; i += 2)
2705     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
2706 }
2707 */
2708
2709 static void no_test_warnings (void)
2710 {
2711 ";
2712
2713   List.iter (
2714     function
2715     | name, _, _, _, [], _, _ ->
2716         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
2717     | name, _, _, _, tests, _, _ -> ()
2718   ) all_functions;
2719
2720   pr "}\n";
2721   pr "\n";
2722
2723   (* Generate the actual tests.  Note that we generate the tests
2724    * in reverse order, deliberately, so that (in general) the
2725    * newest tests run first.  This makes it quicker and easier to
2726    * debug them.
2727    *)
2728   let test_names =
2729     List.map (
2730       fun (name, _, _, _, tests, _, _) ->
2731         mapi (generate_one_test name) tests
2732     ) (List.rev all_functions) in
2733   let test_names = List.concat test_names in
2734   let nr_tests = List.length test_names in
2735
2736   pr "\
2737 int main (int argc, char *argv[])
2738 {
2739   char c = 0;
2740   int failed = 0;
2741   const char *srcdir;
2742   int fd;
2743   char buf[256];
2744   int nr_tests, test_num = 0;
2745
2746   no_test_warnings ();
2747
2748   g = guestfs_create ();
2749   if (g == NULL) {
2750     printf (\"guestfs_create FAILED\\n\");
2751     exit (1);
2752   }
2753
2754   guestfs_set_error_handler (g, print_error, NULL);
2755
2756   srcdir = getenv (\"srcdir\");
2757   if (!srcdir) srcdir = \".\";
2758   guestfs_set_path (g, srcdir);
2759
2760   snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
2761   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2762   if (fd == -1) {
2763     perror (buf);
2764     exit (1);
2765   }
2766   if (lseek (fd, %d, SEEK_SET) == -1) {
2767     perror (\"lseek\");
2768     close (fd);
2769     unlink (buf);
2770     exit (1);
2771   }
2772   if (write (fd, &c, 1) == -1) {
2773     perror (\"write\");
2774     close (fd);
2775     unlink (buf);
2776     exit (1);
2777   }
2778   if (close (fd) == -1) {
2779     perror (buf);
2780     unlink (buf);
2781     exit (1);
2782   }
2783   if (guestfs_add_drive (g, buf) == -1) {
2784     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2785     exit (1);
2786   }
2787
2788   snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
2789   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2790   if (fd == -1) {
2791     perror (buf);
2792     exit (1);
2793   }
2794   if (lseek (fd, %d, SEEK_SET) == -1) {
2795     perror (\"lseek\");
2796     close (fd);
2797     unlink (buf);
2798     exit (1);
2799   }
2800   if (write (fd, &c, 1) == -1) {
2801     perror (\"write\");
2802     close (fd);
2803     unlink (buf);
2804     exit (1);
2805   }
2806   if (close (fd) == -1) {
2807     perror (buf);
2808     unlink (buf);
2809     exit (1);
2810   }
2811   if (guestfs_add_drive (g, buf) == -1) {
2812     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2813     exit (1);
2814   }
2815
2816   snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
2817   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2818   if (fd == -1) {
2819     perror (buf);
2820     exit (1);
2821   }
2822   if (lseek (fd, %d, SEEK_SET) == -1) {
2823     perror (\"lseek\");
2824     close (fd);
2825     unlink (buf);
2826     exit (1);
2827   }
2828   if (write (fd, &c, 1) == -1) {
2829     perror (\"write\");
2830     close (fd);
2831     unlink (buf);
2832     exit (1);
2833   }
2834   if (close (fd) == -1) {
2835     perror (buf);
2836     unlink (buf);
2837     exit (1);
2838   }
2839   if (guestfs_add_drive (g, buf) == -1) {
2840     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2841     exit (1);
2842   }
2843
2844   if (guestfs_launch (g) == -1) {
2845     printf (\"guestfs_launch FAILED\\n\");
2846     exit (1);
2847   }
2848   if (guestfs_wait_ready (g) == -1) {
2849     printf (\"guestfs_wait_ready FAILED\\n\");
2850     exit (1);
2851   }
2852
2853   nr_tests = %d;
2854
2855 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
2856
2857   iteri (
2858     fun i test_name ->
2859       pr "  test_num++;\n";
2860       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
2861       pr "  if (%s () == -1) {\n" test_name;
2862       pr "    printf (\"%s FAILED\\n\");\n" test_name;
2863       pr "    failed++;\n";
2864       pr "  }\n";
2865   ) test_names;
2866   pr "\n";
2867
2868   pr "  guestfs_close (g);\n";
2869   pr "  snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
2870   pr "  unlink (buf);\n";
2871   pr "  snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
2872   pr "  unlink (buf);\n";
2873   pr "  snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
2874   pr "  unlink (buf);\n";
2875   pr "\n";
2876
2877   pr "  if (failed > 0) {\n";
2878   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
2879   pr "    exit (1);\n";
2880   pr "  }\n";
2881   pr "\n";
2882
2883   pr "  exit (0);\n";
2884   pr "}\n"
2885
2886 and generate_one_test name i (init, test) =
2887   let test_name = sprintf "test_%s_%d" name i in
2888
2889   pr "static int %s (void)\n" test_name;
2890   pr "{\n";
2891
2892   (match init with
2893    | InitNone -> ()
2894    | InitEmpty ->
2895        pr "  /* InitEmpty for %s (%d) */\n" name i;
2896        List.iter (generate_test_command_call test_name)
2897          [["umount_all"];
2898           ["lvm_remove_all"]]
2899    | InitBasicFS ->
2900        pr "  /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
2901        List.iter (generate_test_command_call test_name)
2902          [["umount_all"];
2903           ["lvm_remove_all"];
2904           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2905           ["mkfs"; "ext2"; "/dev/sda1"];
2906           ["mount"; "/dev/sda1"; "/"]]
2907    | InitBasicFSonLVM ->
2908        pr "  /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
2909          name i;
2910        List.iter (generate_test_command_call test_name)
2911          [["umount_all"];
2912           ["lvm_remove_all"];
2913           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2914           ["pvcreate"; "/dev/sda1"];
2915           ["vgcreate"; "VG"; "/dev/sda1"];
2916           ["lvcreate"; "LV"; "VG"; "8"];
2917           ["mkfs"; "ext2"; "/dev/VG/LV"];
2918           ["mount"; "/dev/VG/LV"; "/"]]
2919   );
2920
2921   let get_seq_last = function
2922     | [] ->
2923         failwithf "%s: you cannot use [] (empty list) when expecting a command"
2924           test_name
2925     | seq ->
2926         let seq = List.rev seq in
2927         List.rev (List.tl seq), List.hd seq
2928   in
2929
2930   (match test with
2931    | TestRun seq ->
2932        pr "  /* TestRun for %s (%d) */\n" name i;
2933        List.iter (generate_test_command_call test_name) seq
2934    | TestOutput (seq, expected) ->
2935        pr "  /* TestOutput for %s (%d) */\n" name i;
2936        let seq, last = get_seq_last seq in
2937        let test () =
2938          pr "    if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
2939          pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
2940          pr "      return -1;\n";
2941          pr "    }\n"
2942        in
2943        List.iter (generate_test_command_call test_name) seq;
2944        generate_test_command_call ~test test_name last
2945    | TestOutputList (seq, expected) ->
2946        pr "  /* TestOutputList for %s (%d) */\n" name i;
2947        let seq, last = get_seq_last seq in
2948        let test () =
2949          iteri (
2950            fun i str ->
2951              pr "    if (!r[%d]) {\n" i;
2952              pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
2953              pr "      print_strings (r);\n";
2954              pr "      return -1;\n";
2955              pr "    }\n";
2956              pr "    if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
2957              pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
2958              pr "      return -1;\n";
2959              pr "    }\n"
2960          ) expected;
2961          pr "    if (r[%d] != NULL) {\n" (List.length expected);
2962          pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
2963            test_name;
2964          pr "      print_strings (r);\n";
2965          pr "      return -1;\n";
2966          pr "    }\n"
2967        in
2968        List.iter (generate_test_command_call test_name) seq;
2969        generate_test_command_call ~test test_name last
2970    | TestOutputInt (seq, expected) ->
2971        pr "  /* TestOutputInt for %s (%d) */\n" name i;
2972        let seq, last = get_seq_last seq in
2973        let test () =
2974          pr "    if (r != %d) {\n" expected;
2975          pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
2976            test_name expected;
2977          pr "               (int) r);\n";
2978          pr "      return -1;\n";
2979          pr "    }\n"
2980        in
2981        List.iter (generate_test_command_call test_name) seq;
2982        generate_test_command_call ~test test_name last
2983    | TestOutputTrue seq ->
2984        pr "  /* TestOutputTrue for %s (%d) */\n" name i;
2985        let seq, last = get_seq_last seq in
2986        let test () =
2987          pr "    if (!r) {\n";
2988          pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
2989            test_name;
2990          pr "      return -1;\n";
2991          pr "    }\n"
2992        in
2993        List.iter (generate_test_command_call test_name) seq;
2994        generate_test_command_call ~test test_name last
2995    | TestOutputFalse seq ->
2996        pr "  /* TestOutputFalse for %s (%d) */\n" name i;
2997        let seq, last = get_seq_last seq in
2998        let test () =
2999          pr "    if (r) {\n";
3000          pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
3001            test_name;
3002          pr "      return -1;\n";
3003          pr "    }\n"
3004        in
3005        List.iter (generate_test_command_call test_name) seq;
3006        generate_test_command_call ~test test_name last
3007    | TestOutputLength (seq, expected) ->
3008        pr "  /* TestOutputLength for %s (%d) */\n" name i;
3009        let seq, last = get_seq_last seq in
3010        let test () =
3011          pr "    int j;\n";
3012          pr "    for (j = 0; j < %d; ++j)\n" expected;
3013          pr "      if (r[j] == NULL) {\n";
3014          pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
3015            test_name;
3016          pr "        print_strings (r);\n";
3017          pr "        return -1;\n";
3018          pr "      }\n";
3019          pr "    if (r[j] != NULL) {\n";
3020          pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
3021            test_name;
3022          pr "      print_strings (r);\n";
3023          pr "      return -1;\n";
3024          pr "    }\n"
3025        in
3026        List.iter (generate_test_command_call test_name) seq;
3027        generate_test_command_call ~test test_name last
3028    | TestOutputStruct (seq, checks) ->
3029        pr "  /* TestOutputStruct for %s (%d) */\n" name i;
3030        let seq, last = get_seq_last seq in
3031        let test () =
3032          List.iter (
3033            function
3034            | CompareWithInt (field, expected) ->
3035                pr "    if (r->%s != %d) {\n" field expected;
3036                pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
3037                  test_name field expected;
3038                pr "               (int) r->%s);\n" field;
3039                pr "      return -1;\n";
3040                pr "    }\n"
3041            | CompareWithString (field, expected) ->
3042                pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
3043                pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
3044                  test_name field expected;
3045                pr "               r->%s);\n" field;
3046                pr "      return -1;\n";
3047                pr "    }\n"
3048            | CompareFieldsIntEq (field1, field2) ->
3049                pr "    if (r->%s != r->%s) {\n" field1 field2;
3050                pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
3051                  test_name field1 field2;
3052                pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
3053                pr "      return -1;\n";
3054                pr "    }\n"
3055            | CompareFieldsStrEq (field1, field2) ->
3056                pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
3057                pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
3058                  test_name field1 field2;
3059                pr "               r->%s, r->%s);\n" field1 field2;
3060                pr "      return -1;\n";
3061                pr "    }\n"
3062          ) checks
3063        in
3064        List.iter (generate_test_command_call test_name) seq;
3065        generate_test_command_call ~test test_name last
3066    | TestLastFail seq ->
3067        pr "  /* TestLastFail for %s (%d) */\n" name i;
3068        let seq, last = get_seq_last seq in
3069        List.iter (generate_test_command_call test_name) seq;
3070        generate_test_command_call test_name ~expect_error:true last
3071   );
3072
3073   pr "  return 0;\n";
3074   pr "}\n";
3075   pr "\n";
3076   test_name
3077
3078 (* Generate the code to run a command, leaving the result in 'r'.
3079  * If you expect to get an error then you should set expect_error:true.
3080  *)
3081 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
3082   match cmd with
3083   | [] -> assert false
3084   | name :: args ->
3085       (* Look up the command to find out what args/ret it has. *)
3086       let style =
3087         try
3088           let _, style, _, _, _, _, _ =
3089             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
3090           style
3091         with Not_found ->
3092           failwithf "%s: in test, command %s was not found" test_name name in
3093
3094       if List.length (snd style) <> List.length args then
3095         failwithf "%s: in test, wrong number of args given to %s"
3096           test_name name;
3097
3098       pr "  {\n";
3099
3100       List.iter (
3101         function
3102         | String _, _
3103         | OptString _, _
3104         | Int _, _
3105         | Bool _, _ -> ()
3106         | FileIn _, _ | FileOut _, _ -> ()
3107         | StringList n, arg ->
3108             pr "    char *%s[] = {\n" n;
3109             let strs = string_split " " arg in
3110             List.iter (
3111               fun str -> pr "      \"%s\",\n" (c_quote str)
3112             ) strs;
3113             pr "      NULL\n";
3114             pr "    };\n";
3115       ) (List.combine (snd style) args);
3116
3117       let error_code =
3118         match fst style with
3119         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
3120         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
3121         | RConstString _ -> pr "    const char *r;\n"; "NULL"
3122         | RString _ -> pr "    char *r;\n"; "NULL"
3123         | RStringList _ | RHashtable _ ->
3124             pr "    char **r;\n";
3125             pr "    int i;\n";
3126             "NULL"
3127         | RIntBool _ ->
3128             pr "    struct guestfs_int_bool *r;\n"; "NULL"
3129         | RPVList _ ->
3130             pr "    struct guestfs_lvm_pv_list *r;\n"; "NULL"
3131         | RVGList _ ->
3132             pr "    struct guestfs_lvm_vg_list *r;\n"; "NULL"
3133         | RLVList _ ->
3134             pr "    struct guestfs_lvm_lv_list *r;\n"; "NULL"
3135         | RStat _ ->
3136             pr "    struct guestfs_stat *r;\n"; "NULL"
3137         | RStatVFS _ ->
3138             pr "    struct guestfs_statvfs *r;\n"; "NULL" in
3139
3140       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
3141       pr "    r = guestfs_%s (g" name;
3142
3143       (* Generate the parameters. *)
3144       List.iter (
3145         function
3146         | String _, arg
3147         | FileIn _, arg | FileOut _, arg ->
3148             pr ", \"%s\"" (c_quote arg)
3149         | OptString _, arg ->
3150             if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
3151         | StringList n, _ ->
3152             pr ", %s" n
3153         | Int _, arg ->
3154             let i =
3155               try int_of_string arg
3156               with Failure "int_of_string" ->
3157                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
3158             pr ", %d" i
3159         | Bool _, arg ->
3160             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
3161       ) (List.combine (snd style) args);
3162
3163       pr ");\n";
3164       if not expect_error then
3165         pr "    if (r == %s)\n" error_code
3166       else
3167         pr "    if (r != %s)\n" error_code;
3168       pr "      return -1;\n";
3169
3170       (* Insert the test code. *)
3171       (match test with
3172        | None -> ()
3173        | Some f -> f ()
3174       );
3175
3176       (match fst style with
3177        | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
3178        | RString _ -> pr "    free (r);\n"
3179        | RStringList _ | RHashtable _ ->
3180            pr "    for (i = 0; r[i] != NULL; ++i)\n";
3181            pr "      free (r[i]);\n";
3182            pr "    free (r);\n"
3183        | RIntBool _ ->
3184            pr "    guestfs_free_int_bool (r);\n"
3185        | RPVList _ ->
3186            pr "    guestfs_free_lvm_pv_list (r);\n"
3187        | RVGList _ ->
3188            pr "    guestfs_free_lvm_vg_list (r);\n"
3189        | RLVList _ ->
3190            pr "    guestfs_free_lvm_lv_list (r);\n"
3191        | RStat _ | RStatVFS _ ->
3192            pr "    free (r);\n"
3193       );
3194
3195       pr "  }\n"
3196
3197 and c_quote str =
3198   let str = replace_str str "\r" "\\r" in
3199   let str = replace_str str "\n" "\\n" in
3200   let str = replace_str str "\t" "\\t" in
3201   str
3202
3203 (* Generate a lot of different functions for guestfish. *)
3204 and generate_fish_cmds () =
3205   generate_header CStyle GPLv2;
3206
3207   let all_functions =
3208     List.filter (
3209       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3210     ) all_functions in
3211   let all_functions_sorted =
3212     List.filter (
3213       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3214     ) all_functions_sorted in
3215
3216   pr "#include <stdio.h>\n";
3217   pr "#include <stdlib.h>\n";
3218   pr "#include <string.h>\n";
3219   pr "#include <inttypes.h>\n";
3220   pr "\n";
3221   pr "#include <guestfs.h>\n";
3222   pr "#include \"fish.h\"\n";
3223   pr "\n";
3224
3225   (* list_commands function, which implements guestfish -h *)
3226   pr "void list_commands (void)\n";
3227   pr "{\n";
3228   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
3229   pr "  list_builtin_commands ();\n";
3230   List.iter (
3231     fun (name, _, _, flags, _, shortdesc, _) ->
3232       let name = replace_char name '_' '-' in
3233       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
3234         name shortdesc
3235   ) all_functions_sorted;
3236   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
3237   pr "}\n";
3238   pr "\n";
3239
3240   (* display_command function, which implements guestfish -h cmd *)
3241   pr "void display_command (const char *cmd)\n";
3242   pr "{\n";
3243   List.iter (
3244     fun (name, style, _, flags, _, shortdesc, longdesc) ->
3245       let name2 = replace_char name '_' '-' in
3246       let alias =
3247         try find_map (function FishAlias n -> Some n | _ -> None) flags
3248         with Not_found -> name in
3249       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3250       let synopsis =
3251         match snd style with
3252         | [] -> name2
3253         | args ->
3254             sprintf "%s <%s>"
3255               name2 (String.concat "> <" (List.map name_of_argt args)) in
3256
3257       let warnings =
3258         if List.mem ProtocolLimitWarning flags then
3259           ("\n\n" ^ protocol_limit_warning)
3260         else "" in
3261
3262       (* For DangerWillRobinson commands, we should probably have
3263        * guestfish prompt before allowing you to use them (especially
3264        * in interactive mode). XXX
3265        *)
3266       let warnings =
3267         warnings ^
3268           if List.mem DangerWillRobinson flags then
3269             ("\n\n" ^ danger_will_robinson)
3270           else "" in
3271
3272       let describe_alias =
3273         if name <> alias then
3274           sprintf "\n\nYou can use '%s' as an alias for this command." alias
3275         else "" in
3276
3277       pr "  if (";
3278       pr "strcasecmp (cmd, \"%s\") == 0" name;
3279       if name <> name2 then
3280         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3281       if name <> alias then
3282         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3283       pr ")\n";
3284       pr "    pod2text (\"%s - %s\", %S);\n"
3285         name2 shortdesc
3286         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
3287       pr "  else\n"
3288   ) all_functions;
3289   pr "    display_builtin_command (cmd);\n";
3290   pr "}\n";
3291   pr "\n";
3292
3293   (* print_{pv,vg,lv}_list functions *)
3294   List.iter (
3295     function
3296     | typ, cols ->
3297         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
3298         pr "{\n";
3299         pr "  int i;\n";
3300         pr "\n";
3301         List.iter (
3302           function
3303           | name, `String ->
3304               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
3305           | name, `UUID ->
3306               pr "  printf (\"%s: \");\n" name;
3307               pr "  for (i = 0; i < 32; ++i)\n";
3308               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
3309               pr "  printf (\"\\n\");\n"
3310           | name, `Bytes ->
3311               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
3312           | name, `Int ->
3313               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3314           | name, `OptPercent ->
3315               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
3316                 typ name name typ name;
3317               pr "  else printf (\"%s: \\n\");\n" name
3318         ) cols;
3319         pr "}\n";
3320         pr "\n";
3321         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
3322           typ typ typ;
3323         pr "{\n";
3324         pr "  int i;\n";
3325         pr "\n";
3326         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
3327         pr "    print_%s (&%ss->val[i]);\n" typ typ;
3328         pr "}\n";
3329         pr "\n";
3330   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3331
3332   (* print_{stat,statvfs} functions *)
3333   List.iter (
3334     function
3335     | typ, cols ->
3336         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
3337         pr "{\n";
3338         List.iter (
3339           function
3340           | name, `Int ->
3341               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3342         ) cols;
3343         pr "}\n";
3344         pr "\n";
3345   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3346
3347   (* run_<action> actions *)
3348   List.iter (
3349     fun (name, style, _, flags, _, _, _) ->
3350       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
3351       pr "{\n";
3352       (match fst style with
3353        | RErr
3354        | RInt _
3355        | RBool _ -> pr "  int r;\n"
3356        | RInt64 _ -> pr "  int64_t r;\n"
3357        | RConstString _ -> pr "  const char *r;\n"
3358        | RString _ -> pr "  char *r;\n"
3359        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
3360        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
3361        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
3362        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
3363        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
3364        | RStat _ -> pr "  struct guestfs_stat *r;\n"
3365        | RStatVFS _ -> pr "  struct guestfs_statvfs *r;\n"
3366       );
3367       List.iter (
3368         function
3369         | String n
3370         | OptString n
3371         | FileIn n
3372         | FileOut n -> pr "  const char *%s;\n" n
3373         | StringList n -> pr "  char **%s;\n" n
3374         | Bool n -> pr "  int %s;\n" n
3375         | Int n -> pr "  int %s;\n" n
3376       ) (snd style);
3377
3378       (* Check and convert parameters. *)
3379       let argc_expected = List.length (snd style) in
3380       pr "  if (argc != %d) {\n" argc_expected;
3381       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
3382         argc_expected;
3383       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
3384       pr "    return -1;\n";
3385       pr "  }\n";
3386       iteri (
3387         fun i ->
3388           function
3389           | String name -> pr "  %s = argv[%d];\n" name i
3390           | OptString name ->
3391               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
3392                 name i i
3393           | FileIn name ->
3394               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
3395                 name i i
3396           | FileOut name ->
3397               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
3398                 name i i
3399           | StringList name ->
3400               pr "  %s = parse_string_list (argv[%d]);\n" name i
3401           | Bool name ->
3402               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
3403           | Int name ->
3404               pr "  %s = atoi (argv[%d]);\n" name i
3405       ) (snd style);
3406
3407       (* Call C API function. *)
3408       let fn =
3409         try find_map (function FishAction n -> Some n | _ -> None) flags
3410         with Not_found -> sprintf "guestfs_%s" name in
3411       pr "  r = %s " fn;
3412       generate_call_args ~handle:"g" (snd style);
3413       pr ";\n";
3414
3415       (* Check return value for errors and display command results. *)
3416       (match fst style with
3417        | RErr -> pr "  return r;\n"
3418        | RInt _ ->
3419            pr "  if (r == -1) return -1;\n";
3420            pr "  printf (\"%%d\\n\", r);\n";
3421            pr "  return 0;\n"
3422        | RInt64 _ ->
3423            pr "  if (r == -1) return -1;\n";
3424            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
3425            pr "  return 0;\n"
3426        | RBool _ ->
3427            pr "  if (r == -1) return -1;\n";
3428            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
3429            pr "  return 0;\n"
3430        | RConstString _ ->
3431            pr "  if (r == NULL) return -1;\n";
3432            pr "  printf (\"%%s\\n\", r);\n";
3433            pr "  return 0;\n"
3434        | RString _ ->
3435            pr "  if (r == NULL) return -1;\n";
3436            pr "  printf (\"%%s\\n\", r);\n";
3437            pr "  free (r);\n";
3438            pr "  return 0;\n"
3439        | RStringList _ ->
3440            pr "  if (r == NULL) return -1;\n";
3441            pr "  print_strings (r);\n";
3442            pr "  free_strings (r);\n";
3443            pr "  return 0;\n"
3444        | RIntBool _ ->
3445            pr "  if (r == NULL) return -1;\n";
3446            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
3447            pr "    r->b ? \"true\" : \"false\");\n";
3448            pr "  guestfs_free_int_bool (r);\n";
3449            pr "  return 0;\n"
3450        | RPVList _ ->
3451            pr "  if (r == NULL) return -1;\n";
3452            pr "  print_pv_list (r);\n";
3453            pr "  guestfs_free_lvm_pv_list (r);\n";
3454            pr "  return 0;\n"
3455        | RVGList _ ->
3456            pr "  if (r == NULL) return -1;\n";
3457            pr "  print_vg_list (r);\n";
3458            pr "  guestfs_free_lvm_vg_list (r);\n";
3459            pr "  return 0;\n"
3460        | RLVList _ ->
3461            pr "  if (r == NULL) return -1;\n";
3462            pr "  print_lv_list (r);\n";
3463            pr "  guestfs_free_lvm_lv_list (r);\n";
3464            pr "  return 0;\n"
3465        | RStat _ ->
3466            pr "  if (r == NULL) return -1;\n";
3467            pr "  print_stat (r);\n";
3468            pr "  free (r);\n";
3469            pr "  return 0;\n"
3470        | RStatVFS _ ->
3471            pr "  if (r == NULL) return -1;\n";
3472            pr "  print_statvfs (r);\n";
3473            pr "  free (r);\n";
3474            pr "  return 0;\n"
3475        | RHashtable _ ->
3476            pr "  if (r == NULL) return -1;\n";
3477            pr "  print_table (r);\n";
3478            pr "  free_strings (r);\n";
3479            pr "  return 0;\n"
3480       );
3481       pr "}\n";
3482       pr "\n"
3483   ) all_functions;
3484
3485   (* run_action function *)
3486   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3487   pr "{\n";
3488   List.iter (
3489     fun (name, _, _, flags, _, _, _) ->
3490       let name2 = replace_char name '_' '-' in
3491       let alias =
3492         try find_map (function FishAlias n -> Some n | _ -> None) flags
3493         with Not_found -> name in
3494       pr "  if (";
3495       pr "strcasecmp (cmd, \"%s\") == 0" name;
3496       if name <> name2 then
3497         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3498       if name <> alias then
3499         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3500       pr ")\n";
3501       pr "    return run_%s (cmd, argc, argv);\n" name;
3502       pr "  else\n";
3503   ) all_functions;
3504   pr "    {\n";
3505   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3506   pr "      return -1;\n";
3507   pr "    }\n";
3508   pr "  return 0;\n";
3509   pr "}\n";
3510   pr "\n"
3511
3512 (* Readline completion for guestfish. *)
3513 and generate_fish_completion () =
3514   generate_header CStyle GPLv2;
3515
3516   let all_functions =
3517     List.filter (
3518       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3519     ) all_functions in
3520
3521   pr "\
3522 #include <config.h>
3523
3524 #include <stdio.h>
3525 #include <stdlib.h>
3526 #include <string.h>
3527
3528 #ifdef HAVE_LIBREADLINE
3529 #include <readline/readline.h>
3530 #endif
3531
3532 #include \"fish.h\"
3533
3534 #ifdef HAVE_LIBREADLINE
3535
3536 static const char *commands[] = {
3537 ";
3538
3539   (* Get the commands and sort them, including the aliases. *)
3540   let commands =
3541     List.map (
3542       fun (name, _, _, flags, _, _, _) ->
3543         let name2 = replace_char name '_' '-' in
3544         let alias =
3545           try find_map (function FishAlias n -> Some n | _ -> None) flags
3546           with Not_found -> name in
3547
3548         if name <> alias then [name2; alias] else [name2]
3549     ) all_functions in
3550   let commands = List.flatten commands in
3551   let commands = List.sort compare commands in
3552
3553   List.iter (pr "  \"%s\",\n") commands;
3554
3555   pr "  NULL
3556 };
3557
3558 static char *
3559 generator (const char *text, int state)
3560 {
3561   static int index, len;
3562   const char *name;
3563
3564   if (!state) {
3565     index = 0;
3566     len = strlen (text);
3567   }
3568
3569   while ((name = commands[index]) != NULL) {
3570     index++;
3571     if (strncasecmp (name, text, len) == 0)
3572       return strdup (name);
3573   }
3574
3575   return NULL;
3576 }
3577
3578 #endif /* HAVE_LIBREADLINE */
3579
3580 char **do_completion (const char *text, int start, int end)
3581 {
3582   char **matches = NULL;
3583
3584 #ifdef HAVE_LIBREADLINE
3585   if (start == 0)
3586     matches = rl_completion_matches (text, generator);
3587 #endif
3588
3589   return matches;
3590 }
3591 ";
3592
3593 (* Generate the POD documentation for guestfish. *)
3594 and generate_fish_actions_pod () =
3595   let all_functions_sorted =
3596     List.filter (
3597       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3598     ) all_functions_sorted in
3599
3600   List.iter (
3601     fun (name, style, _, flags, _, _, longdesc) ->
3602       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3603       let name = replace_char name '_' '-' in
3604       let alias =
3605         try find_map (function FishAlias n -> Some n | _ -> None) flags
3606         with Not_found -> name in
3607
3608       pr "=head2 %s" name;
3609       if name <> alias then
3610         pr " | %s" alias;
3611       pr "\n";
3612       pr "\n";
3613       pr " %s" name;
3614       List.iter (
3615         function
3616         | String n -> pr " %s" n
3617         | OptString n -> pr " %s" n
3618         | StringList n -> pr " %s,..." n
3619         | Bool _ -> pr " true|false"
3620         | Int n -> pr " %s" n
3621         | FileIn n | FileOut n -> pr " (%s|-)" n
3622       ) (snd style);
3623       pr "\n";
3624       pr "\n";
3625       pr "%s\n\n" longdesc;
3626
3627       if List.exists (function FileIn _ | FileOut _ -> true
3628                       | _ -> false) (snd style) then
3629         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
3630
3631       if List.mem ProtocolLimitWarning flags then
3632         pr "%s\n\n" protocol_limit_warning;
3633
3634       if List.mem DangerWillRobinson flags then
3635         pr "%s\n\n" danger_will_robinson
3636   ) all_functions_sorted
3637
3638 (* Generate a C function prototype. *)
3639 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3640     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3641     ?(prefix = "")
3642     ?handle name style =
3643   if extern then pr "extern ";
3644   if static then pr "static ";
3645   (match fst style with
3646    | RErr -> pr "int "
3647    | RInt _ -> pr "int "
3648    | RInt64 _ -> pr "int64_t "
3649    | RBool _ -> pr "int "
3650    | RConstString _ -> pr "const char *"
3651    | RString _ -> pr "char *"
3652    | RStringList _ | RHashtable _ -> pr "char **"
3653    | RIntBool _ ->
3654        if not in_daemon then pr "struct guestfs_int_bool *"
3655        else pr "guestfs_%s_ret *" name
3656    | RPVList _ ->
3657        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3658        else pr "guestfs_lvm_int_pv_list *"
3659    | RVGList _ ->
3660        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3661        else pr "guestfs_lvm_int_vg_list *"
3662    | RLVList _ ->
3663        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3664        else pr "guestfs_lvm_int_lv_list *"
3665    | RStat _ ->
3666        if not in_daemon then pr "struct guestfs_stat *"
3667        else pr "guestfs_int_stat *"
3668    | RStatVFS _ ->
3669        if not in_daemon then pr "struct guestfs_statvfs *"
3670        else pr "guestfs_int_statvfs *"
3671   );
3672   pr "%s%s (" prefix name;
3673   if handle = None && List.length (snd style) = 0 then
3674     pr "void"
3675   else (
3676     let comma = ref false in
3677     (match handle with
3678      | None -> ()
3679      | Some handle -> pr "guestfs_h *%s" handle; comma := true
3680     );
3681     let next () =
3682       if !comma then (
3683         if single_line then pr ", " else pr ",\n\t\t"
3684       );
3685       comma := true
3686     in
3687     List.iter (
3688       function
3689       | String n
3690       | OptString n -> next (); pr "const char *%s" n
3691       | StringList n -> next (); pr "char * const* const %s" n
3692       | Bool n -> next (); pr "int %s" n
3693       | Int n -> next (); pr "int %s" n
3694       | FileIn n
3695       | FileOut n ->
3696           if not in_daemon then (next (); pr "const char *%s" n)
3697     ) (snd style);
3698   );
3699   pr ")";
3700   if semicolon then pr ";";
3701   if newline then pr "\n"
3702
3703 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3704 and generate_call_args ?handle args =
3705   pr "(";
3706   let comma = ref false in
3707   (match handle with
3708    | None -> ()
3709    | Some handle -> pr "%s" handle; comma := true
3710   );
3711   List.iter (
3712     fun arg ->
3713       if !comma then pr ", ";
3714       comma := true;
3715       pr "%s" (name_of_argt arg)
3716   ) args;
3717   pr ")"
3718
3719 (* Generate the OCaml bindings interface. *)
3720 and generate_ocaml_mli () =
3721   generate_header OCamlStyle LGPLv2;
3722
3723   pr "\
3724 (** For API documentation you should refer to the C API
3725     in the guestfs(3) manual page.  The OCaml API uses almost
3726     exactly the same calls. *)
3727
3728 type t
3729 (** A [guestfs_h] handle. *)
3730
3731 exception Error of string
3732 (** This exception is raised when there is an error. *)
3733
3734 val create : unit -> t
3735
3736 val close : t -> unit
3737 (** Handles are closed by the garbage collector when they become
3738     unreferenced, but callers can also call this in order to
3739     provide predictable cleanup. *)
3740
3741 ";
3742   generate_ocaml_lvm_structure_decls ();
3743
3744   generate_ocaml_stat_structure_decls ();
3745
3746   (* The actions. *)
3747   List.iter (
3748     fun (name, style, _, _, _, shortdesc, _) ->
3749       generate_ocaml_prototype name style;
3750       pr "(** %s *)\n" shortdesc;
3751       pr "\n"
3752   ) all_functions
3753
3754 (* Generate the OCaml bindings implementation. *)
3755 and generate_ocaml_ml () =
3756   generate_header OCamlStyle LGPLv2;
3757
3758   pr "\
3759 type t
3760 exception Error of string
3761 external create : unit -> t = \"ocaml_guestfs_create\"
3762 external close : t -> unit = \"ocaml_guestfs_close\"
3763
3764 let () =
3765   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3766
3767 ";
3768
3769   generate_ocaml_lvm_structure_decls ();
3770
3771   generate_ocaml_stat_structure_decls ();
3772
3773   (* The actions. *)
3774   List.iter (
3775     fun (name, style, _, _, _, shortdesc, _) ->
3776       generate_ocaml_prototype ~is_external:true name style;
3777   ) all_functions
3778
3779 (* Generate the OCaml bindings C implementation. *)
3780 and generate_ocaml_c () =
3781   generate_header CStyle LGPLv2;
3782
3783   pr "\
3784 #include <stdio.h>
3785 #include <stdlib.h>
3786 #include <string.h>
3787
3788 #include <caml/config.h>
3789 #include <caml/alloc.h>
3790 #include <caml/callback.h>
3791 #include <caml/fail.h>
3792 #include <caml/memory.h>
3793 #include <caml/mlvalues.h>
3794 #include <caml/signals.h>
3795
3796 #include <guestfs.h>
3797
3798 #include \"guestfs_c.h\"
3799
3800 /* Copy a hashtable of string pairs into an assoc-list.  We return
3801  * the list in reverse order, but hashtables aren't supposed to be
3802  * ordered anyway.
3803  */
3804 static CAMLprim value
3805 copy_table (char * const * argv)
3806 {
3807   CAMLparam0 ();
3808   CAMLlocal5 (rv, pairv, kv, vv, cons);
3809   int i;
3810
3811   rv = Val_int (0);
3812   for (i = 0; argv[i] != NULL; i += 2) {
3813     kv = caml_copy_string (argv[i]);
3814     vv = caml_copy_string (argv[i+1]);
3815     pairv = caml_alloc (2, 0);
3816     Store_field (pairv, 0, kv);
3817     Store_field (pairv, 1, vv);
3818     cons = caml_alloc (2, 0);
3819     Store_field (cons, 1, rv);
3820     rv = cons;
3821     Store_field (cons, 0, pairv);
3822   }
3823
3824   CAMLreturn (rv);
3825 }
3826
3827 ";
3828
3829   (* LVM struct copy functions. *)
3830   List.iter (
3831     fun (typ, cols) ->
3832       let has_optpercent_col =
3833         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
3834
3835       pr "static CAMLprim value\n";
3836       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
3837       pr "{\n";
3838       pr "  CAMLparam0 ();\n";
3839       if has_optpercent_col then
3840         pr "  CAMLlocal3 (rv, v, v2);\n"
3841       else
3842         pr "  CAMLlocal2 (rv, v);\n";
3843       pr "\n";
3844       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3845       iteri (
3846         fun i col ->
3847           (match col with
3848            | name, `String ->
3849                pr "  v = caml_copy_string (%s->%s);\n" typ name
3850            | name, `UUID ->
3851                pr "  v = caml_alloc_string (32);\n";
3852                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
3853            | name, `Bytes
3854            | name, `Int ->
3855                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3856            | name, `OptPercent ->
3857                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
3858                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
3859                pr "    v = caml_alloc (1, 0);\n";
3860                pr "    Store_field (v, 0, v2);\n";
3861                pr "  } else /* None */\n";
3862                pr "    v = Val_int (0);\n";
3863           );
3864           pr "  Store_field (rv, %d, v);\n" i
3865       ) cols;
3866       pr "  CAMLreturn (rv);\n";
3867       pr "}\n";
3868       pr "\n";
3869
3870       pr "static CAMLprim value\n";
3871       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
3872         typ typ typ;
3873       pr "{\n";
3874       pr "  CAMLparam0 ();\n";
3875       pr "  CAMLlocal2 (rv, v);\n";
3876       pr "  int i;\n";
3877       pr "\n";
3878       pr "  if (%ss->len == 0)\n" typ;
3879       pr "    CAMLreturn (Atom (0));\n";
3880       pr "  else {\n";
3881       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
3882       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
3883       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
3884       pr "      caml_modify (&Field (rv, i), v);\n";
3885       pr "    }\n";
3886       pr "    CAMLreturn (rv);\n";
3887       pr "  }\n";
3888       pr "}\n";
3889       pr "\n";
3890   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3891
3892   (* Stat copy functions. *)
3893   List.iter (
3894     fun (typ, cols) ->
3895       pr "static CAMLprim value\n";
3896       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
3897       pr "{\n";
3898       pr "  CAMLparam0 ();\n";
3899       pr "  CAMLlocal2 (rv, v);\n";
3900       pr "\n";
3901       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3902       iteri (
3903         fun i col ->
3904           (match col with
3905            | name, `Int ->
3906                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3907           );
3908           pr "  Store_field (rv, %d, v);\n" i
3909       ) cols;
3910       pr "  CAMLreturn (rv);\n";
3911       pr "}\n";
3912       pr "\n";
3913   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3914
3915   (* The wrappers. *)
3916   List.iter (
3917     fun (name, style, _, _, _, _, _) ->
3918       let params =
3919         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
3920
3921       pr "CAMLprim value\n";
3922       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
3923       List.iter (pr ", value %s") (List.tl params);
3924       pr ")\n";
3925       pr "{\n";
3926
3927       (match params with
3928        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
3929            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
3930            pr "  CAMLxparam%d (%s);\n"
3931              (List.length rest) (String.concat ", " rest)
3932        | ps ->
3933            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
3934       );
3935       pr "  CAMLlocal1 (rv);\n";
3936       pr "\n";
3937
3938       pr "  guestfs_h *g = Guestfs_val (gv);\n";
3939       pr "  if (g == NULL)\n";
3940       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
3941       pr "\n";
3942
3943       List.iter (
3944         function
3945         | String n
3946         | FileIn n
3947         | FileOut n ->
3948             pr "  const char *%s = String_val (%sv);\n" n n
3949         | OptString n ->
3950             pr "  const char *%s =\n" n;
3951             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
3952               n n
3953         | StringList n ->
3954             pr "  char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
3955         | Bool n ->
3956             pr "  int %s = Bool_val (%sv);\n" n n
3957         | Int n ->
3958             pr "  int %s = Int_val (%sv);\n" n n
3959       ) (snd style);
3960       let error_code =
3961         match fst style with
3962         | RErr -> pr "  int r;\n"; "-1"
3963         | RInt _ -> pr "  int r;\n"; "-1"
3964         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
3965         | RBool _ -> pr "  int r;\n"; "-1"
3966         | RConstString _ -> pr "  const char *r;\n"; "NULL"
3967         | RString _ -> pr "  char *r;\n"; "NULL"
3968         | RStringList _ ->
3969             pr "  int i;\n";
3970             pr "  char **r;\n";
3971             "NULL"
3972         | RIntBool _ ->
3973             pr "  struct guestfs_int_bool *r;\n"; "NULL"
3974         | RPVList _ ->
3975             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
3976         | RVGList _ ->
3977             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
3978         | RLVList _ ->
3979             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
3980         | RStat _ ->
3981             pr "  struct guestfs_stat *r;\n"; "NULL"
3982         | RStatVFS _ ->
3983             pr "  struct guestfs_statvfs *r;\n"; "NULL"
3984         | RHashtable _ ->
3985             pr "  int i;\n";
3986             pr "  char **r;\n";
3987             "NULL" in
3988       pr "\n";
3989
3990       pr "  caml_enter_blocking_section ();\n";
3991       pr "  r = guestfs_%s " name;
3992       generate_call_args ~handle:"g" (snd style);
3993       pr ";\n";
3994       pr "  caml_leave_blocking_section ();\n";
3995
3996       List.iter (
3997         function
3998         | StringList n ->
3999             pr "  ocaml_guestfs_free_strings (%s);\n" n;
4000         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
4001       ) (snd style);
4002
4003       pr "  if (r == %s)\n" error_code;
4004       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
4005       pr "\n";
4006
4007       (match fst style with
4008        | RErr -> pr "  rv = Val_unit;\n"
4009        | RInt _ -> pr "  rv = Val_int (r);\n"
4010        | RInt64 _ ->
4011            pr "  rv = caml_copy_int64 (r);\n"
4012        | RBool _ -> pr "  rv = Val_bool (r);\n"
4013        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
4014        | RString _ ->
4015            pr "  rv = caml_copy_string (r);\n";
4016            pr "  free (r);\n"
4017        | RStringList _ ->
4018            pr "  rv = caml_copy_string_array ((const char **) r);\n";
4019            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4020            pr "  free (r);\n"
4021        | RIntBool _ ->
4022            pr "  rv = caml_alloc (2, 0);\n";
4023            pr "  Store_field (rv, 0, Val_int (r->i));\n";
4024            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
4025            pr "  guestfs_free_int_bool (r);\n";
4026        | RPVList _ ->
4027            pr "  rv = copy_lvm_pv_list (r);\n";
4028            pr "  guestfs_free_lvm_pv_list (r);\n";
4029        | RVGList _ ->
4030            pr "  rv = copy_lvm_vg_list (r);\n";
4031            pr "  guestfs_free_lvm_vg_list (r);\n";
4032        | RLVList _ ->
4033            pr "  rv = copy_lvm_lv_list (r);\n";
4034            pr "  guestfs_free_lvm_lv_list (r);\n";
4035        | RStat _ ->
4036            pr "  rv = copy_stat (r);\n";
4037            pr "  free (r);\n";
4038        | RStatVFS _ ->
4039            pr "  rv = copy_statvfs (r);\n";
4040            pr "  free (r);\n";
4041        | RHashtable _ ->
4042            pr "  rv = copy_table (r);\n";
4043            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4044            pr "  free (r);\n";
4045       );
4046
4047       pr "  CAMLreturn (rv);\n";
4048       pr "}\n";
4049       pr "\n";
4050
4051       if List.length params > 5 then (
4052         pr "CAMLprim value\n";
4053         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
4054         pr "{\n";
4055         pr "  return ocaml_guestfs_%s (argv[0]" name;
4056         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
4057         pr ");\n";
4058         pr "}\n";
4059         pr "\n"
4060       )
4061   ) all_functions
4062
4063 and generate_ocaml_lvm_structure_decls () =
4064   List.iter (
4065     fun (typ, cols) ->
4066       pr "type lvm_%s = {\n" typ;
4067       List.iter (
4068         function
4069         | name, `String -> pr "  %s : string;\n" name
4070         | name, `UUID -> pr "  %s : string;\n" name
4071         | name, `Bytes -> pr "  %s : int64;\n" name
4072         | name, `Int -> pr "  %s : int64;\n" name
4073         | name, `OptPercent -> pr "  %s : float option;\n" name
4074       ) cols;
4075       pr "}\n";
4076       pr "\n"
4077   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4078
4079 and generate_ocaml_stat_structure_decls () =
4080   List.iter (
4081     fun (typ, cols) ->
4082       pr "type %s = {\n" typ;
4083       List.iter (
4084         function
4085         | name, `Int -> pr "  %s : int64;\n" name
4086       ) cols;
4087       pr "}\n";
4088       pr "\n"
4089   ) ["stat", stat_cols; "statvfs", statvfs_cols]
4090
4091 and generate_ocaml_prototype ?(is_external = false) name style =
4092   if is_external then pr "external " else pr "val ";
4093   pr "%s : t -> " name;
4094   List.iter (
4095     function
4096     | String _ | FileIn _ | FileOut _ -> pr "string -> "
4097     | OptString _ -> pr "string option -> "
4098     | StringList _ -> pr "string array -> "
4099     | Bool _ -> pr "bool -> "
4100     | Int _ -> pr "int -> "
4101   ) (snd style);
4102   (match fst style with
4103    | RErr -> pr "unit" (* all errors are turned into exceptions *)
4104    | RInt _ -> pr "int"
4105    | RInt64 _ -> pr "int64"
4106    | RBool _ -> pr "bool"
4107    | RConstString _ -> pr "string"
4108    | RString _ -> pr "string"
4109    | RStringList _ -> pr "string array"
4110    | RIntBool _ -> pr "int * bool"
4111    | RPVList _ -> pr "lvm_pv array"
4112    | RVGList _ -> pr "lvm_vg array"
4113    | RLVList _ -> pr "lvm_lv array"
4114    | RStat _ -> pr "stat"
4115    | RStatVFS _ -> pr "statvfs"
4116    | RHashtable _ -> pr "(string * string) list"
4117   );
4118   if is_external then (
4119     pr " = ";
4120     if List.length (snd style) + 1 > 5 then
4121       pr "\"ocaml_guestfs_%s_byte\" " name;
4122     pr "\"ocaml_guestfs_%s\"" name
4123   );
4124   pr "\n"
4125
4126 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
4127 and generate_perl_xs () =
4128   generate_header CStyle LGPLv2;
4129
4130   pr "\
4131 #include \"EXTERN.h\"
4132 #include \"perl.h\"
4133 #include \"XSUB.h\"
4134
4135 #include <guestfs.h>
4136
4137 #ifndef PRId64
4138 #define PRId64 \"lld\"
4139 #endif
4140
4141 static SV *
4142 my_newSVll(long long val) {
4143 #ifdef USE_64_BIT_ALL
4144   return newSViv(val);
4145 #else
4146   char buf[100];
4147   int len;
4148   len = snprintf(buf, 100, \"%%\" PRId64, val);
4149   return newSVpv(buf, len);
4150 #endif
4151 }
4152
4153 #ifndef PRIu64
4154 #define PRIu64 \"llu\"
4155 #endif
4156
4157 static SV *
4158 my_newSVull(unsigned long long val) {
4159 #ifdef USE_64_BIT_ALL
4160   return newSVuv(val);
4161 #else
4162   char buf[100];
4163   int len;
4164   len = snprintf(buf, 100, \"%%\" PRIu64, val);
4165   return newSVpv(buf, len);
4166 #endif
4167 }
4168
4169 /* http://www.perlmonks.org/?node_id=680842 */
4170 static char **
4171 XS_unpack_charPtrPtr (SV *arg) {
4172   char **ret;
4173   AV *av;
4174   I32 i;
4175
4176   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
4177     croak (\"array reference expected\");
4178   }
4179
4180   av = (AV *)SvRV (arg);
4181   ret = (char **)malloc (av_len (av) + 1 + 1);
4182
4183   for (i = 0; i <= av_len (av); i++) {
4184     SV **elem = av_fetch (av, i, 0);
4185
4186     if (!elem || !*elem)
4187       croak (\"missing element in list\");
4188
4189     ret[i] = SvPV_nolen (*elem);
4190   }
4191
4192   ret[i] = NULL;
4193
4194   return ret;
4195 }
4196
4197 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
4198
4199 guestfs_h *
4200 _create ()
4201    CODE:
4202       RETVAL = guestfs_create ();
4203       if (!RETVAL)
4204         croak (\"could not create guestfs handle\");
4205       guestfs_set_error_handler (RETVAL, NULL, NULL);
4206  OUTPUT:
4207       RETVAL
4208
4209 void
4210 DESTROY (g)
4211       guestfs_h *g;
4212  PPCODE:
4213       guestfs_close (g);
4214
4215 ";
4216
4217   List.iter (
4218     fun (name, style, _, _, _, _, _) ->
4219       (match fst style with
4220        | RErr -> pr "void\n"
4221        | RInt _ -> pr "SV *\n"
4222        | RInt64 _ -> pr "SV *\n"
4223        | RBool _ -> pr "SV *\n"
4224        | RConstString _ -> pr "SV *\n"
4225        | RString _ -> pr "SV *\n"
4226        | RStringList _
4227        | RIntBool _
4228        | RPVList _ | RVGList _ | RLVList _
4229        | RStat _ | RStatVFS _
4230        | RHashtable _ ->
4231            pr "void\n" (* all lists returned implictly on the stack *)
4232       );
4233       (* Call and arguments. *)
4234       pr "%s " name;
4235       generate_call_args ~handle:"g" (snd style);
4236       pr "\n";
4237       pr "      guestfs_h *g;\n";
4238       List.iter (
4239         function
4240         | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
4241         | OptString n -> pr "      char *%s;\n" n
4242         | StringList n -> pr "      char **%s;\n" n
4243         | Bool n -> pr "      int %s;\n" n
4244         | Int n -> pr "      int %s;\n" n
4245       ) (snd style);
4246
4247       let do_cleanups () =
4248         List.iter (
4249           function
4250           | String _ | OptString _ | Bool _ | Int _
4251           | FileIn _ | FileOut _ -> ()
4252           | StringList n -> pr "      free (%s);\n" n
4253         ) (snd style)
4254       in
4255
4256       (* Code. *)
4257       (match fst style with
4258        | RErr ->
4259            pr "PREINIT:\n";
4260            pr "      int r;\n";
4261            pr " PPCODE:\n";
4262            pr "      r = guestfs_%s " name;
4263            generate_call_args ~handle:"g" (snd style);
4264            pr ";\n";
4265            do_cleanups ();
4266            pr "      if (r == -1)\n";
4267            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4268        | RInt n
4269        | RBool n ->
4270            pr "PREINIT:\n";
4271            pr "      int %s;\n" n;
4272            pr "   CODE:\n";
4273            pr "      %s = guestfs_%s " n name;
4274            generate_call_args ~handle:"g" (snd style);
4275            pr ";\n";
4276            do_cleanups ();
4277            pr "      if (%s == -1)\n" n;
4278            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4279            pr "      RETVAL = newSViv (%s);\n" n;
4280            pr " OUTPUT:\n";
4281            pr "      RETVAL\n"
4282        | RInt64 n ->
4283            pr "PREINIT:\n";
4284            pr "      int64_t %s;\n" n;
4285            pr "   CODE:\n";
4286            pr "      %s = guestfs_%s " n name;
4287            generate_call_args ~handle:"g" (snd style);
4288            pr ";\n";
4289            do_cleanups ();
4290            pr "      if (%s == -1)\n" n;
4291            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4292            pr "      RETVAL = my_newSVll (%s);\n" n;
4293            pr " OUTPUT:\n";
4294            pr "      RETVAL\n"
4295        | RConstString n ->
4296            pr "PREINIT:\n";
4297            pr "      const char *%s;\n" n;
4298            pr "   CODE:\n";
4299            pr "      %s = guestfs_%s " n name;
4300            generate_call_args ~handle:"g" (snd style);
4301            pr ";\n";
4302            do_cleanups ();
4303            pr "      if (%s == NULL)\n" n;
4304            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4305            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4306            pr " OUTPUT:\n";
4307            pr "      RETVAL\n"
4308        | RString n ->
4309            pr "PREINIT:\n";
4310            pr "      char *%s;\n" n;
4311            pr "   CODE:\n";
4312            pr "      %s = guestfs_%s " n name;
4313            generate_call_args ~handle:"g" (snd style);
4314            pr ";\n";
4315            do_cleanups ();
4316            pr "      if (%s == NULL)\n" n;
4317            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4318            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4319            pr "      free (%s);\n" n;
4320            pr " OUTPUT:\n";
4321            pr "      RETVAL\n"
4322        | RStringList n | RHashtable n ->
4323            pr "PREINIT:\n";
4324            pr "      char **%s;\n" n;
4325            pr "      int i, n;\n";
4326            pr " PPCODE:\n";
4327            pr "      %s = guestfs_%s " n name;
4328            generate_call_args ~handle:"g" (snd style);
4329            pr ";\n";
4330            do_cleanups ();
4331            pr "      if (%s == NULL)\n" n;
4332            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4333            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
4334            pr "      EXTEND (SP, n);\n";
4335            pr "      for (i = 0; i < n; ++i) {\n";
4336            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
4337            pr "        free (%s[i]);\n" n;
4338            pr "      }\n";
4339            pr "      free (%s);\n" n;
4340        | RIntBool _ ->
4341            pr "PREINIT:\n";
4342            pr "      struct guestfs_int_bool *r;\n";
4343            pr " PPCODE:\n";
4344            pr "      r = guestfs_%s " name;
4345            generate_call_args ~handle:"g" (snd style);
4346            pr ";\n";
4347            do_cleanups ();
4348            pr "      if (r == NULL)\n";
4349            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4350            pr "      EXTEND (SP, 2);\n";
4351            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
4352            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
4353            pr "      guestfs_free_int_bool (r);\n";
4354        | RPVList n ->
4355            generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
4356        | RVGList n ->
4357            generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
4358        | RLVList n ->
4359            generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
4360        | RStat n ->
4361            generate_perl_stat_code "stat" stat_cols name style n do_cleanups
4362        | RStatVFS n ->
4363            generate_perl_stat_code
4364              "statvfs" statvfs_cols name style n do_cleanups
4365       );
4366
4367       pr "\n"
4368   ) all_functions
4369
4370 and generate_perl_lvm_code typ cols name style n do_cleanups =
4371   pr "PREINIT:\n";
4372   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
4373   pr "      int i;\n";
4374   pr "      HV *hv;\n";
4375   pr " PPCODE:\n";
4376   pr "      %s = guestfs_%s " n name;
4377   generate_call_args ~handle:"g" (snd style);
4378   pr ";\n";
4379   do_cleanups ();
4380   pr "      if (%s == NULL)\n" n;
4381   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4382   pr "      EXTEND (SP, %s->len);\n" n;
4383   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
4384   pr "        hv = newHV ();\n";
4385   List.iter (
4386     function
4387     | name, `String ->
4388         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
4389           name (String.length name) n name
4390     | name, `UUID ->
4391         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
4392           name (String.length name) n name
4393     | name, `Bytes ->
4394         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
4395           name (String.length name) n name
4396     | name, `Int ->
4397         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
4398           name (String.length name) n name
4399     | name, `OptPercent ->
4400         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
4401           name (String.length name) n name
4402   ) cols;
4403   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
4404   pr "      }\n";
4405   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
4406
4407 and generate_perl_stat_code typ cols name style n do_cleanups =
4408   pr "PREINIT:\n";
4409   pr "      struct guestfs_%s *%s;\n" typ n;
4410   pr " PPCODE:\n";
4411   pr "      %s = guestfs_%s " n name;
4412   generate_call_args ~handle:"g" (snd style);
4413   pr ";\n";
4414   do_cleanups ();
4415   pr "      if (%s == NULL)\n" n;
4416   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4417   pr "      EXTEND (SP, %d);\n" (List.length cols);
4418   List.iter (
4419     function
4420     | name, `Int ->
4421         pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
4422   ) cols;
4423   pr "      free (%s);\n" n
4424
4425 (* Generate Sys/Guestfs.pm. *)
4426 and generate_perl_pm () =
4427   generate_header HashStyle LGPLv2;
4428
4429   pr "\
4430 =pod
4431
4432 =head1 NAME
4433
4434 Sys::Guestfs - Perl bindings for libguestfs
4435
4436 =head1 SYNOPSIS
4437
4438  use Sys::Guestfs;
4439  
4440  my $h = Sys::Guestfs->new ();
4441  $h->add_drive ('guest.img');
4442  $h->launch ();
4443  $h->wait_ready ();
4444  $h->mount ('/dev/sda1', '/');
4445  $h->touch ('/hello');
4446  $h->sync ();
4447
4448 =head1 DESCRIPTION
4449
4450 The C<Sys::Guestfs> module provides a Perl XS binding to the
4451 libguestfs API for examining and modifying virtual machine
4452 disk images.
4453
4454 Amongst the things this is good for: making batch configuration
4455 changes to guests, getting disk used/free statistics (see also:
4456 virt-df), migrating between virtualization systems (see also:
4457 virt-p2v), performing partial backups, performing partial guest
4458 clones, cloning guests and changing registry/UUID/hostname info, and
4459 much else besides.
4460
4461 Libguestfs uses Linux kernel and qemu code, and can access any type of
4462 guest filesystem that Linux and qemu can, including but not limited
4463 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
4464 schemes, qcow, qcow2, vmdk.
4465
4466 Libguestfs provides ways to enumerate guest storage (eg. partitions,
4467 LVs, what filesystem is in each LV, etc.).  It can also run commands
4468 in the context of the guest.  Also you can access filesystems over FTP.
4469
4470 =head1 ERRORS
4471
4472 All errors turn into calls to C<croak> (see L<Carp(3)>).
4473
4474 =head1 METHODS
4475
4476 =over 4
4477
4478 =cut
4479
4480 package Sys::Guestfs;
4481
4482 use strict;
4483 use warnings;
4484
4485 require XSLoader;
4486 XSLoader::load ('Sys::Guestfs');
4487
4488 =item $h = Sys::Guestfs->new ();
4489
4490 Create a new guestfs handle.
4491
4492 =cut
4493
4494 sub new {
4495   my $proto = shift;
4496   my $class = ref ($proto) || $proto;
4497
4498   my $self = Sys::Guestfs::_create ();
4499   bless $self, $class;
4500   return $self;
4501 }
4502
4503 ";
4504
4505   (* Actions.  We only need to print documentation for these as
4506    * they are pulled in from the XS code automatically.
4507    *)
4508   List.iter (
4509     fun (name, style, _, flags, _, _, longdesc) ->
4510       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
4511       pr "=item ";
4512       generate_perl_prototype name style;
4513       pr "\n\n";
4514       pr "%s\n\n" longdesc;
4515       if List.mem ProtocolLimitWarning flags then
4516         pr "%s\n\n" protocol_limit_warning;
4517       if List.mem DangerWillRobinson flags then
4518         pr "%s\n\n" danger_will_robinson
4519   ) all_functions_sorted;
4520
4521   (* End of file. *)
4522   pr "\
4523 =cut
4524
4525 1;
4526
4527 =back
4528
4529 =head1 COPYRIGHT
4530
4531 Copyright (C) 2009 Red Hat Inc.
4532
4533 =head1 LICENSE
4534
4535 Please see the file COPYING.LIB for the full license.
4536
4537 =head1 SEE ALSO
4538
4539 L<guestfs(3)>, L<guestfish(1)>.
4540
4541 =cut
4542 "
4543
4544 and generate_perl_prototype name style =
4545   (match fst style with
4546    | RErr -> ()
4547    | RBool n
4548    | RInt n
4549    | RInt64 n
4550    | RConstString n
4551    | RString n -> pr "$%s = " n
4552    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4553    | RStringList n
4554    | RPVList n
4555    | RVGList n
4556    | RLVList n -> pr "@%s = " n
4557    | RStat n
4558    | RStatVFS n
4559    | RHashtable n -> pr "%%%s = " n
4560   );
4561   pr "$h->%s (" name;
4562   let comma = ref false in
4563   List.iter (
4564     fun arg ->
4565       if !comma then pr ", ";
4566       comma := true;
4567       match arg with
4568       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
4569           pr "$%s" n
4570       | StringList n ->
4571           pr "\\@%s" n
4572   ) (snd style);
4573   pr ");"
4574
4575 (* Generate Python C module. *)
4576 and generate_python_c () =
4577   generate_header CStyle LGPLv2;
4578
4579   pr "\
4580 #include <stdio.h>
4581 #include <stdlib.h>
4582 #include <assert.h>
4583
4584 #include <Python.h>
4585
4586 #include \"guestfs.h\"
4587
4588 typedef struct {
4589   PyObject_HEAD
4590   guestfs_h *g;
4591 } Pyguestfs_Object;
4592
4593 static guestfs_h *
4594 get_handle (PyObject *obj)
4595 {
4596   assert (obj);
4597   assert (obj != Py_None);
4598   return ((Pyguestfs_Object *) obj)->g;
4599 }
4600
4601 static PyObject *
4602 put_handle (guestfs_h *g)
4603 {
4604   assert (g);
4605   return
4606     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4607 }
4608
4609 /* This list should be freed (but not the strings) after use. */
4610 static const char **
4611 get_string_list (PyObject *obj)
4612 {
4613   int i, len;
4614   const char **r;
4615
4616   assert (obj);
4617
4618   if (!PyList_Check (obj)) {
4619     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4620     return NULL;
4621   }
4622
4623   len = PyList_Size (obj);
4624   r = malloc (sizeof (char *) * (len+1));
4625   if (r == NULL) {
4626     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4627     return NULL;
4628   }
4629
4630   for (i = 0; i < len; ++i)
4631     r[i] = PyString_AsString (PyList_GetItem (obj, i));
4632   r[len] = NULL;
4633
4634   return r;
4635 }
4636
4637 static PyObject *
4638 put_string_list (char * const * const argv)
4639 {
4640   PyObject *list;
4641   int argc, i;
4642
4643   for (argc = 0; argv[argc] != NULL; ++argc)
4644     ;
4645
4646   list = PyList_New (argc);
4647   for (i = 0; i < argc; ++i)
4648     PyList_SetItem (list, i, PyString_FromString (argv[i]));
4649
4650   return list;
4651 }
4652
4653 static PyObject *
4654 put_table (char * const * const argv)
4655 {
4656   PyObject *list, *item;
4657   int argc, i;
4658
4659   for (argc = 0; argv[argc] != NULL; ++argc)
4660     ;
4661
4662   list = PyList_New (argc >> 1);
4663   for (i = 0; i < argc; i += 2) {
4664     item = PyTuple_New (2);
4665     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
4666     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
4667     PyList_SetItem (list, i >> 1, item);
4668   }
4669
4670   return list;
4671 }
4672
4673 static void
4674 free_strings (char **argv)
4675 {
4676   int argc;
4677
4678   for (argc = 0; argv[argc] != NULL; ++argc)
4679     free (argv[argc]);
4680   free (argv);
4681 }
4682
4683 static PyObject *
4684 py_guestfs_create (PyObject *self, PyObject *args)
4685 {
4686   guestfs_h *g;
4687
4688   g = guestfs_create ();
4689   if (g == NULL) {
4690     PyErr_SetString (PyExc_RuntimeError,
4691                      \"guestfs.create: failed to allocate handle\");
4692     return NULL;
4693   }
4694   guestfs_set_error_handler (g, NULL, NULL);
4695   return put_handle (g);
4696 }
4697
4698 static PyObject *
4699 py_guestfs_close (PyObject *self, PyObject *args)
4700 {
4701   PyObject *py_g;
4702   guestfs_h *g;
4703
4704   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4705     return NULL;
4706   g = get_handle (py_g);
4707
4708   guestfs_close (g);
4709
4710   Py_INCREF (Py_None);
4711   return Py_None;
4712 }
4713
4714 ";
4715
4716   (* LVM structures, turned into Python dictionaries. *)
4717   List.iter (
4718     fun (typ, cols) ->
4719       pr "static PyObject *\n";
4720       pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4721       pr "{\n";
4722       pr "  PyObject *dict;\n";
4723       pr "\n";
4724       pr "  dict = PyDict_New ();\n";
4725       List.iter (
4726         function
4727         | name, `String ->
4728             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4729             pr "                        PyString_FromString (%s->%s));\n"
4730               typ name
4731         | name, `UUID ->
4732             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4733             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
4734               typ name
4735         | name, `Bytes ->
4736             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4737             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
4738               typ name
4739         | name, `Int ->
4740             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4741             pr "                        PyLong_FromLongLong (%s->%s));\n"
4742               typ name
4743         | name, `OptPercent ->
4744             pr "  if (%s->%s >= 0)\n" typ name;
4745             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
4746             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
4747               typ name;
4748             pr "  else {\n";
4749             pr "    Py_INCREF (Py_None);\n";
4750             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
4751             pr "  }\n"
4752       ) cols;
4753       pr "  return dict;\n";
4754       pr "};\n";
4755       pr "\n";
4756
4757       pr "static PyObject *\n";
4758       pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
4759       pr "{\n";
4760       pr "  PyObject *list;\n";
4761       pr "  int i;\n";
4762       pr "\n";
4763       pr "  list = PyList_New (%ss->len);\n" typ;
4764       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
4765       pr "    PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
4766       pr "  return list;\n";
4767       pr "};\n";
4768       pr "\n"
4769   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4770
4771   (* Stat structures, turned into Python dictionaries. *)
4772   List.iter (
4773     fun (typ, cols) ->
4774       pr "static PyObject *\n";
4775       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
4776       pr "{\n";
4777       pr "  PyObject *dict;\n";
4778       pr "\n";
4779       pr "  dict = PyDict_New ();\n";
4780       List.iter (
4781         function
4782         | name, `Int ->
4783             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4784             pr "                        PyLong_FromLongLong (%s->%s));\n"
4785               typ name
4786       ) cols;
4787       pr "  return dict;\n";
4788       pr "};\n";
4789       pr "\n";
4790   ) ["stat", stat_cols; "statvfs", statvfs_cols];
4791
4792   (* Python wrapper functions. *)
4793   List.iter (
4794     fun (name, style, _, _, _, _, _) ->
4795       pr "static PyObject *\n";
4796       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
4797       pr "{\n";
4798
4799       pr "  PyObject *py_g;\n";
4800       pr "  guestfs_h *g;\n";
4801       pr "  PyObject *py_r;\n";
4802
4803       let error_code =
4804         match fst style with
4805         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
4806         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4807         | RConstString _ -> pr "  const char *r;\n"; "NULL"
4808         | RString _ -> pr "  char *r;\n"; "NULL"
4809         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
4810         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
4811         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
4812         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
4813         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
4814         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
4815         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
4816
4817       List.iter (
4818         function
4819         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
4820         | OptString n -> pr "  const char *%s;\n" n
4821         | StringList n ->
4822             pr "  PyObject *py_%s;\n" n;
4823             pr "  const char **%s;\n" n
4824         | Bool n -> pr "  int %s;\n" n
4825         | Int n -> pr "  int %s;\n" n
4826       ) (snd style);
4827
4828       pr "\n";
4829
4830       (* Convert the parameters. *)
4831       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
4832       List.iter (
4833         function
4834         | String _ | FileIn _ | FileOut _ -> pr "s"
4835         | OptString _ -> pr "z"
4836         | StringList _ -> pr "O"
4837         | Bool _ -> pr "i" (* XXX Python has booleans? *)
4838         | Int _ -> pr "i"
4839       ) (snd style);
4840       pr ":guestfs_%s\",\n" name;
4841       pr "                         &py_g";
4842       List.iter (
4843         function
4844         | String n | FileIn n | FileOut n -> pr ", &%s" n
4845         | OptString n -> pr ", &%s" n
4846         | StringList n -> pr ", &py_%s" n
4847         | Bool n -> pr ", &%s" n
4848         | Int n -> pr ", &%s" n
4849       ) (snd style);
4850
4851       pr "))\n";
4852       pr "    return NULL;\n";
4853
4854       pr "  g = get_handle (py_g);\n";
4855       List.iter (
4856         function
4857         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
4858         | StringList n ->
4859             pr "  %s = get_string_list (py_%s);\n" n n;
4860             pr "  if (!%s) return NULL;\n" n
4861       ) (snd style);
4862
4863       pr "\n";
4864
4865       pr "  r = guestfs_%s " name;
4866       generate_call_args ~handle:"g" (snd style);
4867       pr ";\n";
4868
4869       List.iter (
4870         function
4871         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
4872         | StringList n ->
4873             pr "  free (%s);\n" n
4874       ) (snd style);
4875
4876       pr "  if (r == %s) {\n" error_code;
4877       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
4878       pr "    return NULL;\n";
4879       pr "  }\n";
4880       pr "\n";
4881
4882       (match fst style with
4883        | RErr ->
4884            pr "  Py_INCREF (Py_None);\n";
4885            pr "  py_r = Py_None;\n"
4886        | RInt _
4887        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
4888        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
4889        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
4890        | RString _ ->
4891            pr "  py_r = PyString_FromString (r);\n";
4892            pr "  free (r);\n"
4893        | RStringList _ ->
4894            pr "  py_r = put_string_list (r);\n";
4895            pr "  free_strings (r);\n"
4896        | RIntBool _ ->
4897            pr "  py_r = PyTuple_New (2);\n";
4898            pr "  PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
4899            pr "  PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
4900            pr "  guestfs_free_int_bool (r);\n"
4901        | RPVList n ->
4902            pr "  py_r = put_lvm_pv_list (r);\n";
4903            pr "  guestfs_free_lvm_pv_list (r);\n"
4904        | RVGList n ->
4905            pr "  py_r = put_lvm_vg_list (r);\n";
4906            pr "  guestfs_free_lvm_vg_list (r);\n"
4907        | RLVList n ->
4908            pr "  py_r = put_lvm_lv_list (r);\n";
4909            pr "  guestfs_free_lvm_lv_list (r);\n"
4910        | RStat n ->
4911            pr "  py_r = put_stat (r);\n";
4912            pr "  free (r);\n"
4913        | RStatVFS n ->
4914            pr "  py_r = put_statvfs (r);\n";
4915            pr "  free (r);\n"
4916        | RHashtable n ->
4917            pr "  py_r = put_table (r);\n";
4918            pr "  free_strings (r);\n"
4919       );
4920
4921       pr "  return py_r;\n";
4922       pr "}\n";
4923       pr "\n"
4924   ) all_functions;
4925
4926   (* Table of functions. *)
4927   pr "static PyMethodDef methods[] = {\n";
4928   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
4929   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
4930   List.iter (
4931     fun (name, _, _, _, _, _, _) ->
4932       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
4933         name name
4934   ) all_functions;
4935   pr "  { NULL, NULL, 0, NULL }\n";
4936   pr "};\n";
4937   pr "\n";
4938
4939   (* Init function. *)
4940   pr "\
4941 void
4942 initlibguestfsmod (void)
4943 {
4944   static int initialized = 0;
4945
4946   if (initialized) return;
4947   Py_InitModule ((char *) \"libguestfsmod\", methods);
4948   initialized = 1;
4949 }
4950 "
4951
4952 (* Generate Python module. *)
4953 and generate_python_py () =
4954   generate_header HashStyle LGPLv2;
4955
4956   pr "\
4957 u\"\"\"Python bindings for libguestfs
4958
4959 import guestfs
4960 g = guestfs.GuestFS ()
4961 g.add_drive (\"guest.img\")
4962 g.launch ()
4963 g.wait_ready ()
4964 parts = g.list_partitions ()
4965
4966 The guestfs module provides a Python binding to the libguestfs API
4967 for examining and modifying virtual machine disk images.
4968
4969 Amongst the things this is good for: making batch configuration
4970 changes to guests, getting disk used/free statistics (see also:
4971 virt-df), migrating between virtualization systems (see also:
4972 virt-p2v), performing partial backups, performing partial guest
4973 clones, cloning guests and changing registry/UUID/hostname info, and
4974 much else besides.
4975
4976 Libguestfs uses Linux kernel and qemu code, and can access any type of
4977 guest filesystem that Linux and qemu can, including but not limited
4978 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
4979 schemes, qcow, qcow2, vmdk.
4980
4981 Libguestfs provides ways to enumerate guest storage (eg. partitions,
4982 LVs, what filesystem is in each LV, etc.).  It can also run commands
4983 in the context of the guest.  Also you can access filesystems over FTP.
4984
4985 Errors which happen while using the API are turned into Python
4986 RuntimeError exceptions.
4987
4988 To create a guestfs handle you usually have to perform the following
4989 sequence of calls:
4990
4991 # Create the handle, call add_drive at least once, and possibly
4992 # several times if the guest has multiple block devices:
4993 g = guestfs.GuestFS ()
4994 g.add_drive (\"guest.img\")
4995
4996 # Launch the qemu subprocess and wait for it to become ready:
4997 g.launch ()
4998 g.wait_ready ()
4999
5000 # Now you can issue commands, for example:
5001 logvols = g.lvs ()
5002
5003 \"\"\"
5004
5005 import libguestfsmod
5006
5007 class GuestFS:
5008     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
5009
5010     def __init__ (self):
5011         \"\"\"Create a new libguestfs handle.\"\"\"
5012         self._o = libguestfsmod.create ()
5013
5014     def __del__ (self):
5015         libguestfsmod.close (self._o)
5016
5017 ";
5018
5019   List.iter (
5020     fun (name, style, _, flags, _, _, longdesc) ->
5021       let doc = replace_str longdesc "C<guestfs_" "C<g." in
5022       let doc =
5023         match fst style with
5024         | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
5025         | RString _ -> doc
5026         | RStringList _ ->
5027             doc ^ "\n\nThis function returns a list of strings."
5028         | RIntBool _ ->
5029             doc ^ "\n\nThis function returns a tuple (int, bool).\n"
5030         | RPVList _ ->
5031             doc ^ "\n\nThis function returns a list of PVs.  Each PV is represented as a dictionary."
5032         | RVGList _ ->
5033             doc ^ "\n\nThis function returns a list of VGs.  Each VG is represented as a dictionary."
5034         | RLVList _ ->
5035             doc ^ "\n\nThis function returns a list of LVs.  Each LV is represented as a dictionary."
5036         | RStat _ ->
5037             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
5038        | RStatVFS _ ->
5039             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
5040        | RHashtable _ ->
5041             doc ^ "\n\nThis function returns a dictionary." in
5042       let doc =
5043         if List.mem ProtocolLimitWarning flags then
5044           doc ^ "\n\n" ^ protocol_limit_warning
5045         else doc in
5046       let doc =
5047         if List.mem DangerWillRobinson flags then
5048           doc ^ "\n\n" ^ danger_will_robinson
5049         else doc in
5050       let doc = pod2text ~width:60 name doc in
5051       let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
5052       let doc = String.concat "\n        " doc in
5053
5054       pr "    def %s " name;
5055       generate_call_args ~handle:"self" (snd style);
5056       pr ":\n";
5057       pr "        u\"\"\"%s\"\"\"\n" doc;
5058       pr "        return libguestfsmod.%s " name;
5059       generate_call_args ~handle:"self._o" (snd style);
5060       pr "\n";
5061       pr "\n";
5062   ) all_functions
5063
5064 (* Useful if you need the longdesc POD text as plain text.  Returns a
5065  * list of lines.
5066  *)
5067 and pod2text ~width name longdesc =
5068   let filename, chan = Filename.open_temp_file "gen" ".tmp" in
5069   fprintf chan "=head1 %s\n\n%s\n" name longdesc;
5070   close_out chan;
5071   let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
5072   let chan = Unix.open_process_in cmd in
5073   let lines = ref [] in
5074   let rec loop i =
5075     let line = input_line chan in
5076     if i = 1 then               (* discard the first line of output *)
5077       loop (i+1)
5078     else (
5079       let line = triml line in
5080       lines := line :: !lines;
5081       loop (i+1)
5082     ) in
5083   let lines = try loop 1 with End_of_file -> List.rev !lines in
5084   Unix.unlink filename;
5085   match Unix.close_process_in chan with
5086   | Unix.WEXITED 0 -> lines
5087   | Unix.WEXITED i ->
5088       failwithf "pod2text: process exited with non-zero status (%d)" i
5089   | Unix.WSIGNALED i | Unix.WSTOPPED i ->
5090       failwithf "pod2text: process signalled or stopped by signal %d" i
5091
5092 (* Generate ruby bindings. *)
5093 and generate_ruby_c () =
5094   generate_header CStyle LGPLv2;
5095
5096   pr "\
5097 #include <stdio.h>
5098 #include <stdlib.h>
5099
5100 #include <ruby.h>
5101
5102 #include \"guestfs.h\"
5103
5104 #include \"extconf.h\"
5105
5106 static VALUE m_guestfs;                 /* guestfs module */
5107 static VALUE c_guestfs;                 /* guestfs_h handle */
5108 static VALUE e_Error;                   /* used for all errors */
5109
5110 static void ruby_guestfs_free (void *p)
5111 {
5112   if (!p) return;
5113   guestfs_close ((guestfs_h *) p);
5114 }
5115
5116 static VALUE ruby_guestfs_create (VALUE m)
5117 {
5118   guestfs_h *g;
5119
5120   g = guestfs_create ();
5121   if (!g)
5122     rb_raise (e_Error, \"failed to create guestfs handle\");
5123
5124   /* Don't print error messages to stderr by default. */
5125   guestfs_set_error_handler (g, NULL, NULL);
5126
5127   /* Wrap it, and make sure the close function is called when the
5128    * handle goes away.
5129    */
5130   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
5131 }
5132
5133 static VALUE ruby_guestfs_close (VALUE gv)
5134 {
5135   guestfs_h *g;
5136   Data_Get_Struct (gv, guestfs_h, g);
5137
5138   ruby_guestfs_free (g);
5139   DATA_PTR (gv) = NULL;
5140
5141   return Qnil;
5142 }
5143
5144 ";
5145
5146   List.iter (
5147     fun (name, style, _, _, _, _, _) ->
5148       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
5149       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
5150       pr ")\n";
5151       pr "{\n";
5152       pr "  guestfs_h *g;\n";
5153       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
5154       pr "  if (!g)\n";
5155       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
5156         name;
5157       pr "\n";
5158
5159       List.iter (
5160         function
5161         | String n | FileIn n | FileOut n ->
5162             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
5163             pr "  if (!%s)\n" n;
5164             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
5165             pr "              \"%s\", \"%s\");\n" n name
5166         | OptString n ->
5167             pr "  const char *%s = StringValueCStr (%sv);\n" n n
5168         | StringList n ->
5169             pr "  char **%s;" n;
5170             pr "  {\n";
5171             pr "    int i, len;\n";
5172             pr "    len = RARRAY_LEN (%sv);\n" n;
5173             pr "    %s = malloc (sizeof (char *) * (len+1));\n" n;
5174             pr "    for (i = 0; i < len; ++i) {\n";
5175             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
5176             pr "      %s[i] = StringValueCStr (v);\n" n;
5177             pr "    }\n";
5178             pr "  }\n";
5179         | Bool n
5180         | Int n ->
5181             pr "  int %s = NUM2INT (%sv);\n" n n
5182       ) (snd style);
5183       pr "\n";
5184
5185       let error_code =
5186         match fst style with
5187         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
5188         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5189         | RConstString _ -> pr "  const char *r;\n"; "NULL"
5190         | RString _ -> pr "  char *r;\n"; "NULL"
5191         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5192         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
5193         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
5194         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
5195         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
5196         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
5197         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
5198       pr "\n";
5199
5200       pr "  r = guestfs_%s " name;
5201       generate_call_args ~handle:"g" (snd style);
5202       pr ";\n";
5203
5204       List.iter (
5205         function
5206         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5207         | StringList n ->
5208             pr "  free (%s);\n" n
5209       ) (snd style);
5210
5211       pr "  if (r == %s)\n" error_code;
5212       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
5213       pr "\n";
5214
5215       (match fst style with
5216        | RErr ->
5217            pr "  return Qnil;\n"
5218        | RInt _ | RBool _ ->
5219            pr "  return INT2NUM (r);\n"
5220        | RInt64 _ ->
5221            pr "  return ULL2NUM (r);\n"
5222        | RConstString _ ->
5223            pr "  return rb_str_new2 (r);\n";
5224        | RString _ ->
5225            pr "  VALUE rv = rb_str_new2 (r);\n";
5226            pr "  free (r);\n";
5227            pr "  return rv;\n";
5228        | RStringList _ ->
5229            pr "  int i, len = 0;\n";
5230            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
5231            pr "  VALUE rv = rb_ary_new2 (len);\n";
5232            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
5233            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
5234            pr "    free (r[i]);\n";
5235            pr "  }\n";
5236            pr "  free (r);\n";
5237            pr "  return rv;\n"
5238        | RIntBool _ ->
5239            pr "  VALUE rv = rb_ary_new2 (2);\n";
5240            pr "  rb_ary_push (rv, INT2NUM (r->i));\n";
5241            pr "  rb_ary_push (rv, INT2NUM (r->b));\n";
5242            pr "  guestfs_free_int_bool (r);\n";
5243            pr "  return rv;\n"
5244        | RPVList n ->
5245            generate_ruby_lvm_code "pv" pv_cols
5246        | RVGList n ->
5247            generate_ruby_lvm_code "vg" vg_cols
5248        | RLVList n ->
5249            generate_ruby_lvm_code "lv" lv_cols
5250        | RStat n ->
5251            pr "  VALUE rv = rb_hash_new ();\n";
5252            List.iter (
5253              function
5254              | name, `Int ->
5255                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5256            ) stat_cols;
5257            pr "  free (r);\n";
5258            pr "  return rv;\n"
5259        | RStatVFS n ->
5260            pr "  VALUE rv = rb_hash_new ();\n";
5261            List.iter (
5262              function
5263              | name, `Int ->
5264                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5265            ) statvfs_cols;
5266            pr "  free (r);\n";
5267            pr "  return rv;\n"
5268        | RHashtable _ ->
5269            pr "  VALUE rv = rb_hash_new ();\n";
5270            pr "  int i;\n";
5271            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
5272            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
5273            pr "    free (r[i]);\n";
5274            pr "    free (r[i+1]);\n";
5275            pr "  }\n";
5276            pr "  free (r);\n";
5277            pr "  return rv;\n"
5278       );
5279
5280       pr "}\n";
5281       pr "\n"
5282   ) all_functions;
5283
5284   pr "\
5285 /* Initialize the module. */
5286 void Init__guestfs ()
5287 {
5288   m_guestfs = rb_define_module (\"Guestfs\");
5289   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
5290   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
5291
5292   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
5293   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
5294
5295 ";
5296   (* Define the rest of the methods. *)
5297   List.iter (
5298     fun (name, style, _, _, _, _, _) ->
5299       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
5300       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
5301   ) all_functions;
5302
5303   pr "}\n"
5304
5305 (* Ruby code to return an LVM struct list. *)
5306 and generate_ruby_lvm_code typ cols =
5307   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
5308   pr "  int i;\n";
5309   pr "  for (i = 0; i < r->len; ++i) {\n";
5310   pr "    VALUE hv = rb_hash_new ();\n";
5311   List.iter (
5312     function
5313     | name, `String ->
5314         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
5315     | name, `UUID ->
5316         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
5317     | name, `Bytes
5318     | name, `Int ->
5319         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
5320     | name, `OptPercent ->
5321         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
5322   ) cols;
5323   pr "    rb_ary_push (rv, hv);\n";
5324   pr "  }\n";
5325   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
5326   pr "  return rv;\n"
5327
5328 let output_to filename =
5329   let filename_new = filename ^ ".new" in
5330   chan := open_out filename_new;
5331   let close () =
5332     close_out !chan;
5333     chan := stdout;
5334     Unix.rename filename_new filename;
5335     printf "written %s\n%!" filename;
5336   in
5337   close
5338
5339 (* Main program. *)
5340 let () =
5341   check_functions ();
5342
5343   if not (Sys.file_exists "configure.ac") then (
5344     eprintf "\
5345 You are probably running this from the wrong directory.
5346 Run it from the top source directory using the command
5347   src/generator.ml
5348 ";
5349     exit 1
5350   );
5351
5352   let close = output_to "src/guestfs_protocol.x" in
5353   generate_xdr ();
5354   close ();
5355
5356   let close = output_to "src/guestfs-structs.h" in
5357   generate_structs_h ();
5358   close ();
5359
5360   let close = output_to "src/guestfs-actions.h" in
5361   generate_actions_h ();
5362   close ();
5363
5364   let close = output_to "src/guestfs-actions.c" in
5365   generate_client_actions ();
5366   close ();
5367
5368   let close = output_to "daemon/actions.h" in
5369   generate_daemon_actions_h ();
5370   close ();
5371
5372   let close = output_to "daemon/stubs.c" in
5373   generate_daemon_actions ();
5374   close ();
5375
5376   let close = output_to "tests.c" in
5377   generate_tests ();
5378   close ();
5379
5380   let close = output_to "fish/cmds.c" in
5381   generate_fish_cmds ();
5382   close ();
5383
5384   let close = output_to "fish/completion.c" in
5385   generate_fish_completion ();
5386   close ();
5387
5388   let close = output_to "guestfs-structs.pod" in
5389   generate_structs_pod ();
5390   close ();
5391
5392   let close = output_to "guestfs-actions.pod" in
5393   generate_actions_pod ();
5394   close ();
5395
5396   let close = output_to "guestfish-actions.pod" in
5397   generate_fish_actions_pod ();
5398   close ();
5399
5400   let close = output_to "ocaml/guestfs.mli" in
5401   generate_ocaml_mli ();
5402   close ();
5403
5404   let close = output_to "ocaml/guestfs.ml" in
5405   generate_ocaml_ml ();
5406   close ();
5407
5408   let close = output_to "ocaml/guestfs_c_actions.c" in
5409   generate_ocaml_c ();
5410   close ();
5411
5412   let close = output_to "perl/Guestfs.xs" in
5413   generate_perl_xs ();
5414   close ();
5415
5416   let close = output_to "perl/lib/Sys/Guestfs.pm" in
5417   generate_perl_pm ();
5418   close ();
5419
5420   let close = output_to "python/guestfs-py.c" in
5421   generate_python_c ();
5422   close ();
5423
5424   let close = output_to "python/guestfs.py" in
5425   generate_python_py ();
5426   close ();
5427
5428   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
5429   generate_ruby_c ();
5430   close ();