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