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