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