960973da0071709623e88cf8574d063e46dc02f0
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009 Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *)
19
20 (* This script generates a large amount of code and documentation for
21  * all the daemon actions.
22  *
23  * To add a new action there are only two files you need to change,
24  * this one to describe the interface (see the big table below), and
25  * daemon/<somefile>.c to write the implementation.
26  *
27  * After editing this file, run it (./src/generator.ml) to regenerate
28  * all the output files.
29  *
30  * IMPORTANT: This script should NOT print any warnings.  If it prints
31  * warnings, you should treat them as errors.
32  * [Need to add -warn-error to ocaml command line]
33  *)
34
35 #load "unix.cma";;
36 #load "str.cma";;
37
38 open Printf
39
40 type style = ret * args
41 and ret =
42     (* "RErr" as a return value means an int used as a simple error
43      * indication, ie. 0 or -1.
44      *)
45   | RErr
46     (* "RInt" as a return value means an int which is -1 for error
47      * or any value >= 0 on success.  Only use this for smallish
48      * positive ints (0 <= i < 2^30).
49      *)
50   | RInt of string
51     (* "RInt64" is the same as RInt, but is guaranteed to be able
52      * to return a full 64 bit value, _except_ that -1 means error
53      * (so -1 cannot be a valid, non-error return value).
54      *)
55   | RInt64 of string
56     (* "RBool" is a bool return value which can be true/false or
57      * -1 for error.
58      *)
59   | RBool of string
60     (* "RConstString" is a string that refers to a constant value.
61      * Try to avoid using this.  In particular you cannot use this
62      * for values returned from the daemon, because there is no
63      * thread-safe way to return them in the C API.
64      *)
65   | RConstString of string
66     (* "RString" and "RStringList" are caller-frees. *)
67   | RString of string
68   | RStringList of string
69     (* Some limited tuples are possible: *)
70   | RIntBool of string * string
71     (* LVM PVs, VGs and LVs. *)
72   | RPVList of string
73   | RVGList of string
74   | RLVList of string
75     (* Stat buffers. *)
76   | RStat of string
77   | RStatVFS of string
78     (* Key-value pairs of untyped strings.  Turns into a hashtable or
79      * dictionary in languages which support it.  DON'T use this as a
80      * general "bucket" for results.  Prefer a stronger typed return
81      * value if one is available, or write a custom struct.  Don't use
82      * this if the list could potentially be very long, since it is
83      * inefficient.  Keys should be unique.  NULLs are not permitted.
84      *)
85   | RHashtable of string
86
87 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
88
89     (* Note in future we should allow a "variable args" parameter as
90      * the final parameter, to allow commands like
91      *   chmod mode file [file(s)...]
92      * This is not implemented yet, but many commands (such as chmod)
93      * are currently defined with the argument order keeping this future
94      * possibility in mind.
95      *)
96 and argt =
97   | String of string    (* const char *name, cannot be NULL *)
98   | OptString of string (* const char *name, may be NULL *)
99   | StringList of string(* list of strings (each string cannot be NULL) *)
100   | Bool of string      (* boolean *)
101   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
102     (* These are treated as filenames (simple string parameters) in
103      * the C API and bindings.  But in the RPC protocol, we transfer
104      * the actual file content up to or down from the daemon.
105      * FileIn: local machine -> daemon (in request)
106      * FileOut: daemon -> local machine (in reply)
107      * In guestfish (only), the special name "-" means read from
108      * stdin or write to stdout.
109      *)
110   | FileIn of string
111   | FileOut of string
112
113 type flags =
114   | ProtocolLimitWarning  (* display warning about protocol size limits *)
115   | DangerWillRobinson    (* flags particularly dangerous commands *)
116   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
117   | FishAction of string  (* call this function in guestfish *)
118   | NotInFish             (* do not export via guestfish *)
119   | NotInDocs             (* do not add this function to documentation *)
120
121 let protocol_limit_warning =
122   "Because of the message protocol, there is a transfer limit 
123 of somewhere between 2MB and 4MB.  To transfer large files you should use
124 FTP."
125
126 let danger_will_robinson =
127   "B<This command is dangerous.  Without careful use you
128 can easily destroy all your data>."
129
130 (* You can supply zero or as many tests as you want per API call.
131  *
132  * Note that the test environment has 3 block devices, of size 500MB,
133  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
134  * a fourth squashfs block device with some known files on it (/dev/sdd).
135  *
136  * Note for partitioning purposes, the 500MB device has 63 cylinders.
137  *
138  * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
139  *
140  * To be able to run the tests in a reasonable amount of time,
141  * the virtual machine and block devices are reused between tests.
142  * So don't try testing kill_subprocess :-x
143  *
144  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
145  *
146  * Don't assume anything about the previous contents of the block
147  * devices.  Use 'Init*' to create some initial scenarios.
148  *
149  * You can add a prerequisite clause to any individual test.  This
150  * is a run-time check, which, if it fails, causes the test to be
151  * skipped.  Useful if testing a command which might not work on
152  * all variations of libguestfs builds.  A test that has prerequisite
153  * of 'Always' is run unconditionally.
154  *
155  * In addition, packagers can skip individual tests by setting the
156  * environment variables:     eg:
157  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
158  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
159  *)
160 type tests = (test_init * test_prereq * test) list
161 and test =
162     (* Run the command sequence and just expect nothing to fail. *)
163   | TestRun of seq
164     (* Run the command sequence and expect the output of the final
165      * command to be the string.
166      *)
167   | TestOutput of seq * string
168     (* Run the command sequence and expect the output of the final
169      * command to be the list of strings.
170      *)
171   | TestOutputList of seq * string list
172     (* Run the command sequence and expect the output of the final
173      * command to be the list of block devices (could be either
174      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
175      * character of each string).
176      *)
177   | TestOutputListOfDevices of seq * string list
178     (* Run the command sequence and expect the output of the final
179      * command to be the integer.
180      *)
181   | TestOutputInt of seq * int
182     (* Run the command sequence and expect the output of the final
183      * command to be a true value (!= 0 or != NULL).
184      *)
185   | TestOutputTrue of seq
186     (* Run the command sequence and expect the output of the final
187      * command to be a false value (== 0 or == NULL, but not an error).
188      *)
189   | TestOutputFalse of seq
190     (* Run the command sequence and expect the output of the final
191      * command to be a list of the given length (but don't care about
192      * content).
193      *)
194   | TestOutputLength of seq * int
195     (* Run the command sequence and expect the output of the final
196      * command to be a structure.
197      *)
198   | TestOutputStruct of seq * test_field_compare list
199     (* Run the command sequence and expect the final command (only)
200      * to fail.
201      *)
202   | TestLastFail of seq
203
204 and test_field_compare =
205   | CompareWithInt of string * int
206   | CompareWithString of string * string
207   | CompareFieldsIntEq of string * string
208   | CompareFieldsStrEq of string * string
209
210 (* Test prerequisites. *)
211 and test_prereq =
212     (* Test always runs. *)
213   | Always
214     (* Test is currently disabled - eg. it fails, or it tests some
215      * unimplemented feature.
216      *)
217   | Disabled
218     (* 'string' is some C code (a function body) that should return
219      * true or false.  The test will run if the code returns true.
220      *)
221   | If of string
222     (* As for 'If' but the test runs _unless_ the code returns true. *)
223   | Unless of string
224
225 (* Some initial scenarios for testing. *)
226 and test_init =
227     (* Do nothing, block devices could contain random stuff including
228      * LVM PVs, and some filesystems might be mounted.  This is usually
229      * a bad idea.
230      *)
231   | InitNone
232     (* Block devices are empty and no filesystems are mounted. *)
233   | InitEmpty
234     (* /dev/sda contains a single partition /dev/sda1, which is formatted
235      * as ext2, empty [except for lost+found] and mounted on /.
236      * /dev/sdb and /dev/sdc may have random content.
237      * No LVM.
238      *)
239   | InitBasicFS
240     (* /dev/sda:
241      *   /dev/sda1 (is a PV):
242      *     /dev/VG/LV (size 8MB):
243      *       formatted as ext2, empty [except for lost+found], mounted on /
244      * /dev/sdb and /dev/sdc may have random content.
245      *)
246   | InitBasicFSonLVM
247
248 (* Sequence of commands for testing. *)
249 and seq = cmd list
250 and cmd = string list
251
252 (* Note about long descriptions: When referring to another
253  * action, use the format C<guestfs_other> (ie. the full name of
254  * the C function).  This will be replaced as appropriate in other
255  * language bindings.
256  *
257  * Apart from that, long descriptions are just perldoc paragraphs.
258  *)
259
260 (* These test functions are used in the language binding tests. *)
261
262 let test_all_args = [
263   String "str";
264   OptString "optstr";
265   StringList "strlist";
266   Bool "b";
267   Int "integer";
268   FileIn "filein";
269   FileOut "fileout";
270 ]
271
272 let test_all_rets = [
273   (* except for RErr, which is tested thoroughly elsewhere *)
274   "test0rint",         RInt "valout";
275   "test0rint64",       RInt64 "valout";
276   "test0rbool",        RBool "valout";
277   "test0rconststring", RConstString "valout";
278   "test0rstring",      RString "valout";
279   "test0rstringlist",  RStringList "valout";
280   "test0rintbool",     RIntBool ("valout", "valout");
281   "test0rpvlist",      RPVList "valout";
282   "test0rvglist",      RVGList "valout";
283   "test0rlvlist",      RLVList "valout";
284   "test0rstat",        RStat "valout";
285   "test0rstatvfs",     RStatVFS "valout";
286   "test0rhashtable",   RHashtable "valout";
287 ]
288
289 let test_functions = [
290   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
291    [],
292    "internal test function - do not use",
293    "\
294 This is an internal test function which is used to test whether
295 the automatically generated bindings can handle every possible
296 parameter type correctly.
297
298 It echos the contents of each parameter to stdout.
299
300 You probably don't want to call this function.");
301 ] @ List.flatten (
302   List.map (
303     fun (name, ret) ->
304       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
305         [],
306         "internal test function - do not use",
307         "\
308 This is an internal test function which is used to test whether
309 the automatically generated bindings can handle every possible
310 return type correctly.
311
312 It converts string C<val> to the return type.
313
314 You probably don't want to call this function.");
315        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
316         [],
317         "internal test function - do not use",
318         "\
319 This is an internal test function which is used to test whether
320 the automatically generated bindings can handle every possible
321 return type correctly.
322
323 This function always returns an error.
324
325 You probably don't want to call this function.")]
326   ) test_all_rets
327 )
328
329 (* non_daemon_functions are any functions which don't get processed
330  * in the daemon, eg. functions for setting and getting local
331  * configuration values.
332  *)
333
334 let non_daemon_functions = test_functions @ [
335   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
336    [],
337    "launch the qemu subprocess",
338    "\
339 Internally libguestfs is implemented by running a virtual machine
340 using L<qemu(1)>.
341
342 You should call this after configuring the handle
343 (eg. adding drives) but before performing any actions.");
344
345   ("wait_ready", (RErr, []), -1, [NotInFish],
346    [],
347    "wait until the qemu subprocess launches",
348    "\
349 Internally libguestfs is implemented by running a virtual machine
350 using L<qemu(1)>.
351
352 You should call this after C<guestfs_launch> to wait for the launch
353 to complete.");
354
355   ("kill_subprocess", (RErr, []), -1, [],
356    [],
357    "kill the qemu subprocess",
358    "\
359 This kills the qemu subprocess.  You should never need to call this.");
360
361   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
362    [],
363    "add an image to examine or modify",
364    "\
365 This function adds a virtual machine disk image C<filename> to the
366 guest.  The first time you call this function, the disk appears as IDE
367 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
368 so on.
369
370 You don't necessarily need to be root when using libguestfs.  However
371 you obviously do need sufficient permissions to access the filename
372 for whatever operations you want to perform (ie. read access if you
373 just want to read the image or write access if you want to modify the
374 image).
375
376 This is equivalent to the qemu parameter C<-drive file=filename,cache=off>.
377
378 Note that this call checks for the existence of C<filename>.  This
379 stops you from specifying other types of drive which are supported
380 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
381 the general C<guestfs_config> call instead.");
382
383   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
384    [],
385    "add a CD-ROM disk image to examine",
386    "\
387 This function adds a virtual CD-ROM disk image to the guest.
388
389 This is equivalent to the qemu parameter C<-cdrom filename>.
390
391 Note that this call checks for the existence of C<filename>.  This
392 stops you from specifying other types of drive which are supported
393 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
394 the general C<guestfs_config> call instead.");
395
396   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
397    [],
398    "add a drive in snapshot mode (read-only)",
399    "\
400 This adds a drive in snapshot mode, making it effectively
401 read-only.
402
403 Note that writes to the device are allowed, and will be seen for
404 the duration of the guestfs handle, but they are written
405 to a temporary file which is discarded as soon as the guestfs
406 handle is closed.  We don't currently have any method to enable
407 changes to be committed, although qemu can support this.
408
409 This is equivalent to the qemu parameter
410 C<-drive file=filename,snapshot=on>.
411
412 Note that this call checks for the existence of C<filename>.  This
413 stops you from specifying other types of drive which are supported
414 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
415 the general C<guestfs_config> call instead.");
416
417   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
418    [],
419    "add qemu parameters",
420    "\
421 This can be used to add arbitrary qemu command line parameters
422 of the form C<-param value>.  Actually it's not quite arbitrary - we
423 prevent you from setting some parameters which would interfere with
424 parameters that we use.
425
426 The first character of C<param> string must be a C<-> (dash).
427
428 C<value> can be NULL.");
429
430   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
431    [],
432    "set the qemu binary",
433    "\
434 Set the qemu binary that we will use.
435
436 The default is chosen when the library was compiled by the
437 configure script.
438
439 You can also override this by setting the C<LIBGUESTFS_QEMU>
440 environment variable.
441
442 Setting C<qemu> to C<NULL> restores the default qemu binary.");
443
444   ("get_qemu", (RConstString "qemu", []), -1, [],
445    [],
446    "get the qemu binary",
447    "\
448 Return the current qemu binary.
449
450 This is always non-NULL.  If it wasn't set already, then this will
451 return the default qemu binary name.");
452
453   ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
454    [],
455    "set the search path",
456    "\
457 Set the path that libguestfs searches for kernel and initrd.img.
458
459 The default is C<$libdir/guestfs> unless overridden by setting
460 C<LIBGUESTFS_PATH> environment variable.
461
462 Setting C<path> to C<NULL> restores the default path.");
463
464   ("get_path", (RConstString "path", []), -1, [],
465    [],
466    "get the search path",
467    "\
468 Return the current search path.
469
470 This is always non-NULL.  If it wasn't set already, then this will
471 return the default path.");
472
473   ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
474    [],
475    "add options to kernel command line",
476    "\
477 This function is used to add additional options to the
478 guest kernel command line.
479
480 The default is C<NULL> unless overridden by setting
481 C<LIBGUESTFS_APPEND> environment variable.
482
483 Setting C<append> to C<NULL> means I<no> additional options
484 are passed (libguestfs always adds a few of its own).");
485
486   ("get_append", (RConstString "append", []), -1, [],
487    [],
488    "get the additional kernel options",
489    "\
490 Return the additional kernel options which are added to the
491 guest kernel command line.
492
493 If C<NULL> then no options are added.");
494
495   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
496    [],
497    "set autosync mode",
498    "\
499 If C<autosync> is true, this enables autosync.  Libguestfs will make a
500 best effort attempt to run C<guestfs_umount_all> followed by
501 C<guestfs_sync> when the handle is closed
502 (also if the program exits without closing handles).
503
504 This is disabled by default (except in guestfish where it is
505 enabled by default).");
506
507   ("get_autosync", (RBool "autosync", []), -1, [],
508    [],
509    "get autosync mode",
510    "\
511 Get the autosync flag.");
512
513   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
514    [],
515    "set verbose mode",
516    "\
517 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
518
519 Verbose messages are disabled unless the environment variable
520 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
521
522   ("get_verbose", (RBool "verbose", []), -1, [],
523    [],
524    "get verbose mode",
525    "\
526 This returns the verbose messages flag.");
527
528   ("is_ready", (RBool "ready", []), -1, [],
529    [],
530    "is ready to accept commands",
531    "\
532 This returns true iff this handle is ready to accept commands
533 (in the C<READY> state).
534
535 For more information on states, see L<guestfs(3)>.");
536
537   ("is_config", (RBool "config", []), -1, [],
538    [],
539    "is in configuration state",
540    "\
541 This returns true iff this handle is being configured
542 (in the C<CONFIG> state).
543
544 For more information on states, see L<guestfs(3)>.");
545
546   ("is_launching", (RBool "launching", []), -1, [],
547    [],
548    "is launching subprocess",
549    "\
550 This returns true iff this handle is launching the subprocess
551 (in the C<LAUNCHING> state).
552
553 For more information on states, see L<guestfs(3)>.");
554
555   ("is_busy", (RBool "busy", []), -1, [],
556    [],
557    "is busy processing a command",
558    "\
559 This returns true iff this handle is busy processing a command
560 (in the C<BUSY> state).
561
562 For more information on states, see L<guestfs(3)>.");
563
564   ("get_state", (RInt "state", []), -1, [],
565    [],
566    "get the current state",
567    "\
568 This returns the current state as an opaque integer.  This is
569 only useful for printing debug and internal error messages.
570
571 For more information on states, see L<guestfs(3)>.");
572
573   ("set_busy", (RErr, []), -1, [NotInFish],
574    [],
575    "set state to busy",
576    "\
577 This sets the state to C<BUSY>.  This is only used when implementing
578 actions using the low-level API.
579
580 For more information on states, see L<guestfs(3)>.");
581
582   ("set_ready", (RErr, []), -1, [NotInFish],
583    [],
584    "set state to ready",
585    "\
586 This sets the state to C<READY>.  This is only used when implementing
587 actions using the low-level API.
588
589 For more information on states, see L<guestfs(3)>.");
590
591   ("end_busy", (RErr, []), -1, [NotInFish],
592    [],
593    "leave the busy state",
594    "\
595 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
596 state as is.  This is only used when implementing
597 actions using the low-level API.
598
599 For more information on states, see L<guestfs(3)>.");
600
601   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
602    [],
603    "set memory allocated to the qemu subprocess",
604    "\
605 This sets the memory size in megabytes allocated to the
606 qemu subprocess.  This only has any effect if called before
607 C<guestfs_launch>.
608
609 You can also change this by setting the environment
610 variable C<LIBGUESTFS_MEMSIZE> before the handle is
611 created.
612
613 For more information on the architecture of libguestfs,
614 see L<guestfs(3)>.");
615
616   ("get_memsize", (RInt "memsize", []), -1, [],
617    [],
618    "get memory allocated to the qemu subprocess",
619    "\
620 This gets the memory size in megabytes allocated to the
621 qemu subprocess.
622
623 If C<guestfs_set_memsize> was not called
624 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
625 then this returns the compiled-in default value for memsize.
626
627 For more information on the architecture of libguestfs,
628 see L<guestfs(3)>.");
629
630 ]
631
632 (* daemon_functions are any functions which cause some action
633  * to take place in the daemon.
634  *)
635
636 let daemon_functions = [
637   ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
638    [InitEmpty, Always, TestOutput (
639       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
640        ["mkfs"; "ext2"; "/dev/sda1"];
641        ["mount"; "/dev/sda1"; "/"];
642        ["write_file"; "/new"; "new file contents"; "0"];
643        ["cat"; "/new"]], "new file contents")],
644    "mount a guest disk at a position in the filesystem",
645    "\
646 Mount a guest disk at a position in the filesystem.  Block devices
647 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
648 the guest.  If those block devices contain partitions, they will have
649 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
650 names can be used.
651
652 The rules are the same as for L<mount(2)>:  A filesystem must
653 first be mounted on C</> before others can be mounted.  Other
654 filesystems can only be mounted on directories which already
655 exist.
656
657 The mounted filesystem is writable, if we have sufficient permissions
658 on the underlying device.
659
660 The filesystem options C<sync> and C<noatime> are set with this
661 call, in order to improve reliability.");
662
663   ("sync", (RErr, []), 2, [],
664    [ InitEmpty, Always, TestRun [["sync"]]],
665    "sync disks, writes are flushed through to the disk image",
666    "\
667 This syncs the disk, so that any writes are flushed through to the
668 underlying disk image.
669
670 You should always call this if you have modified a disk image, before
671 closing the handle.");
672
673   ("touch", (RErr, [String "path"]), 3, [],
674    [InitBasicFS, Always, TestOutputTrue (
675       [["touch"; "/new"];
676        ["exists"; "/new"]])],
677    "update file timestamps or create a new file",
678    "\
679 Touch acts like the L<touch(1)> command.  It can be used to
680 update the timestamps on a file, or, if the file does not exist,
681 to create a new zero-length file.");
682
683   ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
684    [InitBasicFS, Always, TestOutput (
685       [["write_file"; "/new"; "new file contents"; "0"];
686        ["cat"; "/new"]], "new file contents")],
687    "list the contents of a file",
688    "\
689 Return the contents of the file named C<path>.
690
691 Note that this function cannot correctly handle binary files
692 (specifically, files containing C<\\0> character which is treated
693 as end of string).  For those you need to use the C<guestfs_download>
694 function which has a more complex interface.");
695
696   ("ll", (RString "listing", [String "directory"]), 5, [],
697    [], (* XXX Tricky to test because it depends on the exact format
698         * of the 'ls -l' command, which changes between F10 and F11.
699         *)
700    "list the files in a directory (long format)",
701    "\
702 List the files in C<directory> (relative to the root directory,
703 there is no cwd) in the format of 'ls -la'.
704
705 This command is mostly useful for interactive sessions.  It
706 is I<not> intended that you try to parse the output string.");
707
708   ("ls", (RStringList "listing", [String "directory"]), 6, [],
709    [InitBasicFS, Always, TestOutputList (
710       [["touch"; "/new"];
711        ["touch"; "/newer"];
712        ["touch"; "/newest"];
713        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
714    "list the files in a directory",
715    "\
716 List the files in C<directory> (relative to the root directory,
717 there is no cwd).  The '.' and '..' entries are not returned, but
718 hidden files are shown.
719
720 This command is mostly useful for interactive sessions.  Programs
721 should probably use C<guestfs_readdir> instead.");
722
723   ("list_devices", (RStringList "devices", []), 7, [],
724    [InitEmpty, Always, TestOutputListOfDevices (
725       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
726    "list the block devices",
727    "\
728 List all the block devices.
729
730 The full block device names are returned, eg. C</dev/sda>");
731
732   ("list_partitions", (RStringList "partitions", []), 8, [],
733    [InitBasicFS, Always, TestOutputListOfDevices (
734       [["list_partitions"]], ["/dev/sda1"]);
735     InitEmpty, Always, TestOutputListOfDevices (
736       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
737        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
738    "list the partitions",
739    "\
740 List all the partitions detected on all block devices.
741
742 The full partition device names are returned, eg. C</dev/sda1>
743
744 This does not return logical volumes.  For that you will need to
745 call C<guestfs_lvs>.");
746
747   ("pvs", (RStringList "physvols", []), 9, [],
748    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
749       [["pvs"]], ["/dev/sda1"]);
750     InitEmpty, Always, TestOutputListOfDevices (
751       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
752        ["pvcreate"; "/dev/sda1"];
753        ["pvcreate"; "/dev/sda2"];
754        ["pvcreate"; "/dev/sda3"];
755        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
756    "list the LVM physical volumes (PVs)",
757    "\
758 List all the physical volumes detected.  This is the equivalent
759 of the L<pvs(8)> command.
760
761 This returns a list of just the device names that contain
762 PVs (eg. C</dev/sda2>).
763
764 See also C<guestfs_pvs_full>.");
765
766   ("vgs", (RStringList "volgroups", []), 10, [],
767    [InitBasicFSonLVM, Always, TestOutputList (
768       [["vgs"]], ["VG"]);
769     InitEmpty, Always, TestOutputList (
770       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
771        ["pvcreate"; "/dev/sda1"];
772        ["pvcreate"; "/dev/sda2"];
773        ["pvcreate"; "/dev/sda3"];
774        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
775        ["vgcreate"; "VG2"; "/dev/sda3"];
776        ["vgs"]], ["VG1"; "VG2"])],
777    "list the LVM volume groups (VGs)",
778    "\
779 List all the volumes groups detected.  This is the equivalent
780 of the L<vgs(8)> command.
781
782 This returns a list of just the volume group names that were
783 detected (eg. C<VolGroup00>).
784
785 See also C<guestfs_vgs_full>.");
786
787   ("lvs", (RStringList "logvols", []), 11, [],
788    [InitBasicFSonLVM, Always, TestOutputList (
789       [["lvs"]], ["/dev/VG/LV"]);
790     InitEmpty, Always, TestOutputList (
791       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
792        ["pvcreate"; "/dev/sda1"];
793        ["pvcreate"; "/dev/sda2"];
794        ["pvcreate"; "/dev/sda3"];
795        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
796        ["vgcreate"; "VG2"; "/dev/sda3"];
797        ["lvcreate"; "LV1"; "VG1"; "50"];
798        ["lvcreate"; "LV2"; "VG1"; "50"];
799        ["lvcreate"; "LV3"; "VG2"; "50"];
800        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
801    "list the LVM logical volumes (LVs)",
802    "\
803 List all the logical volumes detected.  This is the equivalent
804 of the L<lvs(8)> command.
805
806 This returns a list of the logical volume device names
807 (eg. C</dev/VolGroup00/LogVol00>).
808
809 See also C<guestfs_lvs_full>.");
810
811   ("pvs_full", (RPVList "physvols", []), 12, [],
812    [], (* XXX how to test? *)
813    "list the LVM physical volumes (PVs)",
814    "\
815 List all the physical volumes detected.  This is the equivalent
816 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
817
818   ("vgs_full", (RVGList "volgroups", []), 13, [],
819    [], (* XXX how to test? *)
820    "list the LVM volume groups (VGs)",
821    "\
822 List all the volumes groups detected.  This is the equivalent
823 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
824
825   ("lvs_full", (RLVList "logvols", []), 14, [],
826    [], (* XXX how to test? *)
827    "list the LVM logical volumes (LVs)",
828    "\
829 List all the logical volumes detected.  This is the equivalent
830 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
831
832   ("read_lines", (RStringList "lines", [String "path"]), 15, [],
833    [InitBasicFS, Always, TestOutputList (
834       [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
835        ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
836     InitBasicFS, Always, TestOutputList (
837       [["write_file"; "/new"; ""; "0"];
838        ["read_lines"; "/new"]], [])],
839    "read file as lines",
840    "\
841 Return the contents of the file named C<path>.
842
843 The file contents are returned as a list of lines.  Trailing
844 C<LF> and C<CRLF> character sequences are I<not> returned.
845
846 Note that this function cannot correctly handle binary files
847 (specifically, files containing C<\\0> character which is treated
848 as end of line).  For those you need to use the C<guestfs_read_file>
849 function which has a more complex interface.");
850
851   ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
852    [], (* XXX Augeas code needs tests. *)
853    "create a new Augeas handle",
854    "\
855 Create a new Augeas handle for editing configuration files.
856 If there was any previous Augeas handle associated with this
857 guestfs session, then it is closed.
858
859 You must call this before using any other C<guestfs_aug_*>
860 commands.
861
862 C<root> is the filesystem root.  C<root> must not be NULL,
863 use C</> instead.
864
865 The flags are the same as the flags defined in
866 E<lt>augeas.hE<gt>, the logical I<or> of the following
867 integers:
868
869 =over 4
870
871 =item C<AUG_SAVE_BACKUP> = 1
872
873 Keep the original file with a C<.augsave> extension.
874
875 =item C<AUG_SAVE_NEWFILE> = 2
876
877 Save changes into a file with extension C<.augnew>, and
878 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
879
880 =item C<AUG_TYPE_CHECK> = 4
881
882 Typecheck lenses (can be expensive).
883
884 =item C<AUG_NO_STDINC> = 8
885
886 Do not use standard load path for modules.
887
888 =item C<AUG_SAVE_NOOP> = 16
889
890 Make save a no-op, just record what would have been changed.
891
892 =item C<AUG_NO_LOAD> = 32
893
894 Do not load the tree in C<guestfs_aug_init>.
895
896 =back
897
898 To close the handle, you can call C<guestfs_aug_close>.
899
900 To find out more about Augeas, see L<http://augeas.net/>.");
901
902   ("aug_close", (RErr, []), 26, [],
903    [], (* XXX Augeas code needs tests. *)
904    "close the current Augeas handle",
905    "\
906 Close the current Augeas handle and free up any resources
907 used by it.  After calling this, you have to call
908 C<guestfs_aug_init> again before you can use any other
909 Augeas functions.");
910
911   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
912    [], (* XXX Augeas code needs tests. *)
913    "define an Augeas variable",
914    "\
915 Defines an Augeas variable C<name> whose value is the result
916 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
917 undefined.
918
919 On success this returns the number of nodes in C<expr>, or
920 C<0> if C<expr> evaluates to something which is not a nodeset.");
921
922   ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
923    [], (* XXX Augeas code needs tests. *)
924    "define an Augeas node",
925    "\
926 Defines a variable C<name> whose value is the result of
927 evaluating C<expr>.
928
929 If C<expr> evaluates to an empty nodeset, a node is created,
930 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
931 C<name> will be the nodeset containing that single node.
932
933 On success this returns a pair containing the
934 number of nodes in the nodeset, and a boolean flag
935 if a node was created.");
936
937   ("aug_get", (RString "val", [String "path"]), 19, [],
938    [], (* XXX Augeas code needs tests. *)
939    "look up the value of an Augeas path",
940    "\
941 Look up the value associated with C<path>.  If C<path>
942 matches exactly one node, the C<value> is returned.");
943
944   ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
945    [], (* XXX Augeas code needs tests. *)
946    "set Augeas path to value",
947    "\
948 Set the value associated with C<path> to C<value>.");
949
950   ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
951    [], (* XXX Augeas code needs tests. *)
952    "insert a sibling Augeas node",
953    "\
954 Create a new sibling C<label> for C<path>, inserting it into
955 the tree before or after C<path> (depending on the boolean
956 flag C<before>).
957
958 C<path> must match exactly one existing node in the tree, and
959 C<label> must be a label, ie. not contain C</>, C<*> or end
960 with a bracketed index C<[N]>.");
961
962   ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
963    [], (* XXX Augeas code needs tests. *)
964    "remove an Augeas path",
965    "\
966 Remove C<path> and all of its children.
967
968 On success this returns the number of entries which were removed.");
969
970   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
971    [], (* XXX Augeas code needs tests. *)
972    "move Augeas node",
973    "\
974 Move the node C<src> to C<dest>.  C<src> must match exactly
975 one node.  C<dest> is overwritten if it exists.");
976
977   ("aug_match", (RStringList "matches", [String "path"]), 24, [],
978    [], (* XXX Augeas code needs tests. *)
979    "return Augeas nodes which match path",
980    "\
981 Returns a list of paths which match the path expression C<path>.
982 The returned paths are sufficiently qualified so that they match
983 exactly one node in the current tree.");
984
985   ("aug_save", (RErr, []), 25, [],
986    [], (* XXX Augeas code needs tests. *)
987    "write all pending Augeas changes to disk",
988    "\
989 This writes all pending changes to disk.
990
991 The flags which were passed to C<guestfs_aug_init> affect exactly
992 how files are saved.");
993
994   ("aug_load", (RErr, []), 27, [],
995    [], (* XXX Augeas code needs tests. *)
996    "load files into the tree",
997    "\
998 Load files into the tree.
999
1000 See C<aug_load> in the Augeas documentation for the full gory
1001 details.");
1002
1003   ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
1004    [], (* XXX Augeas code needs tests. *)
1005    "list Augeas nodes under a path",
1006    "\
1007 This is just a shortcut for listing C<guestfs_aug_match>
1008 C<path/*> and sorting the resulting nodes into alphabetical order.");
1009
1010   ("rm", (RErr, [String "path"]), 29, [],
1011    [InitBasicFS, Always, TestRun
1012       [["touch"; "/new"];
1013        ["rm"; "/new"]];
1014     InitBasicFS, Always, TestLastFail
1015       [["rm"; "/new"]];
1016     InitBasicFS, Always, TestLastFail
1017       [["mkdir"; "/new"];
1018        ["rm"; "/new"]]],
1019    "remove a file",
1020    "\
1021 Remove the single file C<path>.");
1022
1023   ("rmdir", (RErr, [String "path"]), 30, [],
1024    [InitBasicFS, Always, TestRun
1025       [["mkdir"; "/new"];
1026        ["rmdir"; "/new"]];
1027     InitBasicFS, Always, TestLastFail
1028       [["rmdir"; "/new"]];
1029     InitBasicFS, Always, TestLastFail
1030       [["touch"; "/new"];
1031        ["rmdir"; "/new"]]],
1032    "remove a directory",
1033    "\
1034 Remove the single directory C<path>.");
1035
1036   ("rm_rf", (RErr, [String "path"]), 31, [],
1037    [InitBasicFS, Always, TestOutputFalse
1038       [["mkdir"; "/new"];
1039        ["mkdir"; "/new/foo"];
1040        ["touch"; "/new/foo/bar"];
1041        ["rm_rf"; "/new"];
1042        ["exists"; "/new"]]],
1043    "remove a file or directory recursively",
1044    "\
1045 Remove the file or directory C<path>, recursively removing the
1046 contents if its a directory.  This is like the C<rm -rf> shell
1047 command.");
1048
1049   ("mkdir", (RErr, [String "path"]), 32, [],
1050    [InitBasicFS, Always, TestOutputTrue
1051       [["mkdir"; "/new"];
1052        ["is_dir"; "/new"]];
1053     InitBasicFS, Always, TestLastFail
1054       [["mkdir"; "/new/foo/bar"]]],
1055    "create a directory",
1056    "\
1057 Create a directory named C<path>.");
1058
1059   ("mkdir_p", (RErr, [String "path"]), 33, [],
1060    [InitBasicFS, Always, TestOutputTrue
1061       [["mkdir_p"; "/new/foo/bar"];
1062        ["is_dir"; "/new/foo/bar"]];
1063     InitBasicFS, Always, TestOutputTrue
1064       [["mkdir_p"; "/new/foo/bar"];
1065        ["is_dir"; "/new/foo"]];
1066     InitBasicFS, Always, TestOutputTrue
1067       [["mkdir_p"; "/new/foo/bar"];
1068        ["is_dir"; "/new"]];
1069     (* Regression tests for RHBZ#503133: *)
1070     InitBasicFS, Always, TestRun
1071       [["mkdir"; "/new"];
1072        ["mkdir_p"; "/new"]];
1073     InitBasicFS, Always, TestLastFail
1074       [["touch"; "/new"];
1075        ["mkdir_p"; "/new"]]],
1076    "create a directory and parents",
1077    "\
1078 Create a directory named C<path>, creating any parent directories
1079 as necessary.  This is like the C<mkdir -p> shell command.");
1080
1081   ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1082    [], (* XXX Need stat command to test *)
1083    "change file mode",
1084    "\
1085 Change the mode (permissions) of C<path> to C<mode>.  Only
1086 numeric modes are supported.");
1087
1088   ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1089    [], (* XXX Need stat command to test *)
1090    "change file owner and group",
1091    "\
1092 Change the file owner to C<owner> and group to C<group>.
1093
1094 Only numeric uid and gid are supported.  If you want to use
1095 names, you will need to locate and parse the password file
1096 yourself (Augeas support makes this relatively easy).");
1097
1098   ("exists", (RBool "existsflag", [String "path"]), 36, [],
1099    [InitBasicFS, Always, TestOutputTrue (
1100       [["touch"; "/new"];
1101        ["exists"; "/new"]]);
1102     InitBasicFS, Always, TestOutputTrue (
1103       [["mkdir"; "/new"];
1104        ["exists"; "/new"]])],
1105    "test if file or directory exists",
1106    "\
1107 This returns C<true> if and only if there is a file, directory
1108 (or anything) with the given C<path> name.
1109
1110 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1111
1112   ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1113    [InitBasicFS, Always, TestOutputTrue (
1114       [["touch"; "/new"];
1115        ["is_file"; "/new"]]);
1116     InitBasicFS, Always, TestOutputFalse (
1117       [["mkdir"; "/new"];
1118        ["is_file"; "/new"]])],
1119    "test if file exists",
1120    "\
1121 This returns C<true> if and only if there is a file
1122 with the given C<path> name.  Note that it returns false for
1123 other objects like directories.
1124
1125 See also C<guestfs_stat>.");
1126
1127   ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1128    [InitBasicFS, Always, TestOutputFalse (
1129       [["touch"; "/new"];
1130        ["is_dir"; "/new"]]);
1131     InitBasicFS, Always, TestOutputTrue (
1132       [["mkdir"; "/new"];
1133        ["is_dir"; "/new"]])],
1134    "test if file exists",
1135    "\
1136 This returns C<true> if and only if there is a directory
1137 with the given C<path> name.  Note that it returns false for
1138 other objects like files.
1139
1140 See also C<guestfs_stat>.");
1141
1142   ("pvcreate", (RErr, [String "device"]), 39, [],
1143    [InitEmpty, Always, TestOutputListOfDevices (
1144       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1145        ["pvcreate"; "/dev/sda1"];
1146        ["pvcreate"; "/dev/sda2"];
1147        ["pvcreate"; "/dev/sda3"];
1148        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1149    "create an LVM physical volume",
1150    "\
1151 This creates an LVM physical volume on the named C<device>,
1152 where C<device> should usually be a partition name such
1153 as C</dev/sda1>.");
1154
1155   ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1156    [InitEmpty, Always, TestOutputList (
1157       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1158        ["pvcreate"; "/dev/sda1"];
1159        ["pvcreate"; "/dev/sda2"];
1160        ["pvcreate"; "/dev/sda3"];
1161        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1162        ["vgcreate"; "VG2"; "/dev/sda3"];
1163        ["vgs"]], ["VG1"; "VG2"])],
1164    "create an LVM volume group",
1165    "\
1166 This creates an LVM volume group called C<volgroup>
1167 from the non-empty list of physical volumes C<physvols>.");
1168
1169   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1170    [InitEmpty, Always, TestOutputList (
1171       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1172        ["pvcreate"; "/dev/sda1"];
1173        ["pvcreate"; "/dev/sda2"];
1174        ["pvcreate"; "/dev/sda3"];
1175        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1176        ["vgcreate"; "VG2"; "/dev/sda3"];
1177        ["lvcreate"; "LV1"; "VG1"; "50"];
1178        ["lvcreate"; "LV2"; "VG1"; "50"];
1179        ["lvcreate"; "LV3"; "VG2"; "50"];
1180        ["lvcreate"; "LV4"; "VG2"; "50"];
1181        ["lvcreate"; "LV5"; "VG2"; "50"];
1182        ["lvs"]],
1183       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1184        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1185    "create an LVM volume group",
1186    "\
1187 This creates an LVM volume group called C<logvol>
1188 on the volume group C<volgroup>, with C<size> megabytes.");
1189
1190   ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1191    [InitEmpty, Always, TestOutput (
1192       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1193        ["mkfs"; "ext2"; "/dev/sda1"];
1194        ["mount"; "/dev/sda1"; "/"];
1195        ["write_file"; "/new"; "new file contents"; "0"];
1196        ["cat"; "/new"]], "new file contents")],
1197    "make a filesystem",
1198    "\
1199 This creates a filesystem on C<device> (usually a partition
1200 or LVM logical volume).  The filesystem type is C<fstype>, for
1201 example C<ext3>.");
1202
1203   ("sfdisk", (RErr, [String "device";
1204                      Int "cyls"; Int "heads"; Int "sectors";
1205                      StringList "lines"]), 43, [DangerWillRobinson],
1206    [],
1207    "create partitions on a block device",
1208    "\
1209 This is a direct interface to the L<sfdisk(8)> program for creating
1210 partitions on block devices.
1211
1212 C<device> should be a block device, for example C</dev/sda>.
1213
1214 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1215 and sectors on the device, which are passed directly to sfdisk as
1216 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1217 of these, then the corresponding parameter is omitted.  Usually for
1218 'large' disks, you can just pass C<0> for these, but for small
1219 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1220 out the right geometry and you will need to tell it.
1221
1222 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1223 information refer to the L<sfdisk(8)> manpage.
1224
1225 To create a single partition occupying the whole disk, you would
1226 pass C<lines> as a single element list, when the single element being
1227 the string C<,> (comma).
1228
1229 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1230
1231   ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1232    [InitBasicFS, Always, TestOutput (
1233       [["write_file"; "/new"; "new file contents"; "0"];
1234        ["cat"; "/new"]], "new file contents");
1235     InitBasicFS, Always, TestOutput (
1236       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1237        ["cat"; "/new"]], "\nnew file contents\n");
1238     InitBasicFS, Always, TestOutput (
1239       [["write_file"; "/new"; "\n\n"; "0"];
1240        ["cat"; "/new"]], "\n\n");
1241     InitBasicFS, Always, TestOutput (
1242       [["write_file"; "/new"; ""; "0"];
1243        ["cat"; "/new"]], "");
1244     InitBasicFS, Always, TestOutput (
1245       [["write_file"; "/new"; "\n\n\n"; "0"];
1246        ["cat"; "/new"]], "\n\n\n");
1247     InitBasicFS, Always, TestOutput (
1248       [["write_file"; "/new"; "\n"; "0"];
1249        ["cat"; "/new"]], "\n")],
1250    "create a file",
1251    "\
1252 This call creates a file called C<path>.  The contents of the
1253 file is the string C<content> (which can contain any 8 bit data),
1254 with length C<size>.
1255
1256 As a special case, if C<size> is C<0>
1257 then the length is calculated using C<strlen> (so in this case
1258 the content cannot contain embedded ASCII NULs).
1259
1260 I<NB.> Owing to a bug, writing content containing ASCII NUL
1261 characters does I<not> work, even if the length is specified.
1262 We hope to resolve this bug in a future version.  In the meantime
1263 use C<guestfs_upload>.");
1264
1265   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1266    [InitEmpty, Always, TestOutputListOfDevices (
1267       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1268        ["mkfs"; "ext2"; "/dev/sda1"];
1269        ["mount"; "/dev/sda1"; "/"];
1270        ["mounts"]], ["/dev/sda1"]);
1271     InitEmpty, Always, TestOutputList (
1272       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1273        ["mkfs"; "ext2"; "/dev/sda1"];
1274        ["mount"; "/dev/sda1"; "/"];
1275        ["umount"; "/"];
1276        ["mounts"]], [])],
1277    "unmount a filesystem",
1278    "\
1279 This unmounts the given filesystem.  The filesystem may be
1280 specified either by its mountpoint (path) or the device which
1281 contains the filesystem.");
1282
1283   ("mounts", (RStringList "devices", []), 46, [],
1284    [InitBasicFS, Always, TestOutputListOfDevices (
1285       [["mounts"]], ["/dev/sda1"])],
1286    "show mounted filesystems",
1287    "\
1288 This returns the list of currently mounted filesystems.  It returns
1289 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1290
1291 Some internal mounts are not shown.");
1292
1293   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1294    [InitBasicFS, Always, TestOutputList (
1295       [["umount_all"];
1296        ["mounts"]], []);
1297     (* check that umount_all can unmount nested mounts correctly: *)
1298     InitEmpty, Always, TestOutputList (
1299       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
1300        ["mkfs"; "ext2"; "/dev/sda1"];
1301        ["mkfs"; "ext2"; "/dev/sda2"];
1302        ["mkfs"; "ext2"; "/dev/sda3"];
1303        ["mount"; "/dev/sda1"; "/"];
1304        ["mkdir"; "/mp1"];
1305        ["mount"; "/dev/sda2"; "/mp1"];
1306        ["mkdir"; "/mp1/mp2"];
1307        ["mount"; "/dev/sda3"; "/mp1/mp2"];
1308        ["mkdir"; "/mp1/mp2/mp3"];
1309        ["umount_all"];
1310        ["mounts"]], [])],
1311    "unmount all filesystems",
1312    "\
1313 This unmounts all mounted filesystems.
1314
1315 Some internal mounts are not unmounted by this call.");
1316
1317   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1318    [],
1319    "remove all LVM LVs, VGs and PVs",
1320    "\
1321 This command removes all LVM logical volumes, volume groups
1322 and physical volumes.");
1323
1324   ("file", (RString "description", [String "path"]), 49, [],
1325    [InitBasicFS, Always, TestOutput (
1326       [["touch"; "/new"];
1327        ["file"; "/new"]], "empty");
1328     InitBasicFS, Always, TestOutput (
1329       [["write_file"; "/new"; "some content\n"; "0"];
1330        ["file"; "/new"]], "ASCII text");
1331     InitBasicFS, Always, TestLastFail (
1332       [["file"; "/nofile"]])],
1333    "determine file type",
1334    "\
1335 This call uses the standard L<file(1)> command to determine
1336 the type or contents of the file.  This also works on devices,
1337 for example to find out whether a partition contains a filesystem.
1338
1339 The exact command which runs is C<file -bsL path>.  Note in
1340 particular that the filename is not prepended to the output
1341 (the C<-b> option).");
1342
1343   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1344    [InitBasicFS, Always, TestOutput (
1345       [["upload"; "test-command"; "/test-command"];
1346        ["chmod"; "0o755"; "/test-command"];
1347        ["command"; "/test-command 1"]], "Result1");
1348     InitBasicFS, Always, TestOutput (
1349       [["upload"; "test-command"; "/test-command"];
1350        ["chmod"; "0o755"; "/test-command"];
1351        ["command"; "/test-command 2"]], "Result2\n");
1352     InitBasicFS, Always, TestOutput (
1353       [["upload"; "test-command"; "/test-command"];
1354        ["chmod"; "0o755"; "/test-command"];
1355        ["command"; "/test-command 3"]], "\nResult3");
1356     InitBasicFS, Always, TestOutput (
1357       [["upload"; "test-command"; "/test-command"];
1358        ["chmod"; "0o755"; "/test-command"];
1359        ["command"; "/test-command 4"]], "\nResult4\n");
1360     InitBasicFS, Always, TestOutput (
1361       [["upload"; "test-command"; "/test-command"];
1362        ["chmod"; "0o755"; "/test-command"];
1363        ["command"; "/test-command 5"]], "\nResult5\n\n");
1364     InitBasicFS, Always, TestOutput (
1365       [["upload"; "test-command"; "/test-command"];
1366        ["chmod"; "0o755"; "/test-command"];
1367        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1368     InitBasicFS, Always, TestOutput (
1369       [["upload"; "test-command"; "/test-command"];
1370        ["chmod"; "0o755"; "/test-command"];
1371        ["command"; "/test-command 7"]], "");
1372     InitBasicFS, Always, TestOutput (
1373       [["upload"; "test-command"; "/test-command"];
1374        ["chmod"; "0o755"; "/test-command"];
1375        ["command"; "/test-command 8"]], "\n");
1376     InitBasicFS, Always, TestOutput (
1377       [["upload"; "test-command"; "/test-command"];
1378        ["chmod"; "0o755"; "/test-command"];
1379        ["command"; "/test-command 9"]], "\n\n");
1380     InitBasicFS, Always, TestOutput (
1381       [["upload"; "test-command"; "/test-command"];
1382        ["chmod"; "0o755"; "/test-command"];
1383        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1384     InitBasicFS, Always, TestOutput (
1385       [["upload"; "test-command"; "/test-command"];
1386        ["chmod"; "0o755"; "/test-command"];
1387        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1388     InitBasicFS, Always, TestLastFail (
1389       [["upload"; "test-command"; "/test-command"];
1390        ["chmod"; "0o755"; "/test-command"];
1391        ["command"; "/test-command"]])],
1392    "run a command from the guest filesystem",
1393    "\
1394 This call runs a command from the guest filesystem.  The
1395 filesystem must be mounted, and must contain a compatible
1396 operating system (ie. something Linux, with the same
1397 or compatible processor architecture).
1398
1399 The single parameter is an argv-style list of arguments.
1400 The first element is the name of the program to run.
1401 Subsequent elements are parameters.  The list must be
1402 non-empty (ie. must contain a program name).  Note that
1403 the command runs directly, and is I<not> invoked via
1404 the shell (see C<guestfs_sh>).
1405
1406 The return value is anything printed to I<stdout> by
1407 the command.
1408
1409 If the command returns a non-zero exit status, then
1410 this function returns an error message.  The error message
1411 string is the content of I<stderr> from the command.
1412
1413 The C<$PATH> environment variable will contain at least
1414 C</usr/bin> and C</bin>.  If you require a program from
1415 another location, you should provide the full path in the
1416 first parameter.
1417
1418 Shared libraries and data files required by the program
1419 must be available on filesystems which are mounted in the
1420 correct places.  It is the caller's responsibility to ensure
1421 all filesystems that are needed are mounted at the right
1422 locations.");
1423
1424   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1425    [InitBasicFS, Always, TestOutputList (
1426       [["upload"; "test-command"; "/test-command"];
1427        ["chmod"; "0o755"; "/test-command"];
1428        ["command_lines"; "/test-command 1"]], ["Result1"]);
1429     InitBasicFS, Always, TestOutputList (
1430       [["upload"; "test-command"; "/test-command"];
1431        ["chmod"; "0o755"; "/test-command"];
1432        ["command_lines"; "/test-command 2"]], ["Result2"]);
1433     InitBasicFS, Always, TestOutputList (
1434       [["upload"; "test-command"; "/test-command"];
1435        ["chmod"; "0o755"; "/test-command"];
1436        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1437     InitBasicFS, Always, TestOutputList (
1438       [["upload"; "test-command"; "/test-command"];
1439        ["chmod"; "0o755"; "/test-command"];
1440        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1441     InitBasicFS, Always, TestOutputList (
1442       [["upload"; "test-command"; "/test-command"];
1443        ["chmod"; "0o755"; "/test-command"];
1444        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1445     InitBasicFS, Always, TestOutputList (
1446       [["upload"; "test-command"; "/test-command"];
1447        ["chmod"; "0o755"; "/test-command"];
1448        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1449     InitBasicFS, Always, TestOutputList (
1450       [["upload"; "test-command"; "/test-command"];
1451        ["chmod"; "0o755"; "/test-command"];
1452        ["command_lines"; "/test-command 7"]], []);
1453     InitBasicFS, Always, TestOutputList (
1454       [["upload"; "test-command"; "/test-command"];
1455        ["chmod"; "0o755"; "/test-command"];
1456        ["command_lines"; "/test-command 8"]], [""]);
1457     InitBasicFS, Always, TestOutputList (
1458       [["upload"; "test-command"; "/test-command"];
1459        ["chmod"; "0o755"; "/test-command"];
1460        ["command_lines"; "/test-command 9"]], ["";""]);
1461     InitBasicFS, Always, TestOutputList (
1462       [["upload"; "test-command"; "/test-command"];
1463        ["chmod"; "0o755"; "/test-command"];
1464        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1465     InitBasicFS, Always, TestOutputList (
1466       [["upload"; "test-command"; "/test-command"];
1467        ["chmod"; "0o755"; "/test-command"];
1468        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1469    "run a command, returning lines",
1470    "\
1471 This is the same as C<guestfs_command>, but splits the
1472 result into a list of lines.
1473
1474 See also: C<guestfs_sh_lines>");
1475
1476   ("stat", (RStat "statbuf", [String "path"]), 52, [],
1477    [InitBasicFS, Always, TestOutputStruct (
1478       [["touch"; "/new"];
1479        ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1480    "get file information",
1481    "\
1482 Returns file information for the given C<path>.
1483
1484 This is the same as the C<stat(2)> system call.");
1485
1486   ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1487    [InitBasicFS, Always, TestOutputStruct (
1488       [["touch"; "/new"];
1489        ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1490    "get file information for a symbolic link",
1491    "\
1492 Returns file information for the given C<path>.
1493
1494 This is the same as C<guestfs_stat> except that if C<path>
1495 is a symbolic link, then the link is stat-ed, not the file it
1496 refers to.
1497
1498 This is the same as the C<lstat(2)> system call.");
1499
1500   ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1501    [InitBasicFS, Always, TestOutputStruct (
1502       [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1503                            CompareWithInt ("blocks", 490020);
1504                            CompareWithInt ("bsize", 1024)])],
1505    "get file system statistics",
1506    "\
1507 Returns file system statistics for any mounted file system.
1508 C<path> should be a file or directory in the mounted file system
1509 (typically it is the mount point itself, but it doesn't need to be).
1510
1511 This is the same as the C<statvfs(2)> system call.");
1512
1513   ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1514    [], (* XXX test *)
1515    "get ext2/ext3/ext4 superblock details",
1516    "\
1517 This returns the contents of the ext2, ext3 or ext4 filesystem
1518 superblock on C<device>.
1519
1520 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1521 manpage for more details.  The list of fields returned isn't
1522 clearly defined, and depends on both the version of C<tune2fs>
1523 that libguestfs was built against, and the filesystem itself.");
1524
1525   ("blockdev_setro", (RErr, [String "device"]), 56, [],
1526    [InitEmpty, Always, TestOutputTrue (
1527       [["blockdev_setro"; "/dev/sda"];
1528        ["blockdev_getro"; "/dev/sda"]])],
1529    "set block device to read-only",
1530    "\
1531 Sets the block device named C<device> to read-only.
1532
1533 This uses the L<blockdev(8)> command.");
1534
1535   ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1536    [InitEmpty, Always, TestOutputFalse (
1537       [["blockdev_setrw"; "/dev/sda"];
1538        ["blockdev_getro"; "/dev/sda"]])],
1539    "set block device to read-write",
1540    "\
1541 Sets the block device named C<device> to read-write.
1542
1543 This uses the L<blockdev(8)> command.");
1544
1545   ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1546    [InitEmpty, Always, TestOutputTrue (
1547       [["blockdev_setro"; "/dev/sda"];
1548        ["blockdev_getro"; "/dev/sda"]])],
1549    "is block device set to read-only",
1550    "\
1551 Returns a boolean indicating if the block device is read-only
1552 (true if read-only, false if not).
1553
1554 This uses the L<blockdev(8)> command.");
1555
1556   ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1557    [InitEmpty, Always, TestOutputInt (
1558       [["blockdev_getss"; "/dev/sda"]], 512)],
1559    "get sectorsize of block device",
1560    "\
1561 This returns the size of sectors on a block device.
1562 Usually 512, but can be larger for modern devices.
1563
1564 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1565 for that).
1566
1567 This uses the L<blockdev(8)> command.");
1568
1569   ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1570    [InitEmpty, Always, TestOutputInt (
1571       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1572    "get blocksize of block device",
1573    "\
1574 This returns the block size of a device.
1575
1576 (Note this is different from both I<size in blocks> and
1577 I<filesystem block size>).
1578
1579 This uses the L<blockdev(8)> command.");
1580
1581   ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1582    [], (* XXX test *)
1583    "set blocksize of block device",
1584    "\
1585 This sets the block size of a device.
1586
1587 (Note this is different from both I<size in blocks> and
1588 I<filesystem block size>).
1589
1590 This uses the L<blockdev(8)> command.");
1591
1592   ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1593    [InitEmpty, Always, TestOutputInt (
1594       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1595    "get total size of device in 512-byte sectors",
1596    "\
1597 This returns the size of the device in units of 512-byte sectors
1598 (even if the sectorsize isn't 512 bytes ... weird).
1599
1600 See also C<guestfs_blockdev_getss> for the real sector size of
1601 the device, and C<guestfs_blockdev_getsize64> for the more
1602 useful I<size in bytes>.
1603
1604 This uses the L<blockdev(8)> command.");
1605
1606   ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1607    [InitEmpty, Always, TestOutputInt (
1608       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1609    "get total size of device in bytes",
1610    "\
1611 This returns the size of the device in bytes.
1612
1613 See also C<guestfs_blockdev_getsz>.
1614
1615 This uses the L<blockdev(8)> command.");
1616
1617   ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1618    [InitEmpty, Always, TestRun
1619       [["blockdev_flushbufs"; "/dev/sda"]]],
1620    "flush device buffers",
1621    "\
1622 This tells the kernel to flush internal buffers associated
1623 with C<device>.
1624
1625 This uses the L<blockdev(8)> command.");
1626
1627   ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1628    [InitEmpty, Always, TestRun
1629       [["blockdev_rereadpt"; "/dev/sda"]]],
1630    "reread partition table",
1631    "\
1632 Reread the partition table on C<device>.
1633
1634 This uses the L<blockdev(8)> command.");
1635
1636   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1637    [InitBasicFS, Always, TestOutput (
1638       (* Pick a file from cwd which isn't likely to change. *)
1639     [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1640      ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1641    "upload a file from the local machine",
1642    "\
1643 Upload local file C<filename> to C<remotefilename> on the
1644 filesystem.
1645
1646 C<filename> can also be a named pipe.
1647
1648 See also C<guestfs_download>.");
1649
1650   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1651    [InitBasicFS, Always, TestOutput (
1652       (* Pick a file from cwd which isn't likely to change. *)
1653     [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1654      ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1655      ["upload"; "testdownload.tmp"; "/upload"];
1656      ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1657    "download a file to the local machine",
1658    "\
1659 Download file C<remotefilename> and save it as C<filename>
1660 on the local machine.
1661
1662 C<filename> can also be a named pipe.
1663
1664 See also C<guestfs_upload>, C<guestfs_cat>.");
1665
1666   ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1667    [InitBasicFS, Always, TestOutput (
1668       [["write_file"; "/new"; "test\n"; "0"];
1669        ["checksum"; "crc"; "/new"]], "935282863");
1670     InitBasicFS, Always, TestLastFail (
1671       [["checksum"; "crc"; "/new"]]);
1672     InitBasicFS, Always, TestOutput (
1673       [["write_file"; "/new"; "test\n"; "0"];
1674        ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1675     InitBasicFS, Always, TestOutput (
1676       [["write_file"; "/new"; "test\n"; "0"];
1677        ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1678     InitBasicFS, Always, TestOutput (
1679       [["write_file"; "/new"; "test\n"; "0"];
1680        ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1681     InitBasicFS, Always, TestOutput (
1682       [["write_file"; "/new"; "test\n"; "0"];
1683        ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1684     InitBasicFS, Always, TestOutput (
1685       [["write_file"; "/new"; "test\n"; "0"];
1686        ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1687     InitBasicFS, Always, TestOutput (
1688       [["write_file"; "/new"; "test\n"; "0"];
1689        ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
1690     InitBasicFS, Always, TestOutput (
1691       (* RHEL 5 thinks this is an HFS+ filesystem unless we give
1692        * the type explicitly.
1693        *)
1694       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
1695        ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
1696    "compute MD5, SHAx or CRC checksum of file",
1697    "\
1698 This call computes the MD5, SHAx or CRC checksum of the
1699 file named C<path>.
1700
1701 The type of checksum to compute is given by the C<csumtype>
1702 parameter which must have one of the following values:
1703
1704 =over 4
1705
1706 =item C<crc>
1707
1708 Compute the cyclic redundancy check (CRC) specified by POSIX
1709 for the C<cksum> command.
1710
1711 =item C<md5>
1712
1713 Compute the MD5 hash (using the C<md5sum> program).
1714
1715 =item C<sha1>
1716
1717 Compute the SHA1 hash (using the C<sha1sum> program).
1718
1719 =item C<sha224>
1720
1721 Compute the SHA224 hash (using the C<sha224sum> program).
1722
1723 =item C<sha256>
1724
1725 Compute the SHA256 hash (using the C<sha256sum> program).
1726
1727 =item C<sha384>
1728
1729 Compute the SHA384 hash (using the C<sha384sum> program).
1730
1731 =item C<sha512>
1732
1733 Compute the SHA512 hash (using the C<sha512sum> program).
1734
1735 =back
1736
1737 The checksum is returned as a printable string.");
1738
1739   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1740    [InitBasicFS, Always, TestOutput (
1741       [["tar_in"; "../images/helloworld.tar"; "/"];
1742        ["cat"; "/hello"]], "hello\n")],
1743    "unpack tarfile to directory",
1744    "\
1745 This command uploads and unpacks local file C<tarfile> (an
1746 I<uncompressed> tar file) into C<directory>.
1747
1748 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1749
1750   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1751    [],
1752    "pack directory into tarfile",
1753    "\
1754 This command packs the contents of C<directory> and downloads
1755 it to local file C<tarfile>.
1756
1757 To download a compressed tarball, use C<guestfs_tgz_out>.");
1758
1759   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1760    [InitBasicFS, Always, TestOutput (
1761       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1762        ["cat"; "/hello"]], "hello\n")],
1763    "unpack compressed tarball to directory",
1764    "\
1765 This command uploads and unpacks local file C<tarball> (a
1766 I<gzip compressed> tar file) into C<directory>.
1767
1768 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1769
1770   ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1771    [],
1772    "pack directory into compressed tarball",
1773    "\
1774 This command packs the contents of C<directory> and downloads
1775 it to local file C<tarball>.
1776
1777 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1778
1779   ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1780    [InitBasicFS, Always, TestLastFail (
1781       [["umount"; "/"];
1782        ["mount_ro"; "/dev/sda1"; "/"];
1783        ["touch"; "/new"]]);
1784     InitBasicFS, Always, TestOutput (
1785       [["write_file"; "/new"; "data"; "0"];
1786        ["umount"; "/"];
1787        ["mount_ro"; "/dev/sda1"; "/"];
1788        ["cat"; "/new"]], "data")],
1789    "mount a guest disk, read-only",
1790    "\
1791 This is the same as the C<guestfs_mount> command, but it
1792 mounts the filesystem with the read-only (I<-o ro>) flag.");
1793
1794   ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1795    [],
1796    "mount a guest disk with mount options",
1797    "\
1798 This is the same as the C<guestfs_mount> command, but it
1799 allows you to set the mount options as for the
1800 L<mount(8)> I<-o> flag.");
1801
1802   ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1803    [],
1804    "mount a guest disk with mount options and vfstype",
1805    "\
1806 This is the same as the C<guestfs_mount> command, but it
1807 allows you to set both the mount options and the vfstype
1808 as for the L<mount(8)> I<-o> and I<-t> flags.");
1809
1810   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1811    [],
1812    "debugging and internals",
1813    "\
1814 The C<guestfs_debug> command exposes some internals of
1815 C<guestfsd> (the guestfs daemon) that runs inside the
1816 qemu subprocess.
1817
1818 There is no comprehensive help for this command.  You have
1819 to look at the file C<daemon/debug.c> in the libguestfs source
1820 to find out what you can do.");
1821
1822   ("lvremove", (RErr, [String "device"]), 77, [],
1823    [InitEmpty, Always, TestOutputList (
1824       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1825        ["pvcreate"; "/dev/sda1"];
1826        ["vgcreate"; "VG"; "/dev/sda1"];
1827        ["lvcreate"; "LV1"; "VG"; "50"];
1828        ["lvcreate"; "LV2"; "VG"; "50"];
1829        ["lvremove"; "/dev/VG/LV1"];
1830        ["lvs"]], ["/dev/VG/LV2"]);
1831     InitEmpty, Always, TestOutputList (
1832       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1833        ["pvcreate"; "/dev/sda1"];
1834        ["vgcreate"; "VG"; "/dev/sda1"];
1835        ["lvcreate"; "LV1"; "VG"; "50"];
1836        ["lvcreate"; "LV2"; "VG"; "50"];
1837        ["lvremove"; "/dev/VG"];
1838        ["lvs"]], []);
1839     InitEmpty, Always, TestOutputList (
1840       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1841        ["pvcreate"; "/dev/sda1"];
1842        ["vgcreate"; "VG"; "/dev/sda1"];
1843        ["lvcreate"; "LV1"; "VG"; "50"];
1844        ["lvcreate"; "LV2"; "VG"; "50"];
1845        ["lvremove"; "/dev/VG"];
1846        ["vgs"]], ["VG"])],
1847    "remove an LVM logical volume",
1848    "\
1849 Remove an LVM logical volume C<device>, where C<device> is
1850 the path to the LV, such as C</dev/VG/LV>.
1851
1852 You can also remove all LVs in a volume group by specifying
1853 the VG name, C</dev/VG>.");
1854
1855   ("vgremove", (RErr, [String "vgname"]), 78, [],
1856    [InitEmpty, Always, TestOutputList (
1857       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1858        ["pvcreate"; "/dev/sda1"];
1859        ["vgcreate"; "VG"; "/dev/sda1"];
1860        ["lvcreate"; "LV1"; "VG"; "50"];
1861        ["lvcreate"; "LV2"; "VG"; "50"];
1862        ["vgremove"; "VG"];
1863        ["lvs"]], []);
1864     InitEmpty, Always, TestOutputList (
1865       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1866        ["pvcreate"; "/dev/sda1"];
1867        ["vgcreate"; "VG"; "/dev/sda1"];
1868        ["lvcreate"; "LV1"; "VG"; "50"];
1869        ["lvcreate"; "LV2"; "VG"; "50"];
1870        ["vgremove"; "VG"];
1871        ["vgs"]], [])],
1872    "remove an LVM volume group",
1873    "\
1874 Remove an LVM volume group C<vgname>, (for example C<VG>).
1875
1876 This also forcibly removes all logical volumes in the volume
1877 group (if any).");
1878
1879   ("pvremove", (RErr, [String "device"]), 79, [],
1880    [InitEmpty, Always, TestOutputListOfDevices (
1881       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1882        ["pvcreate"; "/dev/sda1"];
1883        ["vgcreate"; "VG"; "/dev/sda1"];
1884        ["lvcreate"; "LV1"; "VG"; "50"];
1885        ["lvcreate"; "LV2"; "VG"; "50"];
1886        ["vgremove"; "VG"];
1887        ["pvremove"; "/dev/sda1"];
1888        ["lvs"]], []);
1889     InitEmpty, Always, TestOutputListOfDevices (
1890       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1891        ["pvcreate"; "/dev/sda1"];
1892        ["vgcreate"; "VG"; "/dev/sda1"];
1893        ["lvcreate"; "LV1"; "VG"; "50"];
1894        ["lvcreate"; "LV2"; "VG"; "50"];
1895        ["vgremove"; "VG"];
1896        ["pvremove"; "/dev/sda1"];
1897        ["vgs"]], []);
1898     InitEmpty, Always, TestOutputListOfDevices (
1899       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
1900        ["pvcreate"; "/dev/sda1"];
1901        ["vgcreate"; "VG"; "/dev/sda1"];
1902        ["lvcreate"; "LV1"; "VG"; "50"];
1903        ["lvcreate"; "LV2"; "VG"; "50"];
1904        ["vgremove"; "VG"];
1905        ["pvremove"; "/dev/sda1"];
1906        ["pvs"]], [])],
1907    "remove an LVM physical volume",
1908    "\
1909 This wipes a physical volume C<device> so that LVM will no longer
1910 recognise it.
1911
1912 The implementation uses the C<pvremove> command which refuses to
1913 wipe physical volumes that contain any volume groups, so you have
1914 to remove those first.");
1915
1916   ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
1917    [InitBasicFS, Always, TestOutput (
1918       [["set_e2label"; "/dev/sda1"; "testlabel"];
1919        ["get_e2label"; "/dev/sda1"]], "testlabel")],
1920    "set the ext2/3/4 filesystem label",
1921    "\
1922 This sets the ext2/3/4 filesystem label of the filesystem on
1923 C<device> to C<label>.  Filesystem labels are limited to
1924 16 characters.
1925
1926 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
1927 to return the existing label on a filesystem.");
1928
1929   ("get_e2label", (RString "label", [String "device"]), 81, [],
1930    [],
1931    "get the ext2/3/4 filesystem label",
1932    "\
1933 This returns the ext2/3/4 filesystem label of the filesystem on
1934 C<device>.");
1935
1936   ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
1937    [InitBasicFS, Always, TestOutput (
1938       [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
1939        ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
1940     InitBasicFS, Always, TestOutput (
1941       [["set_e2uuid"; "/dev/sda1"; "clear"];
1942        ["get_e2uuid"; "/dev/sda1"]], "");
1943     (* We can't predict what UUIDs will be, so just check the commands run. *)
1944     InitBasicFS, Always, TestRun (
1945       [["set_e2uuid"; "/dev/sda1"; "random"]]);
1946     InitBasicFS, Always, TestRun (
1947       [["set_e2uuid"; "/dev/sda1"; "time"]])],
1948    "set the ext2/3/4 filesystem UUID",
1949    "\
1950 This sets the ext2/3/4 filesystem UUID of the filesystem on
1951 C<device> to C<uuid>.  The format of the UUID and alternatives
1952 such as C<clear>, C<random> and C<time> are described in the
1953 L<tune2fs(8)> manpage.
1954
1955 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
1956 to return the existing UUID of a filesystem.");
1957
1958   ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
1959    [],
1960    "get the ext2/3/4 filesystem UUID",
1961    "\
1962 This returns the ext2/3/4 filesystem UUID of the filesystem on
1963 C<device>.");
1964
1965   ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
1966    [InitBasicFS, Always, TestOutputInt (
1967       [["umount"; "/dev/sda1"];
1968        ["fsck"; "ext2"; "/dev/sda1"]], 0);
1969     InitBasicFS, Always, TestOutputInt (
1970       [["umount"; "/dev/sda1"];
1971        ["zero"; "/dev/sda1"];
1972        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
1973    "run the filesystem checker",
1974    "\
1975 This runs the filesystem checker (fsck) on C<device> which
1976 should have filesystem type C<fstype>.
1977
1978 The returned integer is the status.  See L<fsck(8)> for the
1979 list of status codes from C<fsck>.
1980
1981 Notes:
1982
1983 =over 4
1984
1985 =item *
1986
1987 Multiple status codes can be summed together.
1988
1989 =item *
1990
1991 A non-zero return code can mean \"success\", for example if
1992 errors have been corrected on the filesystem.
1993
1994 =item *
1995
1996 Checking or repairing NTFS volumes is not supported
1997 (by linux-ntfs).
1998
1999 =back
2000
2001 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2002
2003   ("zero", (RErr, [String "device"]), 85, [],
2004    [InitBasicFS, Always, TestOutput (
2005       [["umount"; "/dev/sda1"];
2006        ["zero"; "/dev/sda1"];
2007        ["file"; "/dev/sda1"]], "data")],
2008    "write zeroes to the device",
2009    "\
2010 This command writes zeroes over the first few blocks of C<device>.
2011
2012 How many blocks are zeroed isn't specified (but it's I<not> enough
2013 to securely wipe the device).  It should be sufficient to remove
2014 any partition tables, filesystem superblocks and so on.
2015
2016 See also: C<guestfs_scrub_device>.");
2017
2018   ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
2019    [InitBasicFS, Always, TestOutputTrue (
2020       [["grub_install"; "/"; "/dev/sda1"];
2021        ["is_dir"; "/boot"]])],
2022    "install GRUB",
2023    "\
2024 This command installs GRUB (the Grand Unified Bootloader) on
2025 C<device>, with the root directory being C<root>.");
2026
2027   ("cp", (RErr, [String "src"; String "dest"]), 87, [],
2028    [InitBasicFS, Always, TestOutput (
2029       [["write_file"; "/old"; "file content"; "0"];
2030        ["cp"; "/old"; "/new"];
2031        ["cat"; "/new"]], "file content");
2032     InitBasicFS, Always, TestOutputTrue (
2033       [["write_file"; "/old"; "file content"; "0"];
2034        ["cp"; "/old"; "/new"];
2035        ["is_file"; "/old"]]);
2036     InitBasicFS, Always, TestOutput (
2037       [["write_file"; "/old"; "file content"; "0"];
2038        ["mkdir"; "/dir"];
2039        ["cp"; "/old"; "/dir/new"];
2040        ["cat"; "/dir/new"]], "file content")],
2041    "copy a file",
2042    "\
2043 This copies a file from C<src> to C<dest> where C<dest> is
2044 either a destination filename or destination directory.");
2045
2046   ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2047    [InitBasicFS, Always, TestOutput (
2048       [["mkdir"; "/olddir"];
2049        ["mkdir"; "/newdir"];
2050        ["write_file"; "/olddir/file"; "file content"; "0"];
2051        ["cp_a"; "/olddir"; "/newdir"];
2052        ["cat"; "/newdir/olddir/file"]], "file content")],
2053    "copy a file or directory recursively",
2054    "\
2055 This copies a file or directory from C<src> to C<dest>
2056 recursively using the C<cp -a> command.");
2057
2058   ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2059    [InitBasicFS, Always, TestOutput (
2060       [["write_file"; "/old"; "file content"; "0"];
2061        ["mv"; "/old"; "/new"];
2062        ["cat"; "/new"]], "file content");
2063     InitBasicFS, Always, TestOutputFalse (
2064       [["write_file"; "/old"; "file content"; "0"];
2065        ["mv"; "/old"; "/new"];
2066        ["is_file"; "/old"]])],
2067    "move a file",
2068    "\
2069 This moves a file from C<src> to C<dest> where C<dest> is
2070 either a destination filename or destination directory.");
2071
2072   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2073    [InitEmpty, Always, TestRun (
2074       [["drop_caches"; "3"]])],
2075    "drop kernel page cache, dentries and inodes",
2076    "\
2077 This instructs the guest kernel to drop its page cache,
2078 and/or dentries and inode caches.  The parameter C<whattodrop>
2079 tells the kernel what precisely to drop, see
2080 L<http://linux-mm.org/Drop_Caches>
2081
2082 Setting C<whattodrop> to 3 should drop everything.
2083
2084 This automatically calls L<sync(2)> before the operation,
2085 so that the maximum guest memory is freed.");
2086
2087   ("dmesg", (RString "kmsgs", []), 91, [],
2088    [InitEmpty, Always, TestRun (
2089       [["dmesg"]])],
2090    "return kernel messages",
2091    "\
2092 This returns the kernel messages (C<dmesg> output) from
2093 the guest kernel.  This is sometimes useful for extended
2094 debugging of problems.
2095
2096 Another way to get the same information is to enable
2097 verbose messages with C<guestfs_set_verbose> or by setting
2098 the environment variable C<LIBGUESTFS_DEBUG=1> before
2099 running the program.");
2100
2101   ("ping_daemon", (RErr, []), 92, [],
2102    [InitEmpty, Always, TestRun (
2103       [["ping_daemon"]])],
2104    "ping the guest daemon",
2105    "\
2106 This is a test probe into the guestfs daemon running inside
2107 the qemu subprocess.  Calling this function checks that the
2108 daemon responds to the ping message, without affecting the daemon
2109 or attached block device(s) in any other way.");
2110
2111   ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2112    [InitBasicFS, Always, TestOutputTrue (
2113       [["write_file"; "/file1"; "contents of a file"; "0"];
2114        ["cp"; "/file1"; "/file2"];
2115        ["equal"; "/file1"; "/file2"]]);
2116     InitBasicFS, Always, TestOutputFalse (
2117       [["write_file"; "/file1"; "contents of a file"; "0"];
2118        ["write_file"; "/file2"; "contents of another file"; "0"];
2119        ["equal"; "/file1"; "/file2"]]);
2120     InitBasicFS, Always, TestLastFail (
2121       [["equal"; "/file1"; "/file2"]])],
2122    "test if two files have equal contents",
2123    "\
2124 This compares the two files C<file1> and C<file2> and returns
2125 true if their content is exactly equal, or false otherwise.
2126
2127 The external L<cmp(1)> program is used for the comparison.");
2128
2129   ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2130    [InitBasicFS, Always, TestOutputList (
2131       [["write_file"; "/new"; "hello\nworld\n"; "0"];
2132        ["strings"; "/new"]], ["hello"; "world"]);
2133     InitBasicFS, Always, TestOutputList (
2134       [["touch"; "/new"];
2135        ["strings"; "/new"]], [])],
2136    "print the printable strings in a file",
2137    "\
2138 This runs the L<strings(1)> command on a file and returns
2139 the list of printable strings found.");
2140
2141   ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2142    [InitBasicFS, Always, TestOutputList (
2143       [["write_file"; "/new"; "hello\nworld\n"; "0"];
2144        ["strings_e"; "b"; "/new"]], []);
2145     InitBasicFS, Disabled, TestOutputList (
2146       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2147        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2148    "print the printable strings in a file",
2149    "\
2150 This is like the C<guestfs_strings> command, but allows you to
2151 specify the encoding.
2152
2153 See the L<strings(1)> manpage for the full list of encodings.
2154
2155 Commonly useful encodings are C<l> (lower case L) which will
2156 show strings inside Windows/x86 files.
2157
2158 The returned strings are transcoded to UTF-8.");
2159
2160   ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2161    [InitBasicFS, Always, TestOutput (
2162       [["write_file"; "/new"; "hello\nworld\n"; "12"];
2163        ["hexdump"; "/new"]], "00000000  68 65 6c 6c 6f 0a 77 6f  72 6c 64 0a              |hello.world.|\n0000000c\n");
2164     (* Test for RHBZ#501888c2 regression which caused large hexdump
2165      * commands to segfault.
2166      *)
2167     InitBasicFS, Always, TestRun (
2168       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2169        ["hexdump"; "/100krandom"]])],
2170    "dump a file in hexadecimal",
2171    "\
2172 This runs C<hexdump -C> on the given C<path>.  The result is
2173 the human-readable, canonical hex dump of the file.");
2174
2175   ("zerofree", (RErr, [String "device"]), 97, [],
2176    [InitNone, Always, TestOutput (
2177       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2178        ["mkfs"; "ext3"; "/dev/sda1"];
2179        ["mount"; "/dev/sda1"; "/"];
2180        ["write_file"; "/new"; "test file"; "0"];
2181        ["umount"; "/dev/sda1"];
2182        ["zerofree"; "/dev/sda1"];
2183        ["mount"; "/dev/sda1"; "/"];
2184        ["cat"; "/new"]], "test file")],
2185    "zero unused inodes and disk blocks on ext2/3 filesystem",
2186    "\
2187 This runs the I<zerofree> program on C<device>.  This program
2188 claims to zero unused inodes and disk blocks on an ext2/3
2189 filesystem, thus making it possible to compress the filesystem
2190 more effectively.
2191
2192 You should B<not> run this program if the filesystem is
2193 mounted.
2194
2195 It is possible that using this program can damage the filesystem
2196 or data on the filesystem.");
2197
2198   ("pvresize", (RErr, [String "device"]), 98, [],
2199    [],
2200    "resize an LVM physical volume",
2201    "\
2202 This resizes (expands or shrinks) an existing LVM physical
2203 volume to match the new size of the underlying device.");
2204
2205   ("sfdisk_N", (RErr, [String "device"; Int "partnum";
2206                        Int "cyls"; Int "heads"; Int "sectors";
2207                        String "line"]), 99, [DangerWillRobinson],
2208    [],
2209    "modify a single partition on a block device",
2210    "\
2211 This runs L<sfdisk(8)> option to modify just the single
2212 partition C<n> (note: C<n> counts from 1).
2213
2214 For other parameters, see C<guestfs_sfdisk>.  You should usually
2215 pass C<0> for the cyls/heads/sectors parameters.");
2216
2217   ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2218    [],
2219    "display the partition table",
2220    "\
2221 This displays the partition table on C<device>, in the
2222 human-readable output of the L<sfdisk(8)> command.  It is
2223 not intended to be parsed.");
2224
2225   ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2226    [],
2227    "display the kernel geometry",
2228    "\
2229 This displays the kernel's idea of the geometry of C<device>.
2230
2231 The result is in human-readable format, and not designed to
2232 be parsed.");
2233
2234   ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2235    [],
2236    "display the disk geometry from the partition table",
2237    "\
2238 This displays the disk geometry of C<device> read from the
2239 partition table.  Especially in the case where the underlying
2240 block device has been resized, this can be different from the
2241 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2242
2243 The result is in human-readable format, and not designed to
2244 be parsed.");
2245
2246   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2247    [],
2248    "activate or deactivate all volume groups",
2249    "\
2250 This command activates or (if C<activate> is false) deactivates
2251 all logical volumes in all volume groups.
2252 If activated, then they are made known to the
2253 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2254 then those devices disappear.
2255
2256 This command is the same as running C<vgchange -a y|n>");
2257
2258   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2259    [],
2260    "activate or deactivate some volume groups",
2261    "\
2262 This command activates or (if C<activate> is false) deactivates
2263 all logical volumes in the listed volume groups C<volgroups>.
2264 If activated, then they are made known to the
2265 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2266 then those devices disappear.
2267
2268 This command is the same as running C<vgchange -a y|n volgroups...>
2269
2270 Note that if C<volgroups> is an empty list then B<all> volume groups
2271 are activated or deactivated.");
2272
2273   ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2274    [InitNone, Always, TestOutput (
2275     [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2276      ["pvcreate"; "/dev/sda1"];
2277      ["vgcreate"; "VG"; "/dev/sda1"];
2278      ["lvcreate"; "LV"; "VG"; "10"];
2279      ["mkfs"; "ext2"; "/dev/VG/LV"];
2280      ["mount"; "/dev/VG/LV"; "/"];
2281      ["write_file"; "/new"; "test content"; "0"];
2282      ["umount"; "/"];
2283      ["lvresize"; "/dev/VG/LV"; "20"];
2284      ["e2fsck_f"; "/dev/VG/LV"];
2285      ["resize2fs"; "/dev/VG/LV"];
2286      ["mount"; "/dev/VG/LV"; "/"];
2287      ["cat"; "/new"]], "test content")],
2288    "resize an LVM logical volume",
2289    "\
2290 This resizes (expands or shrinks) an existing LVM logical
2291 volume to C<mbytes>.  When reducing, data in the reduced part
2292 is lost.");
2293
2294   ("resize2fs", (RErr, [String "device"]), 106, [],
2295    [], (* lvresize tests this *)
2296    "resize an ext2/ext3 filesystem",
2297    "\
2298 This resizes an ext2 or ext3 filesystem to match the size of
2299 the underlying device.
2300
2301 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2302 on the C<device> before calling this command.  For unknown reasons
2303 C<resize2fs> sometimes gives an error about this and sometimes not.
2304 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2305 calling this function.");
2306
2307   ("find", (RStringList "names", [String "directory"]), 107, [],
2308    [InitBasicFS, Always, TestOutputList (
2309       [["find"; "/"]], ["lost+found"]);
2310     InitBasicFS, Always, TestOutputList (
2311       [["touch"; "/a"];
2312        ["mkdir"; "/b"];
2313        ["touch"; "/b/c"];
2314        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2315     InitBasicFS, Always, TestOutputList (
2316       [["mkdir_p"; "/a/b/c"];
2317        ["touch"; "/a/b/c/d"];
2318        ["find"; "/a/b/"]], ["c"; "c/d"])],
2319    "find all files and directories",
2320    "\
2321 This command lists out all files and directories, recursively,
2322 starting at C<directory>.  It is essentially equivalent to
2323 running the shell command C<find directory -print> but some
2324 post-processing happens on the output, described below.
2325
2326 This returns a list of strings I<without any prefix>.  Thus
2327 if the directory structure was:
2328
2329  /tmp/a
2330  /tmp/b
2331  /tmp/c/d
2332
2333 then the returned list from C<guestfs_find> C</tmp> would be
2334 4 elements:
2335
2336  a
2337  b
2338  c
2339  c/d
2340
2341 If C<directory> is not a directory, then this command returns
2342 an error.
2343
2344 The returned list is sorted.");
2345
2346   ("e2fsck_f", (RErr, [String "device"]), 108, [],
2347    [], (* lvresize tests this *)
2348    "check an ext2/ext3 filesystem",
2349    "\
2350 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2351 filesystem checker on C<device>, noninteractively (C<-p>),
2352 even if the filesystem appears to be clean (C<-f>).
2353
2354 This command is only needed because of C<guestfs_resize2fs>
2355 (q.v.).  Normally you should use C<guestfs_fsck>.");
2356
2357   ("sleep", (RErr, [Int "secs"]), 109, [],
2358    [InitNone, Always, TestRun (
2359     [["sleep"; "1"]])],
2360    "sleep for some seconds",
2361    "\
2362 Sleep for C<secs> seconds.");
2363
2364   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [],
2365    [InitNone, Always, TestOutputInt (
2366       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2367        ["mkfs"; "ntfs"; "/dev/sda1"];
2368        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2369     InitNone, Always, TestOutputInt (
2370       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2371        ["mkfs"; "ext2"; "/dev/sda1"];
2372        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2373    "probe NTFS volume",
2374    "\
2375 This command runs the L<ntfs-3g.probe(8)> command which probes
2376 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2377 be mounted read-write, and some cannot be mounted at all).
2378
2379 C<rw> is a boolean flag.  Set it to true if you want to test
2380 if the volume can be mounted read-write.  Set it to false if
2381 you want to test if the volume can be mounted read-only.
2382
2383 The return value is an integer which C<0> if the operation
2384 would succeed, or some non-zero value documented in the
2385 L<ntfs-3g.probe(8)> manual page.");
2386
2387   ("sh", (RString "output", [String "command"]), 111, [],
2388    [], (* XXX needs tests *)
2389    "run a command via the shell",
2390    "\
2391 This call runs a command from the guest filesystem via the
2392 guest's C</bin/sh>.
2393
2394 This is like C<guestfs_command>, but passes the command to:
2395
2396  /bin/sh -c \"command\"
2397
2398 Depending on the guest's shell, this usually results in
2399 wildcards being expanded, shell expressions being interpolated
2400 and so on.
2401
2402 All the provisos about C<guestfs_command> apply to this call.");
2403
2404   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2405    [], (* XXX needs tests *)
2406    "run a command via the shell returning lines",
2407    "\
2408 This is the same as C<guestfs_sh>, but splits the result
2409 into a list of lines.
2410
2411 See also: C<guestfs_command_lines>");
2412
2413   ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [],
2414    [InitBasicFS, Always, TestOutputList (
2415       [["mkdir_p"; "/a/b/c"];
2416        ["touch"; "/a/b/c/d"];
2417        ["touch"; "/a/b/c/e"];
2418        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2419     InitBasicFS, Always, TestOutputList (
2420       [["mkdir_p"; "/a/b/c"];
2421        ["touch"; "/a/b/c/d"];
2422        ["touch"; "/a/b/c/e"];
2423        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2424     InitBasicFS, Always, TestOutputList (
2425       [["mkdir_p"; "/a/b/c"];
2426        ["touch"; "/a/b/c/d"];
2427        ["touch"; "/a/b/c/e"];
2428        ["glob_expand"; "/a/*/x/*"]], [])],
2429    "expand a wildcard path",
2430    "\
2431 This command searches for all the pathnames matching
2432 C<pattern> according to the wildcard expansion rules
2433 used by the shell.
2434
2435 If no paths match, then this returns an empty list
2436 (note: not an error).
2437
2438 It is just a wrapper around the C L<glob(3)> function
2439 with flags C<GLOB_MARK|GLOB_BRACE>.
2440 See that manual page for more details.");
2441
2442   ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson],
2443    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2444       [["scrub_device"; "/dev/sdc"]])],
2445    "scrub (securely wipe) a device",
2446    "\
2447 This command writes patterns over C<device> to make data retrieval
2448 more difficult.
2449
2450 It is an interface to the L<scrub(1)> program.  See that
2451 manual page for more details.");
2452
2453   ("scrub_file", (RErr, [String "file"]), 115, [],
2454    [InitBasicFS, Always, TestRun (
2455       [["write_file"; "/file"; "content"; "0"];
2456        ["scrub_file"; "/file"]])],
2457    "scrub (securely wipe) a file",
2458    "\
2459 This command writes patterns over a file to make data retrieval
2460 more difficult.
2461
2462 The file is I<removed> after scrubbing.
2463
2464 It is an interface to the L<scrub(1)> program.  See that
2465 manual page for more details.");
2466
2467   ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2468    [], (* XXX needs testing *)
2469    "scrub (securely wipe) free space",
2470    "\
2471 This command creates the directory C<dir> and then fills it
2472 with files until the filesystem is full, and scrubs the files
2473 as for C<guestfs_scrub_file>, and deletes them.
2474 The intention is to scrub any free space on the partition
2475 containing C<dir>.
2476
2477 It is an interface to the L<scrub(1)> program.  See that
2478 manual page for more details.");
2479
2480   ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2481    [InitBasicFS, Always, TestRun (
2482       [["mkdir"; "/tmp"];
2483        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2484    "create a temporary directory",
2485    "\
2486 This command creates a temporary directory.  The
2487 C<template> parameter should be a full pathname for the
2488 temporary directory name with the final six characters being
2489 \"XXXXXX\".
2490
2491 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2492 the second one being suitable for Windows filesystems.
2493
2494 The name of the temporary directory that was created
2495 is returned.
2496
2497 The temporary directory is created with mode 0700
2498 and is owned by root.
2499
2500 The caller is responsible for deleting the temporary
2501 directory and its contents after use.
2502
2503 See also: L<mkdtemp(3)>");
2504
2505   ("wc_l", (RInt "lines", [String "path"]), 118, [],
2506    [InitBasicFS, Always, TestOutputInt (
2507       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2508        ["wc_l"; "/10klines"]], 10000)],
2509    "count lines in a file",
2510    "\
2511 This command counts the lines in a file, using the
2512 C<wc -l> external command.");
2513
2514   ("wc_w", (RInt "words", [String "path"]), 119, [],
2515    [InitBasicFS, Always, TestOutputInt (
2516       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2517        ["wc_w"; "/10klines"]], 10000)],
2518    "count words in a file",
2519    "\
2520 This command counts the words in a file, using the
2521 C<wc -w> external command.");
2522
2523   ("wc_c", (RInt "chars", [String "path"]), 120, [],
2524    [InitBasicFS, Always, TestOutputInt (
2525       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2526        ["wc_c"; "/100kallspaces"]], 102400)],
2527    "count characters in a file",
2528    "\
2529 This command counts the characters in a file, using the
2530 C<wc -c> external command.");
2531
2532   ("head", (RStringList "lines", [String "path"]), 121, [ProtocolLimitWarning],
2533    [InitBasicFS, Always, TestOutputList (
2534       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2535        ["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2536    "return first 10 lines of a file",
2537    "\
2538 This command returns up to the first 10 lines of a file as
2539 a list of strings.");
2540
2541   ("head_n", (RStringList "lines", [Int "nrlines"; String "path"]), 122, [ProtocolLimitWarning],
2542    [InitBasicFS, Always, TestOutputList (
2543       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2544        ["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2545     InitBasicFS, Always, TestOutputList (
2546       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2547        ["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2548     InitBasicFS, Always, TestOutputList (
2549       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2550        ["head_n"; "0"; "/10klines"]], [])],
2551    "return first N lines of a file",
2552    "\
2553 If the parameter C<nrlines> is a positive number, this returns the first
2554 C<nrlines> lines of the file C<path>.
2555
2556 If the parameter C<nrlines> is a negative number, this returns lines
2557 from the file C<path>, excluding the last C<nrlines> lines.
2558
2559 If the parameter C<nrlines> is zero, this returns an empty list.");
2560
2561   ("tail", (RStringList "lines", [String "path"]), 123, [ProtocolLimitWarning],
2562    [InitBasicFS, Always, TestOutputList (
2563       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2564        ["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2565    "return last 10 lines of a file",
2566    "\
2567 This command returns up to the last 10 lines of a file as
2568 a list of strings.");
2569
2570   ("tail_n", (RStringList "lines", [Int "nrlines"; String "path"]), 124, [ProtocolLimitWarning],
2571    [InitBasicFS, Always, TestOutputList (
2572       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2573        ["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2574     InitBasicFS, Always, TestOutputList (
2575       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2576        ["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2577     InitBasicFS, Always, TestOutputList (
2578       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2579        ["tail_n"; "0"; "/10klines"]], [])],
2580    "return last N lines of a file",
2581    "\
2582 If the parameter C<nrlines> is a positive number, this returns the last
2583 C<nrlines> lines of the file C<path>.
2584
2585 If the parameter C<nrlines> is a negative number, this returns lines
2586 from the file C<path>, starting with the C<-nrlines>th line.
2587
2588 If the parameter C<nrlines> is zero, this returns an empty list.");
2589
2590   ("df", (RString "output", []), 125, [],
2591    [], (* XXX Tricky to test because it depends on the exact format
2592         * of the 'df' command and other imponderables.
2593         *)
2594    "report file system disk space usage",
2595    "\
2596 This command runs the C<df> command to report disk space used.
2597
2598 This command is mostly useful for interactive sessions.  It
2599 is I<not> intended that you try to parse the output string.
2600 Use C<statvfs> from programs.");
2601
2602   ("df_h", (RString "output", []), 126, [],
2603    [], (* XXX Tricky to test because it depends on the exact format
2604         * of the 'df' command and other imponderables.
2605         *)
2606    "report file system disk space usage (human readable)",
2607    "\
2608 This command runs the C<df -h> command to report disk space used
2609 in human-readable format.
2610
2611 This command is mostly useful for interactive sessions.  It
2612 is I<not> intended that you try to parse the output string.
2613 Use C<statvfs> from programs.");
2614
2615   ("du", (RInt64 "sizekb", [String "path"]), 127, [],
2616    [InitBasicFS, Always, TestOutputInt (
2617       [["mkdir"; "/p"];
2618        ["du"; "/p"]], 1 (* ie. 1 block, so depends on ext3 blocksize *))],
2619    "estimate file space usage",
2620    "\
2621 This command runs the C<du -s> command to estimate file space
2622 usage for C<path>.
2623
2624 C<path> can be a file or a directory.  If C<path> is a directory
2625 then the estimate includes the contents of the directory and all
2626 subdirectories (recursively).
2627
2628 The result is the estimated size in I<kilobytes>
2629 (ie. units of 1024 bytes).");
2630
2631   ("initrd_list", (RStringList "filenames", [String "path"]), 128, [],
2632    [InitBasicFS, Always, TestOutputList (
2633       [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"];
2634        ["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3"])],
2635    "list files in an initrd",
2636    "\
2637 This command lists out files contained in an initrd.
2638
2639 The files are listed without any initial C</> character.  The
2640 files are listed in the order they appear (not necessarily
2641 alphabetical).  Directory names are listed as separate items.
2642
2643 Old Linux kernels (2.4 and earlier) used a compressed ext2
2644 filesystem as initrd.  We I<only> support the newer initramfs
2645 format (compressed cpio files).");
2646
2647   ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
2648    [],
2649    "mount a file using the loop device",
2650    "\
2651 This command lets you mount C<file> (a filesystem image
2652 in a file) on a mount point.  It is entirely equivalent to
2653 the command C<mount -o loop file mountpoint>.");
2654
2655   ("mkswap", (RErr, [String "device"]), 130, [],
2656    [InitEmpty, Always, TestRun (
2657       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2658        ["mkswap"; "/dev/sda1"]])],
2659    "create a swap partition",
2660    "\
2661 Create a swap partition on C<device>.");
2662
2663   ("mkswap_L", (RErr, [String "label"; String "device"]), 131, [],
2664    [InitEmpty, Always, TestRun (
2665       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2666        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2667    "create a swap partition with a label",
2668    "\
2669 Create a swap partition on C<device> with label C<label>.");
2670
2671   ("mkswap_U", (RErr, [String "uuid"; String "device"]), 132, [],
2672    [InitEmpty, Always, TestRun (
2673       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2674        ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
2675    "create a swap partition with an explicit UUID",
2676    "\
2677 Create a swap partition on C<device> with UUID C<uuid>.");
2678
2679   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 133, [],
2680    [InitBasicFS, Always, TestOutputStruct (
2681       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2682        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2683        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2684     InitBasicFS, Always, TestOutputStruct (
2685       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2686        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2687    "make block, character or FIFO devices",
2688    "\
2689 This call creates block or character special devices, or
2690 named pipes (FIFOs).
2691
2692 The C<mode> parameter should be the mode, using the standard
2693 constants.  C<devmajor> and C<devminor> are the
2694 device major and minor numbers, only used when creating block
2695 and character special devices.");
2696
2697   ("mkfifo", (RErr, [Int "mode"; String "path"]), 134, [],
2698    [InitBasicFS, Always, TestOutputStruct (
2699       [["mkfifo"; "0o777"; "/node"];
2700        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2701    "make FIFO (named pipe)",
2702    "\
2703 This call creates a FIFO (named pipe) called C<path> with
2704 mode C<mode>.  It is just a convenient wrapper around
2705 C<guestfs_mknod>.");
2706
2707   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 135, [],
2708    [InitBasicFS, Always, TestOutputStruct (
2709       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2710        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2711    "make block device node",
2712    "\
2713 This call creates a block device node called C<path> with
2714 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2715 It is just a convenient wrapper around C<guestfs_mknod>.");
2716
2717   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 136, [],
2718    [InitBasicFS, Always, TestOutputStruct (
2719       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2720        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2721    "make char device node",
2722    "\
2723 This call creates a char device node called C<path> with
2724 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2725 It is just a convenient wrapper around C<guestfs_mknod>.");
2726
2727   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2728    [], (* XXX umask is one of those stateful things that we should
2729         * reset between each test.
2730         *)
2731    "set file mode creation mask (umask)",
2732    "\
2733 This function sets the mask used for creating new files and
2734 device nodes to C<mask & 0777>.
2735
2736 Typical umask values would be C<022> which creates new files
2737 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2738 C<002> which creates new files with permissions like
2739 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2740
2741 The default umask is C<022>.  This is important because it
2742 means that directories and device nodes will be created with
2743 C<0644> or C<0755> mode even if you specify C<0777>.
2744
2745 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2746
2747 This call returns the previous umask.");
2748
2749 ]
2750
2751 let all_functions = non_daemon_functions @ daemon_functions
2752
2753 (* In some places we want the functions to be displayed sorted
2754  * alphabetically, so this is useful:
2755  *)
2756 let all_functions_sorted =
2757   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
2758                compare n1 n2) all_functions
2759
2760 (* Column names and types from LVM PVs/VGs/LVs. *)
2761 let pv_cols = [
2762   "pv_name", `String;
2763   "pv_uuid", `UUID;
2764   "pv_fmt", `String;
2765   "pv_size", `Bytes;
2766   "dev_size", `Bytes;
2767   "pv_free", `Bytes;
2768   "pv_used", `Bytes;
2769   "pv_attr", `String (* XXX *);
2770   "pv_pe_count", `Int;
2771   "pv_pe_alloc_count", `Int;
2772   "pv_tags", `String;
2773   "pe_start", `Bytes;
2774   "pv_mda_count", `Int;
2775   "pv_mda_free", `Bytes;
2776 (* Not in Fedora 10:
2777   "pv_mda_size", `Bytes;
2778 *)
2779 ]
2780 let vg_cols = [
2781   "vg_name", `String;
2782   "vg_uuid", `UUID;
2783   "vg_fmt", `String;
2784   "vg_attr", `String (* XXX *);
2785   "vg_size", `Bytes;
2786   "vg_free", `Bytes;
2787   "vg_sysid", `String;
2788   "vg_extent_size", `Bytes;
2789   "vg_extent_count", `Int;
2790   "vg_free_count", `Int;
2791   "max_lv", `Int;
2792   "max_pv", `Int;
2793   "pv_count", `Int;
2794   "lv_count", `Int;
2795   "snap_count", `Int;
2796   "vg_seqno", `Int;
2797   "vg_tags", `String;
2798   "vg_mda_count", `Int;
2799   "vg_mda_free", `Bytes;
2800 (* Not in Fedora 10:
2801   "vg_mda_size", `Bytes;
2802 *)
2803 ]
2804 let lv_cols = [
2805   "lv_name", `String;
2806   "lv_uuid", `UUID;
2807   "lv_attr", `String (* XXX *);
2808   "lv_major", `Int;
2809   "lv_minor", `Int;
2810   "lv_kernel_major", `Int;
2811   "lv_kernel_minor", `Int;
2812   "lv_size", `Bytes;
2813   "seg_count", `Int;
2814   "origin", `String;
2815   "snap_percent", `OptPercent;
2816   "copy_percent", `OptPercent;
2817   "move_pv", `String;
2818   "lv_tags", `String;
2819   "mirror_log", `String;
2820   "modules", `String;
2821 ]
2822
2823 (* Column names and types from stat structures.
2824  * NB. Can't use things like 'st_atime' because glibc header files
2825  * define some of these as macros.  Ugh.
2826  *)
2827 let stat_cols = [
2828   "dev", `Int;
2829   "ino", `Int;
2830   "mode", `Int;
2831   "nlink", `Int;
2832   "uid", `Int;
2833   "gid", `Int;
2834   "rdev", `Int;
2835   "size", `Int;
2836   "blksize", `Int;
2837   "blocks", `Int;
2838   "atime", `Int;
2839   "mtime", `Int;
2840   "ctime", `Int;
2841 ]
2842 let statvfs_cols = [
2843   "bsize", `Int;
2844   "frsize", `Int;
2845   "blocks", `Int;
2846   "bfree", `Int;
2847   "bavail", `Int;
2848   "files", `Int;
2849   "ffree", `Int;
2850   "favail", `Int;
2851   "fsid", `Int;
2852   "flag", `Int;
2853   "namemax", `Int;
2854 ]
2855
2856 (* Used for testing language bindings. *)
2857 type callt =
2858   | CallString of string
2859   | CallOptString of string option
2860   | CallStringList of string list
2861   | CallInt of int
2862   | CallBool of bool
2863
2864 (* Useful functions.
2865  * Note we don't want to use any external OCaml libraries which
2866  * makes this a bit harder than it should be.
2867  *)
2868 let failwithf fs = ksprintf failwith fs
2869
2870 let replace_char s c1 c2 =
2871   let s2 = String.copy s in
2872   let r = ref false in
2873   for i = 0 to String.length s2 - 1 do
2874     if String.unsafe_get s2 i = c1 then (
2875       String.unsafe_set s2 i c2;
2876       r := true
2877     )
2878   done;
2879   if not !r then s else s2
2880
2881 let isspace c =
2882   c = ' '
2883   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
2884
2885 let triml ?(test = isspace) str =
2886   let i = ref 0 in
2887   let n = ref (String.length str) in
2888   while !n > 0 && test str.[!i]; do
2889     decr n;
2890     incr i
2891   done;
2892   if !i = 0 then str
2893   else String.sub str !i !n
2894
2895 let trimr ?(test = isspace) str =
2896   let n = ref (String.length str) in
2897   while !n > 0 && test str.[!n-1]; do
2898     decr n
2899   done;
2900   if !n = String.length str then str
2901   else String.sub str 0 !n
2902
2903 let trim ?(test = isspace) str =
2904   trimr ~test (triml ~test str)
2905
2906 let rec find s sub =
2907   let len = String.length s in
2908   let sublen = String.length sub in
2909   let rec loop i =
2910     if i <= len-sublen then (
2911       let rec loop2 j =
2912         if j < sublen then (
2913           if s.[i+j] = sub.[j] then loop2 (j+1)
2914           else -1
2915         ) else
2916           i (* found *)
2917       in
2918       let r = loop2 0 in
2919       if r = -1 then loop (i+1) else r
2920     ) else
2921       -1 (* not found *)
2922   in
2923   loop 0
2924
2925 let rec replace_str s s1 s2 =
2926   let len = String.length s in
2927   let sublen = String.length s1 in
2928   let i = find s s1 in
2929   if i = -1 then s
2930   else (
2931     let s' = String.sub s 0 i in
2932     let s'' = String.sub s (i+sublen) (len-i-sublen) in
2933     s' ^ s2 ^ replace_str s'' s1 s2
2934   )
2935
2936 let rec string_split sep str =
2937   let len = String.length str in
2938   let seplen = String.length sep in
2939   let i = find str sep in
2940   if i = -1 then [str]
2941   else (
2942     let s' = String.sub str 0 i in
2943     let s'' = String.sub str (i+seplen) (len-i-seplen) in
2944     s' :: string_split sep s''
2945   )
2946
2947 let files_equal n1 n2 =
2948   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
2949   match Sys.command cmd with
2950   | 0 -> true
2951   | 1 -> false
2952   | i -> failwithf "%s: failed with error code %d" cmd i
2953
2954 let rec find_map f = function
2955   | [] -> raise Not_found
2956   | x :: xs ->
2957       match f x with
2958       | Some y -> y
2959       | None -> find_map f xs
2960
2961 let iteri f xs =
2962   let rec loop i = function
2963     | [] -> ()
2964     | x :: xs -> f i x; loop (i+1) xs
2965   in
2966   loop 0 xs
2967
2968 let mapi f xs =
2969   let rec loop i = function
2970     | [] -> []
2971     | x :: xs -> let r = f i x in r :: loop (i+1) xs
2972   in
2973   loop 0 xs
2974
2975 let name_of_argt = function
2976   | String n | OptString n | StringList n | Bool n | Int n
2977   | FileIn n | FileOut n -> n
2978
2979 let seq_of_test = function
2980   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
2981   | TestOutputListOfDevices (s, _)
2982   | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
2983   | TestOutputLength (s, _) | TestOutputStruct (s, _)
2984   | TestLastFail s -> s
2985
2986 (* Check function names etc. for consistency. *)
2987 let check_functions () =
2988   let contains_uppercase str =
2989     let len = String.length str in
2990     let rec loop i =
2991       if i >= len then false
2992       else (
2993         let c = str.[i] in
2994         if c >= 'A' && c <= 'Z' then true
2995         else loop (i+1)
2996       )
2997     in
2998     loop 0
2999   in
3000
3001   (* Check function names. *)
3002   List.iter (
3003     fun (name, _, _, _, _, _, _) ->
3004       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
3005         failwithf "function name %s does not need 'guestfs' prefix" name;
3006       if name = "" then
3007         failwithf "function name is empty";
3008       if name.[0] < 'a' || name.[0] > 'z' then
3009         failwithf "function name %s must start with lowercase a-z" name;
3010       if String.contains name '-' then
3011         failwithf "function name %s should not contain '-', use '_' instead."
3012           name
3013   ) all_functions;
3014
3015   (* Check function parameter/return names. *)
3016   List.iter (
3017     fun (name, style, _, _, _, _, _) ->
3018       let check_arg_ret_name n =
3019         if contains_uppercase n then
3020           failwithf "%s param/ret %s should not contain uppercase chars"
3021             name n;
3022         if String.contains n '-' || String.contains n '_' then
3023           failwithf "%s param/ret %s should not contain '-' or '_'"
3024             name n;
3025         if n = "value" then
3026           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;
3027         if n = "int" || n = "char" || n = "short" || n = "long" then
3028           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
3029         if n = "i" || n = "n" then
3030           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
3031         if n = "argv" || n = "args" then
3032           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
3033       in
3034
3035       (match fst style with
3036        | RErr -> ()
3037        | RInt n | RInt64 n | RBool n | RConstString n | RString n
3038        | RStringList n | RPVList n | RVGList n | RLVList n
3039        | RStat n | RStatVFS n
3040        | RHashtable n ->
3041            check_arg_ret_name n
3042        | RIntBool (n,m) ->
3043            check_arg_ret_name n;
3044            check_arg_ret_name m
3045       );
3046       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
3047   ) all_functions;
3048
3049   (* Check short descriptions. *)
3050   List.iter (
3051     fun (name, _, _, _, _, shortdesc, _) ->
3052       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
3053         failwithf "short description of %s should begin with lowercase." name;
3054       let c = shortdesc.[String.length shortdesc-1] in
3055       if c = '\n' || c = '.' then
3056         failwithf "short description of %s should not end with . or \\n." name
3057   ) all_functions;
3058
3059   (* Check long dscriptions. *)
3060   List.iter (
3061     fun (name, _, _, _, _, _, longdesc) ->
3062       if longdesc.[String.length longdesc-1] = '\n' then
3063         failwithf "long description of %s should not end with \\n." name
3064   ) all_functions;
3065
3066   (* Check proc_nrs. *)
3067   List.iter (
3068     fun (name, _, proc_nr, _, _, _, _) ->
3069       if proc_nr <= 0 then
3070         failwithf "daemon function %s should have proc_nr > 0" name
3071   ) daemon_functions;
3072
3073   List.iter (
3074     fun (name, _, proc_nr, _, _, _, _) ->
3075       if proc_nr <> -1 then
3076         failwithf "non-daemon function %s should have proc_nr -1" name
3077   ) non_daemon_functions;
3078
3079   let proc_nrs =
3080     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
3081       daemon_functions in
3082   let proc_nrs =
3083     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
3084   let rec loop = function
3085     | [] -> ()
3086     | [_] -> ()
3087     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
3088         loop rest
3089     | (name1,nr1) :: (name2,nr2) :: _ ->
3090         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
3091           name1 name2 nr1 nr2
3092   in
3093   loop proc_nrs;
3094
3095   (* Check tests. *)
3096   List.iter (
3097     function
3098       (* Ignore functions that have no tests.  We generate a
3099        * warning when the user does 'make check' instead.
3100        *)
3101     | name, _, _, _, [], _, _ -> ()
3102     | name, _, _, _, tests, _, _ ->
3103         let funcs =
3104           List.map (
3105             fun (_, _, test) ->
3106               match seq_of_test test with
3107               | [] ->
3108                   failwithf "%s has a test containing an empty sequence" name
3109               | cmds -> List.map List.hd cmds
3110           ) tests in
3111         let funcs = List.flatten funcs in
3112
3113         let tested = List.mem name funcs in
3114
3115         if not tested then
3116           failwithf "function %s has tests but does not test itself" name
3117   ) all_functions
3118
3119 (* 'pr' prints to the current output file. *)
3120 let chan = ref stdout
3121 let pr fs = ksprintf (output_string !chan) fs
3122
3123 (* Generate a header block in a number of standard styles. *)
3124 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
3125 type license = GPLv2 | LGPLv2
3126
3127 let generate_header comment license =
3128   let c = match comment with
3129     | CStyle ->     pr "/* "; " *"
3130     | HashStyle ->  pr "# ";  "#"
3131     | OCamlStyle -> pr "(* "; " *"
3132     | HaskellStyle -> pr "{- "; "  " in
3133   pr "libguestfs generated file\n";
3134   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
3135   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
3136   pr "%s\n" c;
3137   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
3138   pr "%s\n" c;
3139   (match license with
3140    | GPLv2 ->
3141        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
3142        pr "%s it under the terms of the GNU General Public License as published by\n" c;
3143        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
3144        pr "%s (at your option) any later version.\n" c;
3145        pr "%s\n" c;
3146        pr "%s This program is distributed in the hope that it will be useful,\n" c;
3147        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3148        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
3149        pr "%s GNU General Public License for more details.\n" c;
3150        pr "%s\n" c;
3151        pr "%s You should have received a copy of the GNU General Public License along\n" c;
3152        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
3153        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
3154
3155    | LGPLv2 ->
3156        pr "%s This library is free software; you can redistribute it and/or\n" c;
3157        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
3158        pr "%s License as published by the Free Software Foundation; either\n" c;
3159        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
3160        pr "%s\n" c;
3161        pr "%s This library is distributed in the hope that it will be useful,\n" c;
3162        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3163        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
3164        pr "%s Lesser General Public License for more details.\n" c;
3165        pr "%s\n" c;
3166        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
3167        pr "%s License along with this library; if not, write to the Free Software\n" c;
3168        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
3169   );
3170   (match comment with
3171    | CStyle -> pr " */\n"
3172    | HashStyle -> ()
3173    | OCamlStyle -> pr " *)\n"
3174    | HaskellStyle -> pr "-}\n"
3175   );
3176   pr "\n"
3177
3178 (* Start of main code generation functions below this line. *)
3179
3180 (* Generate the pod documentation for the C API. *)
3181 let rec generate_actions_pod () =
3182   List.iter (
3183     fun (shortname, style, _, flags, _, _, longdesc) ->
3184       if not (List.mem NotInDocs flags) then (
3185         let name = "guestfs_" ^ shortname in
3186         pr "=head2 %s\n\n" name;
3187         pr " ";
3188         generate_prototype ~extern:false ~handle:"handle" name style;
3189         pr "\n\n";
3190         pr "%s\n\n" longdesc;
3191         (match fst style with
3192          | RErr ->
3193              pr "This function returns 0 on success or -1 on error.\n\n"
3194          | RInt _ ->
3195              pr "On error this function returns -1.\n\n"
3196          | RInt64 _ ->
3197              pr "On error this function returns -1.\n\n"
3198          | RBool _ ->
3199              pr "This function returns a C truth value on success or -1 on error.\n\n"
3200          | RConstString _ ->
3201              pr "This function returns a string, or NULL on error.
3202 The string is owned by the guest handle and must I<not> be freed.\n\n"
3203          | RString _ ->
3204              pr "This function returns a string, or NULL on error.
3205 I<The caller must free the returned string after use>.\n\n"
3206          | RStringList _ ->
3207              pr "This function returns a NULL-terminated array of strings
3208 (like L<environ(3)>), or NULL if there was an error.
3209 I<The caller must free the strings and the array after use>.\n\n"
3210          | RIntBool _ ->
3211              pr "This function returns a C<struct guestfs_int_bool *>,
3212 or NULL if there was an error.
3213 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
3214          | RPVList _ ->
3215              pr "This function returns a C<struct guestfs_lvm_pv_list *>
3216 (see E<lt>guestfs-structs.hE<gt>),
3217 or NULL if there was an error.
3218 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
3219          | RVGList _ ->
3220              pr "This function returns a C<struct guestfs_lvm_vg_list *>
3221 (see E<lt>guestfs-structs.hE<gt>),
3222 or NULL if there was an error.
3223 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
3224          | RLVList _ ->
3225              pr "This function returns a C<struct guestfs_lvm_lv_list *>
3226 (see E<lt>guestfs-structs.hE<gt>),
3227 or NULL if there was an error.
3228 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
3229          | RStat _ ->
3230              pr "This function returns a C<struct guestfs_stat *>
3231 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
3232 or NULL if there was an error.
3233 I<The caller must call C<free> after use>.\n\n"
3234          | RStatVFS _ ->
3235              pr "This function returns a C<struct guestfs_statvfs *>
3236 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
3237 or NULL if there was an error.
3238 I<The caller must call C<free> after use>.\n\n"
3239          | RHashtable _ ->
3240              pr "This function returns a NULL-terminated array of
3241 strings, or NULL if there was an error.
3242 The array of strings will always have length C<2n+1>, where
3243 C<n> keys and values alternate, followed by the trailing NULL entry.
3244 I<The caller must free the strings and the array after use>.\n\n"
3245         );
3246         if List.mem ProtocolLimitWarning flags then
3247           pr "%s\n\n" protocol_limit_warning;
3248         if List.mem DangerWillRobinson flags then
3249           pr "%s\n\n" danger_will_robinson
3250       )
3251   ) all_functions_sorted
3252
3253 and generate_structs_pod () =
3254   (* LVM structs documentation. *)
3255   List.iter (
3256     fun (typ, cols) ->
3257       pr "=head2 guestfs_lvm_%s\n" typ;
3258       pr "\n";
3259       pr " struct guestfs_lvm_%s {\n" typ;
3260       List.iter (
3261         function
3262         | name, `String -> pr "  char *%s;\n" name
3263         | name, `UUID ->
3264             pr "  /* The next field is NOT nul-terminated, be careful when printing it: */\n";
3265             pr "  char %s[32];\n" name
3266         | name, `Bytes -> pr "  uint64_t %s;\n" name
3267         | name, `Int -> pr "  int64_t %s;\n" name
3268         | name, `OptPercent ->
3269             pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
3270             pr "  float %s;\n" name
3271       ) cols;
3272       pr " \n";
3273       pr " struct guestfs_lvm_%s_list {\n" typ;
3274       pr "   uint32_t len; /* Number of elements in list. */\n";
3275       pr "   struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
3276       pr " };\n";
3277       pr " \n";
3278       pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
3279         typ typ;
3280       pr "\n"
3281   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3282
3283 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3284  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3285  *
3286  * We have to use an underscore instead of a dash because otherwise
3287  * rpcgen generates incorrect code.
3288  *
3289  * This header is NOT exported to clients, but see also generate_structs_h.
3290  *)
3291 and generate_xdr () =
3292   generate_header CStyle LGPLv2;
3293
3294   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3295   pr "typedef string str<>;\n";
3296   pr "\n";
3297
3298   (* LVM internal structures. *)
3299   List.iter (
3300     function
3301     | typ, cols ->
3302         pr "struct guestfs_lvm_int_%s {\n" typ;
3303         List.iter (function
3304                    | name, `String -> pr "  string %s<>;\n" name
3305                    | name, `UUID -> pr "  opaque %s[32];\n" name
3306                    | name, `Bytes -> pr "  hyper %s;\n" name
3307                    | name, `Int -> pr "  hyper %s;\n" name
3308                    | name, `OptPercent -> pr "  float %s;\n" name
3309                   ) cols;
3310         pr "};\n";
3311         pr "\n";
3312         pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
3313         pr "\n";
3314   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3315
3316   (* Stat internal structures. *)
3317   List.iter (
3318     function
3319     | typ, cols ->
3320         pr "struct guestfs_int_%s {\n" typ;
3321         List.iter (function
3322                    | name, `Int -> pr "  hyper %s;\n" name
3323                   ) cols;
3324         pr "};\n";
3325         pr "\n";
3326   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3327
3328   List.iter (
3329     fun (shortname, style, _, _, _, _, _) ->
3330       let name = "guestfs_" ^ shortname in
3331
3332       (match snd style with
3333        | [] -> ()
3334        | args ->
3335            pr "struct %s_args {\n" name;
3336            List.iter (
3337              function
3338              | String n -> pr "  string %s<>;\n" n
3339              | OptString n -> pr "  str *%s;\n" n
3340              | StringList n -> pr "  str %s<>;\n" n
3341              | Bool n -> pr "  bool %s;\n" n
3342              | Int n -> pr "  int %s;\n" n
3343              | FileIn _ | FileOut _ -> ()
3344            ) args;
3345            pr "};\n\n"
3346       );
3347       (match fst style with
3348        | RErr -> ()
3349        | RInt n ->
3350            pr "struct %s_ret {\n" name;
3351            pr "  int %s;\n" n;
3352            pr "};\n\n"
3353        | RInt64 n ->
3354            pr "struct %s_ret {\n" name;
3355            pr "  hyper %s;\n" n;
3356            pr "};\n\n"
3357        | RBool n ->
3358            pr "struct %s_ret {\n" name;
3359            pr "  bool %s;\n" n;
3360            pr "};\n\n"
3361        | RConstString _ ->
3362            failwithf "RConstString cannot be returned from a daemon function"
3363        | RString n ->
3364            pr "struct %s_ret {\n" name;
3365            pr "  string %s<>;\n" n;
3366            pr "};\n\n"
3367        | RStringList n ->
3368            pr "struct %s_ret {\n" name;
3369            pr "  str %s<>;\n" n;
3370            pr "};\n\n"
3371        | RIntBool (n,m) ->
3372            pr "struct %s_ret {\n" name;
3373            pr "  int %s;\n" n;
3374            pr "  bool %s;\n" m;
3375            pr "};\n\n"
3376        | RPVList n ->
3377            pr "struct %s_ret {\n" name;
3378            pr "  guestfs_lvm_int_pv_list %s;\n" n;
3379            pr "};\n\n"
3380        | RVGList n ->
3381            pr "struct %s_ret {\n" name;
3382            pr "  guestfs_lvm_int_vg_list %s;\n" n;
3383            pr "};\n\n"
3384        | RLVList n ->
3385            pr "struct %s_ret {\n" name;
3386            pr "  guestfs_lvm_int_lv_list %s;\n" n;
3387            pr "};\n\n"
3388        | RStat n ->
3389            pr "struct %s_ret {\n" name;
3390            pr "  guestfs_int_stat %s;\n" n;
3391            pr "};\n\n"
3392        | RStatVFS n ->
3393            pr "struct %s_ret {\n" name;
3394            pr "  guestfs_int_statvfs %s;\n" n;
3395            pr "};\n\n"
3396        | RHashtable n ->
3397            pr "struct %s_ret {\n" name;
3398            pr "  str %s<>;\n" n;
3399            pr "};\n\n"
3400       );
3401   ) daemon_functions;
3402
3403   (* Table of procedure numbers. *)
3404   pr "enum guestfs_procedure {\n";
3405   List.iter (
3406     fun (shortname, _, proc_nr, _, _, _, _) ->
3407       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3408   ) daemon_functions;
3409   pr "  GUESTFS_PROC_NR_PROCS\n";
3410   pr "};\n";
3411   pr "\n";
3412
3413   (* Having to choose a maximum message size is annoying for several
3414    * reasons (it limits what we can do in the API), but it (a) makes
3415    * the protocol a lot simpler, and (b) provides a bound on the size
3416    * of the daemon which operates in limited memory space.  For large
3417    * file transfers you should use FTP.
3418    *)
3419   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3420   pr "\n";
3421
3422   (* Message header, etc. *)
3423   pr "\
3424 /* The communication protocol is now documented in the guestfs(3)
3425  * manpage.
3426  */
3427
3428 const GUESTFS_PROGRAM = 0x2000F5F5;
3429 const GUESTFS_PROTOCOL_VERSION = 1;
3430
3431 /* These constants must be larger than any possible message length. */
3432 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3433 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3434
3435 enum guestfs_message_direction {
3436   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
3437   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
3438 };
3439
3440 enum guestfs_message_status {
3441   GUESTFS_STATUS_OK = 0,
3442   GUESTFS_STATUS_ERROR = 1
3443 };
3444
3445 const GUESTFS_ERROR_LEN = 256;
3446
3447 struct guestfs_message_error {
3448   string error_message<GUESTFS_ERROR_LEN>;
3449 };
3450
3451 struct guestfs_message_header {
3452   unsigned prog;                     /* GUESTFS_PROGRAM */
3453   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
3454   guestfs_procedure proc;            /* GUESTFS_PROC_x */
3455   guestfs_message_direction direction;
3456   unsigned serial;                   /* message serial number */
3457   guestfs_message_status status;
3458 };
3459
3460 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3461
3462 struct guestfs_chunk {
3463   int cancel;                        /* if non-zero, transfer is cancelled */
3464   /* data size is 0 bytes if the transfer has finished successfully */
3465   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3466 };
3467 "
3468
3469 (* Generate the guestfs-structs.h file. *)
3470 and generate_structs_h () =
3471   generate_header CStyle LGPLv2;
3472
3473   (* This is a public exported header file containing various
3474    * structures.  The structures are carefully written to have
3475    * exactly the same in-memory format as the XDR structures that
3476    * we use on the wire to the daemon.  The reason for creating
3477    * copies of these structures here is just so we don't have to
3478    * export the whole of guestfs_protocol.h (which includes much
3479    * unrelated and XDR-dependent stuff that we don't want to be
3480    * public, or required by clients).
3481    *
3482    * To reiterate, we will pass these structures to and from the
3483    * client with a simple assignment or memcpy, so the format
3484    * must be identical to what rpcgen / the RFC defines.
3485    *)
3486
3487   (* guestfs_int_bool structure. *)
3488   pr "struct guestfs_int_bool {\n";
3489   pr "  int32_t i;\n";
3490   pr "  int32_t b;\n";
3491   pr "};\n";
3492   pr "\n";
3493
3494   (* LVM public structures. *)
3495   List.iter (
3496     function
3497     | typ, cols ->
3498         pr "struct guestfs_lvm_%s {\n" typ;
3499         List.iter (
3500           function
3501           | name, `String -> pr "  char *%s;\n" name
3502           | name, `UUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3503           | name, `Bytes -> pr "  uint64_t %s;\n" name
3504           | name, `Int -> pr "  int64_t %s;\n" name
3505           | name, `OptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
3506         ) cols;
3507         pr "};\n";
3508         pr "\n";
3509         pr "struct guestfs_lvm_%s_list {\n" typ;
3510         pr "  uint32_t len;\n";
3511         pr "  struct guestfs_lvm_%s *val;\n" typ;
3512         pr "};\n";
3513         pr "\n"
3514   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3515
3516   (* Stat structures. *)
3517   List.iter (
3518     function
3519     | typ, cols ->
3520         pr "struct guestfs_%s {\n" typ;
3521         List.iter (
3522           function
3523           | name, `Int -> pr "  int64_t %s;\n" name
3524         ) cols;
3525         pr "};\n";
3526         pr "\n"
3527   ) ["stat", stat_cols; "statvfs", statvfs_cols]
3528
3529 (* Generate the guestfs-actions.h file. *)
3530 and generate_actions_h () =
3531   generate_header CStyle LGPLv2;
3532   List.iter (
3533     fun (shortname, style, _, _, _, _, _) ->
3534       let name = "guestfs_" ^ shortname in
3535       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3536         name style
3537   ) all_functions
3538
3539 (* Generate the client-side dispatch stubs. *)
3540 and generate_client_actions () =
3541   generate_header CStyle LGPLv2;
3542
3543   pr "\
3544 #include <stdio.h>
3545 #include <stdlib.h>
3546
3547 #include \"guestfs.h\"
3548 #include \"guestfs_protocol.h\"
3549
3550 #define error guestfs_error
3551 #define perrorf guestfs_perrorf
3552 #define safe_malloc guestfs_safe_malloc
3553 #define safe_realloc guestfs_safe_realloc
3554 #define safe_strdup guestfs_safe_strdup
3555 #define safe_memdup guestfs_safe_memdup
3556
3557 /* Check the return message from a call for validity. */
3558 static int
3559 check_reply_header (guestfs_h *g,
3560                     const struct guestfs_message_header *hdr,
3561                     int proc_nr, int serial)
3562 {
3563   if (hdr->prog != GUESTFS_PROGRAM) {
3564     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3565     return -1;
3566   }
3567   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3568     error (g, \"wrong protocol version (%%d/%%d)\",
3569            hdr->vers, GUESTFS_PROTOCOL_VERSION);
3570     return -1;
3571   }
3572   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3573     error (g, \"unexpected message direction (%%d/%%d)\",
3574            hdr->direction, GUESTFS_DIRECTION_REPLY);
3575     return -1;
3576   }
3577   if (hdr->proc != proc_nr) {
3578     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3579     return -1;
3580   }
3581   if (hdr->serial != serial) {
3582     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3583     return -1;
3584   }
3585
3586   return 0;
3587 }
3588
3589 /* Check we are in the right state to run a high-level action. */
3590 static int
3591 check_state (guestfs_h *g, const char *caller)
3592 {
3593   if (!guestfs_is_ready (g)) {
3594     if (guestfs_is_config (g))
3595       error (g, \"%%s: call launch() before using this function\",
3596         caller);
3597     else if (guestfs_is_launching (g))
3598       error (g, \"%%s: call wait_ready() before using this function\",
3599         caller);
3600     else
3601       error (g, \"%%s called from the wrong state, %%d != READY\",
3602         caller, guestfs_get_state (g));
3603     return -1;
3604   }
3605   return 0;
3606 }
3607
3608 ";
3609
3610   (* Client-side stubs for each function. *)
3611   List.iter (
3612     fun (shortname, style, _, _, _, _, _) ->
3613       let name = "guestfs_" ^ shortname in
3614
3615       (* Generate the context struct which stores the high-level
3616        * state between callback functions.
3617        *)
3618       pr "struct %s_ctx {\n" shortname;
3619       pr "  /* This flag is set by the callbacks, so we know we've done\n";
3620       pr "   * the callbacks as expected, and in the right sequence.\n";
3621       pr "   * 0 = not called, 1 = reply_cb called.\n";
3622       pr "   */\n";
3623       pr "  int cb_sequence;\n";
3624       pr "  struct guestfs_message_header hdr;\n";
3625       pr "  struct guestfs_message_error err;\n";
3626       (match fst style with
3627        | RErr -> ()
3628        | RConstString _ ->
3629            failwithf "RConstString cannot be returned from a daemon function"
3630        | RInt _ | RInt64 _
3631        | RBool _ | RString _ | RStringList _
3632        | RIntBool _
3633        | RPVList _ | RVGList _ | RLVList _
3634        | RStat _ | RStatVFS _
3635        | RHashtable _ ->
3636            pr "  struct %s_ret ret;\n" name
3637       );
3638       pr "};\n";
3639       pr "\n";
3640
3641       (* Generate the reply callback function. *)
3642       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3643       pr "{\n";
3644       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3645       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
3646       pr "\n";
3647       pr "  /* This should definitely not happen. */\n";
3648       pr "  if (ctx->cb_sequence != 0) {\n";
3649       pr "    ctx->cb_sequence = 9999;\n";
3650       pr "    error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
3651       pr "    return;\n";
3652       pr "  }\n";
3653       pr "\n";
3654       pr "  ml->main_loop_quit (ml, g);\n";
3655       pr "\n";
3656       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
3657       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
3658       pr "    return;\n";
3659       pr "  }\n";
3660       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
3661       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
3662       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
3663         name;
3664       pr "      return;\n";
3665       pr "    }\n";
3666       pr "    goto done;\n";
3667       pr "  }\n";
3668
3669       (match fst style with
3670        | RErr -> ()
3671        | RConstString _ ->
3672            failwithf "RConstString cannot be returned from a daemon function"
3673        | RInt _ | RInt64 _
3674        | RBool _ | RString _ | RStringList _
3675        | RIntBool _
3676        | RPVList _ | RVGList _ | RLVList _
3677        | RStat _ | RStatVFS _
3678        | RHashtable _ ->
3679             pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
3680             pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
3681             pr "    return;\n";
3682             pr "  }\n";
3683       );
3684
3685       pr " done:\n";
3686       pr "  ctx->cb_sequence = 1;\n";
3687       pr "}\n\n";
3688
3689       (* Generate the action stub. *)
3690       generate_prototype ~extern:false ~semicolon:false ~newline:true
3691         ~handle:"g" name style;
3692
3693       let error_code =
3694         match fst style with
3695         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
3696         | RConstString _ ->
3697             failwithf "RConstString cannot be returned from a daemon function"
3698         | RString _ | RStringList _ | RIntBool _
3699         | RPVList _ | RVGList _ | RLVList _
3700         | RStat _ | RStatVFS _
3701         | RHashtable _ ->
3702             "NULL" in
3703
3704       pr "{\n";
3705
3706       (match snd style with
3707        | [] -> ()
3708        | _ -> pr "  struct %s_args args;\n" name
3709       );
3710
3711       pr "  struct %s_ctx ctx;\n" shortname;
3712       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3713       pr "  int serial;\n";
3714       pr "\n";
3715       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
3716       pr "  guestfs_set_busy (g);\n";
3717       pr "\n";
3718       pr "  memset (&ctx, 0, sizeof ctx);\n";
3719       pr "\n";
3720
3721       (* Send the main header and arguments. *)
3722       (match snd style with
3723        | [] ->
3724            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
3725              (String.uppercase shortname)
3726        | args ->
3727            List.iter (
3728              function
3729              | String n ->
3730                  pr "  args.%s = (char *) %s;\n" n n
3731              | OptString n ->
3732                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
3733              | StringList n ->
3734                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
3735                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
3736              | Bool n ->
3737                  pr "  args.%s = %s;\n" n n
3738              | Int n ->
3739                  pr "  args.%s = %s;\n" n n
3740              | FileIn _ | FileOut _ -> ()
3741            ) args;
3742            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
3743              (String.uppercase shortname);
3744            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
3745              name;
3746       );
3747       pr "  if (serial == -1) {\n";
3748       pr "    guestfs_end_busy (g);\n";
3749       pr "    return %s;\n" error_code;
3750       pr "  }\n";
3751       pr "\n";
3752
3753       (* Send any additional files (FileIn) requested. *)
3754       let need_read_reply_label = ref false in
3755       List.iter (
3756         function
3757         | FileIn n ->
3758             pr "  {\n";
3759             pr "    int r;\n";
3760             pr "\n";
3761             pr "    r = guestfs__send_file_sync (g, %s);\n" n;
3762             pr "    if (r == -1) {\n";
3763             pr "      guestfs_end_busy (g);\n";
3764             pr "      return %s;\n" error_code;
3765             pr "    }\n";
3766             pr "    if (r == -2) /* daemon cancelled */\n";
3767             pr "      goto read_reply;\n";
3768             need_read_reply_label := true;
3769             pr "  }\n";
3770             pr "\n";
3771         | _ -> ()
3772       ) (snd style);
3773
3774       (* Wait for the reply from the remote end. *)
3775       if !need_read_reply_label then pr " read_reply:\n";
3776       pr "  guestfs__switch_to_receiving (g);\n";
3777       pr "  ctx.cb_sequence = 0;\n";
3778       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
3779       pr "  (void) ml->main_loop_run (ml, g);\n";
3780       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
3781       pr "  if (ctx.cb_sequence != 1) {\n";
3782       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
3783       pr "    guestfs_end_busy (g);\n";
3784       pr "    return %s;\n" error_code;
3785       pr "  }\n";
3786       pr "\n";
3787
3788       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
3789         (String.uppercase shortname);
3790       pr "    guestfs_end_busy (g);\n";
3791       pr "    return %s;\n" error_code;
3792       pr "  }\n";
3793       pr "\n";
3794
3795       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
3796       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
3797       pr "    free (ctx.err.error_message);\n";
3798       pr "    guestfs_end_busy (g);\n";
3799       pr "    return %s;\n" error_code;
3800       pr "  }\n";
3801       pr "\n";
3802
3803       (* Expecting to receive further files (FileOut)? *)
3804       List.iter (
3805         function
3806         | FileOut n ->
3807             pr "  if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
3808             pr "    guestfs_end_busy (g);\n";
3809             pr "    return %s;\n" error_code;
3810             pr "  }\n";
3811             pr "\n";
3812         | _ -> ()
3813       ) (snd style);
3814
3815       pr "  guestfs_end_busy (g);\n";
3816
3817       (match fst style with
3818        | RErr -> pr "  return 0;\n"
3819        | RInt n | RInt64 n | RBool n ->
3820            pr "  return ctx.ret.%s;\n" n
3821        | RConstString _ ->
3822            failwithf "RConstString cannot be returned from a daemon function"
3823        | RString n ->
3824            pr "  return ctx.ret.%s; /* caller will free */\n" n
3825        | RStringList n | RHashtable n ->
3826            pr "  /* caller will free this, but we need to add a NULL entry */\n";
3827            pr "  ctx.ret.%s.%s_val =\n" n n;
3828            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
3829            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
3830              n n;
3831            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
3832            pr "  return ctx.ret.%s.%s_val;\n" n n
3833        | RIntBool _ ->
3834            pr "  /* caller with free this */\n";
3835            pr "  return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
3836        | RPVList n | RVGList n | RLVList n
3837        | RStat n | RStatVFS n ->
3838            pr "  /* caller will free this */\n";
3839            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
3840       );
3841
3842       pr "}\n\n"
3843   ) daemon_functions
3844
3845 (* Generate daemon/actions.h. *)
3846 and generate_daemon_actions_h () =
3847   generate_header CStyle GPLv2;
3848
3849   pr "#include \"../src/guestfs_protocol.h\"\n";
3850   pr "\n";
3851
3852   List.iter (
3853     fun (name, style, _, _, _, _, _) ->
3854         generate_prototype
3855           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
3856           name style;
3857   ) daemon_functions
3858
3859 (* Generate the server-side stubs. *)
3860 and generate_daemon_actions () =
3861   generate_header CStyle GPLv2;
3862
3863   pr "#include <config.h>\n";
3864   pr "\n";
3865   pr "#include <stdio.h>\n";
3866   pr "#include <stdlib.h>\n";
3867   pr "#include <string.h>\n";
3868   pr "#include <inttypes.h>\n";
3869   pr "#include <ctype.h>\n";
3870   pr "#include <rpc/types.h>\n";
3871   pr "#include <rpc/xdr.h>\n";
3872   pr "\n";
3873   pr "#include \"daemon.h\"\n";
3874   pr "#include \"../src/guestfs_protocol.h\"\n";
3875   pr "#include \"actions.h\"\n";
3876   pr "\n";
3877
3878   List.iter (
3879     fun (name, style, _, _, _, _, _) ->
3880       (* Generate server-side stubs. *)
3881       pr "static void %s_stub (XDR *xdr_in)\n" name;
3882       pr "{\n";
3883       let error_code =
3884         match fst style with
3885         | RErr | RInt _ -> pr "  int r;\n"; "-1"
3886         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
3887         | RBool _ -> pr "  int r;\n"; "-1"
3888         | RConstString _ ->
3889             failwithf "RConstString cannot be returned from a daemon function"
3890         | RString _ -> pr "  char *r;\n"; "NULL"
3891         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
3892         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
3893         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
3894         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
3895         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL"
3896         | RStat _ -> pr "  guestfs_int_stat *r;\n"; "NULL"
3897         | RStatVFS _ -> pr "  guestfs_int_statvfs *r;\n"; "NULL" in
3898
3899       (match snd style with
3900        | [] -> ()
3901        | args ->
3902            pr "  struct guestfs_%s_args args;\n" name;
3903            List.iter (
3904              function
3905                (* Note we allow the string to be writable, in order to
3906                 * allow device name translation.  This is safe because
3907                 * we can modify the string (passed from RPC).
3908                 *)
3909              | String n
3910              | OptString n -> pr "  char *%s;\n" n
3911              | StringList n -> pr "  char **%s;\n" n
3912              | Bool n -> pr "  int %s;\n" n
3913              | Int n -> pr "  int %s;\n" n
3914              | FileIn _ | FileOut _ -> ()
3915            ) args
3916       );
3917       pr "\n";
3918
3919       (match snd style with
3920        | [] -> ()
3921        | args ->
3922            pr "  memset (&args, 0, sizeof args);\n";
3923            pr "\n";
3924            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
3925            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
3926            pr "    return;\n";
3927            pr "  }\n";
3928            List.iter (
3929              function
3930              | String n -> pr "  %s = args.%s;\n" n n
3931              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
3932              | StringList n ->
3933                  pr "  %s = realloc (args.%s.%s_val,\n" n n n;
3934                  pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
3935                  pr "  if (%s == NULL) {\n" n;
3936                  pr "    reply_with_perror (\"realloc\");\n";
3937                  pr "    goto done;\n";
3938                  pr "  }\n";
3939                  pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
3940                  pr "  args.%s.%s_val = %s;\n" n n n;
3941              | Bool n -> pr "  %s = args.%s;\n" n n
3942              | Int n -> pr "  %s = args.%s;\n" n n
3943              | FileIn _ | FileOut _ -> ()
3944            ) args;
3945            pr "\n"
3946       );
3947
3948       (* Don't want to call the impl with any FileIn or FileOut
3949        * parameters, since these go "outside" the RPC protocol.
3950        *)
3951       let argsnofile =
3952         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
3953           (snd style) in
3954       pr "  r = do_%s " name;
3955       generate_call_args argsnofile;
3956       pr ";\n";
3957
3958       pr "  if (r == %s)\n" error_code;
3959       pr "    /* do_%s has already called reply_with_error */\n" name;
3960       pr "    goto done;\n";
3961       pr "\n";
3962
3963       (* If there are any FileOut parameters, then the impl must
3964        * send its own reply.
3965        *)
3966       let no_reply =
3967         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
3968       if no_reply then
3969         pr "  /* do_%s has already sent a reply */\n" name
3970       else (
3971         match fst style with
3972         | RErr -> pr "  reply (NULL, NULL);\n"
3973         | RInt n | RInt64 n | RBool n ->
3974             pr "  struct guestfs_%s_ret ret;\n" name;
3975             pr "  ret.%s = r;\n" n;
3976             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3977               name
3978         | RConstString _ ->
3979             failwithf "RConstString cannot be returned from a daemon function"
3980         | RString n ->
3981             pr "  struct guestfs_%s_ret ret;\n" name;
3982             pr "  ret.%s = r;\n" n;
3983             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3984               name;
3985             pr "  free (r);\n"
3986         | RStringList n | RHashtable n ->
3987             pr "  struct guestfs_%s_ret ret;\n" name;
3988             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
3989             pr "  ret.%s.%s_val = r;\n" n n;
3990             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
3991               name;
3992             pr "  free_strings (r);\n"
3993         | RIntBool _ ->
3994             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
3995               name;
3996             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
3997         | RPVList n | RVGList n | RLVList n
3998         | RStat n | RStatVFS n ->
3999             pr "  struct guestfs_%s_ret ret;\n" name;
4000             pr "  ret.%s = *r;\n" n;
4001             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4002               name;
4003             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4004               name
4005       );
4006
4007       (* Free the args. *)
4008       (match snd style with
4009        | [] ->
4010            pr "done: ;\n";
4011        | _ ->
4012            pr "done:\n";
4013            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4014              name
4015       );
4016
4017       pr "}\n\n";
4018   ) daemon_functions;
4019
4020   (* Dispatch function. *)
4021   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4022   pr "{\n";
4023   pr "  switch (proc_nr) {\n";
4024
4025   List.iter (
4026     fun (name, style, _, _, _, _, _) ->
4027         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
4028         pr "      %s_stub (xdr_in);\n" name;
4029         pr "      break;\n"
4030   ) daemon_functions;
4031
4032   pr "    default:\n";
4033   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d, set LIBGUESTFS_PATH to point to the matching libguestfs appliance directory\", proc_nr);\n";
4034   pr "  }\n";
4035   pr "}\n";
4036   pr "\n";
4037
4038   (* LVM columns and tokenization functions. *)
4039   (* XXX This generates crap code.  We should rethink how we
4040    * do this parsing.
4041    *)
4042   List.iter (
4043     function
4044     | typ, cols ->
4045         pr "static const char *lvm_%s_cols = \"%s\";\n"
4046           typ (String.concat "," (List.map fst cols));
4047         pr "\n";
4048
4049         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
4050         pr "{\n";
4051         pr "  char *tok, *p, *next;\n";
4052         pr "  int i, j;\n";
4053         pr "\n";
4054         (*
4055         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4056         pr "\n";
4057         *)
4058         pr "  if (!str) {\n";
4059         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4060         pr "    return -1;\n";
4061         pr "  }\n";
4062         pr "  if (!*str || isspace (*str)) {\n";
4063         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4064         pr "    return -1;\n";
4065         pr "  }\n";
4066         pr "  tok = str;\n";
4067         List.iter (
4068           fun (name, coltype) ->
4069             pr "  if (!tok) {\n";
4070             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4071             pr "    return -1;\n";
4072             pr "  }\n";
4073             pr "  p = strchrnul (tok, ',');\n";
4074             pr "  if (*p) next = p+1; else next = NULL;\n";
4075             pr "  *p = '\\0';\n";
4076             (match coltype with
4077              | `String ->
4078                  pr "  r->%s = strdup (tok);\n" name;
4079                  pr "  if (r->%s == NULL) {\n" name;
4080                  pr "    perror (\"strdup\");\n";
4081                  pr "    return -1;\n";
4082                  pr "  }\n"
4083              | `UUID ->
4084                  pr "  for (i = j = 0; i < 32; ++j) {\n";
4085                  pr "    if (tok[j] == '\\0') {\n";
4086                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4087                  pr "      return -1;\n";
4088                  pr "    } else if (tok[j] != '-')\n";
4089                  pr "      r->%s[i++] = tok[j];\n" name;
4090                  pr "  }\n";
4091              | `Bytes ->
4092                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4093                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4094                  pr "    return -1;\n";
4095                  pr "  }\n";
4096              | `Int ->
4097                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4098                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4099                  pr "    return -1;\n";
4100                  pr "  }\n";
4101              | `OptPercent ->
4102                  pr "  if (tok[0] == '\\0')\n";
4103                  pr "    r->%s = -1;\n" name;
4104                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4105                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4106                  pr "    return -1;\n";
4107                  pr "  }\n";
4108             );
4109             pr "  tok = next;\n";
4110         ) cols;
4111
4112         pr "  if (tok != NULL) {\n";
4113         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4114         pr "    return -1;\n";
4115         pr "  }\n";
4116         pr "  return 0;\n";
4117         pr "}\n";
4118         pr "\n";
4119
4120         pr "guestfs_lvm_int_%s_list *\n" typ;
4121         pr "parse_command_line_%ss (void)\n" typ;
4122         pr "{\n";
4123         pr "  char *out, *err;\n";
4124         pr "  char *p, *pend;\n";
4125         pr "  int r, i;\n";
4126         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
4127         pr "  void *newp;\n";
4128         pr "\n";
4129         pr "  ret = malloc (sizeof *ret);\n";
4130         pr "  if (!ret) {\n";
4131         pr "    reply_with_perror (\"malloc\");\n";
4132         pr "    return NULL;\n";
4133         pr "  }\n";
4134         pr "\n";
4135         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
4136         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
4137         pr "\n";
4138         pr "  r = command (&out, &err,\n";
4139         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
4140         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4141         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4142         pr "  if (r == -1) {\n";
4143         pr "    reply_with_error (\"%%s\", err);\n";
4144         pr "    free (out);\n";
4145         pr "    free (err);\n";
4146         pr "    free (ret);\n";
4147         pr "    return NULL;\n";
4148         pr "  }\n";
4149         pr "\n";
4150         pr "  free (err);\n";
4151         pr "\n";
4152         pr "  /* Tokenize each line of the output. */\n";
4153         pr "  p = out;\n";
4154         pr "  i = 0;\n";
4155         pr "  while (p) {\n";
4156         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
4157         pr "    if (pend) {\n";
4158         pr "      *pend = '\\0';\n";
4159         pr "      pend++;\n";
4160         pr "    }\n";
4161         pr "\n";
4162         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
4163         pr "      p++;\n";
4164         pr "\n";
4165         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
4166         pr "      p = pend;\n";
4167         pr "      continue;\n";
4168         pr "    }\n";
4169         pr "\n";
4170         pr "    /* Allocate some space to store this next entry. */\n";
4171         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
4172         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
4173         pr "    if (newp == NULL) {\n";
4174         pr "      reply_with_perror (\"realloc\");\n";
4175         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
4176         pr "      free (ret);\n";
4177         pr "      free (out);\n";
4178         pr "      return NULL;\n";
4179         pr "    }\n";
4180         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
4181         pr "\n";
4182         pr "    /* Tokenize the next entry. */\n";
4183         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
4184         pr "    if (r == -1) {\n";
4185         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
4186         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
4187         pr "      free (ret);\n";
4188         pr "      free (out);\n";
4189         pr "      return NULL;\n";
4190         pr "    }\n";
4191         pr "\n";
4192         pr "    ++i;\n";
4193         pr "    p = pend;\n";
4194         pr "  }\n";
4195         pr "\n";
4196         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
4197         pr "\n";
4198         pr "  free (out);\n";
4199         pr "  return ret;\n";
4200         pr "}\n"
4201
4202   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4203
4204 (* Generate the tests. *)
4205 and generate_tests () =
4206   generate_header CStyle GPLv2;
4207
4208   pr "\
4209 #include <stdio.h>
4210 #include <stdlib.h>
4211 #include <string.h>
4212 #include <unistd.h>
4213 #include <sys/types.h>
4214 #include <fcntl.h>
4215
4216 #include \"guestfs.h\"
4217
4218 static guestfs_h *g;
4219 static int suppress_error = 0;
4220
4221 static void print_error (guestfs_h *g, void *data, const char *msg)
4222 {
4223   if (!suppress_error)
4224     fprintf (stderr, \"%%s\\n\", msg);
4225 }
4226
4227 static void print_strings (char * const * const argv)
4228 {
4229   int argc;
4230
4231   for (argc = 0; argv[argc] != NULL; ++argc)
4232     printf (\"\\t%%s\\n\", argv[argc]);
4233 }
4234
4235 /*
4236 static void print_table (char * const * const argv)
4237 {
4238   int i;
4239
4240   for (i = 0; argv[i] != NULL; i += 2)
4241     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
4242 }
4243 */
4244
4245 static void no_test_warnings (void)
4246 {
4247 ";
4248
4249   List.iter (
4250     function
4251     | name, _, _, _, [], _, _ ->
4252         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
4253     | name, _, _, _, tests, _, _ -> ()
4254   ) all_functions;
4255
4256   pr "}\n";
4257   pr "\n";
4258
4259   (* Generate the actual tests.  Note that we generate the tests
4260    * in reverse order, deliberately, so that (in general) the
4261    * newest tests run first.  This makes it quicker and easier to
4262    * debug them.
4263    *)
4264   let test_names =
4265     List.map (
4266       fun (name, _, _, _, tests, _, _) ->
4267         mapi (generate_one_test name) tests
4268     ) (List.rev all_functions) in
4269   let test_names = List.concat test_names in
4270   let nr_tests = List.length test_names in
4271
4272   pr "\
4273 int main (int argc, char *argv[])
4274 {
4275   char c = 0;
4276   int failed = 0;
4277   const char *filename;
4278   int fd;
4279   int nr_tests, test_num = 0;
4280
4281   no_test_warnings ();
4282
4283   g = guestfs_create ();
4284   if (g == NULL) {
4285     printf (\"guestfs_create FAILED\\n\");
4286     exit (1);
4287   }
4288
4289   guestfs_set_error_handler (g, print_error, NULL);
4290
4291   guestfs_set_path (g, \"../appliance\");
4292
4293   filename = \"test1.img\";
4294   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4295   if (fd == -1) {
4296     perror (filename);
4297     exit (1);
4298   }
4299   if (lseek (fd, %d, SEEK_SET) == -1) {
4300     perror (\"lseek\");
4301     close (fd);
4302     unlink (filename);
4303     exit (1);
4304   }
4305   if (write (fd, &c, 1) == -1) {
4306     perror (\"write\");
4307     close (fd);
4308     unlink (filename);
4309     exit (1);
4310   }
4311   if (close (fd) == -1) {
4312     perror (filename);
4313     unlink (filename);
4314     exit (1);
4315   }
4316   if (guestfs_add_drive (g, filename) == -1) {
4317     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4318     exit (1);
4319   }
4320
4321   filename = \"test2.img\";
4322   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4323   if (fd == -1) {
4324     perror (filename);
4325     exit (1);
4326   }
4327   if (lseek (fd, %d, SEEK_SET) == -1) {
4328     perror (\"lseek\");
4329     close (fd);
4330     unlink (filename);
4331     exit (1);
4332   }
4333   if (write (fd, &c, 1) == -1) {
4334     perror (\"write\");
4335     close (fd);
4336     unlink (filename);
4337     exit (1);
4338   }
4339   if (close (fd) == -1) {
4340     perror (filename);
4341     unlink (filename);
4342     exit (1);
4343   }
4344   if (guestfs_add_drive (g, filename) == -1) {
4345     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4346     exit (1);
4347   }
4348
4349   filename = \"test3.img\";
4350   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4351   if (fd == -1) {
4352     perror (filename);
4353     exit (1);
4354   }
4355   if (lseek (fd, %d, SEEK_SET) == -1) {
4356     perror (\"lseek\");
4357     close (fd);
4358     unlink (filename);
4359     exit (1);
4360   }
4361   if (write (fd, &c, 1) == -1) {
4362     perror (\"write\");
4363     close (fd);
4364     unlink (filename);
4365     exit (1);
4366   }
4367   if (close (fd) == -1) {
4368     perror (filename);
4369     unlink (filename);
4370     exit (1);
4371   }
4372   if (guestfs_add_drive (g, filename) == -1) {
4373     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4374     exit (1);
4375   }
4376
4377   if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4378     printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4379     exit (1);
4380   }
4381
4382   if (guestfs_launch (g) == -1) {
4383     printf (\"guestfs_launch FAILED\\n\");
4384     exit (1);
4385   }
4386
4387   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4388   alarm (600);
4389
4390   if (guestfs_wait_ready (g) == -1) {
4391     printf (\"guestfs_wait_ready FAILED\\n\");
4392     exit (1);
4393   }
4394
4395   /* Cancel previous alarm. */
4396   alarm (0);
4397
4398   nr_tests = %d;
4399
4400 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4401
4402   iteri (
4403     fun i test_name ->
4404       pr "  test_num++;\n";
4405       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4406       pr "  if (%s () == -1) {\n" test_name;
4407       pr "    printf (\"%s FAILED\\n\");\n" test_name;
4408       pr "    failed++;\n";
4409       pr "  }\n";
4410   ) test_names;
4411   pr "\n";
4412
4413   pr "  guestfs_close (g);\n";
4414   pr "  unlink (\"test1.img\");\n";
4415   pr "  unlink (\"test2.img\");\n";
4416   pr "  unlink (\"test3.img\");\n";
4417   pr "\n";
4418
4419   pr "  if (failed > 0) {\n";
4420   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4421   pr "    exit (1);\n";
4422   pr "  }\n";
4423   pr "\n";
4424
4425   pr "  exit (0);\n";
4426   pr "}\n"
4427
4428 and generate_one_test name i (init, prereq, test) =
4429   let test_name = sprintf "test_%s_%d" name i in
4430
4431   pr "\
4432 static int %s_skip (void)
4433 {
4434   const char *str;
4435
4436   str = getenv (\"TEST_ONLY\");
4437   if (str)
4438     return strstr (str, \"%s\") == NULL;
4439   str = getenv (\"SKIP_%s\");
4440   if (str && strcmp (str, \"1\") == 0) return 1;
4441   str = getenv (\"SKIP_TEST_%s\");
4442   if (str && strcmp (str, \"1\") == 0) return 1;
4443   return 0;
4444 }
4445
4446 " test_name name (String.uppercase test_name) (String.uppercase name);
4447
4448   (match prereq with
4449    | Disabled | Always -> ()
4450    | If code | Unless code ->
4451        pr "static int %s_prereq (void)\n" test_name;
4452        pr "{\n";
4453        pr "  %s\n" code;
4454        pr "}\n";
4455        pr "\n";
4456   );
4457
4458   pr "\
4459 static int %s (void)
4460 {
4461   if (%s_skip ()) {
4462     printf (\"%%s skipped (reason: environment variable set)\\n\", \"%s\");
4463     return 0;
4464   }
4465
4466 " test_name test_name test_name;
4467
4468   (match prereq with
4469    | Disabled ->
4470        pr "  printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4471    | If _ ->
4472        pr "  if (! %s_prereq ()) {\n" test_name;
4473        pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4474        pr "    return 0;\n";
4475        pr "  }\n";
4476        pr "\n";
4477        generate_one_test_body name i test_name init test;
4478    | Unless _ ->
4479        pr "  if (%s_prereq ()) {\n" test_name;
4480        pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4481        pr "    return 0;\n";
4482        pr "  }\n";
4483        pr "\n";
4484        generate_one_test_body name i test_name init test;
4485    | Always ->
4486        generate_one_test_body name i test_name init test
4487   );
4488
4489   pr "  return 0;\n";
4490   pr "}\n";
4491   pr "\n";
4492   test_name
4493
4494 and generate_one_test_body name i test_name init test =
4495   (match init with
4496    | InitNone
4497    | InitEmpty ->
4498        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
4499        List.iter (generate_test_command_call test_name)
4500          [["blockdev_setrw"; "/dev/sda"];
4501           ["umount_all"];
4502           ["lvm_remove_all"]]
4503    | InitBasicFS ->
4504        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4505        List.iter (generate_test_command_call test_name)
4506          [["blockdev_setrw"; "/dev/sda"];
4507           ["umount_all"];
4508           ["lvm_remove_all"];
4509           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4510           ["mkfs"; "ext2"; "/dev/sda1"];
4511           ["mount"; "/dev/sda1"; "/"]]
4512    | InitBasicFSonLVM ->
4513        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4514          test_name;
4515        List.iter (generate_test_command_call test_name)
4516          [["blockdev_setrw"; "/dev/sda"];
4517           ["umount_all"];
4518           ["lvm_remove_all"];
4519           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
4520           ["pvcreate"; "/dev/sda1"];
4521           ["vgcreate"; "VG"; "/dev/sda1"];
4522           ["lvcreate"; "LV"; "VG"; "8"];
4523           ["mkfs"; "ext2"; "/dev/VG/LV"];
4524           ["mount"; "/dev/VG/LV"; "/"]]
4525   );
4526
4527   let get_seq_last = function
4528     | [] ->
4529         failwithf "%s: you cannot use [] (empty list) when expecting a command"
4530           test_name
4531     | seq ->
4532         let seq = List.rev seq in
4533         List.rev (List.tl seq), List.hd seq
4534   in
4535
4536   match test with
4537   | TestRun seq ->
4538       pr "  /* TestRun for %s (%d) */\n" name i;
4539       List.iter (generate_test_command_call test_name) seq
4540   | TestOutput (seq, expected) ->
4541       pr "  /* TestOutput for %s (%d) */\n" name i;
4542       pr "  char expected[] = \"%s\";\n" (c_quote expected);
4543       let seq, last = get_seq_last seq in
4544       let test () =
4545         pr "    if (strcmp (r, expected) != 0) {\n";
4546         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4547         pr "      return -1;\n";
4548         pr "    }\n"
4549       in
4550       List.iter (generate_test_command_call test_name) seq;
4551       generate_test_command_call ~test test_name last
4552   | TestOutputList (seq, expected) ->
4553       pr "  /* TestOutputList for %s (%d) */\n" name i;
4554       let seq, last = get_seq_last seq in
4555       let test () =
4556         iteri (
4557           fun i str ->
4558             pr "    if (!r[%d]) {\n" i;
4559             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4560             pr "      print_strings (r);\n";
4561             pr "      return -1;\n";
4562             pr "    }\n";
4563             pr "    {\n";
4564             pr "      char expected[] = \"%s\";\n" (c_quote str);
4565             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
4566             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4567             pr "        return -1;\n";
4568             pr "      }\n";
4569             pr "    }\n"
4570         ) expected;
4571         pr "    if (r[%d] != NULL) {\n" (List.length expected);
4572         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4573           test_name;
4574         pr "      print_strings (r);\n";
4575         pr "      return -1;\n";
4576         pr "    }\n"
4577       in
4578       List.iter (generate_test_command_call test_name) seq;
4579       generate_test_command_call ~test test_name last
4580   | TestOutputListOfDevices (seq, expected) ->
4581       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
4582       let seq, last = get_seq_last seq in
4583       let test () =
4584         iteri (
4585           fun i str ->
4586             pr "    if (!r[%d]) {\n" i;
4587             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4588             pr "      print_strings (r);\n";
4589             pr "      return -1;\n";
4590             pr "    }\n";
4591             pr "    {\n";
4592             pr "      char expected[] = \"%s\";\n" (c_quote str);
4593             pr "      r[%d][5] = 's';\n" i;
4594             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
4595             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4596             pr "        return -1;\n";
4597             pr "      }\n";
4598             pr "    }\n"
4599         ) expected;
4600         pr "    if (r[%d] != NULL) {\n" (List.length expected);
4601         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4602           test_name;
4603         pr "      print_strings (r);\n";
4604         pr "      return -1;\n";
4605         pr "    }\n"
4606       in
4607       List.iter (generate_test_command_call test_name) seq;
4608       generate_test_command_call ~test test_name last
4609   | TestOutputInt (seq, expected) ->
4610       pr "  /* TestOutputInt for %s (%d) */\n" name i;
4611       let seq, last = get_seq_last seq in
4612       let test () =
4613         pr "    if (r != %d) {\n" expected;
4614         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
4615           test_name expected;
4616         pr "               (int) r);\n";
4617         pr "      return -1;\n";
4618         pr "    }\n"
4619       in
4620       List.iter (generate_test_command_call test_name) seq;
4621       generate_test_command_call ~test test_name last
4622   | TestOutputTrue seq ->
4623       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
4624       let seq, last = get_seq_last seq in
4625       let test () =
4626         pr "    if (!r) {\n";
4627         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
4628           test_name;
4629         pr "      return -1;\n";
4630         pr "    }\n"
4631       in
4632       List.iter (generate_test_command_call test_name) seq;
4633       generate_test_command_call ~test test_name last
4634   | TestOutputFalse seq ->
4635       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
4636       let seq, last = get_seq_last seq in
4637       let test () =
4638         pr "    if (r) {\n";
4639         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
4640           test_name;
4641         pr "      return -1;\n";
4642         pr "    }\n"
4643       in
4644       List.iter (generate_test_command_call test_name) seq;
4645       generate_test_command_call ~test test_name last
4646   | TestOutputLength (seq, expected) ->
4647       pr "  /* TestOutputLength for %s (%d) */\n" name i;
4648       let seq, last = get_seq_last seq in
4649       let test () =
4650         pr "    int j;\n";
4651         pr "    for (j = 0; j < %d; ++j)\n" expected;
4652         pr "      if (r[j] == NULL) {\n";
4653         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
4654           test_name;
4655         pr "        print_strings (r);\n";
4656         pr "        return -1;\n";
4657         pr "      }\n";
4658         pr "    if (r[j] != NULL) {\n";
4659         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
4660           test_name;
4661         pr "      print_strings (r);\n";
4662         pr "      return -1;\n";
4663         pr "    }\n"
4664       in
4665       List.iter (generate_test_command_call test_name) seq;
4666       generate_test_command_call ~test test_name last
4667   | TestOutputStruct (seq, checks) ->
4668       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
4669       let seq, last = get_seq_last seq in
4670       let test () =
4671         List.iter (
4672           function
4673           | CompareWithInt (field, expected) ->
4674               pr "    if (r->%s != %d) {\n" field expected;
4675               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
4676                 test_name field expected;
4677               pr "               (int) r->%s);\n" field;
4678               pr "      return -1;\n";
4679               pr "    }\n"
4680           | CompareWithString (field, expected) ->
4681               pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
4682               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
4683                 test_name field expected;
4684               pr "               r->%s);\n" field;
4685               pr "      return -1;\n";
4686               pr "    }\n"
4687           | CompareFieldsIntEq (field1, field2) ->
4688               pr "    if (r->%s != r->%s) {\n" field1 field2;
4689               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
4690                 test_name field1 field2;
4691               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
4692               pr "      return -1;\n";
4693               pr "    }\n"
4694           | CompareFieldsStrEq (field1, field2) ->
4695               pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
4696               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
4697                 test_name field1 field2;
4698               pr "               r->%s, r->%s);\n" field1 field2;
4699               pr "      return -1;\n";
4700               pr "    }\n"
4701         ) checks
4702       in
4703       List.iter (generate_test_command_call test_name) seq;
4704       generate_test_command_call ~test test_name last
4705   | TestLastFail seq ->
4706       pr "  /* TestLastFail for %s (%d) */\n" name i;
4707       let seq, last = get_seq_last seq in
4708       List.iter (generate_test_command_call test_name) seq;
4709       generate_test_command_call test_name ~expect_error:true last
4710
4711 (* Generate the code to run a command, leaving the result in 'r'.
4712  * If you expect to get an error then you should set expect_error:true.
4713  *)
4714 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
4715   match cmd with
4716   | [] -> assert false
4717   | name :: args ->
4718       (* Look up the command to find out what args/ret it has. *)
4719       let style =
4720         try
4721           let _, style, _, _, _, _, _ =
4722             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
4723           style
4724         with Not_found ->
4725           failwithf "%s: in test, command %s was not found" test_name name in
4726
4727       if List.length (snd style) <> List.length args then
4728         failwithf "%s: in test, wrong number of args given to %s"
4729           test_name name;
4730
4731       pr "  {\n";
4732
4733       List.iter (
4734         function
4735         | OptString n, "NULL" -> ()
4736         | String n, arg
4737         | OptString n, arg ->
4738             pr "    char %s[] = \"%s\";\n" n (c_quote arg);
4739         | Int _, _
4740         | Bool _, _
4741         | FileIn _, _ | FileOut _, _ -> ()
4742         | StringList n, arg ->
4743             let strs = string_split " " arg in
4744             iteri (
4745               fun i str ->
4746                 pr "    char %s_%d[] = \"%s\";\n" n i (c_quote str);
4747             ) strs;
4748             pr "    char *%s[] = {\n" n;
4749             iteri (
4750               fun i _ -> pr "      %s_%d,\n" n i
4751             ) strs;
4752             pr "      NULL\n";
4753             pr "    };\n";
4754       ) (List.combine (snd style) args);
4755
4756       let error_code =
4757         match fst style with
4758         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
4759         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
4760         | RConstString _ -> pr "    const char *r;\n"; "NULL"
4761         | RString _ -> pr "    char *r;\n"; "NULL"
4762         | RStringList _ | RHashtable _ ->
4763             pr "    char **r;\n";
4764             pr "    int i;\n";
4765             "NULL"
4766         | RIntBool _ ->
4767             pr "    struct guestfs_int_bool *r;\n"; "NULL"
4768         | RPVList _ ->
4769             pr "    struct guestfs_lvm_pv_list *r;\n"; "NULL"
4770         | RVGList _ ->
4771             pr "    struct guestfs_lvm_vg_list *r;\n"; "NULL"
4772         | RLVList _ ->
4773             pr "    struct guestfs_lvm_lv_list *r;\n"; "NULL"
4774         | RStat _ ->
4775             pr "    struct guestfs_stat *r;\n"; "NULL"
4776         | RStatVFS _ ->
4777             pr "    struct guestfs_statvfs *r;\n"; "NULL" in
4778
4779       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
4780       pr "    r = guestfs_%s (g" name;
4781
4782       (* Generate the parameters. *)
4783       List.iter (
4784         function
4785         | OptString _, "NULL" -> pr ", NULL"
4786         | String n, _
4787         | OptString n, _ ->
4788             pr ", %s" n
4789         | FileIn _, arg | FileOut _, arg ->
4790             pr ", \"%s\"" (c_quote arg)
4791         | StringList n, _ ->
4792             pr ", %s" n
4793         | Int _, arg ->
4794             let i =
4795               try int_of_string arg
4796               with Failure "int_of_string" ->
4797                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
4798             pr ", %d" i
4799         | Bool _, arg ->
4800             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
4801       ) (List.combine (snd style) args);
4802
4803       pr ");\n";
4804       if not expect_error then
4805         pr "    if (r == %s)\n" error_code
4806       else
4807         pr "    if (r != %s)\n" error_code;
4808       pr "      return -1;\n";
4809
4810       (* Insert the test code. *)
4811       (match test with
4812        | None -> ()
4813        | Some f -> f ()
4814       );
4815
4816       (match fst style with
4817        | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
4818        | RString _ -> pr "    free (r);\n"
4819        | RStringList _ | RHashtable _ ->
4820            pr "    for (i = 0; r[i] != NULL; ++i)\n";
4821            pr "      free (r[i]);\n";
4822            pr "    free (r);\n"
4823        | RIntBool _ ->
4824            pr "    guestfs_free_int_bool (r);\n"
4825        | RPVList _ ->
4826            pr "    guestfs_free_lvm_pv_list (r);\n"
4827        | RVGList _ ->
4828            pr "    guestfs_free_lvm_vg_list (r);\n"
4829        | RLVList _ ->
4830            pr "    guestfs_free_lvm_lv_list (r);\n"
4831        | RStat _ | RStatVFS _ ->
4832            pr "    free (r);\n"
4833       );
4834
4835       pr "  }\n"
4836
4837 and c_quote str =
4838   let str = replace_str str "\r" "\\r" in
4839   let str = replace_str str "\n" "\\n" in
4840   let str = replace_str str "\t" "\\t" in
4841   let str = replace_str str "\000" "\\0" in
4842   str
4843
4844 (* Generate a lot of different functions for guestfish. *)
4845 and generate_fish_cmds () =
4846   generate_header CStyle GPLv2;
4847
4848   let all_functions =
4849     List.filter (
4850       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4851     ) all_functions in
4852   let all_functions_sorted =
4853     List.filter (
4854       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
4855     ) all_functions_sorted in
4856
4857   pr "#include <stdio.h>\n";
4858   pr "#include <stdlib.h>\n";
4859   pr "#include <string.h>\n";
4860   pr "#include <inttypes.h>\n";
4861   pr "\n";
4862   pr "#include <guestfs.h>\n";
4863   pr "#include \"fish.h\"\n";
4864   pr "\n";
4865
4866   (* list_commands function, which implements guestfish -h *)
4867   pr "void list_commands (void)\n";
4868   pr "{\n";
4869   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
4870   pr "  list_builtin_commands ();\n";
4871   List.iter (
4872     fun (name, _, _, flags, _, shortdesc, _) ->
4873       let name = replace_char name '_' '-' in
4874       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
4875         name shortdesc
4876   ) all_functions_sorted;
4877   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
4878   pr "}\n";
4879   pr "\n";
4880
4881   (* display_command function, which implements guestfish -h cmd *)
4882   pr "void display_command (const char *cmd)\n";
4883   pr "{\n";
4884   List.iter (
4885     fun (name, style, _, flags, _, shortdesc, longdesc) ->
4886       let name2 = replace_char name '_' '-' in
4887       let alias =
4888         try find_map (function FishAlias n -> Some n | _ -> None) flags
4889         with Not_found -> name in
4890       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
4891       let synopsis =
4892         match snd style with
4893         | [] -> name2
4894         | args ->
4895             sprintf "%s <%s>"
4896               name2 (String.concat "> <" (List.map name_of_argt args)) in
4897
4898       let warnings =
4899         if List.mem ProtocolLimitWarning flags then
4900           ("\n\n" ^ protocol_limit_warning)
4901         else "" in
4902
4903       (* For DangerWillRobinson commands, we should probably have
4904        * guestfish prompt before allowing you to use them (especially
4905        * in interactive mode). XXX
4906        *)
4907       let warnings =
4908         warnings ^
4909           if List.mem DangerWillRobinson flags then
4910             ("\n\n" ^ danger_will_robinson)
4911           else "" in
4912
4913       let describe_alias =
4914         if name <> alias then
4915           sprintf "\n\nYou can use '%s' as an alias for this command." alias
4916         else "" in
4917
4918       pr "  if (";
4919       pr "strcasecmp (cmd, \"%s\") == 0" name;
4920       if name <> name2 then
4921         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
4922       if name <> alias then
4923         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
4924       pr ")\n";
4925       pr "    pod2text (\"%s - %s\", %S);\n"
4926         name2 shortdesc
4927         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
4928       pr "  else\n"
4929   ) all_functions;
4930   pr "    display_builtin_command (cmd);\n";
4931   pr "}\n";
4932   pr "\n";
4933
4934   (* print_{pv,vg,lv}_list functions *)
4935   List.iter (
4936     function
4937     | typ, cols ->
4938         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4939         pr "{\n";
4940         pr "  int i;\n";
4941         pr "\n";
4942         List.iter (
4943           function
4944           | name, `String ->
4945               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
4946           | name, `UUID ->
4947               pr "  printf (\"%s: \");\n" name;
4948               pr "  for (i = 0; i < 32; ++i)\n";
4949               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
4950               pr "  printf (\"\\n\");\n"
4951           | name, `Bytes ->
4952               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
4953           | name, `Int ->
4954               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4955           | name, `OptPercent ->
4956               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
4957                 typ name name typ name;
4958               pr "  else printf (\"%s: \\n\");\n" name
4959         ) cols;
4960         pr "}\n";
4961         pr "\n";
4962         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
4963           typ typ typ;
4964         pr "{\n";
4965         pr "  int i;\n";
4966         pr "\n";
4967         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
4968         pr "    print_%s (&%ss->val[i]);\n" typ typ;
4969         pr "}\n";
4970         pr "\n";
4971   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4972
4973   (* print_{stat,statvfs} functions *)
4974   List.iter (
4975     function
4976     | typ, cols ->
4977         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
4978         pr "{\n";
4979         List.iter (
4980           function
4981           | name, `Int ->
4982               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
4983         ) cols;
4984         pr "}\n";
4985         pr "\n";
4986   ) ["stat", stat_cols; "statvfs", statvfs_cols];
4987
4988   (* run_<action> actions *)
4989   List.iter (
4990     fun (name, style, _, flags, _, _, _) ->
4991       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
4992       pr "{\n";
4993       (match fst style with
4994        | RErr
4995        | RInt _
4996        | RBool _ -> pr "  int r;\n"
4997        | RInt64 _ -> pr "  int64_t r;\n"
4998        | RConstString _ -> pr "  const char *r;\n"
4999        | RString _ -> pr "  char *r;\n"
5000        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
5001        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
5002        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
5003        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
5004        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
5005        | RStat _ -> pr "  struct guestfs_stat *r;\n"
5006        | RStatVFS _ -> pr "  struct guestfs_statvfs *r;\n"
5007       );
5008       List.iter (
5009         function
5010         | String n
5011         | OptString n
5012         | FileIn n
5013         | FileOut n -> pr "  const char *%s;\n" n
5014         | StringList n -> pr "  char **%s;\n" n
5015         | Bool n -> pr "  int %s;\n" n
5016         | Int n -> pr "  int %s;\n" n
5017       ) (snd style);
5018
5019       (* Check and convert parameters. *)
5020       let argc_expected = List.length (snd style) in
5021       pr "  if (argc != %d) {\n" argc_expected;
5022       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
5023         argc_expected;
5024       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
5025       pr "    return -1;\n";
5026       pr "  }\n";
5027       iteri (
5028         fun i ->
5029           function
5030           | String name -> pr "  %s = argv[%d];\n" name i
5031           | OptString name ->
5032               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5033                 name i i
5034           | FileIn name ->
5035               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5036                 name i i
5037           | FileOut name ->
5038               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5039                 name i i
5040           | StringList name ->
5041               pr "  %s = parse_string_list (argv[%d]);\n" name i
5042           | Bool name ->
5043               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5044           | Int name ->
5045               pr "  %s = atoi (argv[%d]);\n" name i
5046       ) (snd style);
5047
5048       (* Call C API function. *)
5049       let fn =
5050         try find_map (function FishAction n -> Some n | _ -> None) flags
5051         with Not_found -> sprintf "guestfs_%s" name in
5052       pr "  r = %s " fn;
5053       generate_call_args ~handle:"g" (snd style);
5054       pr ";\n";
5055
5056       (* Check return value for errors and display command results. *)
5057       (match fst style with
5058        | RErr -> pr "  return r;\n"
5059        | RInt _ ->
5060            pr "  if (r == -1) return -1;\n";
5061            pr "  printf (\"%%d\\n\", r);\n";
5062            pr "  return 0;\n"
5063        | RInt64 _ ->
5064            pr "  if (r == -1) return -1;\n";
5065            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
5066            pr "  return 0;\n"
5067        | RBool _ ->
5068            pr "  if (r == -1) return -1;\n";
5069            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
5070            pr "  return 0;\n"
5071        | RConstString _ ->
5072            pr "  if (r == NULL) return -1;\n";
5073            pr "  printf (\"%%s\\n\", r);\n";
5074            pr "  return 0;\n"
5075        | RString _ ->
5076            pr "  if (r == NULL) return -1;\n";
5077            pr "  printf (\"%%s\\n\", r);\n";
5078            pr "  free (r);\n";
5079            pr "  return 0;\n"
5080        | RStringList _ ->
5081            pr "  if (r == NULL) return -1;\n";
5082            pr "  print_strings (r);\n";
5083            pr "  free_strings (r);\n";
5084            pr "  return 0;\n"
5085        | RIntBool _ ->
5086            pr "  if (r == NULL) return -1;\n";
5087            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
5088            pr "    r->b ? \"true\" : \"false\");\n";
5089            pr "  guestfs_free_int_bool (r);\n";
5090            pr "  return 0;\n"
5091        | RPVList _ ->
5092            pr "  if (r == NULL) return -1;\n";
5093            pr "  print_pv_list (r);\n";
5094            pr "  guestfs_free_lvm_pv_list (r);\n";
5095            pr "  return 0;\n"
5096        | RVGList _ ->
5097            pr "  if (r == NULL) return -1;\n";
5098            pr "  print_vg_list (r);\n";
5099            pr "  guestfs_free_lvm_vg_list (r);\n";
5100            pr "  return 0;\n"
5101        | RLVList _ ->
5102            pr "  if (r == NULL) return -1;\n";
5103            pr "  print_lv_list (r);\n";
5104            pr "  guestfs_free_lvm_lv_list (r);\n";
5105            pr "  return 0;\n"
5106        | RStat _ ->
5107            pr "  if (r == NULL) return -1;\n";
5108            pr "  print_stat (r);\n";
5109            pr "  free (r);\n";
5110            pr "  return 0;\n"
5111        | RStatVFS _ ->
5112            pr "  if (r == NULL) return -1;\n";
5113            pr "  print_statvfs (r);\n";
5114            pr "  free (r);\n";
5115            pr "  return 0;\n"
5116        | RHashtable _ ->
5117            pr "  if (r == NULL) return -1;\n";
5118            pr "  print_table (r);\n";
5119            pr "  free_strings (r);\n";
5120            pr "  return 0;\n"
5121       );
5122       pr "}\n";
5123       pr "\n"
5124   ) all_functions;
5125
5126   (* run_action function *)
5127   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
5128   pr "{\n";
5129   List.iter (
5130     fun (name, _, _, flags, _, _, _) ->
5131       let name2 = replace_char name '_' '-' in
5132       let alias =
5133         try find_map (function FishAlias n -> Some n | _ -> None) flags
5134         with Not_found -> name in
5135       pr "  if (";
5136       pr "strcasecmp (cmd, \"%s\") == 0" name;
5137       if name <> name2 then
5138         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5139       if name <> alias then
5140         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5141       pr ")\n";
5142       pr "    return run_%s (cmd, argc, argv);\n" name;
5143       pr "  else\n";
5144   ) all_functions;
5145   pr "    {\n";
5146   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
5147   pr "      return -1;\n";
5148   pr "    }\n";
5149   pr "  return 0;\n";
5150   pr "}\n";
5151   pr "\n"
5152
5153 (* Readline completion for guestfish. *)
5154 and generate_fish_completion () =
5155   generate_header CStyle GPLv2;
5156
5157   let all_functions =
5158     List.filter (
5159       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5160     ) all_functions in
5161
5162   pr "\
5163 #include <config.h>
5164
5165 #include <stdio.h>
5166 #include <stdlib.h>
5167 #include <string.h>
5168
5169 #ifdef HAVE_LIBREADLINE
5170 #include <readline/readline.h>
5171 #endif
5172
5173 #include \"fish.h\"
5174
5175 #ifdef HAVE_LIBREADLINE
5176
5177 static const char *const commands[] = {
5178   BUILTIN_COMMANDS_FOR_COMPLETION,
5179 ";
5180
5181   (* Get the commands, including the aliases.  They don't need to be
5182    * sorted - the generator() function just does a dumb linear search.
5183    *)
5184   let commands =
5185     List.map (
5186       fun (name, _, _, flags, _, _, _) ->
5187         let name2 = replace_char name '_' '-' in
5188         let alias =
5189           try find_map (function FishAlias n -> Some n | _ -> None) flags
5190           with Not_found -> name in
5191
5192         if name <> alias then [name2; alias] else [name2]
5193     ) all_functions in
5194   let commands = List.flatten commands in
5195
5196   List.iter (pr "  \"%s\",\n") commands;
5197
5198   pr "  NULL
5199 };
5200
5201 static char *
5202 generator (const char *text, int state)
5203 {
5204   static int index, len;
5205   const char *name;
5206
5207   if (!state) {
5208     index = 0;
5209     len = strlen (text);
5210   }
5211
5212   rl_attempted_completion_over = 1;
5213
5214   while ((name = commands[index]) != NULL) {
5215     index++;
5216     if (strncasecmp (name, text, len) == 0)
5217       return strdup (name);
5218   }
5219
5220   return NULL;
5221 }
5222
5223 #endif /* HAVE_LIBREADLINE */
5224
5225 char **do_completion (const char *text, int start, int end)
5226 {
5227   char **matches = NULL;
5228
5229 #ifdef HAVE_LIBREADLINE
5230   rl_completion_append_character = ' ';
5231
5232   if (start == 0)
5233     matches = rl_completion_matches (text, generator);
5234   else if (complete_dest_paths)
5235     matches = rl_completion_matches (text, complete_dest_paths_generator);
5236 #endif
5237
5238   return matches;
5239 }
5240 ";
5241
5242 (* Generate the POD documentation for guestfish. *)
5243 and generate_fish_actions_pod () =
5244   let all_functions_sorted =
5245     List.filter (
5246       fun (_, _, _, flags, _, _, _) ->
5247         not (List.mem NotInFish flags || List.mem NotInDocs flags)
5248     ) all_functions_sorted in
5249
5250   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
5251
5252   List.iter (
5253     fun (name, style, _, flags, _, _, longdesc) ->
5254       let longdesc =
5255         Str.global_substitute rex (
5256           fun s ->
5257             let sub =
5258               try Str.matched_group 1 s
5259               with Not_found ->
5260                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
5261             "C<" ^ replace_char sub '_' '-' ^ ">"
5262         ) longdesc in
5263       let name = replace_char name '_' '-' in
5264       let alias =
5265         try find_map (function FishAlias n -> Some n | _ -> None) flags
5266         with Not_found -> name in
5267
5268       pr "=head2 %s" name;
5269       if name <> alias then
5270         pr " | %s" alias;
5271       pr "\n";
5272       pr "\n";
5273       pr " %s" name;
5274       List.iter (
5275         function
5276         | String n -> pr " %s" n
5277         | OptString n -> pr " %s" n
5278         | StringList n -> pr " '%s ...'" n
5279         | Bool _ -> pr " true|false"
5280         | Int n -> pr " %s" n
5281         | FileIn n | FileOut n -> pr " (%s|-)" n
5282       ) (snd style);
5283       pr "\n";
5284       pr "\n";
5285       pr "%s\n\n" longdesc;
5286
5287       if List.exists (function FileIn _ | FileOut _ -> true
5288                       | _ -> false) (snd style) then
5289         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5290
5291       if List.mem ProtocolLimitWarning flags then
5292         pr "%s\n\n" protocol_limit_warning;
5293
5294       if List.mem DangerWillRobinson flags then
5295         pr "%s\n\n" danger_will_robinson
5296   ) all_functions_sorted
5297
5298 (* Generate a C function prototype. *)
5299 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5300     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5301     ?(prefix = "")
5302     ?handle name style =
5303   if extern then pr "extern ";
5304   if static then pr "static ";
5305   (match fst style with
5306    | RErr -> pr "int "
5307    | RInt _ -> pr "int "
5308    | RInt64 _ -> pr "int64_t "
5309    | RBool _ -> pr "int "
5310    | RConstString _ -> pr "const char *"
5311    | RString _ -> pr "char *"
5312    | RStringList _ | RHashtable _ -> pr "char **"
5313    | RIntBool _ ->
5314        if not in_daemon then pr "struct guestfs_int_bool *"
5315        else pr "guestfs_%s_ret *" name
5316    | RPVList _ ->
5317        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
5318        else pr "guestfs_lvm_int_pv_list *"
5319    | RVGList _ ->
5320        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
5321        else pr "guestfs_lvm_int_vg_list *"
5322    | RLVList _ ->
5323        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
5324        else pr "guestfs_lvm_int_lv_list *"
5325    | RStat _ ->
5326        if not in_daemon then pr "struct guestfs_stat *"
5327        else pr "guestfs_int_stat *"
5328    | RStatVFS _ ->
5329        if not in_daemon then pr "struct guestfs_statvfs *"
5330        else pr "guestfs_int_statvfs *"
5331   );
5332   pr "%s%s (" prefix name;
5333   if handle = None && List.length (snd style) = 0 then
5334     pr "void"
5335   else (
5336     let comma = ref false in
5337     (match handle with
5338      | None -> ()
5339      | Some handle -> pr "guestfs_h *%s" handle; comma := true
5340     );
5341     let next () =
5342       if !comma then (
5343         if single_line then pr ", " else pr ",\n\t\t"
5344       );
5345       comma := true
5346     in
5347     List.iter (
5348       function
5349       | String n
5350       | OptString n ->
5351           next ();
5352           if not in_daemon then pr "const char *%s" n
5353           else pr "char *%s" n
5354       | StringList n ->
5355           next ();
5356           if not in_daemon then pr "char * const* const %s" n
5357           else pr "char **%s" n
5358       | Bool n -> next (); pr "int %s" n
5359       | Int n -> next (); pr "int %s" n
5360       | FileIn n
5361       | FileOut n ->
5362           if not in_daemon then (next (); pr "const char *%s" n)
5363     ) (snd style);
5364   );
5365   pr ")";
5366   if semicolon then pr ";";
5367   if newline then pr "\n"
5368
5369 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5370 and generate_call_args ?handle args =
5371   pr "(";
5372   let comma = ref false in
5373   (match handle with
5374    | None -> ()
5375    | Some handle -> pr "%s" handle; comma := true
5376   );
5377   List.iter (
5378     fun arg ->
5379       if !comma then pr ", ";
5380       comma := true;
5381       pr "%s" (name_of_argt arg)
5382   ) args;
5383   pr ")"
5384
5385 (* Generate the OCaml bindings interface. *)
5386 and generate_ocaml_mli () =
5387   generate_header OCamlStyle LGPLv2;
5388
5389   pr "\
5390 (** For API documentation you should refer to the C API
5391     in the guestfs(3) manual page.  The OCaml API uses almost
5392     exactly the same calls. *)
5393
5394 type t
5395 (** A [guestfs_h] handle. *)
5396
5397 exception Error of string
5398 (** This exception is raised when there is an error. *)
5399
5400 val create : unit -> t
5401
5402 val close : t -> unit
5403 (** Handles are closed by the garbage collector when they become
5404     unreferenced, but callers can also call this in order to
5405     provide predictable cleanup. *)
5406
5407 ";
5408   generate_ocaml_lvm_structure_decls ();
5409
5410   generate_ocaml_stat_structure_decls ();
5411
5412   (* The actions. *)
5413   List.iter (
5414     fun (name, style, _, _, _, shortdesc, _) ->
5415       generate_ocaml_prototype name style;
5416       pr "(** %s *)\n" shortdesc;
5417       pr "\n"
5418   ) all_functions
5419
5420 (* Generate the OCaml bindings implementation. *)
5421 and generate_ocaml_ml () =
5422   generate_header OCamlStyle LGPLv2;
5423
5424   pr "\
5425 type t
5426 exception Error of string
5427 external create : unit -> t = \"ocaml_guestfs_create\"
5428 external close : t -> unit = \"ocaml_guestfs_close\"
5429
5430 let () =
5431   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
5432
5433 ";
5434
5435   generate_ocaml_lvm_structure_decls ();
5436
5437   generate_ocaml_stat_structure_decls ();
5438
5439   (* The actions. *)
5440   List.iter (
5441     fun (name, style, _, _, _, shortdesc, _) ->
5442       generate_ocaml_prototype ~is_external:true name style;
5443   ) all_functions
5444
5445 (* Generate the OCaml bindings C implementation. *)
5446 and generate_ocaml_c () =
5447   generate_header CStyle LGPLv2;
5448
5449   pr "\
5450 #include <stdio.h>
5451 #include <stdlib.h>
5452 #include <string.h>
5453
5454 #include <caml/config.h>
5455 #include <caml/alloc.h>
5456 #include <caml/callback.h>
5457 #include <caml/fail.h>
5458 #include <caml/memory.h>
5459 #include <caml/mlvalues.h>
5460 #include <caml/signals.h>
5461
5462 #include <guestfs.h>
5463
5464 #include \"guestfs_c.h\"
5465
5466 /* Copy a hashtable of string pairs into an assoc-list.  We return
5467  * the list in reverse order, but hashtables aren't supposed to be
5468  * ordered anyway.
5469  */
5470 static CAMLprim value
5471 copy_table (char * const * argv)
5472 {
5473   CAMLparam0 ();
5474   CAMLlocal5 (rv, pairv, kv, vv, cons);
5475   int i;
5476
5477   rv = Val_int (0);
5478   for (i = 0; argv[i] != NULL; i += 2) {
5479     kv = caml_copy_string (argv[i]);
5480     vv = caml_copy_string (argv[i+1]);
5481     pairv = caml_alloc (2, 0);
5482     Store_field (pairv, 0, kv);
5483     Store_field (pairv, 1, vv);
5484     cons = caml_alloc (2, 0);
5485     Store_field (cons, 1, rv);
5486     rv = cons;
5487     Store_field (cons, 0, pairv);
5488   }
5489
5490   CAMLreturn (rv);
5491 }
5492
5493 ";
5494
5495   (* LVM struct copy functions. *)
5496   List.iter (
5497     fun (typ, cols) ->
5498       let has_optpercent_col =
5499         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
5500
5501       pr "static CAMLprim value\n";
5502       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
5503       pr "{\n";
5504       pr "  CAMLparam0 ();\n";
5505       if has_optpercent_col then
5506         pr "  CAMLlocal3 (rv, v, v2);\n"
5507       else
5508         pr "  CAMLlocal2 (rv, v);\n";
5509       pr "\n";
5510       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
5511       iteri (
5512         fun i col ->
5513           (match col with
5514            | name, `String ->
5515                pr "  v = caml_copy_string (%s->%s);\n" typ name
5516            | name, `UUID ->
5517                pr "  v = caml_alloc_string (32);\n";
5518                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
5519            | name, `Bytes
5520            | name, `Int ->
5521                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
5522            | name, `OptPercent ->
5523                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5524                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
5525                pr "    v = caml_alloc (1, 0);\n";
5526                pr "    Store_field (v, 0, v2);\n";
5527                pr "  } else /* None */\n";
5528                pr "    v = Val_int (0);\n";
5529           );
5530           pr "  Store_field (rv, %d, v);\n" i
5531       ) cols;
5532       pr "  CAMLreturn (rv);\n";
5533       pr "}\n";
5534       pr "\n";
5535
5536       pr "static CAMLprim value\n";
5537       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
5538         typ typ typ;
5539       pr "{\n";
5540       pr "  CAMLparam0 ();\n";
5541       pr "  CAMLlocal2 (rv, v);\n";
5542       pr "  int i;\n";
5543       pr "\n";
5544       pr "  if (%ss->len == 0)\n" typ;
5545       pr "    CAMLreturn (Atom (0));\n";
5546       pr "  else {\n";
5547       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
5548       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
5549       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
5550       pr "      caml_modify (&Field (rv, i), v);\n";
5551       pr "    }\n";
5552       pr "    CAMLreturn (rv);\n";
5553       pr "  }\n";
5554       pr "}\n";
5555       pr "\n";
5556   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
5557
5558   (* Stat copy functions. *)
5559   List.iter (
5560     fun (typ, cols) ->
5561       pr "static CAMLprim value\n";
5562       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5563       pr "{\n";
5564       pr "  CAMLparam0 ();\n";
5565       pr "  CAMLlocal2 (rv, v);\n";
5566       pr "\n";
5567       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
5568       iteri (
5569         fun i col ->
5570           (match col with
5571            | name, `Int ->
5572                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
5573           );
5574           pr "  Store_field (rv, %d, v);\n" i
5575       ) cols;
5576       pr "  CAMLreturn (rv);\n";
5577       pr "}\n";
5578       pr "\n";
5579   ) ["stat", stat_cols; "statvfs", statvfs_cols];
5580
5581   (* The wrappers. *)
5582   List.iter (
5583     fun (name, style, _, _, _, _, _) ->
5584       let params =
5585         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5586
5587       pr "CAMLprim value\n";
5588       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
5589       List.iter (pr ", value %s") (List.tl params);
5590       pr ")\n";
5591       pr "{\n";
5592
5593       (match params with
5594        | [p1; p2; p3; p4; p5] ->
5595            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
5596        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
5597            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
5598            pr "  CAMLxparam%d (%s);\n"
5599              (List.length rest) (String.concat ", " rest)
5600        | ps ->
5601            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
5602       );
5603       pr "  CAMLlocal1 (rv);\n";
5604       pr "\n";
5605
5606       pr "  guestfs_h *g = Guestfs_val (gv);\n";
5607       pr "  if (g == NULL)\n";
5608       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
5609       pr "\n";
5610
5611       List.iter (
5612         function
5613         | String n
5614         | FileIn n
5615         | FileOut n ->
5616             pr "  const char *%s = String_val (%sv);\n" n n
5617         | OptString n ->
5618             pr "  const char *%s =\n" n;
5619             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
5620               n n
5621         | StringList n ->
5622             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
5623         | Bool n ->
5624             pr "  int %s = Bool_val (%sv);\n" n n
5625         | Int n ->
5626             pr "  int %s = Int_val (%sv);\n" n n
5627       ) (snd style);
5628       let error_code =
5629         match fst style with
5630         | RErr -> pr "  int r;\n"; "-1"
5631         | RInt _ -> pr "  int r;\n"; "-1"
5632         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5633         | RBool _ -> pr "  int r;\n"; "-1"
5634         | RConstString _ -> pr "  const char *r;\n"; "NULL"
5635         | RString _ -> pr "  char *r;\n"; "NULL"
5636         | RStringList _ ->
5637             pr "  int i;\n";
5638             pr "  char **r;\n";
5639             "NULL"
5640         | RIntBool _ ->
5641             pr "  struct guestfs_int_bool *r;\n"; "NULL"
5642         | RPVList _ ->
5643             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
5644         | RVGList _ ->
5645             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
5646         | RLVList _ ->
5647             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
5648         | RStat _ ->
5649             pr "  struct guestfs_stat *r;\n"; "NULL"
5650         | RStatVFS _ ->
5651             pr "  struct guestfs_statvfs *r;\n"; "NULL"
5652         | RHashtable _ ->
5653             pr "  int i;\n";
5654             pr "  char **r;\n";
5655             "NULL" in
5656       pr "\n";
5657
5658       pr "  caml_enter_blocking_section ();\n";
5659       pr "  r = guestfs_%s " name;
5660       generate_call_args ~handle:"g" (snd style);
5661       pr ";\n";
5662       pr "  caml_leave_blocking_section ();\n";
5663
5664       List.iter (
5665         function
5666         | StringList n ->
5667             pr "  ocaml_guestfs_free_strings (%s);\n" n;
5668         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
5669       ) (snd style);
5670
5671       pr "  if (r == %s)\n" error_code;
5672       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
5673       pr "\n";
5674
5675       (match fst style with
5676        | RErr -> pr "  rv = Val_unit;\n"
5677        | RInt _ -> pr "  rv = Val_int (r);\n"
5678        | RInt64 _ ->
5679            pr "  rv = caml_copy_int64 (r);\n"
5680        | RBool _ -> pr "  rv = Val_bool (r);\n"
5681        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
5682        | RString _ ->
5683            pr "  rv = caml_copy_string (r);\n";
5684            pr "  free (r);\n"
5685        | RStringList _ ->
5686            pr "  rv = caml_copy_string_array ((const char **) r);\n";
5687            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5688            pr "  free (r);\n"
5689        | RIntBool _ ->
5690            pr "  rv = caml_alloc (2, 0);\n";
5691            pr "  Store_field (rv, 0, Val_int (r->i));\n";
5692            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
5693            pr "  guestfs_free_int_bool (r);\n";
5694        | RPVList _ ->
5695            pr "  rv = copy_lvm_pv_list (r);\n";
5696            pr "  guestfs_free_lvm_pv_list (r);\n";
5697        | RVGList _ ->
5698            pr "  rv = copy_lvm_vg_list (r);\n";
5699            pr "  guestfs_free_lvm_vg_list (r);\n";
5700        | RLVList _ ->
5701            pr "  rv = copy_lvm_lv_list (r);\n";
5702            pr "  guestfs_free_lvm_lv_list (r);\n";
5703        | RStat _ ->
5704            pr "  rv = copy_stat (r);\n";
5705            pr "  free (r);\n";
5706        | RStatVFS _ ->
5707            pr "  rv = copy_statvfs (r);\n";
5708            pr "  free (r);\n";
5709        | RHashtable _ ->
5710            pr "  rv = copy_table (r);\n";
5711            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
5712            pr "  free (r);\n";
5713       );
5714
5715       pr "  CAMLreturn (rv);\n";
5716       pr "}\n";
5717       pr "\n";
5718
5719       if List.length params > 5 then (
5720         pr "CAMLprim value\n";
5721         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
5722         pr "{\n";
5723         pr "  return ocaml_guestfs_%s (argv[0]" name;
5724         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
5725         pr ");\n";
5726         pr "}\n";
5727         pr "\n"
5728       )
5729   ) all_functions
5730
5731 and generate_ocaml_lvm_structure_decls () =
5732   List.iter (
5733     fun (typ, cols) ->
5734       pr "type lvm_%s = {\n" typ;
5735       List.iter (
5736         function
5737         | name, `String -> pr "  %s : string;\n" name
5738         | name, `UUID -> pr "  %s : string;\n" name
5739         | name, `Bytes -> pr "  %s : int64;\n" name
5740         | name, `Int -> pr "  %s : int64;\n" name
5741         | name, `OptPercent -> pr "  %s : float option;\n" name
5742       ) cols;
5743       pr "}\n";
5744       pr "\n"
5745   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
5746
5747 and generate_ocaml_stat_structure_decls () =
5748   List.iter (
5749     fun (typ, cols) ->
5750       pr "type %s = {\n" typ;
5751       List.iter (
5752         function
5753         | name, `Int -> pr "  %s : int64;\n" name
5754       ) cols;
5755       pr "}\n";
5756       pr "\n"
5757   ) ["stat", stat_cols; "statvfs", statvfs_cols]
5758
5759 and generate_ocaml_prototype ?(is_external = false) name style =
5760   if is_external then pr "external " else pr "val ";
5761   pr "%s : t -> " name;
5762   List.iter (
5763     function
5764     | String _ | FileIn _ | FileOut _ -> pr "string -> "
5765     | OptString _ -> pr "string option -> "
5766     | StringList _ -> pr "string array -> "
5767     | Bool _ -> pr "bool -> "
5768     | Int _ -> pr "int -> "
5769   ) (snd style);
5770   (match fst style with
5771    | RErr -> pr "unit" (* all errors are turned into exceptions *)
5772    | RInt _ -> pr "int"
5773    | RInt64 _ -> pr "int64"
5774    | RBool _ -> pr "bool"
5775    | RConstString _ -> pr "string"
5776    | RString _ -> pr "string"
5777    | RStringList _ -> pr "string array"
5778    | RIntBool _ -> pr "int * bool"
5779    | RPVList _ -> pr "lvm_pv array"
5780    | RVGList _ -> pr "lvm_vg array"
5781    | RLVList _ -> pr "lvm_lv array"
5782    | RStat _ -> pr "stat"
5783    | RStatVFS _ -> pr "statvfs"
5784    | RHashtable _ -> pr "(string * string) list"
5785   );
5786   if is_external then (
5787     pr " = ";
5788     if List.length (snd style) + 1 > 5 then
5789       pr "\"ocaml_guestfs_%s_byte\" " name;
5790     pr "\"ocaml_guestfs_%s\"" name
5791   );
5792   pr "\n"
5793
5794 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
5795 and generate_perl_xs () =
5796   generate_header CStyle LGPLv2;
5797
5798   pr "\
5799 #include \"EXTERN.h\"
5800 #include \"perl.h\"
5801 #include \"XSUB.h\"
5802
5803 #include <guestfs.h>
5804
5805 #ifndef PRId64
5806 #define PRId64 \"lld\"
5807 #endif
5808
5809 static SV *
5810 my_newSVll(long long val) {
5811 #ifdef USE_64_BIT_ALL
5812   return newSViv(val);
5813 #else
5814   char buf[100];
5815   int len;
5816   len = snprintf(buf, 100, \"%%\" PRId64, val);
5817   return newSVpv(buf, len);
5818 #endif
5819 }
5820
5821 #ifndef PRIu64
5822 #define PRIu64 \"llu\"
5823 #endif
5824
5825 static SV *
5826 my_newSVull(unsigned long long val) {
5827 #ifdef USE_64_BIT_ALL
5828   return newSVuv(val);
5829 #else
5830   char buf[100];
5831   int len;
5832   len = snprintf(buf, 100, \"%%\" PRIu64, val);
5833   return newSVpv(buf, len);
5834 #endif
5835 }
5836
5837 /* http://www.perlmonks.org/?node_id=680842 */
5838 static char **
5839 XS_unpack_charPtrPtr (SV *arg) {
5840   char **ret;
5841   AV *av;
5842   I32 i;
5843
5844   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
5845     croak (\"array reference expected\");
5846
5847   av = (AV *)SvRV (arg);
5848   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
5849   if (!ret)
5850     croak (\"malloc failed\");
5851
5852   for (i = 0; i <= av_len (av); i++) {
5853     SV **elem = av_fetch (av, i, 0);
5854
5855     if (!elem || !*elem)
5856       croak (\"missing element in list\");
5857
5858     ret[i] = SvPV_nolen (*elem);
5859   }
5860
5861   ret[i] = NULL;
5862
5863   return ret;
5864 }
5865
5866 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
5867
5868 PROTOTYPES: ENABLE
5869
5870 guestfs_h *
5871 _create ()
5872    CODE:
5873       RETVAL = guestfs_create ();
5874       if (!RETVAL)
5875         croak (\"could not create guestfs handle\");
5876       guestfs_set_error_handler (RETVAL, NULL, NULL);
5877  OUTPUT:
5878       RETVAL
5879
5880 void
5881 DESTROY (g)
5882       guestfs_h *g;
5883  PPCODE:
5884       guestfs_close (g);
5885
5886 ";
5887
5888   List.iter (
5889     fun (name, style, _, _, _, _, _) ->
5890       (match fst style with
5891        | RErr -> pr "void\n"
5892        | RInt _ -> pr "SV *\n"
5893        | RInt64 _ -> pr "SV *\n"
5894        | RBool _ -> pr "SV *\n"
5895        | RConstString _ -> pr "SV *\n"
5896        | RString _ -> pr "SV *\n"
5897        | RStringList _
5898        | RIntBool _
5899        | RPVList _ | RVGList _ | RLVList _
5900        | RStat _ | RStatVFS _
5901        | RHashtable _ ->
5902            pr "void\n" (* all lists returned implictly on the stack *)
5903       );
5904       (* Call and arguments. *)
5905       pr "%s " name;
5906       generate_call_args ~handle:"g" (snd style);
5907       pr "\n";
5908       pr "      guestfs_h *g;\n";
5909       iteri (
5910         fun i ->
5911           function
5912           | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
5913           | OptString n ->
5914               (* http://www.perlmonks.org/?node_id=554277
5915                * Note that the implicit handle argument means we have
5916                * to add 1 to the ST(x) operator.
5917                *)
5918               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
5919           | StringList n -> pr "      char **%s;\n" n
5920           | Bool n -> pr "      int %s;\n" n
5921           | Int n -> pr "      int %s;\n" n
5922       ) (snd style);
5923
5924       let do_cleanups () =
5925         List.iter (
5926           function
5927           | String _ | OptString _ | Bool _ | Int _
5928           | FileIn _ | FileOut _ -> ()
5929           | StringList n -> pr "      free (%s);\n" n
5930         ) (snd style)
5931       in
5932
5933       (* Code. *)
5934       (match fst style with
5935        | RErr ->
5936            pr "PREINIT:\n";
5937            pr "      int r;\n";
5938            pr " PPCODE:\n";
5939            pr "      r = guestfs_%s " name;
5940            generate_call_args ~handle:"g" (snd style);
5941            pr ";\n";
5942            do_cleanups ();
5943            pr "      if (r == -1)\n";
5944            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5945        | RInt n
5946        | RBool n ->
5947            pr "PREINIT:\n";
5948            pr "      int %s;\n" n;
5949            pr "   CODE:\n";
5950            pr "      %s = guestfs_%s " n name;
5951            generate_call_args ~handle:"g" (snd style);
5952            pr ";\n";
5953            do_cleanups ();
5954            pr "      if (%s == -1)\n" n;
5955            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5956            pr "      RETVAL = newSViv (%s);\n" n;
5957            pr " OUTPUT:\n";
5958            pr "      RETVAL\n"
5959        | RInt64 n ->
5960            pr "PREINIT:\n";
5961            pr "      int64_t %s;\n" n;
5962            pr "   CODE:\n";
5963            pr "      %s = guestfs_%s " n name;
5964            generate_call_args ~handle:"g" (snd style);
5965            pr ";\n";
5966            do_cleanups ();
5967            pr "      if (%s == -1)\n" n;
5968            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5969            pr "      RETVAL = my_newSVll (%s);\n" n;
5970            pr " OUTPUT:\n";
5971            pr "      RETVAL\n"
5972        | RConstString n ->
5973            pr "PREINIT:\n";
5974            pr "      const char *%s;\n" n;
5975            pr "   CODE:\n";
5976            pr "      %s = guestfs_%s " n name;
5977            generate_call_args ~handle:"g" (snd style);
5978            pr ";\n";
5979            do_cleanups ();
5980            pr "      if (%s == NULL)\n" n;
5981            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5982            pr "      RETVAL = newSVpv (%s, 0);\n" n;
5983            pr " OUTPUT:\n";
5984            pr "      RETVAL\n"
5985        | RString n ->
5986            pr "PREINIT:\n";
5987            pr "      char *%s;\n" n;
5988            pr "   CODE:\n";
5989            pr "      %s = guestfs_%s " n name;
5990            generate_call_args ~handle:"g" (snd style);
5991            pr ";\n";
5992            do_cleanups ();
5993            pr "      if (%s == NULL)\n" n;
5994            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
5995            pr "      RETVAL = newSVpv (%s, 0);\n" n;
5996            pr "      free (%s);\n" n;
5997            pr " OUTPUT:\n";
5998            pr "      RETVAL\n"
5999        | RStringList n | RHashtable n ->
6000            pr "PREINIT:\n";
6001            pr "      char **%s;\n" n;
6002            pr "      int i, n;\n";
6003            pr " PPCODE:\n";
6004            pr "      %s = guestfs_%s " n name;
6005            generate_call_args ~handle:"g" (snd style);
6006            pr ";\n";
6007            do_cleanups ();
6008            pr "      if (%s == NULL)\n" n;
6009            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6010            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6011            pr "      EXTEND (SP, n);\n";
6012            pr "      for (i = 0; i < n; ++i) {\n";
6013            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6014            pr "        free (%s[i]);\n" n;
6015            pr "      }\n";
6016            pr "      free (%s);\n" n;
6017        | RIntBool _ ->
6018            pr "PREINIT:\n";
6019            pr "      struct guestfs_int_bool *r;\n";
6020            pr " PPCODE:\n";
6021            pr "      r = guestfs_%s " name;
6022            generate_call_args ~handle:"g" (snd style);
6023            pr ";\n";
6024            do_cleanups ();
6025            pr "      if (r == NULL)\n";
6026            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6027            pr "      EXTEND (SP, 2);\n";
6028            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
6029            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
6030            pr "      guestfs_free_int_bool (r);\n";
6031        | RPVList n ->
6032            generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
6033        | RVGList n ->
6034            generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
6035        | RLVList n ->
6036            generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
6037        | RStat n ->
6038            generate_perl_stat_code "stat" stat_cols name style n do_cleanups
6039        | RStatVFS n ->
6040            generate_perl_stat_code
6041              "statvfs" statvfs_cols name style n do_cleanups
6042       );
6043
6044       pr "\n"
6045   ) all_functions
6046
6047 and generate_perl_lvm_code typ cols name style n do_cleanups =
6048   pr "PREINIT:\n";
6049   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
6050   pr "      int i;\n";
6051   pr "      HV *hv;\n";
6052   pr " PPCODE:\n";
6053   pr "      %s = guestfs_%s " n name;
6054   generate_call_args ~handle:"g" (snd style);
6055   pr ";\n";
6056   do_cleanups ();
6057   pr "      if (%s == NULL)\n" n;
6058   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6059   pr "      EXTEND (SP, %s->len);\n" n;
6060   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
6061   pr "        hv = newHV ();\n";
6062   List.iter (
6063     function
6064     | name, `String ->
6065         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6066           name (String.length name) n name
6067     | name, `UUID ->
6068         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
6069           name (String.length name) n name
6070     | name, `Bytes ->
6071         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6072           name (String.length name) n name
6073     | name, `Int ->
6074         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
6075           name (String.length name) n name
6076     | name, `OptPercent ->
6077         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6078           name (String.length name) n name
6079   ) cols;
6080   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
6081   pr "      }\n";
6082   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
6083
6084 and generate_perl_stat_code typ cols name style n do_cleanups =
6085   pr "PREINIT:\n";
6086   pr "      struct guestfs_%s *%s;\n" typ n;
6087   pr " PPCODE:\n";
6088   pr "      %s = guestfs_%s " n name;
6089   generate_call_args ~handle:"g" (snd style);
6090   pr ";\n";
6091   do_cleanups ();
6092   pr "      if (%s == NULL)\n" n;
6093   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6094   pr "      EXTEND (SP, %d);\n" (List.length cols);
6095   List.iter (
6096     function
6097     | name, `Int ->
6098         pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
6099   ) cols;
6100   pr "      free (%s);\n" n
6101
6102 (* Generate Sys/Guestfs.pm. *)
6103 and generate_perl_pm () =
6104   generate_header HashStyle LGPLv2;
6105
6106   pr "\
6107 =pod
6108
6109 =head1 NAME
6110
6111 Sys::Guestfs - Perl bindings for libguestfs
6112
6113 =head1 SYNOPSIS
6114
6115  use Sys::Guestfs;
6116  
6117  my $h = Sys::Guestfs->new ();
6118  $h->add_drive ('guest.img');
6119  $h->launch ();
6120  $h->wait_ready ();
6121  $h->mount ('/dev/sda1', '/');
6122  $h->touch ('/hello');
6123  $h->sync ();
6124
6125 =head1 DESCRIPTION
6126
6127 The C<Sys::Guestfs> module provides a Perl XS binding to the
6128 libguestfs API for examining and modifying virtual machine
6129 disk images.
6130
6131 Amongst the things this is good for: making batch configuration
6132 changes to guests, getting disk used/free statistics (see also:
6133 virt-df), migrating between virtualization systems (see also:
6134 virt-p2v), performing partial backups, performing partial guest
6135 clones, cloning guests and changing registry/UUID/hostname info, and
6136 much else besides.
6137
6138 Libguestfs uses Linux kernel and qemu code, and can access any type of
6139 guest filesystem that Linux and qemu can, including but not limited
6140 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6141 schemes, qcow, qcow2, vmdk.
6142
6143 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6144 LVs, what filesystem is in each LV, etc.).  It can also run commands
6145 in the context of the guest.  Also you can access filesystems over FTP.
6146
6147 =head1 ERRORS
6148
6149 All errors turn into calls to C<croak> (see L<Carp(3)>).
6150
6151 =head1 METHODS
6152
6153 =over 4
6154
6155 =cut
6156
6157 package Sys::Guestfs;
6158
6159 use strict;
6160 use warnings;
6161
6162 require XSLoader;
6163 XSLoader::load ('Sys::Guestfs');
6164
6165 =item $h = Sys::Guestfs->new ();
6166
6167 Create a new guestfs handle.
6168
6169 =cut
6170
6171 sub new {
6172   my $proto = shift;
6173   my $class = ref ($proto) || $proto;
6174
6175   my $self = Sys::Guestfs::_create ();
6176   bless $self, $class;
6177   return $self;
6178 }
6179
6180 ";
6181
6182   (* Actions.  We only need to print documentation for these as
6183    * they are pulled in from the XS code automatically.
6184    *)
6185   List.iter (
6186     fun (name, style, _, flags, _, _, longdesc) ->
6187       if not (List.mem NotInDocs flags) then (
6188         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
6189         pr "=item ";
6190         generate_perl_prototype name style;
6191         pr "\n\n";
6192         pr "%s\n\n" longdesc;
6193         if List.mem ProtocolLimitWarning flags then
6194           pr "%s\n\n" protocol_limit_warning;
6195         if List.mem DangerWillRobinson flags then
6196           pr "%s\n\n" danger_will_robinson
6197       )
6198   ) all_functions_sorted;
6199
6200   (* End of file. *)
6201   pr "\
6202 =cut
6203
6204 1;
6205
6206 =back
6207
6208 =head1 COPYRIGHT
6209
6210 Copyright (C) 2009 Red Hat Inc.
6211
6212 =head1 LICENSE
6213
6214 Please see the file COPYING.LIB for the full license.
6215
6216 =head1 SEE ALSO
6217
6218 L<guestfs(3)>, L<guestfish(1)>.
6219
6220 =cut
6221 "
6222
6223 and generate_perl_prototype name style =
6224   (match fst style with
6225    | RErr -> ()
6226    | RBool n
6227    | RInt n
6228    | RInt64 n
6229    | RConstString n
6230    | RString n -> pr "$%s = " n
6231    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
6232    | RStringList n
6233    | RPVList n
6234    | RVGList n
6235    | RLVList n -> pr "@%s = " n
6236    | RStat n
6237    | RStatVFS n
6238    | RHashtable n -> pr "%%%s = " n
6239   );
6240   pr "$h->%s (" name;
6241   let comma = ref false in
6242   List.iter (
6243     fun arg ->
6244       if !comma then pr ", ";
6245       comma := true;
6246       match arg with
6247       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
6248           pr "$%s" n
6249       | StringList n ->
6250           pr "\\@%s" n
6251   ) (snd style);
6252   pr ");"
6253
6254 (* Generate Python C module. *)
6255 and generate_python_c () =
6256   generate_header CStyle LGPLv2;
6257
6258   pr "\
6259 #include <stdio.h>
6260 #include <stdlib.h>
6261 #include <assert.h>
6262
6263 #include <Python.h>
6264
6265 #include \"guestfs.h\"
6266
6267 typedef struct {
6268   PyObject_HEAD
6269   guestfs_h *g;
6270 } Pyguestfs_Object;
6271
6272 static guestfs_h *
6273 get_handle (PyObject *obj)
6274 {
6275   assert (obj);
6276   assert (obj != Py_None);
6277   return ((Pyguestfs_Object *) obj)->g;
6278 }
6279
6280 static PyObject *
6281 put_handle (guestfs_h *g)
6282 {
6283   assert (g);
6284   return
6285     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6286 }
6287
6288 /* This list should be freed (but not the strings) after use. */
6289 static const char **
6290 get_string_list (PyObject *obj)
6291 {
6292   int i, len;
6293   const char **r;
6294
6295   assert (obj);
6296
6297   if (!PyList_Check (obj)) {
6298     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6299     return NULL;
6300   }
6301
6302   len = PyList_Size (obj);
6303   r = malloc (sizeof (char *) * (len+1));
6304   if (r == NULL) {
6305     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6306     return NULL;
6307   }
6308
6309   for (i = 0; i < len; ++i)
6310     r[i] = PyString_AsString (PyList_GetItem (obj, i));
6311   r[len] = NULL;
6312
6313   return r;
6314 }
6315
6316 static PyObject *
6317 put_string_list (char * const * const argv)
6318 {
6319   PyObject *list;
6320   int argc, i;
6321
6322   for (argc = 0; argv[argc] != NULL; ++argc)
6323     ;
6324
6325   list = PyList_New (argc);
6326   for (i = 0; i < argc; ++i)
6327     PyList_SetItem (list, i, PyString_FromString (argv[i]));
6328
6329   return list;
6330 }
6331
6332 static PyObject *
6333 put_table (char * const * const argv)
6334 {
6335   PyObject *list, *item;
6336   int argc, i;
6337
6338   for (argc = 0; argv[argc] != NULL; ++argc)
6339     ;
6340
6341   list = PyList_New (argc >> 1);
6342   for (i = 0; i < argc; i += 2) {
6343     item = PyTuple_New (2);
6344     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
6345     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
6346     PyList_SetItem (list, i >> 1, item);
6347   }
6348
6349   return list;
6350 }
6351
6352 static void
6353 free_strings (char **argv)
6354 {
6355   int argc;
6356
6357   for (argc = 0; argv[argc] != NULL; ++argc)
6358     free (argv[argc]);
6359   free (argv);
6360 }
6361
6362 static PyObject *
6363 py_guestfs_create (PyObject *self, PyObject *args)
6364 {
6365   guestfs_h *g;
6366
6367   g = guestfs_create ();
6368   if (g == NULL) {
6369     PyErr_SetString (PyExc_RuntimeError,
6370                      \"guestfs.create: failed to allocate handle\");
6371     return NULL;
6372   }
6373   guestfs_set_error_handler (g, NULL, NULL);
6374   return put_handle (g);
6375 }
6376
6377 static PyObject *
6378 py_guestfs_close (PyObject *self, PyObject *args)
6379 {
6380   PyObject *py_g;
6381   guestfs_h *g;
6382
6383   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
6384     return NULL;
6385   g = get_handle (py_g);
6386
6387   guestfs_close (g);
6388
6389   Py_INCREF (Py_None);
6390   return Py_None;
6391 }
6392
6393 ";
6394
6395   (* LVM structures, turned into Python dictionaries. *)
6396   List.iter (
6397     fun (typ, cols) ->
6398       pr "static PyObject *\n";
6399       pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
6400       pr "{\n";
6401       pr "  PyObject *dict;\n";
6402       pr "\n";
6403       pr "  dict = PyDict_New ();\n";
6404       List.iter (
6405         function
6406         | name, `String ->
6407             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6408             pr "                        PyString_FromString (%s->%s));\n"
6409               typ name
6410         | name, `UUID ->
6411             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6412             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
6413               typ name
6414         | name, `Bytes ->
6415             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6416             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
6417               typ name
6418         | name, `Int ->
6419             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6420             pr "                        PyLong_FromLongLong (%s->%s));\n"
6421               typ name
6422         | name, `OptPercent ->
6423             pr "  if (%s->%s >= 0)\n" typ name;
6424             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
6425             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
6426               typ name;
6427             pr "  else {\n";
6428             pr "    Py_INCREF (Py_None);\n";
6429             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
6430             pr "  }\n"
6431       ) cols;
6432       pr "  return dict;\n";
6433       pr "};\n";
6434       pr "\n";
6435
6436       pr "static PyObject *\n";
6437       pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
6438       pr "{\n";
6439       pr "  PyObject *list;\n";
6440       pr "  int i;\n";
6441       pr "\n";
6442       pr "  list = PyList_New (%ss->len);\n" typ;
6443       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
6444       pr "    PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
6445       pr "  return list;\n";
6446       pr "};\n";
6447       pr "\n"
6448   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
6449
6450   (* Stat structures, turned into Python dictionaries. *)
6451   List.iter (
6452     fun (typ, cols) ->
6453       pr "static PyObject *\n";
6454       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6455       pr "{\n";
6456       pr "  PyObject *dict;\n";
6457       pr "\n";
6458       pr "  dict = PyDict_New ();\n";
6459       List.iter (
6460         function
6461         | name, `Int ->
6462             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6463             pr "                        PyLong_FromLongLong (%s->%s));\n"
6464               typ name
6465       ) cols;
6466       pr "  return dict;\n";
6467       pr "};\n";
6468       pr "\n";
6469   ) ["stat", stat_cols; "statvfs", statvfs_cols];
6470
6471   (* Python wrapper functions. *)
6472   List.iter (
6473     fun (name, style, _, _, _, _, _) ->
6474       pr "static PyObject *\n";
6475       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6476       pr "{\n";
6477
6478       pr "  PyObject *py_g;\n";
6479       pr "  guestfs_h *g;\n";
6480       pr "  PyObject *py_r;\n";
6481
6482       let error_code =
6483         match fst style with
6484         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
6485         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6486         | RConstString _ -> pr "  const char *r;\n"; "NULL"
6487         | RString _ -> pr "  char *r;\n"; "NULL"
6488         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6489         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
6490         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
6491         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
6492         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
6493         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
6494         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
6495
6496       List.iter (
6497         function
6498         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
6499         | OptString n -> pr "  const char *%s;\n" n
6500         | StringList n ->
6501             pr "  PyObject *py_%s;\n" n;
6502             pr "  const char **%s;\n" n
6503         | Bool n -> pr "  int %s;\n" n
6504         | Int n -> pr "  int %s;\n" n
6505       ) (snd style);
6506
6507       pr "\n";
6508
6509       (* Convert the parameters. *)
6510       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
6511       List.iter (
6512         function
6513         | String _ | FileIn _ | FileOut _ -> pr "s"
6514         | OptString _ -> pr "z"
6515         | StringList _ -> pr "O"
6516         | Bool _ -> pr "i" (* XXX Python has booleans? *)
6517         | Int _ -> pr "i"
6518       ) (snd style);
6519       pr ":guestfs_%s\",\n" name;
6520       pr "                         &py_g";
6521       List.iter (
6522         function
6523         | String n | FileIn n | FileOut n -> pr ", &%s" n
6524         | OptString n -> pr ", &%s" n
6525         | StringList n -> pr ", &py_%s" n
6526         | Bool n -> pr ", &%s" n
6527         | Int n -> pr ", &%s" n
6528       ) (snd style);
6529
6530       pr "))\n";
6531       pr "    return NULL;\n";
6532
6533       pr "  g = get_handle (py_g);\n";
6534       List.iter (
6535         function
6536         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6537         | StringList n ->
6538             pr "  %s = get_string_list (py_%s);\n" n n;
6539             pr "  if (!%s) return NULL;\n" n
6540       ) (snd style);
6541
6542       pr "\n";
6543
6544       pr "  r = guestfs_%s " name;
6545       generate_call_args ~handle:"g" (snd style);
6546       pr ";\n";
6547
6548       List.iter (
6549         function
6550         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6551         | StringList n ->
6552             pr "  free (%s);\n" n
6553       ) (snd style);
6554
6555       pr "  if (r == %s) {\n" error_code;
6556       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6557       pr "    return NULL;\n";
6558       pr "  }\n";
6559       pr "\n";
6560
6561       (match fst style with
6562        | RErr ->
6563            pr "  Py_INCREF (Py_None);\n";
6564            pr "  py_r = Py_None;\n"
6565        | RInt _
6566        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
6567        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
6568        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
6569        | RString _ ->
6570            pr "  py_r = PyString_FromString (r);\n";
6571            pr "  free (r);\n"
6572        | RStringList _ ->
6573            pr "  py_r = put_string_list (r);\n";
6574            pr "  free_strings (r);\n"
6575        | RIntBool _ ->
6576            pr "  py_r = PyTuple_New (2);\n";
6577            pr "  PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
6578            pr "  PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
6579            pr "  guestfs_free_int_bool (r);\n"
6580        | RPVList n ->
6581            pr "  py_r = put_lvm_pv_list (r);\n";
6582            pr "  guestfs_free_lvm_pv_list (r);\n"
6583        | RVGList n ->
6584            pr "  py_r = put_lvm_vg_list (r);\n";
6585            pr "  guestfs_free_lvm_vg_list (r);\n"
6586        | RLVList n ->
6587            pr "  py_r = put_lvm_lv_list (r);\n";
6588            pr "  guestfs_free_lvm_lv_list (r);\n"
6589        | RStat n ->
6590            pr "  py_r = put_stat (r);\n";
6591            pr "  free (r);\n"
6592        | RStatVFS n ->
6593            pr "  py_r = put_statvfs (r);\n";
6594            pr "  free (r);\n"
6595        | RHashtable n ->
6596            pr "  py_r = put_table (r);\n";
6597            pr "  free_strings (r);\n"
6598       );
6599
6600       pr "  return py_r;\n";
6601       pr "}\n";
6602       pr "\n"
6603   ) all_functions;
6604
6605   (* Table of functions. *)
6606   pr "static PyMethodDef methods[] = {\n";
6607   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
6608   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
6609   List.iter (
6610     fun (name, _, _, _, _, _, _) ->
6611       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
6612         name name
6613   ) all_functions;
6614   pr "  { NULL, NULL, 0, NULL }\n";
6615   pr "};\n";
6616   pr "\n";
6617
6618   (* Init function. *)
6619   pr "\
6620 void
6621 initlibguestfsmod (void)
6622 {
6623   static int initialized = 0;
6624
6625   if (initialized) return;
6626   Py_InitModule ((char *) \"libguestfsmod\", methods);
6627   initialized = 1;
6628 }
6629 "
6630
6631 (* Generate Python module. *)
6632 and generate_python_py () =
6633   generate_header HashStyle LGPLv2;
6634
6635   pr "\
6636 u\"\"\"Python bindings for libguestfs
6637
6638 import guestfs
6639 g = guestfs.GuestFS ()
6640 g.add_drive (\"guest.img\")
6641 g.launch ()
6642 g.wait_ready ()
6643 parts = g.list_partitions ()
6644
6645 The guestfs module provides a Python binding to the libguestfs API
6646 for examining and modifying virtual machine disk images.
6647
6648 Amongst the things this is good for: making batch configuration
6649 changes to guests, getting disk used/free statistics (see also:
6650 virt-df), migrating between virtualization systems (see also:
6651 virt-p2v), performing partial backups, performing partial guest
6652 clones, cloning guests and changing registry/UUID/hostname info, and
6653 much else besides.
6654
6655 Libguestfs uses Linux kernel and qemu code, and can access any type of
6656 guest filesystem that Linux and qemu can, including but not limited
6657 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6658 schemes, qcow, qcow2, vmdk.
6659
6660 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6661 LVs, what filesystem is in each LV, etc.).  It can also run commands
6662 in the context of the guest.  Also you can access filesystems over FTP.
6663
6664 Errors which happen while using the API are turned into Python
6665 RuntimeError exceptions.
6666
6667 To create a guestfs handle you usually have to perform the following
6668 sequence of calls:
6669
6670 # Create the handle, call add_drive at least once, and possibly
6671 # several times if the guest has multiple block devices:
6672 g = guestfs.GuestFS ()
6673 g.add_drive (\"guest.img\")
6674
6675 # Launch the qemu subprocess and wait for it to become ready:
6676 g.launch ()
6677 g.wait_ready ()
6678
6679 # Now you can issue commands, for example:
6680 logvols = g.lvs ()
6681
6682 \"\"\"
6683
6684 import libguestfsmod
6685
6686 class GuestFS:
6687     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
6688
6689     def __init__ (self):
6690         \"\"\"Create a new libguestfs handle.\"\"\"
6691         self._o = libguestfsmod.create ()
6692
6693     def __del__ (self):
6694         libguestfsmod.close (self._o)
6695
6696 ";
6697
6698   List.iter (
6699     fun (name, style, _, flags, _, _, longdesc) ->
6700       pr "    def %s " name;
6701       generate_call_args ~handle:"self" (snd style);
6702       pr ":\n";
6703
6704       if not (List.mem NotInDocs flags) then (
6705         let doc = replace_str longdesc "C<guestfs_" "C<g." in
6706         let doc =
6707           match fst style with
6708           | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
6709           | RString _ -> doc
6710           | RStringList _ ->
6711               doc ^ "\n\nThis function returns a list of strings."
6712           | RIntBool _ ->
6713               doc ^ "\n\nThis function returns a tuple (int, bool).\n"
6714           | RPVList _ ->
6715               doc ^ "\n\nThis function returns a list of PVs.  Each PV is represented as a dictionary."
6716           | RVGList _ ->
6717               doc ^ "\n\nThis function returns a list of VGs.  Each VG is represented as a dictionary."
6718           | RLVList _ ->
6719               doc ^ "\n\nThis function returns a list of LVs.  Each LV is represented as a dictionary."
6720           | RStat _ ->
6721               doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
6722           | RStatVFS _ ->
6723               doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
6724           | RHashtable _ ->
6725               doc ^ "\n\nThis function returns a dictionary." in
6726         let doc =
6727           if List.mem ProtocolLimitWarning flags then
6728             doc ^ "\n\n" ^ protocol_limit_warning
6729           else doc in
6730         let doc =
6731           if List.mem DangerWillRobinson flags then
6732             doc ^ "\n\n" ^ danger_will_robinson
6733           else doc in
6734         let doc = pod2text ~width:60 name doc in
6735         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
6736         let doc = String.concat "\n        " doc in
6737         pr "        u\"\"\"%s\"\"\"\n" doc;
6738       );
6739       pr "        return libguestfsmod.%s " name;
6740       generate_call_args ~handle:"self._o" (snd style);
6741       pr "\n";
6742       pr "\n";
6743   ) all_functions
6744
6745 (* Useful if you need the longdesc POD text as plain text.  Returns a
6746  * list of lines.
6747  *
6748  * This is the slowest thing about autogeneration.
6749  *)
6750 and pod2text ~width name longdesc =
6751   let filename, chan = Filename.open_temp_file "gen" ".tmp" in
6752   fprintf chan "=head1 %s\n\n%s\n" name longdesc;
6753   close_out chan;
6754   let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
6755   let chan = Unix.open_process_in cmd in
6756   let lines = ref [] in
6757   let rec loop i =
6758     let line = input_line chan in
6759     if i = 1 then               (* discard the first line of output *)
6760       loop (i+1)
6761     else (
6762       let line = triml line in
6763       lines := line :: !lines;
6764       loop (i+1)
6765     ) in
6766   let lines = try loop 1 with End_of_file -> List.rev !lines in
6767   Unix.unlink filename;
6768   match Unix.close_process_in chan with
6769   | Unix.WEXITED 0 -> lines
6770   | Unix.WEXITED i ->
6771       failwithf "pod2text: process exited with non-zero status (%d)" i
6772   | Unix.WSIGNALED i | Unix.WSTOPPED i ->
6773       failwithf "pod2text: process signalled or stopped by signal %d" i
6774
6775 (* Generate ruby bindings. *)
6776 and generate_ruby_c () =
6777   generate_header CStyle LGPLv2;
6778
6779   pr "\
6780 #include <stdio.h>
6781 #include <stdlib.h>
6782
6783 #include <ruby.h>
6784
6785 #include \"guestfs.h\"
6786
6787 #include \"extconf.h\"
6788
6789 /* For Ruby < 1.9 */
6790 #ifndef RARRAY_LEN
6791 #define RARRAY_LEN(r) (RARRAY((r))->len)
6792 #endif
6793
6794 static VALUE m_guestfs;                 /* guestfs module */
6795 static VALUE c_guestfs;                 /* guestfs_h handle */
6796 static VALUE e_Error;                   /* used for all errors */
6797
6798 static void ruby_guestfs_free (void *p)
6799 {
6800   if (!p) return;
6801   guestfs_close ((guestfs_h *) p);
6802 }
6803
6804 static VALUE ruby_guestfs_create (VALUE m)
6805 {
6806   guestfs_h *g;
6807
6808   g = guestfs_create ();
6809   if (!g)
6810     rb_raise (e_Error, \"failed to create guestfs handle\");
6811
6812   /* Don't print error messages to stderr by default. */
6813   guestfs_set_error_handler (g, NULL, NULL);
6814
6815   /* Wrap it, and make sure the close function is called when the
6816    * handle goes away.
6817    */
6818   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
6819 }
6820
6821 static VALUE ruby_guestfs_close (VALUE gv)
6822 {
6823   guestfs_h *g;
6824   Data_Get_Struct (gv, guestfs_h, g);
6825
6826   ruby_guestfs_free (g);
6827   DATA_PTR (gv) = NULL;
6828
6829   return Qnil;
6830 }
6831
6832 ";
6833
6834   List.iter (
6835     fun (name, style, _, _, _, _, _) ->
6836       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
6837       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
6838       pr ")\n";
6839       pr "{\n";
6840       pr "  guestfs_h *g;\n";
6841       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
6842       pr "  if (!g)\n";
6843       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
6844         name;
6845       pr "\n";
6846
6847       List.iter (
6848         function
6849         | String n | FileIn n | FileOut n ->
6850             pr "  Check_Type (%sv, T_STRING);\n" n;
6851             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
6852             pr "  if (!%s)\n" n;
6853             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
6854             pr "              \"%s\", \"%s\");\n" n name
6855         | OptString n ->
6856             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
6857         | StringList n ->
6858             pr "  char **%s;\n" n;
6859             pr "  Check_Type (%sv, T_ARRAY);\n" n;
6860             pr "  {\n";
6861             pr "    int i, len;\n";
6862             pr "    len = RARRAY_LEN (%sv);\n" n;
6863             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
6864               n;
6865             pr "    for (i = 0; i < len; ++i) {\n";
6866             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
6867             pr "      %s[i] = StringValueCStr (v);\n" n;
6868             pr "    }\n";
6869             pr "    %s[len] = NULL;\n" n;
6870             pr "  }\n";
6871         | Bool n ->
6872             pr "  int %s = RTEST (%sv);\n" n n
6873         | Int n ->
6874             pr "  int %s = NUM2INT (%sv);\n" n n
6875       ) (snd style);
6876       pr "\n";
6877
6878       let error_code =
6879         match fst style with
6880         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
6881         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6882         | RConstString _ -> pr "  const char *r;\n"; "NULL"
6883         | RString _ -> pr "  char *r;\n"; "NULL"
6884         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6885         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
6886         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
6887         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
6888         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
6889         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
6890         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
6891       pr "\n";
6892
6893       pr "  r = guestfs_%s " name;
6894       generate_call_args ~handle:"g" (snd style);
6895       pr ";\n";
6896
6897       List.iter (
6898         function
6899         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6900         | StringList n ->
6901             pr "  free (%s);\n" n
6902       ) (snd style);
6903
6904       pr "  if (r == %s)\n" error_code;
6905       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
6906       pr "\n";
6907
6908       (match fst style with
6909        | RErr ->
6910            pr "  return Qnil;\n"
6911        | RInt _ | RBool _ ->
6912            pr "  return INT2NUM (r);\n"
6913        | RInt64 _ ->
6914            pr "  return ULL2NUM (r);\n"
6915        | RConstString _ ->
6916            pr "  return rb_str_new2 (r);\n";
6917        | RString _ ->
6918            pr "  VALUE rv = rb_str_new2 (r);\n";
6919            pr "  free (r);\n";
6920            pr "  return rv;\n";
6921        | RStringList _ ->
6922            pr "  int i, len = 0;\n";
6923            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
6924            pr "  VALUE rv = rb_ary_new2 (len);\n";
6925            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
6926            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
6927            pr "    free (r[i]);\n";
6928            pr "  }\n";
6929            pr "  free (r);\n";
6930            pr "  return rv;\n"
6931        | RIntBool _ ->
6932            pr "  VALUE rv = rb_ary_new2 (2);\n";
6933            pr "  rb_ary_push (rv, INT2NUM (r->i));\n";
6934            pr "  rb_ary_push (rv, INT2NUM (r->b));\n";
6935            pr "  guestfs_free_int_bool (r);\n";
6936            pr "  return rv;\n"
6937        | RPVList n ->
6938            generate_ruby_lvm_code "pv" pv_cols
6939        | RVGList n ->
6940            generate_ruby_lvm_code "vg" vg_cols
6941        | RLVList n ->
6942            generate_ruby_lvm_code "lv" lv_cols
6943        | RStat n ->
6944            pr "  VALUE rv = rb_hash_new ();\n";
6945            List.iter (
6946              function
6947              | name, `Int ->
6948                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6949            ) stat_cols;
6950            pr "  free (r);\n";
6951            pr "  return rv;\n"
6952        | RStatVFS n ->
6953            pr "  VALUE rv = rb_hash_new ();\n";
6954            List.iter (
6955              function
6956              | name, `Int ->
6957                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
6958            ) statvfs_cols;
6959            pr "  free (r);\n";
6960            pr "  return rv;\n"
6961        | RHashtable _ ->
6962            pr "  VALUE rv = rb_hash_new ();\n";
6963            pr "  int i;\n";
6964            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
6965            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
6966            pr "    free (r[i]);\n";
6967            pr "    free (r[i+1]);\n";
6968            pr "  }\n";
6969            pr "  free (r);\n";
6970            pr "  return rv;\n"
6971       );
6972
6973       pr "}\n";
6974       pr "\n"
6975   ) all_functions;
6976
6977   pr "\
6978 /* Initialize the module. */
6979 void Init__guestfs ()
6980 {
6981   m_guestfs = rb_define_module (\"Guestfs\");
6982   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
6983   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
6984
6985   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
6986   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
6987
6988 ";
6989   (* Define the rest of the methods. *)
6990   List.iter (
6991     fun (name, style, _, _, _, _, _) ->
6992       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
6993       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
6994   ) all_functions;
6995
6996   pr "}\n"
6997
6998 (* Ruby code to return an LVM struct list. *)
6999 and generate_ruby_lvm_code typ cols =
7000   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
7001   pr "  int i;\n";
7002   pr "  for (i = 0; i < r->len; ++i) {\n";
7003   pr "    VALUE hv = rb_hash_new ();\n";
7004   List.iter (
7005     function
7006     | name, `String ->
7007         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7008     | name, `UUID ->
7009         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
7010     | name, `Bytes
7011     | name, `Int ->
7012         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7013     | name, `OptPercent ->
7014         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
7015   ) cols;
7016   pr "    rb_ary_push (rv, hv);\n";
7017   pr "  }\n";
7018   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
7019   pr "  return rv;\n"
7020
7021 (* Generate Java bindings GuestFS.java file. *)
7022 and generate_java_java () =
7023   generate_header CStyle LGPLv2;
7024
7025   pr "\
7026 package com.redhat.et.libguestfs;
7027
7028 import java.util.HashMap;
7029 import com.redhat.et.libguestfs.LibGuestFSException;
7030 import com.redhat.et.libguestfs.PV;
7031 import com.redhat.et.libguestfs.VG;
7032 import com.redhat.et.libguestfs.LV;
7033 import com.redhat.et.libguestfs.Stat;
7034 import com.redhat.et.libguestfs.StatVFS;
7035 import com.redhat.et.libguestfs.IntBool;
7036
7037 /**
7038  * The GuestFS object is a libguestfs handle.
7039  *
7040  * @author rjones
7041  */
7042 public class GuestFS {
7043   // Load the native code.
7044   static {
7045     System.loadLibrary (\"guestfs_jni\");
7046   }
7047
7048   /**
7049    * The native guestfs_h pointer.
7050    */
7051   long g;
7052
7053   /**
7054    * Create a libguestfs handle.
7055    *
7056    * @throws LibGuestFSException
7057    */
7058   public GuestFS () throws LibGuestFSException
7059   {
7060     g = _create ();
7061   }
7062   private native long _create () throws LibGuestFSException;
7063
7064   /**
7065    * Close a libguestfs handle.
7066    *
7067    * You can also leave handles to be collected by the garbage
7068    * collector, but this method ensures that the resources used
7069    * by the handle are freed up immediately.  If you call any
7070    * other methods after closing the handle, you will get an
7071    * exception.
7072    *
7073    * @throws LibGuestFSException
7074    */
7075   public void close () throws LibGuestFSException
7076   {
7077     if (g != 0)
7078       _close (g);
7079     g = 0;
7080   }
7081   private native void _close (long g) throws LibGuestFSException;
7082
7083   public void finalize () throws LibGuestFSException
7084   {
7085     close ();
7086   }
7087
7088 ";
7089
7090   List.iter (
7091     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7092       if not (List.mem NotInDocs flags); then (
7093         let doc = replace_str longdesc "C<guestfs_" "C<g." in
7094         let doc =
7095           if List.mem ProtocolLimitWarning flags then
7096             doc ^ "\n\n" ^ protocol_limit_warning
7097           else doc in
7098         let doc =
7099           if List.mem DangerWillRobinson flags then
7100             doc ^ "\n\n" ^ danger_will_robinson
7101           else doc in
7102         let doc = pod2text ~width:60 name doc in
7103         let doc = List.map (            (* RHBZ#501883 *)
7104           function
7105           | "" -> "<p>"
7106           | nonempty -> nonempty
7107         ) doc in
7108         let doc = String.concat "\n   * " doc in
7109
7110         pr "  /**\n";
7111         pr "   * %s\n" shortdesc;
7112         pr "   * <p>\n";
7113         pr "   * %s\n" doc;
7114         pr "   * @throws LibGuestFSException\n";
7115         pr "   */\n";
7116         pr "  ";
7117       );
7118       generate_java_prototype ~public:true ~semicolon:false name style;
7119       pr "\n";
7120       pr "  {\n";
7121       pr "    if (g == 0)\n";
7122       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
7123         name;
7124       pr "    ";
7125       if fst style <> RErr then pr "return ";
7126       pr "_%s " name;
7127       generate_call_args ~handle:"g" (snd style);
7128       pr ";\n";
7129       pr "  }\n";
7130       pr "  ";
7131       generate_java_prototype ~privat:true ~native:true name style;
7132       pr "\n";
7133       pr "\n";
7134   ) all_functions;
7135
7136   pr "}\n"
7137
7138 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
7139     ?(semicolon=true) name style =
7140   if privat then pr "private ";
7141   if public then pr "public ";
7142   if native then pr "native ";
7143
7144   (* return type *)
7145   (match fst style with
7146    | RErr -> pr "void ";
7147    | RInt _ -> pr "int ";
7148    | RInt64 _ -> pr "long ";
7149    | RBool _ -> pr "boolean ";
7150    | RConstString _ | RString _ -> pr "String ";
7151    | RStringList _ -> pr "String[] ";
7152    | RIntBool _ -> pr "IntBool ";
7153    | RPVList _ -> pr "PV[] ";
7154    | RVGList _ -> pr "VG[] ";
7155    | RLVList _ -> pr "LV[] ";
7156    | RStat _ -> pr "Stat ";
7157    | RStatVFS _ -> pr "StatVFS ";
7158    | RHashtable _ -> pr "HashMap<String,String> ";
7159   );
7160
7161   if native then pr "_%s " name else pr "%s " name;
7162   pr "(";
7163   let needs_comma = ref false in
7164   if native then (
7165     pr "long g";
7166     needs_comma := true
7167   );
7168
7169   (* args *)
7170   List.iter (
7171     fun arg ->
7172       if !needs_comma then pr ", ";
7173       needs_comma := true;
7174
7175       match arg with
7176       | String n
7177       | OptString n
7178       | FileIn n
7179       | FileOut n ->
7180           pr "String %s" n
7181       | StringList n ->
7182           pr "String[] %s" n
7183       | Bool n ->
7184           pr "boolean %s" n
7185       | Int n ->
7186           pr "int %s" n
7187   ) (snd style);
7188
7189   pr ")\n";
7190   pr "    throws LibGuestFSException";
7191   if semicolon then pr ";"
7192
7193 and generate_java_struct typ cols =
7194   generate_header CStyle LGPLv2;
7195
7196   pr "\
7197 package com.redhat.et.libguestfs;
7198
7199 /**
7200  * Libguestfs %s structure.
7201  *
7202  * @author rjones
7203  * @see GuestFS
7204  */
7205 public class %s {
7206 " typ typ;
7207
7208   List.iter (
7209     function
7210     | name, `String
7211     | name, `UUID -> pr "  public String %s;\n" name
7212     | name, `Bytes
7213     | name, `Int -> pr "  public long %s;\n" name
7214     | name, `OptPercent ->
7215         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
7216         pr "  public float %s;\n" name
7217   ) cols;
7218
7219   pr "}\n"
7220
7221 and generate_java_c () =
7222   generate_header CStyle LGPLv2;
7223
7224   pr "\
7225 #include <stdio.h>
7226 #include <stdlib.h>
7227 #include <string.h>
7228
7229 #include \"com_redhat_et_libguestfs_GuestFS.h\"
7230 #include \"guestfs.h\"
7231
7232 /* Note that this function returns.  The exception is not thrown
7233  * until after the wrapper function returns.
7234  */
7235 static void
7236 throw_exception (JNIEnv *env, const char *msg)
7237 {
7238   jclass cl;
7239   cl = (*env)->FindClass (env,
7240                           \"com/redhat/et/libguestfs/LibGuestFSException\");
7241   (*env)->ThrowNew (env, cl, msg);
7242 }
7243
7244 JNIEXPORT jlong JNICALL
7245 Java_com_redhat_et_libguestfs_GuestFS__1create
7246   (JNIEnv *env, jobject obj)
7247 {
7248   guestfs_h *g;
7249
7250   g = guestfs_create ();
7251   if (g == NULL) {
7252     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
7253     return 0;
7254   }
7255   guestfs_set_error_handler (g, NULL, NULL);
7256   return (jlong) (long) g;
7257 }
7258
7259 JNIEXPORT void JNICALL
7260 Java_com_redhat_et_libguestfs_GuestFS__1close
7261   (JNIEnv *env, jobject obj, jlong jg)
7262 {
7263   guestfs_h *g = (guestfs_h *) (long) jg;
7264   guestfs_close (g);
7265 }
7266
7267 ";
7268
7269   List.iter (
7270     fun (name, style, _, _, _, _, _) ->
7271       pr "JNIEXPORT ";
7272       (match fst style with
7273        | RErr -> pr "void ";
7274        | RInt _ -> pr "jint ";
7275        | RInt64 _ -> pr "jlong ";
7276        | RBool _ -> pr "jboolean ";
7277        | RConstString _ | RString _ -> pr "jstring ";
7278        | RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
7279            pr "jobject ";
7280        | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
7281            pr "jobjectArray ";
7282       );
7283       pr "JNICALL\n";
7284       pr "Java_com_redhat_et_libguestfs_GuestFS_";
7285       pr "%s" (replace_str ("_" ^ name) "_" "_1");
7286       pr "\n";
7287       pr "  (JNIEnv *env, jobject obj, jlong jg";
7288       List.iter (
7289         function
7290         | String n
7291         | OptString n
7292         | FileIn n
7293         | FileOut n ->
7294             pr ", jstring j%s" n
7295         | StringList n ->
7296             pr ", jobjectArray j%s" n
7297         | Bool n ->
7298             pr ", jboolean j%s" n
7299         | Int n ->
7300             pr ", jint j%s" n
7301       ) (snd style);
7302       pr ")\n";
7303       pr "{\n";
7304       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
7305       let error_code, no_ret =
7306         match fst style with
7307         | RErr -> pr "  int r;\n"; "-1", ""
7308         | RBool _
7309         | RInt _ -> pr "  int r;\n"; "-1", "0"
7310         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
7311         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
7312         | RString _ ->
7313             pr "  jstring jr;\n";
7314             pr "  char *r;\n"; "NULL", "NULL"
7315         | RStringList _ ->
7316             pr "  jobjectArray jr;\n";
7317             pr "  int r_len;\n";
7318             pr "  jclass cl;\n";
7319             pr "  jstring jstr;\n";
7320             pr "  char **r;\n"; "NULL", "NULL"
7321         | RIntBool _ ->
7322             pr "  jobject jr;\n";
7323             pr "  jclass cl;\n";
7324             pr "  jfieldID fl;\n";
7325             pr "  struct guestfs_int_bool *r;\n"; "NULL", "NULL"
7326         | RStat _ ->
7327             pr "  jobject jr;\n";
7328             pr "  jclass cl;\n";
7329             pr "  jfieldID fl;\n";
7330             pr "  struct guestfs_stat *r;\n"; "NULL", "NULL"
7331         | RStatVFS _ ->
7332             pr "  jobject jr;\n";
7333             pr "  jclass cl;\n";
7334             pr "  jfieldID fl;\n";
7335             pr "  struct guestfs_statvfs *r;\n"; "NULL", "NULL"
7336         | RPVList _ ->
7337             pr "  jobjectArray jr;\n";
7338             pr "  jclass cl;\n";
7339             pr "  jfieldID fl;\n";
7340             pr "  jobject jfl;\n";
7341             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL", "NULL"
7342         | RVGList _ ->
7343             pr "  jobjectArray jr;\n";
7344             pr "  jclass cl;\n";
7345             pr "  jfieldID fl;\n";
7346             pr "  jobject jfl;\n";
7347             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL", "NULL"
7348         | RLVList _ ->
7349             pr "  jobjectArray jr;\n";
7350             pr "  jclass cl;\n";
7351             pr "  jfieldID fl;\n";
7352             pr "  jobject jfl;\n";
7353             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
7354         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL" in
7355       List.iter (
7356         function
7357         | String n
7358         | OptString n
7359         | FileIn n
7360         | FileOut n ->
7361             pr "  const char *%s;\n" n
7362         | StringList n ->
7363             pr "  int %s_len;\n" n;
7364             pr "  const char **%s;\n" n
7365         | Bool n
7366         | Int n ->
7367             pr "  int %s;\n" n
7368       ) (snd style);
7369
7370       let needs_i =
7371         (match fst style with
7372          | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
7373          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
7374          | RString _ | RIntBool _ | RStat _ | RStatVFS _
7375          | RHashtable _ -> false) ||
7376         List.exists (function StringList _ -> true | _ -> false) (snd style) in
7377       if needs_i then
7378         pr "  int i;\n";
7379
7380       pr "\n";
7381
7382       (* Get the parameters. *)
7383       List.iter (
7384         function
7385         | String n
7386         | FileIn n
7387         | FileOut n ->
7388             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
7389         | OptString n ->
7390             (* This is completely undocumented, but Java null becomes
7391              * a NULL parameter.
7392              *)
7393             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
7394         | StringList n ->
7395             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
7396             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
7397             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
7398             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7399               n;
7400             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
7401             pr "  }\n";
7402             pr "  %s[%s_len] = NULL;\n" n n;
7403         | Bool n
7404         | Int n ->
7405             pr "  %s = j%s;\n" n n
7406       ) (snd style);
7407
7408       (* Make the call. *)
7409       pr "  r = guestfs_%s " name;
7410       generate_call_args ~handle:"g" (snd style);
7411       pr ";\n";
7412
7413       (* Release the parameters. *)
7414       List.iter (
7415         function
7416         | String n
7417         | FileIn n
7418         | FileOut n ->
7419             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7420         | OptString n ->
7421             pr "  if (j%s)\n" n;
7422             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7423         | StringList n ->
7424             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
7425             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7426               n;
7427             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
7428             pr "  }\n";
7429             pr "  free (%s);\n" n
7430         | Bool n
7431         | Int n -> ()
7432       ) (snd style);
7433
7434       (* Check for errors. *)
7435       pr "  if (r == %s) {\n" error_code;
7436       pr "    throw_exception (env, guestfs_last_error (g));\n";
7437       pr "    return %s;\n" no_ret;
7438       pr "  }\n";
7439
7440       (* Return value. *)
7441       (match fst style with
7442        | RErr -> ()
7443        | RInt _ -> pr "  return (jint) r;\n"
7444        | RBool _ -> pr "  return (jboolean) r;\n"
7445        | RInt64 _ -> pr "  return (jlong) r;\n"
7446        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
7447        | RString _ ->
7448            pr "  jr = (*env)->NewStringUTF (env, r);\n";
7449            pr "  free (r);\n";
7450            pr "  return jr;\n"
7451        | RStringList _ ->
7452            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7453            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7454            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
7455            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7456            pr "  for (i = 0; i < r_len; ++i) {\n";
7457            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
7458            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7459            pr "    free (r[i]);\n";
7460            pr "  }\n";
7461            pr "  free (r);\n";
7462            pr "  return jr;\n"
7463        | RIntBool _ ->
7464            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/IntBool\");\n";
7465            pr "  jr = (*env)->AllocObject (env, cl);\n";
7466            pr "  fl = (*env)->GetFieldID (env, cl, \"i\", \"I\");\n";
7467            pr "  (*env)->SetIntField (env, jr, fl, r->i);\n";
7468            pr "  fl = (*env)->GetFieldID (env, cl, \"i\", \"Z\");\n";
7469            pr "  (*env)->SetBooleanField (env, jr, fl, r->b);\n";
7470            pr "  guestfs_free_int_bool (r);\n";
7471            pr "  return jr;\n"
7472        | RStat _ ->
7473            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/Stat\");\n";
7474            pr "  jr = (*env)->AllocObject (env, cl);\n";
7475            List.iter (
7476              function
7477              | name, `Int ->
7478                  pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7479                    name;
7480                  pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7481            ) stat_cols;
7482            pr "  free (r);\n";
7483            pr "  return jr;\n"
7484        | RStatVFS _ ->
7485            pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/StatVFS\");\n";
7486            pr "  jr = (*env)->AllocObject (env, cl);\n";
7487            List.iter (
7488              function
7489              | name, `Int ->
7490                  pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n"
7491                    name;
7492                  pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7493            ) statvfs_cols;
7494            pr "  free (r);\n";
7495            pr "  return jr;\n"
7496        | RPVList _ ->
7497            generate_java_lvm_return "pv" "PV" pv_cols
7498        | RVGList _ ->
7499            generate_java_lvm_return "vg" "VG" vg_cols
7500        | RLVList _ ->
7501            generate_java_lvm_return "lv" "LV" lv_cols
7502        | RHashtable _ ->
7503            (* XXX *)
7504            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7505            pr "  return NULL;\n"
7506       );
7507
7508       pr "}\n";
7509       pr "\n"
7510   ) all_functions
7511
7512 and generate_java_lvm_return typ jtyp cols =
7513   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7514   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7515   pr "  for (i = 0; i < r->len; ++i) {\n";
7516   pr "    jfl = (*env)->AllocObject (env, cl);\n";
7517   List.iter (
7518     function
7519     | name, `String ->
7520         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7521         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
7522     | name, `UUID ->
7523         pr "    {\n";
7524         pr "      char s[33];\n";
7525         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
7526         pr "      s[32] = 0;\n";
7527         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7528         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
7529         pr "    }\n";
7530     | name, (`Bytes|`Int) ->
7531         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7532         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
7533     | name, `OptPercent ->
7534         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7535         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
7536   ) cols;
7537   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
7538   pr "  }\n";
7539   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
7540   pr "  return jr;\n"
7541
7542 and generate_haskell_hs () =
7543   generate_header HaskellStyle LGPLv2;
7544
7545   (* XXX We only know how to generate partial FFI for Haskell
7546    * at the moment.  Please help out!
7547    *)
7548   let can_generate style =
7549     match style with
7550     | RErr, _
7551     | RInt _, _
7552     | RInt64 _, _ -> true
7553     | RBool _, _
7554     | RConstString _, _
7555     | RString _, _
7556     | RStringList _, _
7557     | RIntBool _, _
7558     | RPVList _, _
7559     | RVGList _, _
7560     | RLVList _, _
7561     | RStat _, _
7562     | RStatVFS _, _
7563     | RHashtable _, _ -> false in
7564
7565   pr "\
7566 {-# INCLUDE <guestfs.h> #-}
7567 {-# LANGUAGE ForeignFunctionInterface #-}
7568
7569 module Guestfs (
7570   create";
7571
7572   (* List out the names of the actions we want to export. *)
7573   List.iter (
7574     fun (name, style, _, _, _, _, _) ->
7575       if can_generate style then pr ",\n  %s" name
7576   ) all_functions;
7577
7578   pr "
7579   ) where
7580 import Foreign
7581 import Foreign.C
7582 import Foreign.C.Types
7583 import IO
7584 import Control.Exception
7585 import Data.Typeable
7586
7587 data GuestfsS = GuestfsS            -- represents the opaque C struct
7588 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
7589 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
7590
7591 -- XXX define properly later XXX
7592 data PV = PV
7593 data VG = VG
7594 data LV = LV
7595 data IntBool = IntBool
7596 data Stat = Stat
7597 data StatVFS = StatVFS
7598 data Hashtable = Hashtable
7599
7600 foreign import ccall unsafe \"guestfs_create\" c_create
7601   :: IO GuestfsP
7602 foreign import ccall unsafe \"&guestfs_close\" c_close
7603   :: FunPtr (GuestfsP -> IO ())
7604 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
7605   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
7606
7607 create :: IO GuestfsH
7608 create = do
7609   p <- c_create
7610   c_set_error_handler p nullPtr nullPtr
7611   h <- newForeignPtr c_close p
7612   return h
7613
7614 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
7615   :: GuestfsP -> IO CString
7616
7617 -- last_error :: GuestfsH -> IO (Maybe String)
7618 -- last_error h = do
7619 --   str <- withForeignPtr h (\\p -> c_last_error p)
7620 --   maybePeek peekCString str
7621
7622 last_error :: GuestfsH -> IO (String)
7623 last_error h = do
7624   str <- withForeignPtr h (\\p -> c_last_error p)
7625   if (str == nullPtr)
7626     then return \"no error\"
7627     else peekCString str
7628
7629 ";
7630
7631   (* Generate wrappers for each foreign function. *)
7632   List.iter (
7633     fun (name, style, _, _, _, _, _) ->
7634       if can_generate style then (
7635         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
7636         pr "  :: ";
7637         generate_haskell_prototype ~handle:"GuestfsP" style;
7638         pr "\n";
7639         pr "\n";
7640         pr "%s :: " name;
7641         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
7642         pr "\n";
7643         pr "%s %s = do\n" name
7644           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
7645         pr "  r <- ";
7646         (* Convert pointer arguments using with* functions. *)
7647         List.iter (
7648           function
7649           | FileIn n
7650           | FileOut n
7651           | String n -> pr "withCString %s $ \\%s -> " n n
7652           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
7653           | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
7654           | Bool _ | Int _ -> ()
7655         ) (snd style);
7656         (* Convert integer arguments. *)
7657         let args =
7658           List.map (
7659             function
7660             | Bool n -> sprintf "(fromBool %s)" n
7661             | Int n -> sprintf "(fromIntegral %s)" n
7662             | FileIn n | FileOut n | String n | OptString n | StringList n -> n
7663           ) (snd style) in
7664         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
7665           (String.concat " " ("p" :: args));
7666         (match fst style with
7667          | RErr | RInt _ | RInt64 _ | RBool _ ->
7668              pr "  if (r == -1)\n";
7669              pr "    then do\n";
7670              pr "      err <- last_error h\n";
7671              pr "      fail err\n";
7672          | RConstString _ | RString _ | RStringList _ | RIntBool _
7673          | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7674          | RHashtable _ ->
7675              pr "  if (r == nullPtr)\n";
7676              pr "    then do\n";
7677              pr "      err <- last_error h\n";
7678              pr "      fail err\n";
7679         );
7680         (match fst style with
7681          | RErr ->
7682              pr "    else return ()\n"
7683          | RInt _ ->
7684              pr "    else return (fromIntegral r)\n"
7685          | RInt64 _ ->
7686              pr "    else return (fromIntegral r)\n"
7687          | RBool _ ->
7688              pr "    else return (toBool r)\n"
7689          | RConstString _
7690          | RString _
7691          | RStringList _
7692          | RIntBool _
7693          | RPVList _
7694          | RVGList _
7695          | RLVList _
7696          | RStat _
7697          | RStatVFS _
7698          | RHashtable _ ->
7699              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
7700         );
7701         pr "\n";
7702       )
7703   ) all_functions
7704
7705 and generate_haskell_prototype ~handle ?(hs = false) style =
7706   pr "%s -> " handle;
7707   let string = if hs then "String" else "CString" in
7708   let int = if hs then "Int" else "CInt" in
7709   let bool = if hs then "Bool" else "CInt" in
7710   let int64 = if hs then "Integer" else "Int64" in
7711   List.iter (
7712     fun arg ->
7713       (match arg with
7714        | String _ -> pr "%s" string
7715        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
7716        | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
7717        | Bool _ -> pr "%s" bool
7718        | Int _ -> pr "%s" int
7719        | FileIn _ -> pr "%s" string
7720        | FileOut _ -> pr "%s" string
7721       );
7722       pr " -> ";
7723   ) (snd style);
7724   pr "IO (";
7725   (match fst style with
7726    | RErr -> if not hs then pr "CInt"
7727    | RInt _ -> pr "%s" int
7728    | RInt64 _ -> pr "%s" int64
7729    | RBool _ -> pr "%s" bool
7730    | RConstString _ -> pr "%s" string
7731    | RString _ -> pr "%s" string
7732    | RStringList _ -> pr "[%s]" string
7733    | RIntBool _ -> pr "IntBool"
7734    | RPVList _ -> pr "[PV]"
7735    | RVGList _ -> pr "[VG]"
7736    | RLVList _ -> pr "[LV]"
7737    | RStat _ -> pr "Stat"
7738    | RStatVFS _ -> pr "StatVFS"
7739    | RHashtable _ -> pr "Hashtable"
7740   );
7741   pr ")"
7742
7743 and generate_bindtests () =
7744   generate_header CStyle LGPLv2;
7745
7746   pr "\
7747 #include <stdio.h>
7748 #include <stdlib.h>
7749 #include <inttypes.h>
7750 #include <string.h>
7751
7752 #include \"guestfs.h\"
7753 #include \"guestfs_protocol.h\"
7754
7755 #define error guestfs_error
7756
7757 static void
7758 print_strings (char * const* const argv)
7759 {
7760   int argc;
7761
7762   printf (\"[\");
7763   for (argc = 0; argv[argc] != NULL; ++argc) {
7764     if (argc > 0) printf (\", \");
7765     printf (\"\\\"%%s\\\"\", argv[argc]);
7766   }
7767   printf (\"]\\n\");
7768 }
7769
7770 /* The test0 function prints its parameters to stdout. */
7771 ";
7772
7773   let test0, tests =
7774     match test_functions with
7775     | [] -> assert false
7776     | test0 :: tests -> test0, tests in
7777
7778   let () =
7779     let (name, style, _, _, _, _, _) = test0 in
7780     generate_prototype ~extern:false ~semicolon:false ~newline:true
7781       ~handle:"g" ~prefix:"guestfs_" name style;
7782     pr "{\n";
7783     List.iter (
7784       function
7785       | String n
7786       | FileIn n
7787       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
7788       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
7789       | StringList n -> pr "  print_strings (%s);\n" n
7790       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
7791       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
7792     ) (snd style);
7793     pr "  /* Java changes stdout line buffering so we need this: */\n";
7794     pr "  fflush (stdout);\n";
7795     pr "  return 0;\n";
7796     pr "}\n";
7797     pr "\n" in
7798
7799   List.iter (
7800     fun (name, style, _, _, _, _, _) ->
7801       if String.sub name (String.length name - 3) 3 <> "err" then (
7802         pr "/* Test normal return. */\n";
7803         generate_prototype ~extern:false ~semicolon:false ~newline:true
7804           ~handle:"g" ~prefix:"guestfs_" name style;
7805         pr "{\n";
7806         (match fst style with
7807          | RErr ->
7808              pr "  return 0;\n"
7809          | RInt _ ->
7810              pr "  int r;\n";
7811              pr "  sscanf (val, \"%%d\", &r);\n";
7812              pr "  return r;\n"
7813          | RInt64 _ ->
7814              pr "  int64_t r;\n";
7815              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
7816              pr "  return r;\n"
7817          | RBool _ ->
7818              pr "  return strcmp (val, \"true\") == 0;\n"
7819          | RConstString _ ->
7820              (* Can't return the input string here.  Return a static
7821               * string so we ensure we get a segfault if the caller
7822               * tries to free it.
7823               *)
7824              pr "  return \"static string\";\n"
7825          | RString _ ->
7826              pr "  return strdup (val);\n"
7827          | RStringList _ ->
7828              pr "  char **strs;\n";
7829              pr "  int n, i;\n";
7830              pr "  sscanf (val, \"%%d\", &n);\n";
7831              pr "  strs = malloc ((n+1) * sizeof (char *));\n";
7832              pr "  for (i = 0; i < n; ++i) {\n";
7833              pr "    strs[i] = malloc (16);\n";
7834              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
7835              pr "  }\n";
7836              pr "  strs[n] = NULL;\n";
7837              pr "  return strs;\n"
7838          | RIntBool _ ->
7839              pr "  struct guestfs_int_bool *r;\n";
7840              pr "  r = malloc (sizeof (struct guestfs_int_bool));\n";
7841              pr "  sscanf (val, \"%%\" SCNi32, &r->i);\n";
7842              pr "  r->b = 0;\n";
7843              pr "  return r;\n"
7844          | RPVList _ ->
7845              pr "  struct guestfs_lvm_pv_list *r;\n";
7846              pr "  int i;\n";
7847              pr "  r = malloc (sizeof (struct guestfs_lvm_pv_list));\n";
7848              pr "  sscanf (val, \"%%d\", &r->len);\n";
7849              pr "  r->val = calloc (r->len, sizeof (struct guestfs_lvm_pv));\n";
7850              pr "  for (i = 0; i < r->len; ++i) {\n";
7851              pr "    r->val[i].pv_name = malloc (16);\n";
7852              pr "    snprintf (r->val[i].pv_name, 16, \"%%d\", i);\n";
7853              pr "  }\n";
7854              pr "  return r;\n"
7855          | RVGList _ ->
7856              pr "  struct guestfs_lvm_vg_list *r;\n";
7857              pr "  int i;\n";
7858              pr "  r = malloc (sizeof (struct guestfs_lvm_vg_list));\n";
7859              pr "  sscanf (val, \"%%d\", &r->len);\n";
7860              pr "  r->val = calloc (r->len, sizeof (struct guestfs_lvm_vg));\n";
7861              pr "  for (i = 0; i < r->len; ++i) {\n";
7862              pr "    r->val[i].vg_name = malloc (16);\n";
7863              pr "    snprintf (r->val[i].vg_name, 16, \"%%d\", i);\n";
7864              pr "  }\n";
7865              pr "  return r;\n"
7866          | RLVList _ ->
7867              pr "  struct guestfs_lvm_lv_list *r;\n";
7868              pr "  int i;\n";
7869              pr "  r = malloc (sizeof (struct guestfs_lvm_lv_list));\n";
7870              pr "  sscanf (val, \"%%d\", &r->len);\n";
7871              pr "  r->val = calloc (r->len, sizeof (struct guestfs_lvm_lv));\n";
7872              pr "  for (i = 0; i < r->len; ++i) {\n";
7873              pr "    r->val[i].lv_name = malloc (16);\n";
7874              pr "    snprintf (r->val[i].lv_name, 16, \"%%d\", i);\n";
7875              pr "  }\n";
7876              pr "  return r;\n"
7877          | RStat _ ->
7878              pr "  struct guestfs_stat *r;\n";
7879              pr "  r = calloc (1, sizeof (*r));\n";
7880              pr "  sscanf (val, \"%%\" SCNi64, &r->dev);\n";
7881              pr "  return r;\n"
7882          | RStatVFS _ ->
7883              pr "  struct guestfs_statvfs *r;\n";
7884              pr "  r = calloc (1, sizeof (*r));\n";
7885              pr "  sscanf (val, \"%%\" SCNi64, &r->bsize);\n";
7886              pr "  return r;\n"
7887          | RHashtable _ ->
7888              pr "  char **strs;\n";
7889              pr "  int n, i;\n";
7890              pr "  sscanf (val, \"%%d\", &n);\n";
7891              pr "  strs = malloc ((n*2+1) * sizeof (char *));\n";
7892              pr "  for (i = 0; i < n; ++i) {\n";
7893              pr "    strs[i*2] = malloc (16);\n";
7894              pr "    strs[i*2+1] = malloc (16);\n";
7895              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
7896              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
7897              pr "  }\n";
7898              pr "  strs[n*2] = NULL;\n";
7899              pr "  return strs;\n"
7900         );
7901         pr "}\n";
7902         pr "\n"
7903       ) else (
7904         pr "/* Test error return. */\n";
7905         generate_prototype ~extern:false ~semicolon:false ~newline:true
7906           ~handle:"g" ~prefix:"guestfs_" name style;
7907         pr "{\n";
7908         pr "  error (g, \"error\");\n";
7909         (match fst style with
7910          | RErr | RInt _ | RInt64 _ | RBool _ ->
7911              pr "  return -1;\n"
7912          | RConstString _
7913          | RString _ | RStringList _ | RIntBool _
7914          | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
7915          | RHashtable _ ->
7916              pr "  return NULL;\n"
7917         );
7918         pr "}\n";
7919         pr "\n"
7920       )
7921   ) tests
7922
7923 and generate_ocaml_bindtests () =
7924   generate_header OCamlStyle GPLv2;
7925
7926   pr "\
7927 let () =
7928   let g = Guestfs.create () in
7929 ";
7930
7931   let mkargs args =
7932     String.concat " " (
7933       List.map (
7934         function
7935         | CallString s -> "\"" ^ s ^ "\""
7936         | CallOptString None -> "None"
7937         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
7938         | CallStringList xs ->
7939             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
7940         | CallInt i when i >= 0 -> string_of_int i
7941         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
7942         | CallBool b -> string_of_bool b
7943       ) args
7944     )
7945   in
7946
7947   generate_lang_bindtests (
7948     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
7949   );
7950
7951   pr "print_endline \"EOF\"\n"
7952
7953 and generate_perl_bindtests () =
7954   pr "#!/usr/bin/perl -w\n";
7955   generate_header HashStyle GPLv2;
7956
7957   pr "\
7958 use strict;
7959
7960 use Sys::Guestfs;
7961
7962 my $g = Sys::Guestfs->new ();
7963 ";
7964
7965   let mkargs args =
7966     String.concat ", " (
7967       List.map (
7968         function
7969         | CallString s -> "\"" ^ s ^ "\""
7970         | CallOptString None -> "undef"
7971         | CallOptString (Some s) -> sprintf "\"%s\"" s
7972         | CallStringList xs ->
7973             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
7974         | CallInt i -> string_of_int i
7975         | CallBool b -> if b then "1" else "0"
7976       ) args
7977     )
7978   in
7979
7980   generate_lang_bindtests (
7981     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
7982   );
7983
7984   pr "print \"EOF\\n\"\n"
7985
7986 and generate_python_bindtests () =
7987   generate_header HashStyle GPLv2;
7988
7989   pr "\
7990 import guestfs
7991
7992 g = guestfs.GuestFS ()
7993 ";
7994
7995   let mkargs args =
7996     String.concat ", " (
7997       List.map (
7998         function
7999         | CallString s -> "\"" ^ s ^ "\""
8000         | CallOptString None -> "None"
8001         | CallOptString (Some s) -> sprintf "\"%s\"" s
8002         | CallStringList xs ->
8003             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8004         | CallInt i -> string_of_int i
8005         | CallBool b -> if b then "1" else "0"
8006       ) args
8007     )
8008   in
8009
8010   generate_lang_bindtests (
8011     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
8012   );
8013
8014   pr "print \"EOF\"\n"
8015
8016 and generate_ruby_bindtests () =
8017   generate_header HashStyle GPLv2;
8018
8019   pr "\
8020 require 'guestfs'
8021
8022 g = Guestfs::create()
8023 ";
8024
8025   let mkargs args =
8026     String.concat ", " (
8027       List.map (
8028         function
8029         | CallString s -> "\"" ^ s ^ "\""
8030         | CallOptString None -> "nil"
8031         | CallOptString (Some s) -> sprintf "\"%s\"" s
8032         | CallStringList xs ->
8033             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8034         | CallInt i -> string_of_int i
8035         | CallBool b -> string_of_bool b
8036       ) args
8037     )
8038   in
8039
8040   generate_lang_bindtests (
8041     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
8042   );
8043
8044   pr "print \"EOF\\n\"\n"
8045
8046 and generate_java_bindtests () =
8047   generate_header CStyle GPLv2;
8048
8049   pr "\
8050 import com.redhat.et.libguestfs.*;
8051
8052 public class Bindtests {
8053     public static void main (String[] argv)
8054     {
8055         try {
8056             GuestFS g = new GuestFS ();
8057 ";
8058
8059   let mkargs args =
8060     String.concat ", " (
8061       List.map (
8062         function
8063         | CallString s -> "\"" ^ s ^ "\""
8064         | CallOptString None -> "null"
8065         | CallOptString (Some s) -> sprintf "\"%s\"" s
8066         | CallStringList xs ->
8067             "new String[]{" ^
8068               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
8069         | CallInt i -> string_of_int i
8070         | CallBool b -> string_of_bool b
8071       ) args
8072     )
8073   in
8074
8075   generate_lang_bindtests (
8076     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
8077   );
8078
8079   pr "
8080             System.out.println (\"EOF\");
8081         }
8082         catch (Exception exn) {
8083             System.err.println (exn);
8084             System.exit (1);
8085         }
8086     }
8087 }
8088 "
8089
8090 and generate_haskell_bindtests () =
8091   generate_header HaskellStyle GPLv2;
8092
8093   pr "\
8094 module Bindtests where
8095 import qualified Guestfs
8096
8097 main = do
8098   g <- Guestfs.create
8099 ";
8100
8101   let mkargs args =
8102     String.concat " " (
8103       List.map (
8104         function
8105         | CallString s -> "\"" ^ s ^ "\""
8106         | CallOptString None -> "Nothing"
8107         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
8108         | CallStringList xs ->
8109             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8110         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
8111         | CallInt i -> string_of_int i
8112         | CallBool true -> "True"
8113         | CallBool false -> "False"
8114       ) args
8115     )
8116   in
8117
8118   generate_lang_bindtests (
8119     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
8120   );
8121
8122   pr "  putStrLn \"EOF\"\n"
8123
8124 (* Language-independent bindings tests - we do it this way to
8125  * ensure there is parity in testing bindings across all languages.
8126  *)
8127 and generate_lang_bindtests call =
8128   call "test0" [CallString "abc"; CallOptString (Some "def");
8129                 CallStringList []; CallBool false;
8130                 CallInt 0; CallString "123"; CallString "456"];
8131   call "test0" [CallString "abc"; CallOptString None;
8132                 CallStringList []; CallBool false;
8133                 CallInt 0; CallString "123"; CallString "456"];
8134   call "test0" [CallString ""; CallOptString (Some "def");
8135                 CallStringList []; CallBool false;
8136                 CallInt 0; CallString "123"; CallString "456"];
8137   call "test0" [CallString ""; CallOptString (Some "");
8138                 CallStringList []; CallBool false;
8139                 CallInt 0; CallString "123"; CallString "456"];
8140   call "test0" [CallString "abc"; CallOptString (Some "def");
8141                 CallStringList ["1"]; CallBool false;
8142                 CallInt 0; CallString "123"; CallString "456"];
8143   call "test0" [CallString "abc"; CallOptString (Some "def");
8144                 CallStringList ["1"; "2"]; CallBool false;
8145                 CallInt 0; CallString "123"; CallString "456"];
8146   call "test0" [CallString "abc"; CallOptString (Some "def");
8147                 CallStringList ["1"]; CallBool true;
8148                 CallInt 0; CallString "123"; CallString "456"];
8149   call "test0" [CallString "abc"; CallOptString (Some "def");
8150                 CallStringList ["1"]; CallBool false;
8151                 CallInt (-1); CallString "123"; CallString "456"];
8152   call "test0" [CallString "abc"; CallOptString (Some "def");
8153                 CallStringList ["1"]; CallBool false;
8154                 CallInt (-2); CallString "123"; CallString "456"];
8155   call "test0" [CallString "abc"; CallOptString (Some "def");
8156                 CallStringList ["1"]; CallBool false;
8157                 CallInt 1; CallString "123"; CallString "456"];
8158   call "test0" [CallString "abc"; CallOptString (Some "def");
8159                 CallStringList ["1"]; CallBool false;
8160                 CallInt 2; CallString "123"; CallString "456"];
8161   call "test0" [CallString "abc"; CallOptString (Some "def");
8162                 CallStringList ["1"]; CallBool false;
8163                 CallInt 4095; CallString "123"; CallString "456"];
8164   call "test0" [CallString "abc"; CallOptString (Some "def");
8165                 CallStringList ["1"]; CallBool false;
8166                 CallInt 0; CallString ""; CallString ""]
8167
8168   (* XXX Add here tests of the return and error functions. *)
8169
8170 (* This is used to generate the src/MAX_PROC_NR file which
8171  * contains the maximum procedure number, a surrogate for the
8172  * ABI version number.  See src/Makefile.am for the details.
8173  *)
8174 and generate_max_proc_nr () =
8175   let proc_nrs = List.map (
8176     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
8177   ) daemon_functions in
8178
8179   let max_proc_nr = List.fold_left max 0 proc_nrs in
8180
8181   pr "%d\n" max_proc_nr
8182
8183 let output_to filename =
8184   let filename_new = filename ^ ".new" in
8185   chan := open_out filename_new;
8186   let close () =
8187     close_out !chan;
8188     chan := stdout;
8189
8190     (* Is the new file different from the current file? *)
8191     if Sys.file_exists filename && files_equal filename filename_new then
8192       Unix.unlink filename_new          (* same, so skip it *)
8193     else (
8194       (* different, overwrite old one *)
8195       (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
8196       Unix.rename filename_new filename;
8197       Unix.chmod filename 0o444;
8198       printf "written %s\n%!" filename;
8199     )
8200   in
8201   close
8202
8203 (* Main program. *)
8204 let () =
8205   check_functions ();
8206
8207   if not (Sys.file_exists "configure.ac") then (
8208     eprintf "\
8209 You are probably running this from the wrong directory.
8210 Run it from the top source directory using the command
8211   src/generator.ml
8212 ";
8213     exit 1
8214   );
8215
8216   let close = output_to "src/guestfs_protocol.x" in
8217   generate_xdr ();
8218   close ();
8219
8220   let close = output_to "src/guestfs-structs.h" in
8221   generate_structs_h ();
8222   close ();
8223
8224   let close = output_to "src/guestfs-actions.h" in
8225   generate_actions_h ();
8226   close ();
8227
8228   let close = output_to "src/guestfs-actions.c" in
8229   generate_client_actions ();
8230   close ();
8231
8232   let close = output_to "daemon/actions.h" in
8233   generate_daemon_actions_h ();
8234   close ();
8235
8236   let close = output_to "daemon/stubs.c" in
8237   generate_daemon_actions ();
8238   close ();
8239
8240   let close = output_to "capitests/tests.c" in
8241   generate_tests ();
8242   close ();
8243
8244   let close = output_to "src/guestfs-bindtests.c" in
8245   generate_bindtests ();
8246   close ();
8247
8248   let close = output_to "fish/cmds.c" in
8249   generate_fish_cmds ();
8250   close ();
8251
8252   let close = output_to "fish/completion.c" in
8253   generate_fish_completion ();
8254   close ();
8255
8256   let close = output_to "guestfs-structs.pod" in
8257   generate_structs_pod ();
8258   close ();
8259
8260   let close = output_to "guestfs-actions.pod" in
8261   generate_actions_pod ();
8262   close ();
8263
8264   let close = output_to "guestfish-actions.pod" in
8265   generate_fish_actions_pod ();
8266   close ();
8267
8268   let close = output_to "ocaml/guestfs.mli" in
8269   generate_ocaml_mli ();
8270   close ();
8271
8272   let close = output_to "ocaml/guestfs.ml" in
8273   generate_ocaml_ml ();
8274   close ();
8275
8276   let close = output_to "ocaml/guestfs_c_actions.c" in
8277   generate_ocaml_c ();
8278   close ();
8279
8280   let close = output_to "ocaml/bindtests.ml" in
8281   generate_ocaml_bindtests ();
8282   close ();
8283
8284   let close = output_to "perl/Guestfs.xs" in
8285   generate_perl_xs ();
8286   close ();
8287
8288   let close = output_to "perl/lib/Sys/Guestfs.pm" in
8289   generate_perl_pm ();
8290   close ();
8291
8292   let close = output_to "perl/bindtests.pl" in
8293   generate_perl_bindtests ();
8294   close ();
8295
8296   let close = output_to "python/guestfs-py.c" in
8297   generate_python_c ();
8298   close ();
8299
8300   let close = output_to "python/guestfs.py" in
8301   generate_python_py ();
8302   close ();
8303
8304   let close = output_to "python/bindtests.py" in
8305   generate_python_bindtests ();
8306   close ();
8307
8308   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
8309   generate_ruby_c ();
8310   close ();
8311
8312   let close = output_to "ruby/bindtests.rb" in
8313   generate_ruby_bindtests ();
8314   close ();
8315
8316   let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
8317   generate_java_java ();
8318   close ();
8319
8320   let close = output_to "java/com/redhat/et/libguestfs/PV.java" in
8321   generate_java_struct "PV" pv_cols;
8322   close ();
8323
8324   let close = output_to "java/com/redhat/et/libguestfs/VG.java" in
8325   generate_java_struct "VG" vg_cols;
8326   close ();
8327
8328   let close = output_to "java/com/redhat/et/libguestfs/LV.java" in
8329   generate_java_struct "LV" lv_cols;
8330   close ();
8331
8332   let close = output_to "java/com/redhat/et/libguestfs/Stat.java" in
8333   generate_java_struct "Stat" stat_cols;
8334   close ();
8335
8336   let close = output_to "java/com/redhat/et/libguestfs/StatVFS.java" in
8337   generate_java_struct "StatVFS" statvfs_cols;
8338   close ();
8339
8340   let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
8341   generate_java_c ();
8342   close ();
8343
8344   let close = output_to "java/Bindtests.java" in
8345   generate_java_bindtests ();
8346   close ();
8347
8348   let close = output_to "haskell/Guestfs.hs" in
8349   generate_haskell_hs ();
8350   close ();
8351
8352   let close = output_to "haskell/Bindtests.hs" in
8353   generate_haskell_bindtests ();
8354   close ();
8355
8356   let close = output_to "src/MAX_PROC_NR" in
8357   generate_max_proc_nr ();
8358   close ();