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