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