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