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