update generator to emit each RESOLVE_DEVICE call
[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, [String "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, [String "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"; String "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, [String "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, [String "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, [String "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", [String "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", [String "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", [String "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, [String "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", [String "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", [String "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, [String "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, [String "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, [String "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"; String "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"; String "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, [String "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, [String "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, [String "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", [String "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, [String "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", [String "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"; String "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, [String "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"; String "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, [String "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, [String "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, [String "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", [String "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", [String "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", [String "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, [String "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, [String "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, [String "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"; String "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, [String "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, [String "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"; String "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"; String "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, [String "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, [String "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, [String "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                (* Note we allow the string to be writable, in order to
4729                 * allow device name translation.  This is safe because
4730                 * we can modify the string (passed from RPC).
4731                 *)
4732              | Device n | String n
4733              | OptString n -> pr "  char *%s;\n" n
4734              | StringList n -> pr "  char **%s;\n" n
4735              | Bool n -> pr "  int %s;\n" n
4736              | Int n -> pr "  int %s;\n" n
4737              | FileIn _ | FileOut _ -> ()
4738            ) args
4739       );
4740       pr "\n";
4741
4742       (match snd style with
4743        | [] -> ()
4744        | args ->
4745            pr "  memset (&args, 0, sizeof args);\n";
4746            pr "\n";
4747            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4748            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4749            pr "    return;\n";
4750            pr "  }\n";
4751            List.iter (
4752              function
4753              | Device n ->
4754                  pr "  %s = args.%s;\n" n n;
4755                  pr "  RESOLVE_DEVICE (%s, goto done);" n;
4756              | String n -> pr "  %s = args.%s;\n" n n
4757              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
4758              | StringList n ->
4759                  pr "  %s = realloc (args.%s.%s_val,\n" n n n;
4760                  pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4761                  pr "  if (%s == NULL) {\n" n;
4762                  pr "    reply_with_perror (\"realloc\");\n";
4763                  pr "    goto done;\n";
4764                  pr "  }\n";
4765                  pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
4766                  pr "  args.%s.%s_val = %s;\n" n n n;
4767              | Bool n -> pr "  %s = args.%s;\n" n n
4768              | Int n -> pr "  %s = args.%s;\n" n n
4769              | FileIn _ | FileOut _ -> ()
4770            ) args;
4771            pr "\n"
4772       );
4773
4774       (* Don't want to call the impl with any FileIn or FileOut
4775        * parameters, since these go "outside" the RPC protocol.
4776        *)
4777       let args' =
4778         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
4779           (snd style) in
4780       pr "  r = do_%s " name;
4781       generate_c_call_args (fst style, args');
4782       pr ";\n";
4783
4784       pr "  if (r == %s)\n" error_code;
4785       pr "    /* do_%s has already called reply_with_error */\n" name;
4786       pr "    goto done;\n";
4787       pr "\n";
4788
4789       (* If there are any FileOut parameters, then the impl must
4790        * send its own reply.
4791        *)
4792       let no_reply =
4793         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
4794       if no_reply then
4795         pr "  /* do_%s has already sent a reply */\n" name
4796       else (
4797         match fst style with
4798         | RErr -> pr "  reply (NULL, NULL);\n"
4799         | RInt n | RInt64 n | RBool n ->
4800             pr "  struct guestfs_%s_ret ret;\n" name;
4801             pr "  ret.%s = r;\n" n;
4802             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4803               name
4804         | RConstString _ | RConstOptString _ ->
4805             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4806         | RString n ->
4807             pr "  struct guestfs_%s_ret ret;\n" name;
4808             pr "  ret.%s = r;\n" n;
4809             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4810               name;
4811             pr "  free (r);\n"
4812         | RStringList n | RHashtable n ->
4813             pr "  struct guestfs_%s_ret ret;\n" name;
4814             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
4815             pr "  ret.%s.%s_val = r;\n" n n;
4816             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4817               name;
4818             pr "  free_strings (r);\n"
4819         | RStruct (n, _) ->
4820             pr "  struct guestfs_%s_ret ret;\n" name;
4821             pr "  ret.%s = *r;\n" n;
4822             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4823               name;
4824             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4825               name
4826         | RStructList (n, _) ->
4827             pr "  struct guestfs_%s_ret ret;\n" name;
4828             pr "  ret.%s = *r;\n" n;
4829             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4830               name;
4831             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4832               name
4833         | RBufferOut n ->
4834             pr "  struct guestfs_%s_ret ret;\n" name;
4835             pr "  ret.%s.%s_val = r;\n" n n;
4836             pr "  ret.%s.%s_len = size;\n" n n;
4837             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4838               name;
4839             pr "  free (r);\n"
4840       );
4841
4842       (* Free the args. *)
4843       (match snd style with
4844        | [] ->
4845            pr "done: ;\n";
4846        | _ ->
4847            pr "done:\n";
4848            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4849              name
4850       );
4851
4852       pr "}\n\n";
4853   ) daemon_functions;
4854
4855   (* Dispatch function. *)
4856   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4857   pr "{\n";
4858   pr "  switch (proc_nr) {\n";
4859
4860   List.iter (
4861     fun (name, style, _, _, _, _, _) ->
4862       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
4863       pr "      %s_stub (xdr_in);\n" name;
4864       pr "      break;\n"
4865   ) daemon_functions;
4866
4867   pr "    default:\n";
4868   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";
4869   pr "  }\n";
4870   pr "}\n";
4871   pr "\n";
4872
4873   (* LVM columns and tokenization functions. *)
4874   (* XXX This generates crap code.  We should rethink how we
4875    * do this parsing.
4876    *)
4877   List.iter (
4878     function
4879     | typ, cols ->
4880         pr "static const char *lvm_%s_cols = \"%s\";\n"
4881           typ (String.concat "," (List.map fst cols));
4882         pr "\n";
4883
4884         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
4885         pr "{\n";
4886         pr "  char *tok, *p, *next;\n";
4887         pr "  int i, j;\n";
4888         pr "\n";
4889         (*
4890           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4891           pr "\n";
4892         *)
4893         pr "  if (!str) {\n";
4894         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4895         pr "    return -1;\n";
4896         pr "  }\n";
4897         pr "  if (!*str || isspace (*str)) {\n";
4898         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4899         pr "    return -1;\n";
4900         pr "  }\n";
4901         pr "  tok = str;\n";
4902         List.iter (
4903           fun (name, coltype) ->
4904             pr "  if (!tok) {\n";
4905             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4906             pr "    return -1;\n";
4907             pr "  }\n";
4908             pr "  p = strchrnul (tok, ',');\n";
4909             pr "  if (*p) next = p+1; else next = NULL;\n";
4910             pr "  *p = '\\0';\n";
4911             (match coltype with
4912              | FString ->
4913                  pr "  r->%s = strdup (tok);\n" name;
4914                  pr "  if (r->%s == NULL) {\n" name;
4915                  pr "    perror (\"strdup\");\n";
4916                  pr "    return -1;\n";
4917                  pr "  }\n"
4918              | FUUID ->
4919                  pr "  for (i = j = 0; i < 32; ++j) {\n";
4920                  pr "    if (tok[j] == '\\0') {\n";
4921                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4922                  pr "      return -1;\n";
4923                  pr "    } else if (tok[j] != '-')\n";
4924                  pr "      r->%s[i++] = tok[j];\n" name;
4925                  pr "  }\n";
4926              | FBytes ->
4927                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4928                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4929                  pr "    return -1;\n";
4930                  pr "  }\n";
4931              | FInt64 ->
4932                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4933                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4934                  pr "    return -1;\n";
4935                  pr "  }\n";
4936              | FOptPercent ->
4937                  pr "  if (tok[0] == '\\0')\n";
4938                  pr "    r->%s = -1;\n" name;
4939                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4940                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4941                  pr "    return -1;\n";
4942                  pr "  }\n";
4943              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
4944                  assert false (* can never be an LVM column *)
4945             );
4946             pr "  tok = next;\n";
4947         ) cols;
4948
4949         pr "  if (tok != NULL) {\n";
4950         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4951         pr "    return -1;\n";
4952         pr "  }\n";
4953         pr "  return 0;\n";
4954         pr "}\n";
4955         pr "\n";
4956
4957         pr "guestfs_int_lvm_%s_list *\n" typ;
4958         pr "parse_command_line_%ss (void)\n" typ;
4959         pr "{\n";
4960         pr "  char *out, *err;\n";
4961         pr "  char *p, *pend;\n";
4962         pr "  int r, i;\n";
4963         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
4964         pr "  void *newp;\n";
4965         pr "\n";
4966         pr "  ret = malloc (sizeof *ret);\n";
4967         pr "  if (!ret) {\n";
4968         pr "    reply_with_perror (\"malloc\");\n";
4969         pr "    return NULL;\n";
4970         pr "  }\n";
4971         pr "\n";
4972         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
4973         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
4974         pr "\n";
4975         pr "  r = command (&out, &err,\n";
4976         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
4977         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4978         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4979         pr "  if (r == -1) {\n";
4980         pr "    reply_with_error (\"%%s\", err);\n";
4981         pr "    free (out);\n";
4982         pr "    free (err);\n";
4983         pr "    free (ret);\n";
4984         pr "    return NULL;\n";
4985         pr "  }\n";
4986         pr "\n";
4987         pr "  free (err);\n";
4988         pr "\n";
4989         pr "  /* Tokenize each line of the output. */\n";
4990         pr "  p = out;\n";
4991         pr "  i = 0;\n";
4992         pr "  while (p) {\n";
4993         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
4994         pr "    if (pend) {\n";
4995         pr "      *pend = '\\0';\n";
4996         pr "      pend++;\n";
4997         pr "    }\n";
4998         pr "\n";
4999         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
5000         pr "      p++;\n";
5001         pr "\n";
5002         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
5003         pr "      p = pend;\n";
5004         pr "      continue;\n";
5005         pr "    }\n";
5006         pr "\n";
5007         pr "    /* Allocate some space to store this next entry. */\n";
5008         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
5009         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
5010         pr "    if (newp == NULL) {\n";
5011         pr "      reply_with_perror (\"realloc\");\n";
5012         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5013         pr "      free (ret);\n";
5014         pr "      free (out);\n";
5015         pr "      return NULL;\n";
5016         pr "    }\n";
5017         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
5018         pr "\n";
5019         pr "    /* Tokenize the next entry. */\n";
5020         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
5021         pr "    if (r == -1) {\n";
5022         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
5023         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5024         pr "      free (ret);\n";
5025         pr "      free (out);\n";
5026         pr "      return NULL;\n";
5027         pr "    }\n";
5028         pr "\n";
5029         pr "    ++i;\n";
5030         pr "    p = pend;\n";
5031         pr "  }\n";
5032         pr "\n";
5033         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
5034         pr "\n";
5035         pr "  free (out);\n";
5036         pr "  return ret;\n";
5037         pr "}\n"
5038
5039   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
5040
5041 (* Generate a list of function names, for debugging in the daemon.. *)
5042 and generate_daemon_names () =
5043   generate_header CStyle GPLv2;
5044
5045   pr "#include <config.h>\n";
5046   pr "\n";
5047   pr "#include \"daemon.h\"\n";
5048   pr "\n";
5049
5050   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
5051   pr "const char *function_names[] = {\n";
5052   List.iter (
5053     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
5054   ) daemon_functions;
5055   pr "};\n";
5056
5057 (* Generate the tests. *)
5058 and generate_tests () =
5059   generate_header CStyle GPLv2;
5060
5061   pr "\
5062 #include <stdio.h>
5063 #include <stdlib.h>
5064 #include <string.h>
5065 #include <unistd.h>
5066 #include <sys/types.h>
5067 #include <fcntl.h>
5068
5069 #include \"guestfs.h\"
5070
5071 static guestfs_h *g;
5072 static int suppress_error = 0;
5073
5074 static void print_error (guestfs_h *g, void *data, const char *msg)
5075 {
5076   if (!suppress_error)
5077     fprintf (stderr, \"%%s\\n\", msg);
5078 }
5079
5080 static void print_strings (char * const * const argv)
5081 {
5082   int argc;
5083
5084   for (argc = 0; argv[argc] != NULL; ++argc)
5085     printf (\"\\t%%s\\n\", argv[argc]);
5086 }
5087
5088 /*
5089 static void print_table (char * const * const argv)
5090 {
5091   int i;
5092
5093   for (i = 0; argv[i] != NULL; i += 2)
5094     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
5095 }
5096 */
5097
5098 ";
5099
5100   (* Generate a list of commands which are not tested anywhere. *)
5101   pr "static void no_test_warnings (void)\n";
5102   pr "{\n";
5103
5104   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
5105   List.iter (
5106     fun (_, _, _, _, tests, _, _) ->
5107       let tests = filter_map (
5108         function
5109         | (_, (Always|If _|Unless _), test) -> Some test
5110         | (_, Disabled, _) -> None
5111       ) tests in
5112       let seq = List.concat (List.map seq_of_test tests) in
5113       let cmds_tested = List.map List.hd seq in
5114       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
5115   ) all_functions;
5116
5117   List.iter (
5118     fun (name, _, _, _, _, _, _) ->
5119       if not (Hashtbl.mem hash name) then
5120         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
5121   ) all_functions;
5122
5123   pr "}\n";
5124   pr "\n";
5125
5126   (* Generate the actual tests.  Note that we generate the tests
5127    * in reverse order, deliberately, so that (in general) the
5128    * newest tests run first.  This makes it quicker and easier to
5129    * debug them.
5130    *)
5131   let test_names =
5132     List.map (
5133       fun (name, _, _, _, tests, _, _) ->
5134         mapi (generate_one_test name) tests
5135     ) (List.rev all_functions) in
5136   let test_names = List.concat test_names in
5137   let nr_tests = List.length test_names in
5138
5139   pr "\
5140 int main (int argc, char *argv[])
5141 {
5142   char c = 0;
5143   int failed = 0;
5144   const char *filename;
5145   int fd;
5146   int nr_tests, test_num = 0;
5147
5148   setbuf (stdout, NULL);
5149
5150   no_test_warnings ();
5151
5152   g = guestfs_create ();
5153   if (g == NULL) {
5154     printf (\"guestfs_create FAILED\\n\");
5155     exit (1);
5156   }
5157
5158   guestfs_set_error_handler (g, print_error, NULL);
5159
5160   guestfs_set_path (g, \"../appliance\");
5161
5162   filename = \"test1.img\";
5163   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5164   if (fd == -1) {
5165     perror (filename);
5166     exit (1);
5167   }
5168   if (lseek (fd, %d, SEEK_SET) == -1) {
5169     perror (\"lseek\");
5170     close (fd);
5171     unlink (filename);
5172     exit (1);
5173   }
5174   if (write (fd, &c, 1) == -1) {
5175     perror (\"write\");
5176     close (fd);
5177     unlink (filename);
5178     exit (1);
5179   }
5180   if (close (fd) == -1) {
5181     perror (filename);
5182     unlink (filename);
5183     exit (1);
5184   }
5185   if (guestfs_add_drive (g, filename) == -1) {
5186     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5187     exit (1);
5188   }
5189
5190   filename = \"test2.img\";
5191   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5192   if (fd == -1) {
5193     perror (filename);
5194     exit (1);
5195   }
5196   if (lseek (fd, %d, SEEK_SET) == -1) {
5197     perror (\"lseek\");
5198     close (fd);
5199     unlink (filename);
5200     exit (1);
5201   }
5202   if (write (fd, &c, 1) == -1) {
5203     perror (\"write\");
5204     close (fd);
5205     unlink (filename);
5206     exit (1);
5207   }
5208   if (close (fd) == -1) {
5209     perror (filename);
5210     unlink (filename);
5211     exit (1);
5212   }
5213   if (guestfs_add_drive (g, filename) == -1) {
5214     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5215     exit (1);
5216   }
5217
5218   filename = \"test3.img\";
5219   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5220   if (fd == -1) {
5221     perror (filename);
5222     exit (1);
5223   }
5224   if (lseek (fd, %d, SEEK_SET) == -1) {
5225     perror (\"lseek\");
5226     close (fd);
5227     unlink (filename);
5228     exit (1);
5229   }
5230   if (write (fd, &c, 1) == -1) {
5231     perror (\"write\");
5232     close (fd);
5233     unlink (filename);
5234     exit (1);
5235   }
5236   if (close (fd) == -1) {
5237     perror (filename);
5238     unlink (filename);
5239     exit (1);
5240   }
5241   if (guestfs_add_drive (g, filename) == -1) {
5242     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5243     exit (1);
5244   }
5245
5246   if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
5247     printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
5248     exit (1);
5249   }
5250
5251   if (guestfs_launch (g) == -1) {
5252     printf (\"guestfs_launch FAILED\\n\");
5253     exit (1);
5254   }
5255
5256   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
5257   alarm (600);
5258
5259   if (guestfs_wait_ready (g) == -1) {
5260     printf (\"guestfs_wait_ready FAILED\\n\");
5261     exit (1);
5262   }
5263
5264   /* Cancel previous alarm. */
5265   alarm (0);
5266
5267   nr_tests = %d;
5268
5269 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
5270
5271   iteri (
5272     fun i test_name ->
5273       pr "  test_num++;\n";
5274       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
5275       pr "  if (%s () == -1) {\n" test_name;
5276       pr "    printf (\"%s FAILED\\n\");\n" test_name;
5277       pr "    failed++;\n";
5278       pr "  }\n";
5279   ) test_names;
5280   pr "\n";
5281
5282   pr "  guestfs_close (g);\n";
5283   pr "  unlink (\"test1.img\");\n";
5284   pr "  unlink (\"test2.img\");\n";
5285   pr "  unlink (\"test3.img\");\n";
5286   pr "\n";
5287
5288   pr "  if (failed > 0) {\n";
5289   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
5290   pr "    exit (1);\n";
5291   pr "  }\n";
5292   pr "\n";
5293
5294   pr "  exit (0);\n";
5295   pr "}\n"
5296
5297 and generate_one_test name i (init, prereq, test) =
5298   let test_name = sprintf "test_%s_%d" name i in
5299
5300   pr "\
5301 static int %s_skip (void)
5302 {
5303   const char *str;
5304
5305   str = getenv (\"TEST_ONLY\");
5306   if (str)
5307     return strstr (str, \"%s\") == NULL;
5308   str = getenv (\"SKIP_%s\");
5309   if (str && strcmp (str, \"1\") == 0) return 1;
5310   str = getenv (\"SKIP_TEST_%s\");
5311   if (str && strcmp (str, \"1\") == 0) return 1;
5312   return 0;
5313 }
5314
5315 " test_name name (String.uppercase test_name) (String.uppercase name);
5316
5317   (match prereq with
5318    | Disabled | Always -> ()
5319    | If code | Unless code ->
5320        pr "static int %s_prereq (void)\n" test_name;
5321        pr "{\n";
5322        pr "  %s\n" code;
5323        pr "}\n";
5324        pr "\n";
5325   );
5326
5327   pr "\
5328 static int %s (void)
5329 {
5330   if (%s_skip ()) {
5331     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
5332     return 0;
5333   }
5334
5335 " test_name test_name test_name;
5336
5337   (match prereq with
5338    | Disabled ->
5339        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
5340    | If _ ->
5341        pr "  if (! %s_prereq ()) {\n" test_name;
5342        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5343        pr "    return 0;\n";
5344        pr "  }\n";
5345        pr "\n";
5346        generate_one_test_body name i test_name init test;
5347    | Unless _ ->
5348        pr "  if (%s_prereq ()) {\n" test_name;
5349        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5350        pr "    return 0;\n";
5351        pr "  }\n";
5352        pr "\n";
5353        generate_one_test_body name i test_name init test;
5354    | Always ->
5355        generate_one_test_body name i test_name init test
5356   );
5357
5358   pr "  return 0;\n";
5359   pr "}\n";
5360   pr "\n";
5361   test_name
5362
5363 and generate_one_test_body name i test_name init test =
5364   (match init with
5365    | InitNone (* XXX at some point, InitNone and InitEmpty became
5366                * folded together as the same thing.  Really we should
5367                * make InitNone do nothing at all, but the tests may
5368                * need to be checked to make sure this is OK.
5369                *)
5370    | InitEmpty ->
5371        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
5372        List.iter (generate_test_command_call test_name)
5373          [["blockdev_setrw"; "/dev/sda"];
5374           ["umount_all"];
5375           ["lvm_remove_all"]]
5376    | InitPartition ->
5377        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
5378        List.iter (generate_test_command_call test_name)
5379          [["blockdev_setrw"; "/dev/sda"];
5380           ["umount_all"];
5381           ["lvm_remove_all"];
5382           ["sfdiskM"; "/dev/sda"; ","]]
5383    | InitBasicFS ->
5384        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
5385        List.iter (generate_test_command_call test_name)
5386          [["blockdev_setrw"; "/dev/sda"];
5387           ["umount_all"];
5388           ["lvm_remove_all"];
5389           ["sfdiskM"; "/dev/sda"; ","];
5390           ["mkfs"; "ext2"; "/dev/sda1"];
5391           ["mount"; "/dev/sda1"; "/"]]
5392    | InitBasicFSonLVM ->
5393        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
5394          test_name;
5395        List.iter (generate_test_command_call test_name)
5396          [["blockdev_setrw"; "/dev/sda"];
5397           ["umount_all"];
5398           ["lvm_remove_all"];
5399           ["sfdiskM"; "/dev/sda"; ","];
5400           ["pvcreate"; "/dev/sda1"];
5401           ["vgcreate"; "VG"; "/dev/sda1"];
5402           ["lvcreate"; "LV"; "VG"; "8"];
5403           ["mkfs"; "ext2"; "/dev/VG/LV"];
5404           ["mount"; "/dev/VG/LV"; "/"]]
5405    | InitSquashFS ->
5406        pr "  /* InitSquashFS for %s */\n" test_name;
5407        List.iter (generate_test_command_call test_name)
5408          [["blockdev_setrw"; "/dev/sda"];
5409           ["umount_all"];
5410           ["lvm_remove_all"];
5411           ["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"]]
5412   );
5413
5414   let get_seq_last = function
5415     | [] ->
5416         failwithf "%s: you cannot use [] (empty list) when expecting a command"
5417           test_name
5418     | seq ->
5419         let seq = List.rev seq in
5420         List.rev (List.tl seq), List.hd seq
5421   in
5422
5423   match test with
5424   | TestRun seq ->
5425       pr "  /* TestRun for %s (%d) */\n" name i;
5426       List.iter (generate_test_command_call test_name) seq
5427   | TestOutput (seq, expected) ->
5428       pr "  /* TestOutput for %s (%d) */\n" name i;
5429       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5430       let seq, last = get_seq_last seq in
5431       let test () =
5432         pr "    if (strcmp (r, expected) != 0) {\n";
5433         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5434         pr "      return -1;\n";
5435         pr "    }\n"
5436       in
5437       List.iter (generate_test_command_call test_name) seq;
5438       generate_test_command_call ~test test_name last
5439   | TestOutputList (seq, expected) ->
5440       pr "  /* TestOutputList for %s (%d) */\n" name i;
5441       let seq, last = get_seq_last seq in
5442       let test () =
5443         iteri (
5444           fun i str ->
5445             pr "    if (!r[%d]) {\n" i;
5446             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5447             pr "      print_strings (r);\n";
5448             pr "      return -1;\n";
5449             pr "    }\n";
5450             pr "    {\n";
5451             pr "      const char *expected = \"%s\";\n" (c_quote str);
5452             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5453             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5454             pr "        return -1;\n";
5455             pr "      }\n";
5456             pr "    }\n"
5457         ) expected;
5458         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5459         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5460           test_name;
5461         pr "      print_strings (r);\n";
5462         pr "      return -1;\n";
5463         pr "    }\n"
5464       in
5465       List.iter (generate_test_command_call test_name) seq;
5466       generate_test_command_call ~test test_name last
5467   | TestOutputListOfDevices (seq, expected) ->
5468       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
5469       let seq, last = get_seq_last seq in
5470       let test () =
5471         iteri (
5472           fun i str ->
5473             pr "    if (!r[%d]) {\n" i;
5474             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5475             pr "      print_strings (r);\n";
5476             pr "      return -1;\n";
5477             pr "    }\n";
5478             pr "    {\n";
5479             pr "      const char *expected = \"%s\";\n" (c_quote str);
5480             pr "      r[%d][5] = 's';\n" i;
5481             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5482             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5483             pr "        return -1;\n";
5484             pr "      }\n";
5485             pr "    }\n"
5486         ) expected;
5487         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5488         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5489           test_name;
5490         pr "      print_strings (r);\n";
5491         pr "      return -1;\n";
5492         pr "    }\n"
5493       in
5494       List.iter (generate_test_command_call test_name) seq;
5495       generate_test_command_call ~test test_name last
5496   | TestOutputInt (seq, expected) ->
5497       pr "  /* TestOutputInt for %s (%d) */\n" name i;
5498       let seq, last = get_seq_last seq in
5499       let test () =
5500         pr "    if (r != %d) {\n" expected;
5501         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
5502           test_name expected;
5503         pr "               (int) r);\n";
5504         pr "      return -1;\n";
5505         pr "    }\n"
5506       in
5507       List.iter (generate_test_command_call test_name) seq;
5508       generate_test_command_call ~test test_name last
5509   | TestOutputIntOp (seq, op, expected) ->
5510       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
5511       let seq, last = get_seq_last seq in
5512       let test () =
5513         pr "    if (! (r %s %d)) {\n" op expected;
5514         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
5515           test_name op expected;
5516         pr "               (int) r);\n";
5517         pr "      return -1;\n";
5518         pr "    }\n"
5519       in
5520       List.iter (generate_test_command_call test_name) seq;
5521       generate_test_command_call ~test test_name last
5522   | TestOutputTrue seq ->
5523       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
5524       let seq, last = get_seq_last seq in
5525       let test () =
5526         pr "    if (!r) {\n";
5527         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
5528           test_name;
5529         pr "      return -1;\n";
5530         pr "    }\n"
5531       in
5532       List.iter (generate_test_command_call test_name) seq;
5533       generate_test_command_call ~test test_name last
5534   | TestOutputFalse seq ->
5535       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
5536       let seq, last = get_seq_last seq in
5537       let test () =
5538         pr "    if (r) {\n";
5539         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
5540           test_name;
5541         pr "      return -1;\n";
5542         pr "    }\n"
5543       in
5544       List.iter (generate_test_command_call test_name) seq;
5545       generate_test_command_call ~test test_name last
5546   | TestOutputLength (seq, expected) ->
5547       pr "  /* TestOutputLength for %s (%d) */\n" name i;
5548       let seq, last = get_seq_last seq in
5549       let test () =
5550         pr "    int j;\n";
5551         pr "    for (j = 0; j < %d; ++j)\n" expected;
5552         pr "      if (r[j] == NULL) {\n";
5553         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
5554           test_name;
5555         pr "        print_strings (r);\n";
5556         pr "        return -1;\n";
5557         pr "      }\n";
5558         pr "    if (r[j] != NULL) {\n";
5559         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
5560           test_name;
5561         pr "      print_strings (r);\n";
5562         pr "      return -1;\n";
5563         pr "    }\n"
5564       in
5565       List.iter (generate_test_command_call test_name) seq;
5566       generate_test_command_call ~test test_name last
5567   | TestOutputBuffer (seq, expected) ->
5568       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
5569       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5570       let seq, last = get_seq_last seq in
5571       let len = String.length expected in
5572       let test () =
5573         pr "    if (size != %d) {\n" len;
5574         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
5575         pr "      return -1;\n";
5576         pr "    }\n";
5577         pr "    if (strncmp (r, expected, size) != 0) {\n";
5578         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5579         pr "      return -1;\n";
5580         pr "    }\n"
5581       in
5582       List.iter (generate_test_command_call test_name) seq;
5583       generate_test_command_call ~test test_name last
5584   | TestOutputStruct (seq, checks) ->
5585       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
5586       let seq, last = get_seq_last seq in
5587       let test () =
5588         List.iter (
5589           function
5590           | CompareWithInt (field, expected) ->
5591               pr "    if (r->%s != %d) {\n" field expected;
5592               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
5593                 test_name field expected;
5594               pr "               (int) r->%s);\n" field;
5595               pr "      return -1;\n";
5596               pr "    }\n"
5597           | CompareWithIntOp (field, op, expected) ->
5598               pr "    if (!(r->%s %s %d)) {\n" field op expected;
5599               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
5600                 test_name field op expected;
5601               pr "               (int) r->%s);\n" field;
5602               pr "      return -1;\n";
5603               pr "    }\n"
5604           | CompareWithString (field, expected) ->
5605               pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
5606               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
5607                 test_name field expected;
5608               pr "               r->%s);\n" field;
5609               pr "      return -1;\n";
5610               pr "    }\n"
5611           | CompareFieldsIntEq (field1, field2) ->
5612               pr "    if (r->%s != r->%s) {\n" field1 field2;
5613               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
5614                 test_name field1 field2;
5615               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
5616               pr "      return -1;\n";
5617               pr "    }\n"
5618           | CompareFieldsStrEq (field1, field2) ->
5619               pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
5620               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
5621                 test_name field1 field2;
5622               pr "               r->%s, r->%s);\n" field1 field2;
5623               pr "      return -1;\n";
5624               pr "    }\n"
5625         ) checks
5626       in
5627       List.iter (generate_test_command_call test_name) seq;
5628       generate_test_command_call ~test test_name last
5629   | TestLastFail seq ->
5630       pr "  /* TestLastFail for %s (%d) */\n" name i;
5631       let seq, last = get_seq_last seq in
5632       List.iter (generate_test_command_call test_name) seq;
5633       generate_test_command_call test_name ~expect_error:true last
5634
5635 (* Generate the code to run a command, leaving the result in 'r'.
5636  * If you expect to get an error then you should set expect_error:true.
5637  *)
5638 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
5639   match cmd with
5640   | [] -> assert false
5641   | name :: args ->
5642       (* Look up the command to find out what args/ret it has. *)
5643       let style =
5644         try
5645           let _, style, _, _, _, _, _ =
5646             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
5647           style
5648         with Not_found ->
5649           failwithf "%s: in test, command %s was not found" test_name name in
5650
5651       if List.length (snd style) <> List.length args then
5652         failwithf "%s: in test, wrong number of args given to %s"
5653           test_name name;
5654
5655       pr "  {\n";
5656
5657       List.iter (
5658         function
5659         | OptString n, "NULL" -> ()
5660         | Device n, arg
5661         | String n, arg
5662         | OptString n, arg ->
5663             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
5664         | Int _, _
5665         | Bool _, _
5666         | FileIn _, _ | FileOut _, _ -> ()
5667         | StringList n, arg ->
5668             let strs = string_split " " arg in
5669             iteri (
5670               fun i str ->
5671                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
5672             ) strs;
5673             pr "    const char *%s[] = {\n" n;
5674             iteri (
5675               fun i _ -> pr "      %s_%d,\n" n i
5676             ) strs;
5677             pr "      NULL\n";
5678             pr "    };\n";
5679       ) (List.combine (snd style) args);
5680
5681       let error_code =
5682         match fst style with
5683         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
5684         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
5685         | RConstString _ | RConstOptString _ ->
5686             pr "    const char *r;\n"; "NULL"
5687         | RString _ -> pr "    char *r;\n"; "NULL"
5688         | RStringList _ | RHashtable _ ->
5689             pr "    char **r;\n";
5690             pr "    int i;\n";
5691             "NULL"
5692         | RStruct (_, typ) ->
5693             pr "    struct guestfs_%s *r;\n" typ; "NULL"
5694         | RStructList (_, typ) ->
5695             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
5696         | RBufferOut _ ->
5697             pr "    char *r;\n";
5698             pr "    size_t size;\n";
5699             "NULL" in
5700
5701       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
5702       pr "    r = guestfs_%s (g" name;
5703
5704       (* Generate the parameters. *)
5705       List.iter (
5706         function
5707         | OptString _, "NULL" -> pr ", NULL"
5708         | Device n, _
5709         | String n, _
5710         | OptString n, _ ->
5711             pr ", %s" n
5712         | FileIn _, arg | FileOut _, arg ->
5713             pr ", \"%s\"" (c_quote arg)
5714         | StringList n, _ ->
5715             pr ", %s" n
5716         | Int _, arg ->
5717             let i =
5718               try int_of_string arg
5719               with Failure "int_of_string" ->
5720                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
5721             pr ", %d" i
5722         | Bool _, arg ->
5723             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
5724       ) (List.combine (snd style) args);
5725
5726       (match fst style with
5727        | RBufferOut _ -> pr ", &size"
5728        | _ -> ()
5729       );
5730
5731       pr ");\n";
5732
5733       if not expect_error then
5734         pr "    if (r == %s)\n" error_code
5735       else
5736         pr "    if (r != %s)\n" error_code;
5737       pr "      return -1;\n";
5738
5739       (* Insert the test code. *)
5740       (match test with
5741        | None -> ()
5742        | Some f -> f ()
5743       );
5744
5745       (match fst style with
5746        | RErr | RInt _ | RInt64 _ | RBool _
5747        | RConstString _ | RConstOptString _ -> ()
5748        | RString _ | RBufferOut _ -> pr "    free (r);\n"
5749        | RStringList _ | RHashtable _ ->
5750            pr "    for (i = 0; r[i] != NULL; ++i)\n";
5751            pr "      free (r[i]);\n";
5752            pr "    free (r);\n"
5753        | RStruct (_, typ) ->
5754            pr "    guestfs_free_%s (r);\n" typ
5755        | RStructList (_, typ) ->
5756            pr "    guestfs_free_%s_list (r);\n" typ
5757       );
5758
5759       pr "  }\n"
5760
5761 and c_quote str =
5762   let str = replace_str str "\r" "\\r" in
5763   let str = replace_str str "\n" "\\n" in
5764   let str = replace_str str "\t" "\\t" in
5765   let str = replace_str str "\000" "\\0" in
5766   str
5767
5768 (* Generate a lot of different functions for guestfish. *)
5769 and generate_fish_cmds () =
5770   generate_header CStyle GPLv2;
5771
5772   let all_functions =
5773     List.filter (
5774       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5775     ) all_functions in
5776   let all_functions_sorted =
5777     List.filter (
5778       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5779     ) all_functions_sorted in
5780
5781   pr "#include <stdio.h>\n";
5782   pr "#include <stdlib.h>\n";
5783   pr "#include <string.h>\n";
5784   pr "#include <inttypes.h>\n";
5785   pr "#include <ctype.h>\n";
5786   pr "\n";
5787   pr "#include <guestfs.h>\n";
5788   pr "#include \"fish.h\"\n";
5789   pr "\n";
5790
5791   (* list_commands function, which implements guestfish -h *)
5792   pr "void list_commands (void)\n";
5793   pr "{\n";
5794   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
5795   pr "  list_builtin_commands ();\n";
5796   List.iter (
5797     fun (name, _, _, flags, _, shortdesc, _) ->
5798       let name = replace_char name '_' '-' in
5799       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
5800         name shortdesc
5801   ) all_functions_sorted;
5802   pr "  printf (\"    %%s\\n\",";
5803   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
5804   pr "}\n";
5805   pr "\n";
5806
5807   (* display_command function, which implements guestfish -h cmd *)
5808   pr "void display_command (const char *cmd)\n";
5809   pr "{\n";
5810   List.iter (
5811     fun (name, style, _, flags, _, shortdesc, longdesc) ->
5812       let name2 = replace_char name '_' '-' in
5813       let alias =
5814         try find_map (function FishAlias n -> Some n | _ -> None) flags
5815         with Not_found -> name in
5816       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
5817       let synopsis =
5818         match snd style with
5819         | [] -> name2
5820         | args ->
5821             sprintf "%s <%s>"
5822               name2 (String.concat "> <" (List.map name_of_argt args)) in
5823
5824       let warnings =
5825         if List.mem ProtocolLimitWarning flags then
5826           ("\n\n" ^ protocol_limit_warning)
5827         else "" in
5828
5829       (* For DangerWillRobinson commands, we should probably have
5830        * guestfish prompt before allowing you to use them (especially
5831        * in interactive mode). XXX
5832        *)
5833       let warnings =
5834         warnings ^
5835           if List.mem DangerWillRobinson flags then
5836             ("\n\n" ^ danger_will_robinson)
5837           else "" in
5838
5839       let warnings =
5840         warnings ^
5841           match deprecation_notice flags with
5842           | None -> ""
5843           | Some txt -> "\n\n" ^ txt in
5844
5845       let describe_alias =
5846         if name <> alias then
5847           sprintf "\n\nYou can use '%s' as an alias for this command." alias
5848         else "" in
5849
5850       pr "  if (";
5851       pr "strcasecmp (cmd, \"%s\") == 0" name;
5852       if name <> name2 then
5853         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5854       if name <> alias then
5855         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5856       pr ")\n";
5857       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
5858         name2 shortdesc
5859         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
5860       pr "  else\n"
5861   ) all_functions;
5862   pr "    display_builtin_command (cmd);\n";
5863   pr "}\n";
5864   pr "\n";
5865
5866   (* print_* functions *)
5867   List.iter (
5868     fun (typ, cols) ->
5869       let needs_i =
5870         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
5871
5872       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
5873       pr "{\n";
5874       if needs_i then (
5875         pr "  int i;\n";
5876         pr "\n"
5877       );
5878       List.iter (
5879         function
5880         | name, FString ->
5881             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
5882         | name, FUUID ->
5883             pr "  printf (\"%s: \");\n" name;
5884             pr "  for (i = 0; i < 32; ++i)\n";
5885             pr "    printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
5886             pr "  printf (\"\\n\");\n"
5887         | name, FBuffer ->
5888             pr "  printf (\"%%s%s: \", indent);\n" name;
5889             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
5890             pr "    if (isprint (%s->%s[i]))\n" typ name;
5891             pr "      printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
5892             pr "    else\n";
5893             pr "      printf (\"%%s\\\\x%%02x\", indent, %s->%s[i]);\n" typ name;
5894             pr "  printf (\"\\n\");\n"
5895         | name, (FUInt64|FBytes) ->
5896             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
5897               name typ name
5898         | name, FInt64 ->
5899             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
5900               name typ name
5901         | name, FUInt32 ->
5902             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
5903               name typ name
5904         | name, FInt32 ->
5905             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
5906               name typ name
5907         | name, FChar ->
5908             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
5909               name typ name
5910         | name, FOptPercent ->
5911             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
5912               typ name name typ name;
5913             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
5914       ) cols;
5915       pr "}\n";
5916       pr "\n";
5917       pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
5918       pr "{\n";
5919       pr "  print_%s_indent (%s, \"\");\n" typ typ;
5920       pr "}\n";
5921       pr "\n";
5922       pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
5923         typ typ typ;
5924       pr "{\n";
5925       pr "  int i;\n";
5926       pr "\n";
5927       pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
5928       pr "    printf (\"[%%d] = {\\n\", i);\n";
5929       pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
5930       pr "    printf (\"}\\n\");\n";
5931       pr "  }\n";
5932       pr "}\n";
5933       pr "\n";
5934   ) structs;
5935
5936   (* run_<action> actions *)
5937   List.iter (
5938     fun (name, style, _, flags, _, _, _) ->
5939       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
5940       pr "{\n";
5941       (match fst style with
5942        | RErr
5943        | RInt _
5944        | RBool _ -> pr "  int r;\n"
5945        | RInt64 _ -> pr "  int64_t r;\n"
5946        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
5947        | RString _ -> pr "  char *r;\n"
5948        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
5949        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
5950        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
5951        | RBufferOut _ ->
5952            pr "  char *r;\n";
5953            pr "  size_t size;\n";
5954       );
5955       List.iter (
5956         function
5957         | Device n
5958         | String n
5959         | OptString n
5960         | FileIn n
5961         | FileOut n -> pr "  const char *%s;\n" n
5962         | StringList n -> pr "  char **%s;\n" n
5963         | Bool n -> pr "  int %s;\n" n
5964         | Int n -> pr "  int %s;\n" n
5965       ) (snd style);
5966
5967       (* Check and convert parameters. *)
5968       let argc_expected = List.length (snd style) in
5969       pr "  if (argc != %d) {\n" argc_expected;
5970       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
5971         argc_expected;
5972       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
5973       pr "    return -1;\n";
5974       pr "  }\n";
5975       iteri (
5976         fun i ->
5977           function
5978           | Device name | String name -> pr "  %s = argv[%d];\n" name i
5979           | OptString name ->
5980               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5981                 name i i
5982           | FileIn name ->
5983               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5984                 name i i
5985           | FileOut name ->
5986               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5987                 name i i
5988           | StringList name ->
5989               pr "  %s = parse_string_list (argv[%d]);\n" name i
5990           | Bool name ->
5991               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5992           | Int name ->
5993               pr "  %s = atoi (argv[%d]);\n" name i
5994       ) (snd style);
5995
5996       (* Call C API function. *)
5997       let fn =
5998         try find_map (function FishAction n -> Some n | _ -> None) flags
5999         with Not_found -> sprintf "guestfs_%s" name in
6000       pr "  r = %s " fn;
6001       generate_c_call_args ~handle:"g" style;
6002       pr ";\n";
6003
6004       (* Check return value for errors and display command results. *)
6005       (match fst style with
6006        | RErr -> pr "  return r;\n"
6007        | RInt _ ->
6008            pr "  if (r == -1) return -1;\n";
6009            pr "  printf (\"%%d\\n\", r);\n";
6010            pr "  return 0;\n"
6011        | RInt64 _ ->
6012            pr "  if (r == -1) return -1;\n";
6013            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
6014            pr "  return 0;\n"
6015        | RBool _ ->
6016            pr "  if (r == -1) return -1;\n";
6017            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
6018            pr "  return 0;\n"
6019        | RConstString _ ->
6020            pr "  if (r == NULL) return -1;\n";
6021            pr "  printf (\"%%s\\n\", r);\n";
6022            pr "  return 0;\n"
6023        | RConstOptString _ ->
6024            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
6025            pr "  return 0;\n"
6026        | RString _ ->
6027            pr "  if (r == NULL) return -1;\n";
6028            pr "  printf (\"%%s\\n\", r);\n";
6029            pr "  free (r);\n";
6030            pr "  return 0;\n"
6031        | RStringList _ ->
6032            pr "  if (r == NULL) return -1;\n";
6033            pr "  print_strings (r);\n";
6034            pr "  free_strings (r);\n";
6035            pr "  return 0;\n"
6036        | RStruct (_, typ) ->
6037            pr "  if (r == NULL) return -1;\n";
6038            pr "  print_%s (r);\n" typ;
6039            pr "  guestfs_free_%s (r);\n" typ;
6040            pr "  return 0;\n"
6041        | RStructList (_, typ) ->
6042            pr "  if (r == NULL) return -1;\n";
6043            pr "  print_%s_list (r);\n" typ;
6044            pr "  guestfs_free_%s_list (r);\n" typ;
6045            pr "  return 0;\n"
6046        | RHashtable _ ->
6047            pr "  if (r == NULL) return -1;\n";
6048            pr "  print_table (r);\n";
6049            pr "  free_strings (r);\n";
6050            pr "  return 0;\n"
6051        | RBufferOut _ ->
6052            pr "  if (r == NULL) return -1;\n";
6053            pr "  fwrite (r, size, 1, stdout);\n";
6054            pr "  free (r);\n";
6055            pr "  return 0;\n"
6056       );
6057       pr "}\n";
6058       pr "\n"
6059   ) all_functions;
6060
6061   (* run_action function *)
6062   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
6063   pr "{\n";
6064   List.iter (
6065     fun (name, _, _, flags, _, _, _) ->
6066       let name2 = replace_char name '_' '-' in
6067       let alias =
6068         try find_map (function FishAlias n -> Some n | _ -> None) flags
6069         with Not_found -> name in
6070       pr "  if (";
6071       pr "strcasecmp (cmd, \"%s\") == 0" name;
6072       if name <> name2 then
6073         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
6074       if name <> alias then
6075         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
6076       pr ")\n";
6077       pr "    return run_%s (cmd, argc, argv);\n" name;
6078       pr "  else\n";
6079   ) all_functions;
6080   pr "    {\n";
6081   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
6082   pr "      return -1;\n";
6083   pr "    }\n";
6084   pr "  return 0;\n";
6085   pr "}\n";
6086   pr "\n"
6087
6088 (* Readline completion for guestfish. *)
6089 and generate_fish_completion () =
6090   generate_header CStyle GPLv2;
6091
6092   let all_functions =
6093     List.filter (
6094       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6095     ) all_functions in
6096
6097   pr "\
6098 #include <config.h>
6099
6100 #include <stdio.h>
6101 #include <stdlib.h>
6102 #include <string.h>
6103
6104 #ifdef HAVE_LIBREADLINE
6105 #include <readline/readline.h>
6106 #endif
6107
6108 #include \"fish.h\"
6109
6110 #ifdef HAVE_LIBREADLINE
6111
6112 static const char *const commands[] = {
6113   BUILTIN_COMMANDS_FOR_COMPLETION,
6114 ";
6115
6116   (* Get the commands, including the aliases.  They don't need to be
6117    * sorted - the generator() function just does a dumb linear search.
6118    *)
6119   let commands =
6120     List.map (
6121       fun (name, _, _, flags, _, _, _) ->
6122         let name2 = replace_char name '_' '-' in
6123         let alias =
6124           try find_map (function FishAlias n -> Some n | _ -> None) flags
6125           with Not_found -> name in
6126
6127         if name <> alias then [name2; alias] else [name2]
6128     ) all_functions in
6129   let commands = List.flatten commands in
6130
6131   List.iter (pr "  \"%s\",\n") commands;
6132
6133   pr "  NULL
6134 };
6135
6136 static char *
6137 generator (const char *text, int state)
6138 {
6139   static int index, len;
6140   const char *name;
6141
6142   if (!state) {
6143     index = 0;
6144     len = strlen (text);
6145   }
6146
6147   rl_attempted_completion_over = 1;
6148
6149   while ((name = commands[index]) != NULL) {
6150     index++;
6151     if (strncasecmp (name, text, len) == 0)
6152       return strdup (name);
6153   }
6154
6155   return NULL;
6156 }
6157
6158 #endif /* HAVE_LIBREADLINE */
6159
6160 char **do_completion (const char *text, int start, int end)
6161 {
6162   char **matches = NULL;
6163
6164 #ifdef HAVE_LIBREADLINE
6165   rl_completion_append_character = ' ';
6166
6167   if (start == 0)
6168     matches = rl_completion_matches (text, generator);
6169   else if (complete_dest_paths)
6170     matches = rl_completion_matches (text, complete_dest_paths_generator);
6171 #endif
6172
6173   return matches;
6174 }
6175 ";
6176
6177 (* Generate the POD documentation for guestfish. *)
6178 and generate_fish_actions_pod () =
6179   let all_functions_sorted =
6180     List.filter (
6181       fun (_, _, _, flags, _, _, _) ->
6182         not (List.mem NotInFish flags || List.mem NotInDocs flags)
6183     ) all_functions_sorted in
6184
6185   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
6186
6187   List.iter (
6188     fun (name, style, _, flags, _, _, longdesc) ->
6189       let longdesc =
6190         Str.global_substitute rex (
6191           fun s ->
6192             let sub =
6193               try Str.matched_group 1 s
6194               with Not_found ->
6195                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
6196             "C<" ^ replace_char sub '_' '-' ^ ">"
6197         ) longdesc in
6198       let name = replace_char name '_' '-' in
6199       let alias =
6200         try find_map (function FishAlias n -> Some n | _ -> None) flags
6201         with Not_found -> name in
6202
6203       pr "=head2 %s" name;
6204       if name <> alias then
6205         pr " | %s" alias;
6206       pr "\n";
6207       pr "\n";
6208       pr " %s" name;
6209       List.iter (
6210         function
6211         | Device n | String n -> pr " %s" n
6212         | OptString n -> pr " %s" n
6213         | StringList n -> pr " '%s ...'" n
6214         | Bool _ -> pr " true|false"
6215         | Int n -> pr " %s" n
6216         | FileIn n | FileOut n -> pr " (%s|-)" n
6217       ) (snd style);
6218       pr "\n";
6219       pr "\n";
6220       pr "%s\n\n" longdesc;
6221
6222       if List.exists (function FileIn _ | FileOut _ -> true
6223                       | _ -> false) (snd style) then
6224         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
6225
6226       if List.mem ProtocolLimitWarning flags then
6227         pr "%s\n\n" protocol_limit_warning;
6228
6229       if List.mem DangerWillRobinson flags then
6230         pr "%s\n\n" danger_will_robinson;
6231
6232       match deprecation_notice flags with
6233       | None -> ()
6234       | Some txt -> pr "%s\n\n" txt
6235   ) all_functions_sorted
6236
6237 (* Generate a C function prototype. *)
6238 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
6239     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
6240     ?(prefix = "")
6241     ?handle name style =
6242   if extern then pr "extern ";
6243   if static then pr "static ";
6244   (match fst style with
6245    | RErr -> pr "int "
6246    | RInt _ -> pr "int "
6247    | RInt64 _ -> pr "int64_t "
6248    | RBool _ -> pr "int "
6249    | RConstString _ | RConstOptString _ -> pr "const char *"
6250    | RString _ | RBufferOut _ -> pr "char *"
6251    | RStringList _ | RHashtable _ -> pr "char **"
6252    | RStruct (_, typ) ->
6253        if not in_daemon then pr "struct guestfs_%s *" typ
6254        else pr "guestfs_int_%s *" typ
6255    | RStructList (_, typ) ->
6256        if not in_daemon then pr "struct guestfs_%s_list *" typ
6257        else pr "guestfs_int_%s_list *" typ
6258   );
6259   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
6260   pr "%s%s (" prefix name;
6261   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
6262     pr "void"
6263   else (
6264     let comma = ref false in
6265     (match handle with
6266      | None -> ()
6267      | Some handle -> pr "guestfs_h *%s" handle; comma := true
6268     );
6269     let next () =
6270       if !comma then (
6271         if single_line then pr ", " else pr ",\n\t\t"
6272       );
6273       comma := true
6274     in
6275     List.iter (
6276       function
6277       | Device n
6278       | String n
6279       | OptString n ->
6280           next ();
6281           if not in_daemon then pr "const char *%s" n
6282           else pr "char *%s" n
6283       | StringList n ->
6284           next ();
6285           if not in_daemon then pr "char * const* const %s" n
6286           else pr "char **%s" n
6287       | Bool n -> next (); pr "int %s" n
6288       | Int n -> next (); pr "int %s" n
6289       | FileIn n
6290       | FileOut n ->
6291           if not in_daemon then (next (); pr "const char *%s" n)
6292     ) (snd style);
6293     if is_RBufferOut then (next (); pr "size_t *size_r");
6294   );
6295   pr ")";
6296   if semicolon then pr ";";
6297   if newline then pr "\n"
6298
6299 (* Generate C call arguments, eg "(handle, foo, bar)" *)
6300 and generate_c_call_args ?handle ?(decl = false) style =
6301   pr "(";
6302   let comma = ref false in
6303   let next () =
6304     if !comma then pr ", ";
6305     comma := true
6306   in
6307   (match handle with
6308    | None -> ()
6309    | Some handle -> pr "%s" handle; comma := true
6310   );
6311   List.iter (
6312     fun arg ->
6313       next ();
6314       pr "%s" (name_of_argt arg)
6315   ) (snd style);
6316   (* For RBufferOut calls, add implicit &size parameter. *)
6317   if not decl then (
6318     match fst style with
6319     | RBufferOut _ ->
6320         next ();
6321         pr "&size"
6322     | _ -> ()
6323   );
6324   pr ")"
6325
6326 (* Generate the OCaml bindings interface. *)
6327 and generate_ocaml_mli () =
6328   generate_header OCamlStyle LGPLv2;
6329
6330   pr "\
6331 (** For API documentation you should refer to the C API
6332     in the guestfs(3) manual page.  The OCaml API uses almost
6333     exactly the same calls. *)
6334
6335 type t
6336 (** A [guestfs_h] handle. *)
6337
6338 exception Error of string
6339 (** This exception is raised when there is an error. *)
6340
6341 val create : unit -> t
6342
6343 val close : t -> unit
6344 (** Handles are closed by the garbage collector when they become
6345     unreferenced, but callers can also call this in order to
6346     provide predictable cleanup. *)
6347
6348 ";
6349   generate_ocaml_structure_decls ();
6350
6351   (* The actions. *)
6352   List.iter (
6353     fun (name, style, _, _, _, shortdesc, _) ->
6354       generate_ocaml_prototype name style;
6355       pr "(** %s *)\n" shortdesc;
6356       pr "\n"
6357   ) all_functions
6358
6359 (* Generate the OCaml bindings implementation. *)
6360 and generate_ocaml_ml () =
6361   generate_header OCamlStyle LGPLv2;
6362
6363   pr "\
6364 type t
6365 exception Error of string
6366 external create : unit -> t = \"ocaml_guestfs_create\"
6367 external close : t -> unit = \"ocaml_guestfs_close\"
6368
6369 let () =
6370   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
6371
6372 ";
6373
6374   generate_ocaml_structure_decls ();
6375
6376   (* The actions. *)
6377   List.iter (
6378     fun (name, style, _, _, _, shortdesc, _) ->
6379       generate_ocaml_prototype ~is_external:true name style;
6380   ) all_functions
6381
6382 (* Generate the OCaml bindings C implementation. *)
6383 and generate_ocaml_c () =
6384   generate_header CStyle LGPLv2;
6385
6386   pr "\
6387 #include <stdio.h>
6388 #include <stdlib.h>
6389 #include <string.h>
6390
6391 #include <caml/config.h>
6392 #include <caml/alloc.h>
6393 #include <caml/callback.h>
6394 #include <caml/fail.h>
6395 #include <caml/memory.h>
6396 #include <caml/mlvalues.h>
6397 #include <caml/signals.h>
6398
6399 #include <guestfs.h>
6400
6401 #include \"guestfs_c.h\"
6402
6403 /* Copy a hashtable of string pairs into an assoc-list.  We return
6404  * the list in reverse order, but hashtables aren't supposed to be
6405  * ordered anyway.
6406  */
6407 static CAMLprim value
6408 copy_table (char * const * argv)
6409 {
6410   CAMLparam0 ();
6411   CAMLlocal5 (rv, pairv, kv, vv, cons);
6412   int i;
6413
6414   rv = Val_int (0);
6415   for (i = 0; argv[i] != NULL; i += 2) {
6416     kv = caml_copy_string (argv[i]);
6417     vv = caml_copy_string (argv[i+1]);
6418     pairv = caml_alloc (2, 0);
6419     Store_field (pairv, 0, kv);
6420     Store_field (pairv, 1, vv);
6421     cons = caml_alloc (2, 0);
6422     Store_field (cons, 1, rv);
6423     rv = cons;
6424     Store_field (cons, 0, pairv);
6425   }
6426
6427   CAMLreturn (rv);
6428 }
6429
6430 ";
6431
6432   (* Struct copy functions. *)
6433   List.iter (
6434     fun (typ, cols) ->
6435       let has_optpercent_col =
6436         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
6437
6438       pr "static CAMLprim value\n";
6439       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
6440       pr "{\n";
6441       pr "  CAMLparam0 ();\n";
6442       if has_optpercent_col then
6443         pr "  CAMLlocal3 (rv, v, v2);\n"
6444       else
6445         pr "  CAMLlocal2 (rv, v);\n";
6446       pr "\n";
6447       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
6448       iteri (
6449         fun i col ->
6450           (match col with
6451            | name, FString ->
6452                pr "  v = caml_copy_string (%s->%s);\n" typ name
6453            | name, FBuffer ->
6454                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
6455                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
6456                  typ name typ name
6457            | name, FUUID ->
6458                pr "  v = caml_alloc_string (32);\n";
6459                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
6460            | name, (FBytes|FInt64|FUInt64) ->
6461                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
6462            | name, (FInt32|FUInt32) ->
6463                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
6464            | name, FOptPercent ->
6465                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
6466                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
6467                pr "    v = caml_alloc (1, 0);\n";
6468                pr "    Store_field (v, 0, v2);\n";
6469                pr "  } else /* None */\n";
6470                pr "    v = Val_int (0);\n";
6471            | name, FChar ->
6472                pr "  v = Val_int (%s->%s);\n" typ name
6473           );
6474           pr "  Store_field (rv, %d, v);\n" i
6475       ) cols;
6476       pr "  CAMLreturn (rv);\n";
6477       pr "}\n";
6478       pr "\n";
6479
6480       pr "static CAMLprim value\n";
6481       pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n"
6482         typ typ typ;
6483       pr "{\n";
6484       pr "  CAMLparam0 ();\n";
6485       pr "  CAMLlocal2 (rv, v);\n";
6486       pr "  int i;\n";
6487       pr "\n";
6488       pr "  if (%ss->len == 0)\n" typ;
6489       pr "    CAMLreturn (Atom (0));\n";
6490       pr "  else {\n";
6491       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
6492       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
6493       pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
6494       pr "      caml_modify (&Field (rv, i), v);\n";
6495       pr "    }\n";
6496       pr "    CAMLreturn (rv);\n";
6497       pr "  }\n";
6498       pr "}\n";
6499       pr "\n";
6500   ) structs;
6501
6502   (* The wrappers. *)
6503   List.iter (
6504     fun (name, style, _, _, _, _, _) ->
6505       let params =
6506         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
6507
6508       let needs_extra_vs =
6509         match fst style with RConstOptString _ -> true | _ -> false in
6510
6511       pr "CAMLprim value\n";
6512       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
6513       List.iter (pr ", value %s") (List.tl params);
6514       pr ")\n";
6515       pr "{\n";
6516
6517       (match params with
6518        | [p1; p2; p3; p4; p5] ->
6519            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
6520        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
6521            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
6522            pr "  CAMLxparam%d (%s);\n"
6523              (List.length rest) (String.concat ", " rest)
6524        | ps ->
6525            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
6526       );
6527       if not needs_extra_vs then
6528         pr "  CAMLlocal1 (rv);\n"
6529       else
6530         pr "  CAMLlocal3 (rv, v, v2);\n";
6531       pr "\n";
6532
6533       pr "  guestfs_h *g = Guestfs_val (gv);\n";
6534       pr "  if (g == NULL)\n";
6535       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
6536       pr "\n";
6537
6538       List.iter (
6539         function
6540         | Device n
6541         | String n
6542         | FileIn n
6543         | FileOut n ->
6544             pr "  const char *%s = String_val (%sv);\n" n n
6545         | OptString n ->
6546             pr "  const char *%s =\n" n;
6547             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
6548               n n
6549         | StringList n ->
6550             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
6551         | Bool n ->
6552             pr "  int %s = Bool_val (%sv);\n" n n
6553         | Int n ->
6554             pr "  int %s = Int_val (%sv);\n" n n
6555       ) (snd style);
6556       let error_code =
6557         match fst style with
6558         | RErr -> pr "  int r;\n"; "-1"
6559         | RInt _ -> pr "  int r;\n"; "-1"
6560         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6561         | RBool _ -> pr "  int r;\n"; "-1"
6562         | RConstString _ | RConstOptString _ ->
6563             pr "  const char *r;\n"; "NULL"
6564         | RString _ -> pr "  char *r;\n"; "NULL"
6565         | RStringList _ ->
6566             pr "  int i;\n";
6567             pr "  char **r;\n";
6568             "NULL"
6569         | RStruct (_, typ) ->
6570             pr "  struct guestfs_%s *r;\n" typ; "NULL"
6571         | RStructList (_, typ) ->
6572             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
6573         | RHashtable _ ->
6574             pr "  int i;\n";
6575             pr "  char **r;\n";
6576             "NULL"
6577         | RBufferOut _ ->
6578             pr "  char *r;\n";
6579             pr "  size_t size;\n";
6580             "NULL" in
6581       pr "\n";
6582
6583       pr "  caml_enter_blocking_section ();\n";
6584       pr "  r = guestfs_%s " name;
6585       generate_c_call_args ~handle:"g" style;
6586       pr ";\n";
6587       pr "  caml_leave_blocking_section ();\n";
6588
6589       List.iter (
6590         function
6591         | StringList n ->
6592             pr "  ocaml_guestfs_free_strings (%s);\n" n;
6593         | Device _ | String _ | OptString _ | Bool _ | Int _
6594         | FileIn _ | FileOut _ -> ()
6595       ) (snd style);
6596
6597       pr "  if (r == %s)\n" error_code;
6598       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
6599       pr "\n";
6600
6601       (match fst style with
6602        | RErr -> pr "  rv = Val_unit;\n"
6603        | RInt _ -> pr "  rv = Val_int (r);\n"
6604        | RInt64 _ ->
6605            pr "  rv = caml_copy_int64 (r);\n"
6606        | RBool _ -> pr "  rv = Val_bool (r);\n"
6607        | RConstString _ ->
6608            pr "  rv = caml_copy_string (r);\n"
6609        | RConstOptString _ ->
6610            pr "  if (r) { /* Some string */\n";
6611            pr "    v = caml_alloc (1, 0);\n";
6612            pr "    v2 = caml_copy_string (r);\n";
6613            pr "    Store_field (v, 0, v2);\n";
6614            pr "  } else /* None */\n";
6615            pr "    v = Val_int (0);\n";
6616        | RString _ ->
6617            pr "  rv = caml_copy_string (r);\n";
6618            pr "  free (r);\n"
6619        | RStringList _ ->
6620            pr "  rv = caml_copy_string_array ((const char **) r);\n";
6621            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6622            pr "  free (r);\n"
6623        | RStruct (_, typ) ->
6624            pr "  rv = copy_%s (r);\n" typ;
6625            pr "  guestfs_free_%s (r);\n" typ;
6626        | RStructList (_, typ) ->
6627            pr "  rv = copy_%s_list (r);\n" typ;
6628            pr "  guestfs_free_%s_list (r);\n" typ;
6629        | RHashtable _ ->
6630            pr "  rv = copy_table (r);\n";
6631            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6632            pr "  free (r);\n";
6633        | RBufferOut _ ->
6634            pr "  rv = caml_alloc_string (size);\n";
6635            pr "  memcpy (String_val (rv), r, size);\n";
6636       );
6637
6638       pr "  CAMLreturn (rv);\n";
6639       pr "}\n";
6640       pr "\n";
6641
6642       if List.length params > 5 then (
6643         pr "CAMLprim value\n";
6644         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
6645         pr "{\n";
6646         pr "  return ocaml_guestfs_%s (argv[0]" name;
6647         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
6648         pr ");\n";
6649         pr "}\n";
6650         pr "\n"
6651       )
6652   ) all_functions
6653
6654 and generate_ocaml_structure_decls () =
6655   List.iter (
6656     fun (typ, cols) ->
6657       pr "type %s = {\n" typ;
6658       List.iter (
6659         function
6660         | name, FString -> pr "  %s : string;\n" name
6661         | name, FBuffer -> pr "  %s : string;\n" name
6662         | name, FUUID -> pr "  %s : string;\n" name
6663         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
6664         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
6665         | name, FChar -> pr "  %s : char;\n" name
6666         | name, FOptPercent -> pr "  %s : float option;\n" name
6667       ) cols;
6668       pr "}\n";
6669       pr "\n"
6670   ) structs
6671
6672 and generate_ocaml_prototype ?(is_external = false) name style =
6673   if is_external then pr "external " else pr "val ";
6674   pr "%s : t -> " name;
6675   List.iter (
6676     function
6677     | Device _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
6678     | OptString _ -> pr "string option -> "
6679     | StringList _ -> pr "string array -> "
6680     | Bool _ -> pr "bool -> "
6681     | Int _ -> pr "int -> "
6682   ) (snd style);
6683   (match fst style with
6684    | RErr -> pr "unit" (* all errors are turned into exceptions *)
6685    | RInt _ -> pr "int"
6686    | RInt64 _ -> pr "int64"
6687    | RBool _ -> pr "bool"
6688    | RConstString _ -> pr "string"
6689    | RConstOptString _ -> pr "string option"
6690    | RString _ | RBufferOut _ -> pr "string"
6691    | RStringList _ -> pr "string array"
6692    | RStruct (_, typ) -> pr "%s" typ
6693    | RStructList (_, typ) -> pr "%s array" typ
6694    | RHashtable _ -> pr "(string * string) list"
6695   );
6696   if is_external then (
6697     pr " = ";
6698     if List.length (snd style) + 1 > 5 then
6699       pr "\"ocaml_guestfs_%s_byte\" " name;
6700     pr "\"ocaml_guestfs_%s\"" name
6701   );
6702   pr "\n"
6703
6704 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
6705 and generate_perl_xs () =
6706   generate_header CStyle LGPLv2;
6707
6708   pr "\
6709 #include \"EXTERN.h\"
6710 #include \"perl.h\"
6711 #include \"XSUB.h\"
6712
6713 #include <guestfs.h>
6714
6715 #ifndef PRId64
6716 #define PRId64 \"lld\"
6717 #endif
6718
6719 static SV *
6720 my_newSVll(long long val) {
6721 #ifdef USE_64_BIT_ALL
6722   return newSViv(val);
6723 #else
6724   char buf[100];
6725   int len;
6726   len = snprintf(buf, 100, \"%%\" PRId64, val);
6727   return newSVpv(buf, len);
6728 #endif
6729 }
6730
6731 #ifndef PRIu64
6732 #define PRIu64 \"llu\"
6733 #endif
6734
6735 static SV *
6736 my_newSVull(unsigned long long val) {
6737 #ifdef USE_64_BIT_ALL
6738   return newSVuv(val);
6739 #else
6740   char buf[100];
6741   int len;
6742   len = snprintf(buf, 100, \"%%\" PRIu64, val);
6743   return newSVpv(buf, len);
6744 #endif
6745 }
6746
6747 /* http://www.perlmonks.org/?node_id=680842 */
6748 static char **
6749 XS_unpack_charPtrPtr (SV *arg) {
6750   char **ret;
6751   AV *av;
6752   I32 i;
6753
6754   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
6755     croak (\"array reference expected\");
6756
6757   av = (AV *)SvRV (arg);
6758   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
6759   if (!ret)
6760     croak (\"malloc failed\");
6761
6762   for (i = 0; i <= av_len (av); i++) {
6763     SV **elem = av_fetch (av, i, 0);
6764
6765     if (!elem || !*elem)
6766       croak (\"missing element in list\");
6767
6768     ret[i] = SvPV_nolen (*elem);
6769   }
6770
6771   ret[i] = NULL;
6772
6773   return ret;
6774 }
6775
6776 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
6777
6778 PROTOTYPES: ENABLE
6779
6780 guestfs_h *
6781 _create ()
6782    CODE:
6783       RETVAL = guestfs_create ();
6784       if (!RETVAL)
6785         croak (\"could not create guestfs handle\");
6786       guestfs_set_error_handler (RETVAL, NULL, NULL);
6787  OUTPUT:
6788       RETVAL
6789
6790 void
6791 DESTROY (g)
6792       guestfs_h *g;
6793  PPCODE:
6794       guestfs_close (g);
6795
6796 ";
6797
6798   List.iter (
6799     fun (name, style, _, _, _, _, _) ->
6800       (match fst style with
6801        | RErr -> pr "void\n"
6802        | RInt _ -> pr "SV *\n"
6803        | RInt64 _ -> pr "SV *\n"
6804        | RBool _ -> pr "SV *\n"
6805        | RConstString _ -> pr "SV *\n"
6806        | RConstOptString _ -> pr "SV *\n"
6807        | RString _ -> pr "SV *\n"
6808        | RBufferOut _ -> pr "SV *\n"
6809        | RStringList _
6810        | RStruct _ | RStructList _
6811        | RHashtable _ ->
6812            pr "void\n" (* all lists returned implictly on the stack *)
6813       );
6814       (* Call and arguments. *)
6815       pr "%s " name;
6816       generate_c_call_args ~handle:"g" ~decl:true style;
6817       pr "\n";
6818       pr "      guestfs_h *g;\n";
6819       iteri (
6820         fun i ->
6821           function
6822           | Device n | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
6823           | OptString n ->
6824               (* http://www.perlmonks.org/?node_id=554277
6825                * Note that the implicit handle argument means we have
6826                * to add 1 to the ST(x) operator.
6827                *)
6828               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
6829           | StringList n -> pr "      char **%s;\n" n
6830           | Bool n -> pr "      int %s;\n" n
6831           | Int n -> pr "      int %s;\n" n
6832       ) (snd style);
6833
6834       let do_cleanups () =
6835         List.iter (
6836           function
6837           | Device _ | String _ | OptString _ | Bool _ | Int _
6838           | FileIn _ | FileOut _ -> ()
6839           | StringList n -> pr "      free (%s);\n" n
6840         ) (snd style)
6841       in
6842
6843       (* Code. *)
6844       (match fst style with
6845        | RErr ->
6846            pr "PREINIT:\n";
6847            pr "      int r;\n";
6848            pr " PPCODE:\n";
6849            pr "      r = guestfs_%s " name;
6850            generate_c_call_args ~handle:"g" style;
6851            pr ";\n";
6852            do_cleanups ();
6853            pr "      if (r == -1)\n";
6854            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6855        | RInt n
6856        | RBool n ->
6857            pr "PREINIT:\n";
6858            pr "      int %s;\n" n;
6859            pr "   CODE:\n";
6860            pr "      %s = guestfs_%s " n name;
6861            generate_c_call_args ~handle:"g" style;
6862            pr ";\n";
6863            do_cleanups ();
6864            pr "      if (%s == -1)\n" n;
6865            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6866            pr "      RETVAL = newSViv (%s);\n" n;
6867            pr " OUTPUT:\n";
6868            pr "      RETVAL\n"
6869        | RInt64 n ->
6870            pr "PREINIT:\n";
6871            pr "      int64_t %s;\n" n;
6872            pr "   CODE:\n";
6873            pr "      %s = guestfs_%s " n name;
6874            generate_c_call_args ~handle:"g" style;
6875            pr ";\n";
6876            do_cleanups ();
6877            pr "      if (%s == -1)\n" n;
6878            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6879            pr "      RETVAL = my_newSVll (%s);\n" n;
6880            pr " OUTPUT:\n";
6881            pr "      RETVAL\n"
6882        | RConstString n ->
6883            pr "PREINIT:\n";
6884            pr "      const char *%s;\n" n;
6885            pr "   CODE:\n";
6886            pr "      %s = guestfs_%s " n name;
6887            generate_c_call_args ~handle:"g" style;
6888            pr ";\n";
6889            do_cleanups ();
6890            pr "      if (%s == NULL)\n" n;
6891            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6892            pr "      RETVAL = newSVpv (%s, 0);\n" n;
6893            pr " OUTPUT:\n";
6894            pr "      RETVAL\n"
6895        | RConstOptString n ->
6896            pr "PREINIT:\n";
6897            pr "      const char *%s;\n" n;
6898            pr "   CODE:\n";
6899            pr "      %s = guestfs_%s " n name;
6900            generate_c_call_args ~handle:"g" style;
6901            pr ";\n";
6902            do_cleanups ();
6903            pr "      if (%s == NULL)\n" n;
6904            pr "        RETVAL = &PL_sv_undef;\n";
6905            pr "      else\n";
6906            pr "        RETVAL = newSVpv (%s, 0);\n" n;
6907            pr " OUTPUT:\n";
6908            pr "      RETVAL\n"
6909        | RString n ->
6910            pr "PREINIT:\n";
6911            pr "      char *%s;\n" n;
6912            pr "   CODE:\n";
6913            pr "      %s = guestfs_%s " n name;
6914            generate_c_call_args ~handle:"g" style;
6915            pr ";\n";
6916            do_cleanups ();
6917            pr "      if (%s == NULL)\n" n;
6918            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6919            pr "      RETVAL = newSVpv (%s, 0);\n" n;
6920            pr "      free (%s);\n" n;
6921            pr " OUTPUT:\n";
6922            pr "      RETVAL\n"
6923        | RStringList n | RHashtable n ->
6924            pr "PREINIT:\n";
6925            pr "      char **%s;\n" n;
6926            pr "      int i, n;\n";
6927            pr " PPCODE:\n";
6928            pr "      %s = guestfs_%s " n name;
6929            generate_c_call_args ~handle:"g" style;
6930            pr ";\n";
6931            do_cleanups ();
6932            pr "      if (%s == NULL)\n" n;
6933            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6934            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6935            pr "      EXTEND (SP, n);\n";
6936            pr "      for (i = 0; i < n; ++i) {\n";
6937            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6938            pr "        free (%s[i]);\n" n;
6939            pr "      }\n";
6940            pr "      free (%s);\n" n;
6941        | RStruct (n, typ) ->
6942            let cols = cols_of_struct typ in
6943            generate_perl_struct_code typ cols name style n do_cleanups
6944        | RStructList (n, typ) ->
6945            let cols = cols_of_struct typ in
6946            generate_perl_struct_list_code typ cols name style n do_cleanups
6947        | RBufferOut n ->
6948            pr "PREINIT:\n";
6949            pr "      char *%s;\n" n;
6950            pr "      size_t size;\n";
6951            pr "   CODE:\n";
6952            pr "      %s = guestfs_%s " n name;
6953            generate_c_call_args ~handle:"g" style;
6954            pr ";\n";
6955            do_cleanups ();
6956            pr "      if (%s == NULL)\n" n;
6957            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6958            pr "      RETVAL = newSVpv (%s, size);\n" n;
6959            pr "      free (%s);\n" n;
6960            pr " OUTPUT:\n";
6961            pr "      RETVAL\n"
6962       );
6963
6964       pr "\n"
6965   ) all_functions
6966
6967 and generate_perl_struct_list_code typ cols name style n do_cleanups =
6968   pr "PREINIT:\n";
6969   pr "      struct guestfs_%s_list *%s;\n" typ n;
6970   pr "      int i;\n";
6971   pr "      HV *hv;\n";
6972   pr " PPCODE:\n";
6973   pr "      %s = guestfs_%s " n name;
6974   generate_c_call_args ~handle:"g" style;
6975   pr ";\n";
6976   do_cleanups ();
6977   pr "      if (%s == NULL)\n" n;
6978   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6979   pr "      EXTEND (SP, %s->len);\n" n;
6980   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
6981   pr "        hv = newHV ();\n";
6982   List.iter (
6983     function
6984     | name, FString ->
6985         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6986           name (String.length name) n name
6987     | name, FUUID ->
6988         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
6989           name (String.length name) n name
6990     | name, FBuffer ->
6991         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
6992           name (String.length name) n name n name
6993     | name, (FBytes|FUInt64) ->
6994         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6995           name (String.length name) n name
6996     | name, FInt64 ->
6997         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
6998           name (String.length name) n name
6999     | name, (FInt32|FUInt32) ->
7000         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
7001           name (String.length name) n name
7002     | name, FChar ->
7003         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
7004           name (String.length name) n name
7005     | name, FOptPercent ->
7006         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
7007           name (String.length name) n name
7008   ) cols;
7009   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
7010   pr "      }\n";
7011   pr "      guestfs_free_%s_list (%s);\n" typ n
7012
7013 and generate_perl_struct_code typ cols name style n do_cleanups =
7014   pr "PREINIT:\n";
7015   pr "      struct guestfs_%s *%s;\n" typ n;
7016   pr " PPCODE:\n";
7017   pr "      %s = guestfs_%s " n name;
7018   generate_c_call_args ~handle:"g" style;
7019   pr ";\n";
7020   do_cleanups ();
7021   pr "      if (%s == NULL)\n" n;
7022   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7023   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
7024   List.iter (
7025     fun ((name, _) as col) ->
7026       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
7027
7028       match col with
7029       | name, FString ->
7030           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
7031             n name
7032       | name, FBuffer ->
7033           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
7034             n name n name
7035       | name, FUUID ->
7036           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
7037             n name
7038       | name, (FBytes|FUInt64) ->
7039           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
7040             n name
7041       | name, FInt64 ->
7042           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
7043             n name
7044       | name, (FInt32|FUInt32) ->
7045           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
7046             n name
7047       | name, FChar ->
7048           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
7049             n name
7050       | name, FOptPercent ->
7051           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
7052             n name
7053   ) cols;
7054   pr "      free (%s);\n" n
7055
7056 (* Generate Sys/Guestfs.pm. *)
7057 and generate_perl_pm () =
7058   generate_header HashStyle LGPLv2;
7059
7060   pr "\
7061 =pod
7062
7063 =head1 NAME
7064
7065 Sys::Guestfs - Perl bindings for libguestfs
7066
7067 =head1 SYNOPSIS
7068
7069  use Sys::Guestfs;
7070
7071  my $h = Sys::Guestfs->new ();
7072  $h->add_drive ('guest.img');
7073  $h->launch ();
7074  $h->wait_ready ();
7075  $h->mount ('/dev/sda1', '/');
7076  $h->touch ('/hello');
7077  $h->sync ();
7078
7079 =head1 DESCRIPTION
7080
7081 The C<Sys::Guestfs> module provides a Perl XS binding to the
7082 libguestfs API for examining and modifying virtual machine
7083 disk images.
7084
7085 Amongst the things this is good for: making batch configuration
7086 changes to guests, getting disk used/free statistics (see also:
7087 virt-df), migrating between virtualization systems (see also:
7088 virt-p2v), performing partial backups, performing partial guest
7089 clones, cloning guests and changing registry/UUID/hostname info, and
7090 much else besides.
7091
7092 Libguestfs uses Linux kernel and qemu code, and can access any type of
7093 guest filesystem that Linux and qemu can, including but not limited
7094 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7095 schemes, qcow, qcow2, vmdk.
7096
7097 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7098 LVs, what filesystem is in each LV, etc.).  It can also run commands
7099 in the context of the guest.  Also you can access filesystems over FTP.
7100
7101 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
7102 functions for using libguestfs from Perl, including integration
7103 with libvirt.
7104
7105 =head1 ERRORS
7106
7107 All errors turn into calls to C<croak> (see L<Carp(3)>).
7108
7109 =head1 METHODS
7110
7111 =over 4
7112
7113 =cut
7114
7115 package Sys::Guestfs;
7116
7117 use strict;
7118 use warnings;
7119
7120 require XSLoader;
7121 XSLoader::load ('Sys::Guestfs');
7122
7123 =item $h = Sys::Guestfs->new ();
7124
7125 Create a new guestfs handle.
7126
7127 =cut
7128
7129 sub new {
7130   my $proto = shift;
7131   my $class = ref ($proto) || $proto;
7132
7133   my $self = Sys::Guestfs::_create ();
7134   bless $self, $class;
7135   return $self;
7136 }
7137
7138 ";
7139
7140   (* Actions.  We only need to print documentation for these as
7141    * they are pulled in from the XS code automatically.
7142    *)
7143   List.iter (
7144     fun (name, style, _, flags, _, _, longdesc) ->
7145       if not (List.mem NotInDocs flags) then (
7146         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
7147         pr "=item ";
7148         generate_perl_prototype name style;
7149         pr "\n\n";
7150         pr "%s\n\n" longdesc;
7151         if List.mem ProtocolLimitWarning flags then
7152           pr "%s\n\n" protocol_limit_warning;
7153         if List.mem DangerWillRobinson flags then
7154           pr "%s\n\n" danger_will_robinson;
7155         match deprecation_notice flags with
7156         | None -> ()
7157         | Some txt -> pr "%s\n\n" txt
7158       )
7159   ) all_functions_sorted;
7160
7161   (* End of file. *)
7162   pr "\
7163 =cut
7164
7165 1;
7166
7167 =back
7168
7169 =head1 COPYRIGHT
7170
7171 Copyright (C) 2009 Red Hat Inc.
7172
7173 =head1 LICENSE
7174
7175 Please see the file COPYING.LIB for the full license.
7176
7177 =head1 SEE ALSO
7178
7179 L<guestfs(3)>,
7180 L<guestfish(1)>,
7181 L<http://libguestfs.org>,
7182 L<Sys::Guestfs::Lib(3)>.
7183
7184 =cut
7185 "
7186
7187 and generate_perl_prototype name style =
7188   (match fst style with
7189    | RErr -> ()
7190    | RBool n
7191    | RInt n
7192    | RInt64 n
7193    | RConstString n
7194    | RConstOptString n
7195    | RString n
7196    | RBufferOut n -> pr "$%s = " n
7197    | RStruct (n,_)
7198    | RHashtable n -> pr "%%%s = " n
7199    | RStringList n
7200    | RStructList (n,_) -> pr "@%s = " n
7201   );
7202   pr "$h->%s (" name;
7203   let comma = ref false in
7204   List.iter (
7205     fun arg ->
7206       if !comma then pr ", ";
7207       comma := true;
7208       match arg with
7209       | Device n | String n
7210       | OptString n | Bool n | Int n | FileIn n | FileOut n ->
7211           pr "$%s" n
7212       | StringList n ->
7213           pr "\\@%s" n
7214   ) (snd style);
7215   pr ");"
7216
7217 (* Generate Python C module. *)
7218 and generate_python_c () =
7219   generate_header CStyle LGPLv2;
7220
7221   pr "\
7222 #include <stdio.h>
7223 #include <stdlib.h>
7224 #include <assert.h>
7225
7226 #include <Python.h>
7227
7228 #include \"guestfs.h\"
7229
7230 typedef struct {
7231   PyObject_HEAD
7232   guestfs_h *g;
7233 } Pyguestfs_Object;
7234
7235 static guestfs_h *
7236 get_handle (PyObject *obj)
7237 {
7238   assert (obj);
7239   assert (obj != Py_None);
7240   return ((Pyguestfs_Object *) obj)->g;
7241 }
7242
7243 static PyObject *
7244 put_handle (guestfs_h *g)
7245 {
7246   assert (g);
7247   return
7248     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
7249 }
7250
7251 /* This list should be freed (but not the strings) after use. */
7252 static const char **
7253 get_string_list (PyObject *obj)
7254 {
7255   int i, len;
7256   const char **r;
7257
7258   assert (obj);
7259
7260   if (!PyList_Check (obj)) {
7261     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
7262     return NULL;
7263   }
7264
7265   len = PyList_Size (obj);
7266   r = malloc (sizeof (char *) * (len+1));
7267   if (r == NULL) {
7268     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
7269     return NULL;
7270   }
7271
7272   for (i = 0; i < len; ++i)
7273     r[i] = PyString_AsString (PyList_GetItem (obj, i));
7274   r[len] = NULL;
7275
7276   return r;
7277 }
7278
7279 static PyObject *
7280 put_string_list (char * const * const argv)
7281 {
7282   PyObject *list;
7283   int argc, i;
7284
7285   for (argc = 0; argv[argc] != NULL; ++argc)
7286     ;
7287
7288   list = PyList_New (argc);
7289   for (i = 0; i < argc; ++i)
7290     PyList_SetItem (list, i, PyString_FromString (argv[i]));
7291
7292   return list;
7293 }
7294
7295 static PyObject *
7296 put_table (char * const * const argv)
7297 {
7298   PyObject *list, *item;
7299   int argc, i;
7300
7301   for (argc = 0; argv[argc] != NULL; ++argc)
7302     ;
7303
7304   list = PyList_New (argc >> 1);
7305   for (i = 0; i < argc; i += 2) {
7306     item = PyTuple_New (2);
7307     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
7308     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
7309     PyList_SetItem (list, i >> 1, item);
7310   }
7311
7312   return list;
7313 }
7314
7315 static void
7316 free_strings (char **argv)
7317 {
7318   int argc;
7319
7320   for (argc = 0; argv[argc] != NULL; ++argc)
7321     free (argv[argc]);
7322   free (argv);
7323 }
7324
7325 static PyObject *
7326 py_guestfs_create (PyObject *self, PyObject *args)
7327 {
7328   guestfs_h *g;
7329
7330   g = guestfs_create ();
7331   if (g == NULL) {
7332     PyErr_SetString (PyExc_RuntimeError,
7333                      \"guestfs.create: failed to allocate handle\");
7334     return NULL;
7335   }
7336   guestfs_set_error_handler (g, NULL, NULL);
7337   return put_handle (g);
7338 }
7339
7340 static PyObject *
7341 py_guestfs_close (PyObject *self, PyObject *args)
7342 {
7343   PyObject *py_g;
7344   guestfs_h *g;
7345
7346   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
7347     return NULL;
7348   g = get_handle (py_g);
7349
7350   guestfs_close (g);
7351
7352   Py_INCREF (Py_None);
7353   return Py_None;
7354 }
7355
7356 ";
7357
7358   (* Structures, turned into Python dictionaries. *)
7359   List.iter (
7360     fun (typ, cols) ->
7361       pr "static PyObject *\n";
7362       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
7363       pr "{\n";
7364       pr "  PyObject *dict;\n";
7365       pr "\n";
7366       pr "  dict = PyDict_New ();\n";
7367       List.iter (
7368         function
7369         | name, FString ->
7370             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7371             pr "                        PyString_FromString (%s->%s));\n"
7372               typ name
7373         | name, FBuffer ->
7374             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7375             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
7376               typ name typ name
7377         | name, FUUID ->
7378             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7379             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
7380               typ name
7381         | name, (FBytes|FUInt64) ->
7382             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7383             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
7384               typ name
7385         | name, FInt64 ->
7386             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7387             pr "                        PyLong_FromLongLong (%s->%s));\n"
7388               typ name
7389         | name, FUInt32 ->
7390             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7391             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
7392               typ name
7393         | name, FInt32 ->
7394             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7395             pr "                        PyLong_FromLong (%s->%s));\n"
7396               typ name
7397         | name, FOptPercent ->
7398             pr "  if (%s->%s >= 0)\n" typ name;
7399             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
7400             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
7401               typ name;
7402             pr "  else {\n";
7403             pr "    Py_INCREF (Py_None);\n";
7404             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
7405             pr "  }\n"
7406         | name, FChar ->
7407             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7408             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
7409       ) cols;
7410       pr "  return dict;\n";
7411       pr "};\n";
7412       pr "\n";
7413
7414       pr "static PyObject *\n";
7415       pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
7416       pr "{\n";
7417       pr "  PyObject *list;\n";
7418       pr "  int i;\n";
7419       pr "\n";
7420       pr "  list = PyList_New (%ss->len);\n" typ;
7421       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
7422       pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
7423       pr "  return list;\n";
7424       pr "};\n";
7425       pr "\n"
7426   ) structs;
7427
7428   (* Python wrapper functions. *)
7429   List.iter (
7430     fun (name, style, _, _, _, _, _) ->
7431       pr "static PyObject *\n";
7432       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
7433       pr "{\n";
7434
7435       pr "  PyObject *py_g;\n";
7436       pr "  guestfs_h *g;\n";
7437       pr "  PyObject *py_r;\n";
7438
7439       let error_code =
7440         match fst style with
7441         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
7442         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7443         | RConstString _ | RConstOptString _ ->
7444             pr "  const char *r;\n"; "NULL"
7445         | RString _ -> pr "  char *r;\n"; "NULL"
7446         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
7447         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
7448         | RStructList (_, typ) ->
7449             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7450         | RBufferOut _ ->
7451             pr "  char *r;\n";
7452             pr "  size_t size;\n";
7453             "NULL" in
7454
7455       List.iter (
7456         function
7457         | Device n | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
7458         | OptString n -> pr "  const char *%s;\n" n
7459         | StringList n ->
7460             pr "  PyObject *py_%s;\n" n;
7461             pr "  const char **%s;\n" n
7462         | Bool n -> pr "  int %s;\n" n
7463         | Int n -> pr "  int %s;\n" n
7464       ) (snd style);
7465
7466       pr "\n";
7467
7468       (* Convert the parameters. *)
7469       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
7470       List.iter (
7471         function
7472         | Device _ | String _ | FileIn _ | FileOut _ -> pr "s"
7473         | OptString _ -> pr "z"
7474         | StringList _ -> pr "O"
7475         | Bool _ -> pr "i" (* XXX Python has booleans? *)
7476         | Int _ -> pr "i"
7477       ) (snd style);
7478       pr ":guestfs_%s\",\n" name;
7479       pr "                         &py_g";
7480       List.iter (
7481         function
7482         | Device n | String n | FileIn n | FileOut n -> pr ", &%s" n
7483         | OptString n -> pr ", &%s" n
7484         | StringList n -> pr ", &py_%s" n
7485         | Bool n -> pr ", &%s" n
7486         | Int n -> pr ", &%s" n
7487       ) (snd style);
7488
7489       pr "))\n";
7490       pr "    return NULL;\n";
7491
7492       pr "  g = get_handle (py_g);\n";
7493       List.iter (
7494         function
7495         | Device _ | String _
7496         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7497         | StringList n ->
7498             pr "  %s = get_string_list (py_%s);\n" n n;
7499             pr "  if (!%s) return NULL;\n" n
7500       ) (snd style);
7501
7502       pr "\n";
7503
7504       pr "  r = guestfs_%s " name;
7505       generate_c_call_args ~handle:"g" style;
7506       pr ";\n";
7507
7508       List.iter (
7509         function
7510         | Device _ | String _
7511         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7512         | StringList n ->
7513             pr "  free (%s);\n" n
7514       ) (snd style);
7515
7516       pr "  if (r == %s) {\n" error_code;
7517       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
7518       pr "    return NULL;\n";
7519       pr "  }\n";
7520       pr "\n";
7521
7522       (match fst style with
7523        | RErr ->
7524            pr "  Py_INCREF (Py_None);\n";
7525            pr "  py_r = Py_None;\n"
7526        | RInt _
7527        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
7528        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
7529        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
7530        | RConstOptString _ ->
7531            pr "  if (r)\n";
7532            pr "    py_r = PyString_FromString (r);\n";
7533            pr "  else {\n";
7534            pr "    Py_INCREF (Py_None);\n";
7535            pr "    py_r = Py_None;\n";
7536            pr "  }\n"
7537        | RString _ ->
7538            pr "  py_r = PyString_FromString (r);\n";
7539            pr "  free (r);\n"
7540        | RStringList _ ->
7541            pr "  py_r = put_string_list (r);\n";
7542            pr "  free_strings (r);\n"
7543        | RStruct (_, typ) ->
7544            pr "  py_r = put_%s (r);\n" typ;
7545            pr "  guestfs_free_%s (r);\n" typ
7546        | RStructList (_, typ) ->
7547            pr "  py_r = put_%s_list (r);\n" typ;
7548            pr "  guestfs_free_%s_list (r);\n" typ
7549        | RHashtable n ->
7550            pr "  py_r = put_table (r);\n";
7551            pr "  free_strings (r);\n"
7552        | RBufferOut _ ->
7553            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
7554            pr "  free (r);\n"
7555       );
7556
7557       pr "  return py_r;\n";
7558       pr "}\n";
7559       pr "\n"
7560   ) all_functions;
7561
7562   (* Table of functions. *)
7563   pr "static PyMethodDef methods[] = {\n";
7564   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
7565   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
7566   List.iter (
7567     fun (name, _, _, _, _, _, _) ->
7568       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
7569         name name
7570   ) all_functions;
7571   pr "  { NULL, NULL, 0, NULL }\n";
7572   pr "};\n";
7573   pr "\n";
7574
7575   (* Init function. *)
7576   pr "\
7577 void
7578 initlibguestfsmod (void)
7579 {
7580   static int initialized = 0;
7581
7582   if (initialized) return;
7583   Py_InitModule ((char *) \"libguestfsmod\", methods);
7584   initialized = 1;
7585 }
7586 "
7587
7588 (* Generate Python module. *)
7589 and generate_python_py () =
7590   generate_header HashStyle LGPLv2;
7591
7592   pr "\
7593 u\"\"\"Python bindings for libguestfs
7594
7595 import guestfs
7596 g = guestfs.GuestFS ()
7597 g.add_drive (\"guest.img\")
7598 g.launch ()
7599 g.wait_ready ()
7600 parts = g.list_partitions ()
7601
7602 The guestfs module provides a Python binding to the libguestfs API
7603 for examining and modifying virtual machine disk images.
7604
7605 Amongst the things this is good for: making batch configuration
7606 changes to guests, getting disk used/free statistics (see also:
7607 virt-df), migrating between virtualization systems (see also:
7608 virt-p2v), performing partial backups, performing partial guest
7609 clones, cloning guests and changing registry/UUID/hostname info, and
7610 much else besides.
7611
7612 Libguestfs uses Linux kernel and qemu code, and can access any type of
7613 guest filesystem that Linux and qemu can, including but not limited
7614 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7615 schemes, qcow, qcow2, vmdk.
7616
7617 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7618 LVs, what filesystem is in each LV, etc.).  It can also run commands
7619 in the context of the guest.  Also you can access filesystems over FTP.
7620
7621 Errors which happen while using the API are turned into Python
7622 RuntimeError exceptions.
7623
7624 To create a guestfs handle you usually have to perform the following
7625 sequence of calls:
7626
7627 # Create the handle, call add_drive at least once, and possibly
7628 # several times if the guest has multiple block devices:
7629 g = guestfs.GuestFS ()
7630 g.add_drive (\"guest.img\")
7631
7632 # Launch the qemu subprocess and wait for it to become ready:
7633 g.launch ()
7634 g.wait_ready ()
7635
7636 # Now you can issue commands, for example:
7637 logvols = g.lvs ()
7638
7639 \"\"\"
7640
7641 import libguestfsmod
7642
7643 class GuestFS:
7644     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
7645
7646     def __init__ (self):
7647         \"\"\"Create a new libguestfs handle.\"\"\"
7648         self._o = libguestfsmod.create ()
7649
7650     def __del__ (self):
7651         libguestfsmod.close (self._o)
7652
7653 ";
7654
7655   List.iter (
7656     fun (name, style, _, flags, _, _, longdesc) ->
7657       pr "    def %s " name;
7658       generate_py_call_args ~handle:"self" (snd style);
7659       pr ":\n";
7660
7661       if not (List.mem NotInDocs flags) then (
7662         let doc = replace_str longdesc "C<guestfs_" "C<g." in
7663         let doc =
7664           match fst style with
7665           | RErr | RInt _ | RInt64 _ | RBool _
7666           | RConstOptString _ | RConstString _
7667           | RString _ | RBufferOut _ -> doc
7668           | RStringList _ ->
7669               doc ^ "\n\nThis function returns a list of strings."
7670           | RStruct (_, typ) ->
7671               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
7672           | RStructList (_, typ) ->
7673               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
7674           | RHashtable _ ->
7675               doc ^ "\n\nThis function returns a dictionary." in
7676         let doc =
7677           if List.mem ProtocolLimitWarning flags then
7678             doc ^ "\n\n" ^ protocol_limit_warning
7679           else doc in
7680         let doc =
7681           if List.mem DangerWillRobinson flags then
7682             doc ^ "\n\n" ^ danger_will_robinson
7683           else doc in
7684         let doc =
7685           match deprecation_notice flags with
7686           | None -> doc
7687           | Some txt -> doc ^ "\n\n" ^ txt in
7688         let doc = pod2text ~width:60 name doc in
7689         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
7690         let doc = String.concat "\n        " doc in
7691         pr "        u\"\"\"%s\"\"\"\n" doc;
7692       );
7693       pr "        return libguestfsmod.%s " name;
7694       generate_py_call_args ~handle:"self._o" (snd style);
7695       pr "\n";
7696       pr "\n";
7697   ) all_functions
7698
7699 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
7700 and generate_py_call_args ~handle args =
7701   pr "(%s" handle;
7702   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
7703   pr ")"
7704
7705 (* Useful if you need the longdesc POD text as plain text.  Returns a
7706  * list of lines.
7707  *
7708  * Because this is very slow (the slowest part of autogeneration),
7709  * we memoize the results.
7710  *)
7711 and pod2text ~width name longdesc =
7712   let key = width, name, longdesc in
7713   try Hashtbl.find pod2text_memo key
7714   with Not_found ->
7715     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
7716     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
7717     close_out chan;
7718     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
7719     let chan = Unix.open_process_in cmd in
7720     let lines = ref [] in
7721     let rec loop i =
7722       let line = input_line chan in
7723       if i = 1 then             (* discard the first line of output *)
7724         loop (i+1)
7725       else (
7726         let line = triml line in
7727         lines := line :: !lines;
7728         loop (i+1)
7729       ) in
7730     let lines = try loop 1 with End_of_file -> List.rev !lines in
7731     Unix.unlink filename;
7732     (match Unix.close_process_in chan with
7733      | Unix.WEXITED 0 -> ()
7734      | Unix.WEXITED i ->
7735          failwithf "pod2text: process exited with non-zero status (%d)" i
7736      | Unix.WSIGNALED i | Unix.WSTOPPED i ->
7737          failwithf "pod2text: process signalled or stopped by signal %d" i
7738     );
7739     Hashtbl.add pod2text_memo key lines;
7740     let chan = open_out pod2text_memo_filename in
7741     output_value chan pod2text_memo;
7742     close_out chan;
7743     lines
7744
7745 (* Generate ruby bindings. *)
7746 and generate_ruby_c () =
7747   generate_header CStyle LGPLv2;
7748
7749   pr "\
7750 #include <stdio.h>
7751 #include <stdlib.h>
7752
7753 #include <ruby.h>
7754
7755 #include \"guestfs.h\"
7756
7757 #include \"extconf.h\"
7758
7759 /* For Ruby < 1.9 */
7760 #ifndef RARRAY_LEN
7761 #define RARRAY_LEN(r) (RARRAY((r))->len)
7762 #endif
7763
7764 static VALUE m_guestfs;                 /* guestfs module */
7765 static VALUE c_guestfs;                 /* guestfs_h handle */
7766 static VALUE e_Error;                   /* used for all errors */
7767
7768 static void ruby_guestfs_free (void *p)
7769 {
7770   if (!p) return;
7771   guestfs_close ((guestfs_h *) p);
7772 }
7773
7774 static VALUE ruby_guestfs_create (VALUE m)
7775 {
7776   guestfs_h *g;
7777
7778   g = guestfs_create ();
7779   if (!g)
7780     rb_raise (e_Error, \"failed to create guestfs handle\");
7781
7782   /* Don't print error messages to stderr by default. */
7783   guestfs_set_error_handler (g, NULL, NULL);
7784
7785   /* Wrap it, and make sure the close function is called when the
7786    * handle goes away.
7787    */
7788   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
7789 }
7790
7791 static VALUE ruby_guestfs_close (VALUE gv)
7792 {
7793   guestfs_h *g;
7794   Data_Get_Struct (gv, guestfs_h, g);
7795
7796   ruby_guestfs_free (g);
7797   DATA_PTR (gv) = NULL;
7798
7799   return Qnil;
7800 }
7801
7802 ";
7803
7804   List.iter (
7805     fun (name, style, _, _, _, _, _) ->
7806       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
7807       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
7808       pr ")\n";
7809       pr "{\n";
7810       pr "  guestfs_h *g;\n";
7811       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
7812       pr "  if (!g)\n";
7813       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
7814         name;
7815       pr "\n";
7816
7817       List.iter (
7818         function
7819         | Device n | String n | FileIn n | FileOut n ->
7820             pr "  Check_Type (%sv, T_STRING);\n" n;
7821             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
7822             pr "  if (!%s)\n" n;
7823             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
7824             pr "              \"%s\", \"%s\");\n" n name
7825         | OptString n ->
7826             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
7827         | StringList n ->
7828             pr "  char **%s;\n" n;
7829             pr "  Check_Type (%sv, T_ARRAY);\n" n;
7830             pr "  {\n";
7831             pr "    int i, len;\n";
7832             pr "    len = RARRAY_LEN (%sv);\n" n;
7833             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
7834               n;
7835             pr "    for (i = 0; i < len; ++i) {\n";
7836             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
7837             pr "      %s[i] = StringValueCStr (v);\n" n;
7838             pr "    }\n";
7839             pr "    %s[len] = NULL;\n" n;
7840             pr "  }\n";
7841         | Bool n ->
7842             pr "  int %s = RTEST (%sv);\n" n n
7843         | Int n ->
7844             pr "  int %s = NUM2INT (%sv);\n" n n
7845       ) (snd style);
7846       pr "\n";
7847
7848       let error_code =
7849         match fst style with
7850         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
7851         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7852         | RConstString _ | RConstOptString _ ->
7853             pr "  const char *r;\n"; "NULL"
7854         | RString _ -> pr "  char *r;\n"; "NULL"
7855         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
7856         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
7857         | RStructList (_, typ) ->
7858             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7859         | RBufferOut _ ->
7860             pr "  char *r;\n";
7861             pr "  size_t size;\n";
7862             "NULL" in
7863       pr "\n";
7864
7865       pr "  r = guestfs_%s " name;
7866       generate_c_call_args ~handle:"g" style;
7867       pr ";\n";
7868
7869       List.iter (
7870         function
7871         | Device _ | String _
7872         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7873         | StringList n ->
7874             pr "  free (%s);\n" n
7875       ) (snd style);
7876
7877       pr "  if (r == %s)\n" error_code;
7878       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
7879       pr "\n";
7880
7881       (match fst style with
7882        | RErr ->
7883            pr "  return Qnil;\n"
7884        | RInt _ | RBool _ ->
7885            pr "  return INT2NUM (r);\n"
7886        | RInt64 _ ->
7887            pr "  return ULL2NUM (r);\n"
7888        | RConstString _ ->
7889            pr "  return rb_str_new2 (r);\n";
7890        | RConstOptString _ ->
7891            pr "  if (r)\n";
7892            pr "    return rb_str_new2 (r);\n";
7893            pr "  else\n";
7894            pr "    return Qnil;\n";
7895        | RString _ ->
7896            pr "  VALUE rv = rb_str_new2 (r);\n";
7897            pr "  free (r);\n";
7898            pr "  return rv;\n";
7899        | RStringList _ ->
7900            pr "  int i, len = 0;\n";
7901            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
7902            pr "  VALUE rv = rb_ary_new2 (len);\n";
7903            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
7904            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
7905            pr "    free (r[i]);\n";
7906            pr "  }\n";
7907            pr "  free (r);\n";
7908            pr "  return rv;\n"
7909        | RStruct (_, typ) ->
7910            let cols = cols_of_struct typ in
7911            generate_ruby_struct_code typ cols
7912        | RStructList (_, typ) ->
7913            let cols = cols_of_struct typ in
7914            generate_ruby_struct_list_code typ cols
7915        | RHashtable _ ->
7916            pr "  VALUE rv = rb_hash_new ();\n";
7917            pr "  int i;\n";
7918            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
7919            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
7920            pr "    free (r[i]);\n";
7921            pr "    free (r[i+1]);\n";
7922            pr "  }\n";
7923            pr "  free (r);\n";
7924            pr "  return rv;\n"
7925        | RBufferOut _ ->
7926            pr "  VALUE rv = rb_str_new (r, size);\n";
7927            pr "  free (r);\n";
7928            pr "  return rv;\n";
7929       );
7930
7931       pr "}\n";
7932       pr "\n"
7933   ) all_functions;
7934
7935   pr "\
7936 /* Initialize the module. */
7937 void Init__guestfs ()
7938 {
7939   m_guestfs = rb_define_module (\"Guestfs\");
7940   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
7941   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
7942
7943   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
7944   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
7945
7946 ";
7947   (* Define the rest of the methods. *)
7948   List.iter (
7949     fun (name, style, _, _, _, _, _) ->
7950       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
7951       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
7952   ) all_functions;
7953
7954   pr "}\n"
7955
7956 (* Ruby code to return a struct. *)
7957 and generate_ruby_struct_code typ cols =
7958   pr "  VALUE rv = rb_hash_new ();\n";
7959   List.iter (
7960     function
7961     | name, FString ->
7962         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
7963     | name, FBuffer ->
7964         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
7965     | name, FUUID ->
7966         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
7967     | name, (FBytes|FUInt64) ->
7968         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7969     | name, FInt64 ->
7970         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
7971     | name, FUInt32 ->
7972         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
7973     | name, FInt32 ->
7974         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
7975     | name, FOptPercent ->
7976         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
7977     | name, FChar -> (* XXX wrong? *)
7978         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7979   ) cols;
7980   pr "  guestfs_free_%s (r);\n" typ;
7981   pr "  return rv;\n"
7982
7983 (* Ruby code to return a struct list. *)
7984 and generate_ruby_struct_list_code typ cols =
7985   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
7986   pr "  int i;\n";
7987   pr "  for (i = 0; i < r->len; ++i) {\n";
7988   pr "    VALUE hv = rb_hash_new ();\n";
7989   List.iter (
7990     function
7991     | name, FString ->
7992         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7993     | name, FBuffer ->
7994         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
7995     | name, FUUID ->
7996         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
7997     | name, (FBytes|FUInt64) ->
7998         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7999     | name, FInt64 ->
8000         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
8001     | name, FUInt32 ->
8002         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
8003     | name, FInt32 ->
8004         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
8005     | name, FOptPercent ->
8006         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
8007     | name, FChar -> (* XXX wrong? *)
8008         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
8009   ) cols;
8010   pr "    rb_ary_push (rv, hv);\n";
8011   pr "  }\n";
8012   pr "  guestfs_free_%s_list (r);\n" typ;
8013   pr "  return rv;\n"
8014
8015 (* Generate Java bindings GuestFS.java file. *)
8016 and generate_java_java () =
8017   generate_header CStyle LGPLv2;
8018
8019   pr "\
8020 package com.redhat.et.libguestfs;
8021
8022 import java.util.HashMap;
8023 import com.redhat.et.libguestfs.LibGuestFSException;
8024 import com.redhat.et.libguestfs.PV;
8025 import com.redhat.et.libguestfs.VG;
8026 import com.redhat.et.libguestfs.LV;
8027 import com.redhat.et.libguestfs.Stat;
8028 import com.redhat.et.libguestfs.StatVFS;
8029 import com.redhat.et.libguestfs.IntBool;
8030 import com.redhat.et.libguestfs.Dirent;
8031
8032 /**
8033  * The GuestFS object is a libguestfs handle.
8034  *
8035  * @author rjones
8036  */
8037 public class GuestFS {
8038   // Load the native code.
8039   static {
8040     System.loadLibrary (\"guestfs_jni\");
8041   }
8042
8043   /**
8044    * The native guestfs_h pointer.
8045    */
8046   long g;
8047
8048   /**
8049    * Create a libguestfs handle.
8050    *
8051    * @throws LibGuestFSException
8052    */
8053   public GuestFS () throws LibGuestFSException
8054   {
8055     g = _create ();
8056   }
8057   private native long _create () throws LibGuestFSException;
8058
8059   /**
8060    * Close a libguestfs handle.
8061    *
8062    * You can also leave handles to be collected by the garbage
8063    * collector, but this method ensures that the resources used
8064    * by the handle are freed up immediately.  If you call any
8065    * other methods after closing the handle, you will get an
8066    * exception.
8067    *
8068    * @throws LibGuestFSException
8069    */
8070   public void close () throws LibGuestFSException
8071   {
8072     if (g != 0)
8073       _close (g);
8074     g = 0;
8075   }
8076   private native void _close (long g) throws LibGuestFSException;
8077
8078   public void finalize () throws LibGuestFSException
8079   {
8080     close ();
8081   }
8082
8083 ";
8084
8085   List.iter (
8086     fun (name, style, _, flags, _, shortdesc, longdesc) ->
8087       if not (List.mem NotInDocs flags); then (
8088         let doc = replace_str longdesc "C<guestfs_" "C<g." in
8089         let doc =
8090           if List.mem ProtocolLimitWarning flags then
8091             doc ^ "\n\n" ^ protocol_limit_warning
8092           else doc in
8093         let doc =
8094           if List.mem DangerWillRobinson flags then
8095             doc ^ "\n\n" ^ danger_will_robinson
8096           else doc in
8097         let doc =
8098           match deprecation_notice flags with
8099           | None -> doc
8100           | Some txt -> doc ^ "\n\n" ^ txt in
8101         let doc = pod2text ~width:60 name doc in
8102         let doc = List.map (            (* RHBZ#501883 *)
8103           function
8104           | "" -> "<p>"
8105           | nonempty -> nonempty
8106         ) doc in
8107         let doc = String.concat "\n   * " doc in
8108
8109         pr "  /**\n";
8110         pr "   * %s\n" shortdesc;
8111         pr "   * <p>\n";
8112         pr "   * %s\n" doc;
8113         pr "   * @throws LibGuestFSException\n";
8114         pr "   */\n";
8115         pr "  ";
8116       );
8117       generate_java_prototype ~public:true ~semicolon:false name style;
8118       pr "\n";
8119       pr "  {\n";
8120       pr "    if (g == 0)\n";
8121       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
8122         name;
8123       pr "    ";
8124       if fst style <> RErr then pr "return ";
8125       pr "_%s " name;
8126       generate_java_call_args ~handle:"g" (snd style);
8127       pr ";\n";
8128       pr "  }\n";
8129       pr "  ";
8130       generate_java_prototype ~privat:true ~native:true name style;
8131       pr "\n";
8132       pr "\n";
8133   ) all_functions;
8134
8135   pr "}\n"
8136
8137 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
8138 and generate_java_call_args ~handle args =
8139   pr "(%s" handle;
8140   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
8141   pr ")"
8142
8143 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
8144     ?(semicolon=true) name style =
8145   if privat then pr "private ";
8146   if public then pr "public ";
8147   if native then pr "native ";
8148
8149   (* return type *)
8150   (match fst style with
8151    | RErr -> pr "void ";
8152    | RInt _ -> pr "int ";
8153    | RInt64 _ -> pr "long ";
8154    | RBool _ -> pr "boolean ";
8155    | RConstString _ | RConstOptString _ | RString _
8156    | RBufferOut _ -> pr "String ";
8157    | RStringList _ -> pr "String[] ";
8158    | RStruct (_, typ) ->
8159        let name = java_name_of_struct typ in
8160        pr "%s " name;
8161    | RStructList (_, typ) ->
8162        let name = java_name_of_struct typ in
8163        pr "%s[] " name;
8164    | RHashtable _ -> pr "HashMap<String,String> ";
8165   );
8166
8167   if native then pr "_%s " name else pr "%s " name;
8168   pr "(";
8169   let needs_comma = ref false in
8170   if native then (
8171     pr "long g";
8172     needs_comma := true
8173   );
8174
8175   (* args *)
8176   List.iter (
8177     fun arg ->
8178       if !needs_comma then pr ", ";
8179       needs_comma := true;
8180
8181       match arg with
8182       | Device n
8183       | String n
8184       | OptString n
8185       | FileIn n
8186       | FileOut n ->
8187           pr "String %s" n
8188       | StringList n ->
8189           pr "String[] %s" n
8190       | Bool n ->
8191           pr "boolean %s" n
8192       | Int n ->
8193           pr "int %s" n
8194   ) (snd style);
8195
8196   pr ")\n";
8197   pr "    throws LibGuestFSException";
8198   if semicolon then pr ";"
8199
8200 and generate_java_struct jtyp cols =
8201   generate_header CStyle LGPLv2;
8202
8203   pr "\
8204 package com.redhat.et.libguestfs;
8205
8206 /**
8207  * Libguestfs %s structure.
8208  *
8209  * @author rjones
8210  * @see GuestFS
8211  */
8212 public class %s {
8213 " jtyp jtyp;
8214
8215   List.iter (
8216     function
8217     | name, FString
8218     | name, FUUID
8219     | name, FBuffer -> pr "  public String %s;\n" name
8220     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
8221     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
8222     | name, FChar -> pr "  public char %s;\n" name
8223     | name, FOptPercent ->
8224         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
8225         pr "  public float %s;\n" name
8226   ) cols;
8227
8228   pr "}\n"
8229
8230 and generate_java_c () =
8231   generate_header CStyle LGPLv2;
8232
8233   pr "\
8234 #include <stdio.h>
8235 #include <stdlib.h>
8236 #include <string.h>
8237
8238 #include \"com_redhat_et_libguestfs_GuestFS.h\"
8239 #include \"guestfs.h\"
8240
8241 /* Note that this function returns.  The exception is not thrown
8242  * until after the wrapper function returns.
8243  */
8244 static void
8245 throw_exception (JNIEnv *env, const char *msg)
8246 {
8247   jclass cl;
8248   cl = (*env)->FindClass (env,
8249                           \"com/redhat/et/libguestfs/LibGuestFSException\");
8250   (*env)->ThrowNew (env, cl, msg);
8251 }
8252
8253 JNIEXPORT jlong JNICALL
8254 Java_com_redhat_et_libguestfs_GuestFS__1create
8255   (JNIEnv *env, jobject obj)
8256 {
8257   guestfs_h *g;
8258
8259   g = guestfs_create ();
8260   if (g == NULL) {
8261     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
8262     return 0;
8263   }
8264   guestfs_set_error_handler (g, NULL, NULL);
8265   return (jlong) (long) g;
8266 }
8267
8268 JNIEXPORT void JNICALL
8269 Java_com_redhat_et_libguestfs_GuestFS__1close
8270   (JNIEnv *env, jobject obj, jlong jg)
8271 {
8272   guestfs_h *g = (guestfs_h *) (long) jg;
8273   guestfs_close (g);
8274 }
8275
8276 ";
8277
8278   List.iter (
8279     fun (name, style, _, _, _, _, _) ->
8280       pr "JNIEXPORT ";
8281       (match fst style with
8282        | RErr -> pr "void ";
8283        | RInt _ -> pr "jint ";
8284        | RInt64 _ -> pr "jlong ";
8285        | RBool _ -> pr "jboolean ";
8286        | RConstString _ | RConstOptString _ | RString _
8287        | RBufferOut _ -> pr "jstring ";
8288        | RStruct _ | RHashtable _ ->
8289            pr "jobject ";
8290        | RStringList _ | RStructList _ ->
8291            pr "jobjectArray ";
8292       );
8293       pr "JNICALL\n";
8294       pr "Java_com_redhat_et_libguestfs_GuestFS_";
8295       pr "%s" (replace_str ("_" ^ name) "_" "_1");
8296       pr "\n";
8297       pr "  (JNIEnv *env, jobject obj, jlong jg";
8298       List.iter (
8299         function
8300         | Device n
8301         | String n
8302         | OptString n
8303         | FileIn n
8304         | FileOut n ->
8305             pr ", jstring j%s" n
8306         | StringList n ->
8307             pr ", jobjectArray j%s" n
8308         | Bool n ->
8309             pr ", jboolean j%s" n
8310         | Int n ->
8311             pr ", jint j%s" n
8312       ) (snd style);
8313       pr ")\n";
8314       pr "{\n";
8315       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
8316       let error_code, no_ret =
8317         match fst style with
8318         | RErr -> pr "  int r;\n"; "-1", ""
8319         | RBool _
8320         | RInt _ -> pr "  int r;\n"; "-1", "0"
8321         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
8322         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
8323         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
8324         | RString _ ->
8325             pr "  jstring jr;\n";
8326             pr "  char *r;\n"; "NULL", "NULL"
8327         | RStringList _ ->
8328             pr "  jobjectArray jr;\n";
8329             pr "  int r_len;\n";
8330             pr "  jclass cl;\n";
8331             pr "  jstring jstr;\n";
8332             pr "  char **r;\n"; "NULL", "NULL"
8333         | RStruct (_, typ) ->
8334             pr "  jobject jr;\n";
8335             pr "  jclass cl;\n";
8336             pr "  jfieldID fl;\n";
8337             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
8338         | RStructList (_, typ) ->
8339             pr "  jobjectArray jr;\n";
8340             pr "  jclass cl;\n";
8341             pr "  jfieldID fl;\n";
8342             pr "  jobject jfl;\n";
8343             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
8344         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
8345         | RBufferOut _ ->
8346             pr "  jstring jr;\n";
8347             pr "  char *r;\n";
8348             pr "  size_t size;\n";
8349             "NULL", "NULL" in
8350       List.iter (
8351         function
8352         | Device n
8353         | String n
8354         | OptString n
8355         | FileIn n
8356         | FileOut n ->
8357             pr "  const char *%s;\n" n
8358         | StringList n ->
8359             pr "  int %s_len;\n" n;
8360             pr "  const char **%s;\n" n
8361         | Bool n
8362         | Int n ->
8363             pr "  int %s;\n" n
8364       ) (snd style);
8365
8366       let needs_i =
8367         (match fst style with
8368          | RStringList _ | RStructList _ -> true
8369          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
8370          | RConstOptString _
8371          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
8372           List.exists (function StringList _ -> true | _ -> false) (snd style) in
8373       if needs_i then
8374         pr "  int i;\n";
8375
8376       pr "\n";
8377
8378       (* Get the parameters. *)
8379       List.iter (
8380         function
8381         | Device n
8382         | String n
8383         | FileIn n
8384         | FileOut n ->
8385             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
8386         | OptString n ->
8387             (* This is completely undocumented, but Java null becomes
8388              * a NULL parameter.
8389              *)
8390             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
8391         | StringList n ->
8392             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
8393             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
8394             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
8395             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8396               n;
8397             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
8398             pr "  }\n";
8399             pr "  %s[%s_len] = NULL;\n" n n;
8400         | Bool n
8401         | Int n ->
8402             pr "  %s = j%s;\n" n n
8403       ) (snd style);
8404
8405       (* Make the call. *)
8406       pr "  r = guestfs_%s " name;
8407       generate_c_call_args ~handle:"g" style;
8408       pr ";\n";
8409
8410       (* Release the parameters. *)
8411       List.iter (
8412         function
8413         | Device n
8414         | String n
8415         | FileIn n
8416         | FileOut n ->
8417             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8418         | OptString n ->
8419             pr "  if (j%s)\n" n;
8420             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8421         | StringList n ->
8422             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
8423             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8424               n;
8425             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
8426             pr "  }\n";
8427             pr "  free (%s);\n" n
8428         | Bool n
8429         | Int n -> ()
8430       ) (snd style);
8431
8432       (* Check for errors. *)
8433       pr "  if (r == %s) {\n" error_code;
8434       pr "    throw_exception (env, guestfs_last_error (g));\n";
8435       pr "    return %s;\n" no_ret;
8436       pr "  }\n";
8437
8438       (* Return value. *)
8439       (match fst style with
8440        | RErr -> ()
8441        | RInt _ -> pr "  return (jint) r;\n"
8442        | RBool _ -> pr "  return (jboolean) r;\n"
8443        | RInt64 _ -> pr "  return (jlong) r;\n"
8444        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
8445        | RConstOptString _ ->
8446            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
8447        | RString _ ->
8448            pr "  jr = (*env)->NewStringUTF (env, r);\n";
8449            pr "  free (r);\n";
8450            pr "  return jr;\n"
8451        | RStringList _ ->
8452            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
8453            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
8454            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
8455            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
8456            pr "  for (i = 0; i < r_len; ++i) {\n";
8457            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
8458            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
8459            pr "    free (r[i]);\n";
8460            pr "  }\n";
8461            pr "  free (r);\n";
8462            pr "  return jr;\n"
8463        | RStruct (_, typ) ->
8464            let jtyp = java_name_of_struct typ in
8465            let cols = cols_of_struct typ in
8466            generate_java_struct_return typ jtyp cols
8467        | RStructList (_, typ) ->
8468            let jtyp = java_name_of_struct typ in
8469            let cols = cols_of_struct typ in
8470            generate_java_struct_list_return typ jtyp cols
8471        | RHashtable _ ->
8472            (* XXX *)
8473            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
8474            pr "  return NULL;\n"
8475        | RBufferOut _ ->
8476            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
8477            pr "  free (r);\n";
8478            pr "  return jr;\n"
8479       );
8480
8481       pr "}\n";
8482       pr "\n"
8483   ) all_functions
8484
8485 and generate_java_struct_return typ jtyp cols =
8486   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8487   pr "  jr = (*env)->AllocObject (env, cl);\n";
8488   List.iter (
8489     function
8490     | name, FString ->
8491         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8492         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
8493     | name, FUUID ->
8494         pr "  {\n";
8495         pr "    char s[33];\n";
8496         pr "    memcpy (s, r->%s, 32);\n" name;
8497         pr "    s[32] = 0;\n";
8498         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8499         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8500         pr "  }\n";
8501     | name, FBuffer ->
8502         pr "  {\n";
8503         pr "    int len = r->%s_len;\n" name;
8504         pr "    char s[len+1];\n";
8505         pr "    memcpy (s, r->%s, len);\n" name;
8506         pr "    s[len] = 0;\n";
8507         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8508         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8509         pr "  }\n";
8510     | name, (FBytes|FUInt64|FInt64) ->
8511         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8512         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8513     | name, (FUInt32|FInt32) ->
8514         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8515         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8516     | name, FOptPercent ->
8517         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8518         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
8519     | name, FChar ->
8520         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8521         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8522   ) cols;
8523   pr "  free (r);\n";
8524   pr "  return jr;\n"
8525
8526 and generate_java_struct_list_return typ jtyp cols =
8527   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8528   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
8529   pr "  for (i = 0; i < r->len; ++i) {\n";
8530   pr "    jfl = (*env)->AllocObject (env, cl);\n";
8531   List.iter (
8532     function
8533     | name, FString ->
8534         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8535         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
8536     | name, FUUID ->
8537         pr "    {\n";
8538         pr "      char s[33];\n";
8539         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
8540         pr "      s[32] = 0;\n";
8541         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8542         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8543         pr "    }\n";
8544     | name, FBuffer ->
8545         pr "    {\n";
8546         pr "      int len = r->val[i].%s_len;\n" name;
8547         pr "      char s[len+1];\n";
8548         pr "      memcpy (s, r->val[i].%s, len);\n" name;
8549         pr "      s[len] = 0;\n";
8550         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8551         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8552         pr "    }\n";
8553     | name, (FBytes|FUInt64|FInt64) ->
8554         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8555         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8556     | name, (FUInt32|FInt32) ->
8557         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8558         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8559     | name, FOptPercent ->
8560         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8561         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
8562     | name, FChar ->
8563         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8564         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8565   ) cols;
8566   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
8567   pr "  }\n";
8568   pr "  guestfs_free_%s_list (r);\n" typ;
8569   pr "  return jr;\n"
8570
8571 and generate_java_makefile_inc () =
8572   generate_header HashStyle GPLv2;
8573
8574   pr "java_built_sources = \\\n";
8575   List.iter (
8576     fun (typ, jtyp) ->
8577         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
8578   ) java_structs;
8579   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
8580
8581 and generate_haskell_hs () =
8582   generate_header HaskellStyle LGPLv2;
8583
8584   (* XXX We only know how to generate partial FFI for Haskell
8585    * at the moment.  Please help out!
8586    *)
8587   let can_generate style =
8588     match style with
8589     | RErr, _
8590     | RInt _, _
8591     | RInt64 _, _ -> true
8592     | RBool _, _
8593     | RConstString _, _
8594     | RConstOptString _, _
8595     | RString _, _
8596     | RStringList _, _
8597     | RStruct _, _
8598     | RStructList _, _
8599     | RHashtable _, _
8600     | RBufferOut _, _ -> false in
8601
8602   pr "\
8603 {-# INCLUDE <guestfs.h> #-}
8604 {-# LANGUAGE ForeignFunctionInterface #-}
8605
8606 module Guestfs (
8607   create";
8608
8609   (* List out the names of the actions we want to export. *)
8610   List.iter (
8611     fun (name, style, _, _, _, _, _) ->
8612       if can_generate style then pr ",\n  %s" name
8613   ) all_functions;
8614
8615   pr "
8616   ) where
8617 import Foreign
8618 import Foreign.C
8619 import Foreign.C.Types
8620 import IO
8621 import Control.Exception
8622 import Data.Typeable
8623
8624 data GuestfsS = GuestfsS            -- represents the opaque C struct
8625 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
8626 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
8627
8628 -- XXX define properly later XXX
8629 data PV = PV
8630 data VG = VG
8631 data LV = LV
8632 data IntBool = IntBool
8633 data Stat = Stat
8634 data StatVFS = StatVFS
8635 data Hashtable = Hashtable
8636
8637 foreign import ccall unsafe \"guestfs_create\" c_create
8638   :: IO GuestfsP
8639 foreign import ccall unsafe \"&guestfs_close\" c_close
8640   :: FunPtr (GuestfsP -> IO ())
8641 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
8642   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
8643
8644 create :: IO GuestfsH
8645 create = do
8646   p <- c_create
8647   c_set_error_handler p nullPtr nullPtr
8648   h <- newForeignPtr c_close p
8649   return h
8650
8651 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
8652   :: GuestfsP -> IO CString
8653
8654 -- last_error :: GuestfsH -> IO (Maybe String)
8655 -- last_error h = do
8656 --   str <- withForeignPtr h (\\p -> c_last_error p)
8657 --   maybePeek peekCString str
8658
8659 last_error :: GuestfsH -> IO (String)
8660 last_error h = do
8661   str <- withForeignPtr h (\\p -> c_last_error p)
8662   if (str == nullPtr)
8663     then return \"no error\"
8664     else peekCString str
8665
8666 ";
8667
8668   (* Generate wrappers for each foreign function. *)
8669   List.iter (
8670     fun (name, style, _, _, _, _, _) ->
8671       if can_generate style then (
8672         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
8673         pr "  :: ";
8674         generate_haskell_prototype ~handle:"GuestfsP" style;
8675         pr "\n";
8676         pr "\n";
8677         pr "%s :: " name;
8678         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
8679         pr "\n";
8680         pr "%s %s = do\n" name
8681           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
8682         pr "  r <- ";
8683         (* Convert pointer arguments using with* functions. *)
8684         List.iter (
8685           function
8686           | FileIn n
8687           | FileOut n
8688           | Device n | String n -> pr "withCString %s $ \\%s -> " n n
8689           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
8690           | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
8691           | Bool _ | Int _ -> ()
8692         ) (snd style);
8693         (* Convert integer arguments. *)
8694         let args =
8695           List.map (
8696             function
8697             | Bool n -> sprintf "(fromBool %s)" n
8698             | Int n -> sprintf "(fromIntegral %s)" n
8699             | FileIn n | FileOut n
8700             | Device n | String n | OptString n | StringList n -> n
8701           ) (snd style) in
8702         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
8703           (String.concat " " ("p" :: args));
8704         (match fst style with
8705          | RErr | RInt _ | RInt64 _ | RBool _ ->
8706              pr "  if (r == -1)\n";
8707              pr "    then do\n";
8708              pr "      err <- last_error h\n";
8709              pr "      fail err\n";
8710          | RConstString _ | RConstOptString _ | RString _
8711          | RStringList _ | RStruct _
8712          | RStructList _ | RHashtable _ | RBufferOut _ ->
8713              pr "  if (r == nullPtr)\n";
8714              pr "    then do\n";
8715              pr "      err <- last_error h\n";
8716              pr "      fail err\n";
8717         );
8718         (match fst style with
8719          | RErr ->
8720              pr "    else return ()\n"
8721          | RInt _ ->
8722              pr "    else return (fromIntegral r)\n"
8723          | RInt64 _ ->
8724              pr "    else return (fromIntegral r)\n"
8725          | RBool _ ->
8726              pr "    else return (toBool r)\n"
8727          | RConstString _
8728          | RConstOptString _
8729          | RString _
8730          | RStringList _
8731          | RStruct _
8732          | RStructList _
8733          | RHashtable _
8734          | RBufferOut _ ->
8735              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
8736         );
8737         pr "\n";
8738       )
8739   ) all_functions
8740
8741 and generate_haskell_prototype ~handle ?(hs = false) style =
8742   pr "%s -> " handle;
8743   let string = if hs then "String" else "CString" in
8744   let int = if hs then "Int" else "CInt" in
8745   let bool = if hs then "Bool" else "CInt" in
8746   let int64 = if hs then "Integer" else "Int64" in
8747   List.iter (
8748     fun arg ->
8749       (match arg with
8750        | Device _ | String _ -> pr "%s" string
8751        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
8752        | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
8753        | Bool _ -> pr "%s" bool
8754        | Int _ -> pr "%s" int
8755        | FileIn _ -> pr "%s" string
8756        | FileOut _ -> pr "%s" string
8757       );
8758       pr " -> ";
8759   ) (snd style);
8760   pr "IO (";
8761   (match fst style with
8762    | RErr -> if not hs then pr "CInt"
8763    | RInt _ -> pr "%s" int
8764    | RInt64 _ -> pr "%s" int64
8765    | RBool _ -> pr "%s" bool
8766    | RConstString _ -> pr "%s" string
8767    | RConstOptString _ -> pr "Maybe %s" string
8768    | RString _ -> pr "%s" string
8769    | RStringList _ -> pr "[%s]" string
8770    | RStruct (_, typ) ->
8771        let name = java_name_of_struct typ in
8772        pr "%s" name
8773    | RStructList (_, typ) ->
8774        let name = java_name_of_struct typ in
8775        pr "[%s]" name
8776    | RHashtable _ -> pr "Hashtable"
8777    | RBufferOut _ -> pr "%s" string
8778   );
8779   pr ")"
8780
8781 and generate_bindtests () =
8782   generate_header CStyle LGPLv2;
8783
8784   pr "\
8785 #include <stdio.h>
8786 #include <stdlib.h>
8787 #include <inttypes.h>
8788 #include <string.h>
8789
8790 #include \"guestfs.h\"
8791 #include \"guestfs_protocol.h\"
8792
8793 #define error guestfs_error
8794 #define safe_calloc guestfs_safe_calloc
8795 #define safe_malloc guestfs_safe_malloc
8796
8797 static void
8798 print_strings (char * const* const argv)
8799 {
8800   int argc;
8801
8802   printf (\"[\");
8803   for (argc = 0; argv[argc] != NULL; ++argc) {
8804     if (argc > 0) printf (\", \");
8805     printf (\"\\\"%%s\\\"\", argv[argc]);
8806   }
8807   printf (\"]\\n\");
8808 }
8809
8810 /* The test0 function prints its parameters to stdout. */
8811 ";
8812
8813   let test0, tests =
8814     match test_functions with
8815     | [] -> assert false
8816     | test0 :: tests -> test0, tests in
8817
8818   let () =
8819     let (name, style, _, _, _, _, _) = test0 in
8820     generate_prototype ~extern:false ~semicolon:false ~newline:true
8821       ~handle:"g" ~prefix:"guestfs_" name style;
8822     pr "{\n";
8823     List.iter (
8824       function
8825       | Device n
8826       | String n
8827       | FileIn n
8828       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
8829       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
8830       | StringList n -> pr "  print_strings (%s);\n" n
8831       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
8832       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
8833     ) (snd style);
8834     pr "  /* Java changes stdout line buffering so we need this: */\n";
8835     pr "  fflush (stdout);\n";
8836     pr "  return 0;\n";
8837     pr "}\n";
8838     pr "\n" in
8839
8840   List.iter (
8841     fun (name, style, _, _, _, _, _) ->
8842       if String.sub name (String.length name - 3) 3 <> "err" then (
8843         pr "/* Test normal return. */\n";
8844         generate_prototype ~extern:false ~semicolon:false ~newline:true
8845           ~handle:"g" ~prefix:"guestfs_" name style;
8846         pr "{\n";
8847         (match fst style with
8848          | RErr ->
8849              pr "  return 0;\n"
8850          | RInt _ ->
8851              pr "  int r;\n";
8852              pr "  sscanf (val, \"%%d\", &r);\n";
8853              pr "  return r;\n"
8854          | RInt64 _ ->
8855              pr "  int64_t r;\n";
8856              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
8857              pr "  return r;\n"
8858          | RBool _ ->
8859              pr "  return strcmp (val, \"true\") == 0;\n"
8860          | RConstString _
8861          | RConstOptString _ ->
8862              (* Can't return the input string here.  Return a static
8863               * string so we ensure we get a segfault if the caller
8864               * tries to free it.
8865               *)
8866              pr "  return \"static string\";\n"
8867          | RString _ ->
8868              pr "  return strdup (val);\n"
8869          | RStringList _ ->
8870              pr "  char **strs;\n";
8871              pr "  int n, i;\n";
8872              pr "  sscanf (val, \"%%d\", &n);\n";
8873              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
8874              pr "  for (i = 0; i < n; ++i) {\n";
8875              pr "    strs[i] = safe_malloc (g, 16);\n";
8876              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
8877              pr "  }\n";
8878              pr "  strs[n] = NULL;\n";
8879              pr "  return strs;\n"
8880          | RStruct (_, typ) ->
8881              pr "  struct guestfs_%s *r;\n" typ;
8882              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
8883              pr "  return r;\n"
8884          | RStructList (_, typ) ->
8885              pr "  struct guestfs_%s_list *r;\n" typ;
8886              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
8887              pr "  sscanf (val, \"%%d\", &r->len);\n";
8888              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8889              pr "  return r;\n"
8890          | RHashtable _ ->
8891              pr "  char **strs;\n";
8892              pr "  int n, i;\n";
8893              pr "  sscanf (val, \"%%d\", &n);\n";
8894              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
8895              pr "  for (i = 0; i < n; ++i) {\n";
8896              pr "    strs[i*2] = safe_malloc (g, 16);\n";
8897              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
8898              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
8899              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
8900              pr "  }\n";
8901              pr "  strs[n*2] = NULL;\n";
8902              pr "  return strs;\n"
8903          | RBufferOut _ ->
8904              pr "  return strdup (val);\n"
8905         );
8906         pr "}\n";
8907         pr "\n"
8908       ) else (
8909         pr "/* Test error return. */\n";
8910         generate_prototype ~extern:false ~semicolon:false ~newline:true
8911           ~handle:"g" ~prefix:"guestfs_" name style;
8912         pr "{\n";
8913         pr "  error (g, \"error\");\n";
8914         (match fst style with
8915          | RErr | RInt _ | RInt64 _ | RBool _ ->
8916              pr "  return -1;\n"
8917          | RConstString _ | RConstOptString _
8918          | RString _ | RStringList _ | RStruct _
8919          | RStructList _
8920          | RHashtable _
8921          | RBufferOut _ ->
8922              pr "  return NULL;\n"
8923         );
8924         pr "}\n";
8925         pr "\n"
8926       )
8927   ) tests
8928
8929 and generate_ocaml_bindtests () =
8930   generate_header OCamlStyle GPLv2;
8931
8932   pr "\
8933 let () =
8934   let g = Guestfs.create () in
8935 ";
8936
8937   let mkargs args =
8938     String.concat " " (
8939       List.map (
8940         function
8941         | CallString s -> "\"" ^ s ^ "\""
8942         | CallOptString None -> "None"
8943         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
8944         | CallStringList xs ->
8945             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
8946         | CallInt i when i >= 0 -> string_of_int i
8947         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
8948         | CallBool b -> string_of_bool b
8949       ) args
8950     )
8951   in
8952
8953   generate_lang_bindtests (
8954     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
8955   );
8956
8957   pr "print_endline \"EOF\"\n"
8958
8959 and generate_perl_bindtests () =
8960   pr "#!/usr/bin/perl -w\n";
8961   generate_header HashStyle GPLv2;
8962
8963   pr "\
8964 use strict;
8965
8966 use Sys::Guestfs;
8967
8968 my $g = Sys::Guestfs->new ();
8969 ";
8970
8971   let mkargs args =
8972     String.concat ", " (
8973       List.map (
8974         function
8975         | CallString s -> "\"" ^ s ^ "\""
8976         | CallOptString None -> "undef"
8977         | CallOptString (Some s) -> sprintf "\"%s\"" s
8978         | CallStringList xs ->
8979             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8980         | CallInt i -> string_of_int i
8981         | CallBool b -> if b then "1" else "0"
8982       ) args
8983     )
8984   in
8985
8986   generate_lang_bindtests (
8987     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
8988   );
8989
8990   pr "print \"EOF\\n\"\n"
8991
8992 and generate_python_bindtests () =
8993   generate_header HashStyle GPLv2;
8994
8995   pr "\
8996 import guestfs
8997
8998 g = guestfs.GuestFS ()
8999 ";
9000
9001   let mkargs args =
9002     String.concat ", " (
9003       List.map (
9004         function
9005         | CallString s -> "\"" ^ s ^ "\""
9006         | CallOptString None -> "None"
9007         | CallOptString (Some s) -> sprintf "\"%s\"" s
9008         | CallStringList xs ->
9009             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9010         | CallInt i -> string_of_int i
9011         | CallBool b -> if b then "1" else "0"
9012       ) args
9013     )
9014   in
9015
9016   generate_lang_bindtests (
9017     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
9018   );
9019
9020   pr "print \"EOF\"\n"
9021
9022 and generate_ruby_bindtests () =
9023   generate_header HashStyle GPLv2;
9024
9025   pr "\
9026 require 'guestfs'
9027
9028 g = Guestfs::create()
9029 ";
9030
9031   let mkargs args =
9032     String.concat ", " (
9033       List.map (
9034         function
9035         | CallString s -> "\"" ^ s ^ "\""
9036         | CallOptString None -> "nil"
9037         | CallOptString (Some s) -> sprintf "\"%s\"" s
9038         | CallStringList xs ->
9039             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9040         | CallInt i -> string_of_int i
9041         | CallBool b -> string_of_bool b
9042       ) args
9043     )
9044   in
9045
9046   generate_lang_bindtests (
9047     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
9048   );
9049
9050   pr "print \"EOF\\n\"\n"
9051
9052 and generate_java_bindtests () =
9053   generate_header CStyle GPLv2;
9054
9055   pr "\
9056 import com.redhat.et.libguestfs.*;
9057
9058 public class Bindtests {
9059     public static void main (String[] argv)
9060     {
9061         try {
9062             GuestFS g = new GuestFS ();
9063 ";
9064
9065   let mkargs args =
9066     String.concat ", " (
9067       List.map (
9068         function
9069         | CallString s -> "\"" ^ s ^ "\""
9070         | CallOptString None -> "null"
9071         | CallOptString (Some s) -> sprintf "\"%s\"" s
9072         | CallStringList xs ->
9073             "new String[]{" ^
9074               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
9075         | CallInt i -> string_of_int i
9076         | CallBool b -> string_of_bool b
9077       ) args
9078     )
9079   in
9080
9081   generate_lang_bindtests (
9082     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
9083   );
9084
9085   pr "
9086             System.out.println (\"EOF\");
9087         }
9088         catch (Exception exn) {
9089             System.err.println (exn);
9090             System.exit (1);
9091         }
9092     }
9093 }
9094 "
9095
9096 and generate_haskell_bindtests () =
9097   generate_header HaskellStyle GPLv2;
9098
9099   pr "\
9100 module Bindtests where
9101 import qualified Guestfs
9102
9103 main = do
9104   g <- Guestfs.create
9105 ";
9106
9107   let mkargs args =
9108     String.concat " " (
9109       List.map (
9110         function
9111         | CallString s -> "\"" ^ s ^ "\""
9112         | CallOptString None -> "Nothing"
9113         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
9114         | CallStringList xs ->
9115             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9116         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
9117         | CallInt i -> string_of_int i
9118         | CallBool true -> "True"
9119         | CallBool false -> "False"
9120       ) args
9121     )
9122   in
9123
9124   generate_lang_bindtests (
9125     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
9126   );
9127
9128   pr "  putStrLn \"EOF\"\n"
9129
9130 (* Language-independent bindings tests - we do it this way to
9131  * ensure there is parity in testing bindings across all languages.
9132  *)
9133 and generate_lang_bindtests call =
9134   call "test0" [CallString "abc"; CallOptString (Some "def");
9135                 CallStringList []; CallBool false;
9136                 CallInt 0; CallString "123"; CallString "456"];
9137   call "test0" [CallString "abc"; CallOptString None;
9138                 CallStringList []; CallBool false;
9139                 CallInt 0; CallString "123"; CallString "456"];
9140   call "test0" [CallString ""; CallOptString (Some "def");
9141                 CallStringList []; CallBool false;
9142                 CallInt 0; CallString "123"; CallString "456"];
9143   call "test0" [CallString ""; CallOptString (Some "");
9144                 CallStringList []; CallBool false;
9145                 CallInt 0; CallString "123"; CallString "456"];
9146   call "test0" [CallString "abc"; CallOptString (Some "def");
9147                 CallStringList ["1"]; CallBool false;
9148                 CallInt 0; CallString "123"; CallString "456"];
9149   call "test0" [CallString "abc"; CallOptString (Some "def");
9150                 CallStringList ["1"; "2"]; CallBool false;
9151                 CallInt 0; CallString "123"; CallString "456"];
9152   call "test0" [CallString "abc"; CallOptString (Some "def");
9153                 CallStringList ["1"]; CallBool true;
9154                 CallInt 0; CallString "123"; CallString "456"];
9155   call "test0" [CallString "abc"; CallOptString (Some "def");
9156                 CallStringList ["1"]; CallBool false;
9157                 CallInt (-1); CallString "123"; CallString "456"];
9158   call "test0" [CallString "abc"; CallOptString (Some "def");
9159                 CallStringList ["1"]; CallBool false;
9160                 CallInt (-2); CallString "123"; CallString "456"];
9161   call "test0" [CallString "abc"; CallOptString (Some "def");
9162                 CallStringList ["1"]; CallBool false;
9163                 CallInt 1; CallString "123"; CallString "456"];
9164   call "test0" [CallString "abc"; CallOptString (Some "def");
9165                 CallStringList ["1"]; CallBool false;
9166                 CallInt 2; CallString "123"; CallString "456"];
9167   call "test0" [CallString "abc"; CallOptString (Some "def");
9168                 CallStringList ["1"]; CallBool false;
9169                 CallInt 4095; CallString "123"; CallString "456"];
9170   call "test0" [CallString "abc"; CallOptString (Some "def");
9171                 CallStringList ["1"]; CallBool false;
9172                 CallInt 0; CallString ""; CallString ""]
9173
9174 (* XXX Add here tests of the return and error functions. *)
9175
9176 (* This is used to generate the src/MAX_PROC_NR file which
9177  * contains the maximum procedure number, a surrogate for the
9178  * ABI version number.  See src/Makefile.am for the details.
9179  *)
9180 and generate_max_proc_nr () =
9181   let proc_nrs = List.map (
9182     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
9183   ) daemon_functions in
9184
9185   let max_proc_nr = List.fold_left max 0 proc_nrs in
9186
9187   pr "%d\n" max_proc_nr
9188
9189 let output_to filename =
9190   let filename_new = filename ^ ".new" in
9191   chan := open_out filename_new;
9192   let close () =
9193     close_out !chan;
9194     chan := stdout;
9195
9196     (* Is the new file different from the current file? *)
9197     if Sys.file_exists filename && files_equal filename filename_new then
9198       Unix.unlink filename_new          (* same, so skip it *)
9199     else (
9200       (* different, overwrite old one *)
9201       (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
9202       Unix.rename filename_new filename;
9203       Unix.chmod filename 0o444;
9204       printf "written %s\n%!" filename;
9205     )
9206   in
9207   close
9208
9209 (* Main program. *)
9210 let () =
9211   check_functions ();
9212
9213   if not (Sys.file_exists "HACKING") then (
9214     eprintf "\
9215 You are probably running this from the wrong directory.
9216 Run it from the top source directory using the command
9217   src/generator.ml
9218 ";
9219     exit 1
9220   );
9221
9222   let close = output_to "src/guestfs_protocol.x" in
9223   generate_xdr ();
9224   close ();
9225
9226   let close = output_to "src/guestfs-structs.h" in
9227   generate_structs_h ();
9228   close ();
9229
9230   let close = output_to "src/guestfs-actions.h" in
9231   generate_actions_h ();
9232   close ();
9233
9234   let close = output_to "src/guestfs-actions.c" in
9235   generate_client_actions ();
9236   close ();
9237
9238   let close = output_to "daemon/actions.h" in
9239   generate_daemon_actions_h ();
9240   close ();
9241
9242   let close = output_to "daemon/stubs.c" in
9243   generate_daemon_actions ();
9244   close ();
9245
9246   let close = output_to "daemon/names.c" in
9247   generate_daemon_names ();
9248   close ();
9249
9250   let close = output_to "capitests/tests.c" in
9251   generate_tests ();
9252   close ();
9253
9254   let close = output_to "src/guestfs-bindtests.c" in
9255   generate_bindtests ();
9256   close ();
9257
9258   let close = output_to "fish/cmds.c" in
9259   generate_fish_cmds ();
9260   close ();
9261
9262   let close = output_to "fish/completion.c" in
9263   generate_fish_completion ();
9264   close ();
9265
9266   let close = output_to "guestfs-structs.pod" in
9267   generate_structs_pod ();
9268   close ();
9269
9270   let close = output_to "guestfs-actions.pod" in
9271   generate_actions_pod ();
9272   close ();
9273
9274   let close = output_to "guestfish-actions.pod" in
9275   generate_fish_actions_pod ();
9276   close ();
9277
9278   let close = output_to "ocaml/guestfs.mli" in
9279   generate_ocaml_mli ();
9280   close ();
9281
9282   let close = output_to "ocaml/guestfs.ml" in
9283   generate_ocaml_ml ();
9284   close ();
9285
9286   let close = output_to "ocaml/guestfs_c_actions.c" in
9287   generate_ocaml_c ();
9288   close ();
9289
9290   let close = output_to "ocaml/bindtests.ml" in
9291   generate_ocaml_bindtests ();
9292   close ();
9293
9294   let close = output_to "perl/Guestfs.xs" in
9295   generate_perl_xs ();
9296   close ();
9297
9298   let close = output_to "perl/lib/Sys/Guestfs.pm" in
9299   generate_perl_pm ();
9300   close ();
9301
9302   let close = output_to "perl/bindtests.pl" in
9303   generate_perl_bindtests ();
9304   close ();
9305
9306   let close = output_to "python/guestfs-py.c" in
9307   generate_python_c ();
9308   close ();
9309
9310   let close = output_to "python/guestfs.py" in
9311   generate_python_py ();
9312   close ();
9313
9314   let close = output_to "python/bindtests.py" in
9315   generate_python_bindtests ();
9316   close ();
9317
9318   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
9319   generate_ruby_c ();
9320   close ();
9321
9322   let close = output_to "ruby/bindtests.rb" in
9323   generate_ruby_bindtests ();
9324   close ();
9325
9326   let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
9327   generate_java_java ();
9328   close ();
9329
9330   List.iter (
9331     fun (typ, jtyp) ->
9332       let cols = cols_of_struct typ in
9333       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
9334       let close = output_to filename in
9335       generate_java_struct jtyp cols;
9336       close ();
9337   ) java_structs;
9338
9339   let close = output_to "java/Makefile.inc" in
9340   generate_java_makefile_inc ();
9341   close ();
9342
9343   let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
9344   generate_java_c ();
9345   close ();
9346
9347   let close = output_to "java/Bindtests.java" in
9348   generate_java_bindtests ();
9349   close ();
9350
9351   let close = output_to "haskell/Guestfs.hs" in
9352   generate_haskell_hs ();
9353   close ();
9354
9355   let close = output_to "haskell/Bindtests.hs" in
9356   generate_haskell_bindtests ();
9357   close ();
9358
9359   let close = output_to "src/MAX_PROC_NR" in
9360   generate_max_proc_nr ();
9361   close ();
9362
9363   (* Always generate this file last, and unconditionally.  It's used
9364    * by the Makefile to know when we must re-run the generator.
9365    *)
9366   let chan = open_out "src/stamp-generator" in
9367   fprintf chan "1\n";
9368   close_out chan