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