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