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