generator.ml: define new String-like type: "Device"
[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              (* FIXME *)
4524              | Device n | String n ->
4525                  pr "  args.%s = (char *) %s;\n" n n
4526              | OptString n ->
4527                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
4528              | StringList n ->
4529                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
4530                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
4531              | Bool n ->
4532                  pr "  args.%s = %s;\n" n n
4533              | Int n ->
4534                  pr "  args.%s = %s;\n" n n
4535              | FileIn _ | FileOut _ -> ()
4536            ) args;
4537            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
4538              (String.uppercase shortname);
4539            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
4540              name;
4541       );
4542       pr "  if (serial == -1) {\n";
4543       pr "    guestfs_end_busy (g);\n";
4544       pr "    return %s;\n" error_code;
4545       pr "  }\n";
4546       pr "\n";
4547
4548       (* Send any additional files (FileIn) requested. *)
4549       let need_read_reply_label = ref false in
4550       List.iter (
4551         function
4552         | FileIn n ->
4553             pr "  {\n";
4554             pr "    int r;\n";
4555             pr "\n";
4556             pr "    r = guestfs__send_file_sync (g, %s);\n" n;
4557             pr "    if (r == -1) {\n";
4558             pr "      guestfs_end_busy (g);\n";
4559             pr "      return %s;\n" error_code;
4560             pr "    }\n";
4561             pr "    if (r == -2) /* daemon cancelled */\n";
4562             pr "      goto read_reply;\n";
4563             need_read_reply_label := true;
4564             pr "  }\n";
4565             pr "\n";
4566         | _ -> ()
4567       ) (snd style);
4568
4569       (* Wait for the reply from the remote end. *)
4570       if !need_read_reply_label then pr " read_reply:\n";
4571       pr "  guestfs__switch_to_receiving (g);\n";
4572       pr "  ctx.cb_sequence = 0;\n";
4573       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
4574       pr "  (void) ml->main_loop_run (ml, g);\n";
4575       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
4576       pr "  if (ctx.cb_sequence != 1) {\n";
4577       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
4578       pr "    guestfs_end_busy (g);\n";
4579       pr "    return %s;\n" error_code;
4580       pr "  }\n";
4581       pr "\n";
4582
4583       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
4584         (String.uppercase shortname);
4585       pr "    guestfs_end_busy (g);\n";
4586       pr "    return %s;\n" error_code;
4587       pr "  }\n";
4588       pr "\n";
4589
4590       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
4591       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
4592       pr "    free (ctx.err.error_message);\n";
4593       pr "    guestfs_end_busy (g);\n";
4594       pr "    return %s;\n" error_code;
4595       pr "  }\n";
4596       pr "\n";
4597
4598       (* Expecting to receive further files (FileOut)? *)
4599       List.iter (
4600         function
4601         | FileOut n ->
4602             pr "  if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
4603             pr "    guestfs_end_busy (g);\n";
4604             pr "    return %s;\n" error_code;
4605             pr "  }\n";
4606             pr "\n";
4607         | _ -> ()
4608       ) (snd style);
4609
4610       pr "  guestfs_end_busy (g);\n";
4611
4612       (match fst style with
4613        | RErr -> pr "  return 0;\n"
4614        | RInt n | RInt64 n | RBool n ->
4615            pr "  return ctx.ret.%s;\n" n
4616        | RConstString _ | RConstOptString _ ->
4617            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4618        | RString n ->
4619            pr "  return ctx.ret.%s; /* caller will free */\n" n
4620        | RStringList n | RHashtable n ->
4621            pr "  /* caller will free this, but we need to add a NULL entry */\n";
4622            pr "  ctx.ret.%s.%s_val =\n" n n;
4623            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
4624            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
4625              n n;
4626            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
4627            pr "  return ctx.ret.%s.%s_val;\n" n n
4628        | RStruct (n, _) ->
4629            pr "  /* caller will free this */\n";
4630            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4631        | RStructList (n, _) ->
4632            pr "  /* caller will free this */\n";
4633            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4634        | RBufferOut n ->
4635            pr "  *size_r = ctx.ret.%s.%s_len;\n" n n;
4636            pr "  return ctx.ret.%s.%s_val; /* caller will free */\n" n n
4637       );
4638
4639       pr "}\n\n"
4640   ) daemon_functions;
4641
4642   (* Functions to free structures. *)
4643   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
4644   pr " * structure format is identical to the XDR format.  See note in\n";
4645   pr " * generator.ml.\n";
4646   pr " */\n";
4647   pr "\n";
4648
4649   List.iter (
4650     fun (typ, _) ->
4651       pr "void\n";
4652       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
4653       pr "{\n";
4654       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
4655       pr "  free (x);\n";
4656       pr "}\n";
4657       pr "\n";
4658
4659       pr "void\n";
4660       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
4661       pr "{\n";
4662       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
4663       pr "  free (x);\n";
4664       pr "}\n";
4665       pr "\n";
4666
4667   ) structs;
4668
4669 (* Generate daemon/actions.h. *)
4670 and generate_daemon_actions_h () =
4671   generate_header CStyle GPLv2;
4672
4673   pr "#include \"../src/guestfs_protocol.h\"\n";
4674   pr "\n";
4675
4676   List.iter (
4677     fun (name, style, _, _, _, _, _) ->
4678       generate_prototype
4679         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
4680         name style;
4681   ) daemon_functions
4682
4683 (* Generate the server-side stubs. *)
4684 and generate_daemon_actions () =
4685   generate_header CStyle GPLv2;
4686
4687   pr "#include <config.h>\n";
4688   pr "\n";
4689   pr "#include <stdio.h>\n";
4690   pr "#include <stdlib.h>\n";
4691   pr "#include <string.h>\n";
4692   pr "#include <inttypes.h>\n";
4693   pr "#include <ctype.h>\n";
4694   pr "#include <rpc/types.h>\n";
4695   pr "#include <rpc/xdr.h>\n";
4696   pr "\n";
4697   pr "#include \"daemon.h\"\n";
4698   pr "#include \"../src/guestfs_protocol.h\"\n";
4699   pr "#include \"actions.h\"\n";
4700   pr "\n";
4701
4702   List.iter (
4703     fun (name, style, _, _, _, _, _) ->
4704       (* Generate server-side stubs. *)
4705       pr "static void %s_stub (XDR *xdr_in)\n" name;
4706       pr "{\n";
4707       let error_code =
4708         match fst style with
4709         | RErr | RInt _ -> pr "  int r;\n"; "-1"
4710         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4711         | RBool _ -> pr "  int r;\n"; "-1"
4712         | RConstString _ | RConstOptString _ ->
4713             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4714         | RString _ -> pr "  char *r;\n"; "NULL"
4715         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
4716         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
4717         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
4718         | RBufferOut _ ->
4719             pr "  size_t size;\n";
4720             pr "  char *r;\n";
4721             "NULL" in
4722
4723       (match snd style with
4724        | [] -> ()
4725        | args ->
4726            pr "  struct guestfs_%s_args args;\n" name;
4727            List.iter (
4728              function
4729                (* Note we allow the string to be writable, in order to
4730                 * allow device name translation.  This is safe because
4731                 * we can modify the string (passed from RPC).
4732                 *)
4733                (* FIXME *)
4734              | Device n | String n
4735              | OptString n -> pr "  char *%s;\n" n
4736              | StringList n -> pr "  char **%s;\n" n
4737              | Bool n -> pr "  int %s;\n" n
4738              | Int n -> pr "  int %s;\n" n
4739              | FileIn _ | FileOut _ -> ()
4740            ) args
4741       );
4742       pr "\n";
4743
4744       (match snd style with
4745        | [] -> ()
4746        | args ->
4747            pr "  memset (&args, 0, sizeof args);\n";
4748            pr "\n";
4749            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4750            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4751            pr "    return;\n";
4752            pr "  }\n";
4753            List.iter (
4754              function
4755              | Device n | String n -> pr "  %s = args.%s;\n" n n
4756              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
4757              | StringList n ->
4758                  pr "  %s = realloc (args.%s.%s_val,\n" n n n;
4759                  pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4760                  pr "  if (%s == NULL) {\n" n;
4761                  pr "    reply_with_perror (\"realloc\");\n";
4762                  pr "    goto done;\n";
4763                  pr "  }\n";
4764                  pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
4765                  pr "  args.%s.%s_val = %s;\n" n n n;
4766              | Bool n -> pr "  %s = args.%s;\n" n n
4767              | Int n -> pr "  %s = args.%s;\n" n n
4768              | FileIn _ | FileOut _ -> ()
4769            ) args;
4770            pr "\n"
4771       );
4772
4773       (* Don't want to call the impl with any FileIn or FileOut
4774        * parameters, since these go "outside" the RPC protocol.
4775        *)
4776       let args' =
4777         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
4778           (snd style) in
4779       pr "  r = do_%s " name;
4780       generate_c_call_args (fst style, args');
4781       pr ";\n";
4782
4783       pr "  if (r == %s)\n" error_code;
4784       pr "    /* do_%s has already called reply_with_error */\n" name;
4785       pr "    goto done;\n";
4786       pr "\n";
4787
4788       (* If there are any FileOut parameters, then the impl must
4789        * send its own reply.
4790        *)
4791       let no_reply =
4792         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
4793       if no_reply then
4794         pr "  /* do_%s has already sent a reply */\n" name
4795       else (
4796         match fst style with
4797         | RErr -> pr "  reply (NULL, NULL);\n"
4798         | RInt n | RInt64 n | RBool n ->
4799             pr "  struct guestfs_%s_ret ret;\n" name;
4800             pr "  ret.%s = r;\n" n;
4801             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4802               name
4803         | RConstString _ | RConstOptString _ ->
4804             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4805         | RString n ->
4806             pr "  struct guestfs_%s_ret ret;\n" name;
4807             pr "  ret.%s = r;\n" n;
4808             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4809               name;
4810             pr "  free (r);\n"
4811         | RStringList n | RHashtable n ->
4812             pr "  struct guestfs_%s_ret ret;\n" name;
4813             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
4814             pr "  ret.%s.%s_val = r;\n" n n;
4815             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4816               name;
4817             pr "  free_strings (r);\n"
4818         | RStruct (n, _) ->
4819             pr "  struct guestfs_%s_ret ret;\n" name;
4820             pr "  ret.%s = *r;\n" n;
4821             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4822               name;
4823             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4824               name
4825         | RStructList (n, _) ->
4826             pr "  struct guestfs_%s_ret ret;\n" name;
4827             pr "  ret.%s = *r;\n" n;
4828             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4829               name;
4830             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4831               name
4832         | RBufferOut n ->
4833             pr "  struct guestfs_%s_ret ret;\n" name;
4834             pr "  ret.%s.%s_val = r;\n" n n;
4835             pr "  ret.%s.%s_len = size;\n" n n;
4836             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4837               name;
4838             pr "  free (r);\n"
4839       );
4840
4841       (* Free the args. *)
4842       (match snd style with
4843        | [] ->
4844            pr "done: ;\n";
4845        | _ ->
4846            pr "done:\n";
4847            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4848              name
4849       );
4850
4851       pr "}\n\n";
4852   ) daemon_functions;
4853
4854   (* Dispatch function. *)
4855   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4856   pr "{\n";
4857   pr "  switch (proc_nr) {\n";
4858
4859   List.iter (
4860     fun (name, style, _, _, _, _, _) ->
4861       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
4862       pr "      %s_stub (xdr_in);\n" name;
4863       pr "      break;\n"
4864   ) daemon_functions;
4865
4866   pr "    default:\n";
4867   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";
4868   pr "  }\n";
4869   pr "}\n";
4870   pr "\n";
4871
4872   (* LVM columns and tokenization functions. *)
4873   (* XXX This generates crap code.  We should rethink how we
4874    * do this parsing.
4875    *)
4876   List.iter (
4877     function
4878     | typ, cols ->
4879         pr "static const char *lvm_%s_cols = \"%s\";\n"
4880           typ (String.concat "," (List.map fst cols));
4881         pr "\n";
4882
4883         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
4884         pr "{\n";
4885         pr "  char *tok, *p, *next;\n";
4886         pr "  int i, j;\n";
4887         pr "\n";
4888         (*
4889           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4890           pr "\n";
4891         *)
4892         pr "  if (!str) {\n";
4893         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4894         pr "    return -1;\n";
4895         pr "  }\n";
4896         pr "  if (!*str || isspace (*str)) {\n";
4897         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4898         pr "    return -1;\n";
4899         pr "  }\n";
4900         pr "  tok = str;\n";
4901         List.iter (
4902           fun (name, coltype) ->
4903             pr "  if (!tok) {\n";
4904             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4905             pr "    return -1;\n";
4906             pr "  }\n";
4907             pr "  p = strchrnul (tok, ',');\n";
4908             pr "  if (*p) next = p+1; else next = NULL;\n";
4909             pr "  *p = '\\0';\n";
4910             (match coltype with
4911              | FString ->
4912                  pr "  r->%s = strdup (tok);\n" name;
4913                  pr "  if (r->%s == NULL) {\n" name;
4914                  pr "    perror (\"strdup\");\n";
4915                  pr "    return -1;\n";
4916                  pr "  }\n"
4917              | FUUID ->
4918                  pr "  for (i = j = 0; i < 32; ++j) {\n";
4919                  pr "    if (tok[j] == '\\0') {\n";
4920                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4921                  pr "      return -1;\n";
4922                  pr "    } else if (tok[j] != '-')\n";
4923                  pr "      r->%s[i++] = tok[j];\n" name;
4924                  pr "  }\n";
4925              | FBytes ->
4926                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4927                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4928                  pr "    return -1;\n";
4929                  pr "  }\n";
4930              | FInt64 ->
4931                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4932                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4933                  pr "    return -1;\n";
4934                  pr "  }\n";
4935              | FOptPercent ->
4936                  pr "  if (tok[0] == '\\0')\n";
4937                  pr "    r->%s = -1;\n" name;
4938                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4939                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4940                  pr "    return -1;\n";
4941                  pr "  }\n";
4942              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
4943                  assert false (* can never be an LVM column *)
4944             );
4945             pr "  tok = next;\n";
4946         ) cols;
4947
4948         pr "  if (tok != NULL) {\n";
4949         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4950         pr "    return -1;\n";
4951         pr "  }\n";
4952         pr "  return 0;\n";
4953         pr "}\n";
4954         pr "\n";
4955
4956         pr "guestfs_int_lvm_%s_list *\n" typ;
4957         pr "parse_command_line_%ss (void)\n" typ;
4958         pr "{\n";
4959         pr "  char *out, *err;\n";
4960         pr "  char *p, *pend;\n";
4961         pr "  int r, i;\n";
4962         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
4963         pr "  void *newp;\n";
4964         pr "\n";
4965         pr "  ret = malloc (sizeof *ret);\n";
4966         pr "  if (!ret) {\n";
4967         pr "    reply_with_perror (\"malloc\");\n";
4968         pr "    return NULL;\n";
4969         pr "  }\n";
4970         pr "\n";
4971         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
4972         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
4973         pr "\n";
4974         pr "  r = command (&out, &err,\n";
4975         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
4976         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4977         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4978         pr "  if (r == -1) {\n";
4979         pr "    reply_with_error (\"%%s\", err);\n";
4980         pr "    free (out);\n";
4981         pr "    free (err);\n";
4982         pr "    free (ret);\n";
4983         pr "    return NULL;\n";
4984         pr "  }\n";
4985         pr "\n";
4986         pr "  free (err);\n";
4987         pr "\n";
4988         pr "  /* Tokenize each line of the output. */\n";
4989         pr "  p = out;\n";
4990         pr "  i = 0;\n";
4991         pr "  while (p) {\n";
4992         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
4993         pr "    if (pend) {\n";
4994         pr "      *pend = '\\0';\n";
4995         pr "      pend++;\n";
4996         pr "    }\n";
4997         pr "\n";
4998         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
4999         pr "      p++;\n";
5000         pr "\n";
5001         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
5002         pr "      p = pend;\n";
5003         pr "      continue;\n";
5004         pr "    }\n";
5005         pr "\n";
5006         pr "    /* Allocate some space to store this next entry. */\n";
5007         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
5008         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
5009         pr "    if (newp == NULL) {\n";
5010         pr "      reply_with_perror (\"realloc\");\n";
5011         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5012         pr "      free (ret);\n";
5013         pr "      free (out);\n";
5014         pr "      return NULL;\n";
5015         pr "    }\n";
5016         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
5017         pr "\n";
5018         pr "    /* Tokenize the next entry. */\n";
5019         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
5020         pr "    if (r == -1) {\n";
5021         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
5022         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5023         pr "      free (ret);\n";
5024         pr "      free (out);\n";
5025         pr "      return NULL;\n";
5026         pr "    }\n";
5027         pr "\n";
5028         pr "    ++i;\n";
5029         pr "    p = pend;\n";
5030         pr "  }\n";
5031         pr "\n";
5032         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
5033         pr "\n";
5034         pr "  free (out);\n";
5035         pr "  return ret;\n";
5036         pr "}\n"
5037
5038   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
5039
5040 (* Generate a list of function names, for debugging in the daemon.. *)
5041 and generate_daemon_names () =
5042   generate_header CStyle GPLv2;
5043
5044   pr "#include <config.h>\n";
5045   pr "\n";
5046   pr "#include \"daemon.h\"\n";
5047   pr "\n";
5048
5049   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
5050   pr "const char *function_names[] = {\n";
5051   List.iter (
5052     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
5053   ) daemon_functions;
5054   pr "};\n";
5055
5056 (* Generate the tests. *)
5057 and generate_tests () =
5058   generate_header CStyle GPLv2;
5059
5060   pr "\
5061 #include <stdio.h>
5062 #include <stdlib.h>
5063 #include <string.h>
5064 #include <unistd.h>
5065 #include <sys/types.h>
5066 #include <fcntl.h>
5067
5068 #include \"guestfs.h\"
5069
5070 static guestfs_h *g;
5071 static int suppress_error = 0;
5072
5073 static void print_error (guestfs_h *g, void *data, const char *msg)
5074 {
5075   if (!suppress_error)
5076     fprintf (stderr, \"%%s\\n\", msg);
5077 }
5078
5079 static void print_strings (char * const * const argv)
5080 {
5081   int argc;
5082
5083   for (argc = 0; argv[argc] != NULL; ++argc)
5084     printf (\"\\t%%s\\n\", argv[argc]);
5085 }
5086
5087 /*
5088 static void print_table (char * const * const argv)
5089 {
5090   int i;
5091
5092   for (i = 0; argv[i] != NULL; i += 2)
5093     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
5094 }
5095 */
5096
5097 ";
5098
5099   (* Generate a list of commands which are not tested anywhere. *)
5100   pr "static void no_test_warnings (void)\n";
5101   pr "{\n";
5102
5103   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
5104   List.iter (
5105     fun (_, _, _, _, tests, _, _) ->
5106       let tests = filter_map (
5107         function
5108         | (_, (Always|If _|Unless _), test) -> Some test
5109         | (_, Disabled, _) -> None
5110       ) tests in
5111       let seq = List.concat (List.map seq_of_test tests) in
5112       let cmds_tested = List.map List.hd seq in
5113       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
5114   ) all_functions;
5115
5116   List.iter (
5117     fun (name, _, _, _, _, _, _) ->
5118       if not (Hashtbl.mem hash name) then
5119         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
5120   ) all_functions;
5121
5122   pr "}\n";
5123   pr "\n";
5124
5125   (* Generate the actual tests.  Note that we generate the tests
5126    * in reverse order, deliberately, so that (in general) the
5127    * newest tests run first.  This makes it quicker and easier to
5128    * debug them.
5129    *)
5130   let test_names =
5131     List.map (
5132       fun (name, _, _, _, tests, _, _) ->
5133         mapi (generate_one_test name) tests
5134     ) (List.rev all_functions) in
5135   let test_names = List.concat test_names in
5136   let nr_tests = List.length test_names in
5137
5138   pr "\
5139 int main (int argc, char *argv[])
5140 {
5141   char c = 0;
5142   int failed = 0;
5143   const char *filename;
5144   int fd;
5145   int nr_tests, test_num = 0;
5146
5147   setbuf (stdout, NULL);
5148
5149   no_test_warnings ();
5150
5151   g = guestfs_create ();
5152   if (g == NULL) {
5153     printf (\"guestfs_create FAILED\\n\");
5154     exit (1);
5155   }
5156
5157   guestfs_set_error_handler (g, print_error, NULL);
5158
5159   guestfs_set_path (g, \"../appliance\");
5160
5161   filename = \"test1.img\";
5162   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5163   if (fd == -1) {
5164     perror (filename);
5165     exit (1);
5166   }
5167   if (lseek (fd, %d, SEEK_SET) == -1) {
5168     perror (\"lseek\");
5169     close (fd);
5170     unlink (filename);
5171     exit (1);
5172   }
5173   if (write (fd, &c, 1) == -1) {
5174     perror (\"write\");
5175     close (fd);
5176     unlink (filename);
5177     exit (1);
5178   }
5179   if (close (fd) == -1) {
5180     perror (filename);
5181     unlink (filename);
5182     exit (1);
5183   }
5184   if (guestfs_add_drive (g, filename) == -1) {
5185     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5186     exit (1);
5187   }
5188
5189   filename = \"test2.img\";
5190   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5191   if (fd == -1) {
5192     perror (filename);
5193     exit (1);
5194   }
5195   if (lseek (fd, %d, SEEK_SET) == -1) {
5196     perror (\"lseek\");
5197     close (fd);
5198     unlink (filename);
5199     exit (1);
5200   }
5201   if (write (fd, &c, 1) == -1) {
5202     perror (\"write\");
5203     close (fd);
5204     unlink (filename);
5205     exit (1);
5206   }
5207   if (close (fd) == -1) {
5208     perror (filename);
5209     unlink (filename);
5210     exit (1);
5211   }
5212   if (guestfs_add_drive (g, filename) == -1) {
5213     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5214     exit (1);
5215   }
5216
5217   filename = \"test3.img\";
5218   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5219   if (fd == -1) {
5220     perror (filename);
5221     exit (1);
5222   }
5223   if (lseek (fd, %d, SEEK_SET) == -1) {
5224     perror (\"lseek\");
5225     close (fd);
5226     unlink (filename);
5227     exit (1);
5228   }
5229   if (write (fd, &c, 1) == -1) {
5230     perror (\"write\");
5231     close (fd);
5232     unlink (filename);
5233     exit (1);
5234   }
5235   if (close (fd) == -1) {
5236     perror (filename);
5237     unlink (filename);
5238     exit (1);
5239   }
5240   if (guestfs_add_drive (g, filename) == -1) {
5241     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5242     exit (1);
5243   }
5244
5245   if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
5246     printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
5247     exit (1);
5248   }
5249
5250   if (guestfs_launch (g) == -1) {
5251     printf (\"guestfs_launch FAILED\\n\");
5252     exit (1);
5253   }
5254
5255   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
5256   alarm (600);
5257
5258   if (guestfs_wait_ready (g) == -1) {
5259     printf (\"guestfs_wait_ready FAILED\\n\");
5260     exit (1);
5261   }
5262
5263   /* Cancel previous alarm. */
5264   alarm (0);
5265
5266   nr_tests = %d;
5267
5268 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
5269
5270   iteri (
5271     fun i test_name ->
5272       pr "  test_num++;\n";
5273       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
5274       pr "  if (%s () == -1) {\n" test_name;
5275       pr "    printf (\"%s FAILED\\n\");\n" test_name;
5276       pr "    failed++;\n";
5277       pr "  }\n";
5278   ) test_names;
5279   pr "\n";
5280
5281   pr "  guestfs_close (g);\n";
5282   pr "  unlink (\"test1.img\");\n";
5283   pr "  unlink (\"test2.img\");\n";
5284   pr "  unlink (\"test3.img\");\n";
5285   pr "\n";
5286
5287   pr "  if (failed > 0) {\n";
5288   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
5289   pr "    exit (1);\n";
5290   pr "  }\n";
5291   pr "\n";
5292
5293   pr "  exit (0);\n";
5294   pr "}\n"
5295
5296 and generate_one_test name i (init, prereq, test) =
5297   let test_name = sprintf "test_%s_%d" name i in
5298
5299   pr "\
5300 static int %s_skip (void)
5301 {
5302   const char *str;
5303
5304   str = getenv (\"TEST_ONLY\");
5305   if (str)
5306     return strstr (str, \"%s\") == NULL;
5307   str = getenv (\"SKIP_%s\");
5308   if (str && strcmp (str, \"1\") == 0) return 1;
5309   str = getenv (\"SKIP_TEST_%s\");
5310   if (str && strcmp (str, \"1\") == 0) return 1;
5311   return 0;
5312 }
5313
5314 " test_name name (String.uppercase test_name) (String.uppercase name);
5315
5316   (match prereq with
5317    | Disabled | Always -> ()
5318    | If code | Unless code ->
5319        pr "static int %s_prereq (void)\n" test_name;
5320        pr "{\n";
5321        pr "  %s\n" code;
5322        pr "}\n";
5323        pr "\n";
5324   );
5325
5326   pr "\
5327 static int %s (void)
5328 {
5329   if (%s_skip ()) {
5330     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
5331     return 0;
5332   }
5333
5334 " test_name test_name test_name;
5335
5336   (match prereq with
5337    | Disabled ->
5338        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
5339    | If _ ->
5340        pr "  if (! %s_prereq ()) {\n" test_name;
5341        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5342        pr "    return 0;\n";
5343        pr "  }\n";
5344        pr "\n";
5345        generate_one_test_body name i test_name init test;
5346    | Unless _ ->
5347        pr "  if (%s_prereq ()) {\n" test_name;
5348        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5349        pr "    return 0;\n";
5350        pr "  }\n";
5351        pr "\n";
5352        generate_one_test_body name i test_name init test;
5353    | Always ->
5354        generate_one_test_body name i test_name init test
5355   );
5356
5357   pr "  return 0;\n";
5358   pr "}\n";
5359   pr "\n";
5360   test_name
5361
5362 and generate_one_test_body name i test_name init test =
5363   (match init with
5364    | InitNone (* XXX at some point, InitNone and InitEmpty became
5365                * folded together as the same thing.  Really we should
5366                * make InitNone do nothing at all, but the tests may
5367                * need to be checked to make sure this is OK.
5368                *)
5369    | InitEmpty ->
5370        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
5371        List.iter (generate_test_command_call test_name)
5372          [["blockdev_setrw"; "/dev/sda"];
5373           ["umount_all"];
5374           ["lvm_remove_all"]]
5375    | InitPartition ->
5376        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
5377        List.iter (generate_test_command_call test_name)
5378          [["blockdev_setrw"; "/dev/sda"];
5379           ["umount_all"];
5380           ["lvm_remove_all"];
5381           ["sfdiskM"; "/dev/sda"; ","]]
5382    | InitBasicFS ->
5383        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
5384        List.iter (generate_test_command_call test_name)
5385          [["blockdev_setrw"; "/dev/sda"];
5386           ["umount_all"];
5387           ["lvm_remove_all"];
5388           ["sfdiskM"; "/dev/sda"; ","];
5389           ["mkfs"; "ext2"; "/dev/sda1"];
5390           ["mount"; "/dev/sda1"; "/"]]
5391    | InitBasicFSonLVM ->
5392        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
5393          test_name;
5394        List.iter (generate_test_command_call test_name)
5395          [["blockdev_setrw"; "/dev/sda"];
5396           ["umount_all"];
5397           ["lvm_remove_all"];
5398           ["sfdiskM"; "/dev/sda"; ","];
5399           ["pvcreate"; "/dev/sda1"];
5400           ["vgcreate"; "VG"; "/dev/sda1"];
5401           ["lvcreate"; "LV"; "VG"; "8"];
5402           ["mkfs"; "ext2"; "/dev/VG/LV"];
5403           ["mount"; "/dev/VG/LV"; "/"]]
5404    | InitSquashFS ->
5405        pr "  /* InitSquashFS for %s */\n" test_name;
5406        List.iter (generate_test_command_call test_name)
5407          [["blockdev_setrw"; "/dev/sda"];
5408           ["umount_all"];
5409           ["lvm_remove_all"];
5410           ["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"]]
5411   );
5412
5413   let get_seq_last = function
5414     | [] ->
5415         failwithf "%s: you cannot use [] (empty list) when expecting a command"
5416           test_name
5417     | seq ->
5418         let seq = List.rev seq in
5419         List.rev (List.tl seq), List.hd seq
5420   in
5421
5422   match test with
5423   | TestRun seq ->
5424       pr "  /* TestRun for %s (%d) */\n" name i;
5425       List.iter (generate_test_command_call test_name) seq
5426   | TestOutput (seq, expected) ->
5427       pr "  /* TestOutput for %s (%d) */\n" name i;
5428       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5429       let seq, last = get_seq_last seq in
5430       let test () =
5431         pr "    if (strcmp (r, expected) != 0) {\n";
5432         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5433         pr "      return -1;\n";
5434         pr "    }\n"
5435       in
5436       List.iter (generate_test_command_call test_name) seq;
5437       generate_test_command_call ~test test_name last
5438   | TestOutputList (seq, expected) ->
5439       pr "  /* TestOutputList for %s (%d) */\n" name i;
5440       let seq, last = get_seq_last seq in
5441       let test () =
5442         iteri (
5443           fun i str ->
5444             pr "    if (!r[%d]) {\n" i;
5445             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5446             pr "      print_strings (r);\n";
5447             pr "      return -1;\n";
5448             pr "    }\n";
5449             pr "    {\n";
5450             pr "      const char *expected = \"%s\";\n" (c_quote str);
5451             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5452             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5453             pr "        return -1;\n";
5454             pr "      }\n";
5455             pr "    }\n"
5456         ) expected;
5457         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5458         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5459           test_name;
5460         pr "      print_strings (r);\n";
5461         pr "      return -1;\n";
5462         pr "    }\n"
5463       in
5464       List.iter (generate_test_command_call test_name) seq;
5465       generate_test_command_call ~test test_name last
5466   | TestOutputListOfDevices (seq, expected) ->
5467       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
5468       let seq, last = get_seq_last seq in
5469       let test () =
5470         iteri (
5471           fun i str ->
5472             pr "    if (!r[%d]) {\n" i;
5473             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5474             pr "      print_strings (r);\n";
5475             pr "      return -1;\n";
5476             pr "    }\n";
5477             pr "    {\n";
5478             pr "      const char *expected = \"%s\";\n" (c_quote str);
5479             pr "      r[%d][5] = 's';\n" i;
5480             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5481             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5482             pr "        return -1;\n";
5483             pr "      }\n";
5484             pr "    }\n"
5485         ) expected;
5486         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5487         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5488           test_name;
5489         pr "      print_strings (r);\n";
5490         pr "      return -1;\n";
5491         pr "    }\n"
5492       in
5493       List.iter (generate_test_command_call test_name) seq;
5494       generate_test_command_call ~test test_name last
5495   | TestOutputInt (seq, expected) ->
5496       pr "  /* TestOutputInt for %s (%d) */\n" name i;
5497       let seq, last = get_seq_last seq in
5498       let test () =
5499         pr "    if (r != %d) {\n" expected;
5500         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
5501           test_name expected;
5502         pr "               (int) r);\n";
5503         pr "      return -1;\n";
5504         pr "    }\n"
5505       in
5506       List.iter (generate_test_command_call test_name) seq;
5507       generate_test_command_call ~test test_name last
5508   | TestOutputIntOp (seq, op, expected) ->
5509       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
5510       let seq, last = get_seq_last seq in
5511       let test () =
5512         pr "    if (! (r %s %d)) {\n" op expected;
5513         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
5514           test_name op expected;
5515         pr "               (int) r);\n";
5516         pr "      return -1;\n";
5517         pr "    }\n"
5518       in
5519       List.iter (generate_test_command_call test_name) seq;
5520       generate_test_command_call ~test test_name last
5521   | TestOutputTrue seq ->
5522       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
5523       let seq, last = get_seq_last seq in
5524       let test () =
5525         pr "    if (!r) {\n";
5526         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
5527           test_name;
5528         pr "      return -1;\n";
5529         pr "    }\n"
5530       in
5531       List.iter (generate_test_command_call test_name) seq;
5532       generate_test_command_call ~test test_name last
5533   | TestOutputFalse seq ->
5534       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
5535       let seq, last = get_seq_last seq in
5536       let test () =
5537         pr "    if (r) {\n";
5538         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
5539           test_name;
5540         pr "      return -1;\n";
5541         pr "    }\n"
5542       in
5543       List.iter (generate_test_command_call test_name) seq;
5544       generate_test_command_call ~test test_name last
5545   | TestOutputLength (seq, expected) ->
5546       pr "  /* TestOutputLength for %s (%d) */\n" name i;
5547       let seq, last = get_seq_last seq in
5548       let test () =
5549         pr "    int j;\n";
5550         pr "    for (j = 0; j < %d; ++j)\n" expected;
5551         pr "      if (r[j] == NULL) {\n";
5552         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
5553           test_name;
5554         pr "        print_strings (r);\n";
5555         pr "        return -1;\n";
5556         pr "      }\n";
5557         pr "    if (r[j] != NULL) {\n";
5558         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
5559           test_name;
5560         pr "      print_strings (r);\n";
5561         pr "      return -1;\n";
5562         pr "    }\n"
5563       in
5564       List.iter (generate_test_command_call test_name) seq;
5565       generate_test_command_call ~test test_name last
5566   | TestOutputBuffer (seq, expected) ->
5567       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
5568       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5569       let seq, last = get_seq_last seq in
5570       let len = String.length expected in
5571       let test () =
5572         pr "    if (size != %d) {\n" len;
5573         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
5574         pr "      return -1;\n";
5575         pr "    }\n";
5576         pr "    if (strncmp (r, expected, size) != 0) {\n";
5577         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5578         pr "      return -1;\n";
5579         pr "    }\n"
5580       in
5581       List.iter (generate_test_command_call test_name) seq;
5582       generate_test_command_call ~test test_name last
5583   | TestOutputStruct (seq, checks) ->
5584       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
5585       let seq, last = get_seq_last seq in
5586       let test () =
5587         List.iter (
5588           function
5589           | CompareWithInt (field, expected) ->
5590               pr "    if (r->%s != %d) {\n" field expected;
5591               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
5592                 test_name field expected;
5593               pr "               (int) r->%s);\n" field;
5594               pr "      return -1;\n";
5595               pr "    }\n"
5596           | CompareWithIntOp (field, op, expected) ->
5597               pr "    if (!(r->%s %s %d)) {\n" field op expected;
5598               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
5599                 test_name field op expected;
5600               pr "               (int) r->%s);\n" field;
5601               pr "      return -1;\n";
5602               pr "    }\n"
5603           | CompareWithString (field, expected) ->
5604               pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
5605               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
5606                 test_name field expected;
5607               pr "               r->%s);\n" field;
5608               pr "      return -1;\n";
5609               pr "    }\n"
5610           | CompareFieldsIntEq (field1, field2) ->
5611               pr "    if (r->%s != r->%s) {\n" field1 field2;
5612               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
5613                 test_name field1 field2;
5614               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
5615               pr "      return -1;\n";
5616               pr "    }\n"
5617           | CompareFieldsStrEq (field1, field2) ->
5618               pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
5619               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
5620                 test_name field1 field2;
5621               pr "               r->%s, r->%s);\n" field1 field2;
5622               pr "      return -1;\n";
5623               pr "    }\n"
5624         ) checks
5625       in
5626       List.iter (generate_test_command_call test_name) seq;
5627       generate_test_command_call ~test test_name last
5628   | TestLastFail seq ->
5629       pr "  /* TestLastFail for %s (%d) */\n" name i;
5630       let seq, last = get_seq_last seq in
5631       List.iter (generate_test_command_call test_name) seq;
5632       generate_test_command_call test_name ~expect_error:true last
5633
5634 (* Generate the code to run a command, leaving the result in 'r'.
5635  * If you expect to get an error then you should set expect_error:true.
5636  *)
5637 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
5638   match cmd with
5639   | [] -> assert false
5640   | name :: args ->
5641       (* Look up the command to find out what args/ret it has. *)
5642       let style =
5643         try
5644           let _, style, _, _, _, _, _ =
5645             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
5646           style
5647         with Not_found ->
5648           failwithf "%s: in test, command %s was not found" test_name name in
5649
5650       if List.length (snd style) <> List.length args then
5651         failwithf "%s: in test, wrong number of args given to %s"
5652           test_name name;
5653
5654       pr "  {\n";
5655
5656       List.iter (
5657         function
5658         | OptString n, "NULL" -> ()
5659         | Device n, arg
5660         | String n, arg
5661         | OptString n, arg ->
5662             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
5663         | Int _, _
5664         | Bool _, _
5665         | FileIn _, _ | FileOut _, _ -> ()
5666         | StringList n, arg ->
5667             let strs = string_split " " arg in
5668             iteri (
5669               fun i str ->
5670                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
5671             ) strs;
5672             pr "    const char *%s[] = {\n" n;
5673             iteri (
5674               fun i _ -> pr "      %s_%d,\n" n i
5675             ) strs;
5676             pr "      NULL\n";
5677             pr "    };\n";
5678       ) (List.combine (snd style) args);
5679
5680       let error_code =
5681         match fst style with
5682         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
5683         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
5684         | RConstString _ | RConstOptString _ ->
5685             pr "    const char *r;\n"; "NULL"
5686         | RString _ -> pr "    char *r;\n"; "NULL"
5687         | RStringList _ | RHashtable _ ->
5688             pr "    char **r;\n";
5689             pr "    int i;\n";
5690             "NULL"
5691         | RStruct (_, typ) ->
5692             pr "    struct guestfs_%s *r;\n" typ; "NULL"
5693         | RStructList (_, typ) ->
5694             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
5695         | RBufferOut _ ->
5696             pr "    char *r;\n";
5697             pr "    size_t size;\n";
5698             "NULL" in
5699
5700       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
5701       pr "    r = guestfs_%s (g" name;
5702
5703       (* Generate the parameters. *)
5704       List.iter (
5705         function
5706         | OptString _, "NULL" -> pr ", NULL"
5707         | Device n, _
5708         | String n, _
5709         | OptString n, _ ->
5710             pr ", %s" n
5711         | FileIn _, arg | FileOut _, arg ->
5712             pr ", \"%s\"" (c_quote arg)
5713         | StringList n, _ ->
5714             pr ", %s" n
5715         | Int _, arg ->
5716             let i =
5717               try int_of_string arg
5718               with Failure "int_of_string" ->
5719                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
5720             pr ", %d" i
5721         | Bool _, arg ->
5722             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
5723       ) (List.combine (snd style) args);
5724
5725       (match fst style with
5726        | RBufferOut _ -> pr ", &size"
5727        | _ -> ()
5728       );
5729
5730       pr ");\n";
5731
5732       if not expect_error then
5733         pr "    if (r == %s)\n" error_code
5734       else
5735         pr "    if (r != %s)\n" error_code;
5736       pr "      return -1;\n";
5737
5738       (* Insert the test code. *)
5739       (match test with
5740        | None -> ()
5741        | Some f -> f ()
5742       );
5743
5744       (match fst style with
5745        | RErr | RInt _ | RInt64 _ | RBool _
5746        | RConstString _ | RConstOptString _ -> ()
5747        | RString _ | RBufferOut _ -> pr "    free (r);\n"
5748        | RStringList _ | RHashtable _ ->
5749            pr "    for (i = 0; r[i] != NULL; ++i)\n";
5750            pr "      free (r[i]);\n";
5751            pr "    free (r);\n"
5752        | RStruct (_, typ) ->
5753            pr "    guestfs_free_%s (r);\n" typ
5754        | RStructList (_, typ) ->
5755            pr "    guestfs_free_%s_list (r);\n" typ
5756       );
5757
5758       pr "  }\n"
5759
5760 and c_quote str =
5761   let str = replace_str str "\r" "\\r" in
5762   let str = replace_str str "\n" "\\n" in
5763   let str = replace_str str "\t" "\\t" in
5764   let str = replace_str str "\000" "\\0" in
5765   str
5766
5767 (* Generate a lot of different functions for guestfish. *)
5768 and generate_fish_cmds () =
5769   generate_header CStyle GPLv2;
5770
5771   let all_functions =
5772     List.filter (
5773       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5774     ) all_functions in
5775   let all_functions_sorted =
5776     List.filter (
5777       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5778     ) all_functions_sorted in
5779
5780   pr "#include <stdio.h>\n";
5781   pr "#include <stdlib.h>\n";
5782   pr "#include <string.h>\n";
5783   pr "#include <inttypes.h>\n";
5784   pr "#include <ctype.h>\n";
5785   pr "\n";
5786   pr "#include <guestfs.h>\n";
5787   pr "#include \"fish.h\"\n";
5788   pr "\n";
5789
5790   (* list_commands function, which implements guestfish -h *)
5791   pr "void list_commands (void)\n";
5792   pr "{\n";
5793   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
5794   pr "  list_builtin_commands ();\n";
5795   List.iter (
5796     fun (name, _, _, flags, _, shortdesc, _) ->
5797       let name = replace_char name '_' '-' in
5798       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
5799         name shortdesc
5800   ) all_functions_sorted;
5801   pr "  printf (\"    %%s\\n\",";
5802   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
5803   pr "}\n";
5804   pr "\n";
5805
5806   (* display_command function, which implements guestfish -h cmd *)
5807   pr "void display_command (const char *cmd)\n";
5808   pr "{\n";
5809   List.iter (
5810     fun (name, style, _, flags, _, shortdesc, longdesc) ->
5811       let name2 = replace_char name '_' '-' in
5812       let alias =
5813         try find_map (function FishAlias n -> Some n | _ -> None) flags
5814         with Not_found -> name in
5815       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
5816       let synopsis =
5817         match snd style with
5818         | [] -> name2
5819         | args ->
5820             sprintf "%s <%s>"
5821               name2 (String.concat "> <" (List.map name_of_argt args)) in
5822
5823       let warnings =
5824         if List.mem ProtocolLimitWarning flags then
5825           ("\n\n" ^ protocol_limit_warning)
5826         else "" in
5827
5828       (* For DangerWillRobinson commands, we should probably have
5829        * guestfish prompt before allowing you to use them (especially
5830        * in interactive mode). XXX
5831        *)
5832       let warnings =
5833         warnings ^
5834           if List.mem DangerWillRobinson flags then
5835             ("\n\n" ^ danger_will_robinson)
5836           else "" in
5837
5838       let warnings =
5839         warnings ^
5840           match deprecation_notice flags with
5841           | None -> ""
5842           | Some txt -> "\n\n" ^ txt in
5843
5844       let describe_alias =
5845         if name <> alias then
5846           sprintf "\n\nYou can use '%s' as an alias for this command." alias
5847         else "" in
5848
5849       pr "  if (";
5850       pr "strcasecmp (cmd, \"%s\") == 0" name;
5851       if name <> name2 then
5852         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5853       if name <> alias then
5854         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5855       pr ")\n";
5856       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
5857         name2 shortdesc
5858         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
5859       pr "  else\n"
5860   ) all_functions;
5861   pr "    display_builtin_command (cmd);\n";
5862   pr "}\n";
5863   pr "\n";
5864
5865   (* print_* functions *)
5866   List.iter (
5867     fun (typ, cols) ->
5868       let needs_i =
5869         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
5870
5871       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
5872       pr "{\n";
5873       if needs_i then (
5874         pr "  int i;\n";
5875         pr "\n"
5876       );
5877       List.iter (
5878         function
5879         | name, FString ->
5880             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
5881         | name, FUUID ->
5882             pr "  printf (\"%s: \");\n" name;
5883             pr "  for (i = 0; i < 32; ++i)\n";
5884             pr "    printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
5885             pr "  printf (\"\\n\");\n"
5886         | name, FBuffer ->
5887             pr "  printf (\"%%s%s: \", indent);\n" name;
5888             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
5889             pr "    if (isprint (%s->%s[i]))\n" typ name;
5890             pr "      printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
5891             pr "    else\n";
5892             pr "      printf (\"%%s\\\\x%%02x\", indent, %s->%s[i]);\n" typ name;
5893             pr "  printf (\"\\n\");\n"
5894         | name, (FUInt64|FBytes) ->
5895             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
5896               name typ name
5897         | name, FInt64 ->
5898             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
5899               name typ name
5900         | name, FUInt32 ->
5901             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
5902               name typ name
5903         | name, FInt32 ->
5904             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
5905               name typ name
5906         | name, FChar ->
5907             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
5908               name typ name
5909         | name, FOptPercent ->
5910             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
5911               typ name name typ name;
5912             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
5913       ) cols;
5914       pr "}\n";
5915       pr "\n";
5916       pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
5917       pr "{\n";
5918       pr "  print_%s_indent (%s, \"\");\n" typ typ;
5919       pr "}\n";
5920       pr "\n";
5921       pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
5922         typ typ typ;
5923       pr "{\n";
5924       pr "  int i;\n";
5925       pr "\n";
5926       pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
5927       pr "    printf (\"[%%d] = {\\n\", i);\n";
5928       pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
5929       pr "    printf (\"}\\n\");\n";
5930       pr "  }\n";
5931       pr "}\n";
5932       pr "\n";
5933   ) structs;
5934
5935   (* run_<action> actions *)
5936   List.iter (
5937     fun (name, style, _, flags, _, _, _) ->
5938       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
5939       pr "{\n";
5940       (match fst style with
5941        | RErr
5942        | RInt _
5943        | RBool _ -> pr "  int r;\n"
5944        | RInt64 _ -> pr "  int64_t r;\n"
5945        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
5946        | RString _ -> pr "  char *r;\n"
5947        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
5948        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
5949        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
5950        | RBufferOut _ ->
5951            pr "  char *r;\n";
5952            pr "  size_t size;\n";
5953       );
5954       List.iter (
5955         function
5956         | Device n
5957         | String n
5958         | OptString n
5959         | FileIn n
5960         | FileOut n -> pr "  const char *%s;\n" n
5961         | StringList n -> pr "  char **%s;\n" n
5962         | Bool n -> pr "  int %s;\n" n
5963         | Int n -> pr "  int %s;\n" n
5964       ) (snd style);
5965
5966       (* Check and convert parameters. *)
5967       let argc_expected = List.length (snd style) in
5968       pr "  if (argc != %d) {\n" argc_expected;
5969       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
5970         argc_expected;
5971       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
5972       pr "    return -1;\n";
5973       pr "  }\n";
5974       iteri (
5975         fun i ->
5976           function
5977           | Device name | String name -> pr "  %s = argv[%d];\n" name i
5978           | OptString name ->
5979               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5980                 name i i
5981           | FileIn name ->
5982               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5983                 name i i
5984           | FileOut name ->
5985               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5986                 name i i
5987           | StringList name ->
5988               pr "  %s = parse_string_list (argv[%d]);\n" name i
5989           | Bool name ->
5990               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5991           | Int name ->
5992               pr "  %s = atoi (argv[%d]);\n" name i
5993       ) (snd style);
5994
5995       (* Call C API function. *)
5996       let fn =
5997         try find_map (function FishAction n -> Some n | _ -> None) flags
5998         with Not_found -> sprintf "guestfs_%s" name in
5999       pr "  r = %s " fn;
6000       generate_c_call_args ~handle:"g" style;
6001       pr ";\n";
6002
6003       (* Check return value for errors and display command results. *)
6004       (match fst style with
6005        | RErr -> pr "  return r;\n"
6006        | RInt _ ->
6007            pr "  if (r == -1) return -1;\n";
6008            pr "  printf (\"%%d\\n\", r);\n";
6009            pr "  return 0;\n"
6010        | RInt64 _ ->
6011            pr "  if (r == -1) return -1;\n";
6012            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
6013            pr "  return 0;\n"
6014        | RBool _ ->
6015            pr "  if (r == -1) return -1;\n";
6016            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
6017            pr "  return 0;\n"
6018        | RConstString _ ->
6019            pr "  if (r == NULL) return -1;\n";
6020            pr "  printf (\"%%s\\n\", r);\n";
6021            pr "  return 0;\n"
6022        | RConstOptString _ ->
6023            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
6024            pr "  return 0;\n"
6025        | RString _ ->
6026            pr "  if (r == NULL) return -1;\n";
6027            pr "  printf (\"%%s\\n\", r);\n";
6028            pr "  free (r);\n";
6029            pr "  return 0;\n"
6030        | RStringList _ ->
6031            pr "  if (r == NULL) return -1;\n";
6032            pr "  print_strings (r);\n";
6033            pr "  free_strings (r);\n";
6034            pr "  return 0;\n"
6035        | RStruct (_, typ) ->
6036            pr "  if (r == NULL) return -1;\n";
6037            pr "  print_%s (r);\n" typ;
6038            pr "  guestfs_free_%s (r);\n" typ;
6039            pr "  return 0;\n"
6040        | RStructList (_, typ) ->
6041            pr "  if (r == NULL) return -1;\n";
6042            pr "  print_%s_list (r);\n" typ;
6043            pr "  guestfs_free_%s_list (r);\n" typ;
6044            pr "  return 0;\n"
6045        | RHashtable _ ->
6046            pr "  if (r == NULL) return -1;\n";
6047            pr "  print_table (r);\n";
6048            pr "  free_strings (r);\n";
6049            pr "  return 0;\n"
6050        | RBufferOut _ ->
6051            pr "  if (r == NULL) return -1;\n";
6052            pr "  fwrite (r, size, 1, stdout);\n";
6053            pr "  free (r);\n";
6054            pr "  return 0;\n"
6055       );
6056       pr "}\n";
6057       pr "\n"
6058   ) all_functions;
6059
6060   (* run_action function *)
6061   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
6062   pr "{\n";
6063   List.iter (
6064     fun (name, _, _, flags, _, _, _) ->
6065       let name2 = replace_char name '_' '-' in
6066       let alias =
6067         try find_map (function FishAlias n -> Some n | _ -> None) flags
6068         with Not_found -> name in
6069       pr "  if (";
6070       pr "strcasecmp (cmd, \"%s\") == 0" name;
6071       if name <> name2 then
6072         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
6073       if name <> alias then
6074         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
6075       pr ")\n";
6076       pr "    return run_%s (cmd, argc, argv);\n" name;
6077       pr "  else\n";
6078   ) all_functions;
6079   pr "    {\n";
6080   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
6081   pr "      return -1;\n";
6082   pr "    }\n";
6083   pr "  return 0;\n";
6084   pr "}\n";
6085   pr "\n"
6086
6087 (* Readline completion for guestfish. *)
6088 and generate_fish_completion () =
6089   generate_header CStyle GPLv2;
6090
6091   let all_functions =
6092     List.filter (
6093       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6094     ) all_functions in
6095
6096   pr "\
6097 #include <config.h>
6098
6099 #include <stdio.h>
6100 #include <stdlib.h>
6101 #include <string.h>
6102
6103 #ifdef HAVE_LIBREADLINE
6104 #include <readline/readline.h>
6105 #endif
6106
6107 #include \"fish.h\"
6108
6109 #ifdef HAVE_LIBREADLINE
6110
6111 static const char *const commands[] = {
6112   BUILTIN_COMMANDS_FOR_COMPLETION,
6113 ";
6114
6115   (* Get the commands, including the aliases.  They don't need to be
6116    * sorted - the generator() function just does a dumb linear search.
6117    *)
6118   let commands =
6119     List.map (
6120       fun (name, _, _, flags, _, _, _) ->
6121         let name2 = replace_char name '_' '-' in
6122         let alias =
6123           try find_map (function FishAlias n -> Some n | _ -> None) flags
6124           with Not_found -> name in
6125
6126         if name <> alias then [name2; alias] else [name2]
6127     ) all_functions in
6128   let commands = List.flatten commands in
6129
6130   List.iter (pr "  \"%s\",\n") commands;
6131
6132   pr "  NULL
6133 };
6134
6135 static char *
6136 generator (const char *text, int state)
6137 {
6138   static int index, len;
6139   const char *name;
6140
6141   if (!state) {
6142     index = 0;
6143     len = strlen (text);
6144   }
6145
6146   rl_attempted_completion_over = 1;
6147
6148   while ((name = commands[index]) != NULL) {
6149     index++;
6150     if (strncasecmp (name, text, len) == 0)
6151       return strdup (name);
6152   }
6153
6154   return NULL;
6155 }
6156
6157 #endif /* HAVE_LIBREADLINE */
6158
6159 char **do_completion (const char *text, int start, int end)
6160 {
6161   char **matches = NULL;
6162
6163 #ifdef HAVE_LIBREADLINE
6164   rl_completion_append_character = ' ';
6165
6166   if (start == 0)
6167     matches = rl_completion_matches (text, generator);
6168   else if (complete_dest_paths)
6169     matches = rl_completion_matches (text, complete_dest_paths_generator);
6170 #endif
6171
6172   return matches;
6173 }
6174 ";
6175
6176 (* Generate the POD documentation for guestfish. *)
6177 and generate_fish_actions_pod () =
6178   let all_functions_sorted =
6179     List.filter (
6180       fun (_, _, _, flags, _, _, _) ->
6181         not (List.mem NotInFish flags || List.mem NotInDocs flags)
6182     ) all_functions_sorted in
6183
6184   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
6185
6186   List.iter (
6187     fun (name, style, _, flags, _, _, longdesc) ->
6188       let longdesc =
6189         Str.global_substitute rex (
6190           fun s ->
6191             let sub =
6192               try Str.matched_group 1 s
6193               with Not_found ->
6194                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
6195             "C<" ^ replace_char sub '_' '-' ^ ">"
6196         ) longdesc in
6197       let name = replace_char name '_' '-' in
6198       let alias =
6199         try find_map (function FishAlias n -> Some n | _ -> None) flags
6200         with Not_found -> name in
6201
6202       pr "=head2 %s" name;
6203       if name <> alias then
6204         pr " | %s" alias;
6205       pr "\n";
6206       pr "\n";
6207       pr " %s" name;
6208       List.iter (
6209         function
6210         | Device n | String n -> pr " %s" n
6211         | OptString n -> pr " %s" n
6212         | StringList n -> pr " '%s ...'" n
6213         | Bool _ -> pr " true|false"
6214         | Int n -> pr " %s" n
6215         | FileIn n | FileOut n -> pr " (%s|-)" n
6216       ) (snd style);
6217       pr "\n";
6218       pr "\n";
6219       pr "%s\n\n" longdesc;
6220
6221       if List.exists (function FileIn _ | FileOut _ -> true
6222                       | _ -> false) (snd style) then
6223         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
6224
6225       if List.mem ProtocolLimitWarning flags then
6226         pr "%s\n\n" protocol_limit_warning;
6227
6228       if List.mem DangerWillRobinson flags then
6229         pr "%s\n\n" danger_will_robinson;
6230
6231       match deprecation_notice flags with
6232       | None -> ()
6233       | Some txt -> pr "%s\n\n" txt
6234   ) all_functions_sorted
6235
6236 (* Generate a C function prototype. *)
6237 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
6238     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
6239     ?(prefix = "")
6240     ?handle name style =
6241   if extern then pr "extern ";
6242   if static then pr "static ";
6243   (match fst style with
6244    | RErr -> pr "int "
6245    | RInt _ -> pr "int "
6246    | RInt64 _ -> pr "int64_t "
6247    | RBool _ -> pr "int "
6248    | RConstString _ | RConstOptString _ -> pr "const char *"
6249    | RString _ | RBufferOut _ -> pr "char *"
6250    | RStringList _ | RHashtable _ -> pr "char **"
6251    | RStruct (_, typ) ->
6252        if not in_daemon then pr "struct guestfs_%s *" typ
6253        else pr "guestfs_int_%s *" typ
6254    | RStructList (_, typ) ->
6255        if not in_daemon then pr "struct guestfs_%s_list *" typ
6256        else pr "guestfs_int_%s_list *" typ
6257   );
6258   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
6259   pr "%s%s (" prefix name;
6260   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
6261     pr "void"
6262   else (
6263     let comma = ref false in
6264     (match handle with
6265      | None -> ()
6266      | Some handle -> pr "guestfs_h *%s" handle; comma := true
6267     );
6268     let next () =
6269       if !comma then (
6270         if single_line then pr ", " else pr ",\n\t\t"
6271       );
6272       comma := true
6273     in
6274     List.iter (
6275       function
6276       | Device n
6277       | String n
6278       | OptString n ->
6279           next ();
6280 (* FIXME *)
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