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