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