Add 'filesize' call.
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009-2010 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 of
25  * 'daemon_functions' below), and daemon/<somefile>.c to write the
26  * implementation.
27  * 
28  * After editing this file, run it (./src/generator.ml) to regenerate
29  * all the output files.  'make' will rerun this automatically when
30  * necessary.  Note that if you are using a separate build directory
31  * you must run generator.ml from the _source_ directory.
32  * 
33  * IMPORTANT: This script should NOT print any warnings.  If it prints
34  * warnings, you should treat them as errors.
35  *
36  * OCaml tips:
37  * (1) In emacs, install tuareg-mode to display and format OCaml code
38  * correctly.  'vim' comes with a good OCaml editing mode by default.
39  * (2) Read the resources at http://ocaml-tutorial.org/
40  *)
41
42 #load "unix.cma";;
43 #load "str.cma";;
44 #directory "+xml-light";;
45 #load "xml-light.cma";;
46
47 open Unix
48 open Printf
49
50 type style = ret * args
51 and ret =
52     (* "RErr" as a return value means an int used as a simple error
53      * indication, ie. 0 or -1.
54      *)
55   | RErr
56
57     (* "RInt" as a return value means an int which is -1 for error
58      * or any value >= 0 on success.  Only use this for smallish
59      * positive ints (0 <= i < 2^30).
60      *)
61   | RInt of string
62
63     (* "RInt64" is the same as RInt, but is guaranteed to be able
64      * to return a full 64 bit value, _except_ that -1 means error
65      * (so -1 cannot be a valid, non-error return value).
66      *)
67   | RInt64 of string
68
69     (* "RBool" is a bool return value which can be true/false or
70      * -1 for error.
71      *)
72   | RBool of string
73
74     (* "RConstString" is a string that refers to a constant value.
75      * The return value must NOT be NULL (since NULL indicates
76      * an error).
77      *
78      * Try to avoid using this.  In particular you cannot use this
79      * for values returned from the daemon, because there is no
80      * thread-safe way to return them in the C API.
81      *)
82   | RConstString of string
83
84     (* "RConstOptString" is an even more broken version of
85      * "RConstString".  The returned string may be NULL and there
86      * is no way to return an error indication.  Avoid using this!
87      *)
88   | RConstOptString of string
89
90     (* "RString" is a returned string.  It must NOT be NULL, since
91      * a NULL return indicates an error.  The caller frees this.
92      *)
93   | RString of string
94
95     (* "RStringList" is a list of strings.  No string in the list
96      * can be NULL.  The caller frees the strings and the array.
97      *)
98   | RStringList of string
99
100     (* "RStruct" is a function which returns a single named structure
101      * or an error indication (in C, a struct, and in other languages
102      * with varying representations, but usually very efficient).  See
103      * after the function list below for the structures.
104      *)
105   | RStruct of string * string          (* name of retval, name of struct *)
106
107     (* "RStructList" is a function which returns either a list/array
108      * of structures (could be zero-length), or an error indication.
109      *)
110   | RStructList of string * string      (* name of retval, name of struct *)
111
112     (* Key-value pairs of untyped strings.  Turns into a hashtable or
113      * dictionary in languages which support it.  DON'T use this as a
114      * general "bucket" for results.  Prefer a stronger typed return
115      * value if one is available, or write a custom struct.  Don't use
116      * this if the list could potentially be very long, since it is
117      * inefficient.  Keys should be unique.  NULLs are not permitted.
118      *)
119   | RHashtable of string
120
121     (* "RBufferOut" is handled almost exactly like RString, but
122      * it allows the string to contain arbitrary 8 bit data including
123      * ASCII NUL.  In the C API this causes an implicit extra parameter
124      * to be added of type <size_t *size_r>.  The extra parameter
125      * returns the actual size of the return buffer in bytes.
126      *
127      * Other programming languages support strings with arbitrary 8 bit
128      * data.
129      *
130      * At the RPC layer we have to use the opaque<> type instead of
131      * string<>.  Returned data is still limited to the max message
132      * size (ie. ~ 2 MB).
133      *)
134   | RBufferOut of string
135
136 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
137
138     (* Note in future we should allow a "variable args" parameter as
139      * the final parameter, to allow commands like
140      *   chmod mode file [file(s)...]
141      * This is not implemented yet, but many commands (such as chmod)
142      * are currently defined with the argument order keeping this future
143      * possibility in mind.
144      *)
145 and argt =
146   | String of string    (* const char *name, cannot be NULL *)
147   | Device of string    (* /dev device name, cannot be NULL *)
148   | Pathname of string  (* file name, cannot be NULL *)
149   | Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
150   | OptString of string (* const char *name, may be NULL *)
151   | StringList of string(* list of strings (each string cannot be NULL) *)
152   | DeviceList of string(* list of Device names (each cannot be NULL) *)
153   | Bool of string      (* boolean *)
154   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
155   | Int64 of string     (* any 64 bit int *)
156     (* These are treated as filenames (simple string parameters) in
157      * the C API and bindings.  But in the RPC protocol, we transfer
158      * the actual file content up to or down from the daemon.
159      * FileIn: local machine -> daemon (in request)
160      * FileOut: daemon -> local machine (in reply)
161      * In guestfish (only), the special name "-" means read from
162      * stdin or write to stdout.
163      *)
164   | FileIn of string
165   | FileOut of string
166 (* Not implemented:
167     (* Opaque buffer which can contain arbitrary 8 bit data.
168      * In the C API, this is expressed as <char *, int> pair.
169      * Most other languages have a string type which can contain
170      * ASCII NUL.  We use whatever type is appropriate for each
171      * language.
172      * Buffers are limited by the total message size.  To transfer
173      * large blocks of data, use FileIn/FileOut parameters instead.
174      * To return an arbitrary buffer, use RBufferOut.
175      *)
176   | BufferIn of string
177 *)
178
179 type flags =
180   | ProtocolLimitWarning  (* display warning about protocol size limits *)
181   | DangerWillRobinson    (* flags particularly dangerous commands *)
182   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
183   | FishAction of string  (* call this function in guestfish *)
184   | NotInFish             (* do not export via guestfish *)
185   | NotInDocs             (* do not add this function to documentation *)
186   | DeprecatedBy of string (* function is deprecated, use .. instead *)
187   | Optional of string    (* function is part of an optional group *)
188
189 (* You can supply zero or as many tests as you want per API call.
190  *
191  * Note that the test environment has 3 block devices, of size 500MB,
192  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
193  * a fourth ISO block device with some known files on it (/dev/sdd).
194  *
195  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
196  * Number of cylinders was 63 for IDE emulated disks with precisely
197  * the same size.  How exactly this is calculated is a mystery.
198  *
199  * The ISO block device (/dev/sdd) comes from images/test.iso.
200  *
201  * To be able to run the tests in a reasonable amount of time,
202  * the virtual machine and block devices are reused between tests.
203  * So don't try testing kill_subprocess :-x
204  *
205  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
206  *
207  * Don't assume anything about the previous contents of the block
208  * devices.  Use 'Init*' to create some initial scenarios.
209  *
210  * You can add a prerequisite clause to any individual test.  This
211  * is a run-time check, which, if it fails, causes the test to be
212  * skipped.  Useful if testing a command which might not work on
213  * all variations of libguestfs builds.  A test that has prerequisite
214  * of 'Always' is run unconditionally.
215  *
216  * In addition, packagers can skip individual tests by setting the
217  * environment variables:     eg:
218  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
219  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
220  *)
221 type tests = (test_init * test_prereq * test) list
222 and test =
223     (* Run the command sequence and just expect nothing to fail. *)
224   | TestRun of seq
225
226     (* Run the command sequence and expect the output of the final
227      * command to be the string.
228      *)
229   | TestOutput of seq * string
230
231     (* Run the command sequence and expect the output of the final
232      * command to be the list of strings.
233      *)
234   | TestOutputList of seq * string list
235
236     (* Run the command sequence and expect the output of the final
237      * command to be the list of block devices (could be either
238      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
239      * character of each string).
240      *)
241   | TestOutputListOfDevices of seq * string list
242
243     (* Run the command sequence and expect the output of the final
244      * command to be the integer.
245      *)
246   | TestOutputInt of seq * int
247
248     (* Run the command sequence and expect the output of the final
249      * command to be <op> <int>, eg. ">=", "1".
250      *)
251   | TestOutputIntOp of seq * string * int
252
253     (* Run the command sequence and expect the output of the final
254      * command to be a true value (!= 0 or != NULL).
255      *)
256   | TestOutputTrue of seq
257
258     (* Run the command sequence and expect the output of the final
259      * command to be a false value (== 0 or == NULL, but not an error).
260      *)
261   | TestOutputFalse of seq
262
263     (* Run the command sequence and expect the output of the final
264      * command to be a list of the given length (but don't care about
265      * content).
266      *)
267   | TestOutputLength of seq * int
268
269     (* Run the command sequence and expect the output of the final
270      * command to be a buffer (RBufferOut), ie. string + size.
271      *)
272   | TestOutputBuffer of seq * string
273
274     (* Run the command sequence and expect the output of the final
275      * command to be a structure.
276      *)
277   | TestOutputStruct of seq * test_field_compare list
278
279     (* Run the command sequence and expect the final command (only)
280      * to fail.
281      *)
282   | TestLastFail of seq
283
284 and test_field_compare =
285   | CompareWithInt of string * int
286   | CompareWithIntOp of string * string * int
287   | CompareWithString of string * string
288   | CompareFieldsIntEq of string * string
289   | CompareFieldsStrEq of string * string
290
291 (* Test prerequisites. *)
292 and test_prereq =
293     (* Test always runs. *)
294   | Always
295
296     (* Test is currently disabled - eg. it fails, or it tests some
297      * unimplemented feature.
298      *)
299   | Disabled
300
301     (* 'string' is some C code (a function body) that should return
302      * true or false.  The test will run if the code returns true.
303      *)
304   | If of string
305
306     (* As for 'If' but the test runs _unless_ the code returns true. *)
307   | Unless of string
308
309 (* Some initial scenarios for testing. *)
310 and test_init =
311     (* Do nothing, block devices could contain random stuff including
312      * LVM PVs, and some filesystems might be mounted.  This is usually
313      * a bad idea.
314      *)
315   | InitNone
316
317     (* Block devices are empty and no filesystems are mounted. *)
318   | InitEmpty
319
320     (* /dev/sda contains a single partition /dev/sda1, with random
321      * content.  /dev/sdb and /dev/sdc may have random content.
322      * No LVM.
323      *)
324   | InitPartition
325
326     (* /dev/sda contains a single partition /dev/sda1, which is formatted
327      * as ext2, empty [except for lost+found] and mounted on /.
328      * /dev/sdb and /dev/sdc may have random content.
329      * No LVM.
330      *)
331   | InitBasicFS
332
333     (* /dev/sda:
334      *   /dev/sda1 (is a PV):
335      *     /dev/VG/LV (size 8MB):
336      *       formatted as ext2, empty [except for lost+found], mounted on /
337      * /dev/sdb and /dev/sdc may have random content.
338      *)
339   | InitBasicFSonLVM
340
341     (* /dev/sdd (the ISO, see images/ directory in source)
342      * is mounted on /
343      *)
344   | InitISOFS
345
346 (* Sequence of commands for testing. *)
347 and seq = cmd list
348 and cmd = string list
349
350 (* Note about long descriptions: When referring to another
351  * action, use the format C<guestfs_other> (ie. the full name of
352  * the C function).  This will be replaced as appropriate in other
353  * language bindings.
354  *
355  * Apart from that, long descriptions are just perldoc paragraphs.
356  *)
357
358 (* Generate a random UUID (used in tests). *)
359 let uuidgen () =
360   let chan = open_process_in "uuidgen" in
361   let uuid = input_line chan in
362   (match close_process_in chan with
363    | WEXITED 0 -> ()
364    | WEXITED _ ->
365        failwith "uuidgen: process exited with non-zero status"
366    | WSIGNALED _ | WSTOPPED _ ->
367        failwith "uuidgen: process signalled or stopped by signal"
368   );
369   uuid
370
371 (* These test functions are used in the language binding tests. *)
372
373 let test_all_args = [
374   String "str";
375   OptString "optstr";
376   StringList "strlist";
377   Bool "b";
378   Int "integer";
379   Int64 "integer64";
380   FileIn "filein";
381   FileOut "fileout";
382 ]
383
384 let test_all_rets = [
385   (* except for RErr, which is tested thoroughly elsewhere *)
386   "test0rint",         RInt "valout";
387   "test0rint64",       RInt64 "valout";
388   "test0rbool",        RBool "valout";
389   "test0rconststring", RConstString "valout";
390   "test0rconstoptstring", RConstOptString "valout";
391   "test0rstring",      RString "valout";
392   "test0rstringlist",  RStringList "valout";
393   "test0rstruct",      RStruct ("valout", "lvm_pv");
394   "test0rstructlist",  RStructList ("valout", "lvm_pv");
395   "test0rhashtable",   RHashtable "valout";
396 ]
397
398 let test_functions = [
399   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
400    [],
401    "internal test function - do not use",
402    "\
403 This is an internal test function which is used to test whether
404 the automatically generated bindings can handle every possible
405 parameter type correctly.
406
407 It echos the contents of each parameter to stdout.
408
409 You probably don't want to call this function.");
410 ] @ List.flatten (
411   List.map (
412     fun (name, ret) ->
413       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
414         [],
415         "internal test function - do not use",
416         "\
417 This is an internal test function which is used to test whether
418 the automatically generated bindings can handle every possible
419 return type correctly.
420
421 It converts string C<val> to the return type.
422
423 You probably don't want to call this function.");
424        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
425         [],
426         "internal test function - do not use",
427         "\
428 This is an internal test function which is used to test whether
429 the automatically generated bindings can handle every possible
430 return type correctly.
431
432 This function always returns an error.
433
434 You probably don't want to call this function.")]
435   ) test_all_rets
436 )
437
438 (* non_daemon_functions are any functions which don't get processed
439  * in the daemon, eg. functions for setting and getting local
440  * configuration values.
441  *)
442
443 let non_daemon_functions = test_functions @ [
444   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
445    [],
446    "launch the qemu subprocess",
447    "\
448 Internally libguestfs is implemented by running a virtual machine
449 using L<qemu(1)>.
450
451 You should call this after configuring the handle
452 (eg. adding drives) but before performing any actions.");
453
454   ("wait_ready", (RErr, []), -1, [NotInFish],
455    [],
456    "wait until the qemu subprocess launches (no op)",
457    "\
458 This function is a no op.
459
460 In versions of the API E<lt> 1.0.71 you had to call this function
461 just after calling C<guestfs_launch> to wait for the launch
462 to complete.  However this is no longer necessary because
463 C<guestfs_launch> now does the waiting.
464
465 If you see any calls to this function in code then you can just
466 remove them, unless you want to retain compatibility with older
467 versions of the API.");
468
469   ("kill_subprocess", (RErr, []), -1, [],
470    [],
471    "kill the qemu subprocess",
472    "\
473 This kills the qemu subprocess.  You should never need to call this.");
474
475   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
476    [],
477    "add an image to examine or modify",
478    "\
479 This function adds a virtual machine disk image C<filename> to the
480 guest.  The first time you call this function, the disk appears as IDE
481 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
482 so on.
483
484 You don't necessarily need to be root when using libguestfs.  However
485 you obviously do need sufficient permissions to access the filename
486 for whatever operations you want to perform (ie. read access if you
487 just want to read the image or write access if you want to modify the
488 image).
489
490 This is equivalent to the qemu parameter
491 C<-drive file=filename,cache=off,if=...>.
492 C<cache=off> is omitted in cases where it is not supported by
493 the underlying filesystem.
494
495 Note that this call checks for the existence of C<filename>.  This
496 stops you from specifying other types of drive which are supported
497 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
498 the general C<guestfs_config> call instead.");
499
500   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
501    [],
502    "add a CD-ROM disk image to examine",
503    "\
504 This function adds a virtual CD-ROM disk image to the guest.
505
506 This is equivalent to the qemu parameter C<-cdrom filename>.
507
508 Note that this call checks for the existence of C<filename>.  This
509 stops you from specifying other types of drive which are supported
510 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
511 the general C<guestfs_config> call instead.");
512
513   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
514    [],
515    "add a drive in snapshot mode (read-only)",
516    "\
517 This adds a drive in snapshot mode, making it effectively
518 read-only.
519
520 Note that writes to the device are allowed, and will be seen for
521 the duration of the guestfs handle, but they are written
522 to a temporary file which is discarded as soon as the guestfs
523 handle is closed.  We don't currently have any method to enable
524 changes to be committed, although qemu can support this.
525
526 This is equivalent to the qemu parameter
527 C<-drive file=filename,snapshot=on,if=...>.
528
529 Note that this call checks for the existence of C<filename>.  This
530 stops you from specifying other types of drive which are supported
531 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
532 the general C<guestfs_config> call instead.");
533
534   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
535    [],
536    "add qemu parameters",
537    "\
538 This can be used to add arbitrary qemu command line parameters
539 of the form C<-param value>.  Actually it's not quite arbitrary - we
540 prevent you from setting some parameters which would interfere with
541 parameters that we use.
542
543 The first character of C<param> string must be a C<-> (dash).
544
545 C<value> can be NULL.");
546
547   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
548    [],
549    "set the qemu binary",
550    "\
551 Set the qemu binary that we will use.
552
553 The default is chosen when the library was compiled by the
554 configure script.
555
556 You can also override this by setting the C<LIBGUESTFS_QEMU>
557 environment variable.
558
559 Setting C<qemu> to C<NULL> restores the default qemu binary.");
560
561   ("get_qemu", (RConstString "qemu", []), -1, [],
562    [InitNone, Always, TestRun (
563       [["get_qemu"]])],
564    "get the qemu binary",
565    "\
566 Return the current qemu binary.
567
568 This is always non-NULL.  If it wasn't set already, then this will
569 return the default qemu binary name.");
570
571   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
572    [],
573    "set the search path",
574    "\
575 Set the path that libguestfs searches for kernel and initrd.img.
576
577 The default is C<$libdir/guestfs> unless overridden by setting
578 C<LIBGUESTFS_PATH> environment variable.
579
580 Setting C<path> to C<NULL> restores the default path.");
581
582   ("get_path", (RConstString "path", []), -1, [],
583    [InitNone, Always, TestRun (
584       [["get_path"]])],
585    "get the search path",
586    "\
587 Return the current search path.
588
589 This is always non-NULL.  If it wasn't set already, then this will
590 return the default path.");
591
592   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
593    [],
594    "add options to kernel command line",
595    "\
596 This function is used to add additional options to the
597 guest kernel command line.
598
599 The default is C<NULL> unless overridden by setting
600 C<LIBGUESTFS_APPEND> environment variable.
601
602 Setting C<append> to C<NULL> means I<no> additional options
603 are passed (libguestfs always adds a few of its own).");
604
605   ("get_append", (RConstOptString "append", []), -1, [],
606    (* This cannot be tested with the current framework.  The
607     * function can return NULL in normal operations, which the
608     * test framework interprets as an error.
609     *)
610    [],
611    "get the additional kernel options",
612    "\
613 Return the additional kernel options which are added to the
614 guest kernel command line.
615
616 If C<NULL> then no options are added.");
617
618   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
619    [],
620    "set autosync mode",
621    "\
622 If C<autosync> is true, this enables autosync.  Libguestfs will make a
623 best effort attempt to run C<guestfs_umount_all> followed by
624 C<guestfs_sync> when the handle is closed
625 (also if the program exits without closing handles).
626
627 This is disabled by default (except in guestfish where it is
628 enabled by default).");
629
630   ("get_autosync", (RBool "autosync", []), -1, [],
631    [InitNone, Always, TestRun (
632       [["get_autosync"]])],
633    "get autosync mode",
634    "\
635 Get the autosync flag.");
636
637   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
638    [],
639    "set verbose mode",
640    "\
641 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
642
643 Verbose messages are disabled unless the environment variable
644 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
645
646   ("get_verbose", (RBool "verbose", []), -1, [],
647    [],
648    "get verbose mode",
649    "\
650 This returns the verbose messages flag.");
651
652   ("is_ready", (RBool "ready", []), -1, [],
653    [InitNone, Always, TestOutputTrue (
654       [["is_ready"]])],
655    "is ready to accept commands",
656    "\
657 This returns true iff this handle is ready to accept commands
658 (in the C<READY> state).
659
660 For more information on states, see L<guestfs(3)>.");
661
662   ("is_config", (RBool "config", []), -1, [],
663    [InitNone, Always, TestOutputFalse (
664       [["is_config"]])],
665    "is in configuration state",
666    "\
667 This returns true iff this handle is being configured
668 (in the C<CONFIG> state).
669
670 For more information on states, see L<guestfs(3)>.");
671
672   ("is_launching", (RBool "launching", []), -1, [],
673    [InitNone, Always, TestOutputFalse (
674       [["is_launching"]])],
675    "is launching subprocess",
676    "\
677 This returns true iff this handle is launching the subprocess
678 (in the C<LAUNCHING> state).
679
680 For more information on states, see L<guestfs(3)>.");
681
682   ("is_busy", (RBool "busy", []), -1, [],
683    [InitNone, Always, TestOutputFalse (
684       [["is_busy"]])],
685    "is busy processing a command",
686    "\
687 This returns true iff this handle is busy processing a command
688 (in the C<BUSY> state).
689
690 For more information on states, see L<guestfs(3)>.");
691
692   ("get_state", (RInt "state", []), -1, [],
693    [],
694    "get the current state",
695    "\
696 This returns the current state as an opaque integer.  This is
697 only useful for printing debug and internal error messages.
698
699 For more information on states, see L<guestfs(3)>.");
700
701   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
702    [InitNone, Always, TestOutputInt (
703       [["set_memsize"; "500"];
704        ["get_memsize"]], 500)],
705    "set memory allocated to the qemu subprocess",
706    "\
707 This sets the memory size in megabytes allocated to the
708 qemu subprocess.  This only has any effect if called before
709 C<guestfs_launch>.
710
711 You can also change this by setting the environment
712 variable C<LIBGUESTFS_MEMSIZE> before the handle is
713 created.
714
715 For more information on the architecture of libguestfs,
716 see L<guestfs(3)>.");
717
718   ("get_memsize", (RInt "memsize", []), -1, [],
719    [InitNone, Always, TestOutputIntOp (
720       [["get_memsize"]], ">=", 256)],
721    "get memory allocated to the qemu subprocess",
722    "\
723 This gets the memory size in megabytes allocated to the
724 qemu subprocess.
725
726 If C<guestfs_set_memsize> was not called
727 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
728 then this returns the compiled-in default value for memsize.
729
730 For more information on the architecture of libguestfs,
731 see L<guestfs(3)>.");
732
733   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
734    [InitNone, Always, TestOutputIntOp (
735       [["get_pid"]], ">=", 1)],
736    "get PID of qemu subprocess",
737    "\
738 Return the process ID of the qemu subprocess.  If there is no
739 qemu subprocess, then this will return an error.
740
741 This is an internal call used for debugging and testing.");
742
743   ("version", (RStruct ("version", "version"), []), -1, [],
744    [InitNone, Always, TestOutputStruct (
745       [["version"]], [CompareWithInt ("major", 1)])],
746    "get the library version number",
747    "\
748 Return the libguestfs version number that the program is linked
749 against.
750
751 Note that because of dynamic linking this is not necessarily
752 the version of libguestfs that you compiled against.  You can
753 compile the program, and then at runtime dynamically link
754 against a completely different C<libguestfs.so> library.
755
756 This call was added in version C<1.0.58>.  In previous
757 versions of libguestfs there was no way to get the version
758 number.  From C code you can use ELF weak linking tricks to find out if
759 this symbol exists (if it doesn't, then it's an earlier version).
760
761 The call returns a structure with four elements.  The first
762 three (C<major>, C<minor> and C<release>) are numbers and
763 correspond to the usual version triplet.  The fourth element
764 (C<extra>) is a string and is normally empty, but may be
765 used for distro-specific information.
766
767 To construct the original version string:
768 C<$major.$minor.$release$extra>
769
770 I<Note:> Don't use this call to test for availability
771 of features.  Distro backports makes this unreliable.  Use
772 C<guestfs_available> instead.");
773
774   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
775    [InitNone, Always, TestOutputTrue (
776       [["set_selinux"; "true"];
777        ["get_selinux"]])],
778    "set SELinux enabled or disabled at appliance boot",
779    "\
780 This sets the selinux flag that is passed to the appliance
781 at boot time.  The default is C<selinux=0> (disabled).
782
783 Note that if SELinux is enabled, it is always in
784 Permissive mode (C<enforcing=0>).
785
786 For more information on the architecture of libguestfs,
787 see L<guestfs(3)>.");
788
789   ("get_selinux", (RBool "selinux", []), -1, [],
790    [],
791    "get SELinux enabled flag",
792    "\
793 This returns the current setting of the selinux flag which
794 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
795
796 For more information on the architecture of libguestfs,
797 see L<guestfs(3)>.");
798
799   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
800    [InitNone, Always, TestOutputFalse (
801       [["set_trace"; "false"];
802        ["get_trace"]])],
803    "enable or disable command traces",
804    "\
805 If the command trace flag is set to 1, then commands are
806 printed on stdout before they are executed in a format
807 which is very similar to the one used by guestfish.  In
808 other words, you can run a program with this enabled, and
809 you will get out a script which you can feed to guestfish
810 to perform the same set of actions.
811
812 If you want to trace C API calls into libguestfs (and
813 other libraries) then possibly a better way is to use
814 the external ltrace(1) command.
815
816 Command traces are disabled unless the environment variable
817 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
818
819   ("get_trace", (RBool "trace", []), -1, [],
820    [],
821    "get command trace enabled flag",
822    "\
823 Return the command trace flag.");
824
825   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
826    [InitNone, Always, TestOutputFalse (
827       [["set_direct"; "false"];
828        ["get_direct"]])],
829    "enable or disable direct appliance mode",
830    "\
831 If the direct appliance mode flag is enabled, then stdin and
832 stdout are passed directly through to the appliance once it
833 is launched.
834
835 One consequence of this is that log messages aren't caught
836 by the library and handled by C<guestfs_set_log_message_callback>,
837 but go straight to stdout.
838
839 You probably don't want to use this unless you know what you
840 are doing.
841
842 The default is disabled.");
843
844   ("get_direct", (RBool "direct", []), -1, [],
845    [],
846    "get direct appliance mode flag",
847    "\
848 Return the direct appliance mode flag.");
849
850   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
851    [InitNone, Always, TestOutputTrue (
852       [["set_recovery_proc"; "true"];
853        ["get_recovery_proc"]])],
854    "enable or disable the recovery process",
855    "\
856 If this is called with the parameter C<false> then
857 C<guestfs_launch> does not create a recovery process.  The
858 purpose of the recovery process is to stop runaway qemu
859 processes in the case where the main program aborts abruptly.
860
861 This only has any effect if called before C<guestfs_launch>,
862 and the default is true.
863
864 About the only time when you would want to disable this is
865 if the main process will fork itself into the background
866 (\"daemonize\" itself).  In this case the recovery process
867 thinks that the main program has disappeared and so kills
868 qemu, which is not very helpful.");
869
870   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
871    [],
872    "get recovery process enabled flag",
873    "\
874 Return the recovery process enabled flag.");
875
876 ]
877
878 (* daemon_functions are any functions which cause some action
879  * to take place in the daemon.
880  *)
881
882 let daemon_functions = [
883   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
884    [InitEmpty, Always, TestOutput (
885       [["part_disk"; "/dev/sda"; "mbr"];
886        ["mkfs"; "ext2"; "/dev/sda1"];
887        ["mount"; "/dev/sda1"; "/"];
888        ["write_file"; "/new"; "new file contents"; "0"];
889        ["cat"; "/new"]], "new file contents")],
890    "mount a guest disk at a position in the filesystem",
891    "\
892 Mount a guest disk at a position in the filesystem.  Block devices
893 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
894 the guest.  If those block devices contain partitions, they will have
895 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
896 names can be used.
897
898 The rules are the same as for L<mount(2)>:  A filesystem must
899 first be mounted on C</> before others can be mounted.  Other
900 filesystems can only be mounted on directories which already
901 exist.
902
903 The mounted filesystem is writable, if we have sufficient permissions
904 on the underlying device.
905
906 The filesystem options C<sync> and C<noatime> are set with this
907 call, in order to improve reliability.");
908
909   ("sync", (RErr, []), 2, [],
910    [ InitEmpty, Always, TestRun [["sync"]]],
911    "sync disks, writes are flushed through to the disk image",
912    "\
913 This syncs the disk, so that any writes are flushed through to the
914 underlying disk image.
915
916 You should always call this if you have modified a disk image, before
917 closing the handle.");
918
919   ("touch", (RErr, [Pathname "path"]), 3, [],
920    [InitBasicFS, Always, TestOutputTrue (
921       [["touch"; "/new"];
922        ["exists"; "/new"]])],
923    "update file timestamps or create a new file",
924    "\
925 Touch acts like the L<touch(1)> command.  It can be used to
926 update the timestamps on a file, or, if the file does not exist,
927 to create a new zero-length file.");
928
929   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
930    [InitISOFS, Always, TestOutput (
931       [["cat"; "/known-2"]], "abcdef\n")],
932    "list the contents of a file",
933    "\
934 Return the contents of the file named C<path>.
935
936 Note that this function cannot correctly handle binary files
937 (specifically, files containing C<\\0> character which is treated
938 as end of string).  For those you need to use the C<guestfs_read_file>
939 or C<guestfs_download> functions which have a more complex interface.");
940
941   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
942    [], (* XXX Tricky to test because it depends on the exact format
943         * of the 'ls -l' command, which changes between F10 and F11.
944         *)
945    "list the files in a directory (long format)",
946    "\
947 List the files in C<directory> (relative to the root directory,
948 there is no cwd) in the format of 'ls -la'.
949
950 This command is mostly useful for interactive sessions.  It
951 is I<not> intended that you try to parse the output string.");
952
953   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
954    [InitBasicFS, Always, TestOutputList (
955       [["touch"; "/new"];
956        ["touch"; "/newer"];
957        ["touch"; "/newest"];
958        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
959    "list the files in a directory",
960    "\
961 List the files in C<directory> (relative to the root directory,
962 there is no cwd).  The '.' and '..' entries are not returned, but
963 hidden files are shown.
964
965 This command is mostly useful for interactive sessions.  Programs
966 should probably use C<guestfs_readdir> instead.");
967
968   ("list_devices", (RStringList "devices", []), 7, [],
969    [InitEmpty, Always, TestOutputListOfDevices (
970       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
971    "list the block devices",
972    "\
973 List all the block devices.
974
975 The full block device names are returned, eg. C</dev/sda>");
976
977   ("list_partitions", (RStringList "partitions", []), 8, [],
978    [InitBasicFS, Always, TestOutputListOfDevices (
979       [["list_partitions"]], ["/dev/sda1"]);
980     InitEmpty, Always, TestOutputListOfDevices (
981       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
982        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
983    "list the partitions",
984    "\
985 List all the partitions detected on all block devices.
986
987 The full partition device names are returned, eg. C</dev/sda1>
988
989 This does not return logical volumes.  For that you will need to
990 call C<guestfs_lvs>.");
991
992   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
993    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
994       [["pvs"]], ["/dev/sda1"]);
995     InitEmpty, Always, TestOutputListOfDevices (
996       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
997        ["pvcreate"; "/dev/sda1"];
998        ["pvcreate"; "/dev/sda2"];
999        ["pvcreate"; "/dev/sda3"];
1000        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1001    "list the LVM physical volumes (PVs)",
1002    "\
1003 List all the physical volumes detected.  This is the equivalent
1004 of the L<pvs(8)> command.
1005
1006 This returns a list of just the device names that contain
1007 PVs (eg. C</dev/sda2>).
1008
1009 See also C<guestfs_pvs_full>.");
1010
1011   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1012    [InitBasicFSonLVM, Always, TestOutputList (
1013       [["vgs"]], ["VG"]);
1014     InitEmpty, Always, TestOutputList (
1015       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1016        ["pvcreate"; "/dev/sda1"];
1017        ["pvcreate"; "/dev/sda2"];
1018        ["pvcreate"; "/dev/sda3"];
1019        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1020        ["vgcreate"; "VG2"; "/dev/sda3"];
1021        ["vgs"]], ["VG1"; "VG2"])],
1022    "list the LVM volume groups (VGs)",
1023    "\
1024 List all the volumes groups detected.  This is the equivalent
1025 of the L<vgs(8)> command.
1026
1027 This returns a list of just the volume group names that were
1028 detected (eg. C<VolGroup00>).
1029
1030 See also C<guestfs_vgs_full>.");
1031
1032   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1033    [InitBasicFSonLVM, Always, TestOutputList (
1034       [["lvs"]], ["/dev/VG/LV"]);
1035     InitEmpty, Always, TestOutputList (
1036       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1037        ["pvcreate"; "/dev/sda1"];
1038        ["pvcreate"; "/dev/sda2"];
1039        ["pvcreate"; "/dev/sda3"];
1040        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1041        ["vgcreate"; "VG2"; "/dev/sda3"];
1042        ["lvcreate"; "LV1"; "VG1"; "50"];
1043        ["lvcreate"; "LV2"; "VG1"; "50"];
1044        ["lvcreate"; "LV3"; "VG2"; "50"];
1045        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1046    "list the LVM logical volumes (LVs)",
1047    "\
1048 List all the logical volumes detected.  This is the equivalent
1049 of the L<lvs(8)> command.
1050
1051 This returns a list of the logical volume device names
1052 (eg. C</dev/VolGroup00/LogVol00>).
1053
1054 See also C<guestfs_lvs_full>.");
1055
1056   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1057    [], (* XXX how to test? *)
1058    "list the LVM physical volumes (PVs)",
1059    "\
1060 List all the physical volumes detected.  This is the equivalent
1061 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1062
1063   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1064    [], (* XXX how to test? *)
1065    "list the LVM volume groups (VGs)",
1066    "\
1067 List all the volumes groups detected.  This is the equivalent
1068 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1069
1070   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1071    [], (* XXX how to test? *)
1072    "list the LVM logical volumes (LVs)",
1073    "\
1074 List all the logical volumes detected.  This is the equivalent
1075 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1076
1077   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1078    [InitISOFS, Always, TestOutputList (
1079       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1080     InitISOFS, Always, TestOutputList (
1081       [["read_lines"; "/empty"]], [])],
1082    "read file as lines",
1083    "\
1084 Return the contents of the file named C<path>.
1085
1086 The file contents are returned as a list of lines.  Trailing
1087 C<LF> and C<CRLF> character sequences are I<not> returned.
1088
1089 Note that this function cannot correctly handle binary files
1090 (specifically, files containing C<\\0> character which is treated
1091 as end of line).  For those you need to use the C<guestfs_read_file>
1092 function which has a more complex interface.");
1093
1094   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1095    [], (* XXX Augeas code needs tests. *)
1096    "create a new Augeas handle",
1097    "\
1098 Create a new Augeas handle for editing configuration files.
1099 If there was any previous Augeas handle associated with this
1100 guestfs session, then it is closed.
1101
1102 You must call this before using any other C<guestfs_aug_*>
1103 commands.
1104
1105 C<root> is the filesystem root.  C<root> must not be NULL,
1106 use C</> instead.
1107
1108 The flags are the same as the flags defined in
1109 E<lt>augeas.hE<gt>, the logical I<or> of the following
1110 integers:
1111
1112 =over 4
1113
1114 =item C<AUG_SAVE_BACKUP> = 1
1115
1116 Keep the original file with a C<.augsave> extension.
1117
1118 =item C<AUG_SAVE_NEWFILE> = 2
1119
1120 Save changes into a file with extension C<.augnew>, and
1121 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1122
1123 =item C<AUG_TYPE_CHECK> = 4
1124
1125 Typecheck lenses (can be expensive).
1126
1127 =item C<AUG_NO_STDINC> = 8
1128
1129 Do not use standard load path for modules.
1130
1131 =item C<AUG_SAVE_NOOP> = 16
1132
1133 Make save a no-op, just record what would have been changed.
1134
1135 =item C<AUG_NO_LOAD> = 32
1136
1137 Do not load the tree in C<guestfs_aug_init>.
1138
1139 =back
1140
1141 To close the handle, you can call C<guestfs_aug_close>.
1142
1143 To find out more about Augeas, see L<http://augeas.net/>.");
1144
1145   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1146    [], (* XXX Augeas code needs tests. *)
1147    "close the current Augeas handle",
1148    "\
1149 Close the current Augeas handle and free up any resources
1150 used by it.  After calling this, you have to call
1151 C<guestfs_aug_init> again before you can use any other
1152 Augeas functions.");
1153
1154   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1155    [], (* XXX Augeas code needs tests. *)
1156    "define an Augeas variable",
1157    "\
1158 Defines an Augeas variable C<name> whose value is the result
1159 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1160 undefined.
1161
1162 On success this returns the number of nodes in C<expr>, or
1163 C<0> if C<expr> evaluates to something which is not a nodeset.");
1164
1165   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1166    [], (* XXX Augeas code needs tests. *)
1167    "define an Augeas node",
1168    "\
1169 Defines a variable C<name> whose value is the result of
1170 evaluating C<expr>.
1171
1172 If C<expr> evaluates to an empty nodeset, a node is created,
1173 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1174 C<name> will be the nodeset containing that single node.
1175
1176 On success this returns a pair containing the
1177 number of nodes in the nodeset, and a boolean flag
1178 if a node was created.");
1179
1180   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1181    [], (* XXX Augeas code needs tests. *)
1182    "look up the value of an Augeas path",
1183    "\
1184 Look up the value associated with C<path>.  If C<path>
1185 matches exactly one node, the C<value> is returned.");
1186
1187   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1188    [], (* XXX Augeas code needs tests. *)
1189    "set Augeas path to value",
1190    "\
1191 Set the value associated with C<path> to C<value>.");
1192
1193   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1194    [], (* XXX Augeas code needs tests. *)
1195    "insert a sibling Augeas node",
1196    "\
1197 Create a new sibling C<label> for C<path>, inserting it into
1198 the tree before or after C<path> (depending on the boolean
1199 flag C<before>).
1200
1201 C<path> must match exactly one existing node in the tree, and
1202 C<label> must be a label, ie. not contain C</>, C<*> or end
1203 with a bracketed index C<[N]>.");
1204
1205   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1206    [], (* XXX Augeas code needs tests. *)
1207    "remove an Augeas path",
1208    "\
1209 Remove C<path> and all of its children.
1210
1211 On success this returns the number of entries which were removed.");
1212
1213   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1214    [], (* XXX Augeas code needs tests. *)
1215    "move Augeas node",
1216    "\
1217 Move the node C<src> to C<dest>.  C<src> must match exactly
1218 one node.  C<dest> is overwritten if it exists.");
1219
1220   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1221    [], (* XXX Augeas code needs tests. *)
1222    "return Augeas nodes which match augpath",
1223    "\
1224 Returns a list of paths which match the path expression C<path>.
1225 The returned paths are sufficiently qualified so that they match
1226 exactly one node in the current tree.");
1227
1228   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1229    [], (* XXX Augeas code needs tests. *)
1230    "write all pending Augeas changes to disk",
1231    "\
1232 This writes all pending changes to disk.
1233
1234 The flags which were passed to C<guestfs_aug_init> affect exactly
1235 how files are saved.");
1236
1237   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1238    [], (* XXX Augeas code needs tests. *)
1239    "load files into the tree",
1240    "\
1241 Load files into the tree.
1242
1243 See C<aug_load> in the Augeas documentation for the full gory
1244 details.");
1245
1246   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1247    [], (* XXX Augeas code needs tests. *)
1248    "list Augeas nodes under augpath",
1249    "\
1250 This is just a shortcut for listing C<guestfs_aug_match>
1251 C<path/*> and sorting the resulting nodes into alphabetical order.");
1252
1253   ("rm", (RErr, [Pathname "path"]), 29, [],
1254    [InitBasicFS, Always, TestRun
1255       [["touch"; "/new"];
1256        ["rm"; "/new"]];
1257     InitBasicFS, Always, TestLastFail
1258       [["rm"; "/new"]];
1259     InitBasicFS, Always, TestLastFail
1260       [["mkdir"; "/new"];
1261        ["rm"; "/new"]]],
1262    "remove a file",
1263    "\
1264 Remove the single file C<path>.");
1265
1266   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1267    [InitBasicFS, Always, TestRun
1268       [["mkdir"; "/new"];
1269        ["rmdir"; "/new"]];
1270     InitBasicFS, Always, TestLastFail
1271       [["rmdir"; "/new"]];
1272     InitBasicFS, Always, TestLastFail
1273       [["touch"; "/new"];
1274        ["rmdir"; "/new"]]],
1275    "remove a directory",
1276    "\
1277 Remove the single directory C<path>.");
1278
1279   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1280    [InitBasicFS, Always, TestOutputFalse
1281       [["mkdir"; "/new"];
1282        ["mkdir"; "/new/foo"];
1283        ["touch"; "/new/foo/bar"];
1284        ["rm_rf"; "/new"];
1285        ["exists"; "/new"]]],
1286    "remove a file or directory recursively",
1287    "\
1288 Remove the file or directory C<path>, recursively removing the
1289 contents if its a directory.  This is like the C<rm -rf> shell
1290 command.");
1291
1292   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1293    [InitBasicFS, Always, TestOutputTrue
1294       [["mkdir"; "/new"];
1295        ["is_dir"; "/new"]];
1296     InitBasicFS, Always, TestLastFail
1297       [["mkdir"; "/new/foo/bar"]]],
1298    "create a directory",
1299    "\
1300 Create a directory named C<path>.");
1301
1302   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1303    [InitBasicFS, Always, TestOutputTrue
1304       [["mkdir_p"; "/new/foo/bar"];
1305        ["is_dir"; "/new/foo/bar"]];
1306     InitBasicFS, Always, TestOutputTrue
1307       [["mkdir_p"; "/new/foo/bar"];
1308        ["is_dir"; "/new/foo"]];
1309     InitBasicFS, Always, TestOutputTrue
1310       [["mkdir_p"; "/new/foo/bar"];
1311        ["is_dir"; "/new"]];
1312     (* Regression tests for RHBZ#503133: *)
1313     InitBasicFS, Always, TestRun
1314       [["mkdir"; "/new"];
1315        ["mkdir_p"; "/new"]];
1316     InitBasicFS, Always, TestLastFail
1317       [["touch"; "/new"];
1318        ["mkdir_p"; "/new"]]],
1319    "create a directory and parents",
1320    "\
1321 Create a directory named C<path>, creating any parent directories
1322 as necessary.  This is like the C<mkdir -p> shell command.");
1323
1324   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1325    [], (* XXX Need stat command to test *)
1326    "change file mode",
1327    "\
1328 Change the mode (permissions) of C<path> to C<mode>.  Only
1329 numeric modes are supported.");
1330
1331   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1332    [], (* XXX Need stat command to test *)
1333    "change file owner and group",
1334    "\
1335 Change the file owner to C<owner> and group to C<group>.
1336
1337 Only numeric uid and gid are supported.  If you want to use
1338 names, you will need to locate and parse the password file
1339 yourself (Augeas support makes this relatively easy).");
1340
1341   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1342    [InitISOFS, Always, TestOutputTrue (
1343       [["exists"; "/empty"]]);
1344     InitISOFS, Always, TestOutputTrue (
1345       [["exists"; "/directory"]])],
1346    "test if file or directory exists",
1347    "\
1348 This returns C<true> if and only if there is a file, directory
1349 (or anything) with the given C<path> name.
1350
1351 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1352
1353   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1354    [InitISOFS, Always, TestOutputTrue (
1355       [["is_file"; "/known-1"]]);
1356     InitISOFS, Always, TestOutputFalse (
1357       [["is_file"; "/directory"]])],
1358    "test if file exists",
1359    "\
1360 This returns C<true> if and only if there is a file
1361 with the given C<path> name.  Note that it returns false for
1362 other objects like directories.
1363
1364 See also C<guestfs_stat>.");
1365
1366   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1367    [InitISOFS, Always, TestOutputFalse (
1368       [["is_dir"; "/known-3"]]);
1369     InitISOFS, Always, TestOutputTrue (
1370       [["is_dir"; "/directory"]])],
1371    "test if file exists",
1372    "\
1373 This returns C<true> if and only if there is a directory
1374 with the given C<path> name.  Note that it returns false for
1375 other objects like files.
1376
1377 See also C<guestfs_stat>.");
1378
1379   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1380    [InitEmpty, Always, TestOutputListOfDevices (
1381       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1382        ["pvcreate"; "/dev/sda1"];
1383        ["pvcreate"; "/dev/sda2"];
1384        ["pvcreate"; "/dev/sda3"];
1385        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1386    "create an LVM physical volume",
1387    "\
1388 This creates an LVM physical volume on the named C<device>,
1389 where C<device> should usually be a partition name such
1390 as C</dev/sda1>.");
1391
1392   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1393    [InitEmpty, Always, TestOutputList (
1394       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1395        ["pvcreate"; "/dev/sda1"];
1396        ["pvcreate"; "/dev/sda2"];
1397        ["pvcreate"; "/dev/sda3"];
1398        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1399        ["vgcreate"; "VG2"; "/dev/sda3"];
1400        ["vgs"]], ["VG1"; "VG2"])],
1401    "create an LVM volume group",
1402    "\
1403 This creates an LVM volume group called C<volgroup>
1404 from the non-empty list of physical volumes C<physvols>.");
1405
1406   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1407    [InitEmpty, Always, TestOutputList (
1408       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1409        ["pvcreate"; "/dev/sda1"];
1410        ["pvcreate"; "/dev/sda2"];
1411        ["pvcreate"; "/dev/sda3"];
1412        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1413        ["vgcreate"; "VG2"; "/dev/sda3"];
1414        ["lvcreate"; "LV1"; "VG1"; "50"];
1415        ["lvcreate"; "LV2"; "VG1"; "50"];
1416        ["lvcreate"; "LV3"; "VG2"; "50"];
1417        ["lvcreate"; "LV4"; "VG2"; "50"];
1418        ["lvcreate"; "LV5"; "VG2"; "50"];
1419        ["lvs"]],
1420       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1421        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1422    "create an LVM volume group",
1423    "\
1424 This creates an LVM volume group called C<logvol>
1425 on the volume group C<volgroup>, with C<size> megabytes.");
1426
1427   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1428    [InitEmpty, Always, TestOutput (
1429       [["part_disk"; "/dev/sda"; "mbr"];
1430        ["mkfs"; "ext2"; "/dev/sda1"];
1431        ["mount"; "/dev/sda1"; "/"];
1432        ["write_file"; "/new"; "new file contents"; "0"];
1433        ["cat"; "/new"]], "new file contents")],
1434    "make a filesystem",
1435    "\
1436 This creates a filesystem on C<device> (usually a partition
1437 or LVM logical volume).  The filesystem type is C<fstype>, for
1438 example C<ext3>.");
1439
1440   ("sfdisk", (RErr, [Device "device";
1441                      Int "cyls"; Int "heads"; Int "sectors";
1442                      StringList "lines"]), 43, [DangerWillRobinson],
1443    [],
1444    "create partitions on a block device",
1445    "\
1446 This is a direct interface to the L<sfdisk(8)> program for creating
1447 partitions on block devices.
1448
1449 C<device> should be a block device, for example C</dev/sda>.
1450
1451 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1452 and sectors on the device, which are passed directly to sfdisk as
1453 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1454 of these, then the corresponding parameter is omitted.  Usually for
1455 'large' disks, you can just pass C<0> for these, but for small
1456 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1457 out the right geometry and you will need to tell it.
1458
1459 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1460 information refer to the L<sfdisk(8)> manpage.
1461
1462 To create a single partition occupying the whole disk, you would
1463 pass C<lines> as a single element list, when the single element being
1464 the string C<,> (comma).
1465
1466 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1467 C<guestfs_part_init>");
1468
1469   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1470    [InitBasicFS, Always, TestOutput (
1471       [["write_file"; "/new"; "new file contents"; "0"];
1472        ["cat"; "/new"]], "new file contents");
1473     InitBasicFS, Always, TestOutput (
1474       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1475        ["cat"; "/new"]], "\nnew file contents\n");
1476     InitBasicFS, Always, TestOutput (
1477       [["write_file"; "/new"; "\n\n"; "0"];
1478        ["cat"; "/new"]], "\n\n");
1479     InitBasicFS, Always, TestOutput (
1480       [["write_file"; "/new"; ""; "0"];
1481        ["cat"; "/new"]], "");
1482     InitBasicFS, Always, TestOutput (
1483       [["write_file"; "/new"; "\n\n\n"; "0"];
1484        ["cat"; "/new"]], "\n\n\n");
1485     InitBasicFS, Always, TestOutput (
1486       [["write_file"; "/new"; "\n"; "0"];
1487        ["cat"; "/new"]], "\n")],
1488    "create a file",
1489    "\
1490 This call creates a file called C<path>.  The contents of the
1491 file is the string C<content> (which can contain any 8 bit data),
1492 with length C<size>.
1493
1494 As a special case, if C<size> is C<0>
1495 then the length is calculated using C<strlen> (so in this case
1496 the content cannot contain embedded ASCII NULs).
1497
1498 I<NB.> Owing to a bug, writing content containing ASCII NUL
1499 characters does I<not> work, even if the length is specified.
1500 We hope to resolve this bug in a future version.  In the meantime
1501 use C<guestfs_upload>.");
1502
1503   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1504    [InitEmpty, Always, TestOutputListOfDevices (
1505       [["part_disk"; "/dev/sda"; "mbr"];
1506        ["mkfs"; "ext2"; "/dev/sda1"];
1507        ["mount"; "/dev/sda1"; "/"];
1508        ["mounts"]], ["/dev/sda1"]);
1509     InitEmpty, Always, TestOutputList (
1510       [["part_disk"; "/dev/sda"; "mbr"];
1511        ["mkfs"; "ext2"; "/dev/sda1"];
1512        ["mount"; "/dev/sda1"; "/"];
1513        ["umount"; "/"];
1514        ["mounts"]], [])],
1515    "unmount a filesystem",
1516    "\
1517 This unmounts the given filesystem.  The filesystem may be
1518 specified either by its mountpoint (path) or the device which
1519 contains the filesystem.");
1520
1521   ("mounts", (RStringList "devices", []), 46, [],
1522    [InitBasicFS, Always, TestOutputListOfDevices (
1523       [["mounts"]], ["/dev/sda1"])],
1524    "show mounted filesystems",
1525    "\
1526 This returns the list of currently mounted filesystems.  It returns
1527 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1528
1529 Some internal mounts are not shown.
1530
1531 See also: C<guestfs_mountpoints>");
1532
1533   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1534    [InitBasicFS, Always, TestOutputList (
1535       [["umount_all"];
1536        ["mounts"]], []);
1537     (* check that umount_all can unmount nested mounts correctly: *)
1538     InitEmpty, Always, TestOutputList (
1539       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1540        ["mkfs"; "ext2"; "/dev/sda1"];
1541        ["mkfs"; "ext2"; "/dev/sda2"];
1542        ["mkfs"; "ext2"; "/dev/sda3"];
1543        ["mount"; "/dev/sda1"; "/"];
1544        ["mkdir"; "/mp1"];
1545        ["mount"; "/dev/sda2"; "/mp1"];
1546        ["mkdir"; "/mp1/mp2"];
1547        ["mount"; "/dev/sda3"; "/mp1/mp2"];
1548        ["mkdir"; "/mp1/mp2/mp3"];
1549        ["umount_all"];
1550        ["mounts"]], [])],
1551    "unmount all filesystems",
1552    "\
1553 This unmounts all mounted filesystems.
1554
1555 Some internal mounts are not unmounted by this call.");
1556
1557   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1558    [],
1559    "remove all LVM LVs, VGs and PVs",
1560    "\
1561 This command removes all LVM logical volumes, volume groups
1562 and physical volumes.");
1563
1564   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1565    [InitISOFS, Always, TestOutput (
1566       [["file"; "/empty"]], "empty");
1567     InitISOFS, Always, TestOutput (
1568       [["file"; "/known-1"]], "ASCII text");
1569     InitISOFS, Always, TestLastFail (
1570       [["file"; "/notexists"]])],
1571    "determine file type",
1572    "\
1573 This call uses the standard L<file(1)> command to determine
1574 the type or contents of the file.  This also works on devices,
1575 for example to find out whether a partition contains a filesystem.
1576
1577 This call will also transparently look inside various types
1578 of compressed file.
1579
1580 The exact command which runs is C<file -zbsL path>.  Note in
1581 particular that the filename is not prepended to the output
1582 (the C<-b> option).");
1583
1584   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1585    [InitBasicFS, Always, TestOutput (
1586       [["upload"; "test-command"; "/test-command"];
1587        ["chmod"; "0o755"; "/test-command"];
1588        ["command"; "/test-command 1"]], "Result1");
1589     InitBasicFS, Always, TestOutput (
1590       [["upload"; "test-command"; "/test-command"];
1591        ["chmod"; "0o755"; "/test-command"];
1592        ["command"; "/test-command 2"]], "Result2\n");
1593     InitBasicFS, Always, TestOutput (
1594       [["upload"; "test-command"; "/test-command"];
1595        ["chmod"; "0o755"; "/test-command"];
1596        ["command"; "/test-command 3"]], "\nResult3");
1597     InitBasicFS, Always, TestOutput (
1598       [["upload"; "test-command"; "/test-command"];
1599        ["chmod"; "0o755"; "/test-command"];
1600        ["command"; "/test-command 4"]], "\nResult4\n");
1601     InitBasicFS, Always, TestOutput (
1602       [["upload"; "test-command"; "/test-command"];
1603        ["chmod"; "0o755"; "/test-command"];
1604        ["command"; "/test-command 5"]], "\nResult5\n\n");
1605     InitBasicFS, Always, TestOutput (
1606       [["upload"; "test-command"; "/test-command"];
1607        ["chmod"; "0o755"; "/test-command"];
1608        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1609     InitBasicFS, Always, TestOutput (
1610       [["upload"; "test-command"; "/test-command"];
1611        ["chmod"; "0o755"; "/test-command"];
1612        ["command"; "/test-command 7"]], "");
1613     InitBasicFS, Always, TestOutput (
1614       [["upload"; "test-command"; "/test-command"];
1615        ["chmod"; "0o755"; "/test-command"];
1616        ["command"; "/test-command 8"]], "\n");
1617     InitBasicFS, Always, TestOutput (
1618       [["upload"; "test-command"; "/test-command"];
1619        ["chmod"; "0o755"; "/test-command"];
1620        ["command"; "/test-command 9"]], "\n\n");
1621     InitBasicFS, Always, TestOutput (
1622       [["upload"; "test-command"; "/test-command"];
1623        ["chmod"; "0o755"; "/test-command"];
1624        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1625     InitBasicFS, Always, TestOutput (
1626       [["upload"; "test-command"; "/test-command"];
1627        ["chmod"; "0o755"; "/test-command"];
1628        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1629     InitBasicFS, Always, TestLastFail (
1630       [["upload"; "test-command"; "/test-command"];
1631        ["chmod"; "0o755"; "/test-command"];
1632        ["command"; "/test-command"]])],
1633    "run a command from the guest filesystem",
1634    "\
1635 This call runs a command from the guest filesystem.  The
1636 filesystem must be mounted, and must contain a compatible
1637 operating system (ie. something Linux, with the same
1638 or compatible processor architecture).
1639
1640 The single parameter is an argv-style list of arguments.
1641 The first element is the name of the program to run.
1642 Subsequent elements are parameters.  The list must be
1643 non-empty (ie. must contain a program name).  Note that
1644 the command runs directly, and is I<not> invoked via
1645 the shell (see C<guestfs_sh>).
1646
1647 The return value is anything printed to I<stdout> by
1648 the command.
1649
1650 If the command returns a non-zero exit status, then
1651 this function returns an error message.  The error message
1652 string is the content of I<stderr> from the command.
1653
1654 The C<$PATH> environment variable will contain at least
1655 C</usr/bin> and C</bin>.  If you require a program from
1656 another location, you should provide the full path in the
1657 first parameter.
1658
1659 Shared libraries and data files required by the program
1660 must be available on filesystems which are mounted in the
1661 correct places.  It is the caller's responsibility to ensure
1662 all filesystems that are needed are mounted at the right
1663 locations.");
1664
1665   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1666    [InitBasicFS, Always, TestOutputList (
1667       [["upload"; "test-command"; "/test-command"];
1668        ["chmod"; "0o755"; "/test-command"];
1669        ["command_lines"; "/test-command 1"]], ["Result1"]);
1670     InitBasicFS, Always, TestOutputList (
1671       [["upload"; "test-command"; "/test-command"];
1672        ["chmod"; "0o755"; "/test-command"];
1673        ["command_lines"; "/test-command 2"]], ["Result2"]);
1674     InitBasicFS, Always, TestOutputList (
1675       [["upload"; "test-command"; "/test-command"];
1676        ["chmod"; "0o755"; "/test-command"];
1677        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1678     InitBasicFS, Always, TestOutputList (
1679       [["upload"; "test-command"; "/test-command"];
1680        ["chmod"; "0o755"; "/test-command"];
1681        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1682     InitBasicFS, Always, TestOutputList (
1683       [["upload"; "test-command"; "/test-command"];
1684        ["chmod"; "0o755"; "/test-command"];
1685        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1686     InitBasicFS, Always, TestOutputList (
1687       [["upload"; "test-command"; "/test-command"];
1688        ["chmod"; "0o755"; "/test-command"];
1689        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1690     InitBasicFS, Always, TestOutputList (
1691       [["upload"; "test-command"; "/test-command"];
1692        ["chmod"; "0o755"; "/test-command"];
1693        ["command_lines"; "/test-command 7"]], []);
1694     InitBasicFS, Always, TestOutputList (
1695       [["upload"; "test-command"; "/test-command"];
1696        ["chmod"; "0o755"; "/test-command"];
1697        ["command_lines"; "/test-command 8"]], [""]);
1698     InitBasicFS, Always, TestOutputList (
1699       [["upload"; "test-command"; "/test-command"];
1700        ["chmod"; "0o755"; "/test-command"];
1701        ["command_lines"; "/test-command 9"]], ["";""]);
1702     InitBasicFS, Always, TestOutputList (
1703       [["upload"; "test-command"; "/test-command"];
1704        ["chmod"; "0o755"; "/test-command"];
1705        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1706     InitBasicFS, Always, TestOutputList (
1707       [["upload"; "test-command"; "/test-command"];
1708        ["chmod"; "0o755"; "/test-command"];
1709        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1710    "run a command, returning lines",
1711    "\
1712 This is the same as C<guestfs_command>, but splits the
1713 result into a list of lines.
1714
1715 See also: C<guestfs_sh_lines>");
1716
1717   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1718    [InitISOFS, Always, TestOutputStruct (
1719       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1720    "get file information",
1721    "\
1722 Returns file information for the given C<path>.
1723
1724 This is the same as the C<stat(2)> system call.");
1725
1726   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1727    [InitISOFS, Always, TestOutputStruct (
1728       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1729    "get file information for a symbolic link",
1730    "\
1731 Returns file information for the given C<path>.
1732
1733 This is the same as C<guestfs_stat> except that if C<path>
1734 is a symbolic link, then the link is stat-ed, not the file it
1735 refers to.
1736
1737 This is the same as the C<lstat(2)> system call.");
1738
1739   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1740    [InitISOFS, Always, TestOutputStruct (
1741       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1742    "get file system statistics",
1743    "\
1744 Returns file system statistics for any mounted file system.
1745 C<path> should be a file or directory in the mounted file system
1746 (typically it is the mount point itself, but it doesn't need to be).
1747
1748 This is the same as the C<statvfs(2)> system call.");
1749
1750   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1751    [], (* XXX test *)
1752    "get ext2/ext3/ext4 superblock details",
1753    "\
1754 This returns the contents of the ext2, ext3 or ext4 filesystem
1755 superblock on C<device>.
1756
1757 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1758 manpage for more details.  The list of fields returned isn't
1759 clearly defined, and depends on both the version of C<tune2fs>
1760 that libguestfs was built against, and the filesystem itself.");
1761
1762   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1763    [InitEmpty, Always, TestOutputTrue (
1764       [["blockdev_setro"; "/dev/sda"];
1765        ["blockdev_getro"; "/dev/sda"]])],
1766    "set block device to read-only",
1767    "\
1768 Sets the block device named C<device> to read-only.
1769
1770 This uses the L<blockdev(8)> command.");
1771
1772   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1773    [InitEmpty, Always, TestOutputFalse (
1774       [["blockdev_setrw"; "/dev/sda"];
1775        ["blockdev_getro"; "/dev/sda"]])],
1776    "set block device to read-write",
1777    "\
1778 Sets the block device named C<device> to read-write.
1779
1780 This uses the L<blockdev(8)> command.");
1781
1782   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1783    [InitEmpty, Always, TestOutputTrue (
1784       [["blockdev_setro"; "/dev/sda"];
1785        ["blockdev_getro"; "/dev/sda"]])],
1786    "is block device set to read-only",
1787    "\
1788 Returns a boolean indicating if the block device is read-only
1789 (true if read-only, false if not).
1790
1791 This uses the L<blockdev(8)> command.");
1792
1793   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1794    [InitEmpty, Always, TestOutputInt (
1795       [["blockdev_getss"; "/dev/sda"]], 512)],
1796    "get sectorsize of block device",
1797    "\
1798 This returns the size of sectors on a block device.
1799 Usually 512, but can be larger for modern devices.
1800
1801 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1802 for that).
1803
1804 This uses the L<blockdev(8)> command.");
1805
1806   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1807    [InitEmpty, Always, TestOutputInt (
1808       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1809    "get blocksize of block device",
1810    "\
1811 This returns the block size of a device.
1812
1813 (Note this is different from both I<size in blocks> and
1814 I<filesystem block size>).
1815
1816 This uses the L<blockdev(8)> command.");
1817
1818   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1819    [], (* XXX test *)
1820    "set blocksize of block device",
1821    "\
1822 This sets the block size of a device.
1823
1824 (Note this is different from both I<size in blocks> and
1825 I<filesystem block size>).
1826
1827 This uses the L<blockdev(8)> command.");
1828
1829   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1830    [InitEmpty, Always, TestOutputInt (
1831       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1832    "get total size of device in 512-byte sectors",
1833    "\
1834 This returns the size of the device in units of 512-byte sectors
1835 (even if the sectorsize isn't 512 bytes ... weird).
1836
1837 See also C<guestfs_blockdev_getss> for the real sector size of
1838 the device, and C<guestfs_blockdev_getsize64> for the more
1839 useful I<size in bytes>.
1840
1841 This uses the L<blockdev(8)> command.");
1842
1843   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1844    [InitEmpty, Always, TestOutputInt (
1845       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1846    "get total size of device in bytes",
1847    "\
1848 This returns the size of the device in bytes.
1849
1850 See also C<guestfs_blockdev_getsz>.
1851
1852 This uses the L<blockdev(8)> command.");
1853
1854   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1855    [InitEmpty, Always, TestRun
1856       [["blockdev_flushbufs"; "/dev/sda"]]],
1857    "flush device buffers",
1858    "\
1859 This tells the kernel to flush internal buffers associated
1860 with C<device>.
1861
1862 This uses the L<blockdev(8)> command.");
1863
1864   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1865    [InitEmpty, Always, TestRun
1866       [["blockdev_rereadpt"; "/dev/sda"]]],
1867    "reread partition table",
1868    "\
1869 Reread the partition table on C<device>.
1870
1871 This uses the L<blockdev(8)> command.");
1872
1873   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1874    [InitBasicFS, Always, TestOutput (
1875       (* Pick a file from cwd which isn't likely to change. *)
1876       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1877        ["checksum"; "md5"; "/COPYING.LIB"]],
1878       Digest.to_hex (Digest.file "COPYING.LIB"))],
1879    "upload a file from the local machine",
1880    "\
1881 Upload local file C<filename> to C<remotefilename> on the
1882 filesystem.
1883
1884 C<filename> can also be a named pipe.
1885
1886 See also C<guestfs_download>.");
1887
1888   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1889    [InitBasicFS, Always, TestOutput (
1890       (* Pick a file from cwd which isn't likely to change. *)
1891       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1892        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1893        ["upload"; "testdownload.tmp"; "/upload"];
1894        ["checksum"; "md5"; "/upload"]],
1895       Digest.to_hex (Digest.file "COPYING.LIB"))],
1896    "download a file to the local machine",
1897    "\
1898 Download file C<remotefilename> and save it as C<filename>
1899 on the local machine.
1900
1901 C<filename> can also be a named pipe.
1902
1903 See also C<guestfs_upload>, C<guestfs_cat>.");
1904
1905   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1906    [InitISOFS, Always, TestOutput (
1907       [["checksum"; "crc"; "/known-3"]], "2891671662");
1908     InitISOFS, Always, TestLastFail (
1909       [["checksum"; "crc"; "/notexists"]]);
1910     InitISOFS, Always, TestOutput (
1911       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1912     InitISOFS, Always, TestOutput (
1913       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1914     InitISOFS, Always, TestOutput (
1915       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1916     InitISOFS, Always, TestOutput (
1917       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1918     InitISOFS, Always, TestOutput (
1919       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1920     InitISOFS, Always, TestOutput (
1921       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1922    "compute MD5, SHAx or CRC checksum of file",
1923    "\
1924 This call computes the MD5, SHAx or CRC checksum of the
1925 file named C<path>.
1926
1927 The type of checksum to compute is given by the C<csumtype>
1928 parameter which must have one of the following values:
1929
1930 =over 4
1931
1932 =item C<crc>
1933
1934 Compute the cyclic redundancy check (CRC) specified by POSIX
1935 for the C<cksum> command.
1936
1937 =item C<md5>
1938
1939 Compute the MD5 hash (using the C<md5sum> program).
1940
1941 =item C<sha1>
1942
1943 Compute the SHA1 hash (using the C<sha1sum> program).
1944
1945 =item C<sha224>
1946
1947 Compute the SHA224 hash (using the C<sha224sum> program).
1948
1949 =item C<sha256>
1950
1951 Compute the SHA256 hash (using the C<sha256sum> program).
1952
1953 =item C<sha384>
1954
1955 Compute the SHA384 hash (using the C<sha384sum> program).
1956
1957 =item C<sha512>
1958
1959 Compute the SHA512 hash (using the C<sha512sum> program).
1960
1961 =back
1962
1963 The checksum is returned as a printable string.");
1964
1965   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1966    [InitBasicFS, Always, TestOutput (
1967       [["tar_in"; "../images/helloworld.tar"; "/"];
1968        ["cat"; "/hello"]], "hello\n")],
1969    "unpack tarfile to directory",
1970    "\
1971 This command uploads and unpacks local file C<tarfile> (an
1972 I<uncompressed> tar file) into C<directory>.
1973
1974 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1975
1976   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1977    [],
1978    "pack directory into tarfile",
1979    "\
1980 This command packs the contents of C<directory> and downloads
1981 it to local file C<tarfile>.
1982
1983 To download a compressed tarball, use C<guestfs_tgz_out>.");
1984
1985   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1986    [InitBasicFS, Always, TestOutput (
1987       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1988        ["cat"; "/hello"]], "hello\n")],
1989    "unpack compressed tarball to directory",
1990    "\
1991 This command uploads and unpacks local file C<tarball> (a
1992 I<gzip compressed> tar file) into C<directory>.
1993
1994 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1995
1996   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
1997    [],
1998    "pack directory into compressed tarball",
1999    "\
2000 This command packs the contents of C<directory> and downloads
2001 it to local file C<tarball>.
2002
2003 To download an uncompressed tarball, use C<guestfs_tar_out>.");
2004
2005   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
2006    [InitBasicFS, Always, TestLastFail (
2007       [["umount"; "/"];
2008        ["mount_ro"; "/dev/sda1"; "/"];
2009        ["touch"; "/new"]]);
2010     InitBasicFS, Always, TestOutput (
2011       [["write_file"; "/new"; "data"; "0"];
2012        ["umount"; "/"];
2013        ["mount_ro"; "/dev/sda1"; "/"];
2014        ["cat"; "/new"]], "data")],
2015    "mount a guest disk, read-only",
2016    "\
2017 This is the same as the C<guestfs_mount> command, but it
2018 mounts the filesystem with the read-only (I<-o ro>) flag.");
2019
2020   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
2021    [],
2022    "mount a guest disk with mount options",
2023    "\
2024 This is the same as the C<guestfs_mount> command, but it
2025 allows you to set the mount options as for the
2026 L<mount(8)> I<-o> flag.");
2027
2028   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2029    [],
2030    "mount a guest disk with mount options and vfstype",
2031    "\
2032 This is the same as the C<guestfs_mount> command, but it
2033 allows you to set both the mount options and the vfstype
2034 as for the L<mount(8)> I<-o> and I<-t> flags.");
2035
2036   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2037    [],
2038    "debugging and internals",
2039    "\
2040 The C<guestfs_debug> command exposes some internals of
2041 C<guestfsd> (the guestfs daemon) that runs inside the
2042 qemu subprocess.
2043
2044 There is no comprehensive help for this command.  You have
2045 to look at the file C<daemon/debug.c> in the libguestfs source
2046 to find out what you can do.");
2047
2048   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2049    [InitEmpty, Always, TestOutputList (
2050       [["part_disk"; "/dev/sda"; "mbr"];
2051        ["pvcreate"; "/dev/sda1"];
2052        ["vgcreate"; "VG"; "/dev/sda1"];
2053        ["lvcreate"; "LV1"; "VG"; "50"];
2054        ["lvcreate"; "LV2"; "VG"; "50"];
2055        ["lvremove"; "/dev/VG/LV1"];
2056        ["lvs"]], ["/dev/VG/LV2"]);
2057     InitEmpty, Always, TestOutputList (
2058       [["part_disk"; "/dev/sda"; "mbr"];
2059        ["pvcreate"; "/dev/sda1"];
2060        ["vgcreate"; "VG"; "/dev/sda1"];
2061        ["lvcreate"; "LV1"; "VG"; "50"];
2062        ["lvcreate"; "LV2"; "VG"; "50"];
2063        ["lvremove"; "/dev/VG"];
2064        ["lvs"]], []);
2065     InitEmpty, Always, TestOutputList (
2066       [["part_disk"; "/dev/sda"; "mbr"];
2067        ["pvcreate"; "/dev/sda1"];
2068        ["vgcreate"; "VG"; "/dev/sda1"];
2069        ["lvcreate"; "LV1"; "VG"; "50"];
2070        ["lvcreate"; "LV2"; "VG"; "50"];
2071        ["lvremove"; "/dev/VG"];
2072        ["vgs"]], ["VG"])],
2073    "remove an LVM logical volume",
2074    "\
2075 Remove an LVM logical volume C<device>, where C<device> is
2076 the path to the LV, such as C</dev/VG/LV>.
2077
2078 You can also remove all LVs in a volume group by specifying
2079 the VG name, C</dev/VG>.");
2080
2081   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2082    [InitEmpty, Always, TestOutputList (
2083       [["part_disk"; "/dev/sda"; "mbr"];
2084        ["pvcreate"; "/dev/sda1"];
2085        ["vgcreate"; "VG"; "/dev/sda1"];
2086        ["lvcreate"; "LV1"; "VG"; "50"];
2087        ["lvcreate"; "LV2"; "VG"; "50"];
2088        ["vgremove"; "VG"];
2089        ["lvs"]], []);
2090     InitEmpty, Always, TestOutputList (
2091       [["part_disk"; "/dev/sda"; "mbr"];
2092        ["pvcreate"; "/dev/sda1"];
2093        ["vgcreate"; "VG"; "/dev/sda1"];
2094        ["lvcreate"; "LV1"; "VG"; "50"];
2095        ["lvcreate"; "LV2"; "VG"; "50"];
2096        ["vgremove"; "VG"];
2097        ["vgs"]], [])],
2098    "remove an LVM volume group",
2099    "\
2100 Remove an LVM volume group C<vgname>, (for example C<VG>).
2101
2102 This also forcibly removes all logical volumes in the volume
2103 group (if any).");
2104
2105   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2106    [InitEmpty, Always, TestOutputListOfDevices (
2107       [["part_disk"; "/dev/sda"; "mbr"];
2108        ["pvcreate"; "/dev/sda1"];
2109        ["vgcreate"; "VG"; "/dev/sda1"];
2110        ["lvcreate"; "LV1"; "VG"; "50"];
2111        ["lvcreate"; "LV2"; "VG"; "50"];
2112        ["vgremove"; "VG"];
2113        ["pvremove"; "/dev/sda1"];
2114        ["lvs"]], []);
2115     InitEmpty, Always, TestOutputListOfDevices (
2116       [["part_disk"; "/dev/sda"; "mbr"];
2117        ["pvcreate"; "/dev/sda1"];
2118        ["vgcreate"; "VG"; "/dev/sda1"];
2119        ["lvcreate"; "LV1"; "VG"; "50"];
2120        ["lvcreate"; "LV2"; "VG"; "50"];
2121        ["vgremove"; "VG"];
2122        ["pvremove"; "/dev/sda1"];
2123        ["vgs"]], []);
2124     InitEmpty, Always, TestOutputListOfDevices (
2125       [["part_disk"; "/dev/sda"; "mbr"];
2126        ["pvcreate"; "/dev/sda1"];
2127        ["vgcreate"; "VG"; "/dev/sda1"];
2128        ["lvcreate"; "LV1"; "VG"; "50"];
2129        ["lvcreate"; "LV2"; "VG"; "50"];
2130        ["vgremove"; "VG"];
2131        ["pvremove"; "/dev/sda1"];
2132        ["pvs"]], [])],
2133    "remove an LVM physical volume",
2134    "\
2135 This wipes a physical volume C<device> so that LVM will no longer
2136 recognise it.
2137
2138 The implementation uses the C<pvremove> command which refuses to
2139 wipe physical volumes that contain any volume groups, so you have
2140 to remove those first.");
2141
2142   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2143    [InitBasicFS, Always, TestOutput (
2144       [["set_e2label"; "/dev/sda1"; "testlabel"];
2145        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2146    "set the ext2/3/4 filesystem label",
2147    "\
2148 This sets the ext2/3/4 filesystem label of the filesystem on
2149 C<device> to C<label>.  Filesystem labels are limited to
2150 16 characters.
2151
2152 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2153 to return the existing label on a filesystem.");
2154
2155   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2156    [],
2157    "get the ext2/3/4 filesystem label",
2158    "\
2159 This returns the ext2/3/4 filesystem label of the filesystem on
2160 C<device>.");
2161
2162   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2163    (let uuid = uuidgen () in
2164     [InitBasicFS, Always, TestOutput (
2165        [["set_e2uuid"; "/dev/sda1"; uuid];
2166         ["get_e2uuid"; "/dev/sda1"]], uuid);
2167      InitBasicFS, Always, TestOutput (
2168        [["set_e2uuid"; "/dev/sda1"; "clear"];
2169         ["get_e2uuid"; "/dev/sda1"]], "");
2170      (* We can't predict what UUIDs will be, so just check the commands run. *)
2171      InitBasicFS, Always, TestRun (
2172        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2173      InitBasicFS, Always, TestRun (
2174        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2175    "set the ext2/3/4 filesystem UUID",
2176    "\
2177 This sets the ext2/3/4 filesystem UUID of the filesystem on
2178 C<device> to C<uuid>.  The format of the UUID and alternatives
2179 such as C<clear>, C<random> and C<time> are described in the
2180 L<tune2fs(8)> manpage.
2181
2182 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2183 to return the existing UUID of a filesystem.");
2184
2185   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2186    [],
2187    "get the ext2/3/4 filesystem UUID",
2188    "\
2189 This returns the ext2/3/4 filesystem UUID of the filesystem on
2190 C<device>.");
2191
2192   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [],
2193    [InitBasicFS, Always, TestOutputInt (
2194       [["umount"; "/dev/sda1"];
2195        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2196     InitBasicFS, Always, TestOutputInt (
2197       [["umount"; "/dev/sda1"];
2198        ["zero"; "/dev/sda1"];
2199        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2200    "run the filesystem checker",
2201    "\
2202 This runs the filesystem checker (fsck) on C<device> which
2203 should have filesystem type C<fstype>.
2204
2205 The returned integer is the status.  See L<fsck(8)> for the
2206 list of status codes from C<fsck>.
2207
2208 Notes:
2209
2210 =over 4
2211
2212 =item *
2213
2214 Multiple status codes can be summed together.
2215
2216 =item *
2217
2218 A non-zero return code can mean \"success\", for example if
2219 errors have been corrected on the filesystem.
2220
2221 =item *
2222
2223 Checking or repairing NTFS volumes is not supported
2224 (by linux-ntfs).
2225
2226 =back
2227
2228 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2229
2230   ("zero", (RErr, [Device "device"]), 85, [],
2231    [InitBasicFS, Always, TestOutput (
2232       [["umount"; "/dev/sda1"];
2233        ["zero"; "/dev/sda1"];
2234        ["file"; "/dev/sda1"]], "data")],
2235    "write zeroes to the device",
2236    "\
2237 This command writes zeroes over the first few blocks of C<device>.
2238
2239 How many blocks are zeroed isn't specified (but it's I<not> enough
2240 to securely wipe the device).  It should be sufficient to remove
2241 any partition tables, filesystem superblocks and so on.
2242
2243 See also: C<guestfs_scrub_device>.");
2244
2245   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2246    (* Test disabled because grub-install incompatible with virtio-blk driver.
2247     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2248     *)
2249    [InitBasicFS, Disabled, TestOutputTrue (
2250       [["grub_install"; "/"; "/dev/sda1"];
2251        ["is_dir"; "/boot"]])],
2252    "install GRUB",
2253    "\
2254 This command installs GRUB (the Grand Unified Bootloader) on
2255 C<device>, with the root directory being C<root>.");
2256
2257   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2258    [InitBasicFS, Always, TestOutput (
2259       [["write_file"; "/old"; "file content"; "0"];
2260        ["cp"; "/old"; "/new"];
2261        ["cat"; "/new"]], "file content");
2262     InitBasicFS, Always, TestOutputTrue (
2263       [["write_file"; "/old"; "file content"; "0"];
2264        ["cp"; "/old"; "/new"];
2265        ["is_file"; "/old"]]);
2266     InitBasicFS, Always, TestOutput (
2267       [["write_file"; "/old"; "file content"; "0"];
2268        ["mkdir"; "/dir"];
2269        ["cp"; "/old"; "/dir/new"];
2270        ["cat"; "/dir/new"]], "file content")],
2271    "copy a file",
2272    "\
2273 This copies a file from C<src> to C<dest> where C<dest> is
2274 either a destination filename or destination directory.");
2275
2276   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2277    [InitBasicFS, Always, TestOutput (
2278       [["mkdir"; "/olddir"];
2279        ["mkdir"; "/newdir"];
2280        ["write_file"; "/olddir/file"; "file content"; "0"];
2281        ["cp_a"; "/olddir"; "/newdir"];
2282        ["cat"; "/newdir/olddir/file"]], "file content")],
2283    "copy a file or directory recursively",
2284    "\
2285 This copies a file or directory from C<src> to C<dest>
2286 recursively using the C<cp -a> command.");
2287
2288   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2289    [InitBasicFS, Always, TestOutput (
2290       [["write_file"; "/old"; "file content"; "0"];
2291        ["mv"; "/old"; "/new"];
2292        ["cat"; "/new"]], "file content");
2293     InitBasicFS, Always, TestOutputFalse (
2294       [["write_file"; "/old"; "file content"; "0"];
2295        ["mv"; "/old"; "/new"];
2296        ["is_file"; "/old"]])],
2297    "move a file",
2298    "\
2299 This moves a file from C<src> to C<dest> where C<dest> is
2300 either a destination filename or destination directory.");
2301
2302   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2303    [InitEmpty, Always, TestRun (
2304       [["drop_caches"; "3"]])],
2305    "drop kernel page cache, dentries and inodes",
2306    "\
2307 This instructs the guest kernel to drop its page cache,
2308 and/or dentries and inode caches.  The parameter C<whattodrop>
2309 tells the kernel what precisely to drop, see
2310 L<http://linux-mm.org/Drop_Caches>
2311
2312 Setting C<whattodrop> to 3 should drop everything.
2313
2314 This automatically calls L<sync(2)> before the operation,
2315 so that the maximum guest memory is freed.");
2316
2317   ("dmesg", (RString "kmsgs", []), 91, [],
2318    [InitEmpty, Always, TestRun (
2319       [["dmesg"]])],
2320    "return kernel messages",
2321    "\
2322 This returns the kernel messages (C<dmesg> output) from
2323 the guest kernel.  This is sometimes useful for extended
2324 debugging of problems.
2325
2326 Another way to get the same information is to enable
2327 verbose messages with C<guestfs_set_verbose> or by setting
2328 the environment variable C<LIBGUESTFS_DEBUG=1> before
2329 running the program.");
2330
2331   ("ping_daemon", (RErr, []), 92, [],
2332    [InitEmpty, Always, TestRun (
2333       [["ping_daemon"]])],
2334    "ping the guest daemon",
2335    "\
2336 This is a test probe into the guestfs daemon running inside
2337 the qemu subprocess.  Calling this function checks that the
2338 daemon responds to the ping message, without affecting the daemon
2339 or attached block device(s) in any other way.");
2340
2341   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2342    [InitBasicFS, Always, TestOutputTrue (
2343       [["write_file"; "/file1"; "contents of a file"; "0"];
2344        ["cp"; "/file1"; "/file2"];
2345        ["equal"; "/file1"; "/file2"]]);
2346     InitBasicFS, Always, TestOutputFalse (
2347       [["write_file"; "/file1"; "contents of a file"; "0"];
2348        ["write_file"; "/file2"; "contents of another file"; "0"];
2349        ["equal"; "/file1"; "/file2"]]);
2350     InitBasicFS, Always, TestLastFail (
2351       [["equal"; "/file1"; "/file2"]])],
2352    "test if two files have equal contents",
2353    "\
2354 This compares the two files C<file1> and C<file2> and returns
2355 true if their content is exactly equal, or false otherwise.
2356
2357 The external L<cmp(1)> program is used for the comparison.");
2358
2359   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2360    [InitISOFS, Always, TestOutputList (
2361       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2362     InitISOFS, Always, TestOutputList (
2363       [["strings"; "/empty"]], [])],
2364    "print the printable strings in a file",
2365    "\
2366 This runs the L<strings(1)> command on a file and returns
2367 the list of printable strings found.");
2368
2369   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2370    [InitISOFS, Always, TestOutputList (
2371       [["strings_e"; "b"; "/known-5"]], []);
2372     InitBasicFS, Disabled, TestOutputList (
2373       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2374        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2375    "print the printable strings in a file",
2376    "\
2377 This is like the C<guestfs_strings> command, but allows you to
2378 specify the encoding.
2379
2380 See the L<strings(1)> manpage for the full list of encodings.
2381
2382 Commonly useful encodings are C<l> (lower case L) which will
2383 show strings inside Windows/x86 files.
2384
2385 The returned strings are transcoded to UTF-8.");
2386
2387   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2388    [InitISOFS, Always, TestOutput (
2389       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2390     (* Test for RHBZ#501888c2 regression which caused large hexdump
2391      * commands to segfault.
2392      *)
2393     InitISOFS, Always, TestRun (
2394       [["hexdump"; "/100krandom"]])],
2395    "dump a file in hexadecimal",
2396    "\
2397 This runs C<hexdump -C> on the given C<path>.  The result is
2398 the human-readable, canonical hex dump of the file.");
2399
2400   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2401    [InitNone, Always, TestOutput (
2402       [["part_disk"; "/dev/sda"; "mbr"];
2403        ["mkfs"; "ext3"; "/dev/sda1"];
2404        ["mount"; "/dev/sda1"; "/"];
2405        ["write_file"; "/new"; "test file"; "0"];
2406        ["umount"; "/dev/sda1"];
2407        ["zerofree"; "/dev/sda1"];
2408        ["mount"; "/dev/sda1"; "/"];
2409        ["cat"; "/new"]], "test file")],
2410    "zero unused inodes and disk blocks on ext2/3 filesystem",
2411    "\
2412 This runs the I<zerofree> program on C<device>.  This program
2413 claims to zero unused inodes and disk blocks on an ext2/3
2414 filesystem, thus making it possible to compress the filesystem
2415 more effectively.
2416
2417 You should B<not> run this program if the filesystem is
2418 mounted.
2419
2420 It is possible that using this program can damage the filesystem
2421 or data on the filesystem.");
2422
2423   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2424    [],
2425    "resize an LVM physical volume",
2426    "\
2427 This resizes (expands or shrinks) an existing LVM physical
2428 volume to match the new size of the underlying device.");
2429
2430   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2431                        Int "cyls"; Int "heads"; Int "sectors";
2432                        String "line"]), 99, [DangerWillRobinson],
2433    [],
2434    "modify a single partition on a block device",
2435    "\
2436 This runs L<sfdisk(8)> option to modify just the single
2437 partition C<n> (note: C<n> counts from 1).
2438
2439 For other parameters, see C<guestfs_sfdisk>.  You should usually
2440 pass C<0> for the cyls/heads/sectors parameters.
2441
2442 See also: C<guestfs_part_add>");
2443
2444   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2445    [],
2446    "display the partition table",
2447    "\
2448 This displays the partition table on C<device>, in the
2449 human-readable output of the L<sfdisk(8)> command.  It is
2450 not intended to be parsed.
2451
2452 See also: C<guestfs_part_list>");
2453
2454   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2455    [],
2456    "display the kernel geometry",
2457    "\
2458 This displays the kernel's idea of the geometry of C<device>.
2459
2460 The result is in human-readable format, and not designed to
2461 be parsed.");
2462
2463   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2464    [],
2465    "display the disk geometry from the partition table",
2466    "\
2467 This displays the disk geometry of C<device> read from the
2468 partition table.  Especially in the case where the underlying
2469 block device has been resized, this can be different from the
2470 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2471
2472 The result is in human-readable format, and not designed to
2473 be parsed.");
2474
2475   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2476    [],
2477    "activate or deactivate all volume groups",
2478    "\
2479 This command activates or (if C<activate> is false) deactivates
2480 all logical volumes in all volume groups.
2481 If activated, then they are made known to the
2482 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2483 then those devices disappear.
2484
2485 This command is the same as running C<vgchange -a y|n>");
2486
2487   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2488    [],
2489    "activate or deactivate some volume groups",
2490    "\
2491 This command activates or (if C<activate> is false) deactivates
2492 all logical volumes in the listed volume groups C<volgroups>.
2493 If activated, then they are made known to the
2494 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2495 then those devices disappear.
2496
2497 This command is the same as running C<vgchange -a y|n volgroups...>
2498
2499 Note that if C<volgroups> is an empty list then B<all> volume groups
2500 are activated or deactivated.");
2501
2502   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2503    [InitNone, Always, TestOutput (
2504       [["part_disk"; "/dev/sda"; "mbr"];
2505        ["pvcreate"; "/dev/sda1"];
2506        ["vgcreate"; "VG"; "/dev/sda1"];
2507        ["lvcreate"; "LV"; "VG"; "10"];
2508        ["mkfs"; "ext2"; "/dev/VG/LV"];
2509        ["mount"; "/dev/VG/LV"; "/"];
2510        ["write_file"; "/new"; "test content"; "0"];
2511        ["umount"; "/"];
2512        ["lvresize"; "/dev/VG/LV"; "20"];
2513        ["e2fsck_f"; "/dev/VG/LV"];
2514        ["resize2fs"; "/dev/VG/LV"];
2515        ["mount"; "/dev/VG/LV"; "/"];
2516        ["cat"; "/new"]], "test content")],
2517    "resize an LVM logical volume",
2518    "\
2519 This resizes (expands or shrinks) an existing LVM logical
2520 volume to C<mbytes>.  When reducing, data in the reduced part
2521 is lost.");
2522
2523   ("resize2fs", (RErr, [Device "device"]), 106, [],
2524    [], (* lvresize tests this *)
2525    "resize an ext2/ext3 filesystem",
2526    "\
2527 This resizes an ext2 or ext3 filesystem to match the size of
2528 the underlying device.
2529
2530 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2531 on the C<device> before calling this command.  For unknown reasons
2532 C<resize2fs> sometimes gives an error about this and sometimes not.
2533 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2534 calling this function.");
2535
2536   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2537    [InitBasicFS, Always, TestOutputList (
2538       [["find"; "/"]], ["lost+found"]);
2539     InitBasicFS, Always, TestOutputList (
2540       [["touch"; "/a"];
2541        ["mkdir"; "/b"];
2542        ["touch"; "/b/c"];
2543        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2544     InitBasicFS, Always, TestOutputList (
2545       [["mkdir_p"; "/a/b/c"];
2546        ["touch"; "/a/b/c/d"];
2547        ["find"; "/a/b/"]], ["c"; "c/d"])],
2548    "find all files and directories",
2549    "\
2550 This command lists out all files and directories, recursively,
2551 starting at C<directory>.  It is essentially equivalent to
2552 running the shell command C<find directory -print> but some
2553 post-processing happens on the output, described below.
2554
2555 This returns a list of strings I<without any prefix>.  Thus
2556 if the directory structure was:
2557
2558  /tmp/a
2559  /tmp/b
2560  /tmp/c/d
2561
2562 then the returned list from C<guestfs_find> C</tmp> would be
2563 4 elements:
2564
2565  a
2566  b
2567  c
2568  c/d
2569
2570 If C<directory> is not a directory, then this command returns
2571 an error.
2572
2573 The returned list is sorted.
2574
2575 See also C<guestfs_find0>.");
2576
2577   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2578    [], (* lvresize tests this *)
2579    "check an ext2/ext3 filesystem",
2580    "\
2581 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2582 filesystem checker on C<device>, noninteractively (C<-p>),
2583 even if the filesystem appears to be clean (C<-f>).
2584
2585 This command is only needed because of C<guestfs_resize2fs>
2586 (q.v.).  Normally you should use C<guestfs_fsck>.");
2587
2588   ("sleep", (RErr, [Int "secs"]), 109, [],
2589    [InitNone, Always, TestRun (
2590       [["sleep"; "1"]])],
2591    "sleep for some seconds",
2592    "\
2593 Sleep for C<secs> seconds.");
2594
2595   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2596    [InitNone, Always, TestOutputInt (
2597       [["part_disk"; "/dev/sda"; "mbr"];
2598        ["mkfs"; "ntfs"; "/dev/sda1"];
2599        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2600     InitNone, Always, TestOutputInt (
2601       [["part_disk"; "/dev/sda"; "mbr"];
2602        ["mkfs"; "ext2"; "/dev/sda1"];
2603        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2604    "probe NTFS volume",
2605    "\
2606 This command runs the L<ntfs-3g.probe(8)> command which probes
2607 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2608 be mounted read-write, and some cannot be mounted at all).
2609
2610 C<rw> is a boolean flag.  Set it to true if you want to test
2611 if the volume can be mounted read-write.  Set it to false if
2612 you want to test if the volume can be mounted read-only.
2613
2614 The return value is an integer which C<0> if the operation
2615 would succeed, or some non-zero value documented in the
2616 L<ntfs-3g.probe(8)> manual page.");
2617
2618   ("sh", (RString "output", [String "command"]), 111, [],
2619    [], (* XXX needs tests *)
2620    "run a command via the shell",
2621    "\
2622 This call runs a command from the guest filesystem via the
2623 guest's C</bin/sh>.
2624
2625 This is like C<guestfs_command>, but passes the command to:
2626
2627  /bin/sh -c \"command\"
2628
2629 Depending on the guest's shell, this usually results in
2630 wildcards being expanded, shell expressions being interpolated
2631 and so on.
2632
2633 All the provisos about C<guestfs_command> apply to this call.");
2634
2635   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2636    [], (* XXX needs tests *)
2637    "run a command via the shell returning lines",
2638    "\
2639 This is the same as C<guestfs_sh>, but splits the result
2640 into a list of lines.
2641
2642 See also: C<guestfs_command_lines>");
2643
2644   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2645    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2646     * code in stubs.c, since all valid glob patterns must start with "/".
2647     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2648     *)
2649    [InitBasicFS, Always, TestOutputList (
2650       [["mkdir_p"; "/a/b/c"];
2651        ["touch"; "/a/b/c/d"];
2652        ["touch"; "/a/b/c/e"];
2653        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2654     InitBasicFS, Always, TestOutputList (
2655       [["mkdir_p"; "/a/b/c"];
2656        ["touch"; "/a/b/c/d"];
2657        ["touch"; "/a/b/c/e"];
2658        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2659     InitBasicFS, Always, TestOutputList (
2660       [["mkdir_p"; "/a/b/c"];
2661        ["touch"; "/a/b/c/d"];
2662        ["touch"; "/a/b/c/e"];
2663        ["glob_expand"; "/a/*/x/*"]], [])],
2664    "expand a wildcard path",
2665    "\
2666 This command searches for all the pathnames matching
2667 C<pattern> according to the wildcard expansion rules
2668 used by the shell.
2669
2670 If no paths match, then this returns an empty list
2671 (note: not an error).
2672
2673 It is just a wrapper around the C L<glob(3)> function
2674 with flags C<GLOB_MARK|GLOB_BRACE>.
2675 See that manual page for more details.");
2676
2677   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2678    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2679       [["scrub_device"; "/dev/sdc"]])],
2680    "scrub (securely wipe) a device",
2681    "\
2682 This command writes patterns over C<device> to make data retrieval
2683 more difficult.
2684
2685 It is an interface to the L<scrub(1)> program.  See that
2686 manual page for more details.");
2687
2688   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2689    [InitBasicFS, Always, TestRun (
2690       [["write_file"; "/file"; "content"; "0"];
2691        ["scrub_file"; "/file"]])],
2692    "scrub (securely wipe) a file",
2693    "\
2694 This command writes patterns over a file to make data retrieval
2695 more difficult.
2696
2697 The file is I<removed> after scrubbing.
2698
2699 It is an interface to the L<scrub(1)> program.  See that
2700 manual page for more details.");
2701
2702   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2703    [], (* XXX needs testing *)
2704    "scrub (securely wipe) free space",
2705    "\
2706 This command creates the directory C<dir> and then fills it
2707 with files until the filesystem is full, and scrubs the files
2708 as for C<guestfs_scrub_file>, and deletes them.
2709 The intention is to scrub any free space on the partition
2710 containing C<dir>.
2711
2712 It is an interface to the L<scrub(1)> program.  See that
2713 manual page for more details.");
2714
2715   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2716    [InitBasicFS, Always, TestRun (
2717       [["mkdir"; "/tmp"];
2718        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2719    "create a temporary directory",
2720    "\
2721 This command creates a temporary directory.  The
2722 C<template> parameter should be a full pathname for the
2723 temporary directory name with the final six characters being
2724 \"XXXXXX\".
2725
2726 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2727 the second one being suitable for Windows filesystems.
2728
2729 The name of the temporary directory that was created
2730 is returned.
2731
2732 The temporary directory is created with mode 0700
2733 and is owned by root.
2734
2735 The caller is responsible for deleting the temporary
2736 directory and its contents after use.
2737
2738 See also: L<mkdtemp(3)>");
2739
2740   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2741    [InitISOFS, Always, TestOutputInt (
2742       [["wc_l"; "/10klines"]], 10000)],
2743    "count lines in a file",
2744    "\
2745 This command counts the lines in a file, using the
2746 C<wc -l> external command.");
2747
2748   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2749    [InitISOFS, Always, TestOutputInt (
2750       [["wc_w"; "/10klines"]], 10000)],
2751    "count words in a file",
2752    "\
2753 This command counts the words in a file, using the
2754 C<wc -w> external command.");
2755
2756   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2757    [InitISOFS, Always, TestOutputInt (
2758       [["wc_c"; "/100kallspaces"]], 102400)],
2759    "count characters in a file",
2760    "\
2761 This command counts the characters in a file, using the
2762 C<wc -c> external command.");
2763
2764   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2765    [InitISOFS, Always, TestOutputList (
2766       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2767    "return first 10 lines of a file",
2768    "\
2769 This command returns up to the first 10 lines of a file as
2770 a list of strings.");
2771
2772   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2773    [InitISOFS, Always, TestOutputList (
2774       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2775     InitISOFS, Always, TestOutputList (
2776       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2777     InitISOFS, Always, TestOutputList (
2778       [["head_n"; "0"; "/10klines"]], [])],
2779    "return first N lines of a file",
2780    "\
2781 If the parameter C<nrlines> is a positive number, this returns the first
2782 C<nrlines> lines of the file C<path>.
2783
2784 If the parameter C<nrlines> is a negative number, this returns lines
2785 from the file C<path>, excluding the last C<nrlines> lines.
2786
2787 If the parameter C<nrlines> is zero, this returns an empty list.");
2788
2789   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2790    [InitISOFS, Always, TestOutputList (
2791       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2792    "return last 10 lines of a file",
2793    "\
2794 This command returns up to the last 10 lines of a file as
2795 a list of strings.");
2796
2797   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2798    [InitISOFS, Always, TestOutputList (
2799       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2800     InitISOFS, Always, TestOutputList (
2801       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2802     InitISOFS, Always, TestOutputList (
2803       [["tail_n"; "0"; "/10klines"]], [])],
2804    "return last N lines of a file",
2805    "\
2806 If the parameter C<nrlines> is a positive number, this returns the last
2807 C<nrlines> lines of the file C<path>.
2808
2809 If the parameter C<nrlines> is a negative number, this returns lines
2810 from the file C<path>, starting with the C<-nrlines>th line.
2811
2812 If the parameter C<nrlines> is zero, this returns an empty list.");
2813
2814   ("df", (RString "output", []), 125, [],
2815    [], (* XXX Tricky to test because it depends on the exact format
2816         * of the 'df' command and other imponderables.
2817         *)
2818    "report file system disk space usage",
2819    "\
2820 This command runs the C<df> command to report disk space used.
2821
2822 This command is mostly useful for interactive sessions.  It
2823 is I<not> intended that you try to parse the output string.
2824 Use C<statvfs> from programs.");
2825
2826   ("df_h", (RString "output", []), 126, [],
2827    [], (* XXX Tricky to test because it depends on the exact format
2828         * of the 'df' command and other imponderables.
2829         *)
2830    "report file system disk space usage (human readable)",
2831    "\
2832 This command runs the C<df -h> command to report disk space used
2833 in human-readable format.
2834
2835 This command is mostly useful for interactive sessions.  It
2836 is I<not> intended that you try to parse the output string.
2837 Use C<statvfs> from programs.");
2838
2839   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2840    [InitISOFS, Always, TestOutputInt (
2841       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2842    "estimate file space usage",
2843    "\
2844 This command runs the C<du -s> command to estimate file space
2845 usage for C<path>.
2846
2847 C<path> can be a file or a directory.  If C<path> is a directory
2848 then the estimate includes the contents of the directory and all
2849 subdirectories (recursively).
2850
2851 The result is the estimated size in I<kilobytes>
2852 (ie. units of 1024 bytes).");
2853
2854   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2855    [InitISOFS, Always, TestOutputList (
2856       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2857    "list files in an initrd",
2858    "\
2859 This command lists out files contained in an initrd.
2860
2861 The files are listed without any initial C</> character.  The
2862 files are listed in the order they appear (not necessarily
2863 alphabetical).  Directory names are listed as separate items.
2864
2865 Old Linux kernels (2.4 and earlier) used a compressed ext2
2866 filesystem as initrd.  We I<only> support the newer initramfs
2867 format (compressed cpio files).");
2868
2869   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2870    [],
2871    "mount a file using the loop device",
2872    "\
2873 This command lets you mount C<file> (a filesystem image
2874 in a file) on a mount point.  It is entirely equivalent to
2875 the command C<mount -o loop file mountpoint>.");
2876
2877   ("mkswap", (RErr, [Device "device"]), 130, [],
2878    [InitEmpty, Always, TestRun (
2879       [["part_disk"; "/dev/sda"; "mbr"];
2880        ["mkswap"; "/dev/sda1"]])],
2881    "create a swap partition",
2882    "\
2883 Create a swap partition on C<device>.");
2884
2885   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2886    [InitEmpty, Always, TestRun (
2887       [["part_disk"; "/dev/sda"; "mbr"];
2888        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2889    "create a swap partition with a label",
2890    "\
2891 Create a swap partition on C<device> with label C<label>.
2892
2893 Note that you cannot attach a swap label to a block device
2894 (eg. C</dev/sda>), just to a partition.  This appears to be
2895 a limitation of the kernel or swap tools.");
2896
2897   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
2898    (let uuid = uuidgen () in
2899     [InitEmpty, Always, TestRun (
2900        [["part_disk"; "/dev/sda"; "mbr"];
2901         ["mkswap_U"; uuid; "/dev/sda1"]])]),
2902    "create a swap partition with an explicit UUID",
2903    "\
2904 Create a swap partition on C<device> with UUID C<uuid>.");
2905
2906   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
2907    [InitBasicFS, Always, TestOutputStruct (
2908       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2909        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2910        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2911     InitBasicFS, Always, TestOutputStruct (
2912       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2913        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2914    "make block, character or FIFO devices",
2915    "\
2916 This call creates block or character special devices, or
2917 named pipes (FIFOs).
2918
2919 The C<mode> parameter should be the mode, using the standard
2920 constants.  C<devmajor> and C<devminor> are the
2921 device major and minor numbers, only used when creating block
2922 and character special devices.");
2923
2924   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
2925    [InitBasicFS, Always, TestOutputStruct (
2926       [["mkfifo"; "0o777"; "/node"];
2927        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2928    "make FIFO (named pipe)",
2929    "\
2930 This call creates a FIFO (named pipe) called C<path> with
2931 mode C<mode>.  It is just a convenient wrapper around
2932 C<guestfs_mknod>.");
2933
2934   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
2935    [InitBasicFS, Always, TestOutputStruct (
2936       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2937        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2938    "make block device node",
2939    "\
2940 This call creates a block device node called C<path> with
2941 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2942 It is just a convenient wrapper around C<guestfs_mknod>.");
2943
2944   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
2945    [InitBasicFS, Always, TestOutputStruct (
2946       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2947        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2948    "make char device node",
2949    "\
2950 This call creates a char device node called C<path> with
2951 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2952 It is just a convenient wrapper around C<guestfs_mknod>.");
2953
2954   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2955    [], (* XXX umask is one of those stateful things that we should
2956         * reset between each test.
2957         *)
2958    "set file mode creation mask (umask)",
2959    "\
2960 This function sets the mask used for creating new files and
2961 device nodes to C<mask & 0777>.
2962
2963 Typical umask values would be C<022> which creates new files
2964 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2965 C<002> which creates new files with permissions like
2966 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2967
2968 The default umask is C<022>.  This is important because it
2969 means that directories and device nodes will be created with
2970 C<0644> or C<0755> mode even if you specify C<0777>.
2971
2972 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2973
2974 This call returns the previous umask.");
2975
2976   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
2977    [],
2978    "read directories entries",
2979    "\
2980 This returns the list of directory entries in directory C<dir>.
2981
2982 All entries in the directory are returned, including C<.> and
2983 C<..>.  The entries are I<not> sorted, but returned in the same
2984 order as the underlying filesystem.
2985
2986 Also this call returns basic file type information about each
2987 file.  The C<ftyp> field will contain one of the following characters:
2988
2989 =over 4
2990
2991 =item 'b'
2992
2993 Block special
2994
2995 =item 'c'
2996
2997 Char special
2998
2999 =item 'd'
3000
3001 Directory
3002
3003 =item 'f'
3004
3005 FIFO (named pipe)
3006
3007 =item 'l'
3008
3009 Symbolic link
3010
3011 =item 'r'
3012
3013 Regular file
3014
3015 =item 's'
3016
3017 Socket
3018
3019 =item 'u'
3020
3021 Unknown file type
3022
3023 =item '?'
3024
3025 The L<readdir(3)> returned a C<d_type> field with an
3026 unexpected value
3027
3028 =back
3029
3030 This function is primarily intended for use by programs.  To
3031 get a simple list of names, use C<guestfs_ls>.  To get a printable
3032 directory for human consumption, use C<guestfs_ll>.");
3033
3034   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3035    [],
3036    "create partitions on a block device",
3037    "\
3038 This is a simplified interface to the C<guestfs_sfdisk>
3039 command, where partition sizes are specified in megabytes
3040 only (rounded to the nearest cylinder) and you don't need
3041 to specify the cyls, heads and sectors parameters which
3042 were rarely if ever used anyway.
3043
3044 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3045 and C<guestfs_part_disk>");
3046
3047   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3048    [],
3049    "determine file type inside a compressed file",
3050    "\
3051 This command runs C<file> after first decompressing C<path>
3052 using C<method>.
3053
3054 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3055
3056 Since 1.0.63, use C<guestfs_file> instead which can now
3057 process compressed files.");
3058
3059   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3060    [],
3061    "list extended attributes of a file or directory",
3062    "\
3063 This call lists the extended attributes of the file or directory
3064 C<path>.
3065
3066 At the system call level, this is a combination of the
3067 L<listxattr(2)> and L<getxattr(2)> calls.
3068
3069 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3070
3071   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3072    [],
3073    "list extended attributes of a file or directory",
3074    "\
3075 This is the same as C<guestfs_getxattrs>, but if C<path>
3076 is a symbolic link, then it returns the extended attributes
3077 of the link itself.");
3078
3079   ("setxattr", (RErr, [String "xattr";
3080                        String "val"; Int "vallen"; (* will be BufferIn *)
3081                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3082    [],
3083    "set extended attribute of a file or directory",
3084    "\
3085 This call sets the extended attribute named C<xattr>
3086 of the file C<path> to the value C<val> (of length C<vallen>).
3087 The value is arbitrary 8 bit data.
3088
3089 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3090
3091   ("lsetxattr", (RErr, [String "xattr";
3092                         String "val"; Int "vallen"; (* will be BufferIn *)
3093                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3094    [],
3095    "set extended attribute of a file or directory",
3096    "\
3097 This is the same as C<guestfs_setxattr>, but if C<path>
3098 is a symbolic link, then it sets an extended attribute
3099 of the link itself.");
3100
3101   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3102    [],
3103    "remove extended attribute of a file or directory",
3104    "\
3105 This call removes the extended attribute named C<xattr>
3106 of the file C<path>.
3107
3108 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3109
3110   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3111    [],
3112    "remove extended attribute of a file or directory",
3113    "\
3114 This is the same as C<guestfs_removexattr>, but if C<path>
3115 is a symbolic link, then it removes an extended attribute
3116 of the link itself.");
3117
3118   ("mountpoints", (RHashtable "mps", []), 147, [],
3119    [],
3120    "show mountpoints",
3121    "\
3122 This call is similar to C<guestfs_mounts>.  That call returns
3123 a list of devices.  This one returns a hash table (map) of
3124 device name to directory where the device is mounted.");
3125
3126   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3127    (* This is a special case: while you would expect a parameter
3128     * of type "Pathname", that doesn't work, because it implies
3129     * NEED_ROOT in the generated calling code in stubs.c, and
3130     * this function cannot use NEED_ROOT.
3131     *)
3132    [],
3133    "create a mountpoint",
3134    "\
3135 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3136 specialized calls that can be used to create extra mountpoints
3137 before mounting the first filesystem.
3138
3139 These calls are I<only> necessary in some very limited circumstances,
3140 mainly the case where you want to mount a mix of unrelated and/or
3141 read-only filesystems together.
3142
3143 For example, live CDs often contain a \"Russian doll\" nest of
3144 filesystems, an ISO outer layer, with a squashfs image inside, with
3145 an ext2/3 image inside that.  You can unpack this as follows
3146 in guestfish:
3147
3148  add-ro Fedora-11-i686-Live.iso
3149  run
3150  mkmountpoint /cd
3151  mkmountpoint /squash
3152  mkmountpoint /ext3
3153  mount /dev/sda /cd
3154  mount-loop /cd/LiveOS/squashfs.img /squash
3155  mount-loop /squash/LiveOS/ext3fs.img /ext3
3156
3157 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3158
3159   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3160    [],
3161    "remove a mountpoint",
3162    "\
3163 This calls removes a mountpoint that was previously created
3164 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3165 for full details.");
3166
3167   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3168    [InitISOFS, Always, TestOutputBuffer (
3169       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3170    "read a file",
3171    "\
3172 This calls returns the contents of the file C<path> as a
3173 buffer.
3174
3175 Unlike C<guestfs_cat>, this function can correctly
3176 handle files that contain embedded ASCII NUL characters.
3177 However unlike C<guestfs_download>, this function is limited
3178 in the total size of file that can be handled.");
3179
3180   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3181    [InitISOFS, Always, TestOutputList (
3182       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3183     InitISOFS, Always, TestOutputList (
3184       [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3185    "return lines matching a pattern",
3186    "\
3187 This calls the external C<grep> program and returns the
3188 matching lines.");
3189
3190   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3191    [InitISOFS, Always, TestOutputList (
3192       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3193    "return lines matching a pattern",
3194    "\
3195 This calls the external C<egrep> program and returns the
3196 matching lines.");
3197
3198   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3199    [InitISOFS, Always, TestOutputList (
3200       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3201    "return lines matching a pattern",
3202    "\
3203 This calls the external C<fgrep> program and returns the
3204 matching lines.");
3205
3206   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3207    [InitISOFS, Always, TestOutputList (
3208       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3209    "return lines matching a pattern",
3210    "\
3211 This calls the external C<grep -i> program and returns the
3212 matching lines.");
3213
3214   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3215    [InitISOFS, Always, TestOutputList (
3216       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3217    "return lines matching a pattern",
3218    "\
3219 This calls the external C<egrep -i> program and returns the
3220 matching lines.");
3221
3222   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3223    [InitISOFS, Always, TestOutputList (
3224       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3225    "return lines matching a pattern",
3226    "\
3227 This calls the external C<fgrep -i> program and returns the
3228 matching lines.");
3229
3230   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3231    [InitISOFS, Always, TestOutputList (
3232       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3233    "return lines matching a pattern",
3234    "\
3235 This calls the external C<zgrep> program and returns the
3236 matching lines.");
3237
3238   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3239    [InitISOFS, Always, TestOutputList (
3240       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3241    "return lines matching a pattern",
3242    "\
3243 This calls the external C<zegrep> program and returns the
3244 matching lines.");
3245
3246   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3247    [InitISOFS, Always, TestOutputList (
3248       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3249    "return lines matching a pattern",
3250    "\
3251 This calls the external C<zfgrep> program and returns the
3252 matching lines.");
3253
3254   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3255    [InitISOFS, Always, TestOutputList (
3256       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3257    "return lines matching a pattern",
3258    "\
3259 This calls the external C<zgrep -i> program and returns the
3260 matching lines.");
3261
3262   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3263    [InitISOFS, Always, TestOutputList (
3264       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3265    "return lines matching a pattern",
3266    "\
3267 This calls the external C<zegrep -i> program and returns the
3268 matching lines.");
3269
3270   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3271    [InitISOFS, Always, TestOutputList (
3272       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3273    "return lines matching a pattern",
3274    "\
3275 This calls the external C<zfgrep -i> program and returns the
3276 matching lines.");
3277
3278   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3279    [InitISOFS, Always, TestOutput (
3280       [["realpath"; "/../directory"]], "/directory")],
3281    "canonicalized absolute pathname",
3282    "\
3283 Return the canonicalized absolute pathname of C<path>.  The
3284 returned path has no C<.>, C<..> or symbolic link path elements.");
3285
3286   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3287    [InitBasicFS, Always, TestOutputStruct (
3288       [["touch"; "/a"];
3289        ["ln"; "/a"; "/b"];
3290        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3291    "create a hard link",
3292    "\
3293 This command creates a hard link using the C<ln> command.");
3294
3295   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3296    [InitBasicFS, Always, TestOutputStruct (
3297       [["touch"; "/a"];
3298        ["touch"; "/b"];
3299        ["ln_f"; "/a"; "/b"];
3300        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3301    "create a hard link",
3302    "\
3303 This command creates a hard link using the C<ln -f> command.
3304 The C<-f> option removes the link (C<linkname>) if it exists already.");
3305
3306   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3307    [InitBasicFS, Always, TestOutputStruct (
3308       [["touch"; "/a"];
3309        ["ln_s"; "a"; "/b"];
3310        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3311    "create a symbolic link",
3312    "\
3313 This command creates a symbolic link using the C<ln -s> command.");
3314
3315   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3316    [InitBasicFS, Always, TestOutput (
3317       [["mkdir_p"; "/a/b"];
3318        ["touch"; "/a/b/c"];
3319        ["ln_sf"; "../d"; "/a/b/c"];
3320        ["readlink"; "/a/b/c"]], "../d")],
3321    "create a symbolic link",
3322    "\
3323 This command creates a symbolic link using the C<ln -sf> command,
3324 The C<-f> option removes the link (C<linkname>) if it exists already.");
3325
3326   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3327    [] (* XXX tested above *),
3328    "read the target of a symbolic link",
3329    "\
3330 This command reads the target of a symbolic link.");
3331
3332   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3333    [InitBasicFS, Always, TestOutputStruct (
3334       [["fallocate"; "/a"; "1000000"];
3335        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3336    "preallocate a file in the guest filesystem",
3337    "\
3338 This command preallocates a file (containing zero bytes) named
3339 C<path> of size C<len> bytes.  If the file exists already, it
3340 is overwritten.
3341
3342 Do not confuse this with the guestfish-specific
3343 C<alloc> command which allocates a file in the host and
3344 attaches it as a device.");
3345
3346   ("swapon_device", (RErr, [Device "device"]), 170, [],
3347    [InitPartition, Always, TestRun (
3348       [["mkswap"; "/dev/sda1"];
3349        ["swapon_device"; "/dev/sda1"];
3350        ["swapoff_device"; "/dev/sda1"]])],
3351    "enable swap on device",
3352    "\
3353 This command enables the libguestfs appliance to use the
3354 swap device or partition named C<device>.  The increased
3355 memory is made available for all commands, for example
3356 those run using C<guestfs_command> or C<guestfs_sh>.
3357
3358 Note that you should not swap to existing guest swap
3359 partitions unless you know what you are doing.  They may
3360 contain hibernation information, or other information that
3361 the guest doesn't want you to trash.  You also risk leaking
3362 information about the host to the guest this way.  Instead,
3363 attach a new host device to the guest and swap on that.");
3364
3365   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3366    [], (* XXX tested by swapon_device *)
3367    "disable swap on device",
3368    "\
3369 This command disables the libguestfs appliance swap
3370 device or partition named C<device>.
3371 See C<guestfs_swapon_device>.");
3372
3373   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3374    [InitBasicFS, Always, TestRun (
3375       [["fallocate"; "/swap"; "8388608"];
3376        ["mkswap_file"; "/swap"];
3377        ["swapon_file"; "/swap"];
3378        ["swapoff_file"; "/swap"]])],
3379    "enable swap on file",
3380    "\
3381 This command enables swap to a file.
3382 See C<guestfs_swapon_device> for other notes.");
3383
3384   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3385    [], (* XXX tested by swapon_file *)
3386    "disable swap on file",
3387    "\
3388 This command disables the libguestfs appliance swap on file.");
3389
3390   ("swapon_label", (RErr, [String "label"]), 174, [],
3391    [InitEmpty, Always, TestRun (
3392       [["part_disk"; "/dev/sdb"; "mbr"];
3393        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3394        ["swapon_label"; "swapit"];
3395        ["swapoff_label"; "swapit"];
3396        ["zero"; "/dev/sdb"];
3397        ["blockdev_rereadpt"; "/dev/sdb"]])],
3398    "enable swap on labeled swap partition",
3399    "\
3400 This command enables swap to a labeled swap partition.
3401 See C<guestfs_swapon_device> for other notes.");
3402
3403   ("swapoff_label", (RErr, [String "label"]), 175, [],
3404    [], (* XXX tested by swapon_label *)
3405    "disable swap on labeled swap partition",
3406    "\
3407 This command disables the libguestfs appliance swap on
3408 labeled swap partition.");
3409
3410   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3411    (let uuid = uuidgen () in
3412     [InitEmpty, Always, TestRun (
3413        [["mkswap_U"; uuid; "/dev/sdb"];
3414         ["swapon_uuid"; uuid];
3415         ["swapoff_uuid"; uuid]])]),
3416    "enable swap on swap partition by UUID",
3417    "\
3418 This command enables swap to a swap partition with the given UUID.
3419 See C<guestfs_swapon_device> for other notes.");
3420
3421   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3422    [], (* XXX tested by swapon_uuid *)
3423    "disable swap on swap partition by UUID",
3424    "\
3425 This command disables the libguestfs appliance swap partition
3426 with the given UUID.");
3427
3428   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3429    [InitBasicFS, Always, TestRun (
3430       [["fallocate"; "/swap"; "8388608"];
3431        ["mkswap_file"; "/swap"]])],
3432    "create a swap file",
3433    "\
3434 Create a swap file.
3435
3436 This command just writes a swap file signature to an existing
3437 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3438
3439   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3440    [InitISOFS, Always, TestRun (
3441       [["inotify_init"; "0"]])],
3442    "create an inotify handle",
3443    "\
3444 This command creates a new inotify handle.
3445 The inotify subsystem can be used to notify events which happen to
3446 objects in the guest filesystem.
3447
3448 C<maxevents> is the maximum number of events which will be
3449 queued up between calls to C<guestfs_inotify_read> or
3450 C<guestfs_inotify_files>.
3451 If this is passed as C<0>, then the kernel (or previously set)
3452 default is used.  For Linux 2.6.29 the default was 16384 events.
3453 Beyond this limit, the kernel throws away events, but records
3454 the fact that it threw them away by setting a flag
3455 C<IN_Q_OVERFLOW> in the returned structure list (see
3456 C<guestfs_inotify_read>).
3457
3458 Before any events are generated, you have to add some
3459 watches to the internal watch list.  See:
3460 C<guestfs_inotify_add_watch>,
3461 C<guestfs_inotify_rm_watch> and
3462 C<guestfs_inotify_watch_all>.
3463
3464 Queued up events should be read periodically by calling
3465 C<guestfs_inotify_read>
3466 (or C<guestfs_inotify_files> which is just a helpful
3467 wrapper around C<guestfs_inotify_read>).  If you don't
3468 read the events out often enough then you risk the internal
3469 queue overflowing.
3470
3471 The handle should be closed after use by calling
3472 C<guestfs_inotify_close>.  This also removes any
3473 watches automatically.
3474
3475 See also L<inotify(7)> for an overview of the inotify interface
3476 as exposed by the Linux kernel, which is roughly what we expose
3477 via libguestfs.  Note that there is one global inotify handle
3478 per libguestfs instance.");
3479
3480   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3481    [InitBasicFS, Always, TestOutputList (
3482       [["inotify_init"; "0"];
3483        ["inotify_add_watch"; "/"; "1073741823"];
3484        ["touch"; "/a"];
3485        ["touch"; "/b"];
3486        ["inotify_files"]], ["a"; "b"])],
3487    "add an inotify watch",
3488    "\
3489 Watch C<path> for the events listed in C<mask>.
3490
3491 Note that if C<path> is a directory then events within that
3492 directory are watched, but this does I<not> happen recursively
3493 (in subdirectories).
3494
3495 Note for non-C or non-Linux callers: the inotify events are
3496 defined by the Linux kernel ABI and are listed in
3497 C</usr/include/sys/inotify.h>.");
3498
3499   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3500    [],
3501    "remove an inotify watch",
3502    "\
3503 Remove a previously defined inotify watch.
3504 See C<guestfs_inotify_add_watch>.");
3505
3506   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3507    [],
3508    "return list of inotify events",
3509    "\
3510 Return the complete queue of events that have happened
3511 since the previous read call.
3512
3513 If no events have happened, this returns an empty list.
3514
3515 I<Note>: In order to make sure that all events have been
3516 read, you must call this function repeatedly until it
3517 returns an empty list.  The reason is that the call will
3518 read events up to the maximum appliance-to-host message
3519 size and leave remaining events in the queue.");
3520
3521   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3522    [],
3523    "return list of watched files that had events",
3524    "\
3525 This function is a helpful wrapper around C<guestfs_inotify_read>
3526 which just returns a list of pathnames of objects that were
3527 touched.  The returned pathnames are sorted and deduplicated.");
3528
3529   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3530    [],
3531    "close the inotify handle",
3532    "\
3533 This closes the inotify handle which was previously
3534 opened by inotify_init.  It removes all watches, throws
3535 away any pending events, and deallocates all resources.");
3536
3537   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3538    [],
3539    "set SELinux security context",
3540    "\
3541 This sets the SELinux security context of the daemon
3542 to the string C<context>.
3543
3544 See the documentation about SELINUX in L<guestfs(3)>.");
3545
3546   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3547    [],
3548    "get SELinux security context",
3549    "\
3550 This gets the SELinux security context of the daemon.
3551
3552 See the documentation about SELINUX in L<guestfs(3)>,
3553 and C<guestfs_setcon>");
3554
3555   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3556    [InitEmpty, Always, TestOutput (
3557       [["part_disk"; "/dev/sda"; "mbr"];
3558        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3559        ["mount"; "/dev/sda1"; "/"];
3560        ["write_file"; "/new"; "new file contents"; "0"];
3561        ["cat"; "/new"]], "new file contents")],
3562    "make a filesystem with block size",
3563    "\
3564 This call is similar to C<guestfs_mkfs>, but it allows you to
3565 control the block size of the resulting filesystem.  Supported
3566 block sizes depend on the filesystem type, but typically they
3567 are C<1024>, C<2048> or C<4096> only.");
3568
3569   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3570    [InitEmpty, Always, TestOutput (
3571       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3572        ["mke2journal"; "4096"; "/dev/sda1"];
3573        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3574        ["mount"; "/dev/sda2"; "/"];
3575        ["write_file"; "/new"; "new file contents"; "0"];
3576        ["cat"; "/new"]], "new file contents")],
3577    "make ext2/3/4 external journal",
3578    "\
3579 This creates an ext2 external journal on C<device>.  It is equivalent
3580 to the command:
3581
3582  mke2fs -O journal_dev -b blocksize device");
3583
3584   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3585    [InitEmpty, Always, TestOutput (
3586       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3587        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3588        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3589        ["mount"; "/dev/sda2"; "/"];
3590        ["write_file"; "/new"; "new file contents"; "0"];
3591        ["cat"; "/new"]], "new file contents")],
3592    "make ext2/3/4 external journal with label",
3593    "\
3594 This creates an ext2 external journal on C<device> with label C<label>.");
3595
3596   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3597    (let uuid = uuidgen () in
3598     [InitEmpty, Always, TestOutput (
3599        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3600         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3601         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3602         ["mount"; "/dev/sda2"; "/"];
3603         ["write_file"; "/new"; "new file contents"; "0"];
3604         ["cat"; "/new"]], "new file contents")]),
3605    "make ext2/3/4 external journal with UUID",
3606    "\
3607 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3608
3609   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3610    [],
3611    "make ext2/3/4 filesystem with external journal",
3612    "\
3613 This creates an ext2/3/4 filesystem on C<device> with
3614 an external journal on C<journal>.  It is equivalent
3615 to the command:
3616
3617  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3618
3619 See also C<guestfs_mke2journal>.");
3620
3621   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3622    [],
3623    "make ext2/3/4 filesystem with external journal",
3624    "\
3625 This creates an ext2/3/4 filesystem on C<device> with
3626 an external journal on the journal labeled C<label>.
3627
3628 See also C<guestfs_mke2journal_L>.");
3629
3630   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3631    [],
3632    "make ext2/3/4 filesystem with external journal",
3633    "\
3634 This creates an ext2/3/4 filesystem on C<device> with
3635 an external journal on the journal with UUID C<uuid>.
3636
3637 See also C<guestfs_mke2journal_U>.");
3638
3639   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3640    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3641    "load a kernel module",
3642    "\
3643 This loads a kernel module in the appliance.
3644
3645 The kernel module must have been whitelisted when libguestfs
3646 was built (see C<appliance/kmod.whitelist.in> in the source).");
3647
3648   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3649    [InitNone, Always, TestOutput (
3650       [["echo_daemon"; "This is a test"]], "This is a test"
3651     )],
3652    "echo arguments back to the client",
3653    "\
3654 This command concatenate the list of C<words> passed with single spaces between
3655 them and returns the resulting string.
3656
3657 You can use this command to test the connection through to the daemon.
3658
3659 See also C<guestfs_ping_daemon>.");
3660
3661   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3662    [], (* There is a regression test for this. *)
3663    "find all files and directories, returning NUL-separated list",
3664    "\
3665 This command lists out all files and directories, recursively,
3666 starting at C<directory>, placing the resulting list in the
3667 external file called C<files>.
3668
3669 This command works the same way as C<guestfs_find> with the
3670 following exceptions:
3671
3672 =over 4
3673
3674 =item *
3675
3676 The resulting list is written to an external file.
3677
3678 =item *
3679
3680 Items (filenames) in the result are separated
3681 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3682
3683 =item *
3684
3685 This command is not limited in the number of names that it
3686 can return.
3687
3688 =item *
3689
3690 The result list is not sorted.
3691
3692 =back");
3693
3694   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3695    [InitISOFS, Always, TestOutput (
3696       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3697     InitISOFS, Always, TestOutput (
3698       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3699     InitISOFS, Always, TestOutput (
3700       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3701     InitISOFS, Always, TestLastFail (
3702       [["case_sensitive_path"; "/Known-1/"]]);
3703     InitBasicFS, Always, TestOutput (
3704       [["mkdir"; "/a"];
3705        ["mkdir"; "/a/bbb"];
3706        ["touch"; "/a/bbb/c"];
3707        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3708     InitBasicFS, Always, TestOutput (
3709       [["mkdir"; "/a"];
3710        ["mkdir"; "/a/bbb"];
3711        ["touch"; "/a/bbb/c"];
3712        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3713     InitBasicFS, Always, TestLastFail (
3714       [["mkdir"; "/a"];
3715        ["mkdir"; "/a/bbb"];
3716        ["touch"; "/a/bbb/c"];
3717        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3718    "return true path on case-insensitive filesystem",
3719    "\
3720 This can be used to resolve case insensitive paths on
3721 a filesystem which is case sensitive.  The use case is
3722 to resolve paths which you have read from Windows configuration
3723 files or the Windows Registry, to the true path.
3724
3725 The command handles a peculiarity of the Linux ntfs-3g
3726 filesystem driver (and probably others), which is that although
3727 the underlying filesystem is case-insensitive, the driver
3728 exports the filesystem to Linux as case-sensitive.
3729
3730 One consequence of this is that special directories such
3731 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3732 (or other things) depending on the precise details of how
3733 they were created.  In Windows itself this would not be
3734 a problem.
3735
3736 Bug or feature?  You decide:
3737 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3738
3739 This function resolves the true case of each element in the
3740 path and returns the case-sensitive path.
3741
3742 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3743 might return C<\"/WINDOWS/system32\"> (the exact return value
3744 would depend on details of how the directories were originally
3745 created under Windows).
3746
3747 I<Note>:
3748 This function does not handle drive names, backslashes etc.
3749
3750 See also C<guestfs_realpath>.");
3751
3752   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3753    [InitBasicFS, Always, TestOutput (
3754       [["vfs_type"; "/dev/sda1"]], "ext2")],
3755    "get the Linux VFS type corresponding to a mounted device",
3756    "\
3757 This command gets the block device type corresponding to
3758 a mounted device called C<device>.
3759
3760 Usually the result is the name of the Linux VFS module that
3761 is used to mount this device (probably determined automatically
3762 if you used the C<guestfs_mount> call).");
3763
3764   ("truncate", (RErr, [Pathname "path"]), 199, [],
3765    [InitBasicFS, Always, TestOutputStruct (
3766       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3767        ["truncate"; "/test"];
3768        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3769    "truncate a file to zero size",
3770    "\
3771 This command truncates C<path> to a zero-length file.  The
3772 file must exist already.");
3773
3774   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3775    [InitBasicFS, Always, TestOutputStruct (
3776       [["touch"; "/test"];
3777        ["truncate_size"; "/test"; "1000"];
3778        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3779    "truncate a file to a particular size",
3780    "\
3781 This command truncates C<path> to size C<size> bytes.  The file
3782 must exist already.  If the file is smaller than C<size> then
3783 the file is extended to the required size with null bytes.");
3784
3785   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3786    [InitBasicFS, Always, TestOutputStruct (
3787       [["touch"; "/test"];
3788        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3789        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3790    "set timestamp of a file with nanosecond precision",
3791    "\
3792 This command sets the timestamps of a file with nanosecond
3793 precision.
3794
3795 C<atsecs, atnsecs> are the last access time (atime) in secs and
3796 nanoseconds from the epoch.
3797
3798 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3799 secs and nanoseconds from the epoch.
3800
3801 If the C<*nsecs> field contains the special value C<-1> then
3802 the corresponding timestamp is set to the current time.  (The
3803 C<*secs> field is ignored in this case).
3804
3805 If the C<*nsecs> field contains the special value C<-2> then
3806 the corresponding timestamp is left unchanged.  (The
3807 C<*secs> field is ignored in this case).");
3808
3809   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3810    [InitBasicFS, Always, TestOutputStruct (
3811       [["mkdir_mode"; "/test"; "0o111"];
3812        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3813    "create a directory with a particular mode",
3814    "\
3815 This command creates a directory, setting the initial permissions
3816 of the directory to C<mode>.  See also C<guestfs_mkdir>.");
3817
3818   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3819    [], (* XXX *)
3820    "change file owner and group",
3821    "\
3822 Change the file owner to C<owner> and group to C<group>.
3823 This is like C<guestfs_chown> but if C<path> is a symlink then
3824 the link itself is changed, not the target.
3825
3826 Only numeric uid and gid are supported.  If you want to use
3827 names, you will need to locate and parse the password file
3828 yourself (Augeas support makes this relatively easy).");
3829
3830   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3831    [], (* XXX *)
3832    "lstat on multiple files",
3833    "\
3834 This call allows you to perform the C<guestfs_lstat> operation
3835 on multiple files, where all files are in the directory C<path>.
3836 C<names> is the list of files from this directory.
3837
3838 On return you get a list of stat structs, with a one-to-one
3839 correspondence to the C<names> list.  If any name did not exist
3840 or could not be lstat'd, then the C<ino> field of that structure
3841 is set to C<-1>.
3842
3843 This call is intended for programs that want to efficiently
3844 list a directory contents without making many round-trips.
3845 See also C<guestfs_lxattrlist> for a similarly efficient call
3846 for getting extended attributes.  Very long directory listings
3847 might cause the protocol message size to be exceeded, causing
3848 this call to fail.  The caller must split up such requests
3849 into smaller groups of names.");
3850
3851   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3852    [], (* XXX *)
3853    "lgetxattr on multiple files",
3854    "\
3855 This call allows you to get the extended attributes
3856 of multiple files, where all files are in the directory C<path>.
3857 C<names> is the list of files from this directory.
3858
3859 On return you get a flat list of xattr structs which must be
3860 interpreted sequentially.  The first xattr struct always has a zero-length
3861 C<attrname>.  C<attrval> in this struct is zero-length
3862 to indicate there was an error doing C<lgetxattr> for this
3863 file, I<or> is a C string which is a decimal number
3864 (the number of following attributes for this file, which could
3865 be C<\"0\">).  Then after the first xattr struct are the
3866 zero or more attributes for the first named file.
3867 This repeats for the second and subsequent files.
3868
3869 This call is intended for programs that want to efficiently
3870 list a directory contents without making many round-trips.
3871 See also C<guestfs_lstatlist> for a similarly efficient call
3872 for getting standard stats.  Very long directory listings
3873 might cause the protocol message size to be exceeded, causing
3874 this call to fail.  The caller must split up such requests
3875 into smaller groups of names.");
3876
3877   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
3878    [], (* XXX *)
3879    "readlink on multiple files",
3880    "\
3881 This call allows you to do a C<readlink> operation
3882 on multiple files, where all files are in the directory C<path>.
3883 C<names> is the list of files from this directory.
3884
3885 On return you get a list of strings, with a one-to-one
3886 correspondence to the C<names> list.  Each string is the
3887 value of the symbol link.
3888
3889 If the C<readlink(2)> operation fails on any name, then
3890 the corresponding result string is the empty string C<\"\">.
3891 However the whole operation is completed even if there
3892 were C<readlink(2)> errors, and so you can call this
3893 function with names where you don't know if they are
3894 symbolic links already (albeit slightly less efficient).
3895
3896 This call is intended for programs that want to efficiently
3897 list a directory contents without making many round-trips.
3898 Very long directory listings might cause the protocol
3899 message size to be exceeded, causing
3900 this call to fail.  The caller must split up such requests
3901 into smaller groups of names.");
3902
3903   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
3904    [InitISOFS, Always, TestOutputBuffer (
3905       [["pread"; "/known-4"; "1"; "3"]], "\n");
3906     InitISOFS, Always, TestOutputBuffer (
3907       [["pread"; "/empty"; "0"; "100"]], "")],
3908    "read part of a file",
3909    "\
3910 This command lets you read part of a file.  It reads C<count>
3911 bytes of the file, starting at C<offset>, from file C<path>.
3912
3913 This may read fewer bytes than requested.  For further details
3914 see the L<pread(2)> system call.");
3915
3916   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
3917    [InitEmpty, Always, TestRun (
3918       [["part_init"; "/dev/sda"; "gpt"]])],
3919    "create an empty partition table",
3920    "\
3921 This creates an empty partition table on C<device> of one of the
3922 partition types listed below.  Usually C<parttype> should be
3923 either C<msdos> or C<gpt> (for large disks).
3924
3925 Initially there are no partitions.  Following this, you should
3926 call C<guestfs_part_add> for each partition required.
3927
3928 Possible values for C<parttype> are:
3929
3930 =over 4
3931
3932 =item B<efi> | B<gpt>
3933
3934 Intel EFI / GPT partition table.
3935
3936 This is recommended for >= 2 TB partitions that will be accessed
3937 from Linux and Intel-based Mac OS X.  It also has limited backwards
3938 compatibility with the C<mbr> format.
3939
3940 =item B<mbr> | B<msdos>
3941
3942 The standard PC \"Master Boot Record\" (MBR) format used
3943 by MS-DOS and Windows.  This partition type will B<only> work
3944 for device sizes up to 2 TB.  For large disks we recommend
3945 using C<gpt>.
3946
3947 =back
3948
3949 Other partition table types that may work but are not
3950 supported include:
3951
3952 =over 4
3953
3954 =item B<aix>
3955
3956 AIX disk labels.
3957
3958 =item B<amiga> | B<rdb>
3959
3960 Amiga \"Rigid Disk Block\" format.
3961
3962 =item B<bsd>
3963
3964 BSD disk labels.
3965
3966 =item B<dasd>
3967
3968 DASD, used on IBM mainframes.
3969
3970 =item B<dvh>
3971
3972 MIPS/SGI volumes.
3973
3974 =item B<mac>
3975
3976 Old Mac partition format.  Modern Macs use C<gpt>.
3977
3978 =item B<pc98>
3979
3980 NEC PC-98 format, common in Japan apparently.
3981
3982 =item B<sun>
3983
3984 Sun disk labels.
3985
3986 =back");
3987
3988   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
3989    [InitEmpty, Always, TestRun (
3990       [["part_init"; "/dev/sda"; "mbr"];
3991        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
3992     InitEmpty, Always, TestRun (
3993       [["part_init"; "/dev/sda"; "gpt"];
3994        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
3995        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
3996     InitEmpty, Always, TestRun (
3997       [["part_init"; "/dev/sda"; "mbr"];
3998        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
3999        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4000        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4001        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4002    "add a partition to the device",
4003    "\
4004 This command adds a partition to C<device>.  If there is no partition
4005 table on the device, call C<guestfs_part_init> first.
4006
4007 The C<prlogex> parameter is the type of partition.  Normally you
4008 should pass C<p> or C<primary> here, but MBR partition tables also
4009 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4010 types.
4011
4012 C<startsect> and C<endsect> are the start and end of the partition
4013 in I<sectors>.  C<endsect> may be negative, which means it counts
4014 backwards from the end of the disk (C<-1> is the last sector).
4015
4016 Creating a partition which covers the whole disk is not so easy.
4017 Use C<guestfs_part_disk> to do that.");
4018
4019   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4020    [InitEmpty, Always, TestRun (
4021       [["part_disk"; "/dev/sda"; "mbr"]]);
4022     InitEmpty, Always, TestRun (
4023       [["part_disk"; "/dev/sda"; "gpt"]])],
4024    "partition whole disk with a single primary partition",
4025    "\
4026 This command is simply a combination of C<guestfs_part_init>
4027 followed by C<guestfs_part_add> to create a single primary partition
4028 covering the whole disk.
4029
4030 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4031 but other possible values are described in C<guestfs_part_init>.");
4032
4033   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4034    [InitEmpty, Always, TestRun (
4035       [["part_disk"; "/dev/sda"; "mbr"];
4036        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4037    "make a partition bootable",
4038    "\
4039 This sets the bootable flag on partition numbered C<partnum> on
4040 device C<device>.  Note that partitions are numbered from 1.
4041
4042 The bootable flag is used by some PC BIOSes to determine which
4043 partition to boot from.  It is by no means universally recognized,
4044 and in any case if your operating system installed a boot
4045 sector on the device itself, then that takes precedence.");
4046
4047   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4048    [InitEmpty, Always, TestRun (
4049       [["part_disk"; "/dev/sda"; "gpt"];
4050        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4051    "set partition name",
4052    "\
4053 This sets the partition name on partition numbered C<partnum> on
4054 device C<device>.  Note that partitions are numbered from 1.
4055
4056 The partition name can only be set on certain types of partition
4057 table.  This works on C<gpt> but not on C<mbr> partitions.");
4058
4059   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4060    [], (* XXX Add a regression test for this. *)
4061    "list partitions on a device",
4062    "\
4063 This command parses the partition table on C<device> and
4064 returns the list of partitions found.
4065
4066 The fields in the returned structure are:
4067
4068 =over 4
4069
4070 =item B<part_num>
4071
4072 Partition number, counting from 1.
4073
4074 =item B<part_start>
4075
4076 Start of the partition I<in bytes>.  To get sectors you have to
4077 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4078
4079 =item B<part_end>
4080
4081 End of the partition in bytes.
4082
4083 =item B<part_size>
4084
4085 Size of the partition in bytes.
4086
4087 =back");
4088
4089   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4090    [InitEmpty, Always, TestOutput (
4091       [["part_disk"; "/dev/sda"; "gpt"];
4092        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4093    "get the partition table type",
4094    "\
4095 This command examines the partition table on C<device> and
4096 returns the partition table type (format) being used.
4097
4098 Common return values include: C<msdos> (a DOS/Windows style MBR
4099 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4100 values are possible, although unusual.  See C<guestfs_part_init>
4101 for a full list.");
4102
4103   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4104    [InitBasicFS, Always, TestOutputBuffer (
4105       [["fill"; "0x63"; "10"; "/test"];
4106        ["read_file"; "/test"]], "cccccccccc")],
4107    "fill a file with octets",
4108    "\
4109 This command creates a new file called C<path>.  The initial
4110 content of the file is C<len> octets of C<c>, where C<c>
4111 must be a number in the range C<[0..255]>.
4112
4113 To fill a file with zero bytes (sparsely), it is
4114 much more efficient to use C<guestfs_truncate_size>.");
4115
4116   ("available", (RErr, [StringList "groups"]), 216, [],
4117    [InitNone, Always, TestRun [["available"; ""]]],
4118    "test availability of some parts of the API",
4119    "\
4120 This command is used to check the availability of some
4121 groups of functionality in the appliance, which not all builds of
4122 the libguestfs appliance will be able to provide.
4123
4124 The libguestfs groups, and the functions that those
4125 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4126
4127 The argument C<groups> is a list of group names, eg:
4128 C<[\"inotify\", \"augeas\"]> would check for the availability of
4129 the Linux inotify functions and Augeas (configuration file
4130 editing) functions.
4131
4132 The command returns no error if I<all> requested groups are available.
4133
4134 It fails with an error if one or more of the requested
4135 groups is unavailable in the appliance.
4136
4137 If an unknown group name is included in the
4138 list of groups then an error is always returned.
4139
4140 I<Notes:>
4141
4142 =over 4
4143
4144 =item *
4145
4146 You must call C<guestfs_launch> before calling this function.
4147
4148 The reason is because we don't know what groups are
4149 supported by the appliance/daemon until it is running and can
4150 be queried.
4151
4152 =item *
4153
4154 If a group of functions is available, this does not necessarily
4155 mean that they will work.  You still have to check for errors
4156 when calling individual API functions even if they are
4157 available.
4158
4159 =item *
4160
4161 It is usually the job of distro packagers to build
4162 complete functionality into the libguestfs appliance.
4163 Upstream libguestfs, if built from source with all
4164 requirements satisfied, will support everything.
4165
4166 =item *
4167
4168 This call was added in version C<1.0.80>.  In previous
4169 versions of libguestfs all you could do would be to speculatively
4170 execute a command to find out if the daemon implemented it.
4171 See also C<guestfs_version>.
4172
4173 =back");
4174
4175   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4176    [InitBasicFS, Always, TestOutputBuffer (
4177       [["write_file"; "/src"; "hello, world"; "0"];
4178        ["dd"; "/src"; "/dest"];
4179        ["read_file"; "/dest"]], "hello, world")],
4180    "copy from source to destination using dd",
4181    "\
4182 This command copies from one source device or file C<src>
4183 to another destination device or file C<dest>.  Normally you
4184 would use this to copy to or from a device or partition, for
4185 example to duplicate a filesystem.
4186
4187 If the destination is a device, it must be as large or larger
4188 than the source file or device, otherwise the copy will fail.
4189 This command cannot do partial copies.");
4190
4191   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4192    [InitBasicFS, Always, TestOutputInt (
4193       [["write_file"; "/file"; "hello, world"; "0"];
4194        ["filesize"; "/file"]], 12)],
4195    "return the size of the file in bytes",
4196    "\
4197 This command returns the size of C<file> in bytes.
4198
4199 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4200 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4201 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4202
4203 ]
4204
4205 let all_functions = non_daemon_functions @ daemon_functions
4206
4207 (* In some places we want the functions to be displayed sorted
4208  * alphabetically, so this is useful:
4209  *)
4210 let all_functions_sorted =
4211   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4212                compare n1 n2) all_functions
4213
4214 (* Field types for structures. *)
4215 type field =
4216   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4217   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4218   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4219   | FUInt32
4220   | FInt32
4221   | FUInt64
4222   | FInt64
4223   | FBytes                      (* Any int measure that counts bytes. *)
4224   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4225   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4226
4227 (* Because we generate extra parsing code for LVM command line tools,
4228  * we have to pull out the LVM columns separately here.
4229  *)
4230 let lvm_pv_cols = [
4231   "pv_name", FString;
4232   "pv_uuid", FUUID;
4233   "pv_fmt", FString;
4234   "pv_size", FBytes;
4235   "dev_size", FBytes;
4236   "pv_free", FBytes;
4237   "pv_used", FBytes;
4238   "pv_attr", FString (* XXX *);
4239   "pv_pe_count", FInt64;
4240   "pv_pe_alloc_count", FInt64;
4241   "pv_tags", FString;
4242   "pe_start", FBytes;
4243   "pv_mda_count", FInt64;
4244   "pv_mda_free", FBytes;
4245   (* Not in Fedora 10:
4246      "pv_mda_size", FBytes;
4247   *)
4248 ]
4249 let lvm_vg_cols = [
4250   "vg_name", FString;
4251   "vg_uuid", FUUID;
4252   "vg_fmt", FString;
4253   "vg_attr", FString (* XXX *);
4254   "vg_size", FBytes;
4255   "vg_free", FBytes;
4256   "vg_sysid", FString;
4257   "vg_extent_size", FBytes;
4258   "vg_extent_count", FInt64;
4259   "vg_free_count", FInt64;
4260   "max_lv", FInt64;
4261   "max_pv", FInt64;
4262   "pv_count", FInt64;
4263   "lv_count", FInt64;
4264   "snap_count", FInt64;
4265   "vg_seqno", FInt64;
4266   "vg_tags", FString;
4267   "vg_mda_count", FInt64;
4268   "vg_mda_free", FBytes;
4269   (* Not in Fedora 10:
4270      "vg_mda_size", FBytes;
4271   *)
4272 ]
4273 let lvm_lv_cols = [
4274   "lv_name", FString;
4275   "lv_uuid", FUUID;
4276   "lv_attr", FString (* XXX *);
4277   "lv_major", FInt64;
4278   "lv_minor", FInt64;
4279   "lv_kernel_major", FInt64;
4280   "lv_kernel_minor", FInt64;
4281   "lv_size", FBytes;
4282   "seg_count", FInt64;
4283   "origin", FString;
4284   "snap_percent", FOptPercent;
4285   "copy_percent", FOptPercent;
4286   "move_pv", FString;
4287   "lv_tags", FString;
4288   "mirror_log", FString;
4289   "modules", FString;
4290 ]
4291
4292 (* Names and fields in all structures (in RStruct and RStructList)
4293  * that we support.
4294  *)
4295 let structs = [
4296   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4297    * not use this struct in any new code.
4298    *)
4299   "int_bool", [
4300     "i", FInt32;                (* for historical compatibility *)
4301     "b", FInt32;                (* for historical compatibility *)
4302   ];
4303
4304   (* LVM PVs, VGs, LVs. *)
4305   "lvm_pv", lvm_pv_cols;
4306   "lvm_vg", lvm_vg_cols;
4307   "lvm_lv", lvm_lv_cols;
4308
4309   (* Column names and types from stat structures.
4310    * NB. Can't use things like 'st_atime' because glibc header files
4311    * define some of these as macros.  Ugh.
4312    *)
4313   "stat", [
4314     "dev", FInt64;
4315     "ino", FInt64;
4316     "mode", FInt64;
4317     "nlink", FInt64;
4318     "uid", FInt64;
4319     "gid", FInt64;
4320     "rdev", FInt64;
4321     "size", FInt64;
4322     "blksize", FInt64;
4323     "blocks", FInt64;
4324     "atime", FInt64;
4325     "mtime", FInt64;
4326     "ctime", FInt64;
4327   ];
4328   "statvfs", [
4329     "bsize", FInt64;
4330     "frsize", FInt64;
4331     "blocks", FInt64;
4332     "bfree", FInt64;
4333     "bavail", FInt64;
4334     "files", FInt64;
4335     "ffree", FInt64;
4336     "favail", FInt64;
4337     "fsid", FInt64;
4338     "flag", FInt64;
4339     "namemax", FInt64;
4340   ];
4341
4342   (* Column names in dirent structure. *)
4343   "dirent", [
4344     "ino", FInt64;
4345     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4346     "ftyp", FChar;
4347     "name", FString;
4348   ];
4349
4350   (* Version numbers. *)
4351   "version", [
4352     "major", FInt64;
4353     "minor", FInt64;
4354     "release", FInt64;
4355     "extra", FString;
4356   ];
4357
4358   (* Extended attribute. *)
4359   "xattr", [
4360     "attrname", FString;
4361     "attrval", FBuffer;
4362   ];
4363
4364   (* Inotify events. *)
4365   "inotify_event", [
4366     "in_wd", FInt64;
4367     "in_mask", FUInt32;
4368     "in_cookie", FUInt32;
4369     "in_name", FString;
4370   ];
4371
4372   (* Partition table entry. *)
4373   "partition", [
4374     "part_num", FInt32;
4375     "part_start", FBytes;
4376     "part_end", FBytes;
4377     "part_size", FBytes;
4378   ];
4379 ] (* end of structs *)
4380
4381 (* Ugh, Java has to be different ..
4382  * These names are also used by the Haskell bindings.
4383  *)
4384 let java_structs = [
4385   "int_bool", "IntBool";
4386   "lvm_pv", "PV";
4387   "lvm_vg", "VG";
4388   "lvm_lv", "LV";
4389   "stat", "Stat";
4390   "statvfs", "StatVFS";
4391   "dirent", "Dirent";
4392   "version", "Version";
4393   "xattr", "XAttr";
4394   "inotify_event", "INotifyEvent";
4395   "partition", "Partition";
4396 ]
4397
4398 (* What structs are actually returned. *)
4399 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4400
4401 (* Returns a list of RStruct/RStructList structs that are returned
4402  * by any function.  Each element of returned list is a pair:
4403  *
4404  * (structname, RStructOnly)
4405  *    == there exists function which returns RStruct (_, structname)
4406  * (structname, RStructListOnly)
4407  *    == there exists function which returns RStructList (_, structname)
4408  * (structname, RStructAndList)
4409  *    == there are functions returning both RStruct (_, structname)
4410  *                                      and RStructList (_, structname)
4411  *)
4412 let rstructs_used_by functions =
4413   (* ||| is a "logical OR" for rstructs_used_t *)
4414   let (|||) a b =
4415     match a, b with
4416     | RStructAndList, _
4417     | _, RStructAndList -> RStructAndList
4418     | RStructOnly, RStructListOnly
4419     | RStructListOnly, RStructOnly -> RStructAndList
4420     | RStructOnly, RStructOnly -> RStructOnly
4421     | RStructListOnly, RStructListOnly -> RStructListOnly
4422   in
4423
4424   let h = Hashtbl.create 13 in
4425
4426   (* if elem->oldv exists, update entry using ||| operator,
4427    * else just add elem->newv to the hash
4428    *)
4429   let update elem newv =
4430     try  let oldv = Hashtbl.find h elem in
4431          Hashtbl.replace h elem (newv ||| oldv)
4432     with Not_found -> Hashtbl.add h elem newv
4433   in
4434
4435   List.iter (
4436     fun (_, style, _, _, _, _, _) ->
4437       match fst style with
4438       | RStruct (_, structname) -> update structname RStructOnly
4439       | RStructList (_, structname) -> update structname RStructListOnly
4440       | _ -> ()
4441   ) functions;
4442
4443   (* return key->values as a list of (key,value) *)
4444   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4445
4446 (* Used for testing language bindings. *)
4447 type callt =
4448   | CallString of string
4449   | CallOptString of string option
4450   | CallStringList of string list
4451   | CallInt of int
4452   | CallInt64 of int64
4453   | CallBool of bool
4454
4455 (* Used to memoize the result of pod2text. *)
4456 let pod2text_memo_filename = "src/.pod2text.data"
4457 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4458   try
4459     let chan = open_in pod2text_memo_filename in
4460     let v = input_value chan in
4461     close_in chan;
4462     v
4463   with
4464     _ -> Hashtbl.create 13
4465 let pod2text_memo_updated () =
4466   let chan = open_out pod2text_memo_filename in
4467   output_value chan pod2text_memo;
4468   close_out chan
4469
4470 (* Useful functions.
4471  * Note we don't want to use any external OCaml libraries which
4472  * makes this a bit harder than it should be.
4473  *)
4474 module StringMap = Map.Make (String)
4475
4476 let failwithf fs = ksprintf failwith fs
4477
4478 let unique = let i = ref 0 in fun () -> incr i; !i
4479
4480 let replace_char s c1 c2 =
4481   let s2 = String.copy s in
4482   let r = ref false in
4483   for i = 0 to String.length s2 - 1 do
4484     if String.unsafe_get s2 i = c1 then (
4485       String.unsafe_set s2 i c2;
4486       r := true
4487     )
4488   done;
4489   if not !r then s else s2
4490
4491 let isspace c =
4492   c = ' '
4493   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4494
4495 let triml ?(test = isspace) str =
4496   let i = ref 0 in
4497   let n = ref (String.length str) in
4498   while !n > 0 && test str.[!i]; do
4499     decr n;
4500     incr i
4501   done;
4502   if !i = 0 then str
4503   else String.sub str !i !n
4504
4505 let trimr ?(test = isspace) str =
4506   let n = ref (String.length str) in
4507   while !n > 0 && test str.[!n-1]; do
4508     decr n
4509   done;
4510   if !n = String.length str then str
4511   else String.sub str 0 !n
4512
4513 let trim ?(test = isspace) str =
4514   trimr ~test (triml ~test str)
4515
4516 let rec find s sub =
4517   let len = String.length s in
4518   let sublen = String.length sub in
4519   let rec loop i =
4520     if i <= len-sublen then (
4521       let rec loop2 j =
4522         if j < sublen then (
4523           if s.[i+j] = sub.[j] then loop2 (j+1)
4524           else -1
4525         ) else
4526           i (* found *)
4527       in
4528       let r = loop2 0 in
4529       if r = -1 then loop (i+1) else r
4530     ) else
4531       -1 (* not found *)
4532   in
4533   loop 0
4534
4535 let rec replace_str s s1 s2 =
4536   let len = String.length s in
4537   let sublen = String.length s1 in
4538   let i = find s s1 in
4539   if i = -1 then s
4540   else (
4541     let s' = String.sub s 0 i in
4542     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4543     s' ^ s2 ^ replace_str s'' s1 s2
4544   )
4545
4546 let rec string_split sep str =
4547   let len = String.length str in
4548   let seplen = String.length sep in
4549   let i = find str sep in
4550   if i = -1 then [str]
4551   else (
4552     let s' = String.sub str 0 i in
4553     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4554     s' :: string_split sep s''
4555   )
4556
4557 let files_equal n1 n2 =
4558   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4559   match Sys.command cmd with
4560   | 0 -> true
4561   | 1 -> false
4562   | i -> failwithf "%s: failed with error code %d" cmd i
4563
4564 let rec filter_map f = function
4565   | [] -> []
4566   | x :: xs ->
4567       match f x with
4568       | Some y -> y :: filter_map f xs
4569       | None -> filter_map f xs
4570
4571 let rec find_map f = function
4572   | [] -> raise Not_found
4573   | x :: xs ->
4574       match f x with
4575       | Some y -> y
4576       | None -> find_map f xs
4577
4578 let iteri f xs =
4579   let rec loop i = function
4580     | [] -> ()
4581     | x :: xs -> f i x; loop (i+1) xs
4582   in
4583   loop 0 xs
4584
4585 let mapi f xs =
4586   let rec loop i = function
4587     | [] -> []
4588     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4589   in
4590   loop 0 xs
4591
4592 let count_chars c str =
4593   let count = ref 0 in
4594   for i = 0 to String.length str - 1 do
4595     if c = String.unsafe_get str i then incr count
4596   done;
4597   !count
4598
4599 let name_of_argt = function
4600   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4601   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4602   | FileIn n | FileOut n -> n
4603
4604 let java_name_of_struct typ =
4605   try List.assoc typ java_structs
4606   with Not_found ->
4607     failwithf
4608       "java_name_of_struct: no java_structs entry corresponding to %s" typ
4609
4610 let cols_of_struct typ =
4611   try List.assoc typ structs
4612   with Not_found ->
4613     failwithf "cols_of_struct: unknown struct %s" typ
4614
4615 let seq_of_test = function
4616   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
4617   | TestOutputListOfDevices (s, _)
4618   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
4619   | TestOutputTrue s | TestOutputFalse s
4620   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
4621   | TestOutputStruct (s, _)
4622   | TestLastFail s -> s
4623
4624 (* Handling for function flags. *)
4625 let protocol_limit_warning =
4626   "Because of the message protocol, there is a transfer limit
4627 of somewhere between 2MB and 4MB.  To transfer large files you should use
4628 FTP."
4629
4630 let danger_will_robinson =
4631   "B<This command is dangerous.  Without careful use you
4632 can easily destroy all your data>."
4633
4634 let deprecation_notice flags =
4635   try
4636     let alt =
4637       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
4638     let txt =
4639       sprintf "This function is deprecated.
4640 In new code, use the C<%s> call instead.
4641
4642 Deprecated functions will not be removed from the API, but the
4643 fact that they are deprecated indicates that there are problems
4644 with correct use of these functions." alt in
4645     Some txt
4646   with
4647     Not_found -> None
4648
4649 (* Create list of optional groups. *)
4650 let optgroups =
4651   let h = Hashtbl.create 13 in
4652   List.iter (
4653     fun (name, _, _, flags, _, _, _) ->
4654       List.iter (
4655         function
4656         | Optional group ->
4657             let names = try Hashtbl.find h group with Not_found -> [] in
4658             Hashtbl.replace h group (name :: names)
4659         | _ -> ()
4660       ) flags
4661   ) daemon_functions;
4662   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
4663   let groups =
4664     List.map (
4665       fun group -> group, List.sort compare (Hashtbl.find h group)
4666     ) groups in
4667   List.sort (fun x y -> compare (fst x) (fst y)) groups
4668
4669 (* Check function names etc. for consistency. *)
4670 let check_functions () =
4671   let contains_uppercase str =
4672     let len = String.length str in
4673     let rec loop i =
4674       if i >= len then false
4675       else (
4676         let c = str.[i] in
4677         if c >= 'A' && c <= 'Z' then true
4678         else loop (i+1)
4679       )
4680     in
4681     loop 0
4682   in
4683
4684   (* Check function names. *)
4685   List.iter (
4686     fun (name, _, _, _, _, _, _) ->
4687       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
4688         failwithf "function name %s does not need 'guestfs' prefix" name;
4689       if name = "" then
4690         failwithf "function name is empty";
4691       if name.[0] < 'a' || name.[0] > 'z' then
4692         failwithf "function name %s must start with lowercase a-z" name;
4693       if String.contains name '-' then
4694         failwithf "function name %s should not contain '-', use '_' instead."
4695           name
4696   ) all_functions;
4697
4698   (* Check function parameter/return names. *)
4699   List.iter (
4700     fun (name, style, _, _, _, _, _) ->
4701       let check_arg_ret_name n =
4702         if contains_uppercase n then
4703           failwithf "%s param/ret %s should not contain uppercase chars"
4704             name n;
4705         if String.contains n '-' || String.contains n '_' then
4706           failwithf "%s param/ret %s should not contain '-' or '_'"
4707             name n;
4708         if n = "value" then
4709           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;
4710         if n = "int" || n = "char" || n = "short" || n = "long" then
4711           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
4712         if n = "i" || n = "n" then
4713           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
4714         if n = "argv" || n = "args" then
4715           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
4716
4717         (* List Haskell, OCaml and C keywords here.
4718          * http://www.haskell.org/haskellwiki/Keywords
4719          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
4720          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
4721          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
4722          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
4723          * Omitting _-containing words, since they're handled above.
4724          * Omitting the OCaml reserved word, "val", is ok,
4725          * and saves us from renaming several parameters.
4726          *)
4727         let reserved = [
4728           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
4729           "char"; "class"; "const"; "constraint"; "continue"; "data";
4730           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
4731           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
4732           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
4733           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
4734           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
4735           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
4736           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
4737           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
4738           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
4739           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
4740           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
4741           "volatile"; "when"; "where"; "while";
4742           ] in
4743         if List.mem n reserved then
4744           failwithf "%s has param/ret using reserved word %s" name n;
4745       in
4746
4747       (match fst style with
4748        | RErr -> ()
4749        | RInt n | RInt64 n | RBool n
4750        | RConstString n | RConstOptString n | RString n
4751        | RStringList n | RStruct (n, _) | RStructList (n, _)
4752        | RHashtable n | RBufferOut n ->
4753            check_arg_ret_name n
4754       );
4755       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
4756   ) all_functions;
4757
4758   (* Check short descriptions. *)
4759   List.iter (
4760     fun (name, _, _, _, _, shortdesc, _) ->
4761       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
4762         failwithf "short description of %s should begin with lowercase." name;
4763       let c = shortdesc.[String.length shortdesc-1] in
4764       if c = '\n' || c = '.' then
4765         failwithf "short description of %s should not end with . or \\n." name
4766   ) all_functions;
4767
4768   (* Check long dscriptions. *)
4769   List.iter (
4770     fun (name, _, _, _, _, _, longdesc) ->
4771       if longdesc.[String.length longdesc-1] = '\n' then
4772         failwithf "long description of %s should not end with \\n." name
4773   ) all_functions;
4774
4775   (* Check proc_nrs. *)
4776   List.iter (
4777     fun (name, _, proc_nr, _, _, _, _) ->
4778       if proc_nr <= 0 then
4779         failwithf "daemon function %s should have proc_nr > 0" name
4780   ) daemon_functions;
4781
4782   List.iter (
4783     fun (name, _, proc_nr, _, _, _, _) ->
4784       if proc_nr <> -1 then
4785         failwithf "non-daemon function %s should have proc_nr -1" name
4786   ) non_daemon_functions;
4787
4788   let proc_nrs =
4789     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
4790       daemon_functions in
4791   let proc_nrs =
4792     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
4793   let rec loop = function
4794     | [] -> ()
4795     | [_] -> ()
4796     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
4797         loop rest
4798     | (name1,nr1) :: (name2,nr2) :: _ ->
4799         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
4800           name1 name2 nr1 nr2
4801   in
4802   loop proc_nrs;
4803
4804   (* Check tests. *)
4805   List.iter (
4806     function
4807       (* Ignore functions that have no tests.  We generate a
4808        * warning when the user does 'make check' instead.
4809        *)
4810     | name, _, _, _, [], _, _ -> ()
4811     | name, _, _, _, tests, _, _ ->
4812         let funcs =
4813           List.map (
4814             fun (_, _, test) ->
4815               match seq_of_test test with
4816               | [] ->
4817                   failwithf "%s has a test containing an empty sequence" name
4818               | cmds -> List.map List.hd cmds
4819           ) tests in
4820         let funcs = List.flatten funcs in
4821
4822         let tested = List.mem name funcs in
4823
4824         if not tested then
4825           failwithf "function %s has tests but does not test itself" name
4826   ) all_functions
4827
4828 (* 'pr' prints to the current output file. *)
4829 let chan = ref Pervasives.stdout
4830 let lines = ref 0
4831 let pr fs =
4832   ksprintf
4833     (fun str ->
4834        let i = count_chars '\n' str in
4835        lines := !lines + i;
4836        output_string !chan str
4837     ) fs
4838
4839 let copyright_years =
4840   let this_year = 1900 + (localtime (time ())).tm_year in
4841   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
4842
4843 (* Generate a header block in a number of standard styles. *)
4844 type comment_style =
4845     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
4846 type license = GPLv2plus | LGPLv2plus
4847
4848 let generate_header ?(extra_inputs = []) comment license =
4849   let inputs = "src/generator.ml" :: extra_inputs in
4850   let c = match comment with
4851     | CStyle ->         pr "/* "; " *"
4852     | CPlusPlusStyle -> pr "// "; "//"
4853     | HashStyle ->      pr "# ";  "#"
4854     | OCamlStyle ->     pr "(* "; " *"
4855     | HaskellStyle ->   pr "{- "; "  " in
4856   pr "libguestfs generated file\n";
4857   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
4858   List.iter (pr "%s   %s\n" c) inputs;
4859   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
4860   pr "%s\n" c;
4861   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
4862   pr "%s\n" c;
4863   (match license with
4864    | GPLv2plus ->
4865        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
4866        pr "%s it under the terms of the GNU General Public License as published by\n" c;
4867        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
4868        pr "%s (at your option) any later version.\n" c;
4869        pr "%s\n" c;
4870        pr "%s This program is distributed in the hope that it will be useful,\n" c;
4871        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4872        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
4873        pr "%s GNU General Public License for more details.\n" c;
4874        pr "%s\n" c;
4875        pr "%s You should have received a copy of the GNU General Public License along\n" c;
4876        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
4877        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
4878
4879    | LGPLv2plus ->
4880        pr "%s This library is free software; you can redistribute it and/or\n" c;
4881        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
4882        pr "%s License as published by the Free Software Foundation; either\n" c;
4883        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
4884        pr "%s\n" c;
4885        pr "%s This library is distributed in the hope that it will be useful,\n" c;
4886        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4887        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
4888        pr "%s Lesser General Public License for more details.\n" c;
4889        pr "%s\n" c;
4890        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
4891        pr "%s License along with this library; if not, write to the Free Software\n" c;
4892        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
4893   );
4894   (match comment with
4895    | CStyle -> pr " */\n"
4896    | CPlusPlusStyle
4897    | HashStyle -> ()
4898    | OCamlStyle -> pr " *)\n"
4899    | HaskellStyle -> pr "-}\n"
4900   );
4901   pr "\n"
4902
4903 (* Start of main code generation functions below this line. *)
4904
4905 (* Generate the pod documentation for the C API. *)
4906 let rec generate_actions_pod () =
4907   List.iter (
4908     fun (shortname, style, _, flags, _, _, longdesc) ->
4909       if not (List.mem NotInDocs flags) then (
4910         let name = "guestfs_" ^ shortname in
4911         pr "=head2 %s\n\n" name;
4912         pr " ";
4913         generate_prototype ~extern:false ~handle:"handle" name style;
4914         pr "\n\n";
4915         pr "%s\n\n" longdesc;
4916         (match fst style with
4917          | RErr ->
4918              pr "This function returns 0 on success or -1 on error.\n\n"
4919          | RInt _ ->
4920              pr "On error this function returns -1.\n\n"
4921          | RInt64 _ ->
4922              pr "On error this function returns -1.\n\n"
4923          | RBool _ ->
4924              pr "This function returns a C truth value on success or -1 on error.\n\n"
4925          | RConstString _ ->
4926              pr "This function returns a string, or NULL on error.
4927 The string is owned by the guest handle and must I<not> be freed.\n\n"
4928          | RConstOptString _ ->
4929              pr "This function returns a string which may be NULL.
4930 There is way to return an error from this function.
4931 The string is owned by the guest handle and must I<not> be freed.\n\n"
4932          | RString _ ->
4933              pr "This function returns a string, or NULL on error.
4934 I<The caller must free the returned string after use>.\n\n"
4935          | RStringList _ ->
4936              pr "This function returns a NULL-terminated array of strings
4937 (like L<environ(3)>), or NULL if there was an error.
4938 I<The caller must free the strings and the array after use>.\n\n"
4939          | RStruct (_, typ) ->
4940              pr "This function returns a C<struct guestfs_%s *>,
4941 or NULL if there was an error.
4942 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
4943          | RStructList (_, typ) ->
4944              pr "This function returns a C<struct guestfs_%s_list *>
4945 (see E<lt>guestfs-structs.hE<gt>),
4946 or NULL if there was an error.
4947 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
4948          | RHashtable _ ->
4949              pr "This function returns a NULL-terminated array of
4950 strings, or NULL if there was an error.
4951 The array of strings will always have length C<2n+1>, where
4952 C<n> keys and values alternate, followed by the trailing NULL entry.
4953 I<The caller must free the strings and the array after use>.\n\n"
4954          | RBufferOut _ ->
4955              pr "This function returns a buffer, or NULL on error.
4956 The size of the returned buffer is written to C<*size_r>.
4957 I<The caller must free the returned buffer after use>.\n\n"
4958         );
4959         if List.mem ProtocolLimitWarning flags then
4960           pr "%s\n\n" protocol_limit_warning;
4961         if List.mem DangerWillRobinson flags then
4962           pr "%s\n\n" danger_will_robinson;
4963         match deprecation_notice flags with
4964         | None -> ()
4965         | Some txt -> pr "%s\n\n" txt
4966       )
4967   ) all_functions_sorted
4968
4969 and generate_structs_pod () =
4970   (* Structs documentation. *)
4971   List.iter (
4972     fun (typ, cols) ->
4973       pr "=head2 guestfs_%s\n" typ;
4974       pr "\n";
4975       pr " struct guestfs_%s {\n" typ;
4976       List.iter (
4977         function
4978         | name, FChar -> pr "   char %s;\n" name
4979         | name, FUInt32 -> pr "   uint32_t %s;\n" name
4980         | name, FInt32 -> pr "   int32_t %s;\n" name
4981         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
4982         | name, FInt64 -> pr "   int64_t %s;\n" name
4983         | name, FString -> pr "   char *%s;\n" name
4984         | name, FBuffer ->
4985             pr "   /* The next two fields describe a byte array. */\n";
4986             pr "   uint32_t %s_len;\n" name;
4987             pr "   char *%s;\n" name
4988         | name, FUUID ->
4989             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
4990             pr "   char %s[32];\n" name
4991         | name, FOptPercent ->
4992             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
4993             pr "   float %s;\n" name
4994       ) cols;
4995       pr " };\n";
4996       pr " \n";
4997       pr " struct guestfs_%s_list {\n" typ;
4998       pr "   uint32_t len; /* Number of elements in list. */\n";
4999       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5000       pr " };\n";
5001       pr " \n";
5002       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5003       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5004         typ typ;
5005       pr "\n"
5006   ) structs
5007
5008 and generate_availability_pod () =
5009   (* Availability documentation. *)
5010   pr "=over 4\n";
5011   pr "\n";
5012   List.iter (
5013     fun (group, functions) ->
5014       pr "=item B<%s>\n" group;
5015       pr "\n";
5016       pr "The following functions:\n";
5017       List.iter (pr "L</guestfs_%s>\n") functions;
5018       pr "\n"
5019   ) optgroups;
5020   pr "=back\n";
5021   pr "\n"
5022
5023 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5024  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5025  *
5026  * We have to use an underscore instead of a dash because otherwise
5027  * rpcgen generates incorrect code.
5028  *
5029  * This header is NOT exported to clients, but see also generate_structs_h.
5030  *)
5031 and generate_xdr () =
5032   generate_header CStyle LGPLv2plus;
5033
5034   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5035   pr "typedef string str<>;\n";
5036   pr "\n";
5037
5038   (* Internal structures. *)
5039   List.iter (
5040     function
5041     | typ, cols ->
5042         pr "struct guestfs_int_%s {\n" typ;
5043         List.iter (function
5044                    | name, FChar -> pr "  char %s;\n" name
5045                    | name, FString -> pr "  string %s<>;\n" name
5046                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5047                    | name, FUUID -> pr "  opaque %s[32];\n" name
5048                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5049                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5050                    | name, FOptPercent -> pr "  float %s;\n" name
5051                   ) cols;
5052         pr "};\n";
5053         pr "\n";
5054         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5055         pr "\n";
5056   ) structs;
5057
5058   List.iter (
5059     fun (shortname, style, _, _, _, _, _) ->
5060       let name = "guestfs_" ^ shortname in
5061
5062       (match snd style with
5063        | [] -> ()
5064        | args ->
5065            pr "struct %s_args {\n" name;
5066            List.iter (
5067              function
5068              | Pathname n | Device n | Dev_or_Path n | String n ->
5069                  pr "  string %s<>;\n" n
5070              | OptString n -> pr "  str *%s;\n" n
5071              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5072              | Bool n -> pr "  bool %s;\n" n
5073              | Int n -> pr "  int %s;\n" n
5074              | Int64 n -> pr "  hyper %s;\n" n
5075              | FileIn _ | FileOut _ -> ()
5076            ) args;
5077            pr "};\n\n"
5078       );
5079       (match fst style with
5080        | RErr -> ()
5081        | RInt n ->
5082            pr "struct %s_ret {\n" name;
5083            pr "  int %s;\n" n;
5084            pr "};\n\n"
5085        | RInt64 n ->
5086            pr "struct %s_ret {\n" name;
5087            pr "  hyper %s;\n" n;
5088            pr "};\n\n"
5089        | RBool n ->
5090            pr "struct %s_ret {\n" name;
5091            pr "  bool %s;\n" n;
5092            pr "};\n\n"
5093        | RConstString _ | RConstOptString _ ->
5094            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5095        | RString n ->
5096            pr "struct %s_ret {\n" name;
5097            pr "  string %s<>;\n" n;
5098            pr "};\n\n"
5099        | RStringList n ->
5100            pr "struct %s_ret {\n" name;
5101            pr "  str %s<>;\n" n;
5102            pr "};\n\n"
5103        | RStruct (n, typ) ->
5104            pr "struct %s_ret {\n" name;
5105            pr "  guestfs_int_%s %s;\n" typ n;
5106            pr "};\n\n"
5107        | RStructList (n, typ) ->
5108            pr "struct %s_ret {\n" name;
5109            pr "  guestfs_int_%s_list %s;\n" typ n;
5110            pr "};\n\n"
5111        | RHashtable n ->
5112            pr "struct %s_ret {\n" name;
5113            pr "  str %s<>;\n" n;
5114            pr "};\n\n"
5115        | RBufferOut n ->
5116            pr "struct %s_ret {\n" name;
5117            pr "  opaque %s<>;\n" n;
5118            pr "};\n\n"
5119       );
5120   ) daemon_functions;
5121
5122   (* Table of procedure numbers. *)
5123   pr "enum guestfs_procedure {\n";
5124   List.iter (
5125     fun (shortname, _, proc_nr, _, _, _, _) ->
5126       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5127   ) daemon_functions;
5128   pr "  GUESTFS_PROC_NR_PROCS\n";
5129   pr "};\n";
5130   pr "\n";
5131
5132   (* Having to choose a maximum message size is annoying for several
5133    * reasons (it limits what we can do in the API), but it (a) makes
5134    * the protocol a lot simpler, and (b) provides a bound on the size
5135    * of the daemon which operates in limited memory space.  For large
5136    * file transfers you should use FTP.
5137    *)
5138   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5139   pr "\n";
5140
5141   (* Message header, etc. *)
5142   pr "\
5143 /* The communication protocol is now documented in the guestfs(3)
5144  * manpage.
5145  */
5146
5147 const GUESTFS_PROGRAM = 0x2000F5F5;
5148 const GUESTFS_PROTOCOL_VERSION = 1;
5149
5150 /* These constants must be larger than any possible message length. */
5151 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5152 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5153
5154 enum guestfs_message_direction {
5155   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5156   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5157 };
5158
5159 enum guestfs_message_status {
5160   GUESTFS_STATUS_OK = 0,
5161   GUESTFS_STATUS_ERROR = 1
5162 };
5163
5164 const GUESTFS_ERROR_LEN = 256;
5165
5166 struct guestfs_message_error {
5167   string error_message<GUESTFS_ERROR_LEN>;
5168 };
5169
5170 struct guestfs_message_header {
5171   unsigned prog;                     /* GUESTFS_PROGRAM */
5172   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5173   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5174   guestfs_message_direction direction;
5175   unsigned serial;                   /* message serial number */
5176   guestfs_message_status status;
5177 };
5178
5179 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5180
5181 struct guestfs_chunk {
5182   int cancel;                        /* if non-zero, transfer is cancelled */
5183   /* data size is 0 bytes if the transfer has finished successfully */
5184   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5185 };
5186 "
5187
5188 (* Generate the guestfs-structs.h file. *)
5189 and generate_structs_h () =
5190   generate_header CStyle LGPLv2plus;
5191
5192   (* This is a public exported header file containing various
5193    * structures.  The structures are carefully written to have
5194    * exactly the same in-memory format as the XDR structures that
5195    * we use on the wire to the daemon.  The reason for creating
5196    * copies of these structures here is just so we don't have to
5197    * export the whole of guestfs_protocol.h (which includes much
5198    * unrelated and XDR-dependent stuff that we don't want to be
5199    * public, or required by clients).
5200    *
5201    * To reiterate, we will pass these structures to and from the
5202    * client with a simple assignment or memcpy, so the format
5203    * must be identical to what rpcgen / the RFC defines.
5204    *)
5205
5206   (* Public structures. *)
5207   List.iter (
5208     fun (typ, cols) ->
5209       pr "struct guestfs_%s {\n" typ;
5210       List.iter (
5211         function
5212         | name, FChar -> pr "  char %s;\n" name
5213         | name, FString -> pr "  char *%s;\n" name
5214         | name, FBuffer ->
5215             pr "  uint32_t %s_len;\n" name;
5216             pr "  char *%s;\n" name
5217         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5218         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5219         | name, FInt32 -> pr "  int32_t %s;\n" name
5220         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5221         | name, FInt64 -> pr "  int64_t %s;\n" name
5222         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5223       ) cols;
5224       pr "};\n";
5225       pr "\n";
5226       pr "struct guestfs_%s_list {\n" typ;
5227       pr "  uint32_t len;\n";
5228       pr "  struct guestfs_%s *val;\n" typ;
5229       pr "};\n";
5230       pr "\n";
5231       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5232       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5233       pr "\n"
5234   ) structs
5235
5236 (* Generate the guestfs-actions.h file. *)
5237 and generate_actions_h () =
5238   generate_header CStyle LGPLv2plus;
5239   List.iter (
5240     fun (shortname, style, _, _, _, _, _) ->
5241       let name = "guestfs_" ^ shortname in
5242       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5243         name style
5244   ) all_functions
5245
5246 (* Generate the guestfs-internal-actions.h file. *)
5247 and generate_internal_actions_h () =
5248   generate_header CStyle LGPLv2plus;
5249   List.iter (
5250     fun (shortname, style, _, _, _, _, _) ->
5251       let name = "guestfs__" ^ shortname in
5252       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5253         name style
5254   ) non_daemon_functions
5255
5256 (* Generate the client-side dispatch stubs. *)
5257 and generate_client_actions () =
5258   generate_header CStyle LGPLv2plus;
5259
5260   pr "\
5261 #include <stdio.h>
5262 #include <stdlib.h>
5263 #include <stdint.h>
5264 #include <inttypes.h>
5265
5266 #include \"guestfs.h\"
5267 #include \"guestfs-internal.h\"
5268 #include \"guestfs-internal-actions.h\"
5269 #include \"guestfs_protocol.h\"
5270
5271 #define error guestfs_error
5272 //#define perrorf guestfs_perrorf
5273 #define safe_malloc guestfs_safe_malloc
5274 #define safe_realloc guestfs_safe_realloc
5275 //#define safe_strdup guestfs_safe_strdup
5276 #define safe_memdup guestfs_safe_memdup
5277
5278 /* Check the return message from a call for validity. */
5279 static int
5280 check_reply_header (guestfs_h *g,
5281                     const struct guestfs_message_header *hdr,
5282                     unsigned int proc_nr, unsigned int serial)
5283 {
5284   if (hdr->prog != GUESTFS_PROGRAM) {
5285     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5286     return -1;
5287   }
5288   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5289     error (g, \"wrong protocol version (%%d/%%d)\",
5290            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5291     return -1;
5292   }
5293   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5294     error (g, \"unexpected message direction (%%d/%%d)\",
5295            hdr->direction, GUESTFS_DIRECTION_REPLY);
5296     return -1;
5297   }
5298   if (hdr->proc != proc_nr) {
5299     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5300     return -1;
5301   }
5302   if (hdr->serial != serial) {
5303     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5304     return -1;
5305   }
5306
5307   return 0;
5308 }
5309
5310 /* Check we are in the right state to run a high-level action. */
5311 static int
5312 check_state (guestfs_h *g, const char *caller)
5313 {
5314   if (!guestfs__is_ready (g)) {
5315     if (guestfs__is_config (g) || guestfs__is_launching (g))
5316       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5317         caller);
5318     else
5319       error (g, \"%%s called from the wrong state, %%d != READY\",
5320         caller, guestfs__get_state (g));
5321     return -1;
5322   }
5323   return 0;
5324 }
5325
5326 ";
5327
5328   (* Generate code to generate guestfish call traces. *)
5329   let trace_call shortname style =
5330     pr "  if (guestfs__get_trace (g)) {\n";
5331
5332     let needs_i =
5333       List.exists (function
5334                    | StringList _ | DeviceList _ -> true
5335                    | _ -> false) (snd style) in
5336     if needs_i then (
5337       pr "    int i;\n";
5338       pr "\n"
5339     );
5340
5341     pr "    printf (\"%s\");\n" shortname;
5342     List.iter (
5343       function
5344       | String n                        (* strings *)
5345       | Device n
5346       | Pathname n
5347       | Dev_or_Path n
5348       | FileIn n
5349       | FileOut n ->
5350           (* guestfish doesn't support string escaping, so neither do we *)
5351           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5352       | OptString n ->                  (* string option *)
5353           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5354           pr "    else printf (\" null\");\n"
5355       | StringList n
5356       | DeviceList n ->                 (* string list *)
5357           pr "    putchar (' ');\n";
5358           pr "    putchar ('\"');\n";
5359           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5360           pr "      if (i > 0) putchar (' ');\n";
5361           pr "      fputs (%s[i], stdout);\n" n;
5362           pr "    }\n";
5363           pr "    putchar ('\"');\n";
5364       | Bool n ->                       (* boolean *)
5365           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5366       | Int n ->                        (* int *)
5367           pr "    printf (\" %%d\", %s);\n" n
5368       | Int64 n ->
5369           pr "    printf (\" %%\" PRIi64, %s);\n" n
5370     ) (snd style);
5371     pr "    putchar ('\\n');\n";
5372     pr "  }\n";
5373     pr "\n";
5374   in
5375
5376   (* For non-daemon functions, generate a wrapper around each function. *)
5377   List.iter (
5378     fun (shortname, style, _, _, _, _, _) ->
5379       let name = "guestfs_" ^ shortname in
5380
5381       generate_prototype ~extern:false ~semicolon:false ~newline:true
5382         ~handle:"g" name style;
5383       pr "{\n";
5384       trace_call shortname style;
5385       pr "  return guestfs__%s " shortname;
5386       generate_c_call_args ~handle:"g" style;
5387       pr ";\n";
5388       pr "}\n";
5389       pr "\n"
5390   ) non_daemon_functions;
5391
5392   (* Client-side stubs for each function. *)
5393   List.iter (
5394     fun (shortname, style, _, _, _, _, _) ->
5395       let name = "guestfs_" ^ shortname in
5396
5397       (* Generate the action stub. *)
5398       generate_prototype ~extern:false ~semicolon:false ~newline:true
5399         ~handle:"g" name style;
5400
5401       let error_code =
5402         match fst style with
5403         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5404         | RConstString _ | RConstOptString _ ->
5405             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5406         | RString _ | RStringList _
5407         | RStruct _ | RStructList _
5408         | RHashtable _ | RBufferOut _ ->
5409             "NULL" in
5410
5411       pr "{\n";
5412
5413       (match snd style with
5414        | [] -> ()
5415        | _ -> pr "  struct %s_args args;\n" name
5416       );
5417
5418       pr "  guestfs_message_header hdr;\n";
5419       pr "  guestfs_message_error err;\n";
5420       let has_ret =
5421         match fst style with
5422         | RErr -> false
5423         | RConstString _ | RConstOptString _ ->
5424             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5425         | RInt _ | RInt64 _
5426         | RBool _ | RString _ | RStringList _
5427         | RStruct _ | RStructList _
5428         | RHashtable _ | RBufferOut _ ->
5429             pr "  struct %s_ret ret;\n" name;
5430             true in
5431
5432       pr "  int serial;\n";
5433       pr "  int r;\n";
5434       pr "\n";
5435       trace_call shortname style;
5436       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
5437       pr "  guestfs___set_busy (g);\n";
5438       pr "\n";
5439
5440       (* Send the main header and arguments. *)
5441       (match snd style with
5442        | [] ->
5443            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5444              (String.uppercase shortname)
5445        | args ->
5446            List.iter (
5447              function
5448              | Pathname n | Device n | Dev_or_Path n | String n ->
5449                  pr "  args.%s = (char *) %s;\n" n n
5450              | OptString n ->
5451                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5452              | StringList n | DeviceList n ->
5453                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5454                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5455              | Bool n ->
5456                  pr "  args.%s = %s;\n" n n
5457              | Int n ->
5458                  pr "  args.%s = %s;\n" n n
5459              | Int64 n ->
5460                  pr "  args.%s = %s;\n" n n
5461              | FileIn _ | FileOut _ -> ()
5462            ) args;
5463            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5464              (String.uppercase shortname);
5465            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5466              name;
5467       );
5468       pr "  if (serial == -1) {\n";
5469       pr "    guestfs___end_busy (g);\n";
5470       pr "    return %s;\n" error_code;
5471       pr "  }\n";
5472       pr "\n";
5473
5474       (* Send any additional files (FileIn) requested. *)
5475       let need_read_reply_label = ref false in
5476       List.iter (
5477         function
5478         | FileIn n ->
5479             pr "  r = guestfs___send_file (g, %s);\n" n;
5480             pr "  if (r == -1) {\n";
5481             pr "    guestfs___end_busy (g);\n";
5482             pr "    return %s;\n" error_code;
5483             pr "  }\n";
5484             pr "  if (r == -2) /* daemon cancelled */\n";
5485             pr "    goto read_reply;\n";
5486             need_read_reply_label := true;
5487             pr "\n";
5488         | _ -> ()
5489       ) (snd style);
5490
5491       (* Wait for the reply from the remote end. *)
5492       if !need_read_reply_label then pr " read_reply:\n";
5493       pr "  memset (&hdr, 0, sizeof hdr);\n";
5494       pr "  memset (&err, 0, sizeof err);\n";
5495       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5496       pr "\n";
5497       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5498       if not has_ret then
5499         pr "NULL, NULL"
5500       else
5501         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5502       pr ");\n";
5503
5504       pr "  if (r == -1) {\n";
5505       pr "    guestfs___end_busy (g);\n";
5506       pr "    return %s;\n" error_code;
5507       pr "  }\n";
5508       pr "\n";
5509
5510       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5511         (String.uppercase shortname);
5512       pr "    guestfs___end_busy (g);\n";
5513       pr "    return %s;\n" error_code;
5514       pr "  }\n";
5515       pr "\n";
5516
5517       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5518       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5519       pr "    free (err.error_message);\n";
5520       pr "    guestfs___end_busy (g);\n";
5521       pr "    return %s;\n" error_code;
5522       pr "  }\n";
5523       pr "\n";
5524
5525       (* Expecting to receive further files (FileOut)? *)
5526       List.iter (
5527         function
5528         | FileOut n ->
5529             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5530             pr "    guestfs___end_busy (g);\n";
5531             pr "    return %s;\n" error_code;
5532             pr "  }\n";
5533             pr "\n";
5534         | _ -> ()
5535       ) (snd style);
5536
5537       pr "  guestfs___end_busy (g);\n";
5538
5539       (match fst style with
5540        | RErr -> pr "  return 0;\n"
5541        | RInt n | RInt64 n | RBool n ->
5542            pr "  return ret.%s;\n" n
5543        | RConstString _ | RConstOptString _ ->
5544            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5545        | RString n ->
5546            pr "  return ret.%s; /* caller will free */\n" n
5547        | RStringList n | RHashtable n ->
5548            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5549            pr "  ret.%s.%s_val =\n" n n;
5550            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5551            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5552              n n;
5553            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5554            pr "  return ret.%s.%s_val;\n" n n
5555        | RStruct (n, _) ->
5556            pr "  /* caller will free this */\n";
5557            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5558        | RStructList (n, _) ->
5559            pr "  /* caller will free this */\n";
5560            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5561        | RBufferOut n ->
5562            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5563            pr "   * _val might be NULL here.  To make the API saner for\n";
5564            pr "   * callers, we turn this case into a unique pointer (using\n";
5565            pr "   * malloc(1)).\n";
5566            pr "   */\n";
5567            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5568            pr "    *size_r = ret.%s.%s_len;\n" n n;
5569            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5570            pr "  } else {\n";
5571            pr "    free (ret.%s.%s_val);\n" n n;
5572            pr "    char *p = safe_malloc (g, 1);\n";
5573            pr "    *size_r = ret.%s.%s_len;\n" n n;
5574            pr "    return p;\n";
5575            pr "  }\n";
5576       );
5577
5578       pr "}\n\n"
5579   ) daemon_functions;
5580
5581   (* Functions to free structures. *)
5582   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5583   pr " * structure format is identical to the XDR format.  See note in\n";
5584   pr " * generator.ml.\n";
5585   pr " */\n";
5586   pr "\n";
5587
5588   List.iter (
5589     fun (typ, _) ->
5590       pr "void\n";
5591       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5592       pr "{\n";
5593       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5594       pr "  free (x);\n";
5595       pr "}\n";
5596       pr "\n";
5597
5598       pr "void\n";
5599       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5600       pr "{\n";
5601       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
5602       pr "  free (x);\n";
5603       pr "}\n";
5604       pr "\n";
5605
5606   ) structs;
5607
5608 (* Generate daemon/actions.h. *)
5609 and generate_daemon_actions_h () =
5610   generate_header CStyle GPLv2plus;
5611
5612   pr "#include \"../src/guestfs_protocol.h\"\n";
5613   pr "\n";
5614
5615   List.iter (
5616     fun (name, style, _, _, _, _, _) ->
5617       generate_prototype
5618         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
5619         name style;
5620   ) daemon_functions
5621
5622 (* Generate the linker script which controls the visibility of
5623  * symbols in the public ABI and ensures no other symbols get
5624  * exported accidentally.
5625  *)
5626 and generate_linker_script () =
5627   generate_header HashStyle GPLv2plus;
5628
5629   let globals = [
5630     "guestfs_create";
5631     "guestfs_close";
5632     "guestfs_get_error_handler";
5633     "guestfs_get_out_of_memory_handler";
5634     "guestfs_last_error";
5635     "guestfs_set_error_handler";
5636     "guestfs_set_launch_done_callback";
5637     "guestfs_set_log_message_callback";
5638     "guestfs_set_out_of_memory_handler";
5639     "guestfs_set_subprocess_quit_callback";
5640
5641     (* Unofficial parts of the API: the bindings code use these
5642      * functions, so it is useful to export them.
5643      *)
5644     "guestfs_safe_calloc";
5645     "guestfs_safe_malloc";
5646   ] in
5647   let functions =
5648     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
5649       all_functions in
5650   let structs =
5651     List.concat (
5652       List.map (fun (typ, _) ->
5653                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
5654         structs
5655     ) in
5656   let globals = List.sort compare (globals @ functions @ structs) in
5657
5658   pr "{\n";
5659   pr "    global:\n";
5660   List.iter (pr "        %s;\n") globals;
5661   pr "\n";
5662
5663   pr "    local:\n";
5664   pr "        *;\n";
5665   pr "};\n"
5666
5667 (* Generate the server-side stubs. *)
5668 and generate_daemon_actions () =
5669   generate_header CStyle GPLv2plus;
5670
5671   pr "#include <config.h>\n";
5672   pr "\n";
5673   pr "#include <stdio.h>\n";
5674   pr "#include <stdlib.h>\n";
5675   pr "#include <string.h>\n";
5676   pr "#include <inttypes.h>\n";
5677   pr "#include <rpc/types.h>\n";
5678   pr "#include <rpc/xdr.h>\n";
5679   pr "\n";
5680   pr "#include \"daemon.h\"\n";
5681   pr "#include \"c-ctype.h\"\n";
5682   pr "#include \"../src/guestfs_protocol.h\"\n";
5683   pr "#include \"actions.h\"\n";
5684   pr "\n";
5685
5686   List.iter (
5687     fun (name, style, _, _, _, _, _) ->
5688       (* Generate server-side stubs. *)
5689       pr "static void %s_stub (XDR *xdr_in)\n" name;
5690       pr "{\n";
5691       let error_code =
5692         match fst style with
5693         | RErr | RInt _ -> pr "  int r;\n"; "-1"
5694         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5695         | RBool _ -> pr "  int r;\n"; "-1"
5696         | RConstString _ | RConstOptString _ ->
5697             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5698         | RString _ -> pr "  char *r;\n"; "NULL"
5699         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5700         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
5701         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
5702         | RBufferOut _ ->
5703             pr "  size_t size = 1;\n";
5704             pr "  char *r;\n";
5705             "NULL" in
5706
5707       (match snd style with
5708        | [] -> ()
5709        | args ->
5710            pr "  struct guestfs_%s_args args;\n" name;
5711            List.iter (
5712              function
5713              | Device n | Dev_or_Path n
5714              | Pathname n
5715              | String n -> ()
5716              | OptString n -> pr "  char *%s;\n" n
5717              | StringList n | DeviceList n -> pr "  char **%s;\n" n
5718              | Bool n -> pr "  int %s;\n" n
5719              | Int n -> pr "  int %s;\n" n
5720              | Int64 n -> pr "  int64_t %s;\n" n
5721              | FileIn _ | FileOut _ -> ()
5722            ) args
5723       );
5724       pr "\n";
5725
5726       (match snd style with
5727        | [] -> ()
5728        | args ->
5729            pr "  memset (&args, 0, sizeof args);\n";
5730            pr "\n";
5731            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
5732            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
5733            pr "    return;\n";
5734            pr "  }\n";
5735            let pr_args n =
5736              pr "  char *%s = args.%s;\n" n n
5737            in
5738            let pr_list_handling_code n =
5739              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
5740              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
5741              pr "  if (%s == NULL) {\n" n;
5742              pr "    reply_with_perror (\"realloc\");\n";
5743              pr "    goto done;\n";
5744              pr "  }\n";
5745              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
5746              pr "  args.%s.%s_val = %s;\n" n n n;
5747            in
5748            List.iter (
5749              function
5750              | Pathname n ->
5751                  pr_args n;
5752                  pr "  ABS_PATH (%s, goto done);\n" n;
5753              | Device n ->
5754                  pr_args n;
5755                  pr "  RESOLVE_DEVICE (%s, goto done);\n" n;
5756              | Dev_or_Path n ->
5757                  pr_args n;
5758                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n;
5759              | String n -> pr_args n
5760              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
5761              | StringList n ->
5762                  pr_list_handling_code n;
5763              | DeviceList n ->
5764                  pr_list_handling_code n;
5765                  pr "  /* Ensure that each is a device,\n";
5766                  pr "   * and perform device name translation. */\n";
5767                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
5768                  pr "    RESOLVE_DEVICE (physvols[pvi], goto done);\n";
5769                  pr "  }\n";
5770              | Bool n -> pr "  %s = args.%s;\n" n n
5771              | Int n -> pr "  %s = args.%s;\n" n n
5772              | Int64 n -> pr "  %s = args.%s;\n" n n
5773              | FileIn _ | FileOut _ -> ()
5774            ) args;
5775            pr "\n"
5776       );
5777
5778
5779       (* this is used at least for do_equal *)
5780       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
5781         (* Emit NEED_ROOT just once, even when there are two or
5782            more Pathname args *)
5783         pr "  NEED_ROOT (goto done);\n";
5784       );
5785
5786       (* Don't want to call the impl with any FileIn or FileOut
5787        * parameters, since these go "outside" the RPC protocol.
5788        *)
5789       let args' =
5790         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
5791           (snd style) in
5792       pr "  r = do_%s " name;
5793       generate_c_call_args (fst style, args');
5794       pr ";\n";
5795
5796       (match fst style with
5797        | RErr | RInt _ | RInt64 _ | RBool _
5798        | RConstString _ | RConstOptString _
5799        | RString _ | RStringList _ | RHashtable _
5800        | RStruct (_, _) | RStructList (_, _) ->
5801            pr "  if (r == %s)\n" error_code;
5802            pr "    /* do_%s has already called reply_with_error */\n" name;
5803            pr "    goto done;\n";
5804            pr "\n"
5805        | RBufferOut _ ->
5806            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
5807            pr "   * an ordinary zero-length buffer), so be careful ...\n";
5808            pr "   */\n";
5809            pr "  if (size == 1 && r == %s)\n" error_code;
5810            pr "    /* do_%s has already called reply_with_error */\n" name;
5811            pr "    goto done;\n";
5812            pr "\n"
5813       );
5814
5815       (* If there are any FileOut parameters, then the impl must
5816        * send its own reply.
5817        *)
5818       let no_reply =
5819         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
5820       if no_reply then
5821         pr "  /* do_%s has already sent a reply */\n" name
5822       else (
5823         match fst style with
5824         | RErr -> pr "  reply (NULL, NULL);\n"
5825         | RInt n | RInt64 n | RBool n ->
5826             pr "  struct guestfs_%s_ret ret;\n" name;
5827             pr "  ret.%s = r;\n" n;
5828             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5829               name
5830         | RConstString _ | RConstOptString _ ->
5831             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5832         | RString n ->
5833             pr "  struct guestfs_%s_ret ret;\n" name;
5834             pr "  ret.%s = r;\n" n;
5835             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5836               name;
5837             pr "  free (r);\n"
5838         | RStringList n | RHashtable n ->
5839             pr "  struct guestfs_%s_ret ret;\n" name;
5840             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
5841             pr "  ret.%s.%s_val = r;\n" n n;
5842             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5843               name;
5844             pr "  free_strings (r);\n"
5845         | RStruct (n, _) ->
5846             pr "  struct guestfs_%s_ret ret;\n" name;
5847             pr "  ret.%s = *r;\n" n;
5848             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5849               name;
5850             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5851               name
5852         | RStructList (n, _) ->
5853             pr "  struct guestfs_%s_ret ret;\n" name;
5854             pr "  ret.%s = *r;\n" n;
5855             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5856               name;
5857             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5858               name
5859         | RBufferOut n ->
5860             pr "  struct guestfs_%s_ret ret;\n" name;
5861             pr "  ret.%s.%s_val = r;\n" n n;
5862             pr "  ret.%s.%s_len = size;\n" n n;
5863             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5864               name;
5865             pr "  free (r);\n"
5866       );
5867
5868       (* Free the args. *)
5869       (match snd style with
5870        | [] ->
5871            pr "done: ;\n";
5872        | _ ->
5873            pr "done:\n";
5874            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
5875              name
5876       );
5877
5878       pr "}\n\n";
5879   ) daemon_functions;
5880
5881   (* Dispatch function. *)
5882   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
5883   pr "{\n";
5884   pr "  switch (proc_nr) {\n";
5885
5886   List.iter (
5887     fun (name, style, _, _, _, _, _) ->
5888       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
5889       pr "      %s_stub (xdr_in);\n" name;
5890       pr "      break;\n"
5891   ) daemon_functions;
5892
5893   pr "    default:\n";
5894   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";
5895   pr "  }\n";
5896   pr "}\n";
5897   pr "\n";
5898
5899   (* LVM columns and tokenization functions. *)
5900   (* XXX This generates crap code.  We should rethink how we
5901    * do this parsing.
5902    *)
5903   List.iter (
5904     function
5905     | typ, cols ->
5906         pr "static const char *lvm_%s_cols = \"%s\";\n"
5907           typ (String.concat "," (List.map fst cols));
5908         pr "\n";
5909
5910         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
5911         pr "{\n";
5912         pr "  char *tok, *p, *next;\n";
5913         pr "  int i, j;\n";
5914         pr "\n";
5915         (*
5916           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
5917           pr "\n";
5918         *)
5919         pr "  if (!str) {\n";
5920         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
5921         pr "    return -1;\n";
5922         pr "  }\n";
5923         pr "  if (!*str || c_isspace (*str)) {\n";
5924         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
5925         pr "    return -1;\n";
5926         pr "  }\n";
5927         pr "  tok = str;\n";
5928         List.iter (
5929           fun (name, coltype) ->
5930             pr "  if (!tok) {\n";
5931             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
5932             pr "    return -1;\n";
5933             pr "  }\n";
5934             pr "  p = strchrnul (tok, ',');\n";
5935             pr "  if (*p) next = p+1; else next = NULL;\n";
5936             pr "  *p = '\\0';\n";
5937             (match coltype with
5938              | FString ->
5939                  pr "  r->%s = strdup (tok);\n" name;
5940                  pr "  if (r->%s == NULL) {\n" name;
5941                  pr "    perror (\"strdup\");\n";
5942                  pr "    return -1;\n";
5943                  pr "  }\n"
5944              | FUUID ->
5945                  pr "  for (i = j = 0; i < 32; ++j) {\n";
5946                  pr "    if (tok[j] == '\\0') {\n";
5947                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
5948                  pr "      return -1;\n";
5949                  pr "    } else if (tok[j] != '-')\n";
5950                  pr "      r->%s[i++] = tok[j];\n" name;
5951                  pr "  }\n";
5952              | FBytes ->
5953                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
5954                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5955                  pr "    return -1;\n";
5956                  pr "  }\n";
5957              | FInt64 ->
5958                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
5959                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5960                  pr "    return -1;\n";
5961                  pr "  }\n";
5962              | FOptPercent ->
5963                  pr "  if (tok[0] == '\\0')\n";
5964                  pr "    r->%s = -1;\n" name;
5965                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
5966                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5967                  pr "    return -1;\n";
5968                  pr "  }\n";
5969              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
5970                  assert false (* can never be an LVM column *)
5971             );
5972             pr "  tok = next;\n";
5973         ) cols;
5974
5975         pr "  if (tok != NULL) {\n";
5976         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
5977         pr "    return -1;\n";
5978         pr "  }\n";
5979         pr "  return 0;\n";
5980         pr "}\n";
5981         pr "\n";
5982
5983         pr "guestfs_int_lvm_%s_list *\n" typ;
5984         pr "parse_command_line_%ss (void)\n" typ;
5985         pr "{\n";
5986         pr "  char *out, *err;\n";
5987         pr "  char *p, *pend;\n";
5988         pr "  int r, i;\n";
5989         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
5990         pr "  void *newp;\n";
5991         pr "\n";
5992         pr "  ret = malloc (sizeof *ret);\n";
5993         pr "  if (!ret) {\n";
5994         pr "    reply_with_perror (\"malloc\");\n";
5995         pr "    return NULL;\n";
5996         pr "  }\n";
5997         pr "\n";
5998         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
5999         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6000         pr "\n";
6001         pr "  r = command (&out, &err,\n";
6002         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
6003         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6004         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6005         pr "  if (r == -1) {\n";
6006         pr "    reply_with_error (\"%%s\", err);\n";
6007         pr "    free (out);\n";
6008         pr "    free (err);\n";
6009         pr "    free (ret);\n";
6010         pr "    return NULL;\n";
6011         pr "  }\n";
6012         pr "\n";
6013         pr "  free (err);\n";
6014         pr "\n";
6015         pr "  /* Tokenize each line of the output. */\n";
6016         pr "  p = out;\n";
6017         pr "  i = 0;\n";
6018         pr "  while (p) {\n";
6019         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6020         pr "    if (pend) {\n";
6021         pr "      *pend = '\\0';\n";
6022         pr "      pend++;\n";
6023         pr "    }\n";
6024         pr "\n";
6025         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6026         pr "      p++;\n";
6027         pr "\n";
6028         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6029         pr "      p = pend;\n";
6030         pr "      continue;\n";
6031         pr "    }\n";
6032         pr "\n";
6033         pr "    /* Allocate some space to store this next entry. */\n";
6034         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6035         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6036         pr "    if (newp == NULL) {\n";
6037         pr "      reply_with_perror (\"realloc\");\n";
6038         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6039         pr "      free (ret);\n";
6040         pr "      free (out);\n";
6041         pr "      return NULL;\n";
6042         pr "    }\n";
6043         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6044         pr "\n";
6045         pr "    /* Tokenize the next entry. */\n";
6046         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6047         pr "    if (r == -1) {\n";
6048         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6049         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6050         pr "      free (ret);\n";
6051         pr "      free (out);\n";
6052         pr "      return NULL;\n";
6053         pr "    }\n";
6054         pr "\n";
6055         pr "    ++i;\n";
6056         pr "    p = pend;\n";
6057         pr "  }\n";
6058         pr "\n";
6059         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6060         pr "\n";
6061         pr "  free (out);\n";
6062         pr "  return ret;\n";
6063         pr "}\n"
6064
6065   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6066
6067 (* Generate a list of function names, for debugging in the daemon.. *)
6068 and generate_daemon_names () =
6069   generate_header CStyle GPLv2plus;
6070
6071   pr "#include <config.h>\n";
6072   pr "\n";
6073   pr "#include \"daemon.h\"\n";
6074   pr "\n";
6075
6076   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6077   pr "const char *function_names[] = {\n";
6078   List.iter (
6079     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6080   ) daemon_functions;
6081   pr "};\n";
6082
6083 (* Generate the optional groups for the daemon to implement
6084  * guestfs_available.
6085  *)
6086 and generate_daemon_optgroups_c () =
6087   generate_header CStyle GPLv2plus;
6088
6089   pr "#include <config.h>\n";
6090   pr "\n";
6091   pr "#include \"daemon.h\"\n";
6092   pr "#include \"optgroups.h\"\n";
6093   pr "\n";
6094
6095   pr "struct optgroup optgroups[] = {\n";
6096   List.iter (
6097     fun (group, _) ->
6098       pr "  { \"%s\", optgroup_%s_available },\n" group group
6099   ) optgroups;
6100   pr "  { NULL, NULL }\n";
6101   pr "};\n"
6102
6103 and generate_daemon_optgroups_h () =
6104   generate_header CStyle GPLv2plus;
6105
6106   List.iter (
6107     fun (group, _) ->
6108       pr "extern int optgroup_%s_available (void);\n" group
6109   ) optgroups
6110
6111 (* Generate the tests. *)
6112 and generate_tests () =
6113   generate_header CStyle GPLv2plus;
6114
6115   pr "\
6116 #include <stdio.h>
6117 #include <stdlib.h>
6118 #include <string.h>
6119 #include <unistd.h>
6120 #include <sys/types.h>
6121 #include <fcntl.h>
6122
6123 #include \"guestfs.h\"
6124 #include \"guestfs-internal.h\"
6125
6126 static guestfs_h *g;
6127 static int suppress_error = 0;
6128
6129 static void print_error (guestfs_h *g, void *data, const char *msg)
6130 {
6131   if (!suppress_error)
6132     fprintf (stderr, \"%%s\\n\", msg);
6133 }
6134
6135 /* FIXME: nearly identical code appears in fish.c */
6136 static void print_strings (char *const *argv)
6137 {
6138   int argc;
6139
6140   for (argc = 0; argv[argc] != NULL; ++argc)
6141     printf (\"\\t%%s\\n\", argv[argc]);
6142 }
6143
6144 /*
6145 static void print_table (char const *const *argv)
6146 {
6147   int i;
6148
6149   for (i = 0; argv[i] != NULL; i += 2)
6150     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6151 }
6152 */
6153
6154 ";
6155
6156   (* Generate a list of commands which are not tested anywhere. *)
6157   pr "static void no_test_warnings (void)\n";
6158   pr "{\n";
6159
6160   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6161   List.iter (
6162     fun (_, _, _, _, tests, _, _) ->
6163       let tests = filter_map (
6164         function
6165         | (_, (Always|If _|Unless _), test) -> Some test
6166         | (_, Disabled, _) -> None
6167       ) tests in
6168       let seq = List.concat (List.map seq_of_test tests) in
6169       let cmds_tested = List.map List.hd seq in
6170       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6171   ) all_functions;
6172
6173   List.iter (
6174     fun (name, _, _, _, _, _, _) ->
6175       if not (Hashtbl.mem hash name) then
6176         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6177   ) all_functions;
6178
6179   pr "}\n";
6180   pr "\n";
6181
6182   (* Generate the actual tests.  Note that we generate the tests
6183    * in reverse order, deliberately, so that (in general) the
6184    * newest tests run first.  This makes it quicker and easier to
6185    * debug them.
6186    *)
6187   let test_names =
6188     List.map (
6189       fun (name, _, _, flags, tests, _, _) ->
6190         mapi (generate_one_test name flags) tests
6191     ) (List.rev all_functions) in
6192   let test_names = List.concat test_names in
6193   let nr_tests = List.length test_names in
6194
6195   pr "\
6196 int main (int argc, char *argv[])
6197 {
6198   char c = 0;
6199   unsigned long int n_failed = 0;
6200   const char *filename;
6201   int fd;
6202   int nr_tests, test_num = 0;
6203
6204   setbuf (stdout, NULL);
6205
6206   no_test_warnings ();
6207
6208   g = guestfs_create ();
6209   if (g == NULL) {
6210     printf (\"guestfs_create FAILED\\n\");
6211     exit (EXIT_FAILURE);
6212   }
6213
6214   guestfs_set_error_handler (g, print_error, NULL);
6215
6216   guestfs_set_path (g, \"../appliance\");
6217
6218   filename = \"test1.img\";
6219   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6220   if (fd == -1) {
6221     perror (filename);
6222     exit (EXIT_FAILURE);
6223   }
6224   if (lseek (fd, %d, SEEK_SET) == -1) {
6225     perror (\"lseek\");
6226     close (fd);
6227     unlink (filename);
6228     exit (EXIT_FAILURE);
6229   }
6230   if (write (fd, &c, 1) == -1) {
6231     perror (\"write\");
6232     close (fd);
6233     unlink (filename);
6234     exit (EXIT_FAILURE);
6235   }
6236   if (close (fd) == -1) {
6237     perror (filename);
6238     unlink (filename);
6239     exit (EXIT_FAILURE);
6240   }
6241   if (guestfs_add_drive (g, filename) == -1) {
6242     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6243     exit (EXIT_FAILURE);
6244   }
6245
6246   filename = \"test2.img\";
6247   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6248   if (fd == -1) {
6249     perror (filename);
6250     exit (EXIT_FAILURE);
6251   }
6252   if (lseek (fd, %d, SEEK_SET) == -1) {
6253     perror (\"lseek\");
6254     close (fd);
6255     unlink (filename);
6256     exit (EXIT_FAILURE);
6257   }
6258   if (write (fd, &c, 1) == -1) {
6259     perror (\"write\");
6260     close (fd);
6261     unlink (filename);
6262     exit (EXIT_FAILURE);
6263   }
6264   if (close (fd) == -1) {
6265     perror (filename);
6266     unlink (filename);
6267     exit (EXIT_FAILURE);
6268   }
6269   if (guestfs_add_drive (g, filename) == -1) {
6270     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6271     exit (EXIT_FAILURE);
6272   }
6273
6274   filename = \"test3.img\";
6275   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6276   if (fd == -1) {
6277     perror (filename);
6278     exit (EXIT_FAILURE);
6279   }
6280   if (lseek (fd, %d, SEEK_SET) == -1) {
6281     perror (\"lseek\");
6282     close (fd);
6283     unlink (filename);
6284     exit (EXIT_FAILURE);
6285   }
6286   if (write (fd, &c, 1) == -1) {
6287     perror (\"write\");
6288     close (fd);
6289     unlink (filename);
6290     exit (EXIT_FAILURE);
6291   }
6292   if (close (fd) == -1) {
6293     perror (filename);
6294     unlink (filename);
6295     exit (EXIT_FAILURE);
6296   }
6297   if (guestfs_add_drive (g, filename) == -1) {
6298     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6299     exit (EXIT_FAILURE);
6300   }
6301
6302   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6303     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6304     exit (EXIT_FAILURE);
6305   }
6306
6307   if (guestfs_launch (g) == -1) {
6308     printf (\"guestfs_launch FAILED\\n\");
6309     exit (EXIT_FAILURE);
6310   }
6311
6312   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6313   alarm (600);
6314
6315   /* Cancel previous alarm. */
6316   alarm (0);
6317
6318   nr_tests = %d;
6319
6320 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6321
6322   iteri (
6323     fun i test_name ->
6324       pr "  test_num++;\n";
6325       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6326       pr "  if (%s () == -1) {\n" test_name;
6327       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6328       pr "    n_failed++;\n";
6329       pr "  }\n";
6330   ) test_names;
6331   pr "\n";
6332
6333   pr "  guestfs_close (g);\n";
6334   pr "  unlink (\"test1.img\");\n";
6335   pr "  unlink (\"test2.img\");\n";
6336   pr "  unlink (\"test3.img\");\n";
6337   pr "\n";
6338
6339   pr "  if (n_failed > 0) {\n";
6340   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6341   pr "    exit (EXIT_FAILURE);\n";
6342   pr "  }\n";
6343   pr "\n";
6344
6345   pr "  exit (EXIT_SUCCESS);\n";
6346   pr "}\n"
6347
6348 and generate_one_test name flags i (init, prereq, test) =
6349   let test_name = sprintf "test_%s_%d" name i in
6350
6351   pr "\
6352 static int %s_skip (void)
6353 {
6354   const char *str;
6355
6356   str = getenv (\"TEST_ONLY\");
6357   if (str)
6358     return strstr (str, \"%s\") == NULL;
6359   str = getenv (\"SKIP_%s\");
6360   if (str && STREQ (str, \"1\")) return 1;
6361   str = getenv (\"SKIP_TEST_%s\");
6362   if (str && STREQ (str, \"1\")) return 1;
6363   return 0;
6364 }
6365
6366 " test_name name (String.uppercase test_name) (String.uppercase name);
6367
6368   (match prereq with
6369    | Disabled | Always -> ()
6370    | If code | Unless code ->
6371        pr "static int %s_prereq (void)\n" test_name;
6372        pr "{\n";
6373        pr "  %s\n" code;
6374        pr "}\n";
6375        pr "\n";
6376   );
6377
6378   pr "\
6379 static int %s (void)
6380 {
6381   if (%s_skip ()) {
6382     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6383     return 0;
6384   }
6385
6386 " test_name test_name test_name;
6387
6388   (* Optional functions should only be tested if the relevant
6389    * support is available in the daemon.
6390    *)
6391   List.iter (
6392     function
6393     | Optional group ->
6394         pr "  {\n";
6395         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6396         pr "    int r;\n";
6397         pr "    suppress_error = 1;\n";
6398         pr "    r = guestfs_available (g, (char **) groups);\n";
6399         pr "    suppress_error = 0;\n";
6400         pr "    if (r == -1) {\n";
6401         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6402         pr "      return 0;\n";
6403         pr "    }\n";
6404         pr "  }\n";
6405     | _ -> ()
6406   ) flags;
6407
6408   (match prereq with
6409    | Disabled ->
6410        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6411    | If _ ->
6412        pr "  if (! %s_prereq ()) {\n" test_name;
6413        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6414        pr "    return 0;\n";
6415        pr "  }\n";
6416        pr "\n";
6417        generate_one_test_body name i test_name init test;
6418    | Unless _ ->
6419        pr "  if (%s_prereq ()) {\n" test_name;
6420        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6421        pr "    return 0;\n";
6422        pr "  }\n";
6423        pr "\n";
6424        generate_one_test_body name i test_name init test;
6425    | Always ->
6426        generate_one_test_body name i test_name init test
6427   );
6428
6429   pr "  return 0;\n";
6430   pr "}\n";
6431   pr "\n";
6432   test_name
6433
6434 and generate_one_test_body name i test_name init test =
6435   (match init with
6436    | InitNone (* XXX at some point, InitNone and InitEmpty became
6437                * folded together as the same thing.  Really we should
6438                * make InitNone do nothing at all, but the tests may
6439                * need to be checked to make sure this is OK.
6440                *)
6441    | InitEmpty ->
6442        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6443        List.iter (generate_test_command_call test_name)
6444          [["blockdev_setrw"; "/dev/sda"];
6445           ["umount_all"];
6446           ["lvm_remove_all"]]
6447    | InitPartition ->
6448        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6449        List.iter (generate_test_command_call test_name)
6450          [["blockdev_setrw"; "/dev/sda"];
6451           ["umount_all"];
6452           ["lvm_remove_all"];
6453           ["part_disk"; "/dev/sda"; "mbr"]]
6454    | InitBasicFS ->
6455        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6456        List.iter (generate_test_command_call test_name)
6457          [["blockdev_setrw"; "/dev/sda"];
6458           ["umount_all"];
6459           ["lvm_remove_all"];
6460           ["part_disk"; "/dev/sda"; "mbr"];
6461           ["mkfs"; "ext2"; "/dev/sda1"];
6462           ["mount"; "/dev/sda1"; "/"]]
6463    | InitBasicFSonLVM ->
6464        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6465          test_name;
6466        List.iter (generate_test_command_call test_name)
6467          [["blockdev_setrw"; "/dev/sda"];
6468           ["umount_all"];
6469           ["lvm_remove_all"];
6470           ["part_disk"; "/dev/sda"; "mbr"];
6471           ["pvcreate"; "/dev/sda1"];
6472           ["vgcreate"; "VG"; "/dev/sda1"];
6473           ["lvcreate"; "LV"; "VG"; "8"];
6474           ["mkfs"; "ext2"; "/dev/VG/LV"];
6475           ["mount"; "/dev/VG/LV"; "/"]]
6476    | InitISOFS ->
6477        pr "  /* InitISOFS for %s */\n" test_name;
6478        List.iter (generate_test_command_call test_name)
6479          [["blockdev_setrw"; "/dev/sda"];
6480           ["umount_all"];
6481           ["lvm_remove_all"];
6482           ["mount_ro"; "/dev/sdd"; "/"]]
6483   );
6484
6485   let get_seq_last = function
6486     | [] ->
6487         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6488           test_name
6489     | seq ->
6490         let seq = List.rev seq in
6491         List.rev (List.tl seq), List.hd seq
6492   in
6493
6494   match test with
6495   | TestRun seq ->
6496       pr "  /* TestRun for %s (%d) */\n" name i;
6497       List.iter (generate_test_command_call test_name) seq
6498   | TestOutput (seq, expected) ->
6499       pr "  /* TestOutput for %s (%d) */\n" name i;
6500       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6501       let seq, last = get_seq_last seq in
6502       let test () =
6503         pr "    if (STRNEQ (r, expected)) {\n";
6504         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6505         pr "      return -1;\n";
6506         pr "    }\n"
6507       in
6508       List.iter (generate_test_command_call test_name) seq;
6509       generate_test_command_call ~test test_name last
6510   | TestOutputList (seq, expected) ->
6511       pr "  /* TestOutputList for %s (%d) */\n" name i;
6512       let seq, last = get_seq_last seq in
6513       let test () =
6514         iteri (
6515           fun i str ->
6516             pr "    if (!r[%d]) {\n" i;
6517             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6518             pr "      print_strings (r);\n";
6519             pr "      return -1;\n";
6520             pr "    }\n";
6521             pr "    {\n";
6522             pr "      const char *expected = \"%s\";\n" (c_quote str);
6523             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6524             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6525             pr "        return -1;\n";
6526             pr "      }\n";
6527             pr "    }\n"
6528         ) expected;
6529         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6530         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6531           test_name;
6532         pr "      print_strings (r);\n";
6533         pr "      return -1;\n";
6534         pr "    }\n"
6535       in
6536       List.iter (generate_test_command_call test_name) seq;
6537       generate_test_command_call ~test test_name last
6538   | TestOutputListOfDevices (seq, expected) ->
6539       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6540       let seq, last = get_seq_last seq in
6541       let test () =
6542         iteri (
6543           fun i str ->
6544             pr "    if (!r[%d]) {\n" i;
6545             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6546             pr "      print_strings (r);\n";
6547             pr "      return -1;\n";
6548             pr "    }\n";
6549             pr "    {\n";
6550             pr "      const char *expected = \"%s\";\n" (c_quote str);
6551             pr "      r[%d][5] = 's';\n" i;
6552             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6553             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6554             pr "        return -1;\n";
6555             pr "      }\n";
6556             pr "    }\n"
6557         ) expected;
6558         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6559         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6560           test_name;
6561         pr "      print_strings (r);\n";
6562         pr "      return -1;\n";
6563         pr "    }\n"
6564       in
6565       List.iter (generate_test_command_call test_name) seq;
6566       generate_test_command_call ~test test_name last
6567   | TestOutputInt (seq, expected) ->
6568       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6569       let seq, last = get_seq_last seq in
6570       let test () =
6571         pr "    if (r != %d) {\n" expected;
6572         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6573           test_name expected;
6574         pr "               (int) r);\n";
6575         pr "      return -1;\n";
6576         pr "    }\n"
6577       in
6578       List.iter (generate_test_command_call test_name) seq;
6579       generate_test_command_call ~test test_name last
6580   | TestOutputIntOp (seq, op, expected) ->
6581       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6582       let seq, last = get_seq_last seq in
6583       let test () =
6584         pr "    if (! (r %s %d)) {\n" op expected;
6585         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6586           test_name op expected;
6587         pr "               (int) r);\n";
6588         pr "      return -1;\n";
6589         pr "    }\n"
6590       in
6591       List.iter (generate_test_command_call test_name) seq;
6592       generate_test_command_call ~test test_name last
6593   | TestOutputTrue seq ->
6594       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
6595       let seq, last = get_seq_last seq in
6596       let test () =
6597         pr "    if (!r) {\n";
6598         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
6599           test_name;
6600         pr "      return -1;\n";
6601         pr "    }\n"
6602       in
6603       List.iter (generate_test_command_call test_name) seq;
6604       generate_test_command_call ~test test_name last
6605   | TestOutputFalse seq ->
6606       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
6607       let seq, last = get_seq_last seq in
6608       let test () =
6609         pr "    if (r) {\n";
6610         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
6611           test_name;
6612         pr "      return -1;\n";
6613         pr "    }\n"
6614       in
6615       List.iter (generate_test_command_call test_name) seq;
6616       generate_test_command_call ~test test_name last
6617   | TestOutputLength (seq, expected) ->
6618       pr "  /* TestOutputLength for %s (%d) */\n" name i;
6619       let seq, last = get_seq_last seq in
6620       let test () =
6621         pr "    int j;\n";
6622         pr "    for (j = 0; j < %d; ++j)\n" expected;
6623         pr "      if (r[j] == NULL) {\n";
6624         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
6625           test_name;
6626         pr "        print_strings (r);\n";
6627         pr "        return -1;\n";
6628         pr "      }\n";
6629         pr "    if (r[j] != NULL) {\n";
6630         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
6631           test_name;
6632         pr "      print_strings (r);\n";
6633         pr "      return -1;\n";
6634         pr "    }\n"
6635       in
6636       List.iter (generate_test_command_call test_name) seq;
6637       generate_test_command_call ~test test_name last
6638   | TestOutputBuffer (seq, expected) ->
6639       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
6640       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6641       let seq, last = get_seq_last seq in
6642       let len = String.length expected in
6643       let test () =
6644         pr "    if (size != %d) {\n" len;
6645         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
6646         pr "      return -1;\n";
6647         pr "    }\n";
6648         pr "    if (STRNEQLEN (r, expected, size)) {\n";
6649         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6650         pr "      return -1;\n";
6651         pr "    }\n"
6652       in
6653       List.iter (generate_test_command_call test_name) seq;
6654       generate_test_command_call ~test test_name last
6655   | TestOutputStruct (seq, checks) ->
6656       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
6657       let seq, last = get_seq_last seq in
6658       let test () =
6659         List.iter (
6660           function
6661           | CompareWithInt (field, expected) ->
6662               pr "    if (r->%s != %d) {\n" field expected;
6663               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
6664                 test_name field expected;
6665               pr "               (int) r->%s);\n" field;
6666               pr "      return -1;\n";
6667               pr "    }\n"
6668           | CompareWithIntOp (field, op, expected) ->
6669               pr "    if (!(r->%s %s %d)) {\n" field op expected;
6670               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
6671                 test_name field op expected;
6672               pr "               (int) r->%s);\n" field;
6673               pr "      return -1;\n";
6674               pr "    }\n"
6675           | CompareWithString (field, expected) ->
6676               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
6677               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
6678                 test_name field expected;
6679               pr "               r->%s);\n" field;
6680               pr "      return -1;\n";
6681               pr "    }\n"
6682           | CompareFieldsIntEq (field1, field2) ->
6683               pr "    if (r->%s != r->%s) {\n" field1 field2;
6684               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
6685                 test_name field1 field2;
6686               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
6687               pr "      return -1;\n";
6688               pr "    }\n"
6689           | CompareFieldsStrEq (field1, field2) ->
6690               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
6691               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
6692                 test_name field1 field2;
6693               pr "               r->%s, r->%s);\n" field1 field2;
6694               pr "      return -1;\n";
6695               pr "    }\n"
6696         ) checks
6697       in
6698       List.iter (generate_test_command_call test_name) seq;
6699       generate_test_command_call ~test test_name last
6700   | TestLastFail seq ->
6701       pr "  /* TestLastFail for %s (%d) */\n" name i;
6702       let seq, last = get_seq_last seq in
6703       List.iter (generate_test_command_call test_name) seq;
6704       generate_test_command_call test_name ~expect_error:true last
6705
6706 (* Generate the code to run a command, leaving the result in 'r'.
6707  * If you expect to get an error then you should set expect_error:true.
6708  *)
6709 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
6710   match cmd with
6711   | [] -> assert false
6712   | name :: args ->
6713       (* Look up the command to find out what args/ret it has. *)
6714       let style =
6715         try
6716           let _, style, _, _, _, _, _ =
6717             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
6718           style
6719         with Not_found ->
6720           failwithf "%s: in test, command %s was not found" test_name name in
6721
6722       if List.length (snd style) <> List.length args then
6723         failwithf "%s: in test, wrong number of args given to %s"
6724           test_name name;
6725
6726       pr "  {\n";
6727
6728       List.iter (
6729         function
6730         | OptString n, "NULL" -> ()
6731         | Pathname n, arg
6732         | Device n, arg
6733         | Dev_or_Path n, arg
6734         | String n, arg
6735         | OptString n, arg ->
6736             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
6737         | Int _, _
6738         | Int64 _, _
6739         | Bool _, _
6740         | FileIn _, _ | FileOut _, _ -> ()
6741         | StringList n, "" | DeviceList n, "" ->
6742             pr "    const char *const %s[1] = { NULL };\n" n
6743         | StringList n, arg | DeviceList n, arg ->
6744             let strs = string_split " " arg in
6745             iteri (
6746               fun i str ->
6747                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
6748             ) strs;
6749             pr "    const char *const %s[] = {\n" n;
6750             iteri (
6751               fun i _ -> pr "      %s_%d,\n" n i
6752             ) strs;
6753             pr "      NULL\n";
6754             pr "    };\n";
6755       ) (List.combine (snd style) args);
6756
6757       let error_code =
6758         match fst style with
6759         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
6760         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
6761         | RConstString _ | RConstOptString _ ->
6762             pr "    const char *r;\n"; "NULL"
6763         | RString _ -> pr "    char *r;\n"; "NULL"
6764         | RStringList _ | RHashtable _ ->
6765             pr "    char **r;\n";
6766             pr "    int i;\n";
6767             "NULL"
6768         | RStruct (_, typ) ->
6769             pr "    struct guestfs_%s *r;\n" typ; "NULL"
6770         | RStructList (_, typ) ->
6771             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
6772         | RBufferOut _ ->
6773             pr "    char *r;\n";
6774             pr "    size_t size;\n";
6775             "NULL" in
6776
6777       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
6778       pr "    r = guestfs_%s (g" name;
6779
6780       (* Generate the parameters. *)
6781       List.iter (
6782         function
6783         | OptString _, "NULL" -> pr ", NULL"
6784         | Pathname n, _
6785         | Device n, _ | Dev_or_Path n, _
6786         | String n, _
6787         | OptString n, _ ->
6788             pr ", %s" n
6789         | FileIn _, arg | FileOut _, arg ->
6790             pr ", \"%s\"" (c_quote arg)
6791         | StringList n, _ | DeviceList n, _ ->
6792             pr ", (char **) %s" n
6793         | Int _, arg ->
6794             let i =
6795               try int_of_string arg
6796               with Failure "int_of_string" ->
6797                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
6798             pr ", %d" i
6799         | Int64 _, arg ->
6800             let i =
6801               try Int64.of_string arg
6802               with Failure "int_of_string" ->
6803                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
6804             pr ", %Ld" i
6805         | Bool _, arg ->
6806             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
6807       ) (List.combine (snd style) args);
6808
6809       (match fst style with
6810        | RBufferOut _ -> pr ", &size"
6811        | _ -> ()
6812       );
6813
6814       pr ");\n";
6815
6816       if not expect_error then
6817         pr "    if (r == %s)\n" error_code
6818       else
6819         pr "    if (r != %s)\n" error_code;
6820       pr "      return -1;\n";
6821
6822       (* Insert the test code. *)
6823       (match test with
6824        | None -> ()
6825        | Some f -> f ()
6826       );
6827
6828       (match fst style with
6829        | RErr | RInt _ | RInt64 _ | RBool _
6830        | RConstString _ | RConstOptString _ -> ()
6831        | RString _ | RBufferOut _ -> pr "    free (r);\n"
6832        | RStringList _ | RHashtable _ ->
6833            pr "    for (i = 0; r[i] != NULL; ++i)\n";
6834            pr "      free (r[i]);\n";
6835            pr "    free (r);\n"
6836        | RStruct (_, typ) ->
6837            pr "    guestfs_free_%s (r);\n" typ
6838        | RStructList (_, typ) ->
6839            pr "    guestfs_free_%s_list (r);\n" typ
6840       );
6841
6842       pr "  }\n"
6843
6844 and c_quote str =
6845   let str = replace_str str "\r" "\\r" in
6846   let str = replace_str str "\n" "\\n" in
6847   let str = replace_str str "\t" "\\t" in
6848   let str = replace_str str "\000" "\\0" in
6849   str
6850
6851 (* Generate a lot of different functions for guestfish. *)
6852 and generate_fish_cmds () =
6853   generate_header CStyle GPLv2plus;
6854
6855   let all_functions =
6856     List.filter (
6857       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6858     ) all_functions in
6859   let all_functions_sorted =
6860     List.filter (
6861       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6862     ) all_functions_sorted in
6863
6864   pr "#include <stdio.h>\n";
6865   pr "#include <stdlib.h>\n";
6866   pr "#include <string.h>\n";
6867   pr "#include <inttypes.h>\n";
6868   pr "\n";
6869   pr "#include <guestfs.h>\n";
6870   pr "#include \"c-ctype.h\"\n";
6871   pr "#include \"fish.h\"\n";
6872   pr "\n";
6873
6874   (* list_commands function, which implements guestfish -h *)
6875   pr "void list_commands (void)\n";
6876   pr "{\n";
6877   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
6878   pr "  list_builtin_commands ();\n";
6879   List.iter (
6880     fun (name, _, _, flags, _, shortdesc, _) ->
6881       let name = replace_char name '_' '-' in
6882       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
6883         name shortdesc
6884   ) all_functions_sorted;
6885   pr "  printf (\"    %%s\\n\",";
6886   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
6887   pr "}\n";
6888   pr "\n";
6889
6890   (* display_command function, which implements guestfish -h cmd *)
6891   pr "void display_command (const char *cmd)\n";
6892   pr "{\n";
6893   List.iter (
6894     fun (name, style, _, flags, _, shortdesc, longdesc) ->
6895       let name2 = replace_char name '_' '-' in
6896       let alias =
6897         try find_map (function FishAlias n -> Some n | _ -> None) flags
6898         with Not_found -> name in
6899       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
6900       let synopsis =
6901         match snd style with
6902         | [] -> name2
6903         | args ->
6904             sprintf "%s %s"
6905               name2 (String.concat " " (List.map name_of_argt args)) in
6906
6907       let warnings =
6908         if List.mem ProtocolLimitWarning flags then
6909           ("\n\n" ^ protocol_limit_warning)
6910         else "" in
6911
6912       (* For DangerWillRobinson commands, we should probably have
6913        * guestfish prompt before allowing you to use them (especially
6914        * in interactive mode). XXX
6915        *)
6916       let warnings =
6917         warnings ^
6918           if List.mem DangerWillRobinson flags then
6919             ("\n\n" ^ danger_will_robinson)
6920           else "" in
6921
6922       let warnings =
6923         warnings ^
6924           match deprecation_notice flags with
6925           | None -> ""
6926           | Some txt -> "\n\n" ^ txt in
6927
6928       let describe_alias =
6929         if name <> alias then
6930           sprintf "\n\nYou can use '%s' as an alias for this command." alias
6931         else "" in
6932
6933       pr "  if (";
6934       pr "STRCASEEQ (cmd, \"%s\")" name;
6935       if name <> name2 then
6936         pr " || STRCASEEQ (cmd, \"%s\")" name2;
6937       if name <> alias then
6938         pr " || STRCASEEQ (cmd, \"%s\")" alias;
6939       pr ")\n";
6940       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
6941         name2 shortdesc
6942         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
6943          "=head1 DESCRIPTION\n\n" ^
6944          longdesc ^ warnings ^ describe_alias);
6945       pr "  else\n"
6946   ) all_functions;
6947   pr "    display_builtin_command (cmd);\n";
6948   pr "}\n";
6949   pr "\n";
6950
6951   let emit_print_list_function typ =
6952     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
6953       typ typ typ;
6954     pr "{\n";
6955     pr "  unsigned int i;\n";
6956     pr "\n";
6957     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
6958     pr "    printf (\"[%%d] = {\\n\", i);\n";
6959     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
6960     pr "    printf (\"}\\n\");\n";
6961     pr "  }\n";
6962     pr "}\n";
6963     pr "\n";
6964   in
6965
6966   (* print_* functions *)
6967   List.iter (
6968     fun (typ, cols) ->
6969       let needs_i =
6970         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
6971
6972       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
6973       pr "{\n";
6974       if needs_i then (
6975         pr "  unsigned int i;\n";
6976         pr "\n"
6977       );
6978       List.iter (
6979         function
6980         | name, FString ->
6981             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
6982         | name, FUUID ->
6983             pr "  printf (\"%%s%s: \", indent);\n" name;
6984             pr "  for (i = 0; i < 32; ++i)\n";
6985             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
6986             pr "  printf (\"\\n\");\n"
6987         | name, FBuffer ->
6988             pr "  printf (\"%%s%s: \", indent);\n" name;
6989             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
6990             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
6991             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
6992             pr "    else\n";
6993             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
6994             pr "  printf (\"\\n\");\n"
6995         | name, (FUInt64|FBytes) ->
6996             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
6997               name typ name
6998         | name, FInt64 ->
6999             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7000               name typ name
7001         | name, FUInt32 ->
7002             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7003               name typ name
7004         | name, FInt32 ->
7005             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7006               name typ name
7007         | name, FChar ->
7008             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7009               name typ name
7010         | name, FOptPercent ->
7011             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7012               typ name name typ name;
7013             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7014       ) cols;
7015       pr "}\n";
7016       pr "\n";
7017   ) structs;
7018
7019   (* Emit a print_TYPE_list function definition only if that function is used. *)
7020   List.iter (
7021     function
7022     | typ, (RStructListOnly | RStructAndList) ->
7023         (* generate the function for typ *)
7024         emit_print_list_function typ
7025     | typ, _ -> () (* empty *)
7026   ) (rstructs_used_by all_functions);
7027
7028   (* Emit a print_TYPE function definition only if that function is used. *)
7029   List.iter (
7030     function
7031     | typ, (RStructOnly | RStructAndList) ->
7032         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7033         pr "{\n";
7034         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7035         pr "}\n";
7036         pr "\n";
7037     | typ, _ -> () (* empty *)
7038   ) (rstructs_used_by all_functions);
7039
7040   (* run_<action> actions *)
7041   List.iter (
7042     fun (name, style, _, flags, _, _, _) ->
7043       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7044       pr "{\n";
7045       (match fst style with
7046        | RErr
7047        | RInt _
7048        | RBool _ -> pr "  int r;\n"
7049        | RInt64 _ -> pr "  int64_t r;\n"
7050        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7051        | RString _ -> pr "  char *r;\n"
7052        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7053        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7054        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7055        | RBufferOut _ ->
7056            pr "  char *r;\n";
7057            pr "  size_t size;\n";
7058       );
7059       List.iter (
7060         function
7061         | Device n
7062         | String n
7063         | OptString n
7064         | FileIn n
7065         | FileOut n -> pr "  const char *%s;\n" n
7066         | Pathname n
7067         | Dev_or_Path n -> pr "  char *%s;\n" n
7068         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7069         | Bool n -> pr "  int %s;\n" n
7070         | Int n -> pr "  int %s;\n" n
7071         | Int64 n -> pr "  int64_t %s;\n" n
7072       ) (snd style);
7073
7074       (* Check and convert parameters. *)
7075       let argc_expected = List.length (snd style) in
7076       pr "  if (argc != %d) {\n" argc_expected;
7077       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7078         argc_expected;
7079       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7080       pr "    return -1;\n";
7081       pr "  }\n";
7082       iteri (
7083         fun i ->
7084           function
7085           | Device name
7086           | String name ->
7087               pr "  %s = argv[%d];\n" name i
7088           | Pathname name
7089           | Dev_or_Path name ->
7090               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7091               pr "  if (%s == NULL) return -1;\n" name
7092           | OptString name ->
7093               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7094                 name i i
7095           | FileIn name ->
7096               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdin\";\n"
7097                 name i i
7098           | FileOut name ->
7099               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdout\";\n"
7100                 name i i
7101           | StringList name | DeviceList name ->
7102               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7103               pr "  if (%s == NULL) return -1;\n" name;
7104           | Bool name ->
7105               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7106           | Int name ->
7107               pr "  %s = atoi (argv[%d]);\n" name i
7108           | Int64 name ->
7109               pr "  %s = atoll (argv[%d]);\n" name i
7110       ) (snd style);
7111
7112       (* Call C API function. *)
7113       let fn =
7114         try find_map (function FishAction n -> Some n | _ -> None) flags
7115         with Not_found -> sprintf "guestfs_%s" name in
7116       pr "  r = %s " fn;
7117       generate_c_call_args ~handle:"g" style;
7118       pr ";\n";
7119
7120       List.iter (
7121         function
7122         | Device name | String name
7123         | OptString name | FileIn name | FileOut name | Bool name
7124         | Int name | Int64 name -> ()
7125         | Pathname name | Dev_or_Path name ->
7126             pr "  free (%s);\n" name
7127         | StringList name | DeviceList name ->
7128             pr "  free_strings (%s);\n" name
7129       ) (snd style);
7130
7131       (* Check return value for errors and display command results. *)
7132       (match fst style with
7133        | RErr -> pr "  return r;\n"
7134        | RInt _ ->
7135            pr "  if (r == -1) return -1;\n";
7136            pr "  printf (\"%%d\\n\", r);\n";
7137            pr "  return 0;\n"
7138        | RInt64 _ ->
7139            pr "  if (r == -1) return -1;\n";
7140            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7141            pr "  return 0;\n"
7142        | RBool _ ->
7143            pr "  if (r == -1) return -1;\n";
7144            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7145            pr "  return 0;\n"
7146        | RConstString _ ->
7147            pr "  if (r == NULL) return -1;\n";
7148            pr "  printf (\"%%s\\n\", r);\n";
7149            pr "  return 0;\n"
7150        | RConstOptString _ ->
7151            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7152            pr "  return 0;\n"
7153        | RString _ ->
7154            pr "  if (r == NULL) return -1;\n";
7155            pr "  printf (\"%%s\\n\", r);\n";
7156            pr "  free (r);\n";
7157            pr "  return 0;\n"
7158        | RStringList _ ->
7159            pr "  if (r == NULL) return -1;\n";
7160            pr "  print_strings (r);\n";
7161            pr "  free_strings (r);\n";
7162            pr "  return 0;\n"
7163        | RStruct (_, typ) ->
7164            pr "  if (r == NULL) return -1;\n";
7165            pr "  print_%s (r);\n" typ;
7166            pr "  guestfs_free_%s (r);\n" typ;
7167            pr "  return 0;\n"
7168        | RStructList (_, typ) ->
7169            pr "  if (r == NULL) return -1;\n";
7170            pr "  print_%s_list (r);\n" typ;
7171            pr "  guestfs_free_%s_list (r);\n" typ;
7172            pr "  return 0;\n"
7173        | RHashtable _ ->
7174            pr "  if (r == NULL) return -1;\n";
7175            pr "  print_table (r);\n";
7176            pr "  free_strings (r);\n";
7177            pr "  return 0;\n"
7178        | RBufferOut _ ->
7179            pr "  if (r == NULL) return -1;\n";
7180            pr "  fwrite (r, size, 1, stdout);\n";
7181            pr "  free (r);\n";
7182            pr "  return 0;\n"
7183       );
7184       pr "}\n";
7185       pr "\n"
7186   ) all_functions;
7187
7188   (* run_action function *)
7189   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7190   pr "{\n";
7191   List.iter (
7192     fun (name, _, _, flags, _, _, _) ->
7193       let name2 = replace_char name '_' '-' in
7194       let alias =
7195         try find_map (function FishAlias n -> Some n | _ -> None) flags
7196         with Not_found -> name in
7197       pr "  if (";
7198       pr "STRCASEEQ (cmd, \"%s\")" name;
7199       if name <> name2 then
7200         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7201       if name <> alias then
7202         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7203       pr ")\n";
7204       pr "    return run_%s (cmd, argc, argv);\n" name;
7205       pr "  else\n";
7206   ) all_functions;
7207   pr "    {\n";
7208   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7209   pr "      return -1;\n";
7210   pr "    }\n";
7211   pr "  return 0;\n";
7212   pr "}\n";
7213   pr "\n"
7214
7215 (* Readline completion for guestfish. *)
7216 and generate_fish_completion () =
7217   generate_header CStyle GPLv2plus;
7218
7219   let all_functions =
7220     List.filter (
7221       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7222     ) all_functions in
7223
7224   pr "\
7225 #include <config.h>
7226
7227 #include <stdio.h>
7228 #include <stdlib.h>
7229 #include <string.h>
7230
7231 #ifdef HAVE_LIBREADLINE
7232 #include <readline/readline.h>
7233 #endif
7234
7235 #include \"fish.h\"
7236
7237 #ifdef HAVE_LIBREADLINE
7238
7239 static const char *const commands[] = {
7240   BUILTIN_COMMANDS_FOR_COMPLETION,
7241 ";
7242
7243   (* Get the commands, including the aliases.  They don't need to be
7244    * sorted - the generator() function just does a dumb linear search.
7245    *)
7246   let commands =
7247     List.map (
7248       fun (name, _, _, flags, _, _, _) ->
7249         let name2 = replace_char name '_' '-' in
7250         let alias =
7251           try find_map (function FishAlias n -> Some n | _ -> None) flags
7252           with Not_found -> name in
7253
7254         if name <> alias then [name2; alias] else [name2]
7255     ) all_functions in
7256   let commands = List.flatten commands in
7257
7258   List.iter (pr "  \"%s\",\n") commands;
7259
7260   pr "  NULL
7261 };
7262
7263 static char *
7264 generator (const char *text, int state)
7265 {
7266   static int index, len;
7267   const char *name;
7268
7269   if (!state) {
7270     index = 0;
7271     len = strlen (text);
7272   }
7273
7274   rl_attempted_completion_over = 1;
7275
7276   while ((name = commands[index]) != NULL) {
7277     index++;
7278     if (STRCASEEQLEN (name, text, len))
7279       return strdup (name);
7280   }
7281
7282   return NULL;
7283 }
7284
7285 #endif /* HAVE_LIBREADLINE */
7286
7287 char **do_completion (const char *text, int start, int end)
7288 {
7289   char **matches = NULL;
7290
7291 #ifdef HAVE_LIBREADLINE
7292   rl_completion_append_character = ' ';
7293
7294   if (start == 0)
7295     matches = rl_completion_matches (text, generator);
7296   else if (complete_dest_paths)
7297     matches = rl_completion_matches (text, complete_dest_paths_generator);
7298 #endif
7299
7300   return matches;
7301 }
7302 ";
7303
7304 (* Generate the POD documentation for guestfish. *)
7305 and generate_fish_actions_pod () =
7306   let all_functions_sorted =
7307     List.filter (
7308       fun (_, _, _, flags, _, _, _) ->
7309         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7310     ) all_functions_sorted in
7311
7312   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7313
7314   List.iter (
7315     fun (name, style, _, flags, _, _, longdesc) ->
7316       let longdesc =
7317         Str.global_substitute rex (
7318           fun s ->
7319             let sub =
7320               try Str.matched_group 1 s
7321               with Not_found ->
7322                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7323             "C<" ^ replace_char sub '_' '-' ^ ">"
7324         ) longdesc in
7325       let name = replace_char name '_' '-' in
7326       let alias =
7327         try find_map (function FishAlias n -> Some n | _ -> None) flags
7328         with Not_found -> name in
7329
7330       pr "=head2 %s" name;
7331       if name <> alias then
7332         pr " | %s" alias;
7333       pr "\n";
7334       pr "\n";
7335       pr " %s" name;
7336       List.iter (
7337         function
7338         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7339         | OptString n -> pr " %s" n
7340         | StringList n | DeviceList n -> pr " '%s ...'" n
7341         | Bool _ -> pr " true|false"
7342         | Int n -> pr " %s" n
7343         | Int64 n -> pr " %s" n
7344         | FileIn n | FileOut n -> pr " (%s|-)" n
7345       ) (snd style);
7346       pr "\n";
7347       pr "\n";
7348       pr "%s\n\n" longdesc;
7349
7350       if List.exists (function FileIn _ | FileOut _ -> true
7351                       | _ -> false) (snd style) then
7352         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7353
7354       if List.mem ProtocolLimitWarning flags then
7355         pr "%s\n\n" protocol_limit_warning;
7356
7357       if List.mem DangerWillRobinson flags then
7358         pr "%s\n\n" danger_will_robinson;
7359
7360       match deprecation_notice flags with
7361       | None -> ()
7362       | Some txt -> pr "%s\n\n" txt
7363   ) all_functions_sorted
7364
7365 (* Generate a C function prototype. *)
7366 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7367     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7368     ?(prefix = "")
7369     ?handle name style =
7370   if extern then pr "extern ";
7371   if static then pr "static ";
7372   (match fst style with
7373    | RErr -> pr "int "
7374    | RInt _ -> pr "int "
7375    | RInt64 _ -> pr "int64_t "
7376    | RBool _ -> pr "int "
7377    | RConstString _ | RConstOptString _ -> pr "const char *"
7378    | RString _ | RBufferOut _ -> pr "char *"
7379    | RStringList _ | RHashtable _ -> pr "char **"
7380    | RStruct (_, typ) ->
7381        if not in_daemon then pr "struct guestfs_%s *" typ
7382        else pr "guestfs_int_%s *" typ
7383    | RStructList (_, typ) ->
7384        if not in_daemon then pr "struct guestfs_%s_list *" typ
7385        else pr "guestfs_int_%s_list *" typ
7386   );
7387   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7388   pr "%s%s (" prefix name;
7389   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7390     pr "void"
7391   else (
7392     let comma = ref false in
7393     (match handle with
7394      | None -> ()
7395      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7396     );
7397     let next () =
7398       if !comma then (
7399         if single_line then pr ", " else pr ",\n\t\t"
7400       );
7401       comma := true
7402     in
7403     List.iter (
7404       function
7405       | Pathname n
7406       | Device n | Dev_or_Path n
7407       | String n
7408       | OptString n ->
7409           next ();
7410           pr "const char *%s" n
7411       | StringList n | DeviceList n ->
7412           next ();
7413           pr "char *const *%s" n
7414       | Bool n -> next (); pr "int %s" n
7415       | Int n -> next (); pr "int %s" n
7416       | Int64 n -> next (); pr "int64_t %s" n
7417       | FileIn n
7418       | FileOut n ->
7419           if not in_daemon then (next (); pr "const char *%s" n)
7420     ) (snd style);
7421     if is_RBufferOut then (next (); pr "size_t *size_r");
7422   );
7423   pr ")";
7424   if semicolon then pr ";";
7425   if newline then pr "\n"
7426
7427 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7428 and generate_c_call_args ?handle ?(decl = false) style =
7429   pr "(";
7430   let comma = ref false in
7431   let next () =
7432     if !comma then pr ", ";
7433     comma := true
7434   in
7435   (match handle with
7436    | None -> ()
7437    | Some handle -> pr "%s" handle; comma := true
7438   );
7439   List.iter (
7440     fun arg ->
7441       next ();
7442       pr "%s" (name_of_argt arg)
7443   ) (snd style);
7444   (* For RBufferOut calls, add implicit &size parameter. *)
7445   if not decl then (
7446     match fst style with
7447     | RBufferOut _ ->
7448         next ();
7449         pr "&size"
7450     | _ -> ()
7451   );
7452   pr ")"
7453
7454 (* Generate the OCaml bindings interface. *)
7455 and generate_ocaml_mli () =
7456   generate_header OCamlStyle LGPLv2plus;
7457
7458   pr "\
7459 (** For API documentation you should refer to the C API
7460     in the guestfs(3) manual page.  The OCaml API uses almost
7461     exactly the same calls. *)
7462
7463 type t
7464 (** A [guestfs_h] handle. *)
7465
7466 exception Error of string
7467 (** This exception is raised when there is an error. *)
7468
7469 exception Handle_closed of string
7470 (** This exception is raised if you use a {!Guestfs.t} handle
7471     after calling {!close} on it.  The string is the name of
7472     the function. *)
7473
7474 val create : unit -> t
7475 (** Create a {!Guestfs.t} handle. *)
7476
7477 val close : t -> unit
7478 (** Close the {!Guestfs.t} handle and free up all resources used
7479     by it immediately.
7480
7481     Handles are closed by the garbage collector when they become
7482     unreferenced, but callers can call this in order to provide
7483     predictable cleanup. *)
7484
7485 ";
7486   generate_ocaml_structure_decls ();
7487
7488   (* The actions. *)
7489   List.iter (
7490     fun (name, style, _, _, _, shortdesc, _) ->
7491       generate_ocaml_prototype name style;
7492       pr "(** %s *)\n" shortdesc;
7493       pr "\n"
7494   ) all_functions_sorted
7495
7496 (* Generate the OCaml bindings implementation. *)
7497 and generate_ocaml_ml () =
7498   generate_header OCamlStyle LGPLv2plus;
7499
7500   pr "\
7501 type t
7502
7503 exception Error of string
7504 exception Handle_closed of string
7505
7506 external create : unit -> t = \"ocaml_guestfs_create\"
7507 external close : t -> unit = \"ocaml_guestfs_close\"
7508
7509 (* Give the exceptions names, so they can be raised from the C code. *)
7510 let () =
7511   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
7512   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
7513
7514 ";
7515
7516   generate_ocaml_structure_decls ();
7517
7518   (* The actions. *)
7519   List.iter (
7520     fun (name, style, _, _, _, shortdesc, _) ->
7521       generate_ocaml_prototype ~is_external:true name style;
7522   ) all_functions_sorted
7523
7524 (* Generate the OCaml bindings C implementation. *)
7525 and generate_ocaml_c () =
7526   generate_header CStyle LGPLv2plus;
7527
7528   pr "\
7529 #include <stdio.h>
7530 #include <stdlib.h>
7531 #include <string.h>
7532
7533 #include <caml/config.h>
7534 #include <caml/alloc.h>
7535 #include <caml/callback.h>
7536 #include <caml/fail.h>
7537 #include <caml/memory.h>
7538 #include <caml/mlvalues.h>
7539 #include <caml/signals.h>
7540
7541 #include <guestfs.h>
7542
7543 #include \"guestfs_c.h\"
7544
7545 /* Copy a hashtable of string pairs into an assoc-list.  We return
7546  * the list in reverse order, but hashtables aren't supposed to be
7547  * ordered anyway.
7548  */
7549 static CAMLprim value
7550 copy_table (char * const * argv)
7551 {
7552   CAMLparam0 ();
7553   CAMLlocal5 (rv, pairv, kv, vv, cons);
7554   int i;
7555
7556   rv = Val_int (0);
7557   for (i = 0; argv[i] != NULL; i += 2) {
7558     kv = caml_copy_string (argv[i]);
7559     vv = caml_copy_string (argv[i+1]);
7560     pairv = caml_alloc (2, 0);
7561     Store_field (pairv, 0, kv);
7562     Store_field (pairv, 1, vv);
7563     cons = caml_alloc (2, 0);
7564     Store_field (cons, 1, rv);
7565     rv = cons;
7566     Store_field (cons, 0, pairv);
7567   }
7568
7569   CAMLreturn (rv);
7570 }
7571
7572 ";
7573
7574   (* Struct copy functions. *)
7575
7576   let emit_ocaml_copy_list_function typ =
7577     pr "static CAMLprim value\n";
7578     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
7579     pr "{\n";
7580     pr "  CAMLparam0 ();\n";
7581     pr "  CAMLlocal2 (rv, v);\n";
7582     pr "  unsigned int i;\n";
7583     pr "\n";
7584     pr "  if (%ss->len == 0)\n" typ;
7585     pr "    CAMLreturn (Atom (0));\n";
7586     pr "  else {\n";
7587     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
7588     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
7589     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
7590     pr "      caml_modify (&Field (rv, i), v);\n";
7591     pr "    }\n";
7592     pr "    CAMLreturn (rv);\n";
7593     pr "  }\n";
7594     pr "}\n";
7595     pr "\n";
7596   in
7597
7598   List.iter (
7599     fun (typ, cols) ->
7600       let has_optpercent_col =
7601         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
7602
7603       pr "static CAMLprim value\n";
7604       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
7605       pr "{\n";
7606       pr "  CAMLparam0 ();\n";
7607       if has_optpercent_col then
7608         pr "  CAMLlocal3 (rv, v, v2);\n"
7609       else
7610         pr "  CAMLlocal2 (rv, v);\n";
7611       pr "\n";
7612       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
7613       iteri (
7614         fun i col ->
7615           (match col with
7616            | name, FString ->
7617                pr "  v = caml_copy_string (%s->%s);\n" typ name
7618            | name, FBuffer ->
7619                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
7620                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
7621                  typ name typ name
7622            | name, FUUID ->
7623                pr "  v = caml_alloc_string (32);\n";
7624                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
7625            | name, (FBytes|FInt64|FUInt64) ->
7626                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
7627            | name, (FInt32|FUInt32) ->
7628                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
7629            | name, FOptPercent ->
7630                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
7631                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
7632                pr "    v = caml_alloc (1, 0);\n";
7633                pr "    Store_field (v, 0, v2);\n";
7634                pr "  } else /* None */\n";
7635                pr "    v = Val_int (0);\n";
7636            | name, FChar ->
7637                pr "  v = Val_int (%s->%s);\n" typ name
7638           );
7639           pr "  Store_field (rv, %d, v);\n" i
7640       ) cols;
7641       pr "  CAMLreturn (rv);\n";
7642       pr "}\n";
7643       pr "\n";
7644   ) structs;
7645
7646   (* Emit a copy_TYPE_list function definition only if that function is used. *)
7647   List.iter (
7648     function
7649     | typ, (RStructListOnly | RStructAndList) ->
7650         (* generate the function for typ *)
7651         emit_ocaml_copy_list_function typ
7652     | typ, _ -> () (* empty *)
7653   ) (rstructs_used_by all_functions);
7654
7655   (* The wrappers. *)
7656   List.iter (
7657     fun (name, style, _, _, _, _, _) ->
7658       pr "/* Automatically generated wrapper for function\n";
7659       pr " * ";
7660       generate_ocaml_prototype name style;
7661       pr " */\n";
7662       pr "\n";
7663
7664       let params =
7665         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
7666
7667       let needs_extra_vs =
7668         match fst style with RConstOptString _ -> true | _ -> false in
7669
7670       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7671       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
7672       List.iter (pr ", value %s") (List.tl params); pr ");\n";
7673       pr "\n";
7674
7675       pr "CAMLprim value\n";
7676       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
7677       List.iter (pr ", value %s") (List.tl params);
7678       pr ")\n";
7679       pr "{\n";
7680
7681       (match params with
7682        | [p1; p2; p3; p4; p5] ->
7683            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
7684        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
7685            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
7686            pr "  CAMLxparam%d (%s);\n"
7687              (List.length rest) (String.concat ", " rest)
7688        | ps ->
7689            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
7690       );
7691       if not needs_extra_vs then
7692         pr "  CAMLlocal1 (rv);\n"
7693       else
7694         pr "  CAMLlocal3 (rv, v, v2);\n";
7695       pr "\n";
7696
7697       pr "  guestfs_h *g = Guestfs_val (gv);\n";
7698       pr "  if (g == NULL)\n";
7699       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
7700       pr "\n";
7701
7702       List.iter (
7703         function
7704         | Pathname n
7705         | Device n | Dev_or_Path n
7706         | String n
7707         | FileIn n
7708         | FileOut n ->
7709             pr "  const char *%s = String_val (%sv);\n" n n
7710         | OptString n ->
7711             pr "  const char *%s =\n" n;
7712             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
7713               n n
7714         | StringList n | DeviceList n ->
7715             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
7716         | Bool n ->
7717             pr "  int %s = Bool_val (%sv);\n" n n
7718         | Int n ->
7719             pr "  int %s = Int_val (%sv);\n" n n
7720         | Int64 n ->
7721             pr "  int64_t %s = Int64_val (%sv);\n" n n
7722       ) (snd style);
7723       let error_code =
7724         match fst style with
7725         | RErr -> pr "  int r;\n"; "-1"
7726         | RInt _ -> pr "  int r;\n"; "-1"
7727         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7728         | RBool _ -> pr "  int r;\n"; "-1"
7729         | RConstString _ | RConstOptString _ ->
7730             pr "  const char *r;\n"; "NULL"
7731         | RString _ -> pr "  char *r;\n"; "NULL"
7732         | RStringList _ ->
7733             pr "  int i;\n";
7734             pr "  char **r;\n";
7735             "NULL"
7736         | RStruct (_, typ) ->
7737             pr "  struct guestfs_%s *r;\n" typ; "NULL"
7738         | RStructList (_, typ) ->
7739             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7740         | RHashtable _ ->
7741             pr "  int i;\n";
7742             pr "  char **r;\n";
7743             "NULL"
7744         | RBufferOut _ ->
7745             pr "  char *r;\n";
7746             pr "  size_t size;\n";
7747             "NULL" in
7748       pr "\n";
7749
7750       pr "  caml_enter_blocking_section ();\n";
7751       pr "  r = guestfs_%s " name;
7752       generate_c_call_args ~handle:"g" style;
7753       pr ";\n";
7754       pr "  caml_leave_blocking_section ();\n";
7755
7756       List.iter (
7757         function
7758         | StringList n | DeviceList n ->
7759             pr "  ocaml_guestfs_free_strings (%s);\n" n;
7760         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
7761         | Bool _ | Int _ | Int64 _
7762         | FileIn _ | FileOut _ -> ()
7763       ) (snd style);
7764
7765       pr "  if (r == %s)\n" error_code;
7766       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
7767       pr "\n";
7768
7769       (match fst style with
7770        | RErr -> pr "  rv = Val_unit;\n"
7771        | RInt _ -> pr "  rv = Val_int (r);\n"
7772        | RInt64 _ ->
7773            pr "  rv = caml_copy_int64 (r);\n"
7774        | RBool _ -> pr "  rv = Val_bool (r);\n"
7775        | RConstString _ ->
7776            pr "  rv = caml_copy_string (r);\n"
7777        | RConstOptString _ ->
7778            pr "  if (r) { /* Some string */\n";
7779            pr "    v = caml_alloc (1, 0);\n";
7780            pr "    v2 = caml_copy_string (r);\n";
7781            pr "    Store_field (v, 0, v2);\n";
7782            pr "  } else /* None */\n";
7783            pr "    v = Val_int (0);\n";
7784        | RString _ ->
7785            pr "  rv = caml_copy_string (r);\n";
7786            pr "  free (r);\n"
7787        | RStringList _ ->
7788            pr "  rv = caml_copy_string_array ((const char **) r);\n";
7789            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7790            pr "  free (r);\n"
7791        | RStruct (_, typ) ->
7792            pr "  rv = copy_%s (r);\n" typ;
7793            pr "  guestfs_free_%s (r);\n" typ;
7794        | RStructList (_, typ) ->
7795            pr "  rv = copy_%s_list (r);\n" typ;
7796            pr "  guestfs_free_%s_list (r);\n" typ;
7797        | RHashtable _ ->
7798            pr "  rv = copy_table (r);\n";
7799            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7800            pr "  free (r);\n";
7801        | RBufferOut _ ->
7802            pr "  rv = caml_alloc_string (size);\n";
7803            pr "  memcpy (String_val (rv), r, size);\n";
7804       );
7805
7806       pr "  CAMLreturn (rv);\n";
7807       pr "}\n";
7808       pr "\n";
7809
7810       if List.length params > 5 then (
7811         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7812         pr "CAMLprim value ";
7813         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
7814         pr "CAMLprim value\n";
7815         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
7816         pr "{\n";
7817         pr "  return ocaml_guestfs_%s (argv[0]" name;
7818         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
7819         pr ");\n";
7820         pr "}\n";
7821         pr "\n"
7822       )
7823   ) all_functions_sorted
7824
7825 and generate_ocaml_structure_decls () =
7826   List.iter (
7827     fun (typ, cols) ->
7828       pr "type %s = {\n" typ;
7829       List.iter (
7830         function
7831         | name, FString -> pr "  %s : string;\n" name
7832         | name, FBuffer -> pr "  %s : string;\n" name
7833         | name, FUUID -> pr "  %s : string;\n" name
7834         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
7835         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
7836         | name, FChar -> pr "  %s : char;\n" name
7837         | name, FOptPercent -> pr "  %s : float option;\n" name
7838       ) cols;
7839       pr "}\n";
7840       pr "\n"
7841   ) structs
7842
7843 and generate_ocaml_prototype ?(is_external = false) name style =
7844   if is_external then pr "external " else pr "val ";
7845   pr "%s : t -> " name;
7846   List.iter (
7847     function
7848     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
7849     | OptString _ -> pr "string option -> "
7850     | StringList _ | DeviceList _ -> pr "string array -> "
7851     | Bool _ -> pr "bool -> "
7852     | Int _ -> pr "int -> "
7853     | Int64 _ -> pr "int64 -> "
7854   ) (snd style);
7855   (match fst style with
7856    | RErr -> pr "unit" (* all errors are turned into exceptions *)
7857    | RInt _ -> pr "int"
7858    | RInt64 _ -> pr "int64"
7859    | RBool _ -> pr "bool"
7860    | RConstString _ -> pr "string"
7861    | RConstOptString _ -> pr "string option"
7862    | RString _ | RBufferOut _ -> pr "string"
7863    | RStringList _ -> pr "string array"
7864    | RStruct (_, typ) -> pr "%s" typ
7865    | RStructList (_, typ) -> pr "%s array" typ
7866    | RHashtable _ -> pr "(string * string) list"
7867   );
7868   if is_external then (
7869     pr " = ";
7870     if List.length (snd style) + 1 > 5 then
7871       pr "\"ocaml_guestfs_%s_byte\" " name;
7872     pr "\"ocaml_guestfs_%s\"" name
7873   );
7874   pr "\n"
7875
7876 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
7877 and generate_perl_xs () =
7878   generate_header CStyle LGPLv2plus;
7879
7880   pr "\
7881 #include \"EXTERN.h\"
7882 #include \"perl.h\"
7883 #include \"XSUB.h\"
7884
7885 #include <guestfs.h>
7886
7887 #ifndef PRId64
7888 #define PRId64 \"lld\"
7889 #endif
7890
7891 static SV *
7892 my_newSVll(long long val) {
7893 #ifdef USE_64_BIT_ALL
7894   return newSViv(val);
7895 #else
7896   char buf[100];
7897   int len;
7898   len = snprintf(buf, 100, \"%%\" PRId64, val);
7899   return newSVpv(buf, len);
7900 #endif
7901 }
7902
7903 #ifndef PRIu64
7904 #define PRIu64 \"llu\"
7905 #endif
7906
7907 static SV *
7908 my_newSVull(unsigned long long val) {
7909 #ifdef USE_64_BIT_ALL
7910   return newSVuv(val);
7911 #else
7912   char buf[100];
7913   int len;
7914   len = snprintf(buf, 100, \"%%\" PRIu64, val);
7915   return newSVpv(buf, len);
7916 #endif
7917 }
7918
7919 /* http://www.perlmonks.org/?node_id=680842 */
7920 static char **
7921 XS_unpack_charPtrPtr (SV *arg) {
7922   char **ret;
7923   AV *av;
7924   I32 i;
7925
7926   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
7927     croak (\"array reference expected\");
7928
7929   av = (AV *)SvRV (arg);
7930   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
7931   if (!ret)
7932     croak (\"malloc failed\");
7933
7934   for (i = 0; i <= av_len (av); i++) {
7935     SV **elem = av_fetch (av, i, 0);
7936
7937     if (!elem || !*elem)
7938       croak (\"missing element in list\");
7939
7940     ret[i] = SvPV_nolen (*elem);
7941   }
7942
7943   ret[i] = NULL;
7944
7945   return ret;
7946 }
7947
7948 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
7949
7950 PROTOTYPES: ENABLE
7951
7952 guestfs_h *
7953 _create ()
7954    CODE:
7955       RETVAL = guestfs_create ();
7956       if (!RETVAL)
7957         croak (\"could not create guestfs handle\");
7958       guestfs_set_error_handler (RETVAL, NULL, NULL);
7959  OUTPUT:
7960       RETVAL
7961
7962 void
7963 DESTROY (g)
7964       guestfs_h *g;
7965  PPCODE:
7966       guestfs_close (g);
7967
7968 ";
7969
7970   List.iter (
7971     fun (name, style, _, _, _, _, _) ->
7972       (match fst style with
7973        | RErr -> pr "void\n"
7974        | RInt _ -> pr "SV *\n"
7975        | RInt64 _ -> pr "SV *\n"
7976        | RBool _ -> pr "SV *\n"
7977        | RConstString _ -> pr "SV *\n"
7978        | RConstOptString _ -> pr "SV *\n"
7979        | RString _ -> pr "SV *\n"
7980        | RBufferOut _ -> pr "SV *\n"
7981        | RStringList _
7982        | RStruct _ | RStructList _
7983        | RHashtable _ ->
7984            pr "void\n" (* all lists returned implictly on the stack *)
7985       );
7986       (* Call and arguments. *)
7987       pr "%s " name;
7988       generate_c_call_args ~handle:"g" ~decl:true style;
7989       pr "\n";
7990       pr "      guestfs_h *g;\n";
7991       iteri (
7992         fun i ->
7993           function
7994           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
7995               pr "      char *%s;\n" n
7996           | OptString n ->
7997               (* http://www.perlmonks.org/?node_id=554277
7998                * Note that the implicit handle argument means we have
7999                * to add 1 to the ST(x) operator.
8000                *)
8001               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8002           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8003           | Bool n -> pr "      int %s;\n" n
8004           | Int n -> pr "      int %s;\n" n
8005           | Int64 n -> pr "      int64_t %s;\n" n
8006       ) (snd style);
8007
8008       let do_cleanups () =
8009         List.iter (
8010           function
8011           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8012           | Bool _ | Int _ | Int64 _
8013           | FileIn _ | FileOut _ -> ()
8014           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8015         ) (snd style)
8016       in
8017
8018       (* Code. *)
8019       (match fst style with
8020        | RErr ->
8021            pr "PREINIT:\n";
8022            pr "      int r;\n";
8023            pr " PPCODE:\n";
8024            pr "      r = guestfs_%s " name;
8025            generate_c_call_args ~handle:"g" style;
8026            pr ";\n";
8027            do_cleanups ();
8028            pr "      if (r == -1)\n";
8029            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8030        | RInt n
8031        | RBool n ->
8032            pr "PREINIT:\n";
8033            pr "      int %s;\n" n;
8034            pr "   CODE:\n";
8035            pr "      %s = guestfs_%s " n name;
8036            generate_c_call_args ~handle:"g" style;
8037            pr ";\n";
8038            do_cleanups ();
8039            pr "      if (%s == -1)\n" n;
8040            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8041            pr "      RETVAL = newSViv (%s);\n" n;
8042            pr " OUTPUT:\n";
8043            pr "      RETVAL\n"
8044        | RInt64 n ->
8045            pr "PREINIT:\n";
8046            pr "      int64_t %s;\n" n;
8047            pr "   CODE:\n";
8048            pr "      %s = guestfs_%s " n name;
8049            generate_c_call_args ~handle:"g" style;
8050            pr ";\n";
8051            do_cleanups ();
8052            pr "      if (%s == -1)\n" n;
8053            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8054            pr "      RETVAL = my_newSVll (%s);\n" n;
8055            pr " OUTPUT:\n";
8056            pr "      RETVAL\n"
8057        | RConstString n ->
8058            pr "PREINIT:\n";
8059            pr "      const char *%s;\n" n;
8060            pr "   CODE:\n";
8061            pr "      %s = guestfs_%s " n name;
8062            generate_c_call_args ~handle:"g" style;
8063            pr ";\n";
8064            do_cleanups ();
8065            pr "      if (%s == NULL)\n" n;
8066            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8067            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8068            pr " OUTPUT:\n";
8069            pr "      RETVAL\n"
8070        | RConstOptString n ->
8071            pr "PREINIT:\n";
8072            pr "      const char *%s;\n" n;
8073            pr "   CODE:\n";
8074            pr "      %s = guestfs_%s " n name;
8075            generate_c_call_args ~handle:"g" style;
8076            pr ";\n";
8077            do_cleanups ();
8078            pr "      if (%s == NULL)\n" n;
8079            pr "        RETVAL = &PL_sv_undef;\n";
8080            pr "      else\n";
8081            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8082            pr " OUTPUT:\n";
8083            pr "      RETVAL\n"
8084        | RString n ->
8085            pr "PREINIT:\n";
8086            pr "      char *%s;\n" n;
8087            pr "   CODE:\n";
8088            pr "      %s = guestfs_%s " n name;
8089            generate_c_call_args ~handle:"g" style;
8090            pr ";\n";
8091            do_cleanups ();
8092            pr "      if (%s == NULL)\n" n;
8093            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8094            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8095            pr "      free (%s);\n" n;
8096            pr " OUTPUT:\n";
8097            pr "      RETVAL\n"
8098        | RStringList n | RHashtable n ->
8099            pr "PREINIT:\n";
8100            pr "      char **%s;\n" n;
8101            pr "      int i, n;\n";
8102            pr " PPCODE:\n";
8103            pr "      %s = guestfs_%s " n name;
8104            generate_c_call_args ~handle:"g" style;
8105            pr ";\n";
8106            do_cleanups ();
8107            pr "      if (%s == NULL)\n" n;
8108            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8109            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8110            pr "      EXTEND (SP, n);\n";
8111            pr "      for (i = 0; i < n; ++i) {\n";
8112            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8113            pr "        free (%s[i]);\n" n;
8114            pr "      }\n";
8115            pr "      free (%s);\n" n;
8116        | RStruct (n, typ) ->
8117            let cols = cols_of_struct typ in
8118            generate_perl_struct_code typ cols name style n do_cleanups
8119        | RStructList (n, typ) ->
8120            let cols = cols_of_struct typ in
8121            generate_perl_struct_list_code typ cols name style n do_cleanups
8122        | RBufferOut n ->
8123            pr "PREINIT:\n";
8124            pr "      char *%s;\n" n;
8125            pr "      size_t size;\n";
8126            pr "   CODE:\n";
8127            pr "      %s = guestfs_%s " n name;
8128            generate_c_call_args ~handle:"g" style;
8129            pr ";\n";
8130            do_cleanups ();
8131            pr "      if (%s == NULL)\n" n;
8132            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8133            pr "      RETVAL = newSVpv (%s, size);\n" n;
8134            pr "      free (%s);\n" n;
8135            pr " OUTPUT:\n";
8136            pr "      RETVAL\n"
8137       );
8138
8139       pr "\n"
8140   ) all_functions
8141
8142 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8143   pr "PREINIT:\n";
8144   pr "      struct guestfs_%s_list *%s;\n" typ n;
8145   pr "      int i;\n";
8146   pr "      HV *hv;\n";
8147   pr " PPCODE:\n";
8148   pr "      %s = guestfs_%s " n name;
8149   generate_c_call_args ~handle:"g" style;
8150   pr ";\n";
8151   do_cleanups ();
8152   pr "      if (%s == NULL)\n" n;
8153   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8154   pr "      EXTEND (SP, %s->len);\n" n;
8155   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8156   pr "        hv = newHV ();\n";
8157   List.iter (
8158     function
8159     | name, FString ->
8160         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8161           name (String.length name) n name
8162     | name, FUUID ->
8163         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8164           name (String.length name) n name
8165     | name, FBuffer ->
8166         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8167           name (String.length name) n name n name
8168     | name, (FBytes|FUInt64) ->
8169         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8170           name (String.length name) n name
8171     | name, FInt64 ->
8172         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8173           name (String.length name) n name
8174     | name, (FInt32|FUInt32) ->
8175         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8176           name (String.length name) n name
8177     | name, FChar ->
8178         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8179           name (String.length name) n name
8180     | name, FOptPercent ->
8181         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8182           name (String.length name) n name
8183   ) cols;
8184   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8185   pr "      }\n";
8186   pr "      guestfs_free_%s_list (%s);\n" typ n
8187
8188 and generate_perl_struct_code typ cols name style n do_cleanups =
8189   pr "PREINIT:\n";
8190   pr "      struct guestfs_%s *%s;\n" typ n;
8191   pr " PPCODE:\n";
8192   pr "      %s = guestfs_%s " n name;
8193   generate_c_call_args ~handle:"g" style;
8194   pr ";\n";
8195   do_cleanups ();
8196   pr "      if (%s == NULL)\n" n;
8197   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8198   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8199   List.iter (
8200     fun ((name, _) as col) ->
8201       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8202
8203       match col with
8204       | name, FString ->
8205           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8206             n name
8207       | name, FBuffer ->
8208           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
8209             n name n name
8210       | name, FUUID ->
8211           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8212             n name
8213       | name, (FBytes|FUInt64) ->
8214           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8215             n name
8216       | name, FInt64 ->
8217           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8218             n name
8219       | name, (FInt32|FUInt32) ->
8220           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8221             n name
8222       | name, FChar ->
8223           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8224             n name
8225       | name, FOptPercent ->
8226           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8227             n name
8228   ) cols;
8229   pr "      free (%s);\n" n
8230
8231 (* Generate Sys/Guestfs.pm. *)
8232 and generate_perl_pm () =
8233   generate_header HashStyle LGPLv2plus;
8234
8235   pr "\
8236 =pod
8237
8238 =head1 NAME
8239
8240 Sys::Guestfs - Perl bindings for libguestfs
8241
8242 =head1 SYNOPSIS
8243
8244  use Sys::Guestfs;
8245
8246  my $h = Sys::Guestfs->new ();
8247  $h->add_drive ('guest.img');
8248  $h->launch ();
8249  $h->mount ('/dev/sda1', '/');
8250  $h->touch ('/hello');
8251  $h->sync ();
8252
8253 =head1 DESCRIPTION
8254
8255 The C<Sys::Guestfs> module provides a Perl XS binding to the
8256 libguestfs API for examining and modifying virtual machine
8257 disk images.
8258
8259 Amongst the things this is good for: making batch configuration
8260 changes to guests, getting disk used/free statistics (see also:
8261 virt-df), migrating between virtualization systems (see also:
8262 virt-p2v), performing partial backups, performing partial guest
8263 clones, cloning guests and changing registry/UUID/hostname info, and
8264 much else besides.
8265
8266 Libguestfs uses Linux kernel and qemu code, and can access any type of
8267 guest filesystem that Linux and qemu can, including but not limited
8268 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8269 schemes, qcow, qcow2, vmdk.
8270
8271 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8272 LVs, what filesystem is in each LV, etc.).  It can also run commands
8273 in the context of the guest.  Also you can access filesystems over FTP.
8274
8275 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8276 functions for using libguestfs from Perl, including integration
8277 with libvirt.
8278
8279 =head1 ERRORS
8280
8281 All errors turn into calls to C<croak> (see L<Carp(3)>).
8282
8283 =head1 METHODS
8284
8285 =over 4
8286
8287 =cut
8288
8289 package Sys::Guestfs;
8290
8291 use strict;
8292 use warnings;
8293
8294 require XSLoader;
8295 XSLoader::load ('Sys::Guestfs');
8296
8297 =item $h = Sys::Guestfs->new ();
8298
8299 Create a new guestfs handle.
8300
8301 =cut
8302
8303 sub new {
8304   my $proto = shift;
8305   my $class = ref ($proto) || $proto;
8306
8307   my $self = Sys::Guestfs::_create ();
8308   bless $self, $class;
8309   return $self;
8310 }
8311
8312 ";
8313
8314   (* Actions.  We only need to print documentation for these as
8315    * they are pulled in from the XS code automatically.
8316    *)
8317   List.iter (
8318     fun (name, style, _, flags, _, _, longdesc) ->
8319       if not (List.mem NotInDocs flags) then (
8320         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8321         pr "=item ";
8322         generate_perl_prototype name style;
8323         pr "\n\n";
8324         pr "%s\n\n" longdesc;
8325         if List.mem ProtocolLimitWarning flags then
8326           pr "%s\n\n" protocol_limit_warning;
8327         if List.mem DangerWillRobinson flags then
8328           pr "%s\n\n" danger_will_robinson;
8329         match deprecation_notice flags with
8330         | None -> ()
8331         | Some txt -> pr "%s\n\n" txt
8332       )
8333   ) all_functions_sorted;
8334
8335   (* End of file. *)
8336   pr "\
8337 =cut
8338
8339 1;
8340
8341 =back
8342
8343 =head1 COPYRIGHT
8344
8345 Copyright (C) %s Red Hat Inc.
8346
8347 =head1 LICENSE
8348
8349 Please see the file COPYING.LIB for the full license.
8350
8351 =head1 SEE ALSO
8352
8353 L<guestfs(3)>,
8354 L<guestfish(1)>,
8355 L<http://libguestfs.org>,
8356 L<Sys::Guestfs::Lib(3)>.
8357
8358 =cut
8359 " copyright_years
8360
8361 and generate_perl_prototype name style =
8362   (match fst style with
8363    | RErr -> ()
8364    | RBool n
8365    | RInt n
8366    | RInt64 n
8367    | RConstString n
8368    | RConstOptString n
8369    | RString n
8370    | RBufferOut n -> pr "$%s = " n
8371    | RStruct (n,_)
8372    | RHashtable n -> pr "%%%s = " n
8373    | RStringList n
8374    | RStructList (n,_) -> pr "@%s = " n
8375   );
8376   pr "$h->%s (" name;
8377   let comma = ref false in
8378   List.iter (
8379     fun arg ->
8380       if !comma then pr ", ";
8381       comma := true;
8382       match arg with
8383       | Pathname n | Device n | Dev_or_Path n | String n
8384       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8385           pr "$%s" n
8386       | StringList n | DeviceList n ->
8387           pr "\\@%s" n
8388   ) (snd style);
8389   pr ");"
8390
8391 (* Generate Python C module. *)
8392 and generate_python_c () =
8393   generate_header CStyle LGPLv2plus;
8394
8395   pr "\
8396 #include <Python.h>
8397
8398 #include <stdio.h>
8399 #include <stdlib.h>
8400 #include <assert.h>
8401
8402 #include \"guestfs.h\"
8403
8404 typedef struct {
8405   PyObject_HEAD
8406   guestfs_h *g;
8407 } Pyguestfs_Object;
8408
8409 static guestfs_h *
8410 get_handle (PyObject *obj)
8411 {
8412   assert (obj);
8413   assert (obj != Py_None);
8414   return ((Pyguestfs_Object *) obj)->g;
8415 }
8416
8417 static PyObject *
8418 put_handle (guestfs_h *g)
8419 {
8420   assert (g);
8421   return
8422     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8423 }
8424
8425 /* This list should be freed (but not the strings) after use. */
8426 static char **
8427 get_string_list (PyObject *obj)
8428 {
8429   int i, len;
8430   char **r;
8431
8432   assert (obj);
8433
8434   if (!PyList_Check (obj)) {
8435     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8436     return NULL;
8437   }
8438
8439   len = PyList_Size (obj);
8440   r = malloc (sizeof (char *) * (len+1));
8441   if (r == NULL) {
8442     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8443     return NULL;
8444   }
8445
8446   for (i = 0; i < len; ++i)
8447     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8448   r[len] = NULL;
8449
8450   return r;
8451 }
8452
8453 static PyObject *
8454 put_string_list (char * const * const argv)
8455 {
8456   PyObject *list;
8457   int argc, i;
8458
8459   for (argc = 0; argv[argc] != NULL; ++argc)
8460     ;
8461
8462   list = PyList_New (argc);
8463   for (i = 0; i < argc; ++i)
8464     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8465
8466   return list;
8467 }
8468
8469 static PyObject *
8470 put_table (char * const * const argv)
8471 {
8472   PyObject *list, *item;
8473   int argc, i;
8474
8475   for (argc = 0; argv[argc] != NULL; ++argc)
8476     ;
8477
8478   list = PyList_New (argc >> 1);
8479   for (i = 0; i < argc; i += 2) {
8480     item = PyTuple_New (2);
8481     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8482     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8483     PyList_SetItem (list, i >> 1, item);
8484   }
8485
8486   return list;
8487 }
8488
8489 static void
8490 free_strings (char **argv)
8491 {
8492   int argc;
8493
8494   for (argc = 0; argv[argc] != NULL; ++argc)
8495     free (argv[argc]);
8496   free (argv);
8497 }
8498
8499 static PyObject *
8500 py_guestfs_create (PyObject *self, PyObject *args)
8501 {
8502   guestfs_h *g;
8503
8504   g = guestfs_create ();
8505   if (g == NULL) {
8506     PyErr_SetString (PyExc_RuntimeError,
8507                      \"guestfs.create: failed to allocate handle\");
8508     return NULL;
8509   }
8510   guestfs_set_error_handler (g, NULL, NULL);
8511   return put_handle (g);
8512 }
8513
8514 static PyObject *
8515 py_guestfs_close (PyObject *self, PyObject *args)
8516 {
8517   PyObject *py_g;
8518   guestfs_h *g;
8519
8520   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
8521     return NULL;
8522   g = get_handle (py_g);
8523
8524   guestfs_close (g);
8525
8526   Py_INCREF (Py_None);
8527   return Py_None;
8528 }
8529
8530 ";
8531
8532   let emit_put_list_function typ =
8533     pr "static PyObject *\n";
8534     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
8535     pr "{\n";
8536     pr "  PyObject *list;\n";
8537     pr "  int i;\n";
8538     pr "\n";
8539     pr "  list = PyList_New (%ss->len);\n" typ;
8540     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
8541     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
8542     pr "  return list;\n";
8543     pr "};\n";
8544     pr "\n"
8545   in
8546
8547   (* Structures, turned into Python dictionaries. *)
8548   List.iter (
8549     fun (typ, cols) ->
8550       pr "static PyObject *\n";
8551       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
8552       pr "{\n";
8553       pr "  PyObject *dict;\n";
8554       pr "\n";
8555       pr "  dict = PyDict_New ();\n";
8556       List.iter (
8557         function
8558         | name, FString ->
8559             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8560             pr "                        PyString_FromString (%s->%s));\n"
8561               typ name
8562         | name, FBuffer ->
8563             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8564             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
8565               typ name typ name
8566         | name, FUUID ->
8567             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8568             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
8569               typ name
8570         | name, (FBytes|FUInt64) ->
8571             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8572             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
8573               typ name
8574         | name, FInt64 ->
8575             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8576             pr "                        PyLong_FromLongLong (%s->%s));\n"
8577               typ name
8578         | name, FUInt32 ->
8579             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8580             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
8581               typ name
8582         | name, FInt32 ->
8583             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8584             pr "                        PyLong_FromLong (%s->%s));\n"
8585               typ name
8586         | name, FOptPercent ->
8587             pr "  if (%s->%s >= 0)\n" typ name;
8588             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
8589             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
8590               typ name;
8591             pr "  else {\n";
8592             pr "    Py_INCREF (Py_None);\n";
8593             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
8594             pr "  }\n"
8595         | name, FChar ->
8596             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8597             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
8598       ) cols;
8599       pr "  return dict;\n";
8600       pr "};\n";
8601       pr "\n";
8602
8603   ) structs;
8604
8605   (* Emit a put_TYPE_list function definition only if that function is used. *)
8606   List.iter (
8607     function
8608     | typ, (RStructListOnly | RStructAndList) ->
8609         (* generate the function for typ *)
8610         emit_put_list_function typ
8611     | typ, _ -> () (* empty *)
8612   ) (rstructs_used_by all_functions);
8613
8614   (* Python wrapper functions. *)
8615   List.iter (
8616     fun (name, style, _, _, _, _, _) ->
8617       pr "static PyObject *\n";
8618       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
8619       pr "{\n";
8620
8621       pr "  PyObject *py_g;\n";
8622       pr "  guestfs_h *g;\n";
8623       pr "  PyObject *py_r;\n";
8624
8625       let error_code =
8626         match fst style with
8627         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
8628         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8629         | RConstString _ | RConstOptString _ ->
8630             pr "  const char *r;\n"; "NULL"
8631         | RString _ -> pr "  char *r;\n"; "NULL"
8632         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
8633         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
8634         | RStructList (_, typ) ->
8635             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8636         | RBufferOut _ ->
8637             pr "  char *r;\n";
8638             pr "  size_t size;\n";
8639             "NULL" in
8640
8641       List.iter (
8642         function
8643         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8644             pr "  const char *%s;\n" n
8645         | OptString n -> pr "  const char *%s;\n" n
8646         | StringList n | DeviceList n ->
8647             pr "  PyObject *py_%s;\n" n;
8648             pr "  char **%s;\n" n
8649         | Bool n -> pr "  int %s;\n" n
8650         | Int n -> pr "  int %s;\n" n
8651         | Int64 n -> pr "  long long %s;\n" n
8652       ) (snd style);
8653
8654       pr "\n";
8655
8656       (* Convert the parameters. *)
8657       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
8658       List.iter (
8659         function
8660         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
8661         | OptString _ -> pr "z"
8662         | StringList _ | DeviceList _ -> pr "O"
8663         | Bool _ -> pr "i" (* XXX Python has booleans? *)
8664         | Int _ -> pr "i"
8665         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
8666                              * emulate C's int/long/long long in Python?
8667                              *)
8668       ) (snd style);
8669       pr ":guestfs_%s\",\n" name;
8670       pr "                         &py_g";
8671       List.iter (
8672         function
8673         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
8674         | OptString n -> pr ", &%s" n
8675         | StringList n | DeviceList n -> pr ", &py_%s" n
8676         | Bool n -> pr ", &%s" n
8677         | Int n -> pr ", &%s" n
8678         | Int64 n -> pr ", &%s" n
8679       ) (snd style);
8680
8681       pr "))\n";
8682       pr "    return NULL;\n";
8683
8684       pr "  g = get_handle (py_g);\n";
8685       List.iter (
8686         function
8687         | Pathname _ | Device _ | Dev_or_Path _ | String _
8688         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8689         | StringList n | DeviceList n ->
8690             pr "  %s = get_string_list (py_%s);\n" n n;
8691             pr "  if (!%s) return NULL;\n" n
8692       ) (snd style);
8693
8694       pr "\n";
8695
8696       pr "  r = guestfs_%s " name;
8697       generate_c_call_args ~handle:"g" style;
8698       pr ";\n";
8699
8700       List.iter (
8701         function
8702         | Pathname _ | Device _ | Dev_or_Path _ | String _
8703         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8704         | StringList n | DeviceList n ->
8705             pr "  free (%s);\n" n
8706       ) (snd style);
8707
8708       pr "  if (r == %s) {\n" error_code;
8709       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
8710       pr "    return NULL;\n";
8711       pr "  }\n";
8712       pr "\n";
8713
8714       (match fst style with
8715        | RErr ->
8716            pr "  Py_INCREF (Py_None);\n";
8717            pr "  py_r = Py_None;\n"
8718        | RInt _
8719        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
8720        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
8721        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
8722        | RConstOptString _ ->
8723            pr "  if (r)\n";
8724            pr "    py_r = PyString_FromString (r);\n";
8725            pr "  else {\n";
8726            pr "    Py_INCREF (Py_None);\n";
8727            pr "    py_r = Py_None;\n";
8728            pr "  }\n"
8729        | RString _ ->
8730            pr "  py_r = PyString_FromString (r);\n";
8731            pr "  free (r);\n"
8732        | RStringList _ ->
8733            pr "  py_r = put_string_list (r);\n";
8734            pr "  free_strings (r);\n"
8735        | RStruct (_, typ) ->
8736            pr "  py_r = put_%s (r);\n" typ;
8737            pr "  guestfs_free_%s (r);\n" typ
8738        | RStructList (_, typ) ->
8739            pr "  py_r = put_%s_list (r);\n" typ;
8740            pr "  guestfs_free_%s_list (r);\n" typ
8741        | RHashtable n ->
8742            pr "  py_r = put_table (r);\n";
8743            pr "  free_strings (r);\n"
8744        | RBufferOut _ ->
8745            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
8746            pr "  free (r);\n"
8747       );
8748
8749       pr "  return py_r;\n";
8750       pr "}\n";
8751       pr "\n"
8752   ) all_functions;
8753
8754   (* Table of functions. *)
8755   pr "static PyMethodDef methods[] = {\n";
8756   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
8757   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
8758   List.iter (
8759     fun (name, _, _, _, _, _, _) ->
8760       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
8761         name name
8762   ) all_functions;
8763   pr "  { NULL, NULL, 0, NULL }\n";
8764   pr "};\n";
8765   pr "\n";
8766
8767   (* Init function. *)
8768   pr "\
8769 void
8770 initlibguestfsmod (void)
8771 {
8772   static int initialized = 0;
8773
8774   if (initialized) return;
8775   Py_InitModule ((char *) \"libguestfsmod\", methods);
8776   initialized = 1;
8777 }
8778 "
8779
8780 (* Generate Python module. *)
8781 and generate_python_py () =
8782   generate_header HashStyle LGPLv2plus;
8783
8784   pr "\
8785 u\"\"\"Python bindings for libguestfs
8786
8787 import guestfs
8788 g = guestfs.GuestFS ()
8789 g.add_drive (\"guest.img\")
8790 g.launch ()
8791 parts = g.list_partitions ()
8792
8793 The guestfs module provides a Python binding to the libguestfs API
8794 for examining and modifying virtual machine disk images.
8795
8796 Amongst the things this is good for: making batch configuration
8797 changes to guests, getting disk used/free statistics (see also:
8798 virt-df), migrating between virtualization systems (see also:
8799 virt-p2v), performing partial backups, performing partial guest
8800 clones, cloning guests and changing registry/UUID/hostname info, and
8801 much else besides.
8802
8803 Libguestfs uses Linux kernel and qemu code, and can access any type of
8804 guest filesystem that Linux and qemu can, including but not limited
8805 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8806 schemes, qcow, qcow2, vmdk.
8807
8808 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8809 LVs, what filesystem is in each LV, etc.).  It can also run commands
8810 in the context of the guest.  Also you can access filesystems over FTP.
8811
8812 Errors which happen while using the API are turned into Python
8813 RuntimeError exceptions.
8814
8815 To create a guestfs handle you usually have to perform the following
8816 sequence of calls:
8817
8818 # Create the handle, call add_drive at least once, and possibly
8819 # several times if the guest has multiple block devices:
8820 g = guestfs.GuestFS ()
8821 g.add_drive (\"guest.img\")
8822
8823 # Launch the qemu subprocess and wait for it to become ready:
8824 g.launch ()
8825
8826 # Now you can issue commands, for example:
8827 logvols = g.lvs ()
8828
8829 \"\"\"
8830
8831 import libguestfsmod
8832
8833 class GuestFS:
8834     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
8835
8836     def __init__ (self):
8837         \"\"\"Create a new libguestfs handle.\"\"\"
8838         self._o = libguestfsmod.create ()
8839
8840     def __del__ (self):
8841         libguestfsmod.close (self._o)
8842
8843 ";
8844
8845   List.iter (
8846     fun (name, style, _, flags, _, _, longdesc) ->
8847       pr "    def %s " name;
8848       generate_py_call_args ~handle:"self" (snd style);
8849       pr ":\n";
8850
8851       if not (List.mem NotInDocs flags) then (
8852         let doc = replace_str longdesc "C<guestfs_" "C<g." in
8853         let doc =
8854           match fst style with
8855           | RErr | RInt _ | RInt64 _ | RBool _
8856           | RConstOptString _ | RConstString _
8857           | RString _ | RBufferOut _ -> doc
8858           | RStringList _ ->
8859               doc ^ "\n\nThis function returns a list of strings."
8860           | RStruct (_, typ) ->
8861               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
8862           | RStructList (_, typ) ->
8863               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
8864           | RHashtable _ ->
8865               doc ^ "\n\nThis function returns a dictionary." in
8866         let doc =
8867           if List.mem ProtocolLimitWarning flags then
8868             doc ^ "\n\n" ^ protocol_limit_warning
8869           else doc in
8870         let doc =
8871           if List.mem DangerWillRobinson flags then
8872             doc ^ "\n\n" ^ danger_will_robinson
8873           else doc in
8874         let doc =
8875           match deprecation_notice flags with
8876           | None -> doc
8877           | Some txt -> doc ^ "\n\n" ^ txt in
8878         let doc = pod2text ~width:60 name doc in
8879         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
8880         let doc = String.concat "\n        " doc in
8881         pr "        u\"\"\"%s\"\"\"\n" doc;
8882       );
8883       pr "        return libguestfsmod.%s " name;
8884       generate_py_call_args ~handle:"self._o" (snd style);
8885       pr "\n";
8886       pr "\n";
8887   ) all_functions
8888
8889 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
8890 and generate_py_call_args ~handle args =
8891   pr "(%s" handle;
8892   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
8893   pr ")"
8894
8895 (* Useful if you need the longdesc POD text as plain text.  Returns a
8896  * list of lines.
8897  *
8898  * Because this is very slow (the slowest part of autogeneration),
8899  * we memoize the results.
8900  *)
8901 and pod2text ~width name longdesc =
8902   let key = width, name, longdesc in
8903   try Hashtbl.find pod2text_memo key
8904   with Not_found ->
8905     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
8906     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
8907     close_out chan;
8908     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
8909     let chan = open_process_in cmd in
8910     let lines = ref [] in
8911     let rec loop i =
8912       let line = input_line chan in
8913       if i = 1 then             (* discard the first line of output *)
8914         loop (i+1)
8915       else (
8916         let line = triml line in
8917         lines := line :: !lines;
8918         loop (i+1)
8919       ) in
8920     let lines = try loop 1 with End_of_file -> List.rev !lines in
8921     unlink filename;
8922     (match close_process_in chan with
8923      | WEXITED 0 -> ()
8924      | WEXITED i ->
8925          failwithf "pod2text: process exited with non-zero status (%d)" i
8926      | WSIGNALED i | WSTOPPED i ->
8927          failwithf "pod2text: process signalled or stopped by signal %d" i
8928     );
8929     Hashtbl.add pod2text_memo key lines;
8930     pod2text_memo_updated ();
8931     lines
8932
8933 (* Generate ruby bindings. *)
8934 and generate_ruby_c () =
8935   generate_header CStyle LGPLv2plus;
8936
8937   pr "\
8938 #include <stdio.h>
8939 #include <stdlib.h>
8940
8941 #include <ruby.h>
8942
8943 #include \"guestfs.h\"
8944
8945 #include \"extconf.h\"
8946
8947 /* For Ruby < 1.9 */
8948 #ifndef RARRAY_LEN
8949 #define RARRAY_LEN(r) (RARRAY((r))->len)
8950 #endif
8951
8952 static VALUE m_guestfs;                 /* guestfs module */
8953 static VALUE c_guestfs;                 /* guestfs_h handle */
8954 static VALUE e_Error;                   /* used for all errors */
8955
8956 static void ruby_guestfs_free (void *p)
8957 {
8958   if (!p) return;
8959   guestfs_close ((guestfs_h *) p);
8960 }
8961
8962 static VALUE ruby_guestfs_create (VALUE m)
8963 {
8964   guestfs_h *g;
8965
8966   g = guestfs_create ();
8967   if (!g)
8968     rb_raise (e_Error, \"failed to create guestfs handle\");
8969
8970   /* Don't print error messages to stderr by default. */
8971   guestfs_set_error_handler (g, NULL, NULL);
8972
8973   /* Wrap it, and make sure the close function is called when the
8974    * handle goes away.
8975    */
8976   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
8977 }
8978
8979 static VALUE ruby_guestfs_close (VALUE gv)
8980 {
8981   guestfs_h *g;
8982   Data_Get_Struct (gv, guestfs_h, g);
8983
8984   ruby_guestfs_free (g);
8985   DATA_PTR (gv) = NULL;
8986
8987   return Qnil;
8988 }
8989
8990 ";
8991
8992   List.iter (
8993     fun (name, style, _, _, _, _, _) ->
8994       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
8995       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
8996       pr ")\n";
8997       pr "{\n";
8998       pr "  guestfs_h *g;\n";
8999       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9000       pr "  if (!g)\n";
9001       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9002         name;
9003       pr "\n";
9004
9005       List.iter (
9006         function
9007         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9008             pr "  Check_Type (%sv, T_STRING);\n" n;
9009             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9010             pr "  if (!%s)\n" n;
9011             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9012             pr "              \"%s\", \"%s\");\n" n name
9013         | OptString n ->
9014             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9015         | StringList n | DeviceList n ->
9016             pr "  char **%s;\n" n;
9017             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9018             pr "  {\n";
9019             pr "    int i, len;\n";
9020             pr "    len = RARRAY_LEN (%sv);\n" n;
9021             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9022               n;
9023             pr "    for (i = 0; i < len; ++i) {\n";
9024             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9025             pr "      %s[i] = StringValueCStr (v);\n" n;
9026             pr "    }\n";
9027             pr "    %s[len] = NULL;\n" n;
9028             pr "  }\n";
9029         | Bool n ->
9030             pr "  int %s = RTEST (%sv);\n" n n
9031         | Int n ->
9032             pr "  int %s = NUM2INT (%sv);\n" n n
9033         | Int64 n ->
9034             pr "  long long %s = NUM2LL (%sv);\n" n n
9035       ) (snd style);
9036       pr "\n";
9037
9038       let error_code =
9039         match fst style with
9040         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9041         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9042         | RConstString _ | RConstOptString _ ->
9043             pr "  const char *r;\n"; "NULL"
9044         | RString _ -> pr "  char *r;\n"; "NULL"
9045         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9046         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9047         | RStructList (_, typ) ->
9048             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9049         | RBufferOut _ ->
9050             pr "  char *r;\n";
9051             pr "  size_t size;\n";
9052             "NULL" in
9053       pr "\n";
9054
9055       pr "  r = guestfs_%s " name;
9056       generate_c_call_args ~handle:"g" style;
9057       pr ";\n";
9058
9059       List.iter (
9060         function
9061         | Pathname _ | Device _ | Dev_or_Path _ | String _
9062         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9063         | StringList n | DeviceList n ->
9064             pr "  free (%s);\n" n
9065       ) (snd style);
9066
9067       pr "  if (r == %s)\n" error_code;
9068       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9069       pr "\n";
9070
9071       (match fst style with
9072        | RErr ->
9073            pr "  return Qnil;\n"
9074        | RInt _ | RBool _ ->
9075            pr "  return INT2NUM (r);\n"
9076        | RInt64 _ ->
9077            pr "  return ULL2NUM (r);\n"
9078        | RConstString _ ->
9079            pr "  return rb_str_new2 (r);\n";
9080        | RConstOptString _ ->
9081            pr "  if (r)\n";
9082            pr "    return rb_str_new2 (r);\n";
9083            pr "  else\n";
9084            pr "    return Qnil;\n";
9085        | RString _ ->
9086            pr "  VALUE rv = rb_str_new2 (r);\n";
9087            pr "  free (r);\n";
9088            pr "  return rv;\n";
9089        | RStringList _ ->
9090            pr "  int i, len = 0;\n";
9091            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9092            pr "  VALUE rv = rb_ary_new2 (len);\n";
9093            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9094            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9095            pr "    free (r[i]);\n";
9096            pr "  }\n";
9097            pr "  free (r);\n";
9098            pr "  return rv;\n"
9099        | RStruct (_, typ) ->
9100            let cols = cols_of_struct typ in
9101            generate_ruby_struct_code typ cols
9102        | RStructList (_, typ) ->
9103            let cols = cols_of_struct typ in
9104            generate_ruby_struct_list_code typ cols
9105        | RHashtable _ ->
9106            pr "  VALUE rv = rb_hash_new ();\n";
9107            pr "  int i;\n";
9108            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9109            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9110            pr "    free (r[i]);\n";
9111            pr "    free (r[i+1]);\n";
9112            pr "  }\n";
9113            pr "  free (r);\n";
9114            pr "  return rv;\n"
9115        | RBufferOut _ ->
9116            pr "  VALUE rv = rb_str_new (r, size);\n";
9117            pr "  free (r);\n";
9118            pr "  return rv;\n";
9119       );
9120
9121       pr "}\n";
9122       pr "\n"
9123   ) all_functions;
9124
9125   pr "\
9126 /* Initialize the module. */
9127 void Init__guestfs ()
9128 {
9129   m_guestfs = rb_define_module (\"Guestfs\");
9130   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9131   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9132
9133   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9134   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9135
9136 ";
9137   (* Define the rest of the methods. *)
9138   List.iter (
9139     fun (name, style, _, _, _, _, _) ->
9140       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9141       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9142   ) all_functions;
9143
9144   pr "}\n"
9145
9146 (* Ruby code to return a struct. *)
9147 and generate_ruby_struct_code typ cols =
9148   pr "  VALUE rv = rb_hash_new ();\n";
9149   List.iter (
9150     function
9151     | name, FString ->
9152         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9153     | name, FBuffer ->
9154         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9155     | name, FUUID ->
9156         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9157     | name, (FBytes|FUInt64) ->
9158         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9159     | name, FInt64 ->
9160         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9161     | name, FUInt32 ->
9162         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9163     | name, FInt32 ->
9164         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9165     | name, FOptPercent ->
9166         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9167     | name, FChar -> (* XXX wrong? *)
9168         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9169   ) cols;
9170   pr "  guestfs_free_%s (r);\n" typ;
9171   pr "  return rv;\n"
9172
9173 (* Ruby code to return a struct list. *)
9174 and generate_ruby_struct_list_code typ cols =
9175   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9176   pr "  int i;\n";
9177   pr "  for (i = 0; i < r->len; ++i) {\n";
9178   pr "    VALUE hv = rb_hash_new ();\n";
9179   List.iter (
9180     function
9181     | name, FString ->
9182         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9183     | name, FBuffer ->
9184         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
9185     | name, FUUID ->
9186         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9187     | name, (FBytes|FUInt64) ->
9188         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9189     | name, FInt64 ->
9190         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9191     | name, FUInt32 ->
9192         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9193     | name, FInt32 ->
9194         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9195     | name, FOptPercent ->
9196         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9197     | name, FChar -> (* XXX wrong? *)
9198         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9199   ) cols;
9200   pr "    rb_ary_push (rv, hv);\n";
9201   pr "  }\n";
9202   pr "  guestfs_free_%s_list (r);\n" typ;
9203   pr "  return rv;\n"
9204
9205 (* Generate Java bindings GuestFS.java file. *)
9206 and generate_java_java () =
9207   generate_header CStyle LGPLv2plus;
9208
9209   pr "\
9210 package com.redhat.et.libguestfs;
9211
9212 import java.util.HashMap;
9213 import com.redhat.et.libguestfs.LibGuestFSException;
9214 import com.redhat.et.libguestfs.PV;
9215 import com.redhat.et.libguestfs.VG;
9216 import com.redhat.et.libguestfs.LV;
9217 import com.redhat.et.libguestfs.Stat;
9218 import com.redhat.et.libguestfs.StatVFS;
9219 import com.redhat.et.libguestfs.IntBool;
9220 import com.redhat.et.libguestfs.Dirent;
9221
9222 /**
9223  * The GuestFS object is a libguestfs handle.
9224  *
9225  * @author rjones
9226  */
9227 public class GuestFS {
9228   // Load the native code.
9229   static {
9230     System.loadLibrary (\"guestfs_jni\");
9231   }
9232
9233   /**
9234    * The native guestfs_h pointer.
9235    */
9236   long g;
9237
9238   /**
9239    * Create a libguestfs handle.
9240    *
9241    * @throws LibGuestFSException
9242    */
9243   public GuestFS () throws LibGuestFSException
9244   {
9245     g = _create ();
9246   }
9247   private native long _create () throws LibGuestFSException;
9248
9249   /**
9250    * Close a libguestfs handle.
9251    *
9252    * You can also leave handles to be collected by the garbage
9253    * collector, but this method ensures that the resources used
9254    * by the handle are freed up immediately.  If you call any
9255    * other methods after closing the handle, you will get an
9256    * exception.
9257    *
9258    * @throws LibGuestFSException
9259    */
9260   public void close () throws LibGuestFSException
9261   {
9262     if (g != 0)
9263       _close (g);
9264     g = 0;
9265   }
9266   private native void _close (long g) throws LibGuestFSException;
9267
9268   public void finalize () throws LibGuestFSException
9269   {
9270     close ();
9271   }
9272
9273 ";
9274
9275   List.iter (
9276     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9277       if not (List.mem NotInDocs flags); then (
9278         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9279         let doc =
9280           if List.mem ProtocolLimitWarning flags then
9281             doc ^ "\n\n" ^ protocol_limit_warning
9282           else doc in
9283         let doc =
9284           if List.mem DangerWillRobinson flags then
9285             doc ^ "\n\n" ^ danger_will_robinson
9286           else doc in
9287         let doc =
9288           match deprecation_notice flags with
9289           | None -> doc
9290           | Some txt -> doc ^ "\n\n" ^ txt in
9291         let doc = pod2text ~width:60 name doc in
9292         let doc = List.map (            (* RHBZ#501883 *)
9293           function
9294           | "" -> "<p>"
9295           | nonempty -> nonempty
9296         ) doc in
9297         let doc = String.concat "\n   * " doc in
9298
9299         pr "  /**\n";
9300         pr "   * %s\n" shortdesc;
9301         pr "   * <p>\n";
9302         pr "   * %s\n" doc;
9303         pr "   * @throws LibGuestFSException\n";
9304         pr "   */\n";
9305         pr "  ";
9306       );
9307       generate_java_prototype ~public:true ~semicolon:false name style;
9308       pr "\n";
9309       pr "  {\n";
9310       pr "    if (g == 0)\n";
9311       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9312         name;
9313       pr "    ";
9314       if fst style <> RErr then pr "return ";
9315       pr "_%s " name;
9316       generate_java_call_args ~handle:"g" (snd style);
9317       pr ";\n";
9318       pr "  }\n";
9319       pr "  ";
9320       generate_java_prototype ~privat:true ~native:true name style;
9321       pr "\n";
9322       pr "\n";
9323   ) all_functions;
9324
9325   pr "}\n"
9326
9327 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9328 and generate_java_call_args ~handle args =
9329   pr "(%s" handle;
9330   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9331   pr ")"
9332
9333 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9334     ?(semicolon=true) name style =
9335   if privat then pr "private ";
9336   if public then pr "public ";
9337   if native then pr "native ";
9338
9339   (* return type *)
9340   (match fst style with
9341    | RErr -> pr "void ";
9342    | RInt _ -> pr "int ";
9343    | RInt64 _ -> pr "long ";
9344    | RBool _ -> pr "boolean ";
9345    | RConstString _ | RConstOptString _ | RString _
9346    | RBufferOut _ -> pr "String ";
9347    | RStringList _ -> pr "String[] ";
9348    | RStruct (_, typ) ->
9349        let name = java_name_of_struct typ in
9350        pr "%s " name;
9351    | RStructList (_, typ) ->
9352        let name = java_name_of_struct typ in
9353        pr "%s[] " name;
9354    | RHashtable _ -> pr "HashMap<String,String> ";
9355   );
9356
9357   if native then pr "_%s " name else pr "%s " name;
9358   pr "(";
9359   let needs_comma = ref false in
9360   if native then (
9361     pr "long g";
9362     needs_comma := true
9363   );
9364
9365   (* args *)
9366   List.iter (
9367     fun arg ->
9368       if !needs_comma then pr ", ";
9369       needs_comma := true;
9370
9371       match arg with
9372       | Pathname n
9373       | Device n | Dev_or_Path n
9374       | String n
9375       | OptString n
9376       | FileIn n
9377       | FileOut n ->
9378           pr "String %s" n
9379       | StringList n | DeviceList n ->
9380           pr "String[] %s" n
9381       | Bool n ->
9382           pr "boolean %s" n
9383       | Int n ->
9384           pr "int %s" n
9385       | Int64 n ->
9386           pr "long %s" n
9387   ) (snd style);
9388
9389   pr ")\n";
9390   pr "    throws LibGuestFSException";
9391   if semicolon then pr ";"
9392
9393 and generate_java_struct jtyp cols () =
9394   generate_header CStyle LGPLv2plus;
9395
9396   pr "\
9397 package com.redhat.et.libguestfs;
9398
9399 /**
9400  * Libguestfs %s structure.
9401  *
9402  * @author rjones
9403  * @see GuestFS
9404  */
9405 public class %s {
9406 " jtyp jtyp;
9407
9408   List.iter (
9409     function
9410     | name, FString
9411     | name, FUUID
9412     | name, FBuffer -> pr "  public String %s;\n" name
9413     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9414     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9415     | name, FChar -> pr "  public char %s;\n" name
9416     | name, FOptPercent ->
9417         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9418         pr "  public float %s;\n" name
9419   ) cols;
9420
9421   pr "}\n"
9422
9423 and generate_java_c () =
9424   generate_header CStyle LGPLv2plus;
9425
9426   pr "\
9427 #include <stdio.h>
9428 #include <stdlib.h>
9429 #include <string.h>
9430
9431 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9432 #include \"guestfs.h\"
9433
9434 /* Note that this function returns.  The exception is not thrown
9435  * until after the wrapper function returns.
9436  */
9437 static void
9438 throw_exception (JNIEnv *env, const char *msg)
9439 {
9440   jclass cl;
9441   cl = (*env)->FindClass (env,
9442                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9443   (*env)->ThrowNew (env, cl, msg);
9444 }
9445
9446 JNIEXPORT jlong JNICALL
9447 Java_com_redhat_et_libguestfs_GuestFS__1create
9448   (JNIEnv *env, jobject obj)
9449 {
9450   guestfs_h *g;
9451
9452   g = guestfs_create ();
9453   if (g == NULL) {
9454     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9455     return 0;
9456   }
9457   guestfs_set_error_handler (g, NULL, NULL);
9458   return (jlong) (long) g;
9459 }
9460
9461 JNIEXPORT void JNICALL
9462 Java_com_redhat_et_libguestfs_GuestFS__1close
9463   (JNIEnv *env, jobject obj, jlong jg)
9464 {
9465   guestfs_h *g = (guestfs_h *) (long) jg;
9466   guestfs_close (g);
9467 }
9468
9469 ";
9470
9471   List.iter (
9472     fun (name, style, _, _, _, _, _) ->
9473       pr "JNIEXPORT ";
9474       (match fst style with
9475        | RErr -> pr "void ";
9476        | RInt _ -> pr "jint ";
9477        | RInt64 _ -> pr "jlong ";
9478        | RBool _ -> pr "jboolean ";
9479        | RConstString _ | RConstOptString _ | RString _
9480        | RBufferOut _ -> pr "jstring ";
9481        | RStruct _ | RHashtable _ ->
9482            pr "jobject ";
9483        | RStringList _ | RStructList _ ->
9484            pr "jobjectArray ";
9485       );
9486       pr "JNICALL\n";
9487       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9488       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9489       pr "\n";
9490       pr "  (JNIEnv *env, jobject obj, jlong jg";
9491       List.iter (
9492         function
9493         | Pathname n
9494         | Device n | Dev_or_Path n
9495         | String n
9496         | OptString n
9497         | FileIn n
9498         | FileOut n ->
9499             pr ", jstring j%s" n
9500         | StringList n | DeviceList n ->
9501             pr ", jobjectArray j%s" n
9502         | Bool n ->
9503             pr ", jboolean j%s" n
9504         | Int n ->
9505             pr ", jint j%s" n
9506         | Int64 n ->
9507             pr ", jlong j%s" n
9508       ) (snd style);
9509       pr ")\n";
9510       pr "{\n";
9511       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
9512       let error_code, no_ret =
9513         match fst style with
9514         | RErr -> pr "  int r;\n"; "-1", ""
9515         | RBool _
9516         | RInt _ -> pr "  int r;\n"; "-1", "0"
9517         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
9518         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9519         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9520         | RString _ ->
9521             pr "  jstring jr;\n";
9522             pr "  char *r;\n"; "NULL", "NULL"
9523         | RStringList _ ->
9524             pr "  jobjectArray jr;\n";
9525             pr "  int r_len;\n";
9526             pr "  jclass cl;\n";
9527             pr "  jstring jstr;\n";
9528             pr "  char **r;\n"; "NULL", "NULL"
9529         | RStruct (_, typ) ->
9530             pr "  jobject jr;\n";
9531             pr "  jclass cl;\n";
9532             pr "  jfieldID fl;\n";
9533             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
9534         | RStructList (_, typ) ->
9535             pr "  jobjectArray jr;\n";
9536             pr "  jclass cl;\n";
9537             pr "  jfieldID fl;\n";
9538             pr "  jobject jfl;\n";
9539             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
9540         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
9541         | RBufferOut _ ->
9542             pr "  jstring jr;\n";
9543             pr "  char *r;\n";
9544             pr "  size_t size;\n";
9545             "NULL", "NULL" in
9546       List.iter (
9547         function
9548         | Pathname n
9549         | Device n | Dev_or_Path n
9550         | String n
9551         | OptString n
9552         | FileIn n
9553         | FileOut n ->
9554             pr "  const char *%s;\n" n
9555         | StringList n | DeviceList n ->
9556             pr "  int %s_len;\n" n;
9557             pr "  const char **%s;\n" n
9558         | Bool n
9559         | Int n ->
9560             pr "  int %s;\n" n
9561         | Int64 n ->
9562             pr "  int64_t %s;\n" n
9563       ) (snd style);
9564
9565       let needs_i =
9566         (match fst style with
9567          | RStringList _ | RStructList _ -> true
9568          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
9569          | RConstOptString _
9570          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
9571           List.exists (function
9572                        | StringList _ -> true
9573                        | DeviceList _ -> true
9574                        | _ -> false) (snd style) in
9575       if needs_i then
9576         pr "  int i;\n";
9577
9578       pr "\n";
9579
9580       (* Get the parameters. *)
9581       List.iter (
9582         function
9583         | Pathname n
9584         | Device n | Dev_or_Path n
9585         | String n
9586         | FileIn n
9587         | FileOut n ->
9588             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
9589         | OptString n ->
9590             (* This is completely undocumented, but Java null becomes
9591              * a NULL parameter.
9592              *)
9593             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
9594         | StringList n | DeviceList n ->
9595             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
9596             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
9597             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9598             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9599               n;
9600             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
9601             pr "  }\n";
9602             pr "  %s[%s_len] = NULL;\n" n n;
9603         | Bool n
9604         | Int n
9605         | Int64 n ->
9606             pr "  %s = j%s;\n" n n
9607       ) (snd style);
9608
9609       (* Make the call. *)
9610       pr "  r = guestfs_%s " name;
9611       generate_c_call_args ~handle:"g" style;
9612       pr ";\n";
9613
9614       (* Release the parameters. *)
9615       List.iter (
9616         function
9617         | Pathname n
9618         | Device n | Dev_or_Path n
9619         | String n
9620         | FileIn n
9621         | FileOut n ->
9622             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9623         | OptString n ->
9624             pr "  if (j%s)\n" n;
9625             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9626         | StringList n | DeviceList n ->
9627             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9628             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9629               n;
9630             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
9631             pr "  }\n";
9632             pr "  free (%s);\n" n
9633         | Bool n
9634         | Int n
9635         | Int64 n -> ()
9636       ) (snd style);
9637
9638       (* Check for errors. *)
9639       pr "  if (r == %s) {\n" error_code;
9640       pr "    throw_exception (env, guestfs_last_error (g));\n";
9641       pr "    return %s;\n" no_ret;
9642       pr "  }\n";
9643
9644       (* Return value. *)
9645       (match fst style with
9646        | RErr -> ()
9647        | RInt _ -> pr "  return (jint) r;\n"
9648        | RBool _ -> pr "  return (jboolean) r;\n"
9649        | RInt64 _ -> pr "  return (jlong) r;\n"
9650        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
9651        | RConstOptString _ ->
9652            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
9653        | RString _ ->
9654            pr "  jr = (*env)->NewStringUTF (env, r);\n";
9655            pr "  free (r);\n";
9656            pr "  return jr;\n"
9657        | RStringList _ ->
9658            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
9659            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
9660            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
9661            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
9662            pr "  for (i = 0; i < r_len; ++i) {\n";
9663            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
9664            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
9665            pr "    free (r[i]);\n";
9666            pr "  }\n";
9667            pr "  free (r);\n";
9668            pr "  return jr;\n"
9669        | RStruct (_, typ) ->
9670            let jtyp = java_name_of_struct typ in
9671            let cols = cols_of_struct typ in
9672            generate_java_struct_return typ jtyp cols
9673        | RStructList (_, typ) ->
9674            let jtyp = java_name_of_struct typ in
9675            let cols = cols_of_struct typ in
9676            generate_java_struct_list_return typ jtyp cols
9677        | RHashtable _ ->
9678            (* XXX *)
9679            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
9680            pr "  return NULL;\n"
9681        | RBufferOut _ ->
9682            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
9683            pr "  free (r);\n";
9684            pr "  return jr;\n"
9685       );
9686
9687       pr "}\n";
9688       pr "\n"
9689   ) all_functions
9690
9691 and generate_java_struct_return typ jtyp cols =
9692   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9693   pr "  jr = (*env)->AllocObject (env, cl);\n";
9694   List.iter (
9695     function
9696     | name, FString ->
9697         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9698         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
9699     | name, FUUID ->
9700         pr "  {\n";
9701         pr "    char s[33];\n";
9702         pr "    memcpy (s, r->%s, 32);\n" name;
9703         pr "    s[32] = 0;\n";
9704         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9705         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9706         pr "  }\n";
9707     | name, FBuffer ->
9708         pr "  {\n";
9709         pr "    int len = r->%s_len;\n" name;
9710         pr "    char s[len+1];\n";
9711         pr "    memcpy (s, r->%s, len);\n" name;
9712         pr "    s[len] = 0;\n";
9713         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9714         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9715         pr "  }\n";
9716     | name, (FBytes|FUInt64|FInt64) ->
9717         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9718         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9719     | name, (FUInt32|FInt32) ->
9720         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9721         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9722     | name, FOptPercent ->
9723         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9724         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
9725     | name, FChar ->
9726         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9727         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9728   ) cols;
9729   pr "  free (r);\n";
9730   pr "  return jr;\n"
9731
9732 and generate_java_struct_list_return typ jtyp cols =
9733   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9734   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
9735   pr "  for (i = 0; i < r->len; ++i) {\n";
9736   pr "    jfl = (*env)->AllocObject (env, cl);\n";
9737   List.iter (
9738     function
9739     | name, FString ->
9740         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9741         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
9742     | name, FUUID ->
9743         pr "    {\n";
9744         pr "      char s[33];\n";
9745         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
9746         pr "      s[32] = 0;\n";
9747         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9748         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9749         pr "    }\n";
9750     | name, FBuffer ->
9751         pr "    {\n";
9752         pr "      int len = r->val[i].%s_len;\n" name;
9753         pr "      char s[len+1];\n";
9754         pr "      memcpy (s, r->val[i].%s, len);\n" name;
9755         pr "      s[len] = 0;\n";
9756         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9757         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9758         pr "    }\n";
9759     | name, (FBytes|FUInt64|FInt64) ->
9760         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9761         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9762     | name, (FUInt32|FInt32) ->
9763         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9764         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9765     | name, FOptPercent ->
9766         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9767         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
9768     | name, FChar ->
9769         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9770         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9771   ) cols;
9772   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
9773   pr "  }\n";
9774   pr "  guestfs_free_%s_list (r);\n" typ;
9775   pr "  return jr;\n"
9776
9777 and generate_java_makefile_inc () =
9778   generate_header HashStyle GPLv2plus;
9779
9780   pr "java_built_sources = \\\n";
9781   List.iter (
9782     fun (typ, jtyp) ->
9783         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
9784   ) java_structs;
9785   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
9786
9787 and generate_haskell_hs () =
9788   generate_header HaskellStyle LGPLv2plus;
9789
9790   (* XXX We only know how to generate partial FFI for Haskell
9791    * at the moment.  Please help out!
9792    *)
9793   let can_generate style =
9794     match style with
9795     | RErr, _
9796     | RInt _, _
9797     | RInt64 _, _ -> true
9798     | RBool _, _
9799     | RConstString _, _
9800     | RConstOptString _, _
9801     | RString _, _
9802     | RStringList _, _
9803     | RStruct _, _
9804     | RStructList _, _
9805     | RHashtable _, _
9806     | RBufferOut _, _ -> false in
9807
9808   pr "\
9809 {-# INCLUDE <guestfs.h> #-}
9810 {-# LANGUAGE ForeignFunctionInterface #-}
9811
9812 module Guestfs (
9813   create";
9814
9815   (* List out the names of the actions we want to export. *)
9816   List.iter (
9817     fun (name, style, _, _, _, _, _) ->
9818       if can_generate style then pr ",\n  %s" name
9819   ) all_functions;
9820
9821   pr "
9822   ) where
9823
9824 -- Unfortunately some symbols duplicate ones already present
9825 -- in Prelude.  We don't know which, so we hard-code a list
9826 -- here.
9827 import Prelude hiding (truncate)
9828
9829 import Foreign
9830 import Foreign.C
9831 import Foreign.C.Types
9832 import IO
9833 import Control.Exception
9834 import Data.Typeable
9835
9836 data GuestfsS = GuestfsS            -- represents the opaque C struct
9837 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
9838 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
9839
9840 -- XXX define properly later XXX
9841 data PV = PV
9842 data VG = VG
9843 data LV = LV
9844 data IntBool = IntBool
9845 data Stat = Stat
9846 data StatVFS = StatVFS
9847 data Hashtable = Hashtable
9848
9849 foreign import ccall unsafe \"guestfs_create\" c_create
9850   :: IO GuestfsP
9851 foreign import ccall unsafe \"&guestfs_close\" c_close
9852   :: FunPtr (GuestfsP -> IO ())
9853 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
9854   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
9855
9856 create :: IO GuestfsH
9857 create = do
9858   p <- c_create
9859   c_set_error_handler p nullPtr nullPtr
9860   h <- newForeignPtr c_close p
9861   return h
9862
9863 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
9864   :: GuestfsP -> IO CString
9865
9866 -- last_error :: GuestfsH -> IO (Maybe String)
9867 -- last_error h = do
9868 --   str <- withForeignPtr h (\\p -> c_last_error p)
9869 --   maybePeek peekCString str
9870
9871 last_error :: GuestfsH -> IO (String)
9872 last_error h = do
9873   str <- withForeignPtr h (\\p -> c_last_error p)
9874   if (str == nullPtr)
9875     then return \"no error\"
9876     else peekCString str
9877
9878 ";
9879
9880   (* Generate wrappers for each foreign function. *)
9881   List.iter (
9882     fun (name, style, _, _, _, _, _) ->
9883       if can_generate style then (
9884         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
9885         pr "  :: ";
9886         generate_haskell_prototype ~handle:"GuestfsP" style;
9887         pr "\n";
9888         pr "\n";
9889         pr "%s :: " name;
9890         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
9891         pr "\n";
9892         pr "%s %s = do\n" name
9893           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
9894         pr "  r <- ";
9895         (* Convert pointer arguments using with* functions. *)
9896         List.iter (
9897           function
9898           | FileIn n
9899           | FileOut n
9900           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
9901           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
9902           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
9903           | Bool _ | Int _ | Int64 _ -> ()
9904         ) (snd style);
9905         (* Convert integer arguments. *)
9906         let args =
9907           List.map (
9908             function
9909             | Bool n -> sprintf "(fromBool %s)" n
9910             | Int n -> sprintf "(fromIntegral %s)" n
9911             | Int64 n -> sprintf "(fromIntegral %s)" n
9912             | FileIn n | FileOut n
9913             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
9914           ) (snd style) in
9915         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
9916           (String.concat " " ("p" :: args));
9917         (match fst style with
9918          | RErr | RInt _ | RInt64 _ | RBool _ ->
9919              pr "  if (r == -1)\n";
9920              pr "    then do\n";
9921              pr "      err <- last_error h\n";
9922              pr "      fail err\n";
9923          | RConstString _ | RConstOptString _ | RString _
9924          | RStringList _ | RStruct _
9925          | RStructList _ | RHashtable _ | RBufferOut _ ->
9926              pr "  if (r == nullPtr)\n";
9927              pr "    then do\n";
9928              pr "      err <- last_error h\n";
9929              pr "      fail err\n";
9930         );
9931         (match fst style with
9932          | RErr ->
9933              pr "    else return ()\n"
9934          | RInt _ ->
9935              pr "    else return (fromIntegral r)\n"
9936          | RInt64 _ ->
9937              pr "    else return (fromIntegral r)\n"
9938          | RBool _ ->
9939              pr "    else return (toBool r)\n"
9940          | RConstString _
9941          | RConstOptString _
9942          | RString _
9943          | RStringList _
9944          | RStruct _
9945          | RStructList _
9946          | RHashtable _
9947          | RBufferOut _ ->
9948              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
9949         );
9950         pr "\n";
9951       )
9952   ) all_functions
9953
9954 and generate_haskell_prototype ~handle ?(hs = false) style =
9955   pr "%s -> " handle;
9956   let string = if hs then "String" else "CString" in
9957   let int = if hs then "Int" else "CInt" in
9958   let bool = if hs then "Bool" else "CInt" in
9959   let int64 = if hs then "Integer" else "Int64" in
9960   List.iter (
9961     fun arg ->
9962       (match arg with
9963        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
9964        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
9965        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
9966        | Bool _ -> pr "%s" bool
9967        | Int _ -> pr "%s" int
9968        | Int64 _ -> pr "%s" int
9969        | FileIn _ -> pr "%s" string
9970        | FileOut _ -> pr "%s" string
9971       );
9972       pr " -> ";
9973   ) (snd style);
9974   pr "IO (";
9975   (match fst style with
9976    | RErr -> if not hs then pr "CInt"
9977    | RInt _ -> pr "%s" int
9978    | RInt64 _ -> pr "%s" int64
9979    | RBool _ -> pr "%s" bool
9980    | RConstString _ -> pr "%s" string
9981    | RConstOptString _ -> pr "Maybe %s" string
9982    | RString _ -> pr "%s" string
9983    | RStringList _ -> pr "[%s]" string
9984    | RStruct (_, typ) ->
9985        let name = java_name_of_struct typ in
9986        pr "%s" name
9987    | RStructList (_, typ) ->
9988        let name = java_name_of_struct typ in
9989        pr "[%s]" name
9990    | RHashtable _ -> pr "Hashtable"
9991    | RBufferOut _ -> pr "%s" string
9992   );
9993   pr ")"
9994
9995 and generate_csharp () =
9996   generate_header CPlusPlusStyle LGPLv2plus;
9997
9998   (* XXX Make this configurable by the C# assembly users. *)
9999   let library = "libguestfs.so.0" in
10000
10001   pr "\
10002 // These C# bindings are highly experimental at present.
10003 //
10004 // Firstly they only work on Linux (ie. Mono).  In order to get them
10005 // to work on Windows (ie. .Net) you would need to port the library
10006 // itself to Windows first.
10007 //
10008 // The second issue is that some calls are known to be incorrect and
10009 // can cause Mono to segfault.  Particularly: calls which pass or
10010 // return string[], or return any structure value.  This is because
10011 // we haven't worked out the correct way to do this from C#.
10012 //
10013 // The third issue is that when compiling you get a lot of warnings.
10014 // We are not sure whether the warnings are important or not.
10015 //
10016 // Fourthly we do not routinely build or test these bindings as part
10017 // of the make && make check cycle, which means that regressions might
10018 // go unnoticed.
10019 //
10020 // Suggestions and patches are welcome.
10021
10022 // To compile:
10023 //
10024 // gmcs Libguestfs.cs
10025 // mono Libguestfs.exe
10026 //
10027 // (You'll probably want to add a Test class / static main function
10028 // otherwise this won't do anything useful).
10029
10030 using System;
10031 using System.IO;
10032 using System.Runtime.InteropServices;
10033 using System.Runtime.Serialization;
10034 using System.Collections;
10035
10036 namespace Guestfs
10037 {
10038   class Error : System.ApplicationException
10039   {
10040     public Error (string message) : base (message) {}
10041     protected Error (SerializationInfo info, StreamingContext context) {}
10042   }
10043
10044   class Guestfs
10045   {
10046     IntPtr _handle;
10047
10048     [DllImport (\"%s\")]
10049     static extern IntPtr guestfs_create ();
10050
10051     public Guestfs ()
10052     {
10053       _handle = guestfs_create ();
10054       if (_handle == IntPtr.Zero)
10055         throw new Error (\"could not create guestfs handle\");
10056     }
10057
10058     [DllImport (\"%s\")]
10059     static extern void guestfs_close (IntPtr h);
10060
10061     ~Guestfs ()
10062     {
10063       guestfs_close (_handle);
10064     }
10065
10066     [DllImport (\"%s\")]
10067     static extern string guestfs_last_error (IntPtr h);
10068
10069 " library library library;
10070
10071   (* Generate C# structure bindings.  We prefix struct names with
10072    * underscore because C# cannot have conflicting struct names and
10073    * method names (eg. "class stat" and "stat").
10074    *)
10075   List.iter (
10076     fun (typ, cols) ->
10077       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10078       pr "    public class _%s {\n" typ;
10079       List.iter (
10080         function
10081         | name, FChar -> pr "      char %s;\n" name
10082         | name, FString -> pr "      string %s;\n" name
10083         | name, FBuffer ->
10084             pr "      uint %s_len;\n" name;
10085             pr "      string %s;\n" name
10086         | name, FUUID ->
10087             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10088             pr "      string %s;\n" name
10089         | name, FUInt32 -> pr "      uint %s;\n" name
10090         | name, FInt32 -> pr "      int %s;\n" name
10091         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10092         | name, FInt64 -> pr "      long %s;\n" name
10093         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10094       ) cols;
10095       pr "    }\n";
10096       pr "\n"
10097   ) structs;
10098
10099   (* Generate C# function bindings. *)
10100   List.iter (
10101     fun (name, style, _, _, _, shortdesc, _) ->
10102       let rec csharp_return_type () =
10103         match fst style with
10104         | RErr -> "void"
10105         | RBool n -> "bool"
10106         | RInt n -> "int"
10107         | RInt64 n -> "long"
10108         | RConstString n
10109         | RConstOptString n
10110         | RString n
10111         | RBufferOut n -> "string"
10112         | RStruct (_,n) -> "_" ^ n
10113         | RHashtable n -> "Hashtable"
10114         | RStringList n -> "string[]"
10115         | RStructList (_,n) -> sprintf "_%s[]" n
10116
10117       and c_return_type () =
10118         match fst style with
10119         | RErr
10120         | RBool _
10121         | RInt _ -> "int"
10122         | RInt64 _ -> "long"
10123         | RConstString _
10124         | RConstOptString _
10125         | RString _
10126         | RBufferOut _ -> "string"
10127         | RStruct (_,n) -> "_" ^ n
10128         | RHashtable _
10129         | RStringList _ -> "string[]"
10130         | RStructList (_,n) -> sprintf "_%s[]" n
10131     
10132       and c_error_comparison () =
10133         match fst style with
10134         | RErr
10135         | RBool _
10136         | RInt _
10137         | RInt64 _ -> "== -1"
10138         | RConstString _
10139         | RConstOptString _
10140         | RString _
10141         | RBufferOut _
10142         | RStruct (_,_)
10143         | RHashtable _
10144         | RStringList _
10145         | RStructList (_,_) -> "== null"
10146     
10147       and generate_extern_prototype () =
10148         pr "    static extern %s guestfs_%s (IntPtr h"
10149           (c_return_type ()) name;
10150         List.iter (
10151           function
10152           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10153           | FileIn n | FileOut n ->
10154               pr ", [In] string %s" n
10155           | StringList n | DeviceList n ->
10156               pr ", [In] string[] %s" n
10157           | Bool n ->
10158               pr ", bool %s" n
10159           | Int n ->
10160               pr ", int %s" n
10161           | Int64 n ->
10162               pr ", long %s" n
10163         ) (snd style);
10164         pr ");\n"
10165
10166       and generate_public_prototype () =
10167         pr "    public %s %s (" (csharp_return_type ()) name;
10168         let comma = ref false in
10169         let next () =
10170           if !comma then pr ", ";
10171           comma := true
10172         in
10173         List.iter (
10174           function
10175           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10176           | FileIn n | FileOut n ->
10177               next (); pr "string %s" n
10178           | StringList n | DeviceList n ->
10179               next (); pr "string[] %s" n
10180           | Bool n ->
10181               next (); pr "bool %s" n
10182           | Int n ->
10183               next (); pr "int %s" n
10184           | Int64 n ->
10185               next (); pr "long %s" n
10186         ) (snd style);
10187         pr ")\n"
10188
10189       and generate_call () =
10190         pr "guestfs_%s (_handle" name;
10191         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10192         pr ");\n";
10193       in
10194
10195       pr "    [DllImport (\"%s\")]\n" library;
10196       generate_extern_prototype ();
10197       pr "\n";
10198       pr "    /// <summary>\n";
10199       pr "    /// %s\n" shortdesc;
10200       pr "    /// </summary>\n";
10201       generate_public_prototype ();
10202       pr "    {\n";
10203       pr "      %s r;\n" (c_return_type ());
10204       pr "      r = ";
10205       generate_call ();
10206       pr "      if (r %s)\n" (c_error_comparison ());
10207       pr "        throw new Error (\"%s: \" + guestfs_last_error (_handle));\n"
10208         name;
10209       (match fst style with
10210        | RErr -> ()
10211        | RBool _ ->
10212            pr "      return r != 0 ? true : false;\n"
10213        | RHashtable _ ->
10214            pr "      Hashtable rr = new Hashtable ();\n";
10215            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10216            pr "        rr.Add (r[i], r[i+1]);\n";
10217            pr "      return rr;\n"
10218        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10219        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10220        | RStructList _ ->
10221            pr "      return r;\n"
10222       );
10223       pr "    }\n";
10224       pr "\n";
10225   ) all_functions_sorted;
10226
10227   pr "  }
10228 }
10229 "
10230
10231 and generate_bindtests () =
10232   generate_header CStyle LGPLv2plus;
10233
10234   pr "\
10235 #include <stdio.h>
10236 #include <stdlib.h>
10237 #include <inttypes.h>
10238 #include <string.h>
10239
10240 #include \"guestfs.h\"
10241 #include \"guestfs-internal.h\"
10242 #include \"guestfs-internal-actions.h\"
10243 #include \"guestfs_protocol.h\"
10244
10245 #define error guestfs_error
10246 #define safe_calloc guestfs_safe_calloc
10247 #define safe_malloc guestfs_safe_malloc
10248
10249 static void
10250 print_strings (char *const *argv)
10251 {
10252   int argc;
10253
10254   printf (\"[\");
10255   for (argc = 0; argv[argc] != NULL; ++argc) {
10256     if (argc > 0) printf (\", \");
10257     printf (\"\\\"%%s\\\"\", argv[argc]);
10258   }
10259   printf (\"]\\n\");
10260 }
10261
10262 /* The test0 function prints its parameters to stdout. */
10263 ";
10264
10265   let test0, tests =
10266     match test_functions with
10267     | [] -> assert false
10268     | test0 :: tests -> test0, tests in
10269
10270   let () =
10271     let (name, style, _, _, _, _, _) = test0 in
10272     generate_prototype ~extern:false ~semicolon:false ~newline:true
10273       ~handle:"g" ~prefix:"guestfs__" name style;
10274     pr "{\n";
10275     List.iter (
10276       function
10277       | Pathname n
10278       | Device n | Dev_or_Path n
10279       | String n
10280       | FileIn n
10281       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10282       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10283       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10284       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10285       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10286       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10287     ) (snd style);
10288     pr "  /* Java changes stdout line buffering so we need this: */\n";
10289     pr "  fflush (stdout);\n";
10290     pr "  return 0;\n";
10291     pr "}\n";
10292     pr "\n" in
10293
10294   List.iter (
10295     fun (name, style, _, _, _, _, _) ->
10296       if String.sub name (String.length name - 3) 3 <> "err" then (
10297         pr "/* Test normal return. */\n";
10298         generate_prototype ~extern:false ~semicolon:false ~newline:true
10299           ~handle:"g" ~prefix:"guestfs__" name style;
10300         pr "{\n";
10301         (match fst style with
10302          | RErr ->
10303              pr "  return 0;\n"
10304          | RInt _ ->
10305              pr "  int r;\n";
10306              pr "  sscanf (val, \"%%d\", &r);\n";
10307              pr "  return r;\n"
10308          | RInt64 _ ->
10309              pr "  int64_t r;\n";
10310              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10311              pr "  return r;\n"
10312          | RBool _ ->
10313              pr "  return STREQ (val, \"true\");\n"
10314          | RConstString _
10315          | RConstOptString _ ->
10316              (* Can't return the input string here.  Return a static
10317               * string so we ensure we get a segfault if the caller
10318               * tries to free it.
10319               *)
10320              pr "  return \"static string\";\n"
10321          | RString _ ->
10322              pr "  return strdup (val);\n"
10323          | RStringList _ ->
10324              pr "  char **strs;\n";
10325              pr "  int n, i;\n";
10326              pr "  sscanf (val, \"%%d\", &n);\n";
10327              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10328              pr "  for (i = 0; i < n; ++i) {\n";
10329              pr "    strs[i] = safe_malloc (g, 16);\n";
10330              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10331              pr "  }\n";
10332              pr "  strs[n] = NULL;\n";
10333              pr "  return strs;\n"
10334          | RStruct (_, typ) ->
10335              pr "  struct guestfs_%s *r;\n" typ;
10336              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10337              pr "  return r;\n"
10338          | RStructList (_, typ) ->
10339              pr "  struct guestfs_%s_list *r;\n" typ;
10340              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10341              pr "  sscanf (val, \"%%d\", &r->len);\n";
10342              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10343              pr "  return r;\n"
10344          | RHashtable _ ->
10345              pr "  char **strs;\n";
10346              pr "  int n, i;\n";
10347              pr "  sscanf (val, \"%%d\", &n);\n";
10348              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10349              pr "  for (i = 0; i < n; ++i) {\n";
10350              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10351              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10352              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10353              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10354              pr "  }\n";
10355              pr "  strs[n*2] = NULL;\n";
10356              pr "  return strs;\n"
10357          | RBufferOut _ ->
10358              pr "  return strdup (val);\n"
10359         );
10360         pr "}\n";
10361         pr "\n"
10362       ) else (
10363         pr "/* Test error return. */\n";
10364         generate_prototype ~extern:false ~semicolon:false ~newline:true
10365           ~handle:"g" ~prefix:"guestfs__" name style;
10366         pr "{\n";
10367         pr "  error (g, \"error\");\n";
10368         (match fst style with
10369          | RErr | RInt _ | RInt64 _ | RBool _ ->
10370              pr "  return -1;\n"
10371          | RConstString _ | RConstOptString _
10372          | RString _ | RStringList _ | RStruct _
10373          | RStructList _
10374          | RHashtable _
10375          | RBufferOut _ ->
10376              pr "  return NULL;\n"
10377         );
10378         pr "}\n";
10379         pr "\n"
10380       )
10381   ) tests
10382
10383 and generate_ocaml_bindtests () =
10384   generate_header OCamlStyle GPLv2plus;
10385
10386   pr "\
10387 let () =
10388   let g = Guestfs.create () in
10389 ";
10390
10391   let mkargs args =
10392     String.concat " " (
10393       List.map (
10394         function
10395         | CallString s -> "\"" ^ s ^ "\""
10396         | CallOptString None -> "None"
10397         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10398         | CallStringList xs ->
10399             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10400         | CallInt i when i >= 0 -> string_of_int i
10401         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10402         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10403         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10404         | CallBool b -> string_of_bool b
10405       ) args
10406     )
10407   in
10408
10409   generate_lang_bindtests (
10410     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10411   );
10412
10413   pr "print_endline \"EOF\"\n"
10414
10415 and generate_perl_bindtests () =
10416   pr "#!/usr/bin/perl -w\n";
10417   generate_header HashStyle GPLv2plus;
10418
10419   pr "\
10420 use strict;
10421
10422 use Sys::Guestfs;
10423
10424 my $g = Sys::Guestfs->new ();
10425 ";
10426
10427   let mkargs args =
10428     String.concat ", " (
10429       List.map (
10430         function
10431         | CallString s -> "\"" ^ s ^ "\""
10432         | CallOptString None -> "undef"
10433         | CallOptString (Some s) -> sprintf "\"%s\"" s
10434         | CallStringList xs ->
10435             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10436         | CallInt i -> string_of_int i
10437         | CallInt64 i -> Int64.to_string i
10438         | CallBool b -> if b then "1" else "0"
10439       ) args
10440     )
10441   in
10442
10443   generate_lang_bindtests (
10444     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10445   );
10446
10447   pr "print \"EOF\\n\"\n"
10448
10449 and generate_python_bindtests () =
10450   generate_header HashStyle GPLv2plus;
10451
10452   pr "\
10453 import guestfs
10454
10455 g = guestfs.GuestFS ()
10456 ";
10457
10458   let mkargs args =
10459     String.concat ", " (
10460       List.map (
10461         function
10462         | CallString s -> "\"" ^ s ^ "\""
10463         | CallOptString None -> "None"
10464         | CallOptString (Some s) -> sprintf "\"%s\"" s
10465         | CallStringList xs ->
10466             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10467         | CallInt i -> string_of_int i
10468         | CallInt64 i -> Int64.to_string i
10469         | CallBool b -> if b then "1" else "0"
10470       ) args
10471     )
10472   in
10473
10474   generate_lang_bindtests (
10475     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10476   );
10477
10478   pr "print \"EOF\"\n"
10479
10480 and generate_ruby_bindtests () =
10481   generate_header HashStyle GPLv2plus;
10482
10483   pr "\
10484 require 'guestfs'
10485
10486 g = Guestfs::create()
10487 ";
10488
10489   let mkargs args =
10490     String.concat ", " (
10491       List.map (
10492         function
10493         | CallString s -> "\"" ^ s ^ "\""
10494         | CallOptString None -> "nil"
10495         | CallOptString (Some s) -> sprintf "\"%s\"" s
10496         | CallStringList xs ->
10497             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10498         | CallInt i -> string_of_int i
10499         | CallInt64 i -> Int64.to_string i
10500         | CallBool b -> string_of_bool b
10501       ) args
10502     )
10503   in
10504
10505   generate_lang_bindtests (
10506     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10507   );
10508
10509   pr "print \"EOF\\n\"\n"
10510
10511 and generate_java_bindtests () =
10512   generate_header CStyle GPLv2plus;
10513
10514   pr "\
10515 import com.redhat.et.libguestfs.*;
10516
10517 public class Bindtests {
10518     public static void main (String[] argv)
10519     {
10520         try {
10521             GuestFS g = new GuestFS ();
10522 ";
10523
10524   let mkargs args =
10525     String.concat ", " (
10526       List.map (
10527         function
10528         | CallString s -> "\"" ^ s ^ "\""
10529         | CallOptString None -> "null"
10530         | CallOptString (Some s) -> sprintf "\"%s\"" s
10531         | CallStringList xs ->
10532             "new String[]{" ^
10533               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
10534         | CallInt i -> string_of_int i
10535         | CallInt64 i -> Int64.to_string i
10536         | CallBool b -> string_of_bool b
10537       ) args
10538     )
10539   in
10540
10541   generate_lang_bindtests (
10542     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
10543   );
10544
10545   pr "
10546             System.out.println (\"EOF\");
10547         }
10548         catch (Exception exn) {
10549             System.err.println (exn);
10550             System.exit (1);
10551         }
10552     }
10553 }
10554 "
10555
10556 and generate_haskell_bindtests () =
10557   generate_header HaskellStyle GPLv2plus;
10558
10559   pr "\
10560 module Bindtests where
10561 import qualified Guestfs
10562
10563 main = do
10564   g <- Guestfs.create
10565 ";
10566
10567   let mkargs args =
10568     String.concat " " (
10569       List.map (
10570         function
10571         | CallString s -> "\"" ^ s ^ "\""
10572         | CallOptString None -> "Nothing"
10573         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
10574         | CallStringList xs ->
10575             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10576         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
10577         | CallInt i -> string_of_int i
10578         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
10579         | CallInt64 i -> Int64.to_string i
10580         | CallBool true -> "True"
10581         | CallBool false -> "False"
10582       ) args
10583     )
10584   in
10585
10586   generate_lang_bindtests (
10587     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
10588   );
10589
10590   pr "  putStrLn \"EOF\"\n"
10591
10592 (* Language-independent bindings tests - we do it this way to
10593  * ensure there is parity in testing bindings across all languages.
10594  *)
10595 and generate_lang_bindtests call =
10596   call "test0" [CallString "abc"; CallOptString (Some "def");
10597                 CallStringList []; CallBool false;
10598                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10599   call "test0" [CallString "abc"; CallOptString None;
10600                 CallStringList []; CallBool false;
10601                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10602   call "test0" [CallString ""; CallOptString (Some "def");
10603                 CallStringList []; CallBool false;
10604                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10605   call "test0" [CallString ""; CallOptString (Some "");
10606                 CallStringList []; CallBool false;
10607                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10608   call "test0" [CallString "abc"; CallOptString (Some "def");
10609                 CallStringList ["1"]; CallBool false;
10610                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10611   call "test0" [CallString "abc"; CallOptString (Some "def");
10612                 CallStringList ["1"; "2"]; CallBool false;
10613                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10614   call "test0" [CallString "abc"; CallOptString (Some "def");
10615                 CallStringList ["1"]; CallBool true;
10616                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10617   call "test0" [CallString "abc"; CallOptString (Some "def");
10618                 CallStringList ["1"]; CallBool false;
10619                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
10620   call "test0" [CallString "abc"; CallOptString (Some "def");
10621                 CallStringList ["1"]; CallBool false;
10622                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
10623   call "test0" [CallString "abc"; CallOptString (Some "def");
10624                 CallStringList ["1"]; CallBool false;
10625                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
10626   call "test0" [CallString "abc"; CallOptString (Some "def");
10627                 CallStringList ["1"]; CallBool false;
10628                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
10629   call "test0" [CallString "abc"; CallOptString (Some "def");
10630                 CallStringList ["1"]; CallBool false;
10631                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
10632   call "test0" [CallString "abc"; CallOptString (Some "def");
10633                 CallStringList ["1"]; CallBool false;
10634                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
10635
10636 (* XXX Add here tests of the return and error functions. *)
10637
10638 (* Code to generator bindings for virt-inspector.  Currently only
10639  * implemented for OCaml code (for virt-p2v 2.0).
10640  *)
10641 let rng_input = "inspector/virt-inspector.rng"
10642
10643 (* Read the input file and parse it into internal structures.  This is
10644  * by no means a complete RELAX NG parser, but is just enough to be
10645  * able to parse the specific input file.
10646  *)
10647 type rng =
10648   | Element of string * rng list        (* <element name=name/> *)
10649   | Attribute of string * rng list        (* <attribute name=name/> *)
10650   | Interleave of rng list                (* <interleave/> *)
10651   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
10652   | OneOrMore of rng                        (* <oneOrMore/> *)
10653   | Optional of rng                        (* <optional/> *)
10654   | Choice of string list                (* <choice><value/>*</choice> *)
10655   | Value of string                        (* <value>str</value> *)
10656   | Text                                (* <text/> *)
10657
10658 let rec string_of_rng = function
10659   | Element (name, xs) ->
10660       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10661   | Attribute (name, xs) ->
10662       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10663   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
10664   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
10665   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
10666   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
10667   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
10668   | Value value -> "Value \"" ^ value ^ "\""
10669   | Text -> "Text"
10670
10671 and string_of_rng_list xs =
10672   String.concat ", " (List.map string_of_rng xs)
10673
10674 let rec parse_rng ?defines context = function
10675   | [] -> []
10676   | Xml.Element ("element", ["name", name], children) :: rest ->
10677       Element (name, parse_rng ?defines context children)
10678       :: parse_rng ?defines context rest
10679   | Xml.Element ("attribute", ["name", name], children) :: rest ->
10680       Attribute (name, parse_rng ?defines context children)
10681       :: parse_rng ?defines context rest
10682   | Xml.Element ("interleave", [], children) :: rest ->
10683       Interleave (parse_rng ?defines context children)
10684       :: parse_rng ?defines context rest
10685   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
10686       let rng = parse_rng ?defines context [child] in
10687       (match rng with
10688        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
10689        | _ ->
10690            failwithf "%s: <zeroOrMore> contains more than one child element"
10691              context
10692       )
10693   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
10694       let rng = parse_rng ?defines context [child] in
10695       (match rng with
10696        | [child] -> OneOrMore child :: parse_rng ?defines context rest
10697        | _ ->
10698            failwithf "%s: <oneOrMore> contains more than one child element"
10699              context
10700       )
10701   | Xml.Element ("optional", [], [child]) :: rest ->
10702       let rng = parse_rng ?defines context [child] in
10703       (match rng with
10704        | [child] -> Optional child :: parse_rng ?defines context rest
10705        | _ ->
10706            failwithf "%s: <optional> contains more than one child element"
10707              context
10708       )
10709   | Xml.Element ("choice", [], children) :: rest ->
10710       let values = List.map (
10711         function Xml.Element ("value", [], [Xml.PCData value]) -> value
10712         | _ ->
10713             failwithf "%s: can't handle anything except <value> in <choice>"
10714               context
10715       ) children in
10716       Choice values
10717       :: parse_rng ?defines context rest
10718   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
10719       Value value :: parse_rng ?defines context rest
10720   | Xml.Element ("text", [], []) :: rest ->
10721       Text :: parse_rng ?defines context rest
10722   | Xml.Element ("ref", ["name", name], []) :: rest ->
10723       (* Look up the reference.  Because of limitations in this parser,
10724        * we can't handle arbitrarily nested <ref> yet.  You can only
10725        * use <ref> from inside <start>.
10726        *)
10727       (match defines with
10728        | None ->
10729            failwithf "%s: contains <ref>, but no refs are defined yet" context
10730        | Some map ->
10731            let rng = StringMap.find name map in
10732            rng @ parse_rng ?defines context rest
10733       )
10734   | x :: _ ->
10735       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
10736
10737 let grammar =
10738   let xml = Xml.parse_file rng_input in
10739   match xml with
10740   | Xml.Element ("grammar", _,
10741                  Xml.Element ("start", _, gram) :: defines) ->
10742       (* The <define/> elements are referenced in the <start> section,
10743        * so build a map of those first.
10744        *)
10745       let defines = List.fold_left (
10746         fun map ->
10747           function Xml.Element ("define", ["name", name], defn) ->
10748             StringMap.add name defn map
10749           | _ ->
10750               failwithf "%s: expected <define name=name/>" rng_input
10751       ) StringMap.empty defines in
10752       let defines = StringMap.mapi parse_rng defines in
10753
10754       (* Parse the <start> clause, passing the defines. *)
10755       parse_rng ~defines "<start>" gram
10756   | _ ->
10757       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
10758         rng_input
10759
10760 let name_of_field = function
10761   | Element (name, _) | Attribute (name, _)
10762   | ZeroOrMore (Element (name, _))
10763   | OneOrMore (Element (name, _))
10764   | Optional (Element (name, _)) -> name
10765   | Optional (Attribute (name, _)) -> name
10766   | Text -> (* an unnamed field in an element *)
10767       "data"
10768   | rng ->
10769       failwithf "name_of_field failed at: %s" (string_of_rng rng)
10770
10771 (* At the moment this function only generates OCaml types.  However we
10772  * should parameterize it later so it can generate types/structs in a
10773  * variety of languages.
10774  *)
10775 let generate_types xs =
10776   (* A simple type is one that can be printed out directly, eg.
10777    * "string option".  A complex type is one which has a name and has
10778    * to be defined via another toplevel definition, eg. a struct.
10779    *
10780    * generate_type generates code for either simple or complex types.
10781    * In the simple case, it returns the string ("string option").  In
10782    * the complex case, it returns the name ("mountpoint").  In the
10783    * complex case it has to print out the definition before returning,
10784    * so it should only be called when we are at the beginning of a
10785    * new line (BOL context).
10786    *)
10787   let rec generate_type = function
10788     | Text ->                                (* string *)
10789         "string", true
10790     | Choice values ->                        (* [`val1|`val2|...] *)
10791         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
10792     | ZeroOrMore rng ->                        (* <rng> list *)
10793         let t, is_simple = generate_type rng in
10794         t ^ " list (* 0 or more *)", is_simple
10795     | OneOrMore rng ->                        (* <rng> list *)
10796         let t, is_simple = generate_type rng in
10797         t ^ " list (* 1 or more *)", is_simple
10798                                         (* virt-inspector hack: bool *)
10799     | Optional (Attribute (name, [Value "1"])) ->
10800         "bool", true
10801     | Optional rng ->                        (* <rng> list *)
10802         let t, is_simple = generate_type rng in
10803         t ^ " option", is_simple
10804                                         (* type name = { fields ... } *)
10805     | Element (name, fields) when is_attrs_interleave fields ->
10806         generate_type_struct name (get_attrs_interleave fields)
10807     | Element (name, [field])                (* type name = field *)
10808     | Attribute (name, [field]) ->
10809         let t, is_simple = generate_type field in
10810         if is_simple then (t, true)
10811         else (
10812           pr "type %s = %s\n" name t;
10813           name, false
10814         )
10815     | Element (name, fields) ->              (* type name = { fields ... } *)
10816         generate_type_struct name fields
10817     | rng ->
10818         failwithf "generate_type failed at: %s" (string_of_rng rng)
10819
10820   and is_attrs_interleave = function
10821     | [Interleave _] -> true
10822     | Attribute _ :: fields -> is_attrs_interleave fields
10823     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
10824     | _ -> false
10825
10826   and get_attrs_interleave = function
10827     | [Interleave fields] -> fields
10828     | ((Attribute _) as field) :: fields
10829     | ((Optional (Attribute _)) as field) :: fields ->
10830         field :: get_attrs_interleave fields
10831     | _ -> assert false
10832
10833   and generate_types xs =
10834     List.iter (fun x -> ignore (generate_type x)) xs
10835
10836   and generate_type_struct name fields =
10837     (* Calculate the types of the fields first.  We have to do this
10838      * before printing anything so we are still in BOL context.
10839      *)
10840     let types = List.map fst (List.map generate_type fields) in
10841
10842     (* Special case of a struct containing just a string and another
10843      * field.  Turn it into an assoc list.
10844      *)
10845     match types with
10846     | ["string"; other] ->
10847         let fname1, fname2 =
10848           match fields with
10849           | [f1; f2] -> name_of_field f1, name_of_field f2
10850           | _ -> assert false in
10851         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
10852         name, false
10853
10854     | types ->
10855         pr "type %s = {\n" name;
10856         List.iter (
10857           fun (field, ftype) ->
10858             let fname = name_of_field field in
10859             pr "  %s_%s : %s;\n" name fname ftype
10860         ) (List.combine fields types);
10861         pr "}\n";
10862         (* Return the name of this type, and
10863          * false because it's not a simple type.
10864          *)
10865         name, false
10866   in
10867
10868   generate_types xs
10869
10870 let generate_parsers xs =
10871   (* As for generate_type above, generate_parser makes a parser for
10872    * some type, and returns the name of the parser it has generated.
10873    * Because it (may) need to print something, it should always be
10874    * called in BOL context.
10875    *)
10876   let rec generate_parser = function
10877     | Text ->                                (* string *)
10878         "string_child_or_empty"
10879     | Choice values ->                        (* [`val1|`val2|...] *)
10880         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
10881           (String.concat "|"
10882              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
10883     | ZeroOrMore rng ->                        (* <rng> list *)
10884         let pa = generate_parser rng in
10885         sprintf "(fun x -> List.map %s (Xml.children x))" pa
10886     | OneOrMore rng ->                        (* <rng> list *)
10887         let pa = generate_parser rng in
10888         sprintf "(fun x -> List.map %s (Xml.children x))" pa
10889                                         (* virt-inspector hack: bool *)
10890     | Optional (Attribute (name, [Value "1"])) ->
10891         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
10892     | Optional rng ->                        (* <rng> list *)
10893         let pa = generate_parser rng in
10894         sprintf "(function None -> None | Some x -> Some (%s x))" pa
10895                                         (* type name = { fields ... } *)
10896     | Element (name, fields) when is_attrs_interleave fields ->
10897         generate_parser_struct name (get_attrs_interleave fields)
10898     | Element (name, [field]) ->        (* type name = field *)
10899         let pa = generate_parser field in
10900         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
10901         pr "let %s =\n" parser_name;
10902         pr "  %s\n" pa;
10903         pr "let parse_%s = %s\n" name parser_name;
10904         parser_name
10905     | Attribute (name, [field]) ->
10906         let pa = generate_parser field in
10907         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
10908         pr "let %s =\n" parser_name;
10909         pr "  %s\n" pa;
10910         pr "let parse_%s = %s\n" name parser_name;
10911         parser_name
10912     | Element (name, fields) ->              (* type name = { fields ... } *)
10913         generate_parser_struct name ([], fields)
10914     | rng ->
10915         failwithf "generate_parser failed at: %s" (string_of_rng rng)
10916
10917   and is_attrs_interleave = function
10918     | [Interleave _] -> true
10919     | Attribute _ :: fields -> is_attrs_interleave fields
10920     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
10921     | _ -> false
10922
10923   and get_attrs_interleave = function
10924     | [Interleave fields] -> [], fields
10925     | ((Attribute _) as field) :: fields
10926     | ((Optional (Attribute _)) as field) :: fields ->
10927         let attrs, interleaves = get_attrs_interleave fields in
10928         (field :: attrs), interleaves
10929     | _ -> assert false
10930
10931   and generate_parsers xs =
10932     List.iter (fun x -> ignore (generate_parser x)) xs
10933
10934   and generate_parser_struct name (attrs, interleaves) =
10935     (* Generate parsers for the fields first.  We have to do this
10936      * before printing anything so we are still in BOL context.
10937      *)
10938     let fields = attrs @ interleaves in
10939     let pas = List.map generate_parser fields in
10940
10941     (* Generate an intermediate tuple from all the fields first.
10942      * If the type is just a string + another field, then we will
10943      * return this directly, otherwise it is turned into a record.
10944      *
10945      * RELAX NG note: This code treats <interleave> and plain lists of
10946      * fields the same.  In other words, it doesn't bother enforcing
10947      * any ordering of fields in the XML.
10948      *)
10949     pr "let parse_%s x =\n" name;
10950     pr "  let t = (\n    ";
10951     let comma = ref false in
10952     List.iter (
10953       fun x ->
10954         if !comma then pr ",\n    ";
10955         comma := true;
10956         match x with
10957         | Optional (Attribute (fname, [field])), pa ->
10958             pr "%s x" pa
10959         | Optional (Element (fname, [field])), pa ->
10960             pr "%s (optional_child %S x)" pa fname
10961         | Attribute (fname, [Text]), _ ->
10962             pr "attribute %S x" fname
10963         | (ZeroOrMore _ | OneOrMore _), pa ->
10964             pr "%s x" pa
10965         | Text, pa ->
10966             pr "%s x" pa
10967         | (field, pa) ->
10968             let fname = name_of_field field in
10969             pr "%s (child %S x)" pa fname
10970     ) (List.combine fields pas);
10971     pr "\n  ) in\n";
10972
10973     (match fields with
10974      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
10975          pr "  t\n"
10976
10977      | _ ->
10978          pr "  (Obj.magic t : %s)\n" name
10979 (*
10980          List.iter (
10981            function
10982            | (Optional (Attribute (fname, [field])), pa) ->
10983                pr "  %s_%s =\n" name fname;
10984                pr "    %s x;\n" pa
10985            | (Optional (Element (fname, [field])), pa) ->
10986                pr "  %s_%s =\n" name fname;
10987                pr "    (let x = optional_child %S x in\n" fname;
10988                pr "     %s x);\n" pa
10989            | (field, pa) ->
10990                let fname = name_of_field field in
10991                pr "  %s_%s =\n" name fname;
10992                pr "    (let x = child %S x in\n" fname;
10993                pr "     %s x);\n" pa
10994          ) (List.combine fields pas);
10995          pr "}\n"
10996 *)
10997     );
10998     sprintf "parse_%s" name
10999   in
11000
11001   generate_parsers xs
11002
11003 (* Generate ocaml/guestfs_inspector.mli. *)
11004 let generate_ocaml_inspector_mli () =
11005   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11006
11007   pr "\
11008 (** This is an OCaml language binding to the external [virt-inspector]
11009     program.
11010
11011     For more information, please read the man page [virt-inspector(1)].
11012 *)
11013
11014 ";
11015
11016   generate_types grammar;
11017   pr "(** The nested information returned from the {!inspect} function. *)\n";
11018   pr "\n";
11019
11020   pr "\
11021 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11022 (** To inspect a libvirt domain called [name], pass a singleton
11023     list: [inspect [name]].  When using libvirt only, you may
11024     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11025
11026     To inspect a disk image or images, pass a list of the filenames
11027     of the disk images: [inspect filenames]
11028
11029     This function inspects the given guest or disk images and
11030     returns a list of operating system(s) found and a large amount
11031     of information about them.  In the vast majority of cases,
11032     a virtual machine only contains a single operating system.
11033
11034     If the optional [~xml] parameter is given, then this function
11035     skips running the external virt-inspector program and just
11036     parses the given XML directly (which is expected to be XML
11037     produced from a previous run of virt-inspector).  The list of
11038     names and connect URI are ignored in this case.
11039
11040     This function can throw a wide variety of exceptions, for example
11041     if the external virt-inspector program cannot be found, or if
11042     it doesn't generate valid XML.
11043 *)
11044 "
11045
11046 (* Generate ocaml/guestfs_inspector.ml. *)
11047 let generate_ocaml_inspector_ml () =
11048   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11049
11050   pr "open Unix\n";
11051   pr "\n";
11052
11053   generate_types grammar;
11054   pr "\n";
11055
11056   pr "\
11057 (* Misc functions which are used by the parser code below. *)
11058 let first_child = function
11059   | Xml.Element (_, _, c::_) -> c
11060   | Xml.Element (name, _, []) ->
11061       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11062   | Xml.PCData str ->
11063       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11064
11065 let string_child_or_empty = function
11066   | Xml.Element (_, _, [Xml.PCData s]) -> s
11067   | Xml.Element (_, _, []) -> \"\"
11068   | Xml.Element (x, _, _) ->
11069       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11070                 x ^ \" instead\")
11071   | Xml.PCData str ->
11072       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11073
11074 let optional_child name xml =
11075   let children = Xml.children xml in
11076   try
11077     Some (List.find (function
11078                      | Xml.Element (n, _, _) when n = name -> true
11079                      | _ -> false) children)
11080   with
11081     Not_found -> None
11082
11083 let child name xml =
11084   match optional_child name xml with
11085   | Some c -> c
11086   | None ->
11087       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11088
11089 let attribute name xml =
11090   try Xml.attrib xml name
11091   with Xml.No_attribute _ ->
11092     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11093
11094 ";
11095
11096   generate_parsers grammar;
11097   pr "\n";
11098
11099   pr "\
11100 (* Run external virt-inspector, then use parser to parse the XML. *)
11101 let inspect ?connect ?xml names =
11102   let xml =
11103     match xml with
11104     | None ->
11105         if names = [] then invalid_arg \"inspect: no names given\";
11106         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11107           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11108           names in
11109         let cmd = List.map Filename.quote cmd in
11110         let cmd = String.concat \" \" cmd in
11111         let chan = open_process_in cmd in
11112         let xml = Xml.parse_in chan in
11113         (match close_process_in chan with
11114          | WEXITED 0 -> ()
11115          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11116          | WSIGNALED i | WSTOPPED i ->
11117              failwith (\"external virt-inspector command died or stopped on sig \" ^
11118                        string_of_int i)
11119         );
11120         xml
11121     | Some doc ->
11122         Xml.parse_string doc in
11123   parse_operatingsystems xml
11124 "
11125
11126 (* This is used to generate the src/MAX_PROC_NR file which
11127  * contains the maximum procedure number, a surrogate for the
11128  * ABI version number.  See src/Makefile.am for the details.
11129  *)
11130 and generate_max_proc_nr () =
11131   let proc_nrs = List.map (
11132     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11133   ) daemon_functions in
11134
11135   let max_proc_nr = List.fold_left max 0 proc_nrs in
11136
11137   pr "%d\n" max_proc_nr
11138
11139 let output_to filename k =
11140   let filename_new = filename ^ ".new" in
11141   chan := open_out filename_new;
11142   k ();
11143   close_out !chan;
11144   chan := Pervasives.stdout;
11145
11146   (* Is the new file different from the current file? *)
11147   if Sys.file_exists filename && files_equal filename filename_new then
11148     unlink filename_new                 (* same, so skip it *)
11149   else (
11150     (* different, overwrite old one *)
11151     (try chmod filename 0o644 with Unix_error _ -> ());
11152     rename filename_new filename;
11153     chmod filename 0o444;
11154     printf "written %s\n%!" filename;
11155   )
11156
11157 let perror msg = function
11158   | Unix_error (err, _, _) ->
11159       eprintf "%s: %s\n" msg (error_message err)
11160   | exn ->
11161       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11162
11163 (* Main program. *)
11164 let () =
11165   let lock_fd =
11166     try openfile "HACKING" [O_RDWR] 0
11167     with
11168     | Unix_error (ENOENT, _, _) ->
11169         eprintf "\
11170 You are probably running this from the wrong directory.
11171 Run it from the top source directory using the command
11172   src/generator.ml
11173 ";
11174         exit 1
11175     | exn ->
11176         perror "open: HACKING" exn;
11177         exit 1 in
11178
11179   (* Acquire a lock so parallel builds won't try to run the generator
11180    * twice at the same time.  Subsequent builds will wait for the first
11181    * one to finish.  Note the lock is released implicitly when the
11182    * program exits.
11183    *)
11184   (try lockf lock_fd F_LOCK 1
11185    with exn ->
11186      perror "lock: HACKING" exn;
11187      exit 1);
11188
11189   check_functions ();
11190
11191   output_to "src/guestfs_protocol.x" generate_xdr;
11192   output_to "src/guestfs-structs.h" generate_structs_h;
11193   output_to "src/guestfs-actions.h" generate_actions_h;
11194   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11195   output_to "src/guestfs-actions.c" generate_client_actions;
11196   output_to "src/guestfs-bindtests.c" generate_bindtests;
11197   output_to "src/guestfs-structs.pod" generate_structs_pod;
11198   output_to "src/guestfs-actions.pod" generate_actions_pod;
11199   output_to "src/guestfs-availability.pod" generate_availability_pod;
11200   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11201   output_to "src/libguestfs.syms" generate_linker_script;
11202   output_to "daemon/actions.h" generate_daemon_actions_h;
11203   output_to "daemon/stubs.c" generate_daemon_actions;
11204   output_to "daemon/names.c" generate_daemon_names;
11205   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11206   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11207   output_to "capitests/tests.c" generate_tests;
11208   output_to "fish/cmds.c" generate_fish_cmds;
11209   output_to "fish/completion.c" generate_fish_completion;
11210   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11211   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11212   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11213   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11214   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11215   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11216   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11217   output_to "perl/Guestfs.xs" generate_perl_xs;
11218   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11219   output_to "perl/bindtests.pl" generate_perl_bindtests;
11220   output_to "python/guestfs-py.c" generate_python_c;
11221   output_to "python/guestfs.py" generate_python_py;
11222   output_to "python/bindtests.py" generate_python_bindtests;
11223   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11224   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11225   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11226
11227   List.iter (
11228     fun (typ, jtyp) ->
11229       let cols = cols_of_struct typ in
11230       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11231       output_to filename (generate_java_struct jtyp cols);
11232   ) java_structs;
11233
11234   output_to "java/Makefile.inc" generate_java_makefile_inc;
11235   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11236   output_to "java/Bindtests.java" generate_java_bindtests;
11237   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11238   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11239   output_to "csharp/Libguestfs.cs" generate_csharp;
11240
11241   (* Always generate this file last, and unconditionally.  It's used
11242    * by the Makefile to know when we must re-run the generator.
11243    *)
11244   let chan = open_out "src/stamp-generator" in
11245   fprintf chan "1\n";
11246   close_out chan;
11247
11248   printf "generated %d lines of code\n" !lines