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