Add mkdtemp command.
[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   ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2446    [InitBasicFS, Always, TestRun (
2447       [["mkdir"; "/tmp"];
2448        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2449    "create a temporary directory",
2450    "\
2451 This command creates a temporary directory.  The
2452 C<template> parameter should be a full pathname for the
2453 temporary directory with the six characters being
2454 \"XXXXXX\".
2455
2456 For example: \"/tmp/tmpXXXXXX\" or \"/Temp/tmpXXXXXX\",
2457 the second one being suitable for Windows.
2458
2459 The name of the temporary directory that was created
2460 is returned.
2461
2462 The caller is responsible for deleting the temporary
2463 directory and its contents after use.
2464
2465 See also: L<mkdtemp(3)>");
2466
2467 ]
2468
2469 let all_functions = non_daemon_functions @ daemon_functions
2470
2471 (* In some places we want the functions to be displayed sorted
2472  * alphabetically, so this is useful:
2473  *)
2474 let all_functions_sorted =
2475   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2476                compare n1 n2) all_functions
2477
2478 (* Column names and types from LVM PVs/VGs/LVs. *)
2479 let pv_cols = [
2480   "pv_name", `String;
2481   "pv_uuid", `UUID;
2482   "pv_fmt", `String;
2483   "pv_size", `Bytes;
2484   "dev_size", `Bytes;
2485   "pv_free", `Bytes;
2486   "pv_used", `Bytes;
2487   "pv_attr", `String (* XXX *);
2488   "pv_pe_count", `Int;
2489   "pv_pe_alloc_count", `Int;
2490   "pv_tags", `String;
2491   "pe_start", `Bytes;
2492   "pv_mda_count", `Int;
2493   "pv_mda_free", `Bytes;
2494 (* Not in Fedora 10:
2495   "pv_mda_size", `Bytes;
2496 *)
2497 ]
2498 let vg_cols = [
2499   "vg_name", `String;
2500   "vg_uuid", `UUID;
2501   "vg_fmt", `String;
2502   "vg_attr", `String (* XXX *);
2503   "vg_size", `Bytes;
2504   "vg_free", `Bytes;
2505   "vg_sysid", `String;
2506   "vg_extent_size", `Bytes;
2507   "vg_extent_count", `Int;
2508   "vg_free_count", `Int;
2509   "max_lv", `Int;
2510   "max_pv", `Int;
2511   "pv_count", `Int;
2512   "lv_count", `Int;
2513   "snap_count", `Int;
2514   "vg_seqno", `Int;
2515   "vg_tags", `String;
2516   "vg_mda_count", `Int;
2517   "vg_mda_free", `Bytes;
2518 (* Not in Fedora 10:
2519   "vg_mda_size", `Bytes;
2520 *)
2521 ]
2522 let lv_cols = [
2523   "lv_name", `String;
2524   "lv_uuid", `UUID;
2525   "lv_attr", `String (* XXX *);
2526   "lv_major", `Int;
2527   "lv_minor", `Int;
2528   "lv_kernel_major", `Int;
2529   "lv_kernel_minor", `Int;
2530   "lv_size", `Bytes;
2531   "seg_count", `Int;
2532   "origin", `String;
2533   "snap_percent", `OptPercent;
2534   "copy_percent", `OptPercent;
2535   "move_pv", `String;
2536   "lv_tags", `String;
2537   "mirror_log", `String;
2538   "modules", `String;
2539 ]
2540
2541 (* Column names and types from stat structures.
2542  * NB. Can't use things like 'st_atime' because glibc header files
2543  * define some of these as macros.  Ugh.
2544  *)
2545 let stat_cols = [
2546   "dev", `Int;
2547   "ino", `Int;
2548   "mode", `Int;
2549   "nlink", `Int;
2550   "uid", `Int;
2551   "gid", `Int;
2552   "rdev", `Int;
2553   "size", `Int;
2554   "blksize", `Int;
2555   "blocks", `Int;
2556   "atime", `Int;
2557   "mtime", `Int;
2558   "ctime", `Int;
2559 ]
2560 let statvfs_cols = [
2561   "bsize", `Int;
2562   "frsize", `Int;
2563   "blocks", `Int;
2564   "bfree", `Int;
2565   "bavail", `Int;
2566   "files", `Int;
2567   "ffree", `Int;
2568   "favail", `Int;
2569   "fsid", `Int;
2570   "flag", `Int;
2571   "namemax", `Int;
2572 ]
2573
2574 (* Used for testing language bindings. *)
2575 type callt =
2576   | CallString of string
2577   | CallOptString of string option
2578   | CallStringList of string list
2579   | CallInt of int
2580   | CallBool of bool
2581
2582 (* Useful functions.
2583  * Note we don't want to use any external OCaml libraries which
2584  * makes this a bit harder than it should be.
2585  *)
2586 let failwithf fs = ksprintf failwith fs
2587
2588 let replace_char s c1 c2 =
2589   let s2 = String.copy s in
2590   let r = ref false in
2591   for i = 0 to String.length s2 - 1 do
2592     if String.unsafe_get s2 i = c1 then (
2593       String.unsafe_set s2 i c2;
2594       r := true
2595     )
2596   done;
2597   if not !r then s else s2
2598
2599 let isspace c =
2600   c = ' '
2601   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2602
2603 let triml ?(test = isspace) str =
2604   let i = ref 0 in
2605   let n = ref (String.length str) in
2606   while !n > 0 && test str.[!i]; do
2607     decr n;
2608     incr i
2609   done;
2610   if !i = 0 then str
2611   else String.sub str !i !n
2612
2613 let trimr ?(test = isspace) str =
2614   let n = ref (String.length str) in
2615   while !n > 0 && test str.[!n-1]; do
2616     decr n
2617   done;
2618   if !n = String.length str then str
2619   else String.sub str 0 !n
2620
2621 let trim ?(test = isspace) str =
2622   trimr ~test (triml ~test str)
2623
2624 let rec find s sub =
2625   let len = String.length s in
2626   let sublen = String.length sub in
2627   let rec loop i =
2628     if i <= len-sublen then (
2629       let rec loop2 j =
2630         if j < sublen then (
2631           if s.[i+j] = sub.[j] then loop2 (j+1)
2632           else -1
2633         ) else
2634           i (* found *)
2635       in
2636       let r = loop2 0 in
2637       if r = -1 then loop (i+1) else r
2638     ) else
2639       -1 (* not found *)
2640   in
2641   loop 0
2642
2643 let rec replace_str s s1 s2 =
2644   let len = String.length s in
2645   let sublen = String.length s1 in
2646   let i = find s s1 in
2647   if i = -1 then s
2648   else (
2649     let s' = String.sub s 0 i in
2650     let s'' = String.sub s (i+sublen) (len-i-sublen) in
2651     s' ^ s2 ^ replace_str s'' s1 s2
2652   )
2653
2654 let rec string_split sep str =
2655   let len = String.length str in
2656   let seplen = String.length sep in
2657   let i = find str sep in
2658   if i = -1 then [str]
2659   else (
2660     let s' = String.sub str 0 i in
2661     let s'' = String.sub str (i+seplen) (len-i-seplen) in
2662     s' :: string_split sep s''
2663   )
2664
2665 let files_equal n1 n2 =
2666   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
2667   match Sys.command cmd with
2668   | 0 -> true
2669   | 1 -> false
2670   | i -> failwithf "%s: failed with error code %d" cmd i
2671
2672 let rec find_map f = function
2673   | [] -> raise Not_found
2674   | x :: xs ->
2675       match f x with
2676       | Some y -> y
2677       | None -> find_map f xs
2678
2679 let iteri f xs =
2680   let rec loop i = function
2681     | [] -> ()
2682     | x :: xs -> f i x; loop (i+1) xs
2683   in
2684   loop 0 xs
2685
2686 let mapi f xs =
2687   let rec loop i = function
2688     | [] -> []
2689     | x :: xs -> let r = f i x in r :: loop (i+1) xs
2690   in
2691   loop 0 xs
2692
2693 let name_of_argt = function
2694   | String n | OptString n | StringList n | Bool n | Int n
2695   | FileIn n | FileOut n -> n
2696
2697 let seq_of_test = function
2698   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
2699   | TestOutputListOfDevices (s, _)
2700   | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
2701   | TestOutputLength (s, _) | TestOutputStruct (s, _)
2702   | TestLastFail s -> s
2703
2704 (* Check function names etc. for consistency. *)
2705 let check_functions () =
2706   let contains_uppercase str =
2707     let len = String.length str in
2708     let rec loop i =
2709       if i >= len then false
2710       else (
2711         let c = str.[i] in
2712         if c >= 'A' && c <= 'Z' then true
2713         else loop (i+1)
2714       )
2715     in
2716     loop 0
2717   in
2718
2719   (* Check function names. *)
2720   List.iter (
2721     fun (name, _, _, _, _, _, _) ->
2722       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
2723         failwithf "function name %s does not need 'guestfs' prefix" name;
2724       if name = "" then
2725         failwithf "function name is empty";
2726       if name.[0] < 'a' || name.[0] > 'z' then
2727         failwithf "function name %s must start with lowercase a-z" name;
2728       if String.contains name '-' then
2729         failwithf "function name %s should not contain '-', use '_' instead."
2730           name
2731   ) all_functions;
2732
2733   (* Check function parameter/return names. *)
2734   List.iter (
2735     fun (name, style, _, _, _, _, _) ->
2736       let check_arg_ret_name n =
2737         if contains_uppercase n then
2738           failwithf "%s param/ret %s should not contain uppercase chars"
2739             name n;
2740         if String.contains n '-' || String.contains n '_' then
2741           failwithf "%s param/ret %s should not contain '-' or '_'"
2742             name n;
2743         if n = "value" then
2744           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;
2745         if n = "int" || n = "char" || n = "short" || n = "long" then
2746           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
2747         if n = "i" then
2748           failwithf "%s has a param/ret called 'i', which will cause some conflicts in the generated code" name;
2749         if n = "argv" || n = "args" then
2750           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
2751       in
2752
2753       (match fst style with
2754        | RErr -> ()
2755        | RInt n | RInt64 n | RBool n | RConstString n | RString n
2756        | RStringList n | RPVList n | RVGList n | RLVList n
2757        | RStat n | RStatVFS n
2758        | RHashtable n ->
2759            check_arg_ret_name n
2760        | RIntBool (n,m) ->
2761            check_arg_ret_name n;
2762            check_arg_ret_name m
2763       );
2764       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
2765   ) all_functions;
2766
2767   (* Check short descriptions. *)
2768   List.iter (
2769     fun (name, _, _, _, _, shortdesc, _) ->
2770       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
2771         failwithf "short description of %s should begin with lowercase." name;
2772       let c = shortdesc.[String.length shortdesc-1] in
2773       if c = '\n' || c = '.' then
2774         failwithf "short description of %s should not end with . or \\n." name
2775   ) all_functions;
2776
2777   (* Check long dscriptions. *)
2778   List.iter (
2779     fun (name, _, _, _, _, _, longdesc) ->
2780       if longdesc.[String.length longdesc-1] = '\n' then
2781         failwithf "long description of %s should not end with \\n." name
2782   ) all_functions;
2783
2784   (* Check proc_nrs. *)
2785   List.iter (
2786     fun (name, _, proc_nr, _, _, _, _) ->
2787       if proc_nr <= 0 then
2788         failwithf "daemon function %s should have proc_nr > 0" name
2789   ) daemon_functions;
2790
2791   List.iter (
2792     fun (name, _, proc_nr, _, _, _, _) ->
2793       if proc_nr <> -1 then
2794         failwithf "non-daemon function %s should have proc_nr -1" name
2795   ) non_daemon_functions;
2796
2797   let proc_nrs =
2798     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
2799       daemon_functions in
2800   let proc_nrs =
2801     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
2802   let rec loop = function
2803     | [] -> ()
2804     | [_] -> ()
2805     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
2806         loop rest
2807     | (name1,nr1) :: (name2,nr2) :: _ ->
2808         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
2809           name1 name2 nr1 nr2
2810   in
2811   loop proc_nrs;
2812
2813   (* Check tests. *)
2814   List.iter (
2815     function
2816       (* Ignore functions that have no tests.  We generate a
2817        * warning when the user does 'make check' instead.
2818        *)
2819     | name, _, _, _, [], _, _ -> ()
2820     | name, _, _, _, tests, _, _ ->
2821         let funcs =
2822           List.map (
2823             fun (_, _, test) ->
2824               match seq_of_test test with
2825               | [] ->
2826                   failwithf "%s has a test containing an empty sequence" name
2827               | cmds -> List.map List.hd cmds
2828           ) tests in
2829         let funcs = List.flatten funcs in
2830
2831         let tested = List.mem name funcs in
2832
2833         if not tested then
2834           failwithf "function %s has tests but does not test itself" name
2835   ) all_functions
2836
2837 (* 'pr' prints to the current output file. *)
2838 let chan = ref stdout
2839 let pr fs = ksprintf (output_string !chan) fs
2840
2841 (* Generate a header block in a number of standard styles. *)
2842 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
2843 type license = GPLv2 | LGPLv2
2844
2845 let generate_header comment license =
2846   let c = match comment with
2847     | CStyle ->     pr "/* "; " *"
2848     | HashStyle ->  pr "# ";  "#"
2849     | OCamlStyle -> pr "(* "; " *"
2850     | HaskellStyle -> pr "{- "; "  " in
2851   pr "libguestfs generated file\n";
2852   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
2853   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
2854   pr "%s\n" c;
2855   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
2856   pr "%s\n" c;
2857   (match license with
2858    | GPLv2 ->
2859        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
2860        pr "%s it under the terms of the GNU General Public License as published by\n" c;
2861        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
2862        pr "%s (at your option) any later version.\n" c;
2863        pr "%s\n" c;
2864        pr "%s This program is distributed in the hope that it will be useful,\n" c;
2865        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2866        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
2867        pr "%s GNU General Public License for more details.\n" c;
2868        pr "%s\n" c;
2869        pr "%s You should have received a copy of the GNU General Public License along\n" c;
2870        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
2871        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
2872
2873    | LGPLv2 ->
2874        pr "%s This library is free software; you can redistribute it and/or\n" c;
2875        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
2876        pr "%s License as published by the Free Software Foundation; either\n" c;
2877        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
2878        pr "%s\n" c;
2879        pr "%s This library is distributed in the hope that it will be useful,\n" c;
2880        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
2881        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
2882        pr "%s Lesser General Public License for more details.\n" c;
2883        pr "%s\n" c;
2884        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
2885        pr "%s License along with this library; if not, write to the Free Software\n" c;
2886        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
2887   );
2888   (match comment with
2889    | CStyle -> pr " */\n"
2890    | HashStyle -> ()
2891    | OCamlStyle -> pr " *)\n"
2892    | HaskellStyle -> pr "-}\n"
2893   );
2894   pr "\n"
2895
2896 (* Start of main code generation functions below this line. *)
2897
2898 (* Generate the pod documentation for the C API. *)
2899 let rec generate_actions_pod () =
2900   List.iter (
2901     fun (shortname, style, _, flags, _, _, longdesc) ->
2902       if not (List.mem NotInDocs flags) then (
2903         let name = "guestfs_" ^ shortname in
2904         pr "=head2 %s\n\n" name;
2905         pr " ";
2906         generate_prototype ~extern:false ~handle:"handle" name style;
2907         pr "\n\n";
2908         pr "%s\n\n" longdesc;
2909         (match fst style with
2910          | RErr ->
2911              pr "This function returns 0 on success or -1 on error.\n\n"
2912          | RInt _ ->
2913              pr "On error this function returns -1.\n\n"
2914          | RInt64 _ ->
2915              pr "On error this function returns -1.\n\n"
2916          | RBool _ ->
2917              pr "This function returns a C truth value on success or -1 on error.\n\n"
2918          | RConstString _ ->
2919              pr "This function returns a string, or NULL on error.
2920 The string is owned by the guest handle and must I<not> be freed.\n\n"
2921          | RString _ ->
2922              pr "This function returns a string, or NULL on error.
2923 I<The caller must free the returned string after use>.\n\n"
2924          | RStringList _ ->
2925              pr "This function returns a NULL-terminated array of strings
2926 (like L<environ(3)>), or NULL if there was an error.
2927 I<The caller must free the strings and the array after use>.\n\n"
2928          | RIntBool _ ->
2929              pr "This function returns a C<struct guestfs_int_bool *>,
2930 or NULL if there was an error.
2931 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
2932          | RPVList _ ->
2933              pr "This function returns a C<struct guestfs_lvm_pv_list *>
2934 (see E<lt>guestfs-structs.hE<gt>),
2935 or NULL if there was an error.
2936 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
2937          | RVGList _ ->
2938              pr "This function returns a C<struct guestfs_lvm_vg_list *>
2939 (see E<lt>guestfs-structs.hE<gt>),
2940 or NULL if there was an error.
2941 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
2942          | RLVList _ ->
2943              pr "This function returns a C<struct guestfs_lvm_lv_list *>
2944 (see E<lt>guestfs-structs.hE<gt>),
2945 or NULL if there was an error.
2946 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
2947          | RStat _ ->
2948              pr "This function returns a C<struct guestfs_stat *>
2949 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
2950 or NULL if there was an error.
2951 I<The caller must call C<free> after use>.\n\n"
2952          | RStatVFS _ ->
2953              pr "This function returns a C<struct guestfs_statvfs *>
2954 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
2955 or NULL if there was an error.
2956 I<The caller must call C<free> after use>.\n\n"
2957          | RHashtable _ ->
2958              pr "This function returns a NULL-terminated array of
2959 strings, or NULL if there was an error.
2960 The array of strings will always have length C<2n+1>, where
2961 C<n> keys and values alternate, followed by the trailing NULL entry.
2962 I<The caller must free the strings and the array after use>.\n\n"
2963         );
2964         if List.mem ProtocolLimitWarning flags then
2965           pr "%s\n\n" protocol_limit_warning;
2966         if List.mem DangerWillRobinson flags then
2967           pr "%s\n\n" danger_will_robinson
2968       )
2969   ) all_functions_sorted
2970
2971 and generate_structs_pod () =
2972   (* LVM structs documentation. *)
2973   List.iter (
2974     fun (typ, cols) ->
2975       pr "=head2 guestfs_lvm_%s\n" typ;
2976       pr "\n";
2977       pr " struct guestfs_lvm_%s {\n" typ;
2978       List.iter (
2979         function
2980         | name, `String -> pr "  char *%s;\n" name
2981         | name, `UUID ->
2982             pr "  /* The next field is NOT nul-terminated, be careful when printing it: */\n";
2983             pr "  char %s[32];\n" name
2984         | name, `Bytes -> pr "  uint64_t %s;\n" name
2985         | name, `Int -> pr "  int64_t %s;\n" name
2986         | name, `OptPercent ->
2987             pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
2988             pr "  float %s;\n" name
2989       ) cols;
2990       pr " \n";
2991       pr " struct guestfs_lvm_%s_list {\n" typ;
2992       pr "   uint32_t len; /* Number of elements in list. */\n";
2993       pr "   struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
2994       pr " };\n";
2995       pr " \n";
2996       pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
2997         typ typ;
2998       pr "\n"
2999   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3000
3001 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3002  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3003  *
3004  * We have to use an underscore instead of a dash because otherwise
3005  * rpcgen generates incorrect code.
3006  *
3007  * This header is NOT exported to clients, but see also generate_structs_h.
3008  *)
3009 and generate_xdr () =
3010   generate_header CStyle LGPLv2;
3011
3012   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3013   pr "typedef string str<>;\n";
3014   pr "\n";
3015
3016   (* LVM internal structures. *)
3017   List.iter (
3018     function
3019     | typ, cols ->
3020         pr "struct guestfs_lvm_int_%s {\n" typ;
3021         List.iter (function
3022                    | name, `String -> pr "  string %s<>;\n" name
3023                    | name, `UUID -> pr "  opaque %s[32];\n" name
3024                    | name, `Bytes -> pr "  hyper %s;\n" name
3025                    | name, `Int -> pr "  hyper %s;\n" name
3026                    | name, `OptPercent -> pr "  float %s;\n" name
3027                   ) cols;
3028         pr "};\n";
3029         pr "\n";
3030         pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
3031         pr "\n";
3032   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3033
3034   (* Stat internal structures. *)
3035   List.iter (
3036     function
3037     | typ, cols ->
3038         pr "struct guestfs_int_%s {\n" typ;
3039         List.iter (function
3040                    | name, `Int -> pr "  hyper %s;\n" name
3041                   ) cols;
3042         pr "};\n";
3043         pr "\n";
3044   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3045
3046   List.iter (
3047     fun (shortname, style, _, _, _, _, _) ->
3048       let name = "guestfs_" ^ shortname in
3049
3050       (match snd style with
3051        | [] -> ()
3052        | args ->
3053            pr "struct %s_args {\n" name;
3054            List.iter (
3055              function
3056              | String n -> pr "  string %s<>;\n" n
3057              | OptString n -> pr "  str *%s;\n" n
3058              | StringList n -> pr "  str %s<>;\n" n
3059              | Bool n -> pr "  bool %s;\n" n
3060              | Int n -> pr "  int %s;\n" n
3061              | FileIn _ | FileOut _ -> ()
3062            ) args;
3063            pr "};\n\n"
3064       );
3065       (match fst style with
3066        | RErr -> ()
3067        | RInt n ->
3068            pr "struct %s_ret {\n" name;
3069            pr "  int %s;\n" n;
3070            pr "};\n\n"
3071        | RInt64 n ->
3072            pr "struct %s_ret {\n" name;
3073            pr "  hyper %s;\n" n;
3074            pr "};\n\n"
3075        | RBool n ->
3076            pr "struct %s_ret {\n" name;
3077            pr "  bool %s;\n" n;
3078            pr "};\n\n"
3079        | RConstString _ ->
3080            failwithf "RConstString cannot be returned from a daemon function"
3081        | RString n ->
3082            pr "struct %s_ret {\n" name;
3083            pr "  string %s<>;\n" n;
3084            pr "};\n\n"
3085        | RStringList n ->
3086            pr "struct %s_ret {\n" name;
3087            pr "  str %s<>;\n" n;
3088            pr "};\n\n"
3089        | RIntBool (n,m) ->
3090            pr "struct %s_ret {\n" name;
3091            pr "  int %s;\n" n;
3092            pr "  bool %s;\n" m;
3093            pr "};\n\n"
3094        | RPVList n ->
3095            pr "struct %s_ret {\n" name;
3096            pr "  guestfs_lvm_int_pv_list %s;\n" n;
3097            pr "};\n\n"
3098        | RVGList n ->
3099            pr "struct %s_ret {\n" name;
3100            pr "  guestfs_lvm_int_vg_list %s;\n" n;
3101            pr "};\n\n"
3102        | RLVList n ->
3103            pr "struct %s_ret {\n" name;
3104            pr "  guestfs_lvm_int_lv_list %s;\n" n;
3105            pr "};\n\n"
3106        | RStat n ->
3107            pr "struct %s_ret {\n" name;
3108            pr "  guestfs_int_stat %s;\n" n;
3109            pr "};\n\n"
3110        | RStatVFS n ->
3111            pr "struct %s_ret {\n" name;
3112            pr "  guestfs_int_statvfs %s;\n" n;
3113            pr "};\n\n"
3114        | RHashtable n ->
3115            pr "struct %s_ret {\n" name;
3116            pr "  str %s<>;\n" n;
3117            pr "};\n\n"
3118       );
3119   ) daemon_functions;
3120
3121   (* Table of procedure numbers. *)
3122   pr "enum guestfs_procedure {\n";
3123   List.iter (
3124     fun (shortname, _, proc_nr, _, _, _, _) ->
3125       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3126   ) daemon_functions;
3127   pr "  GUESTFS_PROC_NR_PROCS\n";
3128   pr "};\n";
3129   pr "\n";
3130
3131   (* Having to choose a maximum message size is annoying for several
3132    * reasons (it limits what we can do in the API), but it (a) makes
3133    * the protocol a lot simpler, and (b) provides a bound on the size
3134    * of the daemon which operates in limited memory space.  For large
3135    * file transfers you should use FTP.
3136    *)
3137   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3138   pr "\n";
3139
3140   (* Message header, etc. *)
3141   pr "\
3142 /* The communication protocol is now documented in the guestfs(3)
3143  * manpage.
3144  */
3145
3146 const GUESTFS_PROGRAM = 0x2000F5F5;
3147 const GUESTFS_PROTOCOL_VERSION = 1;
3148
3149 /* These constants must be larger than any possible message length. */
3150 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3151 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3152
3153 enum guestfs_message_direction {
3154   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
3155   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
3156 };
3157
3158 enum guestfs_message_status {
3159   GUESTFS_STATUS_OK = 0,
3160   GUESTFS_STATUS_ERROR = 1
3161 };
3162
3163 const GUESTFS_ERROR_LEN = 256;
3164
3165 struct guestfs_message_error {
3166   string error_message<GUESTFS_ERROR_LEN>;
3167 };
3168
3169 struct guestfs_message_header {
3170   unsigned prog;                     /* GUESTFS_PROGRAM */
3171   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
3172   guestfs_procedure proc;            /* GUESTFS_PROC_x */
3173   guestfs_message_direction direction;
3174   unsigned serial;                   /* message serial number */
3175   guestfs_message_status status;
3176 };
3177
3178 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3179
3180 struct guestfs_chunk {
3181   int cancel;                        /* if non-zero, transfer is cancelled */
3182   /* data size is 0 bytes if the transfer has finished successfully */
3183   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3184 };
3185 "
3186
3187 (* Generate the guestfs-structs.h file. *)
3188 and generate_structs_h () =
3189   generate_header CStyle LGPLv2;
3190
3191   (* This is a public exported header file containing various
3192    * structures.  The structures are carefully written to have
3193    * exactly the same in-memory format as the XDR structures that
3194    * we use on the wire to the daemon.  The reason for creating
3195    * copies of these structures here is just so we don't have to
3196    * export the whole of guestfs_protocol.h (which includes much
3197    * unrelated and XDR-dependent stuff that we don't want to be
3198    * public, or required by clients).
3199    *
3200    * To reiterate, we will pass these structures to and from the
3201    * client with a simple assignment or memcpy, so the format
3202    * must be identical to what rpcgen / the RFC defines.
3203    *)
3204
3205   (* guestfs_int_bool structure. *)
3206   pr "struct guestfs_int_bool {\n";
3207   pr "  int32_t i;\n";
3208   pr "  int32_t b;\n";
3209   pr "};\n";
3210   pr "\n";
3211
3212   (* LVM public structures. *)
3213   List.iter (
3214     function
3215     | typ, cols ->
3216         pr "struct guestfs_lvm_%s {\n" typ;
3217         List.iter (
3218           function
3219           | name, `String -> pr "  char *%s;\n" name
3220           | name, `UUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3221           | name, `Bytes -> pr "  uint64_t %s;\n" name
3222           | name, `Int -> pr "  int64_t %s;\n" name
3223           | name, `OptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
3224         ) cols;
3225         pr "};\n";
3226         pr "\n";
3227         pr "struct guestfs_lvm_%s_list {\n" typ;
3228         pr "  uint32_t len;\n";
3229         pr "  struct guestfs_lvm_%s *val;\n" typ;
3230         pr "};\n";
3231         pr "\n"
3232   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3233
3234   (* Stat structures. *)
3235   List.iter (
3236     function
3237     | typ, cols ->
3238         pr "struct guestfs_%s {\n" typ;
3239         List.iter (
3240           function
3241           | name, `Int -> pr "  int64_t %s;\n" name
3242         ) cols;
3243         pr "};\n";
3244         pr "\n"
3245   ) ["stat", stat_cols; "statvfs", statvfs_cols]
3246
3247 (* Generate the guestfs-actions.h file. *)
3248 and generate_actions_h () =
3249   generate_header CStyle LGPLv2;
3250   List.iter (
3251     fun (shortname, style, _, _, _, _, _) ->
3252       let name = "guestfs_" ^ shortname in
3253       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3254         name style
3255   ) all_functions
3256
3257 (* Generate the client-side dispatch stubs. *)
3258 and generate_client_actions () =
3259   generate_header CStyle LGPLv2;
3260
3261   pr "\
3262 #include <stdio.h>
3263 #include <stdlib.h>
3264
3265 #include \"guestfs.h\"
3266 #include \"guestfs_protocol.h\"
3267
3268 #define error guestfs_error
3269 #define perrorf guestfs_perrorf
3270 #define safe_malloc guestfs_safe_malloc
3271 #define safe_realloc guestfs_safe_realloc
3272 #define safe_strdup guestfs_safe_strdup
3273 #define safe_memdup guestfs_safe_memdup
3274
3275 /* Check the return message from a call for validity. */
3276 static int
3277 check_reply_header (guestfs_h *g,
3278                     const struct guestfs_message_header *hdr,
3279                     int proc_nr, int serial)
3280 {
3281   if (hdr->prog != GUESTFS_PROGRAM) {
3282     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3283     return -1;
3284   }
3285   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3286     error (g, \"wrong protocol version (%%d/%%d)\",
3287            hdr->vers, GUESTFS_PROTOCOL_VERSION);
3288     return -1;
3289   }
3290   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3291     error (g, \"unexpected message direction (%%d/%%d)\",
3292            hdr->direction, GUESTFS_DIRECTION_REPLY);
3293     return -1;
3294   }
3295   if (hdr->proc != proc_nr) {
3296     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3297     return -1;
3298   }
3299   if (hdr->serial != serial) {
3300     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3301     return -1;
3302   }
3303
3304   return 0;
3305 }
3306
3307 /* Check we are in the right state to run a high-level action. */
3308 static int
3309 check_state (guestfs_h *g, const char *caller)
3310 {
3311   if (!guestfs_is_ready (g)) {
3312     if (guestfs_is_config (g))
3313       error (g, \"%%s: call launch() before using this function\",
3314         caller);
3315     else if (guestfs_is_launching (g))
3316       error (g, \"%%s: call wait_ready() before using this function\",
3317         caller);
3318     else
3319       error (g, \"%%s called from the wrong state, %%d != READY\",
3320         caller, guestfs_get_state (g));
3321     return -1;
3322   }
3323   return 0;
3324 }
3325
3326 ";
3327
3328   (* Client-side stubs for each function. *)
3329   List.iter (
3330     fun (shortname, style, _, _, _, _, _) ->
3331       let name = "guestfs_" ^ shortname in
3332
3333       (* Generate the context struct which stores the high-level
3334        * state between callback functions.
3335        *)
3336       pr "struct %s_ctx {\n" shortname;
3337       pr "  /* This flag is set by the callbacks, so we know we've done\n";
3338       pr "   * the callbacks as expected, and in the right sequence.\n";
3339       pr "   * 0 = not called, 1 = reply_cb called.\n";
3340       pr "   */\n";
3341       pr "  int cb_sequence;\n";
3342       pr "  struct guestfs_message_header hdr;\n";
3343       pr "  struct guestfs_message_error err;\n";
3344       (match fst style with
3345        | RErr -> ()
3346        | RConstString _ ->
3347            failwithf "RConstString cannot be returned from a daemon function"
3348        | RInt _ | RInt64 _
3349        | RBool _ | RString _ | RStringList _
3350        | RIntBool _
3351        | RPVList _ | RVGList _ | RLVList _
3352        | RStat _ | RStatVFS _
3353        | RHashtable _ ->
3354            pr "  struct %s_ret ret;\n" name
3355       );
3356       pr "};\n";
3357       pr "\n";
3358
3359       (* Generate the reply callback function. *)
3360       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3361       pr "{\n";
3362       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3363       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3364       pr "\n";
3365       pr "  /* This should definitely not happen. */\n";
3366       pr "  if (ctx->cb_sequence != 0) {\n";
3367       pr "    ctx->cb_sequence = 9999;\n";
3368       pr "    error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3369       pr "    return;\n";
3370       pr "  }\n";
3371       pr "\n";
3372       pr "  ml->main_loop_quit (ml, g);\n";
3373       pr "\n";
3374       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3375       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3376       pr "    return;\n";
3377       pr "  }\n";
3378       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3379       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3380       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3381         name;
3382       pr "      return;\n";
3383       pr "    }\n";
3384       pr "    goto done;\n";
3385       pr "  }\n";
3386
3387       (match fst style with
3388        | RErr -> ()
3389        | RConstString _ ->
3390            failwithf "RConstString cannot be returned from a daemon function"
3391        | RInt _ | RInt64 _
3392        | RBool _ | RString _ | RStringList _
3393        | RIntBool _
3394        | RPVList _ | RVGList _ | RLVList _
3395        | RStat _ | RStatVFS _
3396        | RHashtable _ ->
3397             pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3398             pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3399             pr "    return;\n";
3400             pr "  }\n";
3401       );
3402
3403       pr " done:\n";
3404       pr "  ctx->cb_sequence = 1;\n";
3405       pr "}\n\n";
3406
3407       (* Generate the action stub. *)
3408       generate_prototype ~extern:false ~semicolon:false ~newline:true
3409         ~handle:"g" name style;
3410
3411       let error_code =
3412         match fst style with
3413         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3414         | RConstString _ ->
3415             failwithf "RConstString cannot be returned from a daemon function"
3416         | RString _ | RStringList _ | RIntBool _
3417         | RPVList _ | RVGList _ | RLVList _
3418         | RStat _ | RStatVFS _
3419         | RHashtable _ ->
3420             "NULL" in
3421
3422       pr "{\n";
3423
3424       (match snd style with
3425        | [] -> ()
3426        | _ -> pr "  struct %s_args args;\n" name
3427       );
3428
3429       pr "  struct %s_ctx ctx;\n" shortname;
3430       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3431       pr "  int serial;\n";
3432       pr "\n";
3433       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3434       pr "  guestfs_set_busy (g);\n";
3435       pr "\n";
3436       pr "  memset (&ctx, 0, sizeof ctx);\n";
3437       pr "\n";
3438
3439       (* Send the main header and arguments. *)
3440       (match snd style with
3441        | [] ->
3442            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3443              (String.uppercase shortname)
3444        | args ->
3445            List.iter (
3446              function
3447              | String n ->
3448                  pr "  args.%s = (char *) %s;\n" n n
3449              | OptString n ->
3450                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
3451              | StringList n ->
3452                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
3453                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3454              | Bool n ->
3455                  pr "  args.%s = %s;\n" n n
3456              | Int n ->
3457                  pr "  args.%s = %s;\n" n n
3458              | FileIn _ | FileOut _ -> ()
3459            ) args;
3460            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3461              (String.uppercase shortname);
3462            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3463              name;
3464       );
3465       pr "  if (serial == -1) {\n";
3466       pr "    guestfs_end_busy (g);\n";
3467       pr "    return %s;\n" error_code;
3468       pr "  }\n";
3469       pr "\n";
3470
3471       (* Send any additional files (FileIn) requested. *)
3472       let need_read_reply_label = ref false in
3473       List.iter (
3474         function
3475         | FileIn n ->
3476             pr "  {\n";
3477             pr "    int r;\n";
3478             pr "\n";
3479             pr "    r = guestfs__send_file_sync (g, %s);\n" n;
3480             pr "    if (r == -1) {\n";
3481             pr "      guestfs_end_busy (g);\n";
3482             pr "      return %s;\n" error_code;
3483             pr "    }\n";
3484             pr "    if (r == -2) /* daemon cancelled */\n";
3485             pr "      goto read_reply;\n";
3486             need_read_reply_label := true;
3487             pr "  }\n";
3488             pr "\n";
3489         | _ -> ()
3490       ) (snd style);
3491
3492       (* Wait for the reply from the remote end. *)
3493       if !need_read_reply_label then pr " read_reply:\n";
3494       pr "  guestfs__switch_to_receiving (g);\n";
3495       pr "  ctx.cb_sequence = 0;\n";
3496       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3497       pr "  (void) ml->main_loop_run (ml, g);\n";
3498       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
3499       pr "  if (ctx.cb_sequence != 1) {\n";
3500       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3501       pr "    guestfs_end_busy (g);\n";
3502       pr "    return %s;\n" error_code;
3503       pr "  }\n";
3504       pr "\n";
3505
3506       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3507         (String.uppercase shortname);
3508       pr "    guestfs_end_busy (g);\n";
3509       pr "    return %s;\n" error_code;
3510       pr "  }\n";
3511       pr "\n";
3512
3513       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3514       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
3515       pr "    free (ctx.err.error_message);\n";
3516       pr "    guestfs_end_busy (g);\n";
3517       pr "    return %s;\n" error_code;
3518       pr "  }\n";
3519       pr "\n";
3520
3521       (* Expecting to receive further files (FileOut)? *)
3522       List.iter (
3523         function
3524         | FileOut n ->
3525             pr "  if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3526             pr "    guestfs_end_busy (g);\n";
3527             pr "    return %s;\n" error_code;
3528             pr "  }\n";
3529             pr "\n";
3530         | _ -> ()
3531       ) (snd style);
3532
3533       pr "  guestfs_end_busy (g);\n";
3534
3535       (match fst style with
3536        | RErr -> pr "  return 0;\n"
3537        | RInt n | RInt64 n | RBool n ->
3538            pr "  return ctx.ret.%s;\n" n
3539        | RConstString _ ->
3540            failwithf "RConstString cannot be returned from a daemon function"
3541        | RString n ->
3542            pr "  return ctx.ret.%s; /* caller will free */\n" n
3543        | RStringList n | RHashtable n ->
3544            pr "  /* caller will free this, but we need to add a NULL entry */\n";
3545            pr "  ctx.ret.%s.%s_val =\n" n n;
3546            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3547            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3548              n n;
3549            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3550            pr "  return ctx.ret.%s.%s_val;\n" n n
3551        | RIntBool _ ->
3552            pr "  /* caller with free this */\n";
3553            pr "  return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3554        | RPVList n | RVGList n | RLVList n
3555        | RStat n | RStatVFS n ->
3556            pr "  /* caller will free this */\n";
3557            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3558       );
3559
3560       pr "}\n\n"
3561   ) daemon_functions
3562
3563 (* Generate daemon/actions.h. *)
3564 and generate_daemon_actions_h () =
3565   generate_header CStyle GPLv2;
3566
3567   pr "#include \"../src/guestfs_protocol.h\"\n";
3568   pr "\n";
3569
3570   List.iter (
3571     fun (name, style, _, _, _, _, _) ->
3572         generate_prototype
3573           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3574           name style;
3575   ) daemon_functions
3576
3577 (* Generate the server-side stubs. *)
3578 and generate_daemon_actions () =
3579   generate_header CStyle GPLv2;
3580
3581   pr "#include <config.h>\n";
3582   pr "\n";
3583   pr "#include <stdio.h>\n";
3584   pr "#include <stdlib.h>\n";
3585   pr "#include <string.h>\n";
3586   pr "#include <inttypes.h>\n";
3587   pr "#include <ctype.h>\n";
3588   pr "#include <rpc/types.h>\n";
3589   pr "#include <rpc/xdr.h>\n";
3590   pr "\n";
3591   pr "#include \"daemon.h\"\n";
3592   pr "#include \"../src/guestfs_protocol.h\"\n";
3593   pr "#include \"actions.h\"\n";
3594   pr "\n";
3595
3596   List.iter (
3597     fun (name, style, _, _, _, _, _) ->
3598       (* Generate server-side stubs. *)
3599       pr "static void %s_stub (XDR *xdr_in)\n" name;
3600       pr "{\n";
3601       let error_code =
3602         match fst style with
3603         | RErr | RInt _ -> pr "  int r;\n"; "-1"
3604         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
3605         | RBool _ -> pr "  int r;\n"; "-1"
3606         | RConstString _ ->
3607             failwithf "RConstString cannot be returned from a daemon function"
3608         | RString _ -> pr "  char *r;\n"; "NULL"
3609         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
3610         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
3611         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
3612         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
3613         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL"
3614         | RStat _ -> pr "  guestfs_int_stat *r;\n"; "NULL"
3615         | RStatVFS _ -> pr "  guestfs_int_statvfs *r;\n"; "NULL" in
3616
3617       (match snd style with
3618        | [] -> ()
3619        | args ->
3620            pr "  struct guestfs_%s_args args;\n" name;
3621            List.iter (
3622              function
3623                (* Note we allow the string to be writable, in order to
3624                 * allow device name translation.  This is safe because
3625                 * we can modify the string (passed from RPC).
3626                 *)
3627              | String n
3628              | OptString n -> pr "  char *%s;\n" n
3629              | StringList n -> pr "  char **%s;\n" n
3630              | Bool n -> pr "  int %s;\n" n
3631              | Int n -> pr "  int %s;\n" n
3632              | FileIn _ | FileOut _ -> ()
3633            ) args
3634       );
3635       pr "\n";
3636
3637       (match snd style with
3638        | [] -> ()
3639        | args ->
3640            pr "  memset (&args, 0, sizeof args);\n";
3641            pr "\n";
3642            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
3643            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
3644            pr "    return;\n";
3645            pr "  }\n";
3646            List.iter (
3647              function
3648              | String n -> pr "  %s = args.%s;\n" n n
3649              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
3650              | StringList n ->
3651                  pr "  %s = realloc (args.%s.%s_val,\n" n n n;
3652                  pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
3653                  pr "  if (%s == NULL) {\n" n;
3654                  pr "    reply_with_perror (\"realloc\");\n";
3655                  pr "    goto done;\n";
3656                  pr "  }\n";
3657                  pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
3658                  pr "  args.%s.%s_val = %s;\n" n n n;
3659              | Bool n -> pr "  %s = args.%s;\n" n n
3660              | Int n -> pr "  %s = args.%s;\n" n n
3661              | FileIn _ | FileOut _ -> ()
3662            ) args;
3663            pr "\n"
3664       );
3665
3666       (* Don't want to call the impl with any FileIn or FileOut
3667        * parameters, since these go "outside" the RPC protocol.
3668        *)
3669       let argsnofile =
3670         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
3671           (snd style) in
3672       pr "  r = do_%s " name;
3673       generate_call_args argsnofile;
3674       pr ";\n";
3675
3676       pr "  if (r == %s)\n" error_code;
3677       pr "    /* do_%s has already called reply_with_error */\n" name;
3678       pr "    goto done;\n";
3679       pr "\n";
3680
3681       (* If there are any FileOut parameters, then the impl must
3682        * send its own reply.
3683        *)
3684       let no_reply =
3685         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
3686       if no_reply then
3687         pr "  /* do_%s has already sent a reply */\n" name
3688       else (
3689         match fst style with
3690         | RErr -> pr "  reply (NULL, NULL);\n"
3691         | RInt n | RInt64 n | RBool n ->
3692             pr "  struct guestfs_%s_ret ret;\n" name;
3693             pr "  ret.%s = r;\n" n;
3694             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3695               name
3696         | RConstString _ ->
3697             failwithf "RConstString cannot be returned from a daemon function"
3698         | RString n ->
3699             pr "  struct guestfs_%s_ret ret;\n" name;
3700             pr "  ret.%s = r;\n" n;
3701             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3702               name;
3703             pr "  free (r);\n"
3704         | RStringList n | RHashtable n ->
3705             pr "  struct guestfs_%s_ret ret;\n" name;
3706             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
3707             pr "  ret.%s.%s_val = r;\n" n n;
3708             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3709               name;
3710             pr "  free_strings (r);\n"
3711         | RIntBool _ ->
3712             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
3713               name;
3714             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
3715         | RPVList n | RVGList n | RLVList n
3716         | RStat n | RStatVFS n ->
3717             pr "  struct guestfs_%s_ret ret;\n" name;
3718             pr "  ret.%s = *r;\n" n;
3719             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3720               name;
3721             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
3722               name
3723       );
3724
3725       (* Free the args. *)
3726       (match snd style with
3727        | [] ->
3728            pr "done: ;\n";
3729        | _ ->
3730            pr "done:\n";
3731            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
3732              name
3733       );
3734
3735       pr "}\n\n";
3736   ) daemon_functions;
3737
3738   (* Dispatch function. *)
3739   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
3740   pr "{\n";
3741   pr "  switch (proc_nr) {\n";
3742
3743   List.iter (
3744     fun (name, style, _, _, _, _, _) ->
3745         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
3746         pr "      %s_stub (xdr_in);\n" name;
3747         pr "      break;\n"
3748   ) daemon_functions;
3749
3750   pr "    default:\n";
3751   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";
3752   pr "  }\n";
3753   pr "}\n";
3754   pr "\n";
3755
3756   (* LVM columns and tokenization functions. *)
3757   (* XXX This generates crap code.  We should rethink how we
3758    * do this parsing.
3759    *)
3760   List.iter (
3761     function
3762     | typ, cols ->
3763         pr "static const char *lvm_%s_cols = \"%s\";\n"
3764           typ (String.concat "," (List.map fst cols));
3765         pr "\n";
3766
3767         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
3768         pr "{\n";
3769         pr "  char *tok, *p, *next;\n";
3770         pr "  int i, j;\n";
3771         pr "\n";
3772         (*
3773         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
3774         pr "\n";
3775         *)
3776         pr "  if (!str) {\n";
3777         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
3778         pr "    return -1;\n";
3779         pr "  }\n";
3780         pr "  if (!*str || isspace (*str)) {\n";
3781         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
3782         pr "    return -1;\n";
3783         pr "  }\n";
3784         pr "  tok = str;\n";
3785         List.iter (
3786           fun (name, coltype) ->
3787             pr "  if (!tok) {\n";
3788             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
3789             pr "    return -1;\n";
3790             pr "  }\n";
3791             pr "  p = strchrnul (tok, ',');\n";
3792             pr "  if (*p) next = p+1; else next = NULL;\n";
3793             pr "  *p = '\\0';\n";
3794             (match coltype with
3795              | `String ->
3796                  pr "  r->%s = strdup (tok);\n" name;
3797                  pr "  if (r->%s == NULL) {\n" name;
3798                  pr "    perror (\"strdup\");\n";
3799                  pr "    return -1;\n";
3800                  pr "  }\n"
3801              | `UUID ->
3802                  pr "  for (i = j = 0; i < 32; ++j) {\n";
3803                  pr "    if (tok[j] == '\\0') {\n";
3804                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
3805                  pr "      return -1;\n";
3806                  pr "    } else if (tok[j] != '-')\n";
3807                  pr "      r->%s[i++] = tok[j];\n" name;
3808                  pr "  }\n";
3809              | `Bytes ->
3810                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
3811                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3812                  pr "    return -1;\n";
3813                  pr "  }\n";
3814              | `Int ->
3815                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
3816                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3817                  pr "    return -1;\n";
3818                  pr "  }\n";
3819              | `OptPercent ->
3820                  pr "  if (tok[0] == '\\0')\n";
3821                  pr "    r->%s = -1;\n" name;
3822                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
3823                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
3824                  pr "    return -1;\n";
3825                  pr "  }\n";
3826             );
3827             pr "  tok = next;\n";
3828         ) cols;
3829
3830         pr "  if (tok != NULL) {\n";
3831         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
3832         pr "    return -1;\n";
3833         pr "  }\n";
3834         pr "  return 0;\n";
3835         pr "}\n";
3836         pr "\n";
3837
3838         pr "guestfs_lvm_int_%s_list *\n" typ;
3839         pr "parse_command_line_%ss (void)\n" typ;
3840         pr "{\n";
3841         pr "  char *out, *err;\n";
3842         pr "  char *p, *pend;\n";
3843         pr "  int r, i;\n";
3844         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
3845         pr "  void *newp;\n";
3846         pr "\n";
3847         pr "  ret = malloc (sizeof *ret);\n";
3848         pr "  if (!ret) {\n";
3849         pr "    reply_with_perror (\"malloc\");\n";
3850         pr "    return NULL;\n";
3851         pr "  }\n";
3852         pr "\n";
3853         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
3854         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
3855         pr "\n";
3856         pr "  r = command (&out, &err,\n";
3857         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
3858         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
3859         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
3860         pr "  if (r == -1) {\n";
3861         pr "    reply_with_error (\"%%s\", err);\n";
3862         pr "    free (out);\n";
3863         pr "    free (err);\n";
3864         pr "    free (ret);\n";
3865         pr "    return NULL;\n";
3866         pr "  }\n";
3867         pr "\n";
3868         pr "  free (err);\n";
3869         pr "\n";
3870         pr "  /* Tokenize each line of the output. */\n";
3871         pr "  p = out;\n";
3872         pr "  i = 0;\n";
3873         pr "  while (p) {\n";
3874         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
3875         pr "    if (pend) {\n";
3876         pr "      *pend = '\\0';\n";
3877         pr "      pend++;\n";
3878         pr "    }\n";
3879         pr "\n";
3880         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
3881         pr "      p++;\n";
3882         pr "\n";
3883         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
3884         pr "      p = pend;\n";
3885         pr "      continue;\n";
3886         pr "    }\n";
3887         pr "\n";
3888         pr "    /* Allocate some space to store this next entry. */\n";
3889         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
3890         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
3891         pr "    if (newp == NULL) {\n";
3892         pr "      reply_with_perror (\"realloc\");\n";
3893         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3894         pr "      free (ret);\n";
3895         pr "      free (out);\n";
3896         pr "      return NULL;\n";
3897         pr "    }\n";
3898         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
3899         pr "\n";
3900         pr "    /* Tokenize the next entry. */\n";
3901         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
3902         pr "    if (r == -1) {\n";
3903         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
3904         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
3905         pr "      free (ret);\n";
3906         pr "      free (out);\n";
3907         pr "      return NULL;\n";
3908         pr "    }\n";
3909         pr "\n";
3910         pr "    ++i;\n";
3911         pr "    p = pend;\n";
3912         pr "  }\n";
3913         pr "\n";
3914         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
3915         pr "\n";
3916         pr "  free (out);\n";
3917         pr "  return ret;\n";
3918         pr "}\n"
3919
3920   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3921
3922 (* Generate the tests. *)
3923 and generate_tests () =
3924   generate_header CStyle GPLv2;
3925
3926   pr "\
3927 #include <stdio.h>
3928 #include <stdlib.h>
3929 #include <string.h>
3930 #include <unistd.h>
3931 #include <sys/types.h>
3932 #include <fcntl.h>
3933
3934 #include \"guestfs.h\"
3935
3936 static guestfs_h *g;
3937 static int suppress_error = 0;
3938
3939 static void print_error (guestfs_h *g, void *data, const char *msg)
3940 {
3941   if (!suppress_error)
3942     fprintf (stderr, \"%%s\\n\", msg);
3943 }
3944
3945 static void print_strings (char * const * const argv)
3946 {
3947   int argc;
3948
3949   for (argc = 0; argv[argc] != NULL; ++argc)
3950     printf (\"\\t%%s\\n\", argv[argc]);
3951 }
3952
3953 /*
3954 static void print_table (char * const * const argv)
3955 {
3956   int i;
3957
3958   for (i = 0; argv[i] != NULL; i += 2)
3959     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
3960 }
3961 */
3962
3963 static void no_test_warnings (void)
3964 {
3965 ";
3966
3967   List.iter (
3968     function
3969     | name, _, _, _, [], _, _ ->
3970         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
3971     | name, _, _, _, tests, _, _ -> ()
3972   ) all_functions;
3973
3974   pr "}\n";
3975   pr "\n";
3976
3977   (* Generate the actual tests.  Note that we generate the tests
3978    * in reverse order, deliberately, so that (in general) the
3979    * newest tests run first.  This makes it quicker and easier to
3980    * debug them.
3981    *)
3982   let test_names =
3983     List.map (
3984       fun (name, _, _, _, tests, _, _) ->
3985         mapi (generate_one_test name) tests
3986     ) (List.rev all_functions) in
3987   let test_names = List.concat test_names in
3988   let nr_tests = List.length test_names in
3989
3990   pr "\
3991 int main (int argc, char *argv[])
3992 {
3993   char c = 0;
3994   int failed = 0;
3995   const char *filename;
3996   int fd;
3997   int nr_tests, test_num = 0;
3998
3999   no_test_warnings ();
4000
4001   g = guestfs_create ();
4002   if (g == NULL) {
4003     printf (\"guestfs_create FAILED\\n\");
4004     exit (1);
4005   }
4006
4007   guestfs_set_error_handler (g, print_error, NULL);
4008
4009   guestfs_set_path (g, \"../appliance\");
4010
4011   filename = \"test1.img\";
4012   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4013   if (fd == -1) {
4014     perror (filename);
4015     exit (1);
4016   }
4017   if (lseek (fd, %d, SEEK_SET) == -1) {
4018     perror (\"lseek\");
4019     close (fd);
4020     unlink (filename);
4021     exit (1);
4022   }
4023   if (write (fd, &c, 1) == -1) {
4024     perror (\"write\");
4025     close (fd);
4026     unlink (filename);
4027     exit (1);
4028   }
4029   if (close (fd) == -1) {
4030     perror (filename);
4031     unlink (filename);
4032     exit (1);
4033   }
4034   if (guestfs_add_drive (g, filename) == -1) {
4035     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4036     exit (1);
4037   }
4038
4039   filename = \"test2.img\";
4040   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4041   if (fd == -1) {
4042     perror (filename);
4043     exit (1);
4044   }
4045   if (lseek (fd, %d, SEEK_SET) == -1) {
4046     perror (\"lseek\");
4047     close (fd);
4048     unlink (filename);
4049     exit (1);
4050   }
4051   if (write (fd, &c, 1) == -1) {
4052     perror (\"write\");
4053     close (fd);
4054     unlink (filename);
4055     exit (1);
4056   }
4057   if (close (fd) == -1) {
4058     perror (filename);
4059     unlink (filename);
4060     exit (1);
4061   }
4062   if (guestfs_add_drive (g, filename) == -1) {
4063     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4064     exit (1);
4065   }
4066
4067   filename = \"test3.img\";
4068   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4069   if (fd == -1) {
4070     perror (filename);
4071     exit (1);
4072   }
4073   if (lseek (fd, %d, SEEK_SET) == -1) {
4074     perror (\"lseek\");
4075     close (fd);
4076     unlink (filename);
4077     exit (1);
4078   }
4079   if (write (fd, &c, 1) == -1) {
4080     perror (\"write\");
4081     close (fd);
4082     unlink (filename);
4083     exit (1);
4084   }
4085   if (close (fd) == -1) {
4086     perror (filename);
4087     unlink (filename);
4088     exit (1);
4089   }
4090   if (guestfs_add_drive (g, filename) == -1) {
4091     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4092     exit (1);
4093   }
4094
4095   if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4096     printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4097     exit (1);
4098   }
4099
4100   if (guestfs_launch (g) == -1) {
4101     printf (\"guestfs_launch FAILED\\n\");
4102     exit (1);
4103   }
4104
4105   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4106   alarm (600);
4107
4108   if (guestfs_wait_ready (g) == -1) {
4109     printf (\"guestfs_wait_ready FAILED\\n\");
4110     exit (1);
4111   }
4112
4113   /* Cancel previous alarm. */
4114   alarm (0);
4115
4116   nr_tests = %d;
4117
4118 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4119
4120   iteri (
4121     fun i test_name ->
4122       pr "  test_num++;\n";
4123       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4124       pr "  if (%s () == -1) {\n" test_name;
4125       pr "    printf (\"%s FAILED\\n\");\n" test_name;
4126       pr "    failed++;\n";
4127       pr "  }\n";
4128   ) test_names;
4129   pr "\n";
4130
4131   pr "  guestfs_close (g);\n";
4132   pr "  unlink (\"test1.img\");\n";
4133   pr "  unlink (\"test2.img\");\n";
4134   pr "  unlink (\"test3.img\");\n";
4135   pr "\n";
4136
4137   pr "  if (failed > 0) {\n";
4138   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4139   pr "    exit (1);\n";
4140   pr "  }\n";
4141   pr "\n";
4142
4143   pr "  exit (0);\n";
4144   pr "}\n"
4145
4146 and generate_one_test name i (init, prereq, test) =
4147   let test_name = sprintf "test_%s_%d" name i in
4148
4149   pr "\
4150 static int %s_skip (void)
4151 {
4152   const char *str;
4153
4154   str = getenv (\"SKIP_%s\");
4155   if (str && strcmp (str, \"1\") == 0) return 1;
4156   str = getenv (\"SKIP_TEST_%s\");
4157   if (str && strcmp (str, \"1\") == 0) return 1;
4158   return 0;
4159 }
4160
4161 " test_name (String.uppercase test_name) (String.uppercase name);
4162
4163   (match prereq with
4164    | Disabled | Always -> ()
4165    | If code | Unless code ->
4166        pr "static int %s_prereq (void)\n" test_name;
4167        pr "{\n";
4168        pr "  %s\n" code;
4169        pr "}\n";
4170        pr "\n";
4171   );
4172
4173   pr "\
4174 static int %s (void)
4175 {
4176   if (%s_skip ()) {
4177     printf (\"%%s skipped (reason: SKIP_TEST_* variable set)\\n\", \"%s\");
4178     return 0;
4179   }
4180
4181 " test_name test_name test_name;
4182
4183   (match prereq with
4184    | Disabled ->
4185        pr "  printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4186    | If _ ->
4187        pr "  if (! %s_prereq ()) {\n" test_name;
4188        pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4189        pr "    return 0;\n";
4190        pr "  }\n";
4191        pr "\n";
4192        generate_one_test_body name i test_name init test;
4193    | Unless _ ->
4194        pr "  if (%s_prereq ()) {\n" test_name;
4195        pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4196        pr "    return 0;\n";
4197        pr "  }\n";
4198        pr "\n";
4199        generate_one_test_body name i test_name init test;
4200    | Always ->
4201        generate_one_test_body name i test_name init test
4202   );
4203
4204   pr "  return 0;\n";
4205   pr "}\n";
4206   pr "\n";
4207   test_name
4208
4209 and generate_one_test_body name i test_name init test =
4210   (match init with
4211    | InitNone
4212    | InitEmpty ->
4213        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
4214        List.iter (generate_test_command_call test_name)
4215          [["blockdev_setrw"; "/dev/sda"];
4216           ["umount_all"];
4217           ["lvm_remove_all"]]
4218    | InitBasicFS ->
4219        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4220        List.iter (generate_test_command_call test_name)
4221          [["blockdev_setrw"; "/dev/sda"];
4222           ["umount_all"];
4223           ["lvm_remove_all"];
4224           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4225           ["mkfs"; "ext2"; "/dev/sda1"];
4226           ["mount"; "/dev/sda1"; "/"]]
4227    | InitBasicFSonLVM ->
4228        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4229          test_name;
4230        List.iter (generate_test_command_call test_name)
4231          [["blockdev_setrw"; "/dev/sda"];
4232           ["umount_all"];
4233           ["lvm_remove_all"];
4234           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4235           ["pvcreate"; "/dev/sda1"];
4236           ["vgcreate"; "VG"; "/dev/sda1"];
4237           ["lvcreate"; "LV"; "VG"; "8"];
4238           ["mkfs"; "ext2"; "/dev/VG/LV"];
4239           ["mount"; "/dev/VG/LV"; "/"]]
4240   );
4241
4242   let get_seq_last = function
4243     | [] ->
4244         failwithf "%s: you cannot use [] (empty list) when expecting a command"
4245           test_name
4246     | seq ->
4247         let seq = List.rev seq in
4248         List.rev (List.tl seq), List.hd seq
4249   in
4250
4251   match test with
4252   | TestRun seq ->
4253       pr "  /* TestRun for %s (%d) */\n" name i;
4254       List.iter (generate_test_command_call test_name) seq
4255   | TestOutput (seq, expected) ->
4256       pr "  /* TestOutput for %s (%d) */\n" name i;
4257       pr "  char expected[] = \"%s\";\n" (c_quote expected);
4258       let seq, last = get_seq_last seq in
4259       let test () =
4260         pr "    if (strcmp (r, expected) != 0) {\n";
4261         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4262         pr "      return -1;\n";
4263         pr "    }\n"
4264       in
4265       List.iter (generate_test_command_call test_name) seq;
4266       generate_test_command_call ~test test_name last
4267   | TestOutputList (seq, expected) ->
4268       pr "  /* TestOutputList for %s (%d) */\n" name i;
4269       let seq, last = get_seq_last seq in
4270       let test () =
4271         iteri (
4272           fun i str ->
4273             pr "    if (!r[%d]) {\n" i;
4274             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4275             pr "      print_strings (r);\n";
4276             pr "      return -1;\n";
4277             pr "    }\n";
4278             pr "    {\n";
4279             pr "      char expected[] = \"%s\";\n" (c_quote str);
4280             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
4281             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4282             pr "        return -1;\n";
4283             pr "      }\n";
4284             pr "    }\n"
4285         ) expected;
4286         pr "    if (r[%d] != NULL) {\n" (List.length expected);
4287         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4288           test_name;
4289         pr "      print_strings (r);\n";
4290         pr "      return -1;\n";
4291         pr "    }\n"
4292       in
4293       List.iter (generate_test_command_call test_name) seq;
4294       generate_test_command_call ~test test_name last
4295   | TestOutputListOfDevices (seq, expected) ->
4296       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
4297       let seq, last = get_seq_last seq in
4298       let test () =
4299         iteri (
4300           fun i str ->
4301             pr "    if (!r[%d]) {\n" i;
4302             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4303             pr "      print_strings (r);\n";
4304             pr "      return -1;\n";
4305             pr "    }\n";
4306             pr "    {\n";
4307             pr "      char expected[] = \"%s\";\n" (c_quote str);
4308             pr "      r[%d][5] = 's';\n" i;
4309             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
4310             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4311             pr "        return -1;\n";
4312             pr "      }\n";
4313             pr "    }\n"
4314         ) expected;
4315         pr "    if (r[%d] != NULL) {\n" (List.length expected);
4316         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4317           test_name;
4318         pr "      print_strings (r);\n";
4319         pr "      return -1;\n";
4320         pr "    }\n"
4321       in
4322       List.iter (generate_test_command_call test_name) seq;
4323       generate_test_command_call ~test test_name last
4324   | TestOutputInt (seq, expected) ->
4325       pr "  /* TestOutputInt for %s (%d) */\n" name i;
4326       let seq, last = get_seq_last seq in
4327       let test () =
4328         pr "    if (r != %d) {\n" expected;
4329         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4330           test_name expected;
4331         pr "               (int) r);\n";
4332         pr "      return -1;\n";
4333         pr "    }\n"
4334       in
4335       List.iter (generate_test_command_call test_name) seq;
4336       generate_test_command_call ~test test_name last
4337   | TestOutputTrue seq ->
4338       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
4339       let seq, last = get_seq_last seq in
4340       let test () =
4341         pr "    if (!r) {\n";
4342         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4343           test_name;
4344         pr "      return -1;\n";
4345         pr "    }\n"
4346       in
4347       List.iter (generate_test_command_call test_name) seq;
4348       generate_test_command_call ~test test_name last
4349   | TestOutputFalse seq ->
4350       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
4351       let seq, last = get_seq_last seq in
4352       let test () =
4353         pr "    if (r) {\n";
4354         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4355           test_name;
4356         pr "      return -1;\n";
4357         pr "    }\n"
4358       in
4359       List.iter (generate_test_command_call test_name) seq;
4360       generate_test_command_call ~test test_name last
4361   | TestOutputLength (seq, expected) ->
4362       pr "  /* TestOutputLength for %s (%d) */\n" name i;
4363       let seq, last = get_seq_last seq in
4364       let test () =
4365         pr "    int j;\n";
4366         pr "    for (j = 0; j < %d; ++j)\n" expected;
4367         pr "      if (r[j] == NULL) {\n";
4368         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
4369           test_name;
4370         pr "        print_strings (r);\n";
4371         pr "        return -1;\n";
4372         pr "      }\n";
4373         pr "    if (r[j] != NULL) {\n";
4374         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
4375           test_name;
4376         pr "      print_strings (r);\n";
4377         pr "      return -1;\n";
4378         pr "    }\n"
4379       in
4380       List.iter (generate_test_command_call test_name) seq;
4381       generate_test_command_call ~test test_name last
4382   | TestOutputStruct (seq, checks) ->
4383       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
4384       let seq, last = get_seq_last seq in
4385       let test () =
4386         List.iter (
4387           function
4388           | CompareWithInt (field, expected) ->
4389               pr "    if (r->%s != %d) {\n" field expected;
4390               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4391                 test_name field expected;
4392               pr "               (int) r->%s);\n" field;
4393               pr "      return -1;\n";
4394               pr "    }\n"
4395           | CompareWithString (field, expected) ->
4396               pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4397               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4398                 test_name field expected;
4399               pr "               r->%s);\n" field;
4400               pr "      return -1;\n";
4401               pr "    }\n"
4402           | CompareFieldsIntEq (field1, field2) ->
4403               pr "    if (r->%s != r->%s) {\n" field1 field2;
4404               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4405                 test_name field1 field2;
4406               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
4407               pr "      return -1;\n";
4408               pr "    }\n"
4409           | CompareFieldsStrEq (field1, field2) ->
4410               pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4411               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4412                 test_name field1 field2;
4413               pr "               r->%s, r->%s);\n" field1 field2;
4414               pr "      return -1;\n";
4415               pr "    }\n"
4416         ) checks
4417       in
4418       List.iter (generate_test_command_call test_name) seq;
4419       generate_test_command_call ~test test_name last
4420   | TestLastFail seq ->
4421       pr "  /* TestLastFail for %s (%d) */\n" name i;
4422       let seq, last = get_seq_last seq in
4423       List.iter (generate_test_command_call test_name) seq;
4424       generate_test_command_call test_name ~expect_error:true last
4425
4426 (* Generate the code to run a command, leaving the result in 'r'.
4427  * If you expect to get an error then you should set expect_error:true.
4428  *)
4429 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4430   match cmd with
4431   | [] -> assert false
4432   | name :: args ->
4433       (* Look up the command to find out what args/ret it has. *)
4434       let style =
4435         try
4436           let _, style, _, _, _, _, _ =
4437             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4438           style
4439         with Not_found ->
4440           failwithf "%s: in test, command %s was not found" test_name name in
4441
4442       if List.length (snd style) <> List.length args then
4443         failwithf "%s: in test, wrong number of args given to %s"
4444           test_name name;
4445
4446       pr "  {\n";
4447
4448       List.iter (
4449         function
4450         | OptString n, "NULL" -> ()
4451         | String n, arg
4452         | OptString n, arg ->
4453             pr "    char %s[] = \"%s\";\n" n (c_quote arg);
4454         | Int _, _
4455         | Bool _, _
4456         | FileIn _, _ | FileOut _, _ -> ()
4457         | StringList n, arg ->
4458             let strs = string_split " " arg in
4459             iteri (
4460               fun i str ->
4461                 pr "    char %s_%d[] = \"%s\";\n" n i (c_quote str);
4462             ) strs;
4463             pr "    char *%s[] = {\n" n;
4464             iteri (
4465               fun i _ -> pr "      %s_%d,\n" n i
4466             ) strs;
4467             pr "      NULL\n";
4468             pr "    };\n";
4469       ) (List.combine (snd style) args);
4470
4471       let error_code =
4472         match fst style with
4473         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
4474         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
4475         | RConstString _ -> pr "    const char *r;\n"; "NULL"
4476         | RString _ -> pr "    char *r;\n"; "NULL"
4477         | RStringList _ | RHashtable _ ->
4478             pr "    char **r;\n";
4479             pr "    int i;\n";
4480             "NULL"
4481         | RIntBool _ ->
4482             pr "    struct guestfs_int_bool *r;\n"; "NULL"
4483         | RPVList _ ->
4484             pr "    struct guestfs_lvm_pv_list *r;\n"; "NULL"
4485         | RVGList _ ->
4486             pr "    struct guestfs_lvm_vg_list *r;\n"; "NULL"
4487         | RLVList _ ->
4488             pr "    struct guestfs_lvm_lv_list *r;\n"; "NULL"
4489         | RStat _ ->
4490             pr "    struct guestfs_stat *r;\n"; "NULL"
4491         | RStatVFS _ ->
4492             pr "    struct guestfs_statvfs *r;\n"; "NULL" in
4493
4494       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
4495       pr "    r = guestfs_%s (g" name;
4496
4497       (* Generate the parameters. *)
4498       List.iter (
4499         function
4500         | OptString _, "NULL" -> pr ", NULL"
4501         | String n, _
4502         | OptString n, _ ->
4503             pr ", %s" n
4504         | FileIn _, arg | FileOut _, arg ->
4505             pr ", \"%s\"" (c_quote arg)
4506         | StringList n, _ ->
4507             pr ", %s" n
4508         | Int _, arg ->
4509             let i =
4510               try int_of_string arg
4511               with Failure "int_of_string" ->
4512                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4513             pr ", %d" i
4514         | Bool _, arg ->
4515             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4516       ) (List.combine (snd style) args);
4517
4518       pr ");\n";
4519       if not expect_error then
4520         pr "    if (r == %s)\n" error_code
4521       else
4522         pr "    if (r != %s)\n" error_code;
4523       pr "      return -1;\n";
4524
4525       (* Insert the test code. *)
4526       (match test with
4527        | None -> ()
4528        | Some f -> f ()
4529       );
4530
4531       (match fst style with
4532        | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4533        | RString _ -> pr "    free (r);\n"
4534        | RStringList _ | RHashtable _ ->
4535            pr "    for (i = 0; r[i] != NULL; ++i)\n";
4536            pr "      free (r[i]);\n";
4537            pr "    free (r);\n"
4538        | RIntBool _ ->
4539            pr "    guestfs_free_int_bool (r);\n"
4540        | RPVList _ ->
4541            pr "    guestfs_free_lvm_pv_list (r);\n"
4542        | RVGList _ ->
4543            pr "    guestfs_free_lvm_vg_list (r);\n"
4544        | RLVList _ ->
4545            pr "    guestfs_free_lvm_lv_list (r);\n"
4546        | RStat _ | RStatVFS _ ->
4547            pr "    free (r);\n"
4548       );
4549
4550       pr "  }\n"
4551
4552 and c_quote str =
4553   let str = replace_str str "\r" "\\r" in
4554   let str = replace_str str "\n" "\\n" in
4555   let str = replace_str str "\t" "\\t" in
4556   let str = replace_str str "\000" "\\0" in
4557   str
4558
4559 (* Generate a lot of different functions for guestfish. *)
4560 and generate_fish_cmds () =
4561   generate_header CStyle GPLv2;
4562
4563   let all_functions =
4564     List.filter (
4565       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4566     ) all_functions in
4567   let all_functions_sorted =
4568     List.filter (
4569       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4570     ) all_functions_sorted in
4571
4572   pr "#include <stdio.h>\n";
4573   pr "#include <stdlib.h>\n";
4574   pr "#include <string.h>\n";
4575   pr "#include <inttypes.h>\n";
4576   pr "\n";
4577   pr "#include <guestfs.h>\n";
4578   pr "#include \"fish.h\"\n";
4579   pr "\n";
4580
4581   (* list_commands function, which implements guestfish -h *)
4582   pr "void list_commands (void)\n";
4583   pr "{\n";
4584   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
4585   pr "  list_builtin_commands ();\n";
4586   List.iter (
4587     fun (name, _, _, flags, _, shortdesc, _) ->
4588       let name = replace_char name '_' '-' in
4589       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4590         name shortdesc
4591   ) all_functions_sorted;
4592   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4593   pr "}\n";
4594   pr "\n";
4595
4596   (* display_command function, which implements guestfish -h cmd *)
4597   pr "void display_command (const char *cmd)\n";
4598   pr "{\n";
4599   List.iter (
4600     fun (name, style, _, flags, _, shortdesc, longdesc) ->
4601       let name2 = replace_char name '_' '-' in
4602       let alias =
4603         try find_map (function FishAlias n -> Some n | _ -> None) flags
4604         with Not_found -> name in
4605       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4606       let synopsis =
4607         match snd style with
4608         | [] -> name2
4609         | args ->
4610             sprintf "%s <%s>"
4611               name2 (String.concat "> <" (List.map name_of_argt args)) in
4612
4613       let warnings =
4614         if List.mem ProtocolLimitWarning flags then
4615           ("\n\n" ^ protocol_limit_warning)
4616         else "" in
4617
4618       (* For DangerWillRobinson commands, we should probably have
4619        * guestfish prompt before allowing you to use them (especially
4620        * in interactive mode). XXX
4621        *)
4622       let warnings =
4623         warnings ^
4624           if List.mem DangerWillRobinson flags then
4625             ("\n\n" ^ danger_will_robinson)
4626           else "" in
4627
4628       let describe_alias =
4629         if name <> alias then
4630           sprintf "\n\nYou can use '%s' as an alias for this command." alias
4631         else "" in
4632
4633       pr "  if (";
4634       pr "strcasecmp (cmd, \"%s\") == 0" name;
4635       if name <> name2 then
4636         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4637       if name <> alias then
4638         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4639       pr ")\n";
4640       pr "    pod2text (\"%s - %s\", %S);\n"
4641         name2 shortdesc
4642         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4643       pr "  else\n"
4644   ) all_functions;
4645   pr "    display_builtin_command (cmd);\n";
4646   pr "}\n";
4647   pr "\n";
4648
4649   (* print_{pv,vg,lv}_list functions *)
4650   List.iter (
4651     function
4652     | typ, cols ->
4653         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4654         pr "{\n";
4655         pr "  int i;\n";
4656         pr "\n";
4657         List.iter (
4658           function
4659           | name, `String ->
4660               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4661           | name, `UUID ->
4662               pr "  printf (\"%s: \");\n" name;
4663               pr "  for (i = 0; i < 32; ++i)\n";
4664               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
4665               pr "  printf (\"\\n\");\n"
4666           | name, `Bytes ->
4667               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4668           | name, `Int ->
4669               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4670           | name, `OptPercent ->
4671               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4672                 typ name name typ name;
4673               pr "  else printf (\"%s: \\n\");\n" name
4674         ) cols;
4675         pr "}\n";
4676         pr "\n";
4677         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4678           typ typ typ;
4679         pr "{\n";
4680         pr "  int i;\n";
4681         pr "\n";
4682         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
4683         pr "    print_%s (&%ss->val[i]);\n" typ typ;
4684         pr "}\n";
4685         pr "\n";
4686   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4687
4688   (* print_{stat,statvfs} functions *)
4689   List.iter (
4690     function
4691     | typ, cols ->
4692         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4693         pr "{\n";
4694         List.iter (
4695           function
4696           | name, `Int ->
4697               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4698         ) cols;
4699         pr "}\n";
4700         pr "\n";
4701   ) ["stat", stat_cols; "statvfs", statvfs_cols];
4702
4703   (* run_<action> actions *)
4704   List.iter (
4705     fun (name, style, _, flags, _, _, _) ->
4706       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4707       pr "{\n";
4708       (match fst style with
4709        | RErr
4710        | RInt _
4711        | RBool _ -> pr "  int r;\n"
4712        | RInt64 _ -> pr "  int64_t r;\n"
4713        | RConstString _ -> pr "  const char *r;\n"
4714        | RString _ -> pr "  char *r;\n"
4715        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
4716        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
4717        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
4718        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
4719        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
4720        | RStat _ -> pr "  struct guestfs_stat *r;\n"
4721        | RStatVFS _ -> pr "  struct guestfs_statvfs *r;\n"
4722       );
4723       List.iter (
4724         function
4725         | String n
4726         | OptString n
4727         | FileIn n
4728         | FileOut n -> pr "  const char *%s;\n" n
4729         | StringList n -> pr "  char **%s;\n" n
4730         | Bool n -> pr "  int %s;\n" n
4731         | Int n -> pr "  int %s;\n" n
4732       ) (snd style);
4733
4734       (* Check and convert parameters. *)
4735       let argc_expected = List.length (snd style) in
4736       pr "  if (argc != %d) {\n" argc_expected;
4737       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
4738         argc_expected;
4739       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
4740       pr "    return -1;\n";
4741       pr "  }\n";
4742       iteri (
4743         fun i ->
4744           function
4745           | String name -> pr "  %s = argv[%d];\n" name i
4746           | OptString name ->
4747               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
4748                 name i i
4749           | FileIn name ->
4750               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
4751                 name i i
4752           | FileOut name ->
4753               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
4754                 name i i
4755           | StringList name ->
4756               pr "  %s = parse_string_list (argv[%d]);\n" name i
4757           | Bool name ->
4758               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
4759           | Int name ->
4760               pr "  %s = atoi (argv[%d]);\n" name i
4761       ) (snd style);
4762
4763       (* Call C API function. *)
4764       let fn =
4765         try find_map (function FishAction n -> Some n | _ -> None) flags
4766         with Not_found -> sprintf "guestfs_%s" name in
4767       pr "  r = %s " fn;
4768       generate_call_args ~handle:"g" (snd style);
4769       pr ";\n";
4770
4771       (* Check return value for errors and display command results. *)
4772       (match fst style with
4773        | RErr -> pr "  return r;\n"
4774        | RInt _ ->
4775            pr "  if (r == -1) return -1;\n";
4776            pr "  printf (\"%%d\\n\", r);\n";
4777            pr "  return 0;\n"
4778        | RInt64 _ ->
4779            pr "  if (r == -1) return -1;\n";
4780            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
4781            pr "  return 0;\n"
4782        | RBool _ ->
4783            pr "  if (r == -1) return -1;\n";
4784            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
4785            pr "  return 0;\n"
4786        | RConstString _ ->
4787            pr "  if (r == NULL) return -1;\n";
4788            pr "  printf (\"%%s\\n\", r);\n";
4789            pr "  return 0;\n"
4790        | RString _ ->
4791            pr "  if (r == NULL) return -1;\n";
4792            pr "  printf (\"%%s\\n\", r);\n";
4793            pr "  free (r);\n";
4794            pr "  return 0;\n"
4795        | RStringList _ ->
4796            pr "  if (r == NULL) return -1;\n";
4797            pr "  print_strings (r);\n";
4798            pr "  free_strings (r);\n";
4799            pr "  return 0;\n"
4800        | RIntBool _ ->
4801            pr "  if (r == NULL) return -1;\n";
4802            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
4803            pr "    r->b ? \"true\" : \"false\");\n";
4804            pr "  guestfs_free_int_bool (r);\n";
4805            pr "  return 0;\n"
4806        | RPVList _ ->
4807            pr "  if (r == NULL) return -1;\n";
4808            pr "  print_pv_list (r);\n";
4809            pr "  guestfs_free_lvm_pv_list (r);\n";
4810            pr "  return 0;\n"
4811        | RVGList _ ->
4812            pr "  if (r == NULL) return -1;\n";
4813            pr "  print_vg_list (r);\n";
4814            pr "  guestfs_free_lvm_vg_list (r);\n";
4815            pr "  return 0;\n"
4816        | RLVList _ ->
4817            pr "  if (r == NULL) return -1;\n";
4818            pr "  print_lv_list (r);\n";
4819            pr "  guestfs_free_lvm_lv_list (r);\n";
4820            pr "  return 0;\n"
4821        | RStat _ ->
4822            pr "  if (r == NULL) return -1;\n";
4823            pr "  print_stat (r);\n";
4824            pr "  free (r);\n";
4825            pr "  return 0;\n"
4826        | RStatVFS _ ->
4827            pr "  if (r == NULL) return -1;\n";
4828            pr "  print_statvfs (r);\n";
4829            pr "  free (r);\n";
4830            pr "  return 0;\n"
4831        | RHashtable _ ->
4832            pr "  if (r == NULL) return -1;\n";
4833            pr "  print_table (r);\n";
4834            pr "  free_strings (r);\n";
4835            pr "  return 0;\n"
4836       );
4837       pr "}\n";
4838       pr "\n"
4839   ) all_functions;
4840
4841   (* run_action function *)
4842   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
4843   pr "{\n";
4844   List.iter (
4845     fun (name, _, _, flags, _, _, _) ->
4846       let name2 = replace_char name '_' '-' in
4847       let alias =
4848         try find_map (function FishAlias n -> Some n | _ -> None) flags
4849         with Not_found -> name in
4850       pr "  if (";
4851       pr "strcasecmp (cmd, \"%s\") == 0" name;
4852       if name <> name2 then
4853         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4854       if name <> alias then
4855         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4856       pr ")\n";
4857       pr "    return run_%s (cmd, argc, argv);\n" name;
4858       pr "  else\n";
4859   ) all_functions;
4860   pr "    {\n";
4861   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
4862   pr "      return -1;\n";
4863   pr "    }\n";
4864   pr "  return 0;\n";
4865   pr "}\n";
4866   pr "\n"
4867
4868 (* Readline completion for guestfish. *)
4869 and generate_fish_completion () =
4870   generate_header CStyle GPLv2;
4871
4872   let all_functions =
4873     List.filter (
4874       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4875     ) all_functions in
4876
4877   pr "\
4878 #include <config.h>
4879
4880 #include <stdio.h>
4881 #include <stdlib.h>
4882 #include <string.h>
4883
4884 #ifdef HAVE_LIBREADLINE
4885 #include <readline/readline.h>
4886 #endif
4887
4888 #include \"fish.h\"
4889
4890 #ifdef HAVE_LIBREADLINE
4891
4892 static const char *const commands[] = {
4893   BUILTIN_COMMANDS_FOR_COMPLETION,
4894 ";
4895
4896   (* Get the commands, including the aliases.  They don't need to be
4897    * sorted - the generator() function just does a dumb linear search.
4898    *)
4899   let commands =
4900     List.map (
4901       fun (name, _, _, flags, _, _, _) ->
4902         let name2 = replace_char name '_' '-' in
4903         let alias =
4904           try find_map (function FishAlias n -> Some n | _ -> None) flags
4905           with Not_found -> name in
4906
4907         if name <> alias then [name2; alias] else [name2]
4908     ) all_functions in
4909   let commands = List.flatten commands in
4910
4911   List.iter (pr "  \"%s\",\n") commands;
4912
4913   pr "  NULL
4914 };
4915
4916 static char *
4917 generator (const char *text, int state)
4918 {
4919   static int index, len;
4920   const char *name;
4921
4922   if (!state) {
4923     index = 0;
4924     len = strlen (text);
4925   }
4926
4927   rl_attempted_completion_over = 1;
4928
4929   while ((name = commands[index]) != NULL) {
4930     index++;
4931     if (strncasecmp (name, text, len) == 0)
4932       return strdup (name);
4933   }
4934
4935   return NULL;
4936 }
4937
4938 #endif /* HAVE_LIBREADLINE */
4939
4940 char **do_completion (const char *text, int start, int end)
4941 {
4942   char **matches = NULL;
4943
4944 #ifdef HAVE_LIBREADLINE
4945   rl_completion_append_character = ' ';
4946
4947   if (start == 0)
4948     matches = rl_completion_matches (text, generator);
4949   else if (complete_dest_paths)
4950     matches = rl_completion_matches (text, complete_dest_paths_generator);
4951 #endif
4952
4953   return matches;
4954 }
4955 ";
4956
4957 (* Generate the POD documentation for guestfish. *)
4958 and generate_fish_actions_pod () =
4959   let all_functions_sorted =
4960     List.filter (
4961       fun (_, _, _, flags, _, _, _) ->
4962         not (List.mem NotInFish flags || List.mem NotInDocs flags)
4963     ) all_functions_sorted in
4964
4965   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
4966
4967   List.iter (
4968     fun (name, style, _, flags, _, _, longdesc) ->
4969       let longdesc =
4970         Str.global_substitute rex (
4971           fun s ->
4972             let sub =
4973               try Str.matched_group 1 s
4974               with Not_found ->
4975                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
4976             "C<" ^ replace_char sub '_' '-' ^ ">"
4977         ) longdesc in
4978       let name = replace_char name '_' '-' in
4979       let alias =
4980         try find_map (function FishAlias n -> Some n | _ -> None) flags
4981         with Not_found -> name in
4982
4983       pr "=head2 %s" name;
4984       if name <> alias then
4985         pr " | %s" alias;
4986       pr "\n";
4987       pr "\n";
4988       pr " %s" name;
4989       List.iter (
4990         function
4991         | String n -> pr " %s" n
4992         | OptString n -> pr " %s" n
4993         | StringList n -> pr " '%s ...'" n
4994         | Bool _ -> pr " true|false"
4995         | Int n -> pr " %s" n
4996         | FileIn n | FileOut n -> pr " (%s|-)" n
4997       ) (snd style);
4998       pr "\n";
4999       pr "\n";
5000       pr "%s\n\n" longdesc;
5001
5002       if List.exists (function FileIn _ | FileOut _ -> true
5003                       | _ -> false) (snd style) then
5004         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5005
5006       if List.mem ProtocolLimitWarning flags then
5007         pr "%s\n\n" protocol_limit_warning;
5008
5009       if List.mem DangerWillRobinson flags then
5010         pr "%s\n\n" danger_will_robinson
5011   ) all_functions_sorted
5012
5013 (* Generate a C function prototype. *)
5014 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5015     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5016     ?(prefix = "")
5017     ?handle name style =
5018   if extern then pr "extern ";
5019   if static then pr "static ";
5020   (match fst style with
5021    | RErr -> pr "int "
5022    | RInt _ -> pr "int "
5023    | RInt64 _ -> pr "int64_t "
5024    | RBool _ -> pr "int "
5025    | RConstString _ -> pr "const char *"
5026    | RString _ -> pr "char *"
5027    | RStringList _ | RHashtable _ -> pr "char **"
5028    | RIntBool _ ->
5029        if not in_daemon then pr "struct guestfs_int_bool *"
5030        else pr "guestfs_%s_ret *" name
5031    | RPVList _ ->
5032        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
5033        else pr "guestfs_lvm_int_pv_list *"
5034    | RVGList _ ->
5035        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
5036        else pr "guestfs_lvm_int_vg_list *"
5037    | RLVList _ ->
5038        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
5039        else pr "guestfs_lvm_int_lv_list *"
5040    | RStat _ ->
5041        if not in_daemon then pr "struct guestfs_stat *"
5042        else pr "guestfs_int_stat *"
5043    | RStatVFS _ ->
5044        if not in_daemon then pr "struct guestfs_statvfs *"
5045        else pr "guestfs_int_statvfs *"
5046   );
5047   pr "%s%s (" prefix name;
5048   if handle = None && List.length (snd style) = 0 then
5049     pr "void"
5050   else (
5051     let comma = ref false in
5052     (match handle with
5053      | None -> ()
5054      | Some handle -> pr "guestfs_h *%s" handle; comma := true
5055     );
5056     let next () =
5057       if !comma then (
5058         if single_line then pr ", " else pr ",\n\t\t"
5059       );
5060       comma := true
5061     in
5062     List.iter (
5063       function
5064       | String n
5065       | OptString n ->
5066           next ();
5067           if not in_daemon then pr "const char *%s" n
5068           else pr "char *%s" n
5069       | StringList n ->
5070           next ();
5071           if not in_daemon then pr "char * const* const %s" n
5072           else pr "char **%s" n
5073       | Bool n -> next (); pr "int %s" n
5074       | Int n -> next (); pr "int %s" n
5075       | FileIn n
5076       | FileOut n ->
5077           if not in_daemon then (next (); pr "const char *%s" n)
5078     ) (snd style);
5079   );
5080   pr ")";
5081   if semicolon then pr ";";
5082   if newline then pr "\n"
5083
5084 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5085 and generate_call_args ?handle args =
5086   pr "(";
5087   let comma = ref false in
5088   (match handle with
5089    | None -> ()
5090    | Some handle -> pr "%s" handle; comma := true
5091   );
5092   List.iter (
5093     fun arg ->
5094       if !comma then pr ", ";
5095       comma := true;
5096       pr "%s" (name_of_argt arg)
5097   ) args;
5098   pr ")"
5099
5100 (* Generate the OCaml bindings interface. *)
5101 and generate_ocaml_mli () =
5102   generate_header OCamlStyle LGPLv2;
5103
5104   pr "\
5105 (** For API documentation you should refer to the C API
5106     in the guestfs(3) manual page.  The OCaml API uses almost
5107     exactly the same calls. *)
5108
5109 type t
5110 (** A [guestfs_h] handle. *)
5111
5112 exception Error of string
5113 (** This exception is raised when there is an error. *)
5114
5115 val create : unit -> t
5116
5117 val close : t -> unit
5118 (** Handles are closed by the garbage collector when they become
5119     unreferenced, but callers can also call this in order to
5120     provide predictable cleanup. *)
5121
5122 ";
5123   generate_ocaml_lvm_structure_decls ();
5124
5125   generate_ocaml_stat_structure_decls ();
5126
5127   (* The actions. *)
5128   List.iter (
5129     fun (name, style, _, _, _, shortdesc, _) ->
5130       generate_ocaml_prototype name style;
5131       pr "(** %s *)\n" shortdesc;
5132       pr "\n"
5133   ) all_functions
5134
5135 (* Generate the OCaml bindings implementation. *)
5136 and generate_ocaml_ml () =
5137   generate_header OCamlStyle LGPLv2;
5138
5139   pr "\
5140 type t
5141 exception Error of string
5142 external create : unit -> t = \"ocaml_guestfs_create\"
5143 external close : t -> unit = \"ocaml_guestfs_close\"
5144
5145 let () =
5146   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
5147
5148 ";
5149
5150   generate_ocaml_lvm_structure_decls ();
5151
5152   generate_ocaml_stat_structure_decls ();
5153
5154   (* The actions. *)
5155   List.iter (
5156     fun (name, style, _, _, _, shortdesc, _) ->
5157       generate_ocaml_prototype ~is_external:true name style;
5158   ) all_functions
5159
5160 (* Generate the OCaml bindings C implementation. *)
5161 and generate_ocaml_c () =
5162   generate_header CStyle LGPLv2;
5163
5164   pr "\
5165 #include <stdio.h>
5166 #include <stdlib.h>
5167 #include <string.h>
5168
5169 #include <caml/config.h>
5170 #include <caml/alloc.h>
5171 #include <caml/callback.h>
5172 #include <caml/fail.h>
5173 #include <caml/memory.h>
5174 #include <caml/mlvalues.h>
5175 #include <caml/signals.h>
5176
5177 #include <guestfs.h>
5178
5179 #include \"guestfs_c.h\"
5180
5181 /* Copy a hashtable of string pairs into an assoc-list.  We return
5182  * the list in reverse order, but hashtables aren't supposed to be
5183  * ordered anyway.
5184  */
5185 static CAMLprim value
5186 copy_table (char * const * argv)
5187 {
5188   CAMLparam0 ();
5189   CAMLlocal5 (rv, pairv, kv, vv, cons);
5190   int i;
5191
5192   rv = Val_int (0);
5193   for (i = 0; argv[i] != NULL; i += 2) {
5194     kv = caml_copy_string (argv[i]);
5195     vv = caml_copy_string (argv[i+1]);
5196     pairv = caml_alloc (2, 0);
5197     Store_field (pairv, 0, kv);
5198     Store_field (pairv, 1, vv);
5199     cons = caml_alloc (2, 0);
5200     Store_field (cons, 1, rv);
5201     rv = cons;
5202     Store_field (cons, 0, pairv);
5203   }
5204
5205   CAMLreturn (rv);
5206 }
5207
5208 ";
5209
5210   (* LVM struct copy functions. *)
5211   List.iter (
5212     fun (typ, cols) ->
5213       let has_optpercent_col =
5214         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
5215
5216       pr "static CAMLprim value\n";
5217       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
5218       pr "{\n";
5219       pr "  CAMLparam0 ();\n";
5220       if has_optpercent_col then
5221         pr "  CAMLlocal3 (rv, v, v2);\n"
5222       else
5223         pr "  CAMLlocal2 (rv, v);\n";
5224       pr "\n";
5225       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
5226       iteri (
5227         fun i col ->
5228           (match col with
5229            | name, `String ->
5230                pr "  v = caml_copy_string (%s->%s);\n" typ name
5231            | name, `UUID ->
5232                pr "  v = caml_alloc_string (32);\n";
5233                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
5234            | name, `Bytes
5235            | name, `Int ->
5236                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
5237            | name, `OptPercent ->
5238                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5239                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
5240                pr "    v = caml_alloc (1, 0);\n";
5241                pr "    Store_field (v, 0, v2);\n";
5242                pr "  } else /* None */\n";
5243                pr "    v = Val_int (0);\n";
5244           );
5245           pr "  Store_field (rv, %d, v);\n" i
5246       ) cols;
5247       pr "  CAMLreturn (rv);\n";
5248       pr "}\n";
5249       pr "\n";
5250
5251       pr "static CAMLprim value\n";
5252       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
5253         typ typ typ;
5254       pr "{\n";
5255       pr "  CAMLparam0 ();\n";
5256       pr "  CAMLlocal2 (rv, v);\n";
5257       pr "  int i;\n";
5258       pr "\n";
5259       pr "  if (%ss->len == 0)\n" typ;
5260       pr "    CAMLreturn (Atom (0));\n";
5261       pr "  else {\n";
5262       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
5263       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
5264       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
5265       pr "      caml_modify (&Field (rv, i), v);\n";
5266       pr "    }\n";
5267       pr "    CAMLreturn (rv);\n";
5268       pr "  }\n";
5269       pr "}\n";
5270       pr "\n";
5271   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5272
5273   (* Stat copy functions. *)
5274   List.iter (
5275     fun (typ, cols) ->
5276       pr "static CAMLprim value\n";
5277       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5278       pr "{\n";
5279       pr "  CAMLparam0 ();\n";
5280       pr "  CAMLlocal2 (rv, v);\n";
5281       pr "\n";
5282       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
5283       iteri (
5284         fun i col ->
5285           (match col with
5286            | name, `Int ->
5287                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
5288           );
5289           pr "  Store_field (rv, %d, v);\n" i
5290       ) cols;
5291       pr "  CAMLreturn (rv);\n";
5292       pr "}\n";
5293       pr "\n";
5294   ) ["stat", stat_cols; "statvfs", statvfs_cols];
5295
5296   (* The wrappers. *)
5297   List.iter (
5298     fun (name, style, _, _, _, _, _) ->
5299       let params =
5300         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5301
5302       pr "CAMLprim value\n";
5303       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5304       List.iter (pr ", value %s") (List.tl params);
5305       pr ")\n";
5306       pr "{\n";
5307
5308       (match params with
5309        | [p1; p2; p3; p4; p5] ->
5310            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
5311        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5312            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5313            pr "  CAMLxparam%d (%s);\n"
5314              (List.length rest) (String.concat ", " rest)
5315        | ps ->
5316            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5317       );
5318       pr "  CAMLlocal1 (rv);\n";
5319       pr "\n";
5320
5321       pr "  guestfs_h *g = Guestfs_val (gv);\n";
5322       pr "  if (g == NULL)\n";
5323       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
5324       pr "\n";
5325
5326       List.iter (
5327         function
5328         | String n
5329         | FileIn n
5330         | FileOut n ->
5331             pr "  const char *%s = String_val (%sv);\n" n n
5332         | OptString n ->
5333             pr "  const char *%s =\n" n;
5334             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5335               n n
5336         | StringList n ->
5337             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5338         | Bool n ->
5339             pr "  int %s = Bool_val (%sv);\n" n n
5340         | Int n ->
5341             pr "  int %s = Int_val (%sv);\n" n n
5342       ) (snd style);
5343       let error_code =
5344         match fst style with
5345         | RErr -> pr "  int r;\n"; "-1"
5346         | RInt _ -> pr "  int r;\n"; "-1"
5347         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5348         | RBool _ -> pr "  int r;\n"; "-1"
5349         | RConstString _ -> pr "  const char *r;\n"; "NULL"
5350         | RString _ -> pr "  char *r;\n"; "NULL"
5351         | RStringList _ ->
5352             pr "  int i;\n";
5353             pr "  char **r;\n";
5354             "NULL"
5355         | RIntBool _ ->
5356             pr "  struct guestfs_int_bool *r;\n"; "NULL"
5357         | RPVList _ ->
5358             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
5359         | RVGList _ ->
5360             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
5361         | RLVList _ ->
5362             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
5363         | RStat _ ->
5364             pr "  struct guestfs_stat *r;\n"; "NULL"
5365         | RStatVFS _ ->
5366             pr "  struct guestfs_statvfs *r;\n"; "NULL"
5367         | RHashtable _ ->
5368             pr "  int i;\n";
5369             pr "  char **r;\n";
5370             "NULL" in
5371       pr "\n";
5372
5373       pr "  caml_enter_blocking_section ();\n";
5374       pr "  r = guestfs_%s " name;
5375       generate_call_args ~handle:"g" (snd style);
5376       pr ";\n";
5377       pr "  caml_leave_blocking_section ();\n";
5378
5379       List.iter (
5380         function
5381         | StringList n ->
5382             pr "  ocaml_guestfs_free_strings (%s);\n" n;
5383         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5384       ) (snd style);
5385
5386       pr "  if (r == %s)\n" error_code;
5387       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5388       pr "\n";
5389
5390       (match fst style with
5391        | RErr -> pr "  rv = Val_unit;\n"
5392        | RInt _ -> pr "  rv = Val_int (r);\n"
5393        | RInt64 _ ->
5394            pr "  rv = caml_copy_int64 (r);\n"
5395        | RBool _ -> pr "  rv = Val_bool (r);\n"
5396        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
5397        | RString _ ->
5398            pr "  rv = caml_copy_string (r);\n";
5399            pr "  free (r);\n"
5400        | RStringList _ ->
5401            pr "  rv = caml_copy_string_array ((const char **) r);\n";
5402            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5403            pr "  free (r);\n"
5404        | RIntBool _ ->
5405            pr "  rv = caml_alloc (2, 0);\n";
5406            pr "  Store_field (rv, 0, Val_int (r->i));\n";
5407            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
5408            pr "  guestfs_free_int_bool (r);\n";
5409        | RPVList _ ->
5410            pr "  rv = copy_lvm_pv_list (r);\n";
5411            pr "  guestfs_free_lvm_pv_list (r);\n";
5412        | RVGList _ ->
5413            pr "  rv = copy_lvm_vg_list (r);\n";
5414            pr "  guestfs_free_lvm_vg_list (r);\n";
5415        | RLVList _ ->
5416            pr "  rv = copy_lvm_lv_list (r);\n";
5417            pr "  guestfs_free_lvm_lv_list (r);\n";
5418        | RStat _ ->
5419            pr "  rv = copy_stat (r);\n";
5420            pr "  free (r);\n";
5421        | RStatVFS _ ->
5422            pr "  rv = copy_statvfs (r);\n";
5423            pr "  free (r);\n";
5424        | RHashtable _ ->
5425            pr "  rv = copy_table (r);\n";
5426            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5427            pr "  free (r);\n";
5428       );
5429
5430       pr "  CAMLreturn (rv);\n";
5431       pr "}\n";
5432       pr "\n";
5433
5434       if List.length params > 5 then (
5435         pr "CAMLprim value\n";
5436         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5437         pr "{\n";
5438         pr "  return ocaml_guestfs_%s (argv[0]" name;
5439         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5440         pr ");\n";
5441         pr "}\n";
5442         pr "\n"
5443       )
5444   ) all_functions
5445
5446 and generate_ocaml_lvm_structure_decls () =
5447   List.iter (
5448     fun (typ, cols) ->
5449       pr "type lvm_%s = {\n" typ;
5450       List.iter (
5451         function
5452         | name, `String -> pr "  %s : string;\n" name
5453         | name, `UUID -> pr "  %s : string;\n" name
5454         | name, `Bytes -> pr "  %s : int64;\n" name
5455         | name, `Int -> pr "  %s : int64;\n" name
5456         | name, `OptPercent -> pr "  %s : float option;\n" name
5457       ) cols;
5458       pr "}\n";
5459       pr "\n"
5460   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5461
5462 and generate_ocaml_stat_structure_decls () =
5463   List.iter (
5464     fun (typ, cols) ->
5465       pr "type %s = {\n" typ;
5466       List.iter (
5467         function
5468         | name, `Int -> pr "  %s : int64;\n" name
5469       ) cols;
5470       pr "}\n";
5471       pr "\n"
5472   ) ["stat", stat_cols; "statvfs", statvfs_cols]
5473
5474 and generate_ocaml_prototype ?(is_external = false) name style =
5475   if is_external then pr "external " else pr "val ";
5476   pr "%s : t -> " name;
5477   List.iter (
5478     function
5479     | String _ | FileIn _ | FileOut _ -> pr "string -> "
5480     | OptString _ -> pr "string option -> "
5481     | StringList _ -> pr "string array -> "
5482     | Bool _ -> pr "bool -> "
5483     | Int _ -> pr "int -> "
5484   ) (snd style);
5485   (match fst style with
5486    | RErr -> pr "unit" (* all errors are turned into exceptions *)
5487    | RInt _ -> pr "int"
5488    | RInt64 _ -> pr "int64"
5489    | RBool _ -> pr "bool"
5490    | RConstString _ -> pr "string"
5491    | RString _ -> pr "string"
5492    | RStringList _ -> pr "string array"
5493    | RIntBool _ -> pr "int * bool"
5494    | RPVList _ -> pr "lvm_pv array"
5495    | RVGList _ -> pr "lvm_vg array"
5496    | RLVList _ -> pr "lvm_lv array"
5497    | RStat _ -> pr "stat"
5498    | RStatVFS _ -> pr "statvfs"
5499    | RHashtable _ -> pr "(string * string) list"
5500   );
5501   if is_external then (
5502     pr " = ";
5503     if List.length (snd style) + 1 > 5 then
5504       pr "\"ocaml_guestfs_%s_byte\" " name;
5505     pr "\"ocaml_guestfs_%s\"" name
5506   );
5507   pr "\n"
5508
5509 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5510 and generate_perl_xs () =
5511   generate_header CStyle LGPLv2;
5512
5513   pr "\
5514 #include \"EXTERN.h\"
5515 #include \"perl.h\"
5516 #include \"XSUB.h\"
5517
5518 #include <guestfs.h>
5519
5520 #ifndef PRId64
5521 #define PRId64 \"lld\"
5522 #endif
5523
5524 static SV *
5525 my_newSVll(long long val) {
5526 #ifdef USE_64_BIT_ALL
5527   return newSViv(val);
5528 #else
5529   char buf[100];
5530   int len;
5531   len = snprintf(buf, 100, \"%%\" PRId64, val);
5532   return newSVpv(buf, len);
5533 #endif
5534 }
5535
5536 #ifndef PRIu64
5537 #define PRIu64 \"llu\"
5538 #endif
5539
5540 static SV *
5541 my_newSVull(unsigned long long val) {
5542 #ifdef USE_64_BIT_ALL
5543   return newSVuv(val);
5544 #else
5545   char buf[100];
5546   int len;
5547   len = snprintf(buf, 100, \"%%\" PRIu64, val);
5548   return newSVpv(buf, len);
5549 #endif
5550 }
5551
5552 /* http://www.perlmonks.org/?node_id=680842 */
5553 static char **
5554 XS_unpack_charPtrPtr (SV *arg) {
5555   char **ret;
5556   AV *av;
5557   I32 i;
5558
5559   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5560     croak (\"array reference expected\");
5561
5562   av = (AV *)SvRV (arg);
5563   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5564   if (!ret)
5565     croak (\"malloc failed\");
5566
5567   for (i = 0; i <= av_len (av); i++) {
5568     SV **elem = av_fetch (av, i, 0);
5569
5570     if (!elem || !*elem)
5571       croak (\"missing element in list\");
5572
5573     ret[i] = SvPV_nolen (*elem);
5574   }
5575
5576   ret[i] = NULL;
5577
5578   return ret;
5579 }
5580
5581 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
5582
5583 PROTOTYPES: ENABLE
5584
5585 guestfs_h *
5586 _create ()
5587    CODE:
5588       RETVAL = guestfs_create ();
5589       if (!RETVAL)
5590         croak (\"could not create guestfs handle\");
5591       guestfs_set_error_handler (RETVAL, NULL, NULL);
5592  OUTPUT:
5593       RETVAL
5594
5595 void
5596 DESTROY (g)
5597       guestfs_h *g;
5598  PPCODE:
5599       guestfs_close (g);
5600
5601 ";
5602
5603   List.iter (
5604     fun (name, style, _, _, _, _, _) ->
5605       (match fst style with
5606        | RErr -> pr "void\n"
5607        | RInt _ -> pr "SV *\n"
5608        | RInt64 _ -> pr "SV *\n"
5609        | RBool _ -> pr "SV *\n"
5610        | RConstString _ -> pr "SV *\n"
5611        | RString _ -> pr "SV *\n"
5612        | RStringList _
5613        | RIntBool _
5614        | RPVList _ | RVGList _ | RLVList _
5615        | RStat _ | RStatVFS _
5616        | RHashtable _ ->
5617            pr "void\n" (* all lists returned implictly on the stack *)
5618       );
5619       (* Call and arguments. *)
5620       pr "%s " name;
5621       generate_call_args ~handle:"g" (snd style);
5622       pr "\n";
5623       pr "      guestfs_h *g;\n";
5624       iteri (
5625         fun i ->
5626           function
5627           | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
5628           | OptString n ->
5629               (* http://www.perlmonks.org/?node_id=554277
5630                * Note that the implicit handle argument means we have
5631                * to add 1 to the ST(x) operator.
5632                *)
5633               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
5634           | StringList n -> pr "      char **%s;\n" n
5635           | Bool n -> pr "      int %s;\n" n
5636           | Int n -> pr "      int %s;\n" n
5637       ) (snd style);
5638
5639       let do_cleanups () =
5640         List.iter (
5641           function
5642           | String _ | OptString _ | Bool _ | Int _
5643           | FileIn _ | FileOut _ -> ()
5644           | StringList n -> pr "      free (%s);\n" n
5645         ) (snd style)
5646       in
5647
5648       (* Code. *)
5649       (match fst style with
5650        | RErr ->
5651            pr "PREINIT:\n";
5652            pr "      int r;\n";
5653            pr " PPCODE:\n";
5654            pr "      r = guestfs_%s " name;
5655            generate_call_args ~handle:"g" (snd style);
5656            pr ";\n";
5657            do_cleanups ();
5658            pr "      if (r == -1)\n";
5659            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5660        | RInt n
5661        | RBool n ->
5662            pr "PREINIT:\n";
5663            pr "      int %s;\n" n;
5664            pr "   CODE:\n";
5665            pr "      %s = guestfs_%s " n name;
5666            generate_call_args ~handle:"g" (snd style);
5667            pr ";\n";
5668            do_cleanups ();
5669            pr "      if (%s == -1)\n" n;
5670            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5671            pr "      RETVAL = newSViv (%s);\n" n;
5672            pr " OUTPUT:\n";
5673            pr "      RETVAL\n"
5674        | RInt64 n ->
5675            pr "PREINIT:\n";
5676            pr "      int64_t %s;\n" n;
5677            pr "   CODE:\n";
5678            pr "      %s = guestfs_%s " n name;
5679            generate_call_args ~handle:"g" (snd style);
5680            pr ";\n";
5681            do_cleanups ();
5682            pr "      if (%s == -1)\n" n;
5683            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5684            pr "      RETVAL = my_newSVll (%s);\n" n;
5685            pr " OUTPUT:\n";
5686            pr "      RETVAL\n"
5687        | RConstString n ->
5688            pr "PREINIT:\n";
5689            pr "      const char *%s;\n" n;
5690            pr "   CODE:\n";
5691            pr "      %s = guestfs_%s " n name;
5692            generate_call_args ~handle:"g" (snd style);
5693            pr ";\n";
5694            do_cleanups ();
5695            pr "      if (%s == NULL)\n" n;
5696            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5697            pr "      RETVAL = newSVpv (%s, 0);\n" n;
5698            pr " OUTPUT:\n";
5699            pr "      RETVAL\n"
5700        | RString n ->
5701            pr "PREINIT:\n";
5702            pr "      char *%s;\n" n;
5703            pr "   CODE:\n";
5704            pr "      %s = guestfs_%s " n name;
5705            generate_call_args ~handle:"g" (snd style);
5706            pr ";\n";
5707            do_cleanups ();
5708            pr "      if (%s == NULL)\n" n;
5709            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5710            pr "      RETVAL = newSVpv (%s, 0);\n" n;
5711            pr "      free (%s);\n" n;
5712            pr " OUTPUT:\n";
5713            pr "      RETVAL\n"
5714        | RStringList n | RHashtable n ->
5715            pr "PREINIT:\n";
5716            pr "      char **%s;\n" n;
5717            pr "      int i, n;\n";
5718            pr " PPCODE:\n";
5719            pr "      %s = guestfs_%s " n name;
5720            generate_call_args ~handle:"g" (snd style);
5721            pr ";\n";
5722            do_cleanups ();
5723            pr "      if (%s == NULL)\n" n;
5724            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5725            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
5726            pr "      EXTEND (SP, n);\n";
5727            pr "      for (i = 0; i < n; ++i) {\n";
5728            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
5729            pr "        free (%s[i]);\n" n;
5730            pr "      }\n";
5731            pr "      free (%s);\n" n;
5732        | RIntBool _ ->
5733            pr "PREINIT:\n";
5734            pr "      struct guestfs_int_bool *r;\n";
5735            pr " PPCODE:\n";
5736            pr "      r = guestfs_%s " name;
5737            generate_call_args ~handle:"g" (snd style);
5738            pr ";\n";
5739            do_cleanups ();
5740            pr "      if (r == NULL)\n";
5741            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5742            pr "      EXTEND (SP, 2);\n";
5743            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
5744            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
5745            pr "      guestfs_free_int_bool (r);\n";
5746        | RPVList n ->
5747            generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
5748        | RVGList n ->
5749            generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
5750        | RLVList n ->
5751            generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
5752        | RStat n ->
5753            generate_perl_stat_code "stat" stat_cols name style n do_cleanups
5754        | RStatVFS n ->
5755            generate_perl_stat_code
5756              "statvfs" statvfs_cols name style n do_cleanups
5757       );
5758
5759       pr "\n"
5760   ) all_functions
5761
5762 and generate_perl_lvm_code typ cols name style n do_cleanups =
5763   pr "PREINIT:\n";
5764   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
5765   pr "      int i;\n";
5766   pr "      HV *hv;\n";
5767   pr " PPCODE:\n";
5768   pr "      %s = guestfs_%s " n name;
5769   generate_call_args ~handle:"g" (snd style);
5770   pr ";\n";
5771   do_cleanups ();
5772   pr "      if (%s == NULL)\n" n;
5773   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5774   pr "      EXTEND (SP, %s->len);\n" n;
5775   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
5776   pr "        hv = newHV ();\n";
5777   List.iter (
5778     function
5779     | name, `String ->
5780         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
5781           name (String.length name) n name
5782     | name, `UUID ->
5783         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
5784           name (String.length name) n name
5785     | name, `Bytes ->
5786         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
5787           name (String.length name) n name
5788     | name, `Int ->
5789         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
5790           name (String.length name) n name
5791     | name, `OptPercent ->
5792         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
5793           name (String.length name) n name
5794   ) cols;
5795   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
5796   pr "      }\n";
5797   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
5798
5799 and generate_perl_stat_code typ cols name style n do_cleanups =
5800   pr "PREINIT:\n";
5801   pr "      struct guestfs_%s *%s;\n" typ n;
5802   pr " PPCODE:\n";
5803   pr "      %s = guestfs_%s " n name;
5804   generate_call_args ~handle:"g" (snd style);
5805   pr ";\n";
5806   do_cleanups ();
5807   pr "      if (%s == NULL)\n" n;
5808   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5809   pr "      EXTEND (SP, %d);\n" (List.length cols);
5810   List.iter (
5811     function
5812     | name, `Int ->
5813         pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
5814   ) cols;
5815   pr "      free (%s);\n" n
5816
5817 (* Generate Sys/Guestfs.pm. *)
5818 and generate_perl_pm () =
5819   generate_header HashStyle LGPLv2;
5820
5821   pr "\
5822 =pod
5823
5824 =head1 NAME
5825
5826 Sys::Guestfs - Perl bindings for libguestfs
5827
5828 =head1 SYNOPSIS
5829
5830  use Sys::Guestfs;
5831  
5832  my $h = Sys::Guestfs->new ();
5833  $h->add_drive ('guest.img');
5834  $h->launch ();
5835  $h->wait_ready ();
5836  $h->mount ('/dev/sda1', '/');
5837  $h->touch ('/hello');
5838  $h->sync ();
5839
5840 =head1 DESCRIPTION
5841
5842 The C<Sys::Guestfs> module provides a Perl XS binding to the
5843 libguestfs API for examining and modifying virtual machine
5844 disk images.
5845
5846 Amongst the things this is good for: making batch configuration
5847 changes to guests, getting disk used/free statistics (see also:
5848 virt-df), migrating between virtualization systems (see also:
5849 virt-p2v), performing partial backups, performing partial guest
5850 clones, cloning guests and changing registry/UUID/hostname info, and
5851 much else besides.
5852
5853 Libguestfs uses Linux kernel and qemu code, and can access any type of
5854 guest filesystem that Linux and qemu can, including but not limited
5855 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5856 schemes, qcow, qcow2, vmdk.
5857
5858 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5859 LVs, what filesystem is in each LV, etc.).  It can also run commands
5860 in the context of the guest.  Also you can access filesystems over FTP.
5861
5862 =head1 ERRORS
5863
5864 All errors turn into calls to C<croak> (see L<Carp(3)>).
5865
5866 =head1 METHODS
5867
5868 =over 4
5869
5870 =cut
5871
5872 package Sys::Guestfs;
5873
5874 use strict;
5875 use warnings;
5876
5877 require XSLoader;
5878 XSLoader::load ('Sys::Guestfs');
5879
5880 =item $h = Sys::Guestfs->new ();
5881
5882 Create a new guestfs handle.
5883
5884 =cut
5885
5886 sub new {
5887   my $proto = shift;
5888   my $class = ref ($proto) || $proto;
5889
5890   my $self = Sys::Guestfs::_create ();
5891   bless $self, $class;
5892   return $self;
5893 }
5894
5895 ";
5896
5897   (* Actions.  We only need to print documentation for these as
5898    * they are pulled in from the XS code automatically.
5899    *)
5900   List.iter (
5901     fun (name, style, _, flags, _, _, longdesc) ->
5902       if not (List.mem NotInDocs flags) then (
5903         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
5904         pr "=item ";
5905         generate_perl_prototype name style;
5906         pr "\n\n";
5907         pr "%s\n\n" longdesc;
5908         if List.mem ProtocolLimitWarning flags then
5909           pr "%s\n\n" protocol_limit_warning;
5910         if List.mem DangerWillRobinson flags then
5911           pr "%s\n\n" danger_will_robinson
5912       )
5913   ) all_functions_sorted;
5914
5915   (* End of file. *)
5916   pr "\
5917 =cut
5918
5919 1;
5920
5921 =back
5922
5923 =head1 COPYRIGHT
5924
5925 Copyright (C) 2009 Red Hat Inc.
5926
5927 =head1 LICENSE
5928
5929 Please see the file COPYING.LIB for the full license.
5930
5931 =head1 SEE ALSO
5932
5933 L<guestfs(3)>, L<guestfish(1)>.
5934
5935 =cut
5936 "
5937
5938 and generate_perl_prototype name style =
5939   (match fst style with
5940    | RErr -> ()
5941    | RBool n
5942    | RInt n
5943    | RInt64 n
5944    | RConstString n
5945    | RString n -> pr "$%s = " n
5946    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
5947    | RStringList n
5948    | RPVList n
5949    | RVGList n
5950    | RLVList n -> pr "@%s = " n
5951    | RStat n
5952    | RStatVFS n
5953    | RHashtable n -> pr "%%%s = " n
5954   );
5955   pr "$h->%s (" name;
5956   let comma = ref false in
5957   List.iter (
5958     fun arg ->
5959       if !comma then pr ", ";
5960       comma := true;
5961       match arg with
5962       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
5963           pr "$%s" n
5964       | StringList n ->
5965           pr "\\@%s" n
5966   ) (snd style);
5967   pr ");"
5968
5969 (* Generate Python C module. *)
5970 and generate_python_c () =
5971   generate_header CStyle LGPLv2;
5972
5973   pr "\
5974 #include <stdio.h>
5975 #include <stdlib.h>
5976 #include <assert.h>
5977
5978 #include <Python.h>
5979
5980 #include \"guestfs.h\"
5981
5982 typedef struct {
5983   PyObject_HEAD
5984   guestfs_h *g;
5985 } Pyguestfs_Object;
5986
5987 static guestfs_h *
5988 get_handle (PyObject *obj)
5989 {
5990   assert (obj);
5991   assert (obj != Py_None);
5992   return ((Pyguestfs_Object *) obj)->g;
5993 }
5994
5995 static PyObject *
5996 put_handle (guestfs_h *g)
5997 {
5998   assert (g);
5999   return
6000     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6001 }
6002
6003 /* This list should be freed (but not the strings) after use. */
6004 static const char **
6005 get_string_list (PyObject *obj)
6006 {
6007   int i, len;
6008   const char **r;
6009
6010   assert (obj);
6011
6012   if (!PyList_Check (obj)) {
6013     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6014     return NULL;
6015   }
6016
6017   len = PyList_Size (obj);
6018   r = malloc (sizeof (char *) * (len+1));
6019   if (r == NULL) {
6020     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6021     return NULL;
6022   }
6023
6024   for (i = 0; i < len; ++i)
6025     r[i] = PyString_AsString (PyList_GetItem (obj, i));
6026   r[len] = NULL;
6027
6028   return r;
6029 }
6030
6031 static PyObject *
6032 put_string_list (char * const * const argv)
6033 {
6034   PyObject *list;
6035   int argc, i;
6036
6037   for (argc = 0; argv[argc] != NULL; ++argc)
6038     ;
6039
6040   list = PyList_New (argc);
6041   for (i = 0; i < argc; ++i)
6042     PyList_SetItem (list, i, PyString_FromString (argv[i]));
6043
6044   return list;
6045 }
6046
6047 static PyObject *
6048 put_table (char * const * const argv)
6049 {
6050   PyObject *list, *item;
6051   int argc, i;
6052
6053   for (argc = 0; argv[argc] != NULL; ++argc)
6054     ;
6055
6056   list = PyList_New (argc >> 1);
6057   for (i = 0; i < argc; i += 2) {
6058     item = PyTuple_New (2);
6059     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
6060     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
6061     PyList_SetItem (list, i >> 1, item);
6062   }
6063
6064   return list;
6065 }
6066
6067 static void
6068 free_strings (char **argv)
6069 {
6070   int argc;
6071
6072   for (argc = 0; argv[argc] != NULL; ++argc)
6073     free (argv[argc]);
6074   free (argv);
6075 }
6076
6077 static PyObject *
6078 py_guestfs_create (PyObject *self, PyObject *args)
6079 {
6080   guestfs_h *g;
6081
6082   g = guestfs_create ();
6083   if (g == NULL) {
6084     PyErr_SetString (PyExc_RuntimeError,
6085                      \"guestfs.create: failed to allocate handle\");
6086     return NULL;
6087   }
6088   guestfs_set_error_handler (g, NULL, NULL);
6089   return put_handle (g);
6090 }
6091
6092 static PyObject *
6093 py_guestfs_close (PyObject *self, PyObject *args)
6094 {
6095   PyObject *py_g;
6096   guestfs_h *g;
6097
6098   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
6099     return NULL;
6100   g = get_handle (py_g);
6101
6102   guestfs_close (g);
6103
6104   Py_INCREF (Py_None);
6105   return Py_None;
6106 }
6107
6108 ";
6109
6110   (* LVM structures, turned into Python dictionaries. *)
6111   List.iter (
6112     fun (typ, cols) ->
6113       pr "static PyObject *\n";
6114       pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
6115       pr "{\n";
6116       pr "  PyObject *dict;\n";
6117       pr "\n";
6118       pr "  dict = PyDict_New ();\n";
6119       List.iter (
6120         function
6121         | name, `String ->
6122             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6123             pr "                        PyString_FromString (%s->%s));\n"
6124               typ name
6125         | name, `UUID ->
6126             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6127             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
6128               typ name
6129         | name, `Bytes ->
6130             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6131             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
6132               typ name
6133         | name, `Int ->
6134             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6135             pr "                        PyLong_FromLongLong (%s->%s));\n"
6136               typ name
6137         | name, `OptPercent ->
6138             pr "  if (%s->%s >= 0)\n" typ name;
6139             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
6140             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
6141               typ name;
6142             pr "  else {\n";
6143             pr "    Py_INCREF (Py_None);\n";
6144             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
6145             pr "  }\n"
6146       ) cols;
6147       pr "  return dict;\n";
6148       pr "};\n";
6149       pr "\n";
6150
6151       pr "static PyObject *\n";
6152       pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
6153       pr "{\n";
6154       pr "  PyObject *list;\n";
6155       pr "  int i;\n";
6156       pr "\n";
6157       pr "  list = PyList_New (%ss->len);\n" typ;
6158       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
6159       pr "    PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
6160       pr "  return list;\n";
6161       pr "};\n";
6162       pr "\n"
6163   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
6164
6165   (* Stat structures, turned into Python dictionaries. *)
6166   List.iter (
6167     fun (typ, cols) ->
6168       pr "static PyObject *\n";
6169       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6170       pr "{\n";
6171       pr "  PyObject *dict;\n";
6172       pr "\n";
6173       pr "  dict = PyDict_New ();\n";
6174       List.iter (
6175         function
6176         | name, `Int ->
6177             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6178             pr "                        PyLong_FromLongLong (%s->%s));\n"
6179               typ name
6180       ) cols;
6181       pr "  return dict;\n";
6182       pr "};\n";
6183       pr "\n";
6184   ) ["stat", stat_cols; "statvfs", statvfs_cols];
6185
6186   (* Python wrapper functions. *)
6187   List.iter (
6188     fun (name, style, _, _, _, _, _) ->
6189       pr "static PyObject *\n";
6190       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6191       pr "{\n";
6192
6193       pr "  PyObject *py_g;\n";
6194       pr "  guestfs_h *g;\n";
6195       pr "  PyObject *py_r;\n";
6196
6197       let error_code =
6198         match fst style with
6199         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
6200         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6201         | RConstString _ -> pr "  const char *r;\n"; "NULL"
6202         | RString _ -> pr "  char *r;\n"; "NULL"
6203         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6204         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
6205         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
6206         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
6207         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
6208         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
6209         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
6210
6211       List.iter (
6212         function
6213         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
6214         | OptString n -> pr "  const char *%s;\n" n
6215         | StringList n ->
6216             pr "  PyObject *py_%s;\n" n;
6217             pr "  const char **%s;\n" n
6218         | Bool n -> pr "  int %s;\n" n
6219         | Int n -> pr "  int %s;\n" n
6220       ) (snd style);
6221
6222       pr "\n";
6223
6224       (* Convert the parameters. *)
6225       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
6226       List.iter (
6227         function
6228         | String _ | FileIn _ | FileOut _ -> pr "s"
6229         | OptString _ -> pr "z"
6230         | StringList _ -> pr "O"
6231         | Bool _ -> pr "i" (* XXX Python has booleans? *)
6232         | Int _ -> pr "i"
6233       ) (snd style);
6234       pr ":guestfs_%s\",\n" name;
6235       pr "                         &py_g";
6236       List.iter (
6237         function
6238         | String n | FileIn n | FileOut n -> pr ", &%s" n
6239         | OptString n -> pr ", &%s" n
6240         | StringList n -> pr ", &py_%s" n
6241         | Bool n -> pr ", &%s" n
6242         | Int n -> pr ", &%s" n
6243       ) (snd style);
6244
6245       pr "))\n";
6246       pr "    return NULL;\n";
6247
6248       pr "  g = get_handle (py_g);\n";
6249       List.iter (
6250         function
6251         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6252         | StringList n ->
6253             pr "  %s = get_string_list (py_%s);\n" n n;
6254             pr "  if (!%s) return NULL;\n" n
6255       ) (snd style);
6256
6257       pr "\n";
6258
6259       pr "  r = guestfs_%s " name;
6260       generate_call_args ~handle:"g" (snd style);
6261       pr ";\n";
6262
6263       List.iter (
6264         function
6265         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6266         | StringList n ->
6267             pr "  free (%s);\n" n
6268       ) (snd style);
6269
6270       pr "  if (r == %s) {\n" error_code;
6271       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6272       pr "    return NULL;\n";
6273       pr "  }\n";
6274       pr "\n";
6275
6276       (match fst style with
6277        | RErr ->
6278            pr "  Py_INCREF (Py_None);\n";
6279            pr "  py_r = Py_None;\n"
6280        | RInt _
6281        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
6282        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
6283        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
6284        | RString _ ->
6285            pr "  py_r = PyString_FromString (r);\n";
6286            pr "  free (r);\n"
6287        | RStringList _ ->
6288            pr "  py_r = put_string_list (r);\n";
6289            pr "  free_strings (r);\n"
6290        | RIntBool _ ->
6291            pr "  py_r = PyTuple_New (2);\n";
6292            pr "  PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
6293            pr "  PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
6294            pr "  guestfs_free_int_bool (r);\n"
6295        | RPVList n ->
6296            pr "  py_r = put_lvm_pv_list (r);\n";
6297            pr "  guestfs_free_lvm_pv_list (r);\n"
6298        | RVGList n ->
6299            pr "  py_r = put_lvm_vg_list (r);\n";
6300            pr "  guestfs_free_lvm_vg_list (r);\n"
6301        | RLVList n ->
6302            pr "  py_r = put_lvm_lv_list (r);\n";
6303            pr "  guestfs_free_lvm_lv_list (r);\n"
6304        | RStat n ->
6305            pr "  py_r = put_stat (r);\n";
6306            pr "  free (r);\n"
6307        | RStatVFS n ->
6308            pr "  py_r = put_statvfs (r);\n";
6309            pr "  free (r);\n"
6310        | RHashtable n ->
6311            pr "  py_r = put_table (r);\n";
6312            pr "  free_strings (r);\n"
6313       );
6314
6315       pr "  return py_r;\n";
6316       pr "}\n";
6317       pr "\n"
6318   ) all_functions;
6319
6320   (* Table of functions. *)
6321   pr "static PyMethodDef methods[] = {\n";
6322   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6323   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6324   List.iter (
6325     fun (name, _, _, _, _, _, _) ->
6326       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6327         name name
6328   ) all_functions;
6329   pr "  { NULL, NULL, 0, NULL }\n";
6330   pr "};\n";
6331   pr "\n";
6332
6333   (* Init function. *)
6334   pr "\
6335 void
6336 initlibguestfsmod (void)
6337 {
6338   static int initialized = 0;
6339
6340   if (initialized) return;
6341   Py_InitModule ((char *) \"libguestfsmod\", methods);
6342   initialized = 1;
6343 }
6344 "
6345
6346 (* Generate Python module. *)
6347 and generate_python_py () =
6348   generate_header HashStyle LGPLv2;
6349
6350   pr "\
6351 u\"\"\"Python bindings for libguestfs
6352
6353 import guestfs
6354 g = guestfs.GuestFS ()
6355 g.add_drive (\"guest.img\")
6356 g.launch ()
6357 g.wait_ready ()
6358 parts = g.list_partitions ()
6359
6360 The guestfs module provides a Python binding to the libguestfs API
6361 for examining and modifying virtual machine disk images.
6362
6363 Amongst the things this is good for: making batch configuration
6364 changes to guests, getting disk used/free statistics (see also:
6365 virt-df), migrating between virtualization systems (see also:
6366 virt-p2v), performing partial backups, performing partial guest
6367 clones, cloning guests and changing registry/UUID/hostname info, and
6368 much else besides.
6369
6370 Libguestfs uses Linux kernel and qemu code, and can access any type of
6371 guest filesystem that Linux and qemu can, including but not limited
6372 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6373 schemes, qcow, qcow2, vmdk.
6374
6375 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6376 LVs, what filesystem is in each LV, etc.).  It can also run commands
6377 in the context of the guest.  Also you can access filesystems over FTP.
6378
6379 Errors which happen while using the API are turned into Python
6380 RuntimeError exceptions.
6381
6382 To create a guestfs handle you usually have to perform the following
6383 sequence of calls:
6384
6385 # Create the handle, call add_drive at least once, and possibly
6386 # several times if the guest has multiple block devices:
6387 g = guestfs.GuestFS ()
6388 g.add_drive (\"guest.img\")
6389
6390 # Launch the qemu subprocess and wait for it to become ready:
6391 g.launch ()
6392 g.wait_ready ()
6393
6394 # Now you can issue commands, for example:
6395 logvols = g.lvs ()
6396
6397 \"\"\"
6398
6399 import libguestfsmod
6400
6401 class GuestFS:
6402     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6403
6404     def __init__ (self):
6405         \"\"\"Create a new libguestfs handle.\"\"\"
6406         self._o = libguestfsmod.create ()
6407
6408     def __del__ (self):
6409         libguestfsmod.close (self._o)
6410
6411 ";
6412
6413   List.iter (
6414     fun (name, style, _, flags, _, _, longdesc) ->
6415       pr "    def %s " name;
6416       generate_call_args ~handle:"self" (snd style);
6417       pr ":\n";
6418
6419       if not (List.mem NotInDocs flags) then (
6420         let doc = replace_str longdesc "C<guestfs_" "C<g." in
6421         let doc =
6422           match fst style with
6423           | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6424           | RString _ -> doc
6425           | RStringList _ ->
6426               doc ^ "\n\nThis function returns a list of strings."
6427           | RIntBool _ ->
6428               doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6429           | RPVList _ ->
6430               doc ^ "\n\nThis function returns a list of PVs.  Each PV is represented as a dictionary."
6431           | RVGList _ ->
6432               doc ^ "\n\nThis function returns a list of VGs.  Each VG is represented as a dictionary."
6433           | RLVList _ ->
6434               doc ^ "\n\nThis function returns a list of LVs.  Each LV is represented as a dictionary."
6435           | RStat _ ->
6436               doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6437           | RStatVFS _ ->
6438               doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6439           | RHashtable _ ->
6440               doc ^ "\n\nThis function returns a dictionary." in
6441         let doc =
6442           if List.mem ProtocolLimitWarning flags then
6443             doc ^ "\n\n" ^ protocol_limit_warning
6444           else doc in
6445         let doc =
6446           if List.mem DangerWillRobinson flags then
6447             doc ^ "\n\n" ^ danger_will_robinson
6448           else doc in
6449         let doc = pod2text ~width:60 name doc in
6450         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6451         let doc = String.concat "\n        " doc in
6452         pr "        u\"\"\"%s\"\"\"\n" doc;
6453       );
6454       pr "        return libguestfsmod.%s " name;
6455       generate_call_args ~handle:"self._o" (snd style);
6456       pr "\n";
6457       pr "\n";
6458   ) all_functions
6459
6460 (* Useful if you need the longdesc POD text as plain text.  Returns a
6461  * list of lines.
6462  *
6463  * This is the slowest thing about autogeneration.
6464  *)
6465 and pod2text ~width name longdesc =
6466   let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6467   fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6468   close_out chan;
6469   let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6470   let chan = Unix.open_process_in cmd in
6471   let lines = ref [] in
6472   let rec loop i =
6473     let line = input_line chan in
6474     if i = 1 then               (* discard the first line of output *)
6475       loop (i+1)
6476     else (
6477       let line = triml line in
6478       lines := line :: !lines;
6479       loop (i+1)
6480     ) in
6481   let lines = try loop 1 with End_of_file -> List.rev !lines in
6482   Unix.unlink filename;
6483   match Unix.close_process_in chan with
6484   | Unix.WEXITED 0 -> lines
6485   | Unix.WEXITED i ->
6486       failwithf "pod2text: process exited with non-zero status (%d)" i
6487   | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6488       failwithf "pod2text: process signalled or stopped by signal %d" i
6489
6490 (* Generate ruby bindings. *)
6491 and generate_ruby_c () =
6492   generate_header CStyle LGPLv2;
6493
6494   pr "\
6495 #include <stdio.h>
6496 #include <stdlib.h>
6497
6498 #include <ruby.h>
6499
6500 #include \"guestfs.h\"
6501
6502 #include \"extconf.h\"
6503
6504 /* For Ruby < 1.9 */
6505 #ifndef RARRAY_LEN
6506 #define RARRAY_LEN(r) (RARRAY((r))->len)
6507 #endif
6508
6509 static VALUE m_guestfs;                 /* guestfs module */
6510 static VALUE c_guestfs;                 /* guestfs_h handle */
6511 static VALUE e_Error;                   /* used for all errors */
6512
6513 static void ruby_guestfs_free (void *p)
6514 {
6515   if (!p) return;
6516   guestfs_close ((guestfs_h *) p);
6517 }
6518
6519 static VALUE ruby_guestfs_create (VALUE m)
6520 {
6521   guestfs_h *g;
6522
6523   g = guestfs_create ();
6524   if (!g)
6525     rb_raise (e_Error, \"failed to create guestfs handle\");
6526
6527   /* Don't print error messages to stderr by default. */
6528   guestfs_set_error_handler (g, NULL, NULL);
6529
6530   /* Wrap it, and make sure the close function is called when the
6531    * handle goes away.
6532    */
6533   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6534 }
6535
6536 static VALUE ruby_guestfs_close (VALUE gv)
6537 {
6538   guestfs_h *g;
6539   Data_Get_Struct (gv, guestfs_h, g);
6540
6541   ruby_guestfs_free (g);
6542   DATA_PTR (gv) = NULL;
6543
6544   return Qnil;
6545 }
6546
6547 ";
6548
6549   List.iter (
6550     fun (name, style, _, _, _, _, _) ->
6551       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6552       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6553       pr ")\n";
6554       pr "{\n";
6555       pr "  guestfs_h *g;\n";
6556       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
6557       pr "  if (!g)\n";
6558       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6559         name;
6560       pr "\n";
6561
6562       List.iter (
6563         function
6564         | String n | FileIn n | FileOut n ->
6565             pr "  Check_Type (%sv, T_STRING);\n" n;
6566             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
6567             pr "  if (!%s)\n" n;
6568             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6569             pr "              \"%s\", \"%s\");\n" n name
6570         | OptString n ->
6571             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
6572         | StringList n ->
6573             pr "  char **%s;\n" n;
6574             pr "  Check_Type (%sv, T_ARRAY);\n" n;
6575             pr "  {\n";
6576             pr "    int i, len;\n";
6577             pr "    len = RARRAY_LEN (%sv);\n" n;
6578             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6579               n;
6580             pr "    for (i = 0; i < len; ++i) {\n";
6581             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
6582             pr "      %s[i] = StringValueCStr (v);\n" n;
6583             pr "    }\n";
6584             pr "    %s[len] = NULL;\n" n;
6585             pr "  }\n";
6586         | Bool n ->
6587             pr "  int %s = RTEST (%sv);\n" n n
6588         | Int n ->
6589             pr "  int %s = NUM2INT (%sv);\n" n n
6590       ) (snd style);
6591       pr "\n";
6592
6593       let error_code =
6594         match fst style with
6595         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
6596         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6597         | RConstString _ -> pr "  const char *r;\n"; "NULL"
6598         | RString _ -> pr "  char *r;\n"; "NULL"
6599         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6600         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
6601         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
6602         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
6603         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
6604         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
6605         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
6606       pr "\n";
6607
6608       pr "  r = guestfs_%s " name;
6609       generate_call_args ~handle:"g" (snd style);
6610       pr ";\n";
6611
6612       List.iter (
6613         function
6614         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6615         | StringList n ->
6616             pr "  free (%s);\n" n
6617       ) (snd style);
6618
6619       pr "  if (r == %s)\n" error_code;
6620       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6621       pr "\n";
6622
6623       (match fst style with
6624        | RErr ->
6625            pr "  return Qnil;\n"
6626        | RInt _ | RBool _ ->
6627            pr "  return INT2NUM (r);\n"
6628        | RInt64 _ ->
6629            pr "  return ULL2NUM (r);\n"
6630        | RConstString _ ->
6631            pr "  return rb_str_new2 (r);\n";
6632        | RString _ ->
6633            pr "  VALUE rv = rb_str_new2 (r);\n";
6634            pr "  free (r);\n";
6635            pr "  return rv;\n";
6636        | RStringList _ ->
6637            pr "  int i, len = 0;\n";
6638            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
6639            pr "  VALUE rv = rb_ary_new2 (len);\n";
6640            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
6641            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6642            pr "    free (r[i]);\n";
6643            pr "  }\n";
6644            pr "  free (r);\n";
6645            pr "  return rv;\n"
6646        | RIntBool _ ->
6647            pr "  VALUE rv = rb_ary_new2 (2);\n";
6648            pr "  rb_ary_push (rv, INT2NUM (r->i));\n";
6649            pr "  rb_ary_push (rv, INT2NUM (r->b));\n";
6650            pr "  guestfs_free_int_bool (r);\n";
6651            pr "  return rv;\n"
6652        | RPVList n ->
6653            generate_ruby_lvm_code "pv" pv_cols
6654        | RVGList n ->
6655            generate_ruby_lvm_code "vg" vg_cols
6656        | RLVList n ->
6657            generate_ruby_lvm_code "lv" lv_cols
6658        | RStat n ->
6659            pr "  VALUE rv = rb_hash_new ();\n";
6660            List.iter (
6661              function
6662              | name, `Int ->
6663                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6664            ) stat_cols;
6665            pr "  free (r);\n";
6666            pr "  return rv;\n"
6667        | RStatVFS n ->
6668            pr "  VALUE rv = rb_hash_new ();\n";
6669            List.iter (
6670              function
6671              | name, `Int ->
6672                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6673            ) statvfs_cols;
6674            pr "  free (r);\n";
6675            pr "  return rv;\n"
6676        | RHashtable _ ->
6677            pr "  VALUE rv = rb_hash_new ();\n";
6678            pr "  int i;\n";
6679            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
6680            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6681            pr "    free (r[i]);\n";
6682            pr "    free (r[i+1]);\n";
6683            pr "  }\n";
6684            pr "  free (r);\n";
6685            pr "  return rv;\n"
6686       );
6687
6688       pr "}\n";
6689       pr "\n"
6690   ) all_functions;
6691
6692   pr "\
6693 /* Initialize the module. */
6694 void Init__guestfs ()
6695 {
6696   m_guestfs = rb_define_module (\"Guestfs\");
6697   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6698   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6699
6700   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6701   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6702
6703 ";
6704   (* Define the rest of the methods. *)
6705   List.iter (
6706     fun (name, style, _, _, _, _, _) ->
6707       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
6708       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6709   ) all_functions;
6710
6711   pr "}\n"
6712
6713 (* Ruby code to return an LVM struct list. *)
6714 and generate_ruby_lvm_code typ cols =
6715   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
6716   pr "  int i;\n";
6717   pr "  for (i = 0; i < r->len; ++i) {\n";
6718   pr "    VALUE hv = rb_hash_new ();\n";
6719   List.iter (
6720     function
6721     | name, `String ->
6722         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
6723     | name, `UUID ->
6724         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
6725     | name, `Bytes
6726     | name, `Int ->
6727         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
6728     | name, `OptPercent ->
6729         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
6730   ) cols;
6731   pr "    rb_ary_push (rv, hv);\n";
6732   pr "  }\n";
6733   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
6734   pr "  return rv;\n"
6735
6736 (* Generate Java bindings GuestFS.java file. *)
6737 and generate_java_java () =
6738   generate_header CStyle LGPLv2;
6739
6740   pr "\
6741 package com.redhat.et.libguestfs;
6742
6743 import java.util.HashMap;
6744 import com.redhat.et.libguestfs.LibGuestFSException;
6745 import com.redhat.et.libguestfs.PV;
6746 import com.redhat.et.libguestfs.VG;
6747 import com.redhat.et.libguestfs.LV;
6748 import com.redhat.et.libguestfs.Stat;
6749 import com.redhat.et.libguestfs.StatVFS;
6750 import com.redhat.et.libguestfs.IntBool;
6751
6752 /**
6753  * The GuestFS object is a libguestfs handle.
6754  *
6755  * @author rjones
6756  */
6757 public class GuestFS {
6758   // Load the native code.
6759   static {
6760     System.loadLibrary (\"guestfs_jni\");
6761   }
6762
6763   /**
6764    * The native guestfs_h pointer.
6765    */
6766   long g;
6767
6768   /**
6769    * Create a libguestfs handle.
6770    *
6771    * @throws LibGuestFSException
6772    */
6773   public GuestFS () throws LibGuestFSException
6774   {
6775     g = _create ();
6776   }
6777   private native long _create () throws LibGuestFSException;
6778
6779   /**
6780    * Close a libguestfs handle.
6781    *
6782    * You can also leave handles to be collected by the garbage
6783    * collector, but this method ensures that the resources used
6784    * by the handle are freed up immediately.  If you call any
6785    * other methods after closing the handle, you will get an
6786    * exception.
6787    *
6788    * @throws LibGuestFSException
6789    */
6790   public void close () throws LibGuestFSException
6791   {
6792     if (g != 0)
6793       _close (g);
6794     g = 0;
6795   }
6796   private native void _close (long g) throws LibGuestFSException;
6797
6798   public void finalize () throws LibGuestFSException
6799   {
6800     close ();
6801   }
6802
6803 ";
6804
6805   List.iter (
6806     fun (name, style, _, flags, _, shortdesc, longdesc) ->
6807       if not (List.mem NotInDocs flags); then (
6808         let doc = replace_str longdesc "C<guestfs_" "C<g." in
6809         let doc =
6810           if List.mem ProtocolLimitWarning flags then
6811             doc ^ "\n\n" ^ protocol_limit_warning
6812           else doc in
6813         let doc =
6814           if List.mem DangerWillRobinson flags then
6815             doc ^ "\n\n" ^ danger_will_robinson
6816           else doc in
6817         let doc = pod2text ~width:60 name doc in
6818         let doc = List.map (            (* RHBZ#501883 *)
6819           function
6820           | "" -> "<p>"
6821           | nonempty -> nonempty
6822         ) doc in
6823         let doc = String.concat "\n   * " doc in
6824
6825         pr "  /**\n";
6826         pr "   * %s\n" shortdesc;
6827         pr "   * <p>\n";
6828         pr "   * %s\n" doc;
6829         pr "   * @throws LibGuestFSException\n";
6830         pr "   */\n";
6831         pr "  ";
6832       );
6833       generate_java_prototype ~public:true ~semicolon:false name style;
6834       pr "\n";
6835       pr "  {\n";
6836       pr "    if (g == 0)\n";
6837       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
6838         name;
6839       pr "    ";
6840       if fst style <> RErr then pr "return ";
6841       pr "_%s " name;
6842       generate_call_args ~handle:"g" (snd style);
6843       pr ";\n";
6844       pr "  }\n";
6845       pr "  ";
6846       generate_java_prototype ~privat:true ~native:true name style;
6847       pr "\n";
6848       pr "\n";
6849   ) all_functions;
6850
6851   pr "}\n"
6852
6853 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
6854     ?(semicolon=true) name style =
6855   if privat then pr "private ";
6856   if public then pr "public ";
6857   if native then pr "native ";
6858
6859   (* return type *)
6860   (match fst style with
6861    | RErr -> pr "void ";
6862    | RInt _ -> pr "int ";
6863    | RInt64 _ -> pr "long ";
6864    | RBool _ -> pr "boolean ";
6865    | RConstString _ | RString _ -> pr "String ";
6866    | RStringList _ -> pr "String[] ";
6867    | RIntBool _ -> pr "IntBool ";
6868    | RPVList _ -> pr "PV[] ";
6869    | RVGList _ -> pr "VG[] ";
6870    | RLVList _ -> pr "LV[] ";
6871    | RStat _ -> pr "Stat ";
6872    | RStatVFS _ -> pr "StatVFS ";
6873    | RHashtable _ -> pr "HashMap<String,String> ";
6874   );
6875
6876   if native then pr "_%s " name else pr "%s " name;
6877   pr "(";
6878   let needs_comma = ref false in
6879   if native then (
6880     pr "long g";
6881     needs_comma := true
6882   );
6883
6884   (* args *)
6885   List.iter (
6886     fun arg ->
6887       if !needs_comma then pr ", ";
6888       needs_comma := true;
6889
6890       match arg with
6891       | String n
6892       | OptString n
6893       | FileIn n
6894       | FileOut n ->
6895           pr "String %s" n
6896       | StringList n ->
6897           pr "String[] %s" n
6898       | Bool n ->
6899           pr "boolean %s" n
6900       | Int n ->
6901           pr "int %s" n
6902   ) (snd style);
6903
6904   pr ")\n";
6905   pr "    throws LibGuestFSException";
6906   if semicolon then pr ";"
6907
6908 and generate_java_struct typ cols =
6909   generate_header CStyle LGPLv2;
6910
6911   pr "\
6912 package com.redhat.et.libguestfs;
6913
6914 /**
6915  * Libguestfs %s structure.
6916  *
6917  * @author rjones
6918  * @see GuestFS
6919  */
6920 public class %s {
6921 " typ typ;
6922
6923   List.iter (
6924     function
6925     | name, `String
6926     | name, `UUID -> pr "  public String %s;\n" name
6927     | name, `Bytes
6928     | name, `Int -> pr "  public long %s;\n" name
6929     | name, `OptPercent ->
6930         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
6931         pr "  public float %s;\n" name
6932   ) cols;
6933
6934   pr "}\n"
6935
6936 and generate_java_c () =
6937   generate_header CStyle LGPLv2;
6938
6939   pr "\
6940 #include <stdio.h>
6941 #include <stdlib.h>
6942 #include <string.h>
6943
6944 #include \"com_redhat_et_libguestfs_GuestFS.h\"
6945 #include \"guestfs.h\"
6946
6947 /* Note that this function returns.  The exception is not thrown
6948  * until after the wrapper function returns.
6949  */
6950 static void
6951 throw_exception (JNIEnv *env, const char *msg)
6952 {
6953   jclass cl;
6954   cl = (*env)->FindClass (env,
6955                           \"com/redhat/et/libguestfs/LibGuestFSException\");
6956   (*env)->ThrowNew (env, cl, msg);
6957 }
6958
6959 JNIEXPORT jlong JNICALL
6960 Java_com_redhat_et_libguestfs_GuestFS__1create
6961   (JNIEnv *env, jobject obj)
6962 {
6963   guestfs_h *g;
6964
6965   g = guestfs_create ();
6966   if (g == NULL) {
6967     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
6968     return 0;
6969   }
6970   guestfs_set_error_handler (g, NULL, NULL);
6971   return (jlong) (long) g;
6972 }
6973
6974 JNIEXPORT void JNICALL
6975 Java_com_redhat_et_libguestfs_GuestFS__1close
6976   (JNIEnv *env, jobject obj, jlong jg)
6977 {
6978   guestfs_h *g = (guestfs_h *) (long) jg;
6979   guestfs_close (g);
6980 }
6981
6982 ";
6983
6984   List.iter (
6985     fun (name, style, _, _, _, _, _) ->
6986       pr "JNIEXPORT ";
6987       (match fst style with
6988        | RErr -> pr "void ";
6989        | RInt _ -> pr "jint ";
6990        | RInt64 _ -> pr "jlong ";
6991        | RBool _ -> pr "jboolean ";
6992        | RConstString _ | RString _ -> pr "jstring ";
6993        | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
6994            pr "jobject ";
6995        | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
6996            pr "jobjectArray ";
6997       );
6998       pr "JNICALL\n";
6999       pr "Java_com_redhat_et_libguestfs_GuestFS_";
7000       pr "%s" (replace_str ("_" ^ name) "_" "_1");
7001       pr "\n";
7002       pr "  (JNIEnv *env, jobject obj, jlong jg";
7003       List.iter (
7004         function
7005         | String n
7006         | OptString n
7007         | FileIn n
7008         | FileOut n ->
7009             pr ", jstring j%s" n
7010         | StringList n ->
7011             pr ", jobjectArray j%s" n
7012         | Bool n ->
7013             pr ", jboolean j%s" n
7014         | Int n ->
7015             pr ", jint j%s" n
7016       ) (snd style);
7017       pr ")\n";
7018       pr "{\n";
7019       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
7020       let error_code, no_ret =
7021         match fst style with
7022         | RErr -> pr "  int r;\n"; "-1", ""
7023         | RBool _
7024         | RInt _ -> pr "  int r;\n"; "-1", "0"
7025         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
7026         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
7027         | RString _ ->
7028             pr "  jstring jr;\n";
7029             pr "  char *r;\n"; "NULL", "NULL"
7030         | RStringList _ ->
7031             pr "  jobjectArray jr;\n";
7032             pr "  int r_len;\n";
7033             pr "  jclass cl;\n";
7034             pr "  jstring jstr;\n";
7035             pr "  char **r;\n"; "NULL", "NULL"
7036         | RIntBool _ ->
7037             pr "  jobject jr;\n";
7038             pr "  jclass cl;\n";
7039             pr "  jfieldID fl;\n";
7040             pr "  struct guestfs_int_bool *r;\n"; "NULL", "NULL"
7041         | RStat _ ->
7042             pr "  jobject jr;\n";
7043             pr "  jclass cl;\n";
7044             pr "  jfieldID fl;\n";
7045             pr "  struct guestfs_stat *r;\n"; "NULL", "NULL"
7046         | RStatVFS _ ->
7047             pr "  jobject jr;\n";
7048             pr "  jclass cl;\n";
7049             pr "  jfieldID fl;\n";
7050             pr "  struct guestfs_statvfs *r;\n"; "NULL", "NULL"
7051         | RPVList _ ->
7052             pr "  jobjectArray jr;\n";
7053             pr "  jclass cl;\n";
7054             pr "  jfieldID fl;\n";
7055             pr "  jobject jfl;\n";
7056             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
7057         | RVGList _ ->
7058             pr "  jobjectArray jr;\n";
7059             pr "  jclass cl;\n";
7060             pr "  jfieldID fl;\n";
7061             pr "  jobject jfl;\n";
7062             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
7063         | RLVList _ ->
7064             pr "  jobjectArray jr;\n";
7065             pr "  jclass cl;\n";
7066             pr "  jfieldID fl;\n";
7067             pr "  jobject jfl;\n";
7068             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
7069         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL" in
7070       List.iter (
7071         function
7072         | String n
7073         | OptString n
7074         | FileIn n
7075         | FileOut n ->
7076             pr "  const char *%s;\n" n
7077         | StringList n ->
7078             pr "  int %s_len;\n" n;
7079             pr "  const char **%s;\n" n
7080         | Bool n
7081         | Int n ->
7082             pr "  int %s;\n" n
7083       ) (snd style);
7084
7085       let needs_i =
7086         (match fst style with
7087          | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
7088          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
7089          | RString _ | RIntBool _ | RStat _ | RStatVFS _
7090          | RHashtable _ -> false) ||
7091         List.exists (function StringList _ -> true | _ -> false) (snd style) in
7092       if needs_i then
7093         pr "  int i;\n";
7094
7095       pr "\n";
7096
7097       (* Get the parameters. *)
7098       List.iter (
7099         function
7100         | String n
7101         | FileIn n
7102         | FileOut n ->
7103             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
7104         | OptString n ->
7105             (* This is completely undocumented, but Java null becomes
7106              * a NULL parameter.
7107              *)
7108             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
7109         | StringList n ->
7110             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
7111             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
7112             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
7113             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7114               n;
7115             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
7116             pr "  }\n";
7117             pr "  %s[%s_len] = NULL;\n" n n;
7118         | Bool n
7119         | Int n ->
7120             pr "  %s = j%s;\n" n n
7121       ) (snd style);
7122
7123       (* Make the call. *)
7124       pr "  r = guestfs_%s " name;
7125       generate_call_args ~handle:"g" (snd style);
7126       pr ";\n";
7127
7128       (* Release the parameters. *)
7129       List.iter (
7130         function
7131         | String n
7132         | FileIn n
7133         | FileOut n ->
7134             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7135         | OptString n ->
7136             pr "  if (j%s)\n" n;
7137             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7138         | StringList n ->
7139             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
7140             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7141               n;
7142             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
7143             pr "  }\n";
7144             pr "  free (%s);\n" n
7145         | Bool n
7146         | Int n -> ()
7147       ) (snd style);
7148
7149       (* Check for errors. *)
7150       pr "  if (r == %s) {\n" error_code;
7151       pr "    throw_exception (env, guestfs_last_error (g));\n";
7152       pr "    return %s;\n" no_ret;
7153       pr "  }\n";
7154
7155       (* Return value. *)
7156       (match fst style with
7157        | RErr -> ()
7158        | RInt _ -> pr "  return (jint) r;\n"
7159        | RBool _ -> pr "  return (jboolean) r;\n"
7160        | RInt64 _ -> pr "  return (jlong) r;\n"
7161        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
7162        | RString _ ->
7163            pr "  jr = (*env)->NewStringUTF (env, r);\n";
7164            pr "  free (r);\n";
7165            pr "  return jr;\n"
7166        | RStringList _ ->
7167            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7168            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7169            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
7170            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7171            pr "  for (i = 0; i < r_len; ++i) {\n";
7172            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
7173            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7174            pr "    free (r[i]);\n";
7175            pr "  }\n";
7176            pr "  free (r);\n";
7177            pr "  return jr;\n"
7178        | RIntBool _ ->
7179            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
7180            pr "  jr = (*env)->AllocObject (env, cl);\n";
7181            pr "  fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
7182            pr "  (*env)->SetIntField (env, jr, fl, r->i);\n";
7183            pr "  fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
7184            pr "  (*env)->SetBooleanField (env, jr, fl, r->b);\n";
7185            pr "  guestfs_free_int_bool (r);\n";
7186            pr "  return jr;\n"
7187        | RStat _ ->
7188            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
7189            pr "  jr = (*env)->AllocObject (env, cl);\n";
7190            List.iter (
7191              function
7192              | name, `Int ->
7193                  pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7194                    name;
7195                  pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7196            ) stat_cols;
7197            pr "  free (r);\n";
7198            pr "  return jr;\n"
7199        | RStatVFS _ ->
7200            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
7201            pr "  jr = (*env)->AllocObject (env, cl);\n";
7202            List.iter (
7203              function
7204              | name, `Int ->
7205                  pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7206                    name;
7207                  pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7208            ) statvfs_cols;
7209            pr "  free (r);\n";
7210            pr "  return jr;\n"
7211        | RPVList _ ->
7212            generate_java_lvm_return "pv" "PV" pv_cols
7213        | RVGList _ ->
7214            generate_java_lvm_return "vg" "VG" vg_cols
7215        | RLVList _ ->
7216            generate_java_lvm_return "lv" "LV" lv_cols
7217        | RHashtable _ ->
7218            (* XXX *)
7219            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7220            pr "  return NULL;\n"
7221       );
7222
7223       pr "}\n";
7224       pr "\n"
7225   ) all_functions
7226
7227 and generate_java_lvm_return typ jtyp cols =
7228   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7229   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7230   pr "  for (i = 0; i < r->len; ++i) {\n";
7231   pr "    jfl = (*env)->AllocObject (env, cl);\n";
7232   List.iter (
7233     function
7234     | name, `String ->
7235         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7236         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7237     | name, `UUID ->
7238         pr "    {\n";
7239         pr "      char s[33];\n";
7240         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
7241         pr "      s[32] = 0;\n";
7242         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7243         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7244         pr "    }\n";
7245     | name, (`Bytes|`Int) ->
7246         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7247         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7248     | name, `OptPercent ->
7249         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7250         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7251   ) cols;
7252   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7253   pr "  }\n";
7254   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
7255   pr "  return jr;\n"
7256
7257 and generate_haskell_hs () =
7258   generate_header HaskellStyle LGPLv2;
7259
7260   (* XXX We only know how to generate partial FFI for Haskell
7261    * at the moment.  Please help out!
7262    *)
7263   let can_generate style =
7264     let check_no_bad_args =
7265       List.for_all (function Bool _ | Int _ -> false | _ -> true)
7266     in
7267     match style with
7268     | RErr, args -> check_no_bad_args args
7269     | RBool _, _
7270     | RInt _, _
7271     | RInt64 _, _
7272     | RConstString _, _
7273     | RString _, _
7274     | RStringList _, _
7275     | RIntBool _, _
7276     | RPVList _, _
7277     | RVGList _, _
7278     | RLVList _, _
7279     | RStat _, _
7280     | RStatVFS _, _
7281     | RHashtable _, _ -> false in
7282
7283   pr "\
7284 {-# INCLUDE <guestfs.h> #-}
7285 {-# LANGUAGE ForeignFunctionInterface #-}
7286
7287 module Guestfs (
7288   create";
7289
7290   (* List out the names of the actions we want to export. *)
7291   List.iter (
7292     fun (name, style, _, _, _, _, _) ->
7293       if can_generate style then pr ",\n  %s" name
7294   ) all_functions;
7295
7296   pr "
7297   ) where
7298 import Foreign
7299 import Foreign.C
7300 import IO
7301 import Control.Exception
7302 import Data.Typeable
7303
7304 data GuestfsS = GuestfsS            -- represents the opaque C struct
7305 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
7306 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7307
7308 -- XXX define properly later XXX
7309 data PV = PV
7310 data VG = VG
7311 data LV = LV
7312 data IntBool = IntBool
7313 data Stat = Stat
7314 data StatVFS = StatVFS
7315 data Hashtable = Hashtable
7316
7317 foreign import ccall unsafe \"guestfs_create\" c_create
7318   :: IO GuestfsP
7319 foreign import ccall unsafe \"&guestfs_close\" c_close
7320   :: FunPtr (GuestfsP -> IO ())
7321 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
7322   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
7323
7324 create :: IO GuestfsH
7325 create = do
7326   p <- c_create
7327   c_set_error_handler p nullPtr nullPtr
7328   h <- newForeignPtr c_close p
7329   return h
7330
7331 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
7332   :: GuestfsP -> IO CString
7333
7334 -- last_error :: GuestfsH -> IO (Maybe String)
7335 -- last_error h = do
7336 --   str <- withForeignPtr h (\\p -> c_last_error p)
7337 --   maybePeek peekCString str
7338
7339 last_error :: GuestfsH -> IO (String)
7340 last_error h = do
7341   str <- withForeignPtr h (\\p -> c_last_error p)
7342   if (str == nullPtr)
7343     then return \"no error\"
7344     else peekCString str
7345
7346 ";
7347
7348   (* Generate wrappers for each foreign function. *)
7349   List.iter (
7350     fun (name, style, _, _, _, _, _) ->
7351       if can_generate style then (
7352         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7353         pr "  :: ";
7354         generate_haskell_prototype ~handle:"GuestfsP" style;
7355         pr "\n";
7356         pr "\n";
7357         pr "%s :: " name;
7358         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7359         pr "\n";
7360         pr "%s %s = do\n" name
7361           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7362         pr "  r <- ";
7363         List.iter (
7364           function
7365           | FileIn n
7366           | FileOut n
7367           | String n -> pr "withCString %s $ \\%s -> " n n
7368           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7369           | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7370           | Bool n ->
7371               (* XXX this doesn't work *)
7372               pr "      let\n";
7373               pr "        %s = case %s of\n" n n;
7374               pr "          False -> 0\n";
7375               pr "          True -> 1\n";
7376               pr "      in fromIntegral %s $ \\%s ->\n" n n
7377           | Int n -> pr "fromIntegral %s $ \\%s -> " n n
7378         ) (snd style);
7379         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7380           (String.concat " " ("p" :: List.map name_of_argt (snd style)));
7381         (match fst style with
7382          | RErr | RInt _ | RInt64 _ | RBool _ ->
7383              pr "  if (r == -1)\n";
7384              pr "    then do\n";
7385              pr "      err <- last_error h\n";
7386              pr "      fail err\n";
7387          | RConstString _ | RString _ | RStringList _ | RIntBool _
7388          | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7389          | RHashtable _ ->
7390              pr "  if (r == nullPtr)\n";
7391              pr "    then do\n";
7392              pr "      err <- last_error h\n";
7393              pr "      fail err\n";
7394         );
7395         (match fst style with
7396          | RErr ->
7397              pr "    else return ()\n"
7398          | RInt _ ->
7399              pr "    else return (fromIntegral r)\n"
7400          | RInt64 _ ->
7401              pr "    else return (fromIntegral r)\n"
7402          | RBool _ ->
7403              pr "    else return (toBool r)\n"
7404          | RConstString _
7405          | RString _
7406          | RStringList _
7407          | RIntBool _
7408          | RPVList _
7409          | RVGList _
7410          | RLVList _
7411          | RStat _
7412          | RStatVFS _
7413          | RHashtable _ ->
7414              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7415         );
7416         pr "\n";
7417       )
7418   ) all_functions
7419
7420 and generate_haskell_prototype ~handle ?(hs = false) style =
7421   pr "%s -> " handle;
7422   let string = if hs then "String" else "CString" in
7423   let int = if hs then "Int" else "CInt" in
7424   let bool = if hs then "Bool" else "CInt" in
7425   let int64 = if hs then "Integer" else "Int64" in
7426   List.iter (
7427     fun arg ->
7428       (match arg with
7429        | String _ -> pr "%s" string
7430        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7431        | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7432        | Bool _ -> pr "%s" bool
7433        | Int _ -> pr "%s" int
7434        | FileIn _ -> pr "%s" string
7435        | FileOut _ -> pr "%s" string
7436       );
7437       pr " -> ";
7438   ) (snd style);
7439   pr "IO (";
7440   (match fst style with
7441    | RErr -> if not hs then pr "CInt"
7442    | RInt _ -> pr "%s" int
7443    | RInt64 _ -> pr "%s" int64
7444    | RBool _ -> pr "%s" bool
7445    | RConstString _ -> pr "%s" string
7446    | RString _ -> pr "%s" string
7447    | RStringList _ -> pr "[%s]" string
7448    | RIntBool _ -> pr "IntBool"
7449    | RPVList _ -> pr "[PV]"
7450    | RVGList _ -> pr "[VG]"
7451    | RLVList _ -> pr "[LV]"
7452    | RStat _ -> pr "Stat"
7453    | RStatVFS _ -> pr "StatVFS"
7454    | RHashtable _ -> pr "Hashtable"
7455   );
7456   pr ")"
7457
7458 and generate_bindtests () =
7459   generate_header CStyle LGPLv2;
7460
7461   pr "\
7462 #include <stdio.h>
7463 #include <stdlib.h>
7464 #include <inttypes.h>
7465 #include <string.h>
7466
7467 #include \"guestfs.h\"
7468 #include \"guestfs_protocol.h\"
7469
7470 #define error guestfs_error
7471
7472 static void
7473 print_strings (char * const* const argv)
7474 {
7475   int argc;
7476
7477   printf (\"[\");
7478   for (argc = 0; argv[argc] != NULL; ++argc) {
7479     if (argc > 0) printf (\", \");
7480     printf (\"\\\"%%s\\\"\", argv[argc]);
7481   }
7482   printf (\"]\\n\");
7483 }
7484
7485 /* The test0 function prints its parameters to stdout. */
7486 ";
7487
7488   let test0, tests =
7489     match test_functions with
7490     | [] -> assert false
7491     | test0 :: tests -> test0, tests in
7492
7493   let () =
7494     let (name, style, _, _, _, _, _) = test0 in
7495     generate_prototype ~extern:false ~semicolon:false ~newline:true
7496       ~handle:"g" ~prefix:"guestfs_" name style;
7497     pr "{\n";
7498     List.iter (
7499       function
7500       | String n
7501       | FileIn n
7502       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
7503       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
7504       | StringList n -> pr "  print_strings (%s);\n" n
7505       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
7506       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
7507     ) (snd style);
7508     pr "  /* Java changes stdout line buffering so we need this: */\n";
7509     pr "  fflush (stdout);\n";
7510     pr "  return 0;\n";
7511     pr "}\n";
7512     pr "\n" in
7513
7514   List.iter (
7515     fun (name, style, _, _, _, _, _) ->
7516       if String.sub name (String.length name - 3) 3 <> "err" then (
7517         pr "/* Test normal return. */\n";
7518         generate_prototype ~extern:false ~semicolon:false ~newline:true
7519           ~handle:"g" ~prefix:"guestfs_" name style;
7520         pr "{\n";
7521         (match fst style with
7522          | RErr ->
7523              pr "  return 0;\n"
7524          | RInt _ ->
7525              pr "  int r;\n";
7526              pr "  sscanf (val, \"%%d\", &r);\n";
7527              pr "  return r;\n"
7528          | RInt64 _ ->
7529              pr "  int64_t r;\n";
7530              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
7531              pr "  return r;\n"
7532          | RBool _ ->
7533              pr "  return strcmp (val, \"true\") == 0;\n"
7534          | RConstString _ ->
7535              (* Can't return the input string here.  Return a static
7536               * string so we ensure we get a segfault if the caller
7537               * tries to free it.
7538               *)
7539              pr "  return \"static string\";\n"
7540          | RString _ ->
7541              pr "  return strdup (val);\n"
7542          | RStringList _ ->
7543              pr "  char **strs;\n";
7544              pr "  int n, i;\n";
7545              pr "  sscanf (val, \"%%d\", &n);\n";
7546              pr "  strs = malloc ((n+1) * sizeof (char *));\n";
7547              pr "  for (i = 0; i < n; ++i) {\n";
7548              pr "    strs[i] = malloc (16);\n";
7549              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
7550              pr "  }\n";
7551              pr "  strs[n] = NULL;\n";
7552              pr "  return strs;\n"
7553          | RIntBool _ ->
7554              pr "  struct guestfs_int_bool *r;\n";
7555              pr "  r = malloc (sizeof (struct guestfs_int_bool));\n";
7556              pr "  sscanf (val, \"%%\" SCNi32, &r->i);\n";
7557              pr "  r->b = 0;\n";
7558              pr "  return r;\n"
7559          | RPVList _ ->
7560              pr "  struct guestfs_lvm_pv_list *r;\n";
7561              pr "  int i;\n";
7562              pr "  r = malloc (sizeof (struct guestfs_lvm_pv_list));\n";
7563              pr "  sscanf (val, \"%%d\", &r->len);\n";
7564              pr "  r->val = calloc (r->len, sizeof (struct guestfs_lvm_pv));\n";
7565              pr "  for (i = 0; i < r->len; ++i) {\n";
7566              pr "    r->val[i].pv_name = malloc (16);\n";
7567              pr "    snprintf (r->val[i].pv_name, 16, \"%%d\", i);\n";
7568              pr "  }\n";
7569              pr "  return r;\n"
7570          | RVGList _ ->
7571              pr "  struct guestfs_lvm_vg_list *r;\n";
7572              pr "  int i;\n";
7573              pr "  r = malloc (sizeof (struct guestfs_lvm_vg_list));\n";
7574              pr "  sscanf (val, \"%%d\", &r->len);\n";
7575              pr "  r->val = calloc (r->len, sizeof (struct guestfs_lvm_vg));\n";
7576              pr "  for (i = 0; i < r->len; ++i) {\n";
7577              pr "    r->val[i].vg_name = malloc (16);\n";
7578              pr "    snprintf (r->val[i].vg_name, 16, \"%%d\", i);\n";
7579              pr "  }\n";
7580              pr "  return r;\n"
7581          | RLVList _ ->
7582              pr "  struct guestfs_lvm_lv_list *r;\n";
7583              pr "  int i;\n";
7584              pr "  r = malloc (sizeof (struct guestfs_lvm_lv_list));\n";
7585              pr "  sscanf (val, \"%%d\", &r->len);\n";
7586              pr "  r->val = calloc (r->len, sizeof (struct guestfs_lvm_lv));\n";
7587              pr "  for (i = 0; i < r->len; ++i) {\n";
7588              pr "    r->val[i].lv_name = malloc (16);\n";
7589              pr "    snprintf (r->val[i].lv_name, 16, \"%%d\", i);\n";
7590              pr "  }\n";
7591              pr "  return r;\n"
7592          | RStat _ ->
7593              pr "  struct guestfs_stat *r;\n";
7594              pr "  r = calloc (1, sizeof (*r));\n";
7595              pr "  sscanf (val, \"%%\" SCNi64, &r->dev);\n";
7596              pr "  return r;\n"
7597          | RStatVFS _ ->
7598              pr "  struct guestfs_statvfs *r;\n";
7599              pr "  r = calloc (1, sizeof (*r));\n";
7600              pr "  sscanf (val, \"%%\" SCNi64, &r->bsize);\n";
7601              pr "  return r;\n"
7602          | RHashtable _ ->
7603              pr "  char **strs;\n";
7604              pr "  int n, i;\n";
7605              pr "  sscanf (val, \"%%d\", &n);\n";
7606              pr "  strs = malloc ((n*2+1) * sizeof (char *));\n";
7607              pr "  for (i = 0; i < n; ++i) {\n";
7608              pr "    strs[i*2] = malloc (16);\n";
7609              pr "    strs[i*2+1] = malloc (16);\n";
7610              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
7611              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
7612              pr "  }\n";
7613              pr "  strs[n*2] = NULL;\n";
7614              pr "  return strs;\n"
7615         );
7616         pr "}\n";
7617         pr "\n"
7618       ) else (
7619         pr "/* Test error return. */\n";
7620         generate_prototype ~extern:false ~semicolon:false ~newline:true
7621           ~handle:"g" ~prefix:"guestfs_" name style;
7622         pr "{\n";
7623         pr "  error (g, \"error\");\n";
7624         (match fst style with
7625          | RErr | RInt _ | RInt64 _ | RBool _ ->
7626              pr "  return -1;\n"
7627          | RConstString _
7628          | RString _ | RStringList _ | RIntBool _
7629          | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7630          | RHashtable _ ->
7631              pr "  return NULL;\n"
7632         );
7633         pr "}\n";
7634         pr "\n"
7635       )
7636   ) tests
7637
7638 and generate_ocaml_bindtests () =
7639   generate_header OCamlStyle GPLv2;
7640
7641   pr "\
7642 let () =
7643   let g = Guestfs.create () in
7644 ";
7645
7646   let mkargs args =
7647     String.concat " " (
7648       List.map (
7649         function
7650         | CallString s -> "\"" ^ s ^ "\""
7651         | CallOptString None -> "None"
7652         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
7653         | CallStringList xs ->
7654             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
7655         | CallInt i when i >= 0 -> string_of_int i
7656         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
7657         | CallBool b -> string_of_bool b
7658       ) args
7659     )
7660   in
7661
7662   generate_lang_bindtests (
7663     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
7664   );
7665
7666   pr "print_endline \"EOF\"\n"
7667
7668 and generate_perl_bindtests () =
7669   pr "#!/usr/bin/perl -w\n";
7670   generate_header HashStyle GPLv2;
7671
7672   pr "\
7673 use strict;
7674
7675 use Sys::Guestfs;
7676
7677 my $g = Sys::Guestfs->new ();
7678 ";
7679
7680   let mkargs args =
7681     String.concat ", " (
7682       List.map (
7683         function
7684         | CallString s -> "\"" ^ s ^ "\""
7685         | CallOptString None -> "undef"
7686         | CallOptString (Some s) -> sprintf "\"%s\"" s
7687         | CallStringList xs ->
7688             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7689         | CallInt i -> string_of_int i
7690         | CallBool b -> if b then "1" else "0"
7691       ) args
7692     )
7693   in
7694
7695   generate_lang_bindtests (
7696     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
7697   );
7698
7699   pr "print \"EOF\\n\"\n"
7700
7701 and generate_python_bindtests () =
7702   generate_header HashStyle GPLv2;
7703
7704   pr "\
7705 import guestfs
7706
7707 g = guestfs.GuestFS ()
7708 ";
7709
7710   let mkargs args =
7711     String.concat ", " (
7712       List.map (
7713         function
7714         | CallString s -> "\"" ^ s ^ "\""
7715         | CallOptString None -> "None"
7716         | CallOptString (Some s) -> sprintf "\"%s\"" s
7717         | CallStringList xs ->
7718             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7719         | CallInt i -> string_of_int i
7720         | CallBool b -> if b then "1" else "0"
7721       ) args
7722     )
7723   in
7724
7725   generate_lang_bindtests (
7726     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
7727   );
7728
7729   pr "print \"EOF\"\n"
7730
7731 and generate_ruby_bindtests () =
7732   generate_header HashStyle GPLv2;
7733
7734   pr "\
7735 require 'guestfs'
7736
7737 g = Guestfs::create()
7738 ";
7739
7740   let mkargs args =
7741     String.concat ", " (
7742       List.map (
7743         function
7744         | CallString s -> "\"" ^ s ^ "\""
7745         | CallOptString None -> "nil"
7746         | CallOptString (Some s) -> sprintf "\"%s\"" s
7747         | CallStringList xs ->
7748             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7749         | CallInt i -> string_of_int i
7750         | CallBool b -> string_of_bool b
7751       ) args
7752     )
7753   in
7754
7755   generate_lang_bindtests (
7756     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
7757   );
7758
7759   pr "print \"EOF\\n\"\n"
7760
7761 and generate_java_bindtests () =
7762   generate_header CStyle GPLv2;
7763
7764   pr "\
7765 import com.redhat.et.libguestfs.*;
7766
7767 public class Bindtests {
7768     public static void main (String[] argv)
7769     {
7770         try {
7771             GuestFS g = new GuestFS ();
7772 ";
7773
7774   let mkargs args =
7775     String.concat ", " (
7776       List.map (
7777         function
7778         | CallString s -> "\"" ^ s ^ "\""
7779         | CallOptString None -> "null"
7780         | CallOptString (Some s) -> sprintf "\"%s\"" s
7781         | CallStringList xs ->
7782             "new String[]{" ^
7783               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
7784         | CallInt i -> string_of_int i
7785         | CallBool b -> string_of_bool b
7786       ) args
7787     )
7788   in
7789
7790   generate_lang_bindtests (
7791     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
7792   );
7793
7794   pr "
7795             System.out.println (\"EOF\");
7796         }
7797         catch (Exception exn) {
7798             System.err.println (exn);
7799             System.exit (1);
7800         }
7801     }
7802 }
7803 "
7804
7805 and generate_haskell_bindtests () =
7806   () (* XXX Haskell bindings need to be fleshed out. *)
7807
7808 (* Language-independent bindings tests - we do it this way to
7809  * ensure there is parity in testing bindings across all languages.
7810  *)
7811 and generate_lang_bindtests call =
7812   call "test0" [CallString "abc"; CallOptString (Some "def");
7813                 CallStringList []; CallBool false;
7814                 CallInt 0; CallString "123"; CallString "456"];
7815   call "test0" [CallString "abc"; CallOptString None;
7816                 CallStringList []; CallBool false;
7817                 CallInt 0; CallString "123"; CallString "456"];
7818   call "test0" [CallString ""; CallOptString (Some "def");
7819                 CallStringList []; CallBool false;
7820                 CallInt 0; CallString "123"; CallString "456"];
7821   call "test0" [CallString ""; CallOptString (Some "");
7822                 CallStringList []; CallBool false;
7823                 CallInt 0; CallString "123"; CallString "456"];
7824   call "test0" [CallString "abc"; CallOptString (Some "def");
7825                 CallStringList ["1"]; CallBool false;
7826                 CallInt 0; CallString "123"; CallString "456"];
7827   call "test0" [CallString "abc"; CallOptString (Some "def");
7828                 CallStringList ["1"; "2"]; CallBool false;
7829                 CallInt 0; CallString "123"; CallString "456"];
7830   call "test0" [CallString "abc"; CallOptString (Some "def");
7831                 CallStringList ["1"]; CallBool true;
7832                 CallInt 0; CallString "123"; CallString "456"];
7833   call "test0" [CallString "abc"; CallOptString (Some "def");
7834                 CallStringList ["1"]; CallBool false;
7835                 CallInt (-1); CallString "123"; CallString "456"];
7836   call "test0" [CallString "abc"; CallOptString (Some "def");
7837                 CallStringList ["1"]; CallBool false;
7838                 CallInt (-2); CallString "123"; CallString "456"];
7839   call "test0" [CallString "abc"; CallOptString (Some "def");
7840                 CallStringList ["1"]; CallBool false;
7841                 CallInt 1; CallString "123"; CallString "456"];
7842   call "test0" [CallString "abc"; CallOptString (Some "def");
7843                 CallStringList ["1"]; CallBool false;
7844                 CallInt 2; CallString "123"; CallString "456"];
7845   call "test0" [CallString "abc"; CallOptString (Some "def");
7846                 CallStringList ["1"]; CallBool false;
7847                 CallInt 4095; CallString "123"; CallString "456"];
7848   call "test0" [CallString "abc"; CallOptString (Some "def");
7849                 CallStringList ["1"]; CallBool false;
7850                 CallInt 0; CallString ""; CallString ""]
7851
7852   (* XXX Add here tests of the return and error functions. *)
7853
7854 (* This is used to generate the src/MAX_PROC_NR file which
7855  * contains the maximum procedure number, a surrogate for the
7856  * ABI version number.  See src/Makefile.am for the details.
7857  *)
7858 and generate_max_proc_nr () =
7859   let proc_nrs = List.map (
7860     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
7861   ) daemon_functions in
7862
7863   let max_proc_nr = List.fold_left max 0 proc_nrs in
7864
7865   pr "%d\n" max_proc_nr
7866
7867 let output_to filename =
7868   let filename_new = filename ^ ".new" in
7869   chan := open_out filename_new;
7870   let close () =
7871     close_out !chan;
7872     chan := stdout;
7873
7874     (* Is the new file different from the current file? *)
7875     if Sys.file_exists filename && files_equal filename filename_new then
7876       Unix.unlink filename_new          (* same, so skip it *)
7877     else (
7878       (* different, overwrite old one *)
7879       (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
7880       Unix.rename filename_new filename;
7881       Unix.chmod filename 0o444;
7882       printf "written %s\n%!" filename;
7883     )
7884   in
7885   close
7886
7887 (* Main program. *)
7888 let () =
7889   check_functions ();
7890
7891   if not (Sys.file_exists "configure.ac") then (
7892     eprintf "\
7893 You are probably running this from the wrong directory.
7894 Run it from the top source directory using the command
7895   src/generator.ml
7896 ";
7897     exit 1
7898   );
7899
7900   let close = output_to "src/guestfs_protocol.x" in
7901   generate_xdr ();
7902   close ();
7903
7904   let close = output_to "src/guestfs-structs.h" in
7905   generate_structs_h ();
7906   close ();
7907
7908   let close = output_to "src/guestfs-actions.h" in
7909   generate_actions_h ();
7910   close ();
7911
7912   let close = output_to "src/guestfs-actions.c" in
7913   generate_client_actions ();
7914   close ();
7915
7916   let close = output_to "daemon/actions.h" in
7917   generate_daemon_actions_h ();
7918   close ();
7919
7920   let close = output_to "daemon/stubs.c" in
7921   generate_daemon_actions ();
7922   close ();
7923
7924   let close = output_to "capitests/tests.c" in
7925   generate_tests ();
7926   close ();
7927
7928   let close = output_to "src/guestfs-bindtests.c" in
7929   generate_bindtests ();
7930   close ();
7931
7932   let close = output_to "fish/cmds.c" in
7933   generate_fish_cmds ();
7934   close ();
7935
7936   let close = output_to "fish/completion.c" in
7937   generate_fish_completion ();
7938   close ();
7939
7940   let close = output_to "guestfs-structs.pod" in
7941   generate_structs_pod ();
7942   close ();
7943
7944   let close = output_to "guestfs-actions.pod" in
7945   generate_actions_pod ();
7946   close ();
7947
7948   let close = output_to "guestfish-actions.pod" in
7949   generate_fish_actions_pod ();
7950   close ();
7951
7952   let close = output_to "ocaml/guestfs.mli" in
7953   generate_ocaml_mli ();
7954   close ();
7955
7956   let close = output_to "ocaml/guestfs.ml" in
7957   generate_ocaml_ml ();
7958   close ();
7959
7960   let close = output_to "ocaml/guestfs_c_actions.c" in
7961   generate_ocaml_c ();
7962   close ();
7963
7964   let close = output_to "ocaml/bindtests.ml" in
7965   generate_ocaml_bindtests ();
7966   close ();
7967
7968   let close = output_to "perl/Guestfs.xs" in
7969   generate_perl_xs ();
7970   close ();
7971
7972   let close = output_to "perl/lib/Sys/Guestfs.pm" in
7973   generate_perl_pm ();
7974   close ();
7975
7976   let close = output_to "perl/bindtests.pl" in
7977   generate_perl_bindtests ();
7978   close ();
7979
7980   let close = output_to "python/guestfs-py.c" in
7981   generate_python_c ();
7982   close ();
7983
7984   let close = output_to "python/guestfs.py" in
7985   generate_python_py ();
7986   close ();
7987
7988   let close = output_to "python/bindtests.py" in
7989   generate_python_bindtests ();
7990   close ();
7991
7992   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
7993   generate_ruby_c ();
7994   close ();
7995
7996   let close = output_to "ruby/bindtests.rb" in
7997   generate_ruby_bindtests ();
7998   close ();
7999
8000   let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
8001   generate_java_java ();
8002   close ();
8003
8004   let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
8005   generate_java_struct "PV" pv_cols;
8006   close ();
8007
8008   let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
8009   generate_java_struct "VG" vg_cols;
8010   close ();
8011
8012   let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
8013   generate_java_struct "LV" lv_cols;
8014   close ();
8015
8016   let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
8017   generate_java_struct "Stat" stat_cols;
8018   close ();
8019
8020   let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
8021   generate_java_struct "StatVFS" statvfs_cols;
8022   close ();
8023
8024   let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
8025   generate_java_c ();
8026   close ();
8027
8028   let close = output_to "java/Bindtests.java" in
8029   generate_java_bindtests ();
8030   close ();
8031
8032   let close = output_to "haskell/Guestfs.hs" in
8033   generate_haskell_hs ();
8034   close ();
8035
8036   let close = output_to "haskell/bindtests.hs" in
8037   generate_haskell_bindtests ();
8038   close ();
8039
8040   let close = output_to "src/MAX_PROC_NR" in
8041   generate_max_proc_nr ();
8042   close ();