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