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