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