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