d2abafcbb63a72ca53b36d3ada08b75f57ca7bef
[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 #directory "+../pkg-lib/xml-light";; (* for GODI users *)
46 #load "xml-light.cma";;
47
48 open Unix
49 open Printf
50
51 type style = ret * args
52 and ret =
53     (* "RErr" as a return value means an int used as a simple error
54      * indication, ie. 0 or -1.
55      *)
56   | RErr
57
58     (* "RInt" as a return value means an int which is -1 for error
59      * or any value >= 0 on success.  Only use this for smallish
60      * positive ints (0 <= i < 2^30).
61      *)
62   | RInt of string
63
64     (* "RInt64" is the same as RInt, but is guaranteed to be able
65      * to return a full 64 bit value, _except_ that -1 means error
66      * (so -1 cannot be a valid, non-error return value).
67      *)
68   | RInt64 of string
69
70     (* "RBool" is a bool return value which can be true/false or
71      * -1 for error.
72      *)
73   | RBool of string
74
75     (* "RConstString" is a string that refers to a constant value.
76      * The return value must NOT be NULL (since NULL indicates
77      * an error).
78      *
79      * Try to avoid using this.  In particular you cannot use this
80      * for values returned from the daemon, because there is no
81      * thread-safe way to return them in the C API.
82      *)
83   | RConstString of string
84
85     (* "RConstOptString" is an even more broken version of
86      * "RConstString".  The returned string may be NULL and there
87      * is no way to return an error indication.  Avoid using this!
88      *)
89   | RConstOptString of string
90
91     (* "RString" is a returned string.  It must NOT be NULL, since
92      * a NULL return indicates an error.  The caller frees this.
93      *)
94   | RString of string
95
96     (* "RStringList" is a list of strings.  No string in the list
97      * can be NULL.  The caller frees the strings and the array.
98      *)
99   | RStringList of string
100
101     (* "RStruct" is a function which returns a single named structure
102      * or an error indication (in C, a struct, and in other languages
103      * with varying representations, but usually very efficient).  See
104      * after the function list below for the structures.
105      *)
106   | RStruct of string * string          (* name of retval, name of struct *)
107
108     (* "RStructList" is a function which returns either a list/array
109      * of structures (could be zero-length), or an error indication.
110      *)
111   | RStructList of string * string      (* name of retval, name of struct *)
112
113     (* Key-value pairs of untyped strings.  Turns into a hashtable or
114      * dictionary in languages which support it.  DON'T use this as a
115      * general "bucket" for results.  Prefer a stronger typed return
116      * value if one is available, or write a custom struct.  Don't use
117      * this if the list could potentially be very long, since it is
118      * inefficient.  Keys should be unique.  NULLs are not permitted.
119      *)
120   | RHashtable of string
121
122     (* "RBufferOut" is handled almost exactly like RString, but
123      * it allows the string to contain arbitrary 8 bit data including
124      * ASCII NUL.  In the C API this causes an implicit extra parameter
125      * to be added of type <size_t *size_r>.  The extra parameter
126      * returns the actual size of the return buffer in bytes.
127      *
128      * Other programming languages support strings with arbitrary 8 bit
129      * data.
130      *
131      * At the RPC layer we have to use the opaque<> type instead of
132      * string<>.  Returned data is still limited to the max message
133      * size (ie. ~ 2 MB).
134      *)
135   | RBufferOut of string
136
137 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
138
139     (* Note in future we should allow a "variable args" parameter as
140      * the final parameter, to allow commands like
141      *   chmod mode file [file(s)...]
142      * This is not implemented yet, but many commands (such as chmod)
143      * are currently defined with the argument order keeping this future
144      * possibility in mind.
145      *)
146 and argt =
147   | String of string    (* const char *name, cannot be NULL *)
148   | Device of string    (* /dev device name, cannot be NULL *)
149   | Pathname of string  (* file name, cannot be NULL *)
150   | Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
151   | OptString of string (* const char *name, may be NULL *)
152   | StringList of string(* list of strings (each string cannot be NULL) *)
153   | DeviceList of string(* list of Device names (each cannot be NULL) *)
154   | Bool of string      (* boolean *)
155   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
156   | Int64 of string     (* any 64 bit int *)
157     (* These are treated as filenames (simple string parameters) in
158      * the C API and bindings.  But in the RPC protocol, we transfer
159      * the actual file content up to or down from the daemon.
160      * FileIn: local machine -> daemon (in request)
161      * FileOut: daemon -> local machine (in reply)
162      * In guestfish (only), the special name "-" means read from
163      * stdin or write to stdout.
164      *)
165   | FileIn of string
166   | FileOut of string
167 (* Not implemented:
168     (* Opaque buffer which can contain arbitrary 8 bit data.
169      * In the C API, this is expressed as <char *, int> pair.
170      * Most other languages have a string type which can contain
171      * ASCII NUL.  We use whatever type is appropriate for each
172      * language.
173      * Buffers are limited by the total message size.  To transfer
174      * large blocks of data, use FileIn/FileOut parameters instead.
175      * To return an arbitrary buffer, use RBufferOut.
176      *)
177   | BufferIn of string
178 *)
179
180 type flags =
181   | ProtocolLimitWarning  (* display warning about protocol size limits *)
182   | DangerWillRobinson    (* flags particularly dangerous commands *)
183   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
184   | FishOutput of fish_output_t (* how to display output in guestfish *)
185   | NotInFish             (* do not export via guestfish *)
186   | NotInDocs             (* do not add this function to documentation *)
187   | DeprecatedBy of string (* function is deprecated, use .. instead *)
188   | Optional of string    (* function is part of an optional group *)
189
190 and fish_output_t =
191   | FishOutputOctal       (* for int return, print in octal *)
192   | FishOutputHexadecimal (* for int return, print in hex *)
193
194 (* You can supply zero or as many tests as you want per API call.
195  *
196  * Note that the test environment has 3 block devices, of size 500MB,
197  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
198  * a fourth ISO block device with some known files on it (/dev/sdd).
199  *
200  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
201  * Number of cylinders was 63 for IDE emulated disks with precisely
202  * the same size.  How exactly this is calculated is a mystery.
203  *
204  * The ISO block device (/dev/sdd) comes from images/test.iso.
205  *
206  * To be able to run the tests in a reasonable amount of time,
207  * the virtual machine and block devices are reused between tests.
208  * So don't try testing kill_subprocess :-x
209  *
210  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
211  *
212  * Don't assume anything about the previous contents of the block
213  * devices.  Use 'Init*' to create some initial scenarios.
214  *
215  * You can add a prerequisite clause to any individual test.  This
216  * is a run-time check, which, if it fails, causes the test to be
217  * skipped.  Useful if testing a command which might not work on
218  * all variations of libguestfs builds.  A test that has prerequisite
219  * of 'Always' is run unconditionally.
220  *
221  * In addition, packagers can skip individual tests by setting the
222  * environment variables:     eg:
223  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
224  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
225  *)
226 type tests = (test_init * test_prereq * test) list
227 and test =
228     (* Run the command sequence and just expect nothing to fail. *)
229   | TestRun of seq
230
231     (* Run the command sequence and expect the output of the final
232      * command to be the string.
233      *)
234   | TestOutput of seq * string
235
236     (* Run the command sequence and expect the output of the final
237      * command to be the list of strings.
238      *)
239   | TestOutputList of seq * string list
240
241     (* Run the command sequence and expect the output of the final
242      * command to be the list of block devices (could be either
243      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
244      * character of each string).
245      *)
246   | TestOutputListOfDevices of seq * string list
247
248     (* Run the command sequence and expect the output of the final
249      * command to be the integer.
250      *)
251   | TestOutputInt of seq * int
252
253     (* Run the command sequence and expect the output of the final
254      * command to be <op> <int>, eg. ">=", "1".
255      *)
256   | TestOutputIntOp of seq * string * int
257
258     (* Run the command sequence and expect the output of the final
259      * command to be a true value (!= 0 or != NULL).
260      *)
261   | TestOutputTrue of seq
262
263     (* Run the command sequence and expect the output of the final
264      * command to be a false value (== 0 or == NULL, but not an error).
265      *)
266   | TestOutputFalse of seq
267
268     (* Run the command sequence and expect the output of the final
269      * command to be a list of the given length (but don't care about
270      * content).
271      *)
272   | TestOutputLength of seq * int
273
274     (* Run the command sequence and expect the output of the final
275      * command to be a buffer (RBufferOut), ie. string + size.
276      *)
277   | TestOutputBuffer of seq * string
278
279     (* Run the command sequence and expect the output of the final
280      * command to be a structure.
281      *)
282   | TestOutputStruct of seq * test_field_compare list
283
284     (* Run the command sequence and expect the final command (only)
285      * to fail.
286      *)
287   | TestLastFail of seq
288
289 and test_field_compare =
290   | CompareWithInt of string * int
291   | CompareWithIntOp of string * string * int
292   | CompareWithString of string * string
293   | CompareFieldsIntEq of string * string
294   | CompareFieldsStrEq of string * string
295
296 (* Test prerequisites. *)
297 and test_prereq =
298     (* Test always runs. *)
299   | Always
300
301     (* Test is currently disabled - eg. it fails, or it tests some
302      * unimplemented feature.
303      *)
304   | Disabled
305
306     (* 'string' is some C code (a function body) that should return
307      * true or false.  The test will run if the code returns true.
308      *)
309   | If of string
310
311     (* As for 'If' but the test runs _unless_ the code returns true. *)
312   | Unless of string
313
314 (* Some initial scenarios for testing. *)
315 and test_init =
316     (* Do nothing, block devices could contain random stuff including
317      * LVM PVs, and some filesystems might be mounted.  This is usually
318      * a bad idea.
319      *)
320   | InitNone
321
322     (* Block devices are empty and no filesystems are mounted. *)
323   | InitEmpty
324
325     (* /dev/sda contains a single partition /dev/sda1, with random
326      * content.  /dev/sdb and /dev/sdc may have random content.
327      * No LVM.
328      *)
329   | InitPartition
330
331     (* /dev/sda contains a single partition /dev/sda1, which is formatted
332      * as ext2, empty [except for lost+found] and mounted on /.
333      * /dev/sdb and /dev/sdc may have random content.
334      * No LVM.
335      *)
336   | InitBasicFS
337
338     (* /dev/sda:
339      *   /dev/sda1 (is a PV):
340      *     /dev/VG/LV (size 8MB):
341      *       formatted as ext2, empty [except for lost+found], mounted on /
342      * /dev/sdb and /dev/sdc may have random content.
343      *)
344   | InitBasicFSonLVM
345
346     (* /dev/sdd (the ISO, see images/ directory in source)
347      * is mounted on /
348      *)
349   | InitISOFS
350
351 (* Sequence of commands for testing. *)
352 and seq = cmd list
353 and cmd = string list
354
355 (* Note about long descriptions: When referring to another
356  * action, use the format C<guestfs_other> (ie. the full name of
357  * the C function).  This will be replaced as appropriate in other
358  * language bindings.
359  *
360  * Apart from that, long descriptions are just perldoc paragraphs.
361  *)
362
363 (* Generate a random UUID (used in tests). *)
364 let uuidgen () =
365   let chan = open_process_in "uuidgen" in
366   let uuid = input_line chan in
367   (match close_process_in chan with
368    | WEXITED 0 -> ()
369    | WEXITED _ ->
370        failwith "uuidgen: process exited with non-zero status"
371    | WSIGNALED _ | WSTOPPED _ ->
372        failwith "uuidgen: process signalled or stopped by signal"
373   );
374   uuid
375
376 (* These test functions are used in the language binding tests. *)
377
378 let test_all_args = [
379   String "str";
380   OptString "optstr";
381   StringList "strlist";
382   Bool "b";
383   Int "integer";
384   Int64 "integer64";
385   FileIn "filein";
386   FileOut "fileout";
387 ]
388
389 let test_all_rets = [
390   (* except for RErr, which is tested thoroughly elsewhere *)
391   "test0rint",         RInt "valout";
392   "test0rint64",       RInt64 "valout";
393   "test0rbool",        RBool "valout";
394   "test0rconststring", RConstString "valout";
395   "test0rconstoptstring", RConstOptString "valout";
396   "test0rstring",      RString "valout";
397   "test0rstringlist",  RStringList "valout";
398   "test0rstruct",      RStruct ("valout", "lvm_pv");
399   "test0rstructlist",  RStructList ("valout", "lvm_pv");
400   "test0rhashtable",   RHashtable "valout";
401 ]
402
403 let test_functions = [
404   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
405    [],
406    "internal test function - do not use",
407    "\
408 This is an internal test function which is used to test whether
409 the automatically generated bindings can handle every possible
410 parameter type correctly.
411
412 It echos the contents of each parameter to stdout.
413
414 You probably don't want to call this function.");
415 ] @ List.flatten (
416   List.map (
417     fun (name, ret) ->
418       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
419         [],
420         "internal test function - do not use",
421         "\
422 This is an internal test function which is used to test whether
423 the automatically generated bindings can handle every possible
424 return type correctly.
425
426 It converts string C<val> to the return type.
427
428 You probably don't want to call this function.");
429        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
430         [],
431         "internal test function - do not use",
432         "\
433 This is an internal test function which is used to test whether
434 the automatically generated bindings can handle every possible
435 return type correctly.
436
437 This function always returns an error.
438
439 You probably don't want to call this function.")]
440   ) test_all_rets
441 )
442
443 (* non_daemon_functions are any functions which don't get processed
444  * in the daemon, eg. functions for setting and getting local
445  * configuration values.
446  *)
447
448 let non_daemon_functions = test_functions @ [
449   ("launch", (RErr, []), -1, [FishAlias "run"],
450    [],
451    "launch the qemu subprocess",
452    "\
453 Internally libguestfs is implemented by running a virtual machine
454 using L<qemu(1)>.
455
456 You should call this after configuring the handle
457 (eg. adding drives) but before performing any actions.");
458
459   ("wait_ready", (RErr, []), -1, [NotInFish],
460    [],
461    "wait until the qemu subprocess launches (no op)",
462    "\
463 This function is a no op.
464
465 In versions of the API E<lt> 1.0.71 you had to call this function
466 just after calling C<guestfs_launch> to wait for the launch
467 to complete.  However this is no longer necessary because
468 C<guestfs_launch> now does the waiting.
469
470 If you see any calls to this function in code then you can just
471 remove them, unless you want to retain compatibility with older
472 versions of the API.");
473
474   ("kill_subprocess", (RErr, []), -1, [],
475    [],
476    "kill the qemu subprocess",
477    "\
478 This kills the qemu subprocess.  You should never need to call this.");
479
480   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
481    [],
482    "add an image to examine or modify",
483    "\
484 This function adds a virtual machine disk image C<filename> to the
485 guest.  The first time you call this function, the disk appears as IDE
486 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
487 so on.
488
489 You don't necessarily need to be root when using libguestfs.  However
490 you obviously do need sufficient permissions to access the filename
491 for whatever operations you want to perform (ie. read access if you
492 just want to read the image or write access if you want to modify the
493 image).
494
495 This is equivalent to the qemu parameter
496 C<-drive file=filename,cache=off,if=...>.
497
498 C<cache=off> is omitted in cases where it is not supported by
499 the underlying filesystem.
500
501 C<if=...> is set at compile time by the configuration option
502 C<./configure --with-drive-if=...>.  In the rare case where you
503 might need to change this at run time, use C<guestfs_add_drive_with_if>
504 or C<guestfs_add_drive_ro_with_if>.
505
506 Note that this call checks for the existence of C<filename>.  This
507 stops you from specifying other types of drive which are supported
508 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
509 the general C<guestfs_config> call instead.");
510
511   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
512    [],
513    "add a CD-ROM disk image to examine",
514    "\
515 This function adds a virtual CD-ROM disk image to the guest.
516
517 This is equivalent to the qemu parameter C<-cdrom filename>.
518
519 Notes:
520
521 =over 4
522
523 =item *
524
525 This call checks for the existence of C<filename>.  This
526 stops you from specifying other types of drive which are supported
527 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
528 the general C<guestfs_config> call instead.
529
530 =item *
531
532 If you just want to add an ISO file (often you use this as an
533 efficient way to transfer large files into the guest), then you
534 should probably use C<guestfs_add_drive_ro> instead.
535
536 =back");
537
538   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
539    [],
540    "add a drive in snapshot mode (read-only)",
541    "\
542 This adds a drive in snapshot mode, making it effectively
543 read-only.
544
545 Note that writes to the device are allowed, and will be seen for
546 the duration of the guestfs handle, but they are written
547 to a temporary file which is discarded as soon as the guestfs
548 handle is closed.  We don't currently have any method to enable
549 changes to be committed, although qemu can support this.
550
551 This is equivalent to the qemu parameter
552 C<-drive file=filename,snapshot=on,readonly=on,if=...>.
553
554 C<if=...> is set at compile time by the configuration option
555 C<./configure --with-drive-if=...>.  In the rare case where you
556 might need to change this at run time, use C<guestfs_add_drive_with_if>
557 or C<guestfs_add_drive_ro_with_if>.
558
559 C<readonly=on> is only added where qemu supports this option.
560
561 Note that this call checks for the existence of C<filename>.  This
562 stops you from specifying other types of drive which are supported
563 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
564 the general C<guestfs_config> call instead.");
565
566   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
567    [],
568    "add qemu parameters",
569    "\
570 This can be used to add arbitrary qemu command line parameters
571 of the form C<-param value>.  Actually it's not quite arbitrary - we
572 prevent you from setting some parameters which would interfere with
573 parameters that we use.
574
575 The first character of C<param> string must be a C<-> (dash).
576
577 C<value> can be NULL.");
578
579   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
580    [],
581    "set the qemu binary",
582    "\
583 Set the qemu binary that we will use.
584
585 The default is chosen when the library was compiled by the
586 configure script.
587
588 You can also override this by setting the C<LIBGUESTFS_QEMU>
589 environment variable.
590
591 Setting C<qemu> to C<NULL> restores the default qemu binary.
592
593 Note that you should call this function as early as possible
594 after creating the handle.  This is because some pre-launch
595 operations depend on testing qemu features (by running C<qemu -help>).
596 If the qemu binary changes, we don't retest features, and
597 so you might see inconsistent results.  Using the environment
598 variable C<LIBGUESTFS_QEMU> is safest of all since that picks
599 the qemu binary at the same time as the handle is created.");
600
601   ("get_qemu", (RConstString "qemu", []), -1, [],
602    [InitNone, Always, TestRun (
603       [["get_qemu"]])],
604    "get the qemu binary",
605    "\
606 Return the current qemu binary.
607
608 This is always non-NULL.  If it wasn't set already, then this will
609 return the default qemu binary name.");
610
611   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
612    [],
613    "set the search path",
614    "\
615 Set the path that libguestfs searches for kernel and initrd.img.
616
617 The default is C<$libdir/guestfs> unless overridden by setting
618 C<LIBGUESTFS_PATH> environment variable.
619
620 Setting C<path> to C<NULL> restores the default path.");
621
622   ("get_path", (RConstString "path", []), -1, [],
623    [InitNone, Always, TestRun (
624       [["get_path"]])],
625    "get the search path",
626    "\
627 Return the current search path.
628
629 This is always non-NULL.  If it wasn't set already, then this will
630 return the default path.");
631
632   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
633    [],
634    "add options to kernel command line",
635    "\
636 This function is used to add additional options to the
637 guest kernel command line.
638
639 The default is C<NULL> unless overridden by setting
640 C<LIBGUESTFS_APPEND> environment variable.
641
642 Setting C<append> to C<NULL> means I<no> additional options
643 are passed (libguestfs always adds a few of its own).");
644
645   ("get_append", (RConstOptString "append", []), -1, [],
646    (* This cannot be tested with the current framework.  The
647     * function can return NULL in normal operations, which the
648     * test framework interprets as an error.
649     *)
650    [],
651    "get the additional kernel options",
652    "\
653 Return the additional kernel options which are added to the
654 guest kernel command line.
655
656 If C<NULL> then no options are added.");
657
658   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
659    [],
660    "set autosync mode",
661    "\
662 If C<autosync> is true, this enables autosync.  Libguestfs will make a
663 best effort attempt to run C<guestfs_umount_all> followed by
664 C<guestfs_sync> when the handle is closed
665 (also if the program exits without closing handles).
666
667 This is disabled by default (except in guestfish where it is
668 enabled by default).");
669
670   ("get_autosync", (RBool "autosync", []), -1, [],
671    [InitNone, Always, TestRun (
672       [["get_autosync"]])],
673    "get autosync mode",
674    "\
675 Get the autosync flag.");
676
677   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
678    [],
679    "set verbose mode",
680    "\
681 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
682
683 Verbose messages are disabled unless the environment variable
684 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
685
686   ("get_verbose", (RBool "verbose", []), -1, [],
687    [],
688    "get verbose mode",
689    "\
690 This returns the verbose messages flag.");
691
692   ("is_ready", (RBool "ready", []), -1, [],
693    [InitNone, Always, TestOutputTrue (
694       [["is_ready"]])],
695    "is ready to accept commands",
696    "\
697 This returns true iff this handle is ready to accept commands
698 (in the C<READY> state).
699
700 For more information on states, see L<guestfs(3)>.");
701
702   ("is_config", (RBool "config", []), -1, [],
703    [InitNone, Always, TestOutputFalse (
704       [["is_config"]])],
705    "is in configuration state",
706    "\
707 This returns true iff this handle is being configured
708 (in the C<CONFIG> state).
709
710 For more information on states, see L<guestfs(3)>.");
711
712   ("is_launching", (RBool "launching", []), -1, [],
713    [InitNone, Always, TestOutputFalse (
714       [["is_launching"]])],
715    "is launching subprocess",
716    "\
717 This returns true iff this handle is launching the subprocess
718 (in the C<LAUNCHING> state).
719
720 For more information on states, see L<guestfs(3)>.");
721
722   ("is_busy", (RBool "busy", []), -1, [],
723    [InitNone, Always, TestOutputFalse (
724       [["is_busy"]])],
725    "is busy processing a command",
726    "\
727 This returns true iff this handle is busy processing a command
728 (in the C<BUSY> state).
729
730 For more information on states, see L<guestfs(3)>.");
731
732   ("get_state", (RInt "state", []), -1, [],
733    [],
734    "get the current state",
735    "\
736 This returns the current state as an opaque integer.  This is
737 only useful for printing debug and internal error messages.
738
739 For more information on states, see L<guestfs(3)>.");
740
741   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
742    [InitNone, Always, TestOutputInt (
743       [["set_memsize"; "500"];
744        ["get_memsize"]], 500)],
745    "set memory allocated to the qemu subprocess",
746    "\
747 This sets the memory size in megabytes allocated to the
748 qemu subprocess.  This only has any effect if called before
749 C<guestfs_launch>.
750
751 You can also change this by setting the environment
752 variable C<LIBGUESTFS_MEMSIZE> before the handle is
753 created.
754
755 For more information on the architecture of libguestfs,
756 see L<guestfs(3)>.");
757
758   ("get_memsize", (RInt "memsize", []), -1, [],
759    [InitNone, Always, TestOutputIntOp (
760       [["get_memsize"]], ">=", 256)],
761    "get memory allocated to the qemu subprocess",
762    "\
763 This gets the memory size in megabytes allocated to the
764 qemu subprocess.
765
766 If C<guestfs_set_memsize> was not called
767 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
768 then this returns the compiled-in default value for memsize.
769
770 For more information on the architecture of libguestfs,
771 see L<guestfs(3)>.");
772
773   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
774    [InitNone, Always, TestOutputIntOp (
775       [["get_pid"]], ">=", 1)],
776    "get PID of qemu subprocess",
777    "\
778 Return the process ID of the qemu subprocess.  If there is no
779 qemu subprocess, then this will return an error.
780
781 This is an internal call used for debugging and testing.");
782
783   ("version", (RStruct ("version", "version"), []), -1, [],
784    [InitNone, Always, TestOutputStruct (
785       [["version"]], [CompareWithInt ("major", 1)])],
786    "get the library version number",
787    "\
788 Return the libguestfs version number that the program is linked
789 against.
790
791 Note that because of dynamic linking this is not necessarily
792 the version of libguestfs that you compiled against.  You can
793 compile the program, and then at runtime dynamically link
794 against a completely different C<libguestfs.so> library.
795
796 This call was added in version C<1.0.58>.  In previous
797 versions of libguestfs there was no way to get the version
798 number.  From C code you can use ELF weak linking tricks to find out if
799 this symbol exists (if it doesn't, then it's an earlier version).
800
801 The call returns a structure with four elements.  The first
802 three (C<major>, C<minor> and C<release>) are numbers and
803 correspond to the usual version triplet.  The fourth element
804 (C<extra>) is a string and is normally empty, but may be
805 used for distro-specific information.
806
807 To construct the original version string:
808 C<$major.$minor.$release$extra>
809
810 I<Note:> Don't use this call to test for availability
811 of features.  Distro backports makes this unreliable.  Use
812 C<guestfs_available> instead.");
813
814   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
815    [InitNone, Always, TestOutputTrue (
816       [["set_selinux"; "true"];
817        ["get_selinux"]])],
818    "set SELinux enabled or disabled at appliance boot",
819    "\
820 This sets the selinux flag that is passed to the appliance
821 at boot time.  The default is C<selinux=0> (disabled).
822
823 Note that if SELinux is enabled, it is always in
824 Permissive mode (C<enforcing=0>).
825
826 For more information on the architecture of libguestfs,
827 see L<guestfs(3)>.");
828
829   ("get_selinux", (RBool "selinux", []), -1, [],
830    [],
831    "get SELinux enabled flag",
832    "\
833 This returns the current setting of the selinux flag which
834 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
835
836 For more information on the architecture of libguestfs,
837 see L<guestfs(3)>.");
838
839   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
840    [InitNone, Always, TestOutputFalse (
841       [["set_trace"; "false"];
842        ["get_trace"]])],
843    "enable or disable command traces",
844    "\
845 If the command trace flag is set to 1, then commands are
846 printed on stdout before they are executed in a format
847 which is very similar to the one used by guestfish.  In
848 other words, you can run a program with this enabled, and
849 you will get out a script which you can feed to guestfish
850 to perform the same set of actions.
851
852 If you want to trace C API calls into libguestfs (and
853 other libraries) then possibly a better way is to use
854 the external ltrace(1) command.
855
856 Command traces are disabled unless the environment variable
857 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
858
859   ("get_trace", (RBool "trace", []), -1, [],
860    [],
861    "get command trace enabled flag",
862    "\
863 Return the command trace flag.");
864
865   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
866    [InitNone, Always, TestOutputFalse (
867       [["set_direct"; "false"];
868        ["get_direct"]])],
869    "enable or disable direct appliance mode",
870    "\
871 If the direct appliance mode flag is enabled, then stdin and
872 stdout are passed directly through to the appliance once it
873 is launched.
874
875 One consequence of this is that log messages aren't caught
876 by the library and handled by C<guestfs_set_log_message_callback>,
877 but go straight to stdout.
878
879 You probably don't want to use this unless you know what you
880 are doing.
881
882 The default is disabled.");
883
884   ("get_direct", (RBool "direct", []), -1, [],
885    [],
886    "get direct appliance mode flag",
887    "\
888 Return the direct appliance mode flag.");
889
890   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
891    [InitNone, Always, TestOutputTrue (
892       [["set_recovery_proc"; "true"];
893        ["get_recovery_proc"]])],
894    "enable or disable the recovery process",
895    "\
896 If this is called with the parameter C<false> then
897 C<guestfs_launch> does not create a recovery process.  The
898 purpose of the recovery process is to stop runaway qemu
899 processes in the case where the main program aborts abruptly.
900
901 This only has any effect if called before C<guestfs_launch>,
902 and the default is true.
903
904 About the only time when you would want to disable this is
905 if the main process will fork itself into the background
906 (\"daemonize\" itself).  In this case the recovery process
907 thinks that the main program has disappeared and so kills
908 qemu, which is not very helpful.");
909
910   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
911    [],
912    "get recovery process enabled flag",
913    "\
914 Return the recovery process enabled flag.");
915
916   ("add_drive_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
917    [],
918    "add a drive specifying the QEMU block emulation to use",
919    "\
920 This is the same as C<guestfs_add_drive> but it allows you
921 to specify the QEMU interface emulation to use at run time.");
922
923   ("add_drive_ro_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
924    [],
925    "add a drive read-only specifying the QEMU block emulation to use",
926    "\
927 This is the same as C<guestfs_add_drive_ro> but it allows you
928 to specify the QEMU interface emulation to use at run time.");
929
930 ]
931
932 (* daemon_functions are any functions which cause some action
933  * to take place in the daemon.
934  *)
935
936 let daemon_functions = [
937   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
938    [InitEmpty, Always, TestOutput (
939       [["part_disk"; "/dev/sda"; "mbr"];
940        ["mkfs"; "ext2"; "/dev/sda1"];
941        ["mount"; "/dev/sda1"; "/"];
942        ["write_file"; "/new"; "new file contents"; "0"];
943        ["cat"; "/new"]], "new file contents")],
944    "mount a guest disk at a position in the filesystem",
945    "\
946 Mount a guest disk at a position in the filesystem.  Block devices
947 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
948 the guest.  If those block devices contain partitions, they will have
949 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
950 names can be used.
951
952 The rules are the same as for L<mount(2)>:  A filesystem must
953 first be mounted on C</> before others can be mounted.  Other
954 filesystems can only be mounted on directories which already
955 exist.
956
957 The mounted filesystem is writable, if we have sufficient permissions
958 on the underlying device.
959
960 B<Important note:>
961 When you use this call, the filesystem options C<sync> and C<noatime>
962 are set implicitly.  This was originally done because we thought it
963 would improve reliability, but it turns out that I<-o sync> has a
964 very large negative performance impact and negligible effect on
965 reliability.  Therefore we recommend that you avoid using
966 C<guestfs_mount> in any code that needs performance, and instead
967 use C<guestfs_mount_options> (use an empty string for the first
968 parameter if you don't want any options).");
969
970   ("sync", (RErr, []), 2, [],
971    [ InitEmpty, Always, TestRun [["sync"]]],
972    "sync disks, writes are flushed through to the disk image",
973    "\
974 This syncs the disk, so that any writes are flushed through to the
975 underlying disk image.
976
977 You should always call this if you have modified a disk image, before
978 closing the handle.");
979
980   ("touch", (RErr, [Pathname "path"]), 3, [],
981    [InitBasicFS, Always, TestOutputTrue (
982       [["touch"; "/new"];
983        ["exists"; "/new"]])],
984    "update file timestamps or create a new file",
985    "\
986 Touch acts like the L<touch(1)> command.  It can be used to
987 update the timestamps on a file, or, if the file does not exist,
988 to create a new zero-length file.");
989
990   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
991    [InitISOFS, Always, TestOutput (
992       [["cat"; "/known-2"]], "abcdef\n")],
993    "list the contents of a file",
994    "\
995 Return the contents of the file named C<path>.
996
997 Note that this function cannot correctly handle binary files
998 (specifically, files containing C<\\0> character which is treated
999 as end of string).  For those you need to use the C<guestfs_read_file>
1000 or C<guestfs_download> functions which have a more complex interface.");
1001
1002   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
1003    [], (* XXX Tricky to test because it depends on the exact format
1004         * of the 'ls -l' command, which changes between F10 and F11.
1005         *)
1006    "list the files in a directory (long format)",
1007    "\
1008 List the files in C<directory> (relative to the root directory,
1009 there is no cwd) in the format of 'ls -la'.
1010
1011 This command is mostly useful for interactive sessions.  It
1012 is I<not> intended that you try to parse the output string.");
1013
1014   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
1015    [InitBasicFS, Always, TestOutputList (
1016       [["touch"; "/new"];
1017        ["touch"; "/newer"];
1018        ["touch"; "/newest"];
1019        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
1020    "list the files in a directory",
1021    "\
1022 List the files in C<directory> (relative to the root directory,
1023 there is no cwd).  The '.' and '..' entries are not returned, but
1024 hidden files are shown.
1025
1026 This command is mostly useful for interactive sessions.  Programs
1027 should probably use C<guestfs_readdir> instead.");
1028
1029   ("list_devices", (RStringList "devices", []), 7, [],
1030    [InitEmpty, Always, TestOutputListOfDevices (
1031       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
1032    "list the block devices",
1033    "\
1034 List all the block devices.
1035
1036 The full block device names are returned, eg. C</dev/sda>");
1037
1038   ("list_partitions", (RStringList "partitions", []), 8, [],
1039    [InitBasicFS, Always, TestOutputListOfDevices (
1040       [["list_partitions"]], ["/dev/sda1"]);
1041     InitEmpty, Always, TestOutputListOfDevices (
1042       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1043        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1044    "list the partitions",
1045    "\
1046 List all the partitions detected on all block devices.
1047
1048 The full partition device names are returned, eg. C</dev/sda1>
1049
1050 This does not return logical volumes.  For that you will need to
1051 call C<guestfs_lvs>.");
1052
1053   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
1054    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
1055       [["pvs"]], ["/dev/sda1"]);
1056     InitEmpty, Always, TestOutputListOfDevices (
1057       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1058        ["pvcreate"; "/dev/sda1"];
1059        ["pvcreate"; "/dev/sda2"];
1060        ["pvcreate"; "/dev/sda3"];
1061        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1062    "list the LVM physical volumes (PVs)",
1063    "\
1064 List all the physical volumes detected.  This is the equivalent
1065 of the L<pvs(8)> command.
1066
1067 This returns a list of just the device names that contain
1068 PVs (eg. C</dev/sda2>).
1069
1070 See also C<guestfs_pvs_full>.");
1071
1072   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1073    [InitBasicFSonLVM, Always, TestOutputList (
1074       [["vgs"]], ["VG"]);
1075     InitEmpty, Always, TestOutputList (
1076       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1077        ["pvcreate"; "/dev/sda1"];
1078        ["pvcreate"; "/dev/sda2"];
1079        ["pvcreate"; "/dev/sda3"];
1080        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1081        ["vgcreate"; "VG2"; "/dev/sda3"];
1082        ["vgs"]], ["VG1"; "VG2"])],
1083    "list the LVM volume groups (VGs)",
1084    "\
1085 List all the volumes groups detected.  This is the equivalent
1086 of the L<vgs(8)> command.
1087
1088 This returns a list of just the volume group names that were
1089 detected (eg. C<VolGroup00>).
1090
1091 See also C<guestfs_vgs_full>.");
1092
1093   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1094    [InitBasicFSonLVM, Always, TestOutputList (
1095       [["lvs"]], ["/dev/VG/LV"]);
1096     InitEmpty, Always, TestOutputList (
1097       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1098        ["pvcreate"; "/dev/sda1"];
1099        ["pvcreate"; "/dev/sda2"];
1100        ["pvcreate"; "/dev/sda3"];
1101        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1102        ["vgcreate"; "VG2"; "/dev/sda3"];
1103        ["lvcreate"; "LV1"; "VG1"; "50"];
1104        ["lvcreate"; "LV2"; "VG1"; "50"];
1105        ["lvcreate"; "LV3"; "VG2"; "50"];
1106        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1107    "list the LVM logical volumes (LVs)",
1108    "\
1109 List all the logical volumes detected.  This is the equivalent
1110 of the L<lvs(8)> command.
1111
1112 This returns a list of the logical volume device names
1113 (eg. C</dev/VolGroup00/LogVol00>).
1114
1115 See also C<guestfs_lvs_full>.");
1116
1117   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1118    [], (* XXX how to test? *)
1119    "list the LVM physical volumes (PVs)",
1120    "\
1121 List all the physical volumes detected.  This is the equivalent
1122 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1123
1124   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1125    [], (* XXX how to test? *)
1126    "list the LVM volume groups (VGs)",
1127    "\
1128 List all the volumes groups detected.  This is the equivalent
1129 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1130
1131   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1132    [], (* XXX how to test? *)
1133    "list the LVM logical volumes (LVs)",
1134    "\
1135 List all the logical volumes detected.  This is the equivalent
1136 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1137
1138   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1139    [InitISOFS, Always, TestOutputList (
1140       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1141     InitISOFS, Always, TestOutputList (
1142       [["read_lines"; "/empty"]], [])],
1143    "read file as lines",
1144    "\
1145 Return the contents of the file named C<path>.
1146
1147 The file contents are returned as a list of lines.  Trailing
1148 C<LF> and C<CRLF> character sequences are I<not> returned.
1149
1150 Note that this function cannot correctly handle binary files
1151 (specifically, files containing C<\\0> character which is treated
1152 as end of line).  For those you need to use the C<guestfs_read_file>
1153 function which has a more complex interface.");
1154
1155   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1156    [], (* XXX Augeas code needs tests. *)
1157    "create a new Augeas handle",
1158    "\
1159 Create a new Augeas handle for editing configuration files.
1160 If there was any previous Augeas handle associated with this
1161 guestfs session, then it is closed.
1162
1163 You must call this before using any other C<guestfs_aug_*>
1164 commands.
1165
1166 C<root> is the filesystem root.  C<root> must not be NULL,
1167 use C</> instead.
1168
1169 The flags are the same as the flags defined in
1170 E<lt>augeas.hE<gt>, the logical I<or> of the following
1171 integers:
1172
1173 =over 4
1174
1175 =item C<AUG_SAVE_BACKUP> = 1
1176
1177 Keep the original file with a C<.augsave> extension.
1178
1179 =item C<AUG_SAVE_NEWFILE> = 2
1180
1181 Save changes into a file with extension C<.augnew>, and
1182 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1183
1184 =item C<AUG_TYPE_CHECK> = 4
1185
1186 Typecheck lenses (can be expensive).
1187
1188 =item C<AUG_NO_STDINC> = 8
1189
1190 Do not use standard load path for modules.
1191
1192 =item C<AUG_SAVE_NOOP> = 16
1193
1194 Make save a no-op, just record what would have been changed.
1195
1196 =item C<AUG_NO_LOAD> = 32
1197
1198 Do not load the tree in C<guestfs_aug_init>.
1199
1200 =back
1201
1202 To close the handle, you can call C<guestfs_aug_close>.
1203
1204 To find out more about Augeas, see L<http://augeas.net/>.");
1205
1206   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1207    [], (* XXX Augeas code needs tests. *)
1208    "close the current Augeas handle",
1209    "\
1210 Close the current Augeas handle and free up any resources
1211 used by it.  After calling this, you have to call
1212 C<guestfs_aug_init> again before you can use any other
1213 Augeas functions.");
1214
1215   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1216    [], (* XXX Augeas code needs tests. *)
1217    "define an Augeas variable",
1218    "\
1219 Defines an Augeas variable C<name> whose value is the result
1220 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1221 undefined.
1222
1223 On success this returns the number of nodes in C<expr>, or
1224 C<0> if C<expr> evaluates to something which is not a nodeset.");
1225
1226   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1227    [], (* XXX Augeas code needs tests. *)
1228    "define an Augeas node",
1229    "\
1230 Defines a variable C<name> whose value is the result of
1231 evaluating C<expr>.
1232
1233 If C<expr> evaluates to an empty nodeset, a node is created,
1234 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1235 C<name> will be the nodeset containing that single node.
1236
1237 On success this returns a pair containing the
1238 number of nodes in the nodeset, and a boolean flag
1239 if a node was created.");
1240
1241   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1242    [], (* XXX Augeas code needs tests. *)
1243    "look up the value of an Augeas path",
1244    "\
1245 Look up the value associated with C<path>.  If C<path>
1246 matches exactly one node, the C<value> is returned.");
1247
1248   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1249    [], (* XXX Augeas code needs tests. *)
1250    "set Augeas path to value",
1251    "\
1252 Set the value associated with C<path> to C<val>.
1253
1254 In the Augeas API, it is possible to clear a node by setting
1255 the value to NULL.  Due to an oversight in the libguestfs API
1256 you cannot do that with this call.  Instead you must use the
1257 C<guestfs_aug_clear> call.");
1258
1259   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1260    [], (* XXX Augeas code needs tests. *)
1261    "insert a sibling Augeas node",
1262    "\
1263 Create a new sibling C<label> for C<path>, inserting it into
1264 the tree before or after C<path> (depending on the boolean
1265 flag C<before>).
1266
1267 C<path> must match exactly one existing node in the tree, and
1268 C<label> must be a label, ie. not contain C</>, C<*> or end
1269 with a bracketed index C<[N]>.");
1270
1271   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1272    [], (* XXX Augeas code needs tests. *)
1273    "remove an Augeas path",
1274    "\
1275 Remove C<path> and all of its children.
1276
1277 On success this returns the number of entries which were removed.");
1278
1279   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1280    [], (* XXX Augeas code needs tests. *)
1281    "move Augeas node",
1282    "\
1283 Move the node C<src> to C<dest>.  C<src> must match exactly
1284 one node.  C<dest> is overwritten if it exists.");
1285
1286   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1287    [], (* XXX Augeas code needs tests. *)
1288    "return Augeas nodes which match augpath",
1289    "\
1290 Returns a list of paths which match the path expression C<path>.
1291 The returned paths are sufficiently qualified so that they match
1292 exactly one node in the current tree.");
1293
1294   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1295    [], (* XXX Augeas code needs tests. *)
1296    "write all pending Augeas changes to disk",
1297    "\
1298 This writes all pending changes to disk.
1299
1300 The flags which were passed to C<guestfs_aug_init> affect exactly
1301 how files are saved.");
1302
1303   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1304    [], (* XXX Augeas code needs tests. *)
1305    "load files into the tree",
1306    "\
1307 Load files into the tree.
1308
1309 See C<aug_load> in the Augeas documentation for the full gory
1310 details.");
1311
1312   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1313    [], (* XXX Augeas code needs tests. *)
1314    "list Augeas nodes under augpath",
1315    "\
1316 This is just a shortcut for listing C<guestfs_aug_match>
1317 C<path/*> and sorting the resulting nodes into alphabetical order.");
1318
1319   ("rm", (RErr, [Pathname "path"]), 29, [],
1320    [InitBasicFS, Always, TestRun
1321       [["touch"; "/new"];
1322        ["rm"; "/new"]];
1323     InitBasicFS, Always, TestLastFail
1324       [["rm"; "/new"]];
1325     InitBasicFS, Always, TestLastFail
1326       [["mkdir"; "/new"];
1327        ["rm"; "/new"]]],
1328    "remove a file",
1329    "\
1330 Remove the single file C<path>.");
1331
1332   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1333    [InitBasicFS, Always, TestRun
1334       [["mkdir"; "/new"];
1335        ["rmdir"; "/new"]];
1336     InitBasicFS, Always, TestLastFail
1337       [["rmdir"; "/new"]];
1338     InitBasicFS, Always, TestLastFail
1339       [["touch"; "/new"];
1340        ["rmdir"; "/new"]]],
1341    "remove a directory",
1342    "\
1343 Remove the single directory C<path>.");
1344
1345   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1346    [InitBasicFS, Always, TestOutputFalse
1347       [["mkdir"; "/new"];
1348        ["mkdir"; "/new/foo"];
1349        ["touch"; "/new/foo/bar"];
1350        ["rm_rf"; "/new"];
1351        ["exists"; "/new"]]],
1352    "remove a file or directory recursively",
1353    "\
1354 Remove the file or directory C<path>, recursively removing the
1355 contents if its a directory.  This is like the C<rm -rf> shell
1356 command.");
1357
1358   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1359    [InitBasicFS, Always, TestOutputTrue
1360       [["mkdir"; "/new"];
1361        ["is_dir"; "/new"]];
1362     InitBasicFS, Always, TestLastFail
1363       [["mkdir"; "/new/foo/bar"]]],
1364    "create a directory",
1365    "\
1366 Create a directory named C<path>.");
1367
1368   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1369    [InitBasicFS, Always, TestOutputTrue
1370       [["mkdir_p"; "/new/foo/bar"];
1371        ["is_dir"; "/new/foo/bar"]];
1372     InitBasicFS, Always, TestOutputTrue
1373       [["mkdir_p"; "/new/foo/bar"];
1374        ["is_dir"; "/new/foo"]];
1375     InitBasicFS, Always, TestOutputTrue
1376       [["mkdir_p"; "/new/foo/bar"];
1377        ["is_dir"; "/new"]];
1378     (* Regression tests for RHBZ#503133: *)
1379     InitBasicFS, Always, TestRun
1380       [["mkdir"; "/new"];
1381        ["mkdir_p"; "/new"]];
1382     InitBasicFS, Always, TestLastFail
1383       [["touch"; "/new"];
1384        ["mkdir_p"; "/new"]]],
1385    "create a directory and parents",
1386    "\
1387 Create a directory named C<path>, creating any parent directories
1388 as necessary.  This is like the C<mkdir -p> shell command.");
1389
1390   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1391    [], (* XXX Need stat command to test *)
1392    "change file mode",
1393    "\
1394 Change the mode (permissions) of C<path> to C<mode>.  Only
1395 numeric modes are supported.
1396
1397 I<Note>: When using this command from guestfish, C<mode>
1398 by default would be decimal, unless you prefix it with
1399 C<0> to get octal, ie. use C<0700> not C<700>.
1400
1401 The mode actually set is affected by the umask.");
1402
1403   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1404    [], (* XXX Need stat command to test *)
1405    "change file owner and group",
1406    "\
1407 Change the file owner to C<owner> and group to C<group>.
1408
1409 Only numeric uid and gid are supported.  If you want to use
1410 names, you will need to locate and parse the password file
1411 yourself (Augeas support makes this relatively easy).");
1412
1413   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1414    [InitISOFS, Always, TestOutputTrue (
1415       [["exists"; "/empty"]]);
1416     InitISOFS, Always, TestOutputTrue (
1417       [["exists"; "/directory"]])],
1418    "test if file or directory exists",
1419    "\
1420 This returns C<true> if and only if there is a file, directory
1421 (or anything) with the given C<path> name.
1422
1423 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1424
1425   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1426    [InitISOFS, Always, TestOutputTrue (
1427       [["is_file"; "/known-1"]]);
1428     InitISOFS, Always, TestOutputFalse (
1429       [["is_file"; "/directory"]])],
1430    "test if file exists",
1431    "\
1432 This returns C<true> if and only if there is a file
1433 with the given C<path> name.  Note that it returns false for
1434 other objects like directories.
1435
1436 See also C<guestfs_stat>.");
1437
1438   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1439    [InitISOFS, Always, TestOutputFalse (
1440       [["is_dir"; "/known-3"]]);
1441     InitISOFS, Always, TestOutputTrue (
1442       [["is_dir"; "/directory"]])],
1443    "test if file exists",
1444    "\
1445 This returns C<true> if and only if there is a directory
1446 with the given C<path> name.  Note that it returns false for
1447 other objects like files.
1448
1449 See also C<guestfs_stat>.");
1450
1451   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1452    [InitEmpty, Always, TestOutputListOfDevices (
1453       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1454        ["pvcreate"; "/dev/sda1"];
1455        ["pvcreate"; "/dev/sda2"];
1456        ["pvcreate"; "/dev/sda3"];
1457        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1458    "create an LVM physical volume",
1459    "\
1460 This creates an LVM physical volume on the named C<device>,
1461 where C<device> should usually be a partition name such
1462 as C</dev/sda1>.");
1463
1464   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1465    [InitEmpty, Always, TestOutputList (
1466       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1467        ["pvcreate"; "/dev/sda1"];
1468        ["pvcreate"; "/dev/sda2"];
1469        ["pvcreate"; "/dev/sda3"];
1470        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1471        ["vgcreate"; "VG2"; "/dev/sda3"];
1472        ["vgs"]], ["VG1"; "VG2"])],
1473    "create an LVM volume group",
1474    "\
1475 This creates an LVM volume group called C<volgroup>
1476 from the non-empty list of physical volumes C<physvols>.");
1477
1478   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1479    [InitEmpty, Always, TestOutputList (
1480       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1481        ["pvcreate"; "/dev/sda1"];
1482        ["pvcreate"; "/dev/sda2"];
1483        ["pvcreate"; "/dev/sda3"];
1484        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1485        ["vgcreate"; "VG2"; "/dev/sda3"];
1486        ["lvcreate"; "LV1"; "VG1"; "50"];
1487        ["lvcreate"; "LV2"; "VG1"; "50"];
1488        ["lvcreate"; "LV3"; "VG2"; "50"];
1489        ["lvcreate"; "LV4"; "VG2"; "50"];
1490        ["lvcreate"; "LV5"; "VG2"; "50"];
1491        ["lvs"]],
1492       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1493        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1494    "create an LVM logical volume",
1495    "\
1496 This creates an LVM logical volume called C<logvol>
1497 on the volume group C<volgroup>, with C<size> megabytes.");
1498
1499   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1500    [InitEmpty, Always, TestOutput (
1501       [["part_disk"; "/dev/sda"; "mbr"];
1502        ["mkfs"; "ext2"; "/dev/sda1"];
1503        ["mount_options"; ""; "/dev/sda1"; "/"];
1504        ["write_file"; "/new"; "new file contents"; "0"];
1505        ["cat"; "/new"]], "new file contents")],
1506    "make a filesystem",
1507    "\
1508 This creates a filesystem on C<device> (usually a partition
1509 or LVM logical volume).  The filesystem type is C<fstype>, for
1510 example C<ext3>.");
1511
1512   ("sfdisk", (RErr, [Device "device";
1513                      Int "cyls"; Int "heads"; Int "sectors";
1514                      StringList "lines"]), 43, [DangerWillRobinson],
1515    [],
1516    "create partitions on a block device",
1517    "\
1518 This is a direct interface to the L<sfdisk(8)> program for creating
1519 partitions on block devices.
1520
1521 C<device> should be a block device, for example C</dev/sda>.
1522
1523 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1524 and sectors on the device, which are passed directly to sfdisk as
1525 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1526 of these, then the corresponding parameter is omitted.  Usually for
1527 'large' disks, you can just pass C<0> for these, but for small
1528 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1529 out the right geometry and you will need to tell it.
1530
1531 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1532 information refer to the L<sfdisk(8)> manpage.
1533
1534 To create a single partition occupying the whole disk, you would
1535 pass C<lines> as a single element list, when the single element being
1536 the string C<,> (comma).
1537
1538 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1539 C<guestfs_part_init>");
1540
1541   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1542    [InitBasicFS, Always, TestOutput (
1543       [["write_file"; "/new"; "new file contents"; "0"];
1544        ["cat"; "/new"]], "new file contents");
1545     InitBasicFS, Always, TestOutput (
1546       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1547        ["cat"; "/new"]], "\nnew file contents\n");
1548     InitBasicFS, Always, TestOutput (
1549       [["write_file"; "/new"; "\n\n"; "0"];
1550        ["cat"; "/new"]], "\n\n");
1551     InitBasicFS, Always, TestOutput (
1552       [["write_file"; "/new"; ""; "0"];
1553        ["cat"; "/new"]], "");
1554     InitBasicFS, Always, TestOutput (
1555       [["write_file"; "/new"; "\n\n\n"; "0"];
1556        ["cat"; "/new"]], "\n\n\n");
1557     InitBasicFS, Always, TestOutput (
1558       [["write_file"; "/new"; "\n"; "0"];
1559        ["cat"; "/new"]], "\n")],
1560    "create a file",
1561    "\
1562 This call creates a file called C<path>.  The contents of the
1563 file is the string C<content> (which can contain any 8 bit data),
1564 with length C<size>.
1565
1566 As a special case, if C<size> is C<0>
1567 then the length is calculated using C<strlen> (so in this case
1568 the content cannot contain embedded ASCII NULs).
1569
1570 I<NB.> Owing to a bug, writing content containing ASCII NUL
1571 characters does I<not> work, even if the length is specified.
1572 We hope to resolve this bug in a future version.  In the meantime
1573 use C<guestfs_upload>.");
1574
1575   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1576    [InitEmpty, Always, TestOutputListOfDevices (
1577       [["part_disk"; "/dev/sda"; "mbr"];
1578        ["mkfs"; "ext2"; "/dev/sda1"];
1579        ["mount_options"; ""; "/dev/sda1"; "/"];
1580        ["mounts"]], ["/dev/sda1"]);
1581     InitEmpty, Always, TestOutputList (
1582       [["part_disk"; "/dev/sda"; "mbr"];
1583        ["mkfs"; "ext2"; "/dev/sda1"];
1584        ["mount_options"; ""; "/dev/sda1"; "/"];
1585        ["umount"; "/"];
1586        ["mounts"]], [])],
1587    "unmount a filesystem",
1588    "\
1589 This unmounts the given filesystem.  The filesystem may be
1590 specified either by its mountpoint (path) or the device which
1591 contains the filesystem.");
1592
1593   ("mounts", (RStringList "devices", []), 46, [],
1594    [InitBasicFS, Always, TestOutputListOfDevices (
1595       [["mounts"]], ["/dev/sda1"])],
1596    "show mounted filesystems",
1597    "\
1598 This returns the list of currently mounted filesystems.  It returns
1599 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1600
1601 Some internal mounts are not shown.
1602
1603 See also: C<guestfs_mountpoints>");
1604
1605   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1606    [InitBasicFS, Always, TestOutputList (
1607       [["umount_all"];
1608        ["mounts"]], []);
1609     (* check that umount_all can unmount nested mounts correctly: *)
1610     InitEmpty, Always, TestOutputList (
1611       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1612        ["mkfs"; "ext2"; "/dev/sda1"];
1613        ["mkfs"; "ext2"; "/dev/sda2"];
1614        ["mkfs"; "ext2"; "/dev/sda3"];
1615        ["mount_options"; ""; "/dev/sda1"; "/"];
1616        ["mkdir"; "/mp1"];
1617        ["mount_options"; ""; "/dev/sda2"; "/mp1"];
1618        ["mkdir"; "/mp1/mp2"];
1619        ["mount_options"; ""; "/dev/sda3"; "/mp1/mp2"];
1620        ["mkdir"; "/mp1/mp2/mp3"];
1621        ["umount_all"];
1622        ["mounts"]], [])],
1623    "unmount all filesystems",
1624    "\
1625 This unmounts all mounted filesystems.
1626
1627 Some internal mounts are not unmounted by this call.");
1628
1629   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1630    [],
1631    "remove all LVM LVs, VGs and PVs",
1632    "\
1633 This command removes all LVM logical volumes, volume groups
1634 and physical volumes.");
1635
1636   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1637    [InitISOFS, Always, TestOutput (
1638       [["file"; "/empty"]], "empty");
1639     InitISOFS, Always, TestOutput (
1640       [["file"; "/known-1"]], "ASCII text");
1641     InitISOFS, Always, TestLastFail (
1642       [["file"; "/notexists"]])],
1643    "determine file type",
1644    "\
1645 This call uses the standard L<file(1)> command to determine
1646 the type or contents of the file.  This also works on devices,
1647 for example to find out whether a partition contains a filesystem.
1648
1649 This call will also transparently look inside various types
1650 of compressed file.
1651
1652 The exact command which runs is C<file -zbsL path>.  Note in
1653 particular that the filename is not prepended to the output
1654 (the C<-b> option).");
1655
1656   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1657    [InitBasicFS, Always, TestOutput (
1658       [["upload"; "test-command"; "/test-command"];
1659        ["chmod"; "0o755"; "/test-command"];
1660        ["command"; "/test-command 1"]], "Result1");
1661     InitBasicFS, Always, TestOutput (
1662       [["upload"; "test-command"; "/test-command"];
1663        ["chmod"; "0o755"; "/test-command"];
1664        ["command"; "/test-command 2"]], "Result2\n");
1665     InitBasicFS, Always, TestOutput (
1666       [["upload"; "test-command"; "/test-command"];
1667        ["chmod"; "0o755"; "/test-command"];
1668        ["command"; "/test-command 3"]], "\nResult3");
1669     InitBasicFS, Always, TestOutput (
1670       [["upload"; "test-command"; "/test-command"];
1671        ["chmod"; "0o755"; "/test-command"];
1672        ["command"; "/test-command 4"]], "\nResult4\n");
1673     InitBasicFS, Always, TestOutput (
1674       [["upload"; "test-command"; "/test-command"];
1675        ["chmod"; "0o755"; "/test-command"];
1676        ["command"; "/test-command 5"]], "\nResult5\n\n");
1677     InitBasicFS, Always, TestOutput (
1678       [["upload"; "test-command"; "/test-command"];
1679        ["chmod"; "0o755"; "/test-command"];
1680        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1681     InitBasicFS, Always, TestOutput (
1682       [["upload"; "test-command"; "/test-command"];
1683        ["chmod"; "0o755"; "/test-command"];
1684        ["command"; "/test-command 7"]], "");
1685     InitBasicFS, Always, TestOutput (
1686       [["upload"; "test-command"; "/test-command"];
1687        ["chmod"; "0o755"; "/test-command"];
1688        ["command"; "/test-command 8"]], "\n");
1689     InitBasicFS, Always, TestOutput (
1690       [["upload"; "test-command"; "/test-command"];
1691        ["chmod"; "0o755"; "/test-command"];
1692        ["command"; "/test-command 9"]], "\n\n");
1693     InitBasicFS, Always, TestOutput (
1694       [["upload"; "test-command"; "/test-command"];
1695        ["chmod"; "0o755"; "/test-command"];
1696        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1697     InitBasicFS, Always, TestOutput (
1698       [["upload"; "test-command"; "/test-command"];
1699        ["chmod"; "0o755"; "/test-command"];
1700        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1701     InitBasicFS, Always, TestLastFail (
1702       [["upload"; "test-command"; "/test-command"];
1703        ["chmod"; "0o755"; "/test-command"];
1704        ["command"; "/test-command"]])],
1705    "run a command from the guest filesystem",
1706    "\
1707 This call runs a command from the guest filesystem.  The
1708 filesystem must be mounted, and must contain a compatible
1709 operating system (ie. something Linux, with the same
1710 or compatible processor architecture).
1711
1712 The single parameter is an argv-style list of arguments.
1713 The first element is the name of the program to run.
1714 Subsequent elements are parameters.  The list must be
1715 non-empty (ie. must contain a program name).  Note that
1716 the command runs directly, and is I<not> invoked via
1717 the shell (see C<guestfs_sh>).
1718
1719 The return value is anything printed to I<stdout> by
1720 the command.
1721
1722 If the command returns a non-zero exit status, then
1723 this function returns an error message.  The error message
1724 string is the content of I<stderr> from the command.
1725
1726 The C<$PATH> environment variable will contain at least
1727 C</usr/bin> and C</bin>.  If you require a program from
1728 another location, you should provide the full path in the
1729 first parameter.
1730
1731 Shared libraries and data files required by the program
1732 must be available on filesystems which are mounted in the
1733 correct places.  It is the caller's responsibility to ensure
1734 all filesystems that are needed are mounted at the right
1735 locations.");
1736
1737   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1738    [InitBasicFS, Always, TestOutputList (
1739       [["upload"; "test-command"; "/test-command"];
1740        ["chmod"; "0o755"; "/test-command"];
1741        ["command_lines"; "/test-command 1"]], ["Result1"]);
1742     InitBasicFS, Always, TestOutputList (
1743       [["upload"; "test-command"; "/test-command"];
1744        ["chmod"; "0o755"; "/test-command"];
1745        ["command_lines"; "/test-command 2"]], ["Result2"]);
1746     InitBasicFS, Always, TestOutputList (
1747       [["upload"; "test-command"; "/test-command"];
1748        ["chmod"; "0o755"; "/test-command"];
1749        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1750     InitBasicFS, Always, TestOutputList (
1751       [["upload"; "test-command"; "/test-command"];
1752        ["chmod"; "0o755"; "/test-command"];
1753        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1754     InitBasicFS, Always, TestOutputList (
1755       [["upload"; "test-command"; "/test-command"];
1756        ["chmod"; "0o755"; "/test-command"];
1757        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1758     InitBasicFS, Always, TestOutputList (
1759       [["upload"; "test-command"; "/test-command"];
1760        ["chmod"; "0o755"; "/test-command"];
1761        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1762     InitBasicFS, Always, TestOutputList (
1763       [["upload"; "test-command"; "/test-command"];
1764        ["chmod"; "0o755"; "/test-command"];
1765        ["command_lines"; "/test-command 7"]], []);
1766     InitBasicFS, Always, TestOutputList (
1767       [["upload"; "test-command"; "/test-command"];
1768        ["chmod"; "0o755"; "/test-command"];
1769        ["command_lines"; "/test-command 8"]], [""]);
1770     InitBasicFS, Always, TestOutputList (
1771       [["upload"; "test-command"; "/test-command"];
1772        ["chmod"; "0o755"; "/test-command"];
1773        ["command_lines"; "/test-command 9"]], ["";""]);
1774     InitBasicFS, Always, TestOutputList (
1775       [["upload"; "test-command"; "/test-command"];
1776        ["chmod"; "0o755"; "/test-command"];
1777        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1778     InitBasicFS, Always, TestOutputList (
1779       [["upload"; "test-command"; "/test-command"];
1780        ["chmod"; "0o755"; "/test-command"];
1781        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1782    "run a command, returning lines",
1783    "\
1784 This is the same as C<guestfs_command>, but splits the
1785 result into a list of lines.
1786
1787 See also: C<guestfs_sh_lines>");
1788
1789   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1790    [InitISOFS, Always, TestOutputStruct (
1791       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1792    "get file information",
1793    "\
1794 Returns file information for the given C<path>.
1795
1796 This is the same as the C<stat(2)> system call.");
1797
1798   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1799    [InitISOFS, Always, TestOutputStruct (
1800       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1801    "get file information for a symbolic link",
1802    "\
1803 Returns file information for the given C<path>.
1804
1805 This is the same as C<guestfs_stat> except that if C<path>
1806 is a symbolic link, then the link is stat-ed, not the file it
1807 refers to.
1808
1809 This is the same as the C<lstat(2)> system call.");
1810
1811   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1812    [InitISOFS, Always, TestOutputStruct (
1813       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1814    "get file system statistics",
1815    "\
1816 Returns file system statistics for any mounted file system.
1817 C<path> should be a file or directory in the mounted file system
1818 (typically it is the mount point itself, but it doesn't need to be).
1819
1820 This is the same as the C<statvfs(2)> system call.");
1821
1822   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1823    [], (* XXX test *)
1824    "get ext2/ext3/ext4 superblock details",
1825    "\
1826 This returns the contents of the ext2, ext3 or ext4 filesystem
1827 superblock on C<device>.
1828
1829 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1830 manpage for more details.  The list of fields returned isn't
1831 clearly defined, and depends on both the version of C<tune2fs>
1832 that libguestfs was built against, and the filesystem itself.");
1833
1834   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1835    [InitEmpty, Always, TestOutputTrue (
1836       [["blockdev_setro"; "/dev/sda"];
1837        ["blockdev_getro"; "/dev/sda"]])],
1838    "set block device to read-only",
1839    "\
1840 Sets the block device named C<device> to read-only.
1841
1842 This uses the L<blockdev(8)> command.");
1843
1844   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1845    [InitEmpty, Always, TestOutputFalse (
1846       [["blockdev_setrw"; "/dev/sda"];
1847        ["blockdev_getro"; "/dev/sda"]])],
1848    "set block device to read-write",
1849    "\
1850 Sets the block device named C<device> to read-write.
1851
1852 This uses the L<blockdev(8)> command.");
1853
1854   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1855    [InitEmpty, Always, TestOutputTrue (
1856       [["blockdev_setro"; "/dev/sda"];
1857        ["blockdev_getro"; "/dev/sda"]])],
1858    "is block device set to read-only",
1859    "\
1860 Returns a boolean indicating if the block device is read-only
1861 (true if read-only, false if not).
1862
1863 This uses the L<blockdev(8)> command.");
1864
1865   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1866    [InitEmpty, Always, TestOutputInt (
1867       [["blockdev_getss"; "/dev/sda"]], 512)],
1868    "get sectorsize of block device",
1869    "\
1870 This returns the size of sectors on a block device.
1871 Usually 512, but can be larger for modern devices.
1872
1873 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1874 for that).
1875
1876 This uses the L<blockdev(8)> command.");
1877
1878   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1879    [InitEmpty, Always, TestOutputInt (
1880       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1881    "get blocksize of block device",
1882    "\
1883 This returns the block size of a device.
1884
1885 (Note this is different from both I<size in blocks> and
1886 I<filesystem block size>).
1887
1888 This uses the L<blockdev(8)> command.");
1889
1890   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1891    [], (* XXX test *)
1892    "set blocksize of block device",
1893    "\
1894 This sets the block size of a device.
1895
1896 (Note this is different from both I<size in blocks> and
1897 I<filesystem block size>).
1898
1899 This uses the L<blockdev(8)> command.");
1900
1901   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1902    [InitEmpty, Always, TestOutputInt (
1903       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1904    "get total size of device in 512-byte sectors",
1905    "\
1906 This returns the size of the device in units of 512-byte sectors
1907 (even if the sectorsize isn't 512 bytes ... weird).
1908
1909 See also C<guestfs_blockdev_getss> for the real sector size of
1910 the device, and C<guestfs_blockdev_getsize64> for the more
1911 useful I<size in bytes>.
1912
1913 This uses the L<blockdev(8)> command.");
1914
1915   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1916    [InitEmpty, Always, TestOutputInt (
1917       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1918    "get total size of device in bytes",
1919    "\
1920 This returns the size of the device in bytes.
1921
1922 See also C<guestfs_blockdev_getsz>.
1923
1924 This uses the L<blockdev(8)> command.");
1925
1926   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1927    [InitEmpty, Always, TestRun
1928       [["blockdev_flushbufs"; "/dev/sda"]]],
1929    "flush device buffers",
1930    "\
1931 This tells the kernel to flush internal buffers associated
1932 with C<device>.
1933
1934 This uses the L<blockdev(8)> command.");
1935
1936   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1937    [InitEmpty, Always, TestRun
1938       [["blockdev_rereadpt"; "/dev/sda"]]],
1939    "reread partition table",
1940    "\
1941 Reread the partition table on C<device>.
1942
1943 This uses the L<blockdev(8)> command.");
1944
1945   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1946    [InitBasicFS, Always, TestOutput (
1947       (* Pick a file from cwd which isn't likely to change. *)
1948       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1949        ["checksum"; "md5"; "/COPYING.LIB"]],
1950       Digest.to_hex (Digest.file "COPYING.LIB"))],
1951    "upload a file from the local machine",
1952    "\
1953 Upload local file C<filename> to C<remotefilename> on the
1954 filesystem.
1955
1956 C<filename> can also be a named pipe.
1957
1958 See also C<guestfs_download>.");
1959
1960   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1961    [InitBasicFS, Always, TestOutput (
1962       (* Pick a file from cwd which isn't likely to change. *)
1963       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1964        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1965        ["upload"; "testdownload.tmp"; "/upload"];
1966        ["checksum"; "md5"; "/upload"]],
1967       Digest.to_hex (Digest.file "COPYING.LIB"))],
1968    "download a file to the local machine",
1969    "\
1970 Download file C<remotefilename> and save it as C<filename>
1971 on the local machine.
1972
1973 C<filename> can also be a named pipe.
1974
1975 See also C<guestfs_upload>, C<guestfs_cat>.");
1976
1977   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1978    [InitISOFS, Always, TestOutput (
1979       [["checksum"; "crc"; "/known-3"]], "2891671662");
1980     InitISOFS, Always, TestLastFail (
1981       [["checksum"; "crc"; "/notexists"]]);
1982     InitISOFS, Always, TestOutput (
1983       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1984     InitISOFS, Always, TestOutput (
1985       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1986     InitISOFS, Always, TestOutput (
1987       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1988     InitISOFS, Always, TestOutput (
1989       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1990     InitISOFS, Always, TestOutput (
1991       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1992     InitISOFS, Always, TestOutput (
1993       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6");
1994     (* Test for RHBZ#579608, absolute symbolic links. *)
1995     InitISOFS, Always, TestOutput (
1996       [["checksum"; "sha512"; "/abssymlink"]], "5f57d0639bc95081c53afc63a449403883818edc64da48930ad6b1a4fb49be90404686877743fbcd7c99811f3def7df7bc22635c885c6a8cf79c806b43451c1a")],
1997    "compute MD5, SHAx or CRC checksum of file",
1998    "\
1999 This call computes the MD5, SHAx or CRC checksum of the
2000 file named C<path>.
2001
2002 The type of checksum to compute is given by the C<csumtype>
2003 parameter which must have one of the following values:
2004
2005 =over 4
2006
2007 =item C<crc>
2008
2009 Compute the cyclic redundancy check (CRC) specified by POSIX
2010 for the C<cksum> command.
2011
2012 =item C<md5>
2013
2014 Compute the MD5 hash (using the C<md5sum> program).
2015
2016 =item C<sha1>
2017
2018 Compute the SHA1 hash (using the C<sha1sum> program).
2019
2020 =item C<sha224>
2021
2022 Compute the SHA224 hash (using the C<sha224sum> program).
2023
2024 =item C<sha256>
2025
2026 Compute the SHA256 hash (using the C<sha256sum> program).
2027
2028 =item C<sha384>
2029
2030 Compute the SHA384 hash (using the C<sha384sum> program).
2031
2032 =item C<sha512>
2033
2034 Compute the SHA512 hash (using the C<sha512sum> program).
2035
2036 =back
2037
2038 The checksum is returned as a printable string.
2039
2040 To get the checksum for a device, use C<guestfs_checksum_device>.
2041
2042 To get the checksums for many files, use C<guestfs_checksums_out>.");
2043
2044   ("tar_in", (RErr, [FileIn "tarfile"; Pathname "directory"]), 69, [],
2045    [InitBasicFS, Always, TestOutput (
2046       [["tar_in"; "../images/helloworld.tar"; "/"];
2047        ["cat"; "/hello"]], "hello\n")],
2048    "unpack tarfile to directory",
2049    "\
2050 This command uploads and unpacks local file C<tarfile> (an
2051 I<uncompressed> tar file) into C<directory>.
2052
2053 To upload a compressed tarball, use C<guestfs_tgz_in>
2054 or C<guestfs_txz_in>.");
2055
2056   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
2057    [],
2058    "pack directory into tarfile",
2059    "\
2060 This command packs the contents of C<directory> and downloads
2061 it to local file C<tarfile>.
2062
2063 To download a compressed tarball, use C<guestfs_tgz_out>
2064 or C<guestfs_txz_out>.");
2065
2066   ("tgz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 71, [],
2067    [InitBasicFS, Always, TestOutput (
2068       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
2069        ["cat"; "/hello"]], "hello\n")],
2070    "unpack compressed tarball to directory",
2071    "\
2072 This command uploads and unpacks local file C<tarball> (a
2073 I<gzip compressed> tar file) into C<directory>.
2074
2075 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
2076
2077   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
2078    [],
2079    "pack directory into compressed tarball",
2080    "\
2081 This command packs the contents of C<directory> and downloads
2082 it to local file C<tarball>.
2083
2084 To download an uncompressed tarball, use C<guestfs_tar_out>.");
2085
2086   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
2087    [InitBasicFS, Always, TestLastFail (
2088       [["umount"; "/"];
2089        ["mount_ro"; "/dev/sda1"; "/"];
2090        ["touch"; "/new"]]);
2091     InitBasicFS, Always, TestOutput (
2092       [["write_file"; "/new"; "data"; "0"];
2093        ["umount"; "/"];
2094        ["mount_ro"; "/dev/sda1"; "/"];
2095        ["cat"; "/new"]], "data")],
2096    "mount a guest disk, read-only",
2097    "\
2098 This is the same as the C<guestfs_mount> command, but it
2099 mounts the filesystem with the read-only (I<-o ro>) flag.");
2100
2101   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
2102    [],
2103    "mount a guest disk with mount options",
2104    "\
2105 This is the same as the C<guestfs_mount> command, but it
2106 allows you to set the mount options as for the
2107 L<mount(8)> I<-o> flag.
2108
2109 If the C<options> parameter is an empty string, then
2110 no options are passed (all options default to whatever
2111 the filesystem uses).");
2112
2113   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2114    [],
2115    "mount a guest disk with mount options and vfstype",
2116    "\
2117 This is the same as the C<guestfs_mount> command, but it
2118 allows you to set both the mount options and the vfstype
2119 as for the L<mount(8)> I<-o> and I<-t> flags.");
2120
2121   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2122    [],
2123    "debugging and internals",
2124    "\
2125 The C<guestfs_debug> command exposes some internals of
2126 C<guestfsd> (the guestfs daemon) that runs inside the
2127 qemu subprocess.
2128
2129 There is no comprehensive help for this command.  You have
2130 to look at the file C<daemon/debug.c> in the libguestfs source
2131 to find out what you can do.");
2132
2133   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2134    [InitEmpty, Always, TestOutputList (
2135       [["part_disk"; "/dev/sda"; "mbr"];
2136        ["pvcreate"; "/dev/sda1"];
2137        ["vgcreate"; "VG"; "/dev/sda1"];
2138        ["lvcreate"; "LV1"; "VG"; "50"];
2139        ["lvcreate"; "LV2"; "VG"; "50"];
2140        ["lvremove"; "/dev/VG/LV1"];
2141        ["lvs"]], ["/dev/VG/LV2"]);
2142     InitEmpty, Always, TestOutputList (
2143       [["part_disk"; "/dev/sda"; "mbr"];
2144        ["pvcreate"; "/dev/sda1"];
2145        ["vgcreate"; "VG"; "/dev/sda1"];
2146        ["lvcreate"; "LV1"; "VG"; "50"];
2147        ["lvcreate"; "LV2"; "VG"; "50"];
2148        ["lvremove"; "/dev/VG"];
2149        ["lvs"]], []);
2150     InitEmpty, Always, TestOutputList (
2151       [["part_disk"; "/dev/sda"; "mbr"];
2152        ["pvcreate"; "/dev/sda1"];
2153        ["vgcreate"; "VG"; "/dev/sda1"];
2154        ["lvcreate"; "LV1"; "VG"; "50"];
2155        ["lvcreate"; "LV2"; "VG"; "50"];
2156        ["lvremove"; "/dev/VG"];
2157        ["vgs"]], ["VG"])],
2158    "remove an LVM logical volume",
2159    "\
2160 Remove an LVM logical volume C<device>, where C<device> is
2161 the path to the LV, such as C</dev/VG/LV>.
2162
2163 You can also remove all LVs in a volume group by specifying
2164 the VG name, C</dev/VG>.");
2165
2166   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2167    [InitEmpty, Always, TestOutputList (
2168       [["part_disk"; "/dev/sda"; "mbr"];
2169        ["pvcreate"; "/dev/sda1"];
2170        ["vgcreate"; "VG"; "/dev/sda1"];
2171        ["lvcreate"; "LV1"; "VG"; "50"];
2172        ["lvcreate"; "LV2"; "VG"; "50"];
2173        ["vgremove"; "VG"];
2174        ["lvs"]], []);
2175     InitEmpty, Always, TestOutputList (
2176       [["part_disk"; "/dev/sda"; "mbr"];
2177        ["pvcreate"; "/dev/sda1"];
2178        ["vgcreate"; "VG"; "/dev/sda1"];
2179        ["lvcreate"; "LV1"; "VG"; "50"];
2180        ["lvcreate"; "LV2"; "VG"; "50"];
2181        ["vgremove"; "VG"];
2182        ["vgs"]], [])],
2183    "remove an LVM volume group",
2184    "\
2185 Remove an LVM volume group C<vgname>, (for example C<VG>).
2186
2187 This also forcibly removes all logical volumes in the volume
2188 group (if any).");
2189
2190   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2191    [InitEmpty, Always, TestOutputListOfDevices (
2192       [["part_disk"; "/dev/sda"; "mbr"];
2193        ["pvcreate"; "/dev/sda1"];
2194        ["vgcreate"; "VG"; "/dev/sda1"];
2195        ["lvcreate"; "LV1"; "VG"; "50"];
2196        ["lvcreate"; "LV2"; "VG"; "50"];
2197        ["vgremove"; "VG"];
2198        ["pvremove"; "/dev/sda1"];
2199        ["lvs"]], []);
2200     InitEmpty, Always, TestOutputListOfDevices (
2201       [["part_disk"; "/dev/sda"; "mbr"];
2202        ["pvcreate"; "/dev/sda1"];
2203        ["vgcreate"; "VG"; "/dev/sda1"];
2204        ["lvcreate"; "LV1"; "VG"; "50"];
2205        ["lvcreate"; "LV2"; "VG"; "50"];
2206        ["vgremove"; "VG"];
2207        ["pvremove"; "/dev/sda1"];
2208        ["vgs"]], []);
2209     InitEmpty, Always, TestOutputListOfDevices (
2210       [["part_disk"; "/dev/sda"; "mbr"];
2211        ["pvcreate"; "/dev/sda1"];
2212        ["vgcreate"; "VG"; "/dev/sda1"];
2213        ["lvcreate"; "LV1"; "VG"; "50"];
2214        ["lvcreate"; "LV2"; "VG"; "50"];
2215        ["vgremove"; "VG"];
2216        ["pvremove"; "/dev/sda1"];
2217        ["pvs"]], [])],
2218    "remove an LVM physical volume",
2219    "\
2220 This wipes a physical volume C<device> so that LVM will no longer
2221 recognise it.
2222
2223 The implementation uses the C<pvremove> command which refuses to
2224 wipe physical volumes that contain any volume groups, so you have
2225 to remove those first.");
2226
2227   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2228    [InitBasicFS, Always, TestOutput (
2229       [["set_e2label"; "/dev/sda1"; "testlabel"];
2230        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2231    "set the ext2/3/4 filesystem label",
2232    "\
2233 This sets the ext2/3/4 filesystem label of the filesystem on
2234 C<device> to C<label>.  Filesystem labels are limited to
2235 16 characters.
2236
2237 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2238 to return the existing label on a filesystem.");
2239
2240   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2241    [],
2242    "get the ext2/3/4 filesystem label",
2243    "\
2244 This returns the ext2/3/4 filesystem label of the filesystem on
2245 C<device>.");
2246
2247   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2248    (let uuid = uuidgen () in
2249     [InitBasicFS, Always, TestOutput (
2250        [["set_e2uuid"; "/dev/sda1"; uuid];
2251         ["get_e2uuid"; "/dev/sda1"]], uuid);
2252      InitBasicFS, Always, TestOutput (
2253        [["set_e2uuid"; "/dev/sda1"; "clear"];
2254         ["get_e2uuid"; "/dev/sda1"]], "");
2255      (* We can't predict what UUIDs will be, so just check the commands run. *)
2256      InitBasicFS, Always, TestRun (
2257        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2258      InitBasicFS, Always, TestRun (
2259        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2260    "set the ext2/3/4 filesystem UUID",
2261    "\
2262 This sets the ext2/3/4 filesystem UUID of the filesystem on
2263 C<device> to C<uuid>.  The format of the UUID and alternatives
2264 such as C<clear>, C<random> and C<time> are described in the
2265 L<tune2fs(8)> manpage.
2266
2267 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2268 to return the existing UUID of a filesystem.");
2269
2270   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2271    [],
2272    "get the ext2/3/4 filesystem UUID",
2273    "\
2274 This returns the ext2/3/4 filesystem UUID of the filesystem on
2275 C<device>.");
2276
2277   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [FishOutput FishOutputHexadecimal],
2278    [InitBasicFS, Always, TestOutputInt (
2279       [["umount"; "/dev/sda1"];
2280        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2281     InitBasicFS, Always, TestOutputInt (
2282       [["umount"; "/dev/sda1"];
2283        ["zero"; "/dev/sda1"];
2284        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2285    "run the filesystem checker",
2286    "\
2287 This runs the filesystem checker (fsck) on C<device> which
2288 should have filesystem type C<fstype>.
2289
2290 The returned integer is the status.  See L<fsck(8)> for the
2291 list of status codes from C<fsck>.
2292
2293 Notes:
2294
2295 =over 4
2296
2297 =item *
2298
2299 Multiple status codes can be summed together.
2300
2301 =item *
2302
2303 A non-zero return code can mean \"success\", for example if
2304 errors have been corrected on the filesystem.
2305
2306 =item *
2307
2308 Checking or repairing NTFS volumes is not supported
2309 (by linux-ntfs).
2310
2311 =back
2312
2313 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2314
2315   ("zero", (RErr, [Device "device"]), 85, [],
2316    [InitBasicFS, Always, TestOutput (
2317       [["umount"; "/dev/sda1"];
2318        ["zero"; "/dev/sda1"];
2319        ["file"; "/dev/sda1"]], "data")],
2320    "write zeroes to the device",
2321    "\
2322 This command writes zeroes over the first few blocks of C<device>.
2323
2324 How many blocks are zeroed isn't specified (but it's I<not> enough
2325 to securely wipe the device).  It should be sufficient to remove
2326 any partition tables, filesystem superblocks and so on.
2327
2328 See also: C<guestfs_zero_device>, C<guestfs_scrub_device>.");
2329
2330   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2331    (* Test disabled because grub-install incompatible with virtio-blk driver.
2332     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2333     *)
2334    [InitBasicFS, Disabled, TestOutputTrue (
2335       [["grub_install"; "/"; "/dev/sda1"];
2336        ["is_dir"; "/boot"]])],
2337    "install GRUB",
2338    "\
2339 This command installs GRUB (the Grand Unified Bootloader) on
2340 C<device>, with the root directory being C<root>.");
2341
2342   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2343    [InitBasicFS, Always, TestOutput (
2344       [["write_file"; "/old"; "file content"; "0"];
2345        ["cp"; "/old"; "/new"];
2346        ["cat"; "/new"]], "file content");
2347     InitBasicFS, Always, TestOutputTrue (
2348       [["write_file"; "/old"; "file content"; "0"];
2349        ["cp"; "/old"; "/new"];
2350        ["is_file"; "/old"]]);
2351     InitBasicFS, Always, TestOutput (
2352       [["write_file"; "/old"; "file content"; "0"];
2353        ["mkdir"; "/dir"];
2354        ["cp"; "/old"; "/dir/new"];
2355        ["cat"; "/dir/new"]], "file content")],
2356    "copy a file",
2357    "\
2358 This copies a file from C<src> to C<dest> where C<dest> is
2359 either a destination filename or destination directory.");
2360
2361   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2362    [InitBasicFS, Always, TestOutput (
2363       [["mkdir"; "/olddir"];
2364        ["mkdir"; "/newdir"];
2365        ["write_file"; "/olddir/file"; "file content"; "0"];
2366        ["cp_a"; "/olddir"; "/newdir"];
2367        ["cat"; "/newdir/olddir/file"]], "file content")],
2368    "copy a file or directory recursively",
2369    "\
2370 This copies a file or directory from C<src> to C<dest>
2371 recursively using the C<cp -a> command.");
2372
2373   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2374    [InitBasicFS, Always, TestOutput (
2375       [["write_file"; "/old"; "file content"; "0"];
2376        ["mv"; "/old"; "/new"];
2377        ["cat"; "/new"]], "file content");
2378     InitBasicFS, Always, TestOutputFalse (
2379       [["write_file"; "/old"; "file content"; "0"];
2380        ["mv"; "/old"; "/new"];
2381        ["is_file"; "/old"]])],
2382    "move a file",
2383    "\
2384 This moves a file from C<src> to C<dest> where C<dest> is
2385 either a destination filename or destination directory.");
2386
2387   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2388    [InitEmpty, Always, TestRun (
2389       [["drop_caches"; "3"]])],
2390    "drop kernel page cache, dentries and inodes",
2391    "\
2392 This instructs the guest kernel to drop its page cache,
2393 and/or dentries and inode caches.  The parameter C<whattodrop>
2394 tells the kernel what precisely to drop, see
2395 L<http://linux-mm.org/Drop_Caches>
2396
2397 Setting C<whattodrop> to 3 should drop everything.
2398
2399 This automatically calls L<sync(2)> before the operation,
2400 so that the maximum guest memory is freed.");
2401
2402   ("dmesg", (RString "kmsgs", []), 91, [],
2403    [InitEmpty, Always, TestRun (
2404       [["dmesg"]])],
2405    "return kernel messages",
2406    "\
2407 This returns the kernel messages (C<dmesg> output) from
2408 the guest kernel.  This is sometimes useful for extended
2409 debugging of problems.
2410
2411 Another way to get the same information is to enable
2412 verbose messages with C<guestfs_set_verbose> or by setting
2413 the environment variable C<LIBGUESTFS_DEBUG=1> before
2414 running the program.");
2415
2416   ("ping_daemon", (RErr, []), 92, [],
2417    [InitEmpty, Always, TestRun (
2418       [["ping_daemon"]])],
2419    "ping the guest daemon",
2420    "\
2421 This is a test probe into the guestfs daemon running inside
2422 the qemu subprocess.  Calling this function checks that the
2423 daemon responds to the ping message, without affecting the daemon
2424 or attached block device(s) in any other way.");
2425
2426   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2427    [InitBasicFS, Always, TestOutputTrue (
2428       [["write_file"; "/file1"; "contents of a file"; "0"];
2429        ["cp"; "/file1"; "/file2"];
2430        ["equal"; "/file1"; "/file2"]]);
2431     InitBasicFS, Always, TestOutputFalse (
2432       [["write_file"; "/file1"; "contents of a file"; "0"];
2433        ["write_file"; "/file2"; "contents of another file"; "0"];
2434        ["equal"; "/file1"; "/file2"]]);
2435     InitBasicFS, Always, TestLastFail (
2436       [["equal"; "/file1"; "/file2"]])],
2437    "test if two files have equal contents",
2438    "\
2439 This compares the two files C<file1> and C<file2> and returns
2440 true if their content is exactly equal, or false otherwise.
2441
2442 The external L<cmp(1)> program is used for the comparison.");
2443
2444   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2445    [InitISOFS, Always, TestOutputList (
2446       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2447     InitISOFS, Always, TestOutputList (
2448       [["strings"; "/empty"]], []);
2449     (* Test for RHBZ#579608, absolute symbolic links. *)
2450     InitISOFS, Always, TestRun (
2451       [["strings"; "/abssymlink"]])],
2452    "print the printable strings in a file",
2453    "\
2454 This runs the L<strings(1)> command on a file and returns
2455 the list of printable strings found.");
2456
2457   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2458    [InitISOFS, Always, TestOutputList (
2459       [["strings_e"; "b"; "/known-5"]], []);
2460     InitBasicFS, Disabled, TestOutputList (
2461       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2462        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2463    "print the printable strings in a file",
2464    "\
2465 This is like the C<guestfs_strings> command, but allows you to
2466 specify the encoding.
2467
2468 See the L<strings(1)> manpage for the full list of encodings.
2469
2470 Commonly useful encodings are C<l> (lower case L) which will
2471 show strings inside Windows/x86 files.
2472
2473 The returned strings are transcoded to UTF-8.");
2474
2475   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2476    [InitISOFS, Always, TestOutput (
2477       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2478     (* Test for RHBZ#501888c2 regression which caused large hexdump
2479      * commands to segfault.
2480      *)
2481     InitISOFS, Always, TestRun (
2482       [["hexdump"; "/100krandom"]]);
2483     (* Test for RHBZ#579608, absolute symbolic links. *)
2484     InitISOFS, Always, TestRun (
2485       [["hexdump"; "/abssymlink"]])],
2486    "dump a file in hexadecimal",
2487    "\
2488 This runs C<hexdump -C> on the given C<path>.  The result is
2489 the human-readable, canonical hex dump of the file.");
2490
2491   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2492    [InitNone, Always, TestOutput (
2493       [["part_disk"; "/dev/sda"; "mbr"];
2494        ["mkfs"; "ext3"; "/dev/sda1"];
2495        ["mount_options"; ""; "/dev/sda1"; "/"];
2496        ["write_file"; "/new"; "test file"; "0"];
2497        ["umount"; "/dev/sda1"];
2498        ["zerofree"; "/dev/sda1"];
2499        ["mount_options"; ""; "/dev/sda1"; "/"];
2500        ["cat"; "/new"]], "test file")],
2501    "zero unused inodes and disk blocks on ext2/3 filesystem",
2502    "\
2503 This runs the I<zerofree> program on C<device>.  This program
2504 claims to zero unused inodes and disk blocks on an ext2/3
2505 filesystem, thus making it possible to compress the filesystem
2506 more effectively.
2507
2508 You should B<not> run this program if the filesystem is
2509 mounted.
2510
2511 It is possible that using this program can damage the filesystem
2512 or data on the filesystem.");
2513
2514   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2515    [],
2516    "resize an LVM physical volume",
2517    "\
2518 This resizes (expands or shrinks) an existing LVM physical
2519 volume to match the new size of the underlying device.");
2520
2521   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2522                        Int "cyls"; Int "heads"; Int "sectors";
2523                        String "line"]), 99, [DangerWillRobinson],
2524    [],
2525    "modify a single partition on a block device",
2526    "\
2527 This runs L<sfdisk(8)> option to modify just the single
2528 partition C<n> (note: C<n> counts from 1).
2529
2530 For other parameters, see C<guestfs_sfdisk>.  You should usually
2531 pass C<0> for the cyls/heads/sectors parameters.
2532
2533 See also: C<guestfs_part_add>");
2534
2535   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2536    [],
2537    "display the partition table",
2538    "\
2539 This displays the partition table on C<device>, in the
2540 human-readable output of the L<sfdisk(8)> command.  It is
2541 not intended to be parsed.
2542
2543 See also: C<guestfs_part_list>");
2544
2545   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2546    [],
2547    "display the kernel geometry",
2548    "\
2549 This displays the kernel's idea of the geometry of C<device>.
2550
2551 The result is in human-readable format, and not designed to
2552 be parsed.");
2553
2554   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2555    [],
2556    "display the disk geometry from the partition table",
2557    "\
2558 This displays the disk geometry of C<device> read from the
2559 partition table.  Especially in the case where the underlying
2560 block device has been resized, this can be different from the
2561 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2562
2563 The result is in human-readable format, and not designed to
2564 be parsed.");
2565
2566   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2567    [],
2568    "activate or deactivate all volume groups",
2569    "\
2570 This command activates or (if C<activate> is false) deactivates
2571 all logical volumes in all volume groups.
2572 If activated, then they are made known to the
2573 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2574 then those devices disappear.
2575
2576 This command is the same as running C<vgchange -a y|n>");
2577
2578   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2579    [],
2580    "activate or deactivate some volume groups",
2581    "\
2582 This command activates or (if C<activate> is false) deactivates
2583 all logical volumes in the listed volume groups C<volgroups>.
2584 If activated, then they are made known to the
2585 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2586 then those devices disappear.
2587
2588 This command is the same as running C<vgchange -a y|n volgroups...>
2589
2590 Note that if C<volgroups> is an empty list then B<all> volume groups
2591 are activated or deactivated.");
2592
2593   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2594    [InitNone, Always, TestOutput (
2595       [["part_disk"; "/dev/sda"; "mbr"];
2596        ["pvcreate"; "/dev/sda1"];
2597        ["vgcreate"; "VG"; "/dev/sda1"];
2598        ["lvcreate"; "LV"; "VG"; "10"];
2599        ["mkfs"; "ext2"; "/dev/VG/LV"];
2600        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2601        ["write_file"; "/new"; "test content"; "0"];
2602        ["umount"; "/"];
2603        ["lvresize"; "/dev/VG/LV"; "20"];
2604        ["e2fsck_f"; "/dev/VG/LV"];
2605        ["resize2fs"; "/dev/VG/LV"];
2606        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2607        ["cat"; "/new"]], "test content");
2608     InitNone, Always, TestRun (
2609       (* Make an LV smaller to test RHBZ#587484. *)
2610       [["part_disk"; "/dev/sda"; "mbr"];
2611        ["pvcreate"; "/dev/sda1"];
2612        ["vgcreate"; "VG"; "/dev/sda1"];
2613        ["lvcreate"; "LV"; "VG"; "20"];
2614        ["lvresize"; "/dev/VG/LV"; "10"]])],
2615    "resize an LVM logical volume",
2616    "\
2617 This resizes (expands or shrinks) an existing LVM logical
2618 volume to C<mbytes>.  When reducing, data in the reduced part
2619 is lost.");
2620
2621   ("resize2fs", (RErr, [Device "device"]), 106, [],
2622    [], (* lvresize tests this *)
2623    "resize an ext2/ext3 filesystem",
2624    "\
2625 This resizes an ext2 or ext3 filesystem to match the size of
2626 the underlying device.
2627
2628 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2629 on the C<device> before calling this command.  For unknown reasons
2630 C<resize2fs> sometimes gives an error about this and sometimes not.
2631 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2632 calling this function.");
2633
2634   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2635    [InitBasicFS, Always, TestOutputList (
2636       [["find"; "/"]], ["lost+found"]);
2637     InitBasicFS, Always, TestOutputList (
2638       [["touch"; "/a"];
2639        ["mkdir"; "/b"];
2640        ["touch"; "/b/c"];
2641        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2642     InitBasicFS, Always, TestOutputList (
2643       [["mkdir_p"; "/a/b/c"];
2644        ["touch"; "/a/b/c/d"];
2645        ["find"; "/a/b/"]], ["c"; "c/d"])],
2646    "find all files and directories",
2647    "\
2648 This command lists out all files and directories, recursively,
2649 starting at C<directory>.  It is essentially equivalent to
2650 running the shell command C<find directory -print> but some
2651 post-processing happens on the output, described below.
2652
2653 This returns a list of strings I<without any prefix>.  Thus
2654 if the directory structure was:
2655
2656  /tmp/a
2657  /tmp/b
2658  /tmp/c/d
2659
2660 then the returned list from C<guestfs_find> C</tmp> would be
2661 4 elements:
2662
2663  a
2664  b
2665  c
2666  c/d
2667
2668 If C<directory> is not a directory, then this command returns
2669 an error.
2670
2671 The returned list is sorted.
2672
2673 See also C<guestfs_find0>.");
2674
2675   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2676    [], (* lvresize tests this *)
2677    "check an ext2/ext3 filesystem",
2678    "\
2679 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2680 filesystem checker on C<device>, noninteractively (C<-p>),
2681 even if the filesystem appears to be clean (C<-f>).
2682
2683 This command is only needed because of C<guestfs_resize2fs>
2684 (q.v.).  Normally you should use C<guestfs_fsck>.");
2685
2686   ("sleep", (RErr, [Int "secs"]), 109, [],
2687    [InitNone, Always, TestRun (
2688       [["sleep"; "1"]])],
2689    "sleep for some seconds",
2690    "\
2691 Sleep for C<secs> seconds.");
2692
2693   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2694    [InitNone, Always, TestOutputInt (
2695       [["part_disk"; "/dev/sda"; "mbr"];
2696        ["mkfs"; "ntfs"; "/dev/sda1"];
2697        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2698     InitNone, Always, TestOutputInt (
2699       [["part_disk"; "/dev/sda"; "mbr"];
2700        ["mkfs"; "ext2"; "/dev/sda1"];
2701        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2702    "probe NTFS volume",
2703    "\
2704 This command runs the L<ntfs-3g.probe(8)> command which probes
2705 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2706 be mounted read-write, and some cannot be mounted at all).
2707
2708 C<rw> is a boolean flag.  Set it to true if you want to test
2709 if the volume can be mounted read-write.  Set it to false if
2710 you want to test if the volume can be mounted read-only.
2711
2712 The return value is an integer which C<0> if the operation
2713 would succeed, or some non-zero value documented in the
2714 L<ntfs-3g.probe(8)> manual page.");
2715
2716   ("sh", (RString "output", [String "command"]), 111, [],
2717    [], (* XXX needs tests *)
2718    "run a command via the shell",
2719    "\
2720 This call runs a command from the guest filesystem via the
2721 guest's C</bin/sh>.
2722
2723 This is like C<guestfs_command>, but passes the command to:
2724
2725  /bin/sh -c \"command\"
2726
2727 Depending on the guest's shell, this usually results in
2728 wildcards being expanded, shell expressions being interpolated
2729 and so on.
2730
2731 All the provisos about C<guestfs_command> apply to this call.");
2732
2733   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2734    [], (* XXX needs tests *)
2735    "run a command via the shell returning lines",
2736    "\
2737 This is the same as C<guestfs_sh>, but splits the result
2738 into a list of lines.
2739
2740 See also: C<guestfs_command_lines>");
2741
2742   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2743    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2744     * code in stubs.c, since all valid glob patterns must start with "/".
2745     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2746     *)
2747    [InitBasicFS, Always, TestOutputList (
2748       [["mkdir_p"; "/a/b/c"];
2749        ["touch"; "/a/b/c/d"];
2750        ["touch"; "/a/b/c/e"];
2751        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2752     InitBasicFS, Always, TestOutputList (
2753       [["mkdir_p"; "/a/b/c"];
2754        ["touch"; "/a/b/c/d"];
2755        ["touch"; "/a/b/c/e"];
2756        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2757     InitBasicFS, Always, TestOutputList (
2758       [["mkdir_p"; "/a/b/c"];
2759        ["touch"; "/a/b/c/d"];
2760        ["touch"; "/a/b/c/e"];
2761        ["glob_expand"; "/a/*/x/*"]], [])],
2762    "expand a wildcard path",
2763    "\
2764 This command searches for all the pathnames matching
2765 C<pattern> according to the wildcard expansion rules
2766 used by the shell.
2767
2768 If no paths match, then this returns an empty list
2769 (note: not an error).
2770
2771 It is just a wrapper around the C L<glob(3)> function
2772 with flags C<GLOB_MARK|GLOB_BRACE>.
2773 See that manual page for more details.");
2774
2775   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2776    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2777       [["scrub_device"; "/dev/sdc"]])],
2778    "scrub (securely wipe) a device",
2779    "\
2780 This command writes patterns over C<device> to make data retrieval
2781 more difficult.
2782
2783 It is an interface to the L<scrub(1)> program.  See that
2784 manual page for more details.");
2785
2786   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2787    [InitBasicFS, Always, TestRun (
2788       [["write_file"; "/file"; "content"; "0"];
2789        ["scrub_file"; "/file"]])],
2790    "scrub (securely wipe) a file",
2791    "\
2792 This command writes patterns over a file to make data retrieval
2793 more difficult.
2794
2795 The file is I<removed> after scrubbing.
2796
2797 It is an interface to the L<scrub(1)> program.  See that
2798 manual page for more details.");
2799
2800   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2801    [], (* XXX needs testing *)
2802    "scrub (securely wipe) free space",
2803    "\
2804 This command creates the directory C<dir> and then fills it
2805 with files until the filesystem is full, and scrubs the files
2806 as for C<guestfs_scrub_file>, and deletes them.
2807 The intention is to scrub any free space on the partition
2808 containing C<dir>.
2809
2810 It is an interface to the L<scrub(1)> program.  See that
2811 manual page for more details.");
2812
2813   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2814    [InitBasicFS, Always, TestRun (
2815       [["mkdir"; "/tmp"];
2816        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2817    "create a temporary directory",
2818    "\
2819 This command creates a temporary directory.  The
2820 C<template> parameter should be a full pathname for the
2821 temporary directory name with the final six characters being
2822 \"XXXXXX\".
2823
2824 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2825 the second one being suitable for Windows filesystems.
2826
2827 The name of the temporary directory that was created
2828 is returned.
2829
2830 The temporary directory is created with mode 0700
2831 and is owned by root.
2832
2833 The caller is responsible for deleting the temporary
2834 directory and its contents after use.
2835
2836 See also: L<mkdtemp(3)>");
2837
2838   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2839    [InitISOFS, Always, TestOutputInt (
2840       [["wc_l"; "/10klines"]], 10000);
2841     (* Test for RHBZ#579608, absolute symbolic links. *)
2842     InitISOFS, Always, TestOutputInt (
2843       [["wc_l"; "/abssymlink"]], 10000)],
2844    "count lines in a file",
2845    "\
2846 This command counts the lines in a file, using the
2847 C<wc -l> external command.");
2848
2849   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2850    [InitISOFS, Always, TestOutputInt (
2851       [["wc_w"; "/10klines"]], 10000)],
2852    "count words in a file",
2853    "\
2854 This command counts the words in a file, using the
2855 C<wc -w> external command.");
2856
2857   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2858    [InitISOFS, Always, TestOutputInt (
2859       [["wc_c"; "/100kallspaces"]], 102400)],
2860    "count characters in a file",
2861    "\
2862 This command counts the characters in a file, using the
2863 C<wc -c> external command.");
2864
2865   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2866    [InitISOFS, Always, TestOutputList (
2867       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"]);
2868     (* Test for RHBZ#579608, absolute symbolic links. *)
2869     InitISOFS, Always, TestOutputList (
2870       [["head"; "/abssymlink"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2871    "return first 10 lines of a file",
2872    "\
2873 This command returns up to the first 10 lines of a file as
2874 a list of strings.");
2875
2876   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2877    [InitISOFS, Always, TestOutputList (
2878       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2879     InitISOFS, Always, TestOutputList (
2880       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2881     InitISOFS, Always, TestOutputList (
2882       [["head_n"; "0"; "/10klines"]], [])],
2883    "return first N lines of a file",
2884    "\
2885 If the parameter C<nrlines> is a positive number, this returns the first
2886 C<nrlines> lines of the file C<path>.
2887
2888 If the parameter C<nrlines> is a negative number, this returns lines
2889 from the file C<path>, excluding the last C<nrlines> lines.
2890
2891 If the parameter C<nrlines> is zero, this returns an empty list.");
2892
2893   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2894    [InitISOFS, Always, TestOutputList (
2895       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2896    "return last 10 lines of a file",
2897    "\
2898 This command returns up to the last 10 lines of a file as
2899 a list of strings.");
2900
2901   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2902    [InitISOFS, Always, TestOutputList (
2903       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2904     InitISOFS, Always, TestOutputList (
2905       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2906     InitISOFS, Always, TestOutputList (
2907       [["tail_n"; "0"; "/10klines"]], [])],
2908    "return last N lines of a file",
2909    "\
2910 If the parameter C<nrlines> is a positive number, this returns the last
2911 C<nrlines> lines of the file C<path>.
2912
2913 If the parameter C<nrlines> is a negative number, this returns lines
2914 from the file C<path>, starting with the C<-nrlines>th line.
2915
2916 If the parameter C<nrlines> is zero, this returns an empty list.");
2917
2918   ("df", (RString "output", []), 125, [],
2919    [], (* XXX Tricky to test because it depends on the exact format
2920         * of the 'df' command and other imponderables.
2921         *)
2922    "report file system disk space usage",
2923    "\
2924 This command runs the C<df> command to report disk space used.
2925
2926 This command is mostly useful for interactive sessions.  It
2927 is I<not> intended that you try to parse the output string.
2928 Use C<statvfs> from programs.");
2929
2930   ("df_h", (RString "output", []), 126, [],
2931    [], (* XXX Tricky to test because it depends on the exact format
2932         * of the 'df' command and other imponderables.
2933         *)
2934    "report file system disk space usage (human readable)",
2935    "\
2936 This command runs the C<df -h> command to report disk space used
2937 in human-readable format.
2938
2939 This command is mostly useful for interactive sessions.  It
2940 is I<not> intended that you try to parse the output string.
2941 Use C<statvfs> from programs.");
2942
2943   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2944    [InitISOFS, Always, TestOutputInt (
2945       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2946    "estimate file space usage",
2947    "\
2948 This command runs the C<du -s> command to estimate file space
2949 usage for C<path>.
2950
2951 C<path> can be a file or a directory.  If C<path> is a directory
2952 then the estimate includes the contents of the directory and all
2953 subdirectories (recursively).
2954
2955 The result is the estimated size in I<kilobytes>
2956 (ie. units of 1024 bytes).");
2957
2958   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2959    [InitISOFS, Always, TestOutputList (
2960       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2961    "list files in an initrd",
2962    "\
2963 This command lists out files contained in an initrd.
2964
2965 The files are listed without any initial C</> character.  The
2966 files are listed in the order they appear (not necessarily
2967 alphabetical).  Directory names are listed as separate items.
2968
2969 Old Linux kernels (2.4 and earlier) used a compressed ext2
2970 filesystem as initrd.  We I<only> support the newer initramfs
2971 format (compressed cpio files).");
2972
2973   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2974    [],
2975    "mount a file using the loop device",
2976    "\
2977 This command lets you mount C<file> (a filesystem image
2978 in a file) on a mount point.  It is entirely equivalent to
2979 the command C<mount -o loop file mountpoint>.");
2980
2981   ("mkswap", (RErr, [Device "device"]), 130, [],
2982    [InitEmpty, Always, TestRun (
2983       [["part_disk"; "/dev/sda"; "mbr"];
2984        ["mkswap"; "/dev/sda1"]])],
2985    "create a swap partition",
2986    "\
2987 Create a swap partition on C<device>.");
2988
2989   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2990    [InitEmpty, Always, TestRun (
2991       [["part_disk"; "/dev/sda"; "mbr"];
2992        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2993    "create a swap partition with a label",
2994    "\
2995 Create a swap partition on C<device> with label C<label>.
2996
2997 Note that you cannot attach a swap label to a block device
2998 (eg. C</dev/sda>), just to a partition.  This appears to be
2999 a limitation of the kernel or swap tools.");
3000
3001   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
3002    (let uuid = uuidgen () in
3003     [InitEmpty, Always, TestRun (
3004        [["part_disk"; "/dev/sda"; "mbr"];
3005         ["mkswap_U"; uuid; "/dev/sda1"]])]),
3006    "create a swap partition with an explicit UUID",
3007    "\
3008 Create a swap partition on C<device> with UUID C<uuid>.");
3009
3010   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
3011    [InitBasicFS, Always, TestOutputStruct (
3012       [["mknod"; "0o10777"; "0"; "0"; "/node"];
3013        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
3014        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
3015     InitBasicFS, Always, TestOutputStruct (
3016       [["mknod"; "0o60777"; "66"; "99"; "/node"];
3017        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3018    "make block, character or FIFO devices",
3019    "\
3020 This call creates block or character special devices, or
3021 named pipes (FIFOs).
3022
3023 The C<mode> parameter should be the mode, using the standard
3024 constants.  C<devmajor> and C<devminor> are the
3025 device major and minor numbers, only used when creating block
3026 and character special devices.
3027
3028 Note that, just like L<mknod(2)>, the mode must be bitwise
3029 OR'd with S_IFBLK, S_IFCHR, S_IFIFO or S_IFSOCK (otherwise this call
3030 just creates a regular file).  These constants are
3031 available in the standard Linux header files, or you can use
3032 C<guestfs_mknod_b>, C<guestfs_mknod_c> or C<guestfs_mkfifo>
3033 which are wrappers around this command which bitwise OR
3034 in the appropriate constant for you.
3035
3036 The mode actually set is affected by the umask.");
3037
3038   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
3039    [InitBasicFS, Always, TestOutputStruct (
3040       [["mkfifo"; "0o777"; "/node"];
3041        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
3042    "make FIFO (named pipe)",
3043    "\
3044 This call creates a FIFO (named pipe) called C<path> with
3045 mode C<mode>.  It is just a convenient wrapper around
3046 C<guestfs_mknod>.
3047
3048 The mode actually set is affected by the umask.");
3049
3050   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
3051    [InitBasicFS, Always, TestOutputStruct (
3052       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
3053        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3054    "make block device node",
3055    "\
3056 This call creates a block device node called C<path> with
3057 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3058 It is just a convenient wrapper around C<guestfs_mknod>.
3059
3060 The mode actually set is affected by the umask.");
3061
3062   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
3063    [InitBasicFS, Always, TestOutputStruct (
3064       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
3065        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
3066    "make char device node",
3067    "\
3068 This call creates a char device node called C<path> with
3069 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3070 It is just a convenient wrapper around C<guestfs_mknod>.
3071
3072 The mode actually set is affected by the umask.");
3073
3074   ("umask", (RInt "oldmask", [Int "mask"]), 137, [FishOutput FishOutputOctal],
3075    [InitEmpty, Always, TestOutputInt (
3076       [["umask"; "0o22"]], 0o22)],
3077    "set file mode creation mask (umask)",
3078    "\
3079 This function sets the mask used for creating new files and
3080 device nodes to C<mask & 0777>.
3081
3082 Typical umask values would be C<022> which creates new files
3083 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
3084 C<002> which creates new files with permissions like
3085 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
3086
3087 The default umask is C<022>.  This is important because it
3088 means that directories and device nodes will be created with
3089 C<0644> or C<0755> mode even if you specify C<0777>.
3090
3091 See also C<guestfs_get_umask>,
3092 L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
3093
3094 This call returns the previous umask.");
3095
3096   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
3097    [],
3098    "read directories entries",
3099    "\
3100 This returns the list of directory entries in directory C<dir>.
3101
3102 All entries in the directory are returned, including C<.> and
3103 C<..>.  The entries are I<not> sorted, but returned in the same
3104 order as the underlying filesystem.
3105
3106 Also this call returns basic file type information about each
3107 file.  The C<ftyp> field will contain one of the following characters:
3108
3109 =over 4
3110
3111 =item 'b'
3112
3113 Block special
3114
3115 =item 'c'
3116
3117 Char special
3118
3119 =item 'd'
3120
3121 Directory
3122
3123 =item 'f'
3124
3125 FIFO (named pipe)
3126
3127 =item 'l'
3128
3129 Symbolic link
3130
3131 =item 'r'
3132
3133 Regular file
3134
3135 =item 's'
3136
3137 Socket
3138
3139 =item 'u'
3140
3141 Unknown file type
3142
3143 =item '?'
3144
3145 The L<readdir(3)> returned a C<d_type> field with an
3146 unexpected value
3147
3148 =back
3149
3150 This function is primarily intended for use by programs.  To
3151 get a simple list of names, use C<guestfs_ls>.  To get a printable
3152 directory for human consumption, use C<guestfs_ll>.");
3153
3154   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3155    [],
3156    "create partitions on a block device",
3157    "\
3158 This is a simplified interface to the C<guestfs_sfdisk>
3159 command, where partition sizes are specified in megabytes
3160 only (rounded to the nearest cylinder) and you don't need
3161 to specify the cyls, heads and sectors parameters which
3162 were rarely if ever used anyway.
3163
3164 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3165 and C<guestfs_part_disk>");
3166
3167   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3168    [],
3169    "determine file type inside a compressed file",
3170    "\
3171 This command runs C<file> after first decompressing C<path>
3172 using C<method>.
3173
3174 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3175
3176 Since 1.0.63, use C<guestfs_file> instead which can now
3177 process compressed files.");
3178
3179   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3180    [],
3181    "list extended attributes of a file or directory",
3182    "\
3183 This call lists the extended attributes of the file or directory
3184 C<path>.
3185
3186 At the system call level, this is a combination of the
3187 L<listxattr(2)> and L<getxattr(2)> calls.
3188
3189 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3190
3191   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3192    [],
3193    "list extended attributes of a file or directory",
3194    "\
3195 This is the same as C<guestfs_getxattrs>, but if C<path>
3196 is a symbolic link, then it returns the extended attributes
3197 of the link itself.");
3198
3199   ("setxattr", (RErr, [String "xattr";
3200                        String "val"; Int "vallen"; (* will be BufferIn *)
3201                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3202    [],
3203    "set extended attribute of a file or directory",
3204    "\
3205 This call sets the extended attribute named C<xattr>
3206 of the file C<path> to the value C<val> (of length C<vallen>).
3207 The value is arbitrary 8 bit data.
3208
3209 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3210
3211   ("lsetxattr", (RErr, [String "xattr";
3212                         String "val"; Int "vallen"; (* will be BufferIn *)
3213                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3214    [],
3215    "set extended attribute of a file or directory",
3216    "\
3217 This is the same as C<guestfs_setxattr>, but if C<path>
3218 is a symbolic link, then it sets an extended attribute
3219 of the link itself.");
3220
3221   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3222    [],
3223    "remove extended attribute of a file or directory",
3224    "\
3225 This call removes the extended attribute named C<xattr>
3226 of the file C<path>.
3227
3228 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3229
3230   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3231    [],
3232    "remove extended attribute of a file or directory",
3233    "\
3234 This is the same as C<guestfs_removexattr>, but if C<path>
3235 is a symbolic link, then it removes an extended attribute
3236 of the link itself.");
3237
3238   ("mountpoints", (RHashtable "mps", []), 147, [],
3239    [],
3240    "show mountpoints",
3241    "\
3242 This call is similar to C<guestfs_mounts>.  That call returns
3243 a list of devices.  This one returns a hash table (map) of
3244 device name to directory where the device is mounted.");
3245
3246   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3247    (* This is a special case: while you would expect a parameter
3248     * of type "Pathname", that doesn't work, because it implies
3249     * NEED_ROOT in the generated calling code in stubs.c, and
3250     * this function cannot use NEED_ROOT.
3251     *)
3252    [],
3253    "create a mountpoint",
3254    "\
3255 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3256 specialized calls that can be used to create extra mountpoints
3257 before mounting the first filesystem.
3258
3259 These calls are I<only> necessary in some very limited circumstances,
3260 mainly the case where you want to mount a mix of unrelated and/or
3261 read-only filesystems together.
3262
3263 For example, live CDs often contain a \"Russian doll\" nest of
3264 filesystems, an ISO outer layer, with a squashfs image inside, with
3265 an ext2/3 image inside that.  You can unpack this as follows
3266 in guestfish:
3267
3268  add-ro Fedora-11-i686-Live.iso
3269  run
3270  mkmountpoint /cd
3271  mkmountpoint /squash
3272  mkmountpoint /ext3
3273  mount /dev/sda /cd
3274  mount-loop /cd/LiveOS/squashfs.img /squash
3275  mount-loop /squash/LiveOS/ext3fs.img /ext3
3276
3277 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3278
3279   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3280    [],
3281    "remove a mountpoint",
3282    "\
3283 This calls removes a mountpoint that was previously created
3284 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3285 for full details.");
3286
3287   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3288    [InitISOFS, Always, TestOutputBuffer (
3289       [["read_file"; "/known-4"]], "abc\ndef\nghi");
3290     (* Test various near large, large and too large files (RHBZ#589039). *)
3291     InitBasicFS, Always, TestLastFail (
3292       [["touch"; "/a"];
3293        ["truncate_size"; "/a"; "4194303"]; (* GUESTFS_MESSAGE_MAX - 1 *)
3294        ["read_file"; "/a"]]);
3295     InitBasicFS, Always, TestLastFail (
3296       [["touch"; "/a"];
3297        ["truncate_size"; "/a"; "4194304"]; (* GUESTFS_MESSAGE_MAX *)
3298        ["read_file"; "/a"]]);
3299     InitBasicFS, Always, TestLastFail (
3300       [["touch"; "/a"];
3301        ["truncate_size"; "/a"; "41943040"]; (* GUESTFS_MESSAGE_MAX * 10 *)
3302        ["read_file"; "/a"]])],
3303    "read a file",
3304    "\
3305 This calls returns the contents of the file C<path> as a
3306 buffer.
3307
3308 Unlike C<guestfs_cat>, this function can correctly
3309 handle files that contain embedded ASCII NUL characters.
3310 However unlike C<guestfs_download>, this function is limited
3311 in the total size of file that can be handled.");
3312
3313   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3314    [InitISOFS, Always, TestOutputList (
3315       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3316     InitISOFS, Always, TestOutputList (
3317       [["grep"; "nomatch"; "/test-grep.txt"]], []);
3318     (* Test for RHBZ#579608, absolute symbolic links. *)
3319     InitISOFS, Always, TestOutputList (
3320       [["grep"; "nomatch"; "/abssymlink"]], [])],
3321    "return lines matching a pattern",
3322    "\
3323 This calls the external C<grep> program and returns the
3324 matching lines.");
3325
3326   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3327    [InitISOFS, Always, TestOutputList (
3328       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3329    "return lines matching a pattern",
3330    "\
3331 This calls the external C<egrep> program and returns the
3332 matching lines.");
3333
3334   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3335    [InitISOFS, Always, TestOutputList (
3336       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3337    "return lines matching a pattern",
3338    "\
3339 This calls the external C<fgrep> program and returns the
3340 matching lines.");
3341
3342   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3343    [InitISOFS, Always, TestOutputList (
3344       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3345    "return lines matching a pattern",
3346    "\
3347 This calls the external C<grep -i> program and returns the
3348 matching lines.");
3349
3350   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3351    [InitISOFS, Always, TestOutputList (
3352       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3353    "return lines matching a pattern",
3354    "\
3355 This calls the external C<egrep -i> program and returns the
3356 matching lines.");
3357
3358   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3359    [InitISOFS, Always, TestOutputList (
3360       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3361    "return lines matching a pattern",
3362    "\
3363 This calls the external C<fgrep -i> program and returns the
3364 matching lines.");
3365
3366   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3367    [InitISOFS, Always, TestOutputList (
3368       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3369    "return lines matching a pattern",
3370    "\
3371 This calls the external C<zgrep> program and returns the
3372 matching lines.");
3373
3374   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3375    [InitISOFS, Always, TestOutputList (
3376       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3377    "return lines matching a pattern",
3378    "\
3379 This calls the external C<zegrep> program and returns the
3380 matching lines.");
3381
3382   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3383    [InitISOFS, Always, TestOutputList (
3384       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3385    "return lines matching a pattern",
3386    "\
3387 This calls the external C<zfgrep> program and returns the
3388 matching lines.");
3389
3390   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3391    [InitISOFS, Always, TestOutputList (
3392       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3393    "return lines matching a pattern",
3394    "\
3395 This calls the external C<zgrep -i> program and returns the
3396 matching lines.");
3397
3398   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3399    [InitISOFS, Always, TestOutputList (
3400       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3401    "return lines matching a pattern",
3402    "\
3403 This calls the external C<zegrep -i> program and returns the
3404 matching lines.");
3405
3406   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3407    [InitISOFS, Always, TestOutputList (
3408       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3409    "return lines matching a pattern",
3410    "\
3411 This calls the external C<zfgrep -i> program and returns the
3412 matching lines.");
3413
3414   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3415    [InitISOFS, Always, TestOutput (
3416       [["realpath"; "/../directory"]], "/directory")],
3417    "canonicalized absolute pathname",
3418    "\
3419 Return the canonicalized absolute pathname of C<path>.  The
3420 returned path has no C<.>, C<..> or symbolic link path elements.");
3421
3422   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3423    [InitBasicFS, Always, TestOutputStruct (
3424       [["touch"; "/a"];
3425        ["ln"; "/a"; "/b"];
3426        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3427    "create a hard link",
3428    "\
3429 This command creates a hard link using the C<ln> command.");
3430
3431   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3432    [InitBasicFS, Always, TestOutputStruct (
3433       [["touch"; "/a"];
3434        ["touch"; "/b"];
3435        ["ln_f"; "/a"; "/b"];
3436        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3437    "create a hard link",
3438    "\
3439 This command creates a hard link using the C<ln -f> command.
3440 The C<-f> option removes the link (C<linkname>) if it exists already.");
3441
3442   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3443    [InitBasicFS, Always, TestOutputStruct (
3444       [["touch"; "/a"];
3445        ["ln_s"; "a"; "/b"];
3446        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3447    "create a symbolic link",
3448    "\
3449 This command creates a symbolic link using the C<ln -s> command.");
3450
3451   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3452    [InitBasicFS, Always, TestOutput (
3453       [["mkdir_p"; "/a/b"];
3454        ["touch"; "/a/b/c"];
3455        ["ln_sf"; "../d"; "/a/b/c"];
3456        ["readlink"; "/a/b/c"]], "../d")],
3457    "create a symbolic link",
3458    "\
3459 This command creates a symbolic link using the C<ln -sf> command,
3460 The C<-f> option removes the link (C<linkname>) if it exists already.");
3461
3462   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3463    [] (* XXX tested above *),
3464    "read the target of a symbolic link",
3465    "\
3466 This command reads the target of a symbolic link.");
3467
3468   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3469    [InitBasicFS, Always, TestOutputStruct (
3470       [["fallocate"; "/a"; "1000000"];
3471        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3472    "preallocate a file in the guest filesystem",
3473    "\
3474 This command preallocates a file (containing zero bytes) named
3475 C<path> of size C<len> bytes.  If the file exists already, it
3476 is overwritten.
3477
3478 Do not confuse this with the guestfish-specific
3479 C<alloc> command which allocates a file in the host and
3480 attaches it as a device.");
3481
3482   ("swapon_device", (RErr, [Device "device"]), 170, [],
3483    [InitPartition, Always, TestRun (
3484       [["mkswap"; "/dev/sda1"];
3485        ["swapon_device"; "/dev/sda1"];
3486        ["swapoff_device"; "/dev/sda1"]])],
3487    "enable swap on device",
3488    "\
3489 This command enables the libguestfs appliance to use the
3490 swap device or partition named C<device>.  The increased
3491 memory is made available for all commands, for example
3492 those run using C<guestfs_command> or C<guestfs_sh>.
3493
3494 Note that you should not swap to existing guest swap
3495 partitions unless you know what you are doing.  They may
3496 contain hibernation information, or other information that
3497 the guest doesn't want you to trash.  You also risk leaking
3498 information about the host to the guest this way.  Instead,
3499 attach a new host device to the guest and swap on that.");
3500
3501   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3502    [], (* XXX tested by swapon_device *)
3503    "disable swap on device",
3504    "\
3505 This command disables the libguestfs appliance swap
3506 device or partition named C<device>.
3507 See C<guestfs_swapon_device>.");
3508
3509   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3510    [InitBasicFS, Always, TestRun (
3511       [["fallocate"; "/swap"; "8388608"];
3512        ["mkswap_file"; "/swap"];
3513        ["swapon_file"; "/swap"];
3514        ["swapoff_file"; "/swap"]])],
3515    "enable swap on file",
3516    "\
3517 This command enables swap to a file.
3518 See C<guestfs_swapon_device> for other notes.");
3519
3520   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3521    [], (* XXX tested by swapon_file *)
3522    "disable swap on file",
3523    "\
3524 This command disables the libguestfs appliance swap on file.");
3525
3526   ("swapon_label", (RErr, [String "label"]), 174, [],
3527    [InitEmpty, Always, TestRun (
3528       [["part_disk"; "/dev/sdb"; "mbr"];
3529        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3530        ["swapon_label"; "swapit"];
3531        ["swapoff_label"; "swapit"];
3532        ["zero"; "/dev/sdb"];
3533        ["blockdev_rereadpt"; "/dev/sdb"]])],
3534    "enable swap on labeled swap partition",
3535    "\
3536 This command enables swap to a labeled swap partition.
3537 See C<guestfs_swapon_device> for other notes.");
3538
3539   ("swapoff_label", (RErr, [String "label"]), 175, [],
3540    [], (* XXX tested by swapon_label *)
3541    "disable swap on labeled swap partition",
3542    "\
3543 This command disables the libguestfs appliance swap on
3544 labeled swap partition.");
3545
3546   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3547    (let uuid = uuidgen () in
3548     [InitEmpty, Always, TestRun (
3549        [["mkswap_U"; uuid; "/dev/sdb"];
3550         ["swapon_uuid"; uuid];
3551         ["swapoff_uuid"; uuid]])]),
3552    "enable swap on swap partition by UUID",
3553    "\
3554 This command enables swap to a swap partition with the given UUID.
3555 See C<guestfs_swapon_device> for other notes.");
3556
3557   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3558    [], (* XXX tested by swapon_uuid *)
3559    "disable swap on swap partition by UUID",
3560    "\
3561 This command disables the libguestfs appliance swap partition
3562 with the given UUID.");
3563
3564   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3565    [InitBasicFS, Always, TestRun (
3566       [["fallocate"; "/swap"; "8388608"];
3567        ["mkswap_file"; "/swap"]])],
3568    "create a swap file",
3569    "\
3570 Create a swap file.
3571
3572 This command just writes a swap file signature to an existing
3573 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3574
3575   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3576    [InitISOFS, Always, TestRun (
3577       [["inotify_init"; "0"]])],
3578    "create an inotify handle",
3579    "\
3580 This command creates a new inotify handle.
3581 The inotify subsystem can be used to notify events which happen to
3582 objects in the guest filesystem.
3583
3584 C<maxevents> is the maximum number of events which will be
3585 queued up between calls to C<guestfs_inotify_read> or
3586 C<guestfs_inotify_files>.
3587 If this is passed as C<0>, then the kernel (or previously set)
3588 default is used.  For Linux 2.6.29 the default was 16384 events.
3589 Beyond this limit, the kernel throws away events, but records
3590 the fact that it threw them away by setting a flag
3591 C<IN_Q_OVERFLOW> in the returned structure list (see
3592 C<guestfs_inotify_read>).
3593
3594 Before any events are generated, you have to add some
3595 watches to the internal watch list.  See:
3596 C<guestfs_inotify_add_watch>,
3597 C<guestfs_inotify_rm_watch> and
3598 C<guestfs_inotify_watch_all>.
3599
3600 Queued up events should be read periodically by calling
3601 C<guestfs_inotify_read>
3602 (or C<guestfs_inotify_files> which is just a helpful
3603 wrapper around C<guestfs_inotify_read>).  If you don't
3604 read the events out often enough then you risk the internal
3605 queue overflowing.
3606
3607 The handle should be closed after use by calling
3608 C<guestfs_inotify_close>.  This also removes any
3609 watches automatically.
3610
3611 See also L<inotify(7)> for an overview of the inotify interface
3612 as exposed by the Linux kernel, which is roughly what we expose
3613 via libguestfs.  Note that there is one global inotify handle
3614 per libguestfs instance.");
3615
3616   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3617    [InitBasicFS, Always, TestOutputList (
3618       [["inotify_init"; "0"];
3619        ["inotify_add_watch"; "/"; "1073741823"];
3620        ["touch"; "/a"];
3621        ["touch"; "/b"];
3622        ["inotify_files"]], ["a"; "b"])],
3623    "add an inotify watch",
3624    "\
3625 Watch C<path> for the events listed in C<mask>.
3626
3627 Note that if C<path> is a directory then events within that
3628 directory are watched, but this does I<not> happen recursively
3629 (in subdirectories).
3630
3631 Note for non-C or non-Linux callers: the inotify events are
3632 defined by the Linux kernel ABI and are listed in
3633 C</usr/include/sys/inotify.h>.");
3634
3635   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3636    [],
3637    "remove an inotify watch",
3638    "\
3639 Remove a previously defined inotify watch.
3640 See C<guestfs_inotify_add_watch>.");
3641
3642   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3643    [],
3644    "return list of inotify events",
3645    "\
3646 Return the complete queue of events that have happened
3647 since the previous read call.
3648
3649 If no events have happened, this returns an empty list.
3650
3651 I<Note>: In order to make sure that all events have been
3652 read, you must call this function repeatedly until it
3653 returns an empty list.  The reason is that the call will
3654 read events up to the maximum appliance-to-host message
3655 size and leave remaining events in the queue.");
3656
3657   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3658    [],
3659    "return list of watched files that had events",
3660    "\
3661 This function is a helpful wrapper around C<guestfs_inotify_read>
3662 which just returns a list of pathnames of objects that were
3663 touched.  The returned pathnames are sorted and deduplicated.");
3664
3665   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3666    [],
3667    "close the inotify handle",
3668    "\
3669 This closes the inotify handle which was previously
3670 opened by inotify_init.  It removes all watches, throws
3671 away any pending events, and deallocates all resources.");
3672
3673   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3674    [],
3675    "set SELinux security context",
3676    "\
3677 This sets the SELinux security context of the daemon
3678 to the string C<context>.
3679
3680 See the documentation about SELINUX in L<guestfs(3)>.");
3681
3682   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3683    [],
3684    "get SELinux security context",
3685    "\
3686 This gets the SELinux security context of the daemon.
3687
3688 See the documentation about SELINUX in L<guestfs(3)>,
3689 and C<guestfs_setcon>");
3690
3691   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3692    [InitEmpty, Always, TestOutput (
3693       [["part_disk"; "/dev/sda"; "mbr"];
3694        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3695        ["mount_options"; ""; "/dev/sda1"; "/"];
3696        ["write_file"; "/new"; "new file contents"; "0"];
3697        ["cat"; "/new"]], "new file contents")],
3698    "make a filesystem with block size",
3699    "\
3700 This call is similar to C<guestfs_mkfs>, but it allows you to
3701 control the block size of the resulting filesystem.  Supported
3702 block sizes depend on the filesystem type, but typically they
3703 are C<1024>, C<2048> or C<4096> only.");
3704
3705   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3706    [InitEmpty, Always, TestOutput (
3707       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3708        ["mke2journal"; "4096"; "/dev/sda1"];
3709        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3710        ["mount_options"; ""; "/dev/sda2"; "/"];
3711        ["write_file"; "/new"; "new file contents"; "0"];
3712        ["cat"; "/new"]], "new file contents")],
3713    "make ext2/3/4 external journal",
3714    "\
3715 This creates an ext2 external journal on C<device>.  It is equivalent
3716 to the command:
3717
3718  mke2fs -O journal_dev -b blocksize device");
3719
3720   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3721    [InitEmpty, Always, TestOutput (
3722       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3723        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3724        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3725        ["mount_options"; ""; "/dev/sda2"; "/"];
3726        ["write_file"; "/new"; "new file contents"; "0"];
3727        ["cat"; "/new"]], "new file contents")],
3728    "make ext2/3/4 external journal with label",
3729    "\
3730 This creates an ext2 external journal on C<device> with label C<label>.");
3731
3732   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3733    (let uuid = uuidgen () in
3734     [InitEmpty, Always, TestOutput (
3735        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3736         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3737         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3738         ["mount_options"; ""; "/dev/sda2"; "/"];
3739         ["write_file"; "/new"; "new file contents"; "0"];
3740         ["cat"; "/new"]], "new file contents")]),
3741    "make ext2/3/4 external journal with UUID",
3742    "\
3743 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3744
3745   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3746    [],
3747    "make ext2/3/4 filesystem with external journal",
3748    "\
3749 This creates an ext2/3/4 filesystem on C<device> with
3750 an external journal on C<journal>.  It is equivalent
3751 to the command:
3752
3753  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3754
3755 See also C<guestfs_mke2journal>.");
3756
3757   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3758    [],
3759    "make ext2/3/4 filesystem with external journal",
3760    "\
3761 This creates an ext2/3/4 filesystem on C<device> with
3762 an external journal on the journal labeled C<label>.
3763
3764 See also C<guestfs_mke2journal_L>.");
3765
3766   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3767    [],
3768    "make ext2/3/4 filesystem with external journal",
3769    "\
3770 This creates an ext2/3/4 filesystem on C<device> with
3771 an external journal on the journal with UUID C<uuid>.
3772
3773 See also C<guestfs_mke2journal_U>.");
3774
3775   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3776    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3777    "load a kernel module",
3778    "\
3779 This loads a kernel module in the appliance.
3780
3781 The kernel module must have been whitelisted when libguestfs
3782 was built (see C<appliance/kmod.whitelist.in> in the source).");
3783
3784   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3785    [InitNone, Always, TestOutput (
3786       [["echo_daemon"; "This is a test"]], "This is a test"
3787     )],
3788    "echo arguments back to the client",
3789    "\
3790 This command concatenate the list of C<words> passed with single spaces between
3791 them and returns the resulting string.
3792
3793 You can use this command to test the connection through to the daemon.
3794
3795 See also C<guestfs_ping_daemon>.");
3796
3797   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3798    [], (* There is a regression test for this. *)
3799    "find all files and directories, returning NUL-separated list",
3800    "\
3801 This command lists out all files and directories, recursively,
3802 starting at C<directory>, placing the resulting list in the
3803 external file called C<files>.
3804
3805 This command works the same way as C<guestfs_find> with the
3806 following exceptions:
3807
3808 =over 4
3809
3810 =item *
3811
3812 The resulting list is written to an external file.
3813
3814 =item *
3815
3816 Items (filenames) in the result are separated
3817 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3818
3819 =item *
3820
3821 This command is not limited in the number of names that it
3822 can return.
3823
3824 =item *
3825
3826 The result list is not sorted.
3827
3828 =back");
3829
3830   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3831    [InitISOFS, Always, TestOutput (
3832       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3833     InitISOFS, Always, TestOutput (
3834       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3835     InitISOFS, Always, TestOutput (
3836       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3837     InitISOFS, Always, TestLastFail (
3838       [["case_sensitive_path"; "/Known-1/"]]);
3839     InitBasicFS, Always, TestOutput (
3840       [["mkdir"; "/a"];
3841        ["mkdir"; "/a/bbb"];
3842        ["touch"; "/a/bbb/c"];
3843        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3844     InitBasicFS, Always, TestOutput (
3845       [["mkdir"; "/a"];
3846        ["mkdir"; "/a/bbb"];
3847        ["touch"; "/a/bbb/c"];
3848        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3849     InitBasicFS, Always, TestLastFail (
3850       [["mkdir"; "/a"];
3851        ["mkdir"; "/a/bbb"];
3852        ["touch"; "/a/bbb/c"];
3853        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3854    "return true path on case-insensitive filesystem",
3855    "\
3856 This can be used to resolve case insensitive paths on
3857 a filesystem which is case sensitive.  The use case is
3858 to resolve paths which you have read from Windows configuration
3859 files or the Windows Registry, to the true path.
3860
3861 The command handles a peculiarity of the Linux ntfs-3g
3862 filesystem driver (and probably others), which is that although
3863 the underlying filesystem is case-insensitive, the driver
3864 exports the filesystem to Linux as case-sensitive.
3865
3866 One consequence of this is that special directories such
3867 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3868 (or other things) depending on the precise details of how
3869 they were created.  In Windows itself this would not be
3870 a problem.
3871
3872 Bug or feature?  You decide:
3873 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3874
3875 This function resolves the true case of each element in the
3876 path and returns the case-sensitive path.
3877
3878 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3879 might return C<\"/WINDOWS/system32\"> (the exact return value
3880 would depend on details of how the directories were originally
3881 created under Windows).
3882
3883 I<Note>:
3884 This function does not handle drive names, backslashes etc.
3885
3886 See also C<guestfs_realpath>.");
3887
3888   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3889    [InitBasicFS, Always, TestOutput (
3890       [["vfs_type"; "/dev/sda1"]], "ext2")],
3891    "get the Linux VFS type corresponding to a mounted device",
3892    "\
3893 This command gets the block device type corresponding to
3894 a mounted device called C<device>.
3895
3896 Usually the result is the name of the Linux VFS module that
3897 is used to mount this device (probably determined automatically
3898 if you used the C<guestfs_mount> call).");
3899
3900   ("truncate", (RErr, [Pathname "path"]), 199, [],
3901    [InitBasicFS, Always, TestOutputStruct (
3902       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3903        ["truncate"; "/test"];
3904        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3905    "truncate a file to zero size",
3906    "\
3907 This command truncates C<path> to a zero-length file.  The
3908 file must exist already.");
3909
3910   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3911    [InitBasicFS, Always, TestOutputStruct (
3912       [["touch"; "/test"];
3913        ["truncate_size"; "/test"; "1000"];
3914        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3915    "truncate a file to a particular size",
3916    "\
3917 This command truncates C<path> to size C<size> bytes.  The file
3918 must exist already.  If the file is smaller than C<size> then
3919 the file is extended to the required size with null bytes.");
3920
3921   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3922    [InitBasicFS, Always, TestOutputStruct (
3923       [["touch"; "/test"];
3924        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3925        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3926    "set timestamp of a file with nanosecond precision",
3927    "\
3928 This command sets the timestamps of a file with nanosecond
3929 precision.
3930
3931 C<atsecs, atnsecs> are the last access time (atime) in secs and
3932 nanoseconds from the epoch.
3933
3934 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3935 secs and nanoseconds from the epoch.
3936
3937 If the C<*nsecs> field contains the special value C<-1> then
3938 the corresponding timestamp is set to the current time.  (The
3939 C<*secs> field is ignored in this case).
3940
3941 If the C<*nsecs> field contains the special value C<-2> then
3942 the corresponding timestamp is left unchanged.  (The
3943 C<*secs> field is ignored in this case).");
3944
3945   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3946    [InitBasicFS, Always, TestOutputStruct (
3947       [["mkdir_mode"; "/test"; "0o111"];
3948        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3949    "create a directory with a particular mode",
3950    "\
3951 This command creates a directory, setting the initial permissions
3952 of the directory to C<mode>.
3953
3954 For common Linux filesystems, the actual mode which is set will
3955 be C<mode & ~umask & 01777>.  Non-native-Linux filesystems may
3956 interpret the mode in other ways.
3957
3958 See also C<guestfs_mkdir>, C<guestfs_umask>");
3959
3960   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3961    [], (* XXX *)
3962    "change file owner and group",
3963    "\
3964 Change the file owner to C<owner> and group to C<group>.
3965 This is like C<guestfs_chown> but if C<path> is a symlink then
3966 the link itself is changed, not the target.
3967
3968 Only numeric uid and gid are supported.  If you want to use
3969 names, you will need to locate and parse the password file
3970 yourself (Augeas support makes this relatively easy).");
3971
3972   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3973    [], (* XXX *)
3974    "lstat on multiple files",
3975    "\
3976 This call allows you to perform the C<guestfs_lstat> operation
3977 on multiple files, where all files are in the directory C<path>.
3978 C<names> is the list of files from this directory.
3979
3980 On return you get a list of stat structs, with a one-to-one
3981 correspondence to the C<names> list.  If any name did not exist
3982 or could not be lstat'd, then the C<ino> field of that structure
3983 is set to C<-1>.
3984
3985 This call is intended for programs that want to efficiently
3986 list a directory contents without making many round-trips.
3987 See also C<guestfs_lxattrlist> for a similarly efficient call
3988 for getting extended attributes.  Very long directory listings
3989 might cause the protocol message size to be exceeded, causing
3990 this call to fail.  The caller must split up such requests
3991 into smaller groups of names.");
3992
3993   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3994    [], (* XXX *)
3995    "lgetxattr on multiple files",
3996    "\
3997 This call allows you to get the extended attributes
3998 of multiple files, where all files are in the directory C<path>.
3999 C<names> is the list of files from this directory.
4000
4001 On return you get a flat list of xattr structs which must be
4002 interpreted sequentially.  The first xattr struct always has a zero-length
4003 C<attrname>.  C<attrval> in this struct is zero-length
4004 to indicate there was an error doing C<lgetxattr> for this
4005 file, I<or> is a C string which is a decimal number
4006 (the number of following attributes for this file, which could
4007 be C<\"0\">).  Then after the first xattr struct are the
4008 zero or more attributes for the first named file.
4009 This repeats for the second and subsequent files.
4010
4011 This call is intended for programs that want to efficiently
4012 list a directory contents without making many round-trips.
4013 See also C<guestfs_lstatlist> for a similarly efficient call
4014 for getting standard stats.  Very long directory listings
4015 might cause the protocol message size to be exceeded, causing
4016 this call to fail.  The caller must split up such requests
4017 into smaller groups of names.");
4018
4019   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
4020    [], (* XXX *)
4021    "readlink on multiple files",
4022    "\
4023 This call allows you to do a C<readlink> operation
4024 on multiple files, where all files are in the directory C<path>.
4025 C<names> is the list of files from this directory.
4026
4027 On return you get a list of strings, with a one-to-one
4028 correspondence to the C<names> list.  Each string is the
4029 value of the symbol link.
4030
4031 If the C<readlink(2)> operation fails on any name, then
4032 the corresponding result string is the empty string C<\"\">.
4033 However the whole operation is completed even if there
4034 were C<readlink(2)> errors, and so you can call this
4035 function with names where you don't know if they are
4036 symbolic links already (albeit slightly less efficient).
4037
4038 This call is intended for programs that want to efficiently
4039 list a directory contents without making many round-trips.
4040 Very long directory listings might cause the protocol
4041 message size to be exceeded, causing
4042 this call to fail.  The caller must split up such requests
4043 into smaller groups of names.");
4044
4045   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
4046    [InitISOFS, Always, TestOutputBuffer (
4047       [["pread"; "/known-4"; "1"; "3"]], "\n");
4048     InitISOFS, Always, TestOutputBuffer (
4049       [["pread"; "/empty"; "0"; "100"]], "")],
4050    "read part of a file",
4051    "\
4052 This command lets you read part of a file.  It reads C<count>
4053 bytes of the file, starting at C<offset>, from file C<path>.
4054
4055 This may read fewer bytes than requested.  For further details
4056 see the L<pread(2)> system call.");
4057
4058   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
4059    [InitEmpty, Always, TestRun (
4060       [["part_init"; "/dev/sda"; "gpt"]])],
4061    "create an empty partition table",
4062    "\
4063 This creates an empty partition table on C<device> of one of the
4064 partition types listed below.  Usually C<parttype> should be
4065 either C<msdos> or C<gpt> (for large disks).
4066
4067 Initially there are no partitions.  Following this, you should
4068 call C<guestfs_part_add> for each partition required.
4069
4070 Possible values for C<parttype> are:
4071
4072 =over 4
4073
4074 =item B<efi> | B<gpt>
4075
4076 Intel EFI / GPT partition table.
4077
4078 This is recommended for >= 2 TB partitions that will be accessed
4079 from Linux and Intel-based Mac OS X.  It also has limited backwards
4080 compatibility with the C<mbr> format.
4081
4082 =item B<mbr> | B<msdos>
4083
4084 The standard PC \"Master Boot Record\" (MBR) format used
4085 by MS-DOS and Windows.  This partition type will B<only> work
4086 for device sizes up to 2 TB.  For large disks we recommend
4087 using C<gpt>.
4088
4089 =back
4090
4091 Other partition table types that may work but are not
4092 supported include:
4093
4094 =over 4
4095
4096 =item B<aix>
4097
4098 AIX disk labels.
4099
4100 =item B<amiga> | B<rdb>
4101
4102 Amiga \"Rigid Disk Block\" format.
4103
4104 =item B<bsd>
4105
4106 BSD disk labels.
4107
4108 =item B<dasd>
4109
4110 DASD, used on IBM mainframes.
4111
4112 =item B<dvh>
4113
4114 MIPS/SGI volumes.
4115
4116 =item B<mac>
4117
4118 Old Mac partition format.  Modern Macs use C<gpt>.
4119
4120 =item B<pc98>
4121
4122 NEC PC-98 format, common in Japan apparently.
4123
4124 =item B<sun>
4125
4126 Sun disk labels.
4127
4128 =back");
4129
4130   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
4131    [InitEmpty, Always, TestRun (
4132       [["part_init"; "/dev/sda"; "mbr"];
4133        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
4134     InitEmpty, Always, TestRun (
4135       [["part_init"; "/dev/sda"; "gpt"];
4136        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
4137        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
4138     InitEmpty, Always, TestRun (
4139       [["part_init"; "/dev/sda"; "mbr"];
4140        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
4141        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4142        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4143        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4144    "add a partition to the device",
4145    "\
4146 This command adds a partition to C<device>.  If there is no partition
4147 table on the device, call C<guestfs_part_init> first.
4148
4149 The C<prlogex> parameter is the type of partition.  Normally you
4150 should pass C<p> or C<primary> here, but MBR partition tables also
4151 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4152 types.
4153
4154 C<startsect> and C<endsect> are the start and end of the partition
4155 in I<sectors>.  C<endsect> may be negative, which means it counts
4156 backwards from the end of the disk (C<-1> is the last sector).
4157
4158 Creating a partition which covers the whole disk is not so easy.
4159 Use C<guestfs_part_disk> to do that.");
4160
4161   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4162    [InitEmpty, Always, TestRun (
4163       [["part_disk"; "/dev/sda"; "mbr"]]);
4164     InitEmpty, Always, TestRun (
4165       [["part_disk"; "/dev/sda"; "gpt"]])],
4166    "partition whole disk with a single primary partition",
4167    "\
4168 This command is simply a combination of C<guestfs_part_init>
4169 followed by C<guestfs_part_add> to create a single primary partition
4170 covering the whole disk.
4171
4172 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4173 but other possible values are described in C<guestfs_part_init>.");
4174
4175   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4176    [InitEmpty, Always, TestRun (
4177       [["part_disk"; "/dev/sda"; "mbr"];
4178        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4179    "make a partition bootable",
4180    "\
4181 This sets the bootable flag on partition numbered C<partnum> on
4182 device C<device>.  Note that partitions are numbered from 1.
4183
4184 The bootable flag is used by some operating systems (notably
4185 Windows) to determine which partition to boot from.  It is by
4186 no means universally recognized.");
4187
4188   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4189    [InitEmpty, Always, TestRun (
4190       [["part_disk"; "/dev/sda"; "gpt"];
4191        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4192    "set partition name",
4193    "\
4194 This sets the partition name on partition numbered C<partnum> on
4195 device C<device>.  Note that partitions are numbered from 1.
4196
4197 The partition name can only be set on certain types of partition
4198 table.  This works on C<gpt> but not on C<mbr> partitions.");
4199
4200   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4201    [], (* XXX Add a regression test for this. *)
4202    "list partitions on a device",
4203    "\
4204 This command parses the partition table on C<device> and
4205 returns the list of partitions found.
4206
4207 The fields in the returned structure are:
4208
4209 =over 4
4210
4211 =item B<part_num>
4212
4213 Partition number, counting from 1.
4214
4215 =item B<part_start>
4216
4217 Start of the partition I<in bytes>.  To get sectors you have to
4218 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4219
4220 =item B<part_end>
4221
4222 End of the partition in bytes.
4223
4224 =item B<part_size>
4225
4226 Size of the partition in bytes.
4227
4228 =back");
4229
4230   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4231    [InitEmpty, Always, TestOutput (
4232       [["part_disk"; "/dev/sda"; "gpt"];
4233        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4234    "get the partition table type",
4235    "\
4236 This command examines the partition table on C<device> and
4237 returns the partition table type (format) being used.
4238
4239 Common return values include: C<msdos> (a DOS/Windows style MBR
4240 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4241 values are possible, although unusual.  See C<guestfs_part_init>
4242 for a full list.");
4243
4244   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4245    [InitBasicFS, Always, TestOutputBuffer (
4246       [["fill"; "0x63"; "10"; "/test"];
4247        ["read_file"; "/test"]], "cccccccccc")],
4248    "fill a file with octets",
4249    "\
4250 This command creates a new file called C<path>.  The initial
4251 content of the file is C<len> octets of C<c>, where C<c>
4252 must be a number in the range C<[0..255]>.
4253
4254 To fill a file with zero bytes (sparsely), it is
4255 much more efficient to use C<guestfs_truncate_size>.");
4256
4257   ("available", (RErr, [StringList "groups"]), 216, [],
4258    [InitNone, Always, TestRun [["available"; ""]]],
4259    "test availability of some parts of the API",
4260    "\
4261 This command is used to check the availability of some
4262 groups of functionality in the appliance, which not all builds of
4263 the libguestfs appliance will be able to provide.
4264
4265 The libguestfs groups, and the functions that those
4266 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4267
4268 The argument C<groups> is a list of group names, eg:
4269 C<[\"inotify\", \"augeas\"]> would check for the availability of
4270 the Linux inotify functions and Augeas (configuration file
4271 editing) functions.
4272
4273 The command returns no error if I<all> requested groups are available.
4274
4275 It fails with an error if one or more of the requested
4276 groups is unavailable in the appliance.
4277
4278 If an unknown group name is included in the
4279 list of groups then an error is always returned.
4280
4281 I<Notes:>
4282
4283 =over 4
4284
4285 =item *
4286
4287 You must call C<guestfs_launch> before calling this function.
4288
4289 The reason is because we don't know what groups are
4290 supported by the appliance/daemon until it is running and can
4291 be queried.
4292
4293 =item *
4294
4295 If a group of functions is available, this does not necessarily
4296 mean that they will work.  You still have to check for errors
4297 when calling individual API functions even if they are
4298 available.
4299
4300 =item *
4301
4302 It is usually the job of distro packagers to build
4303 complete functionality into the libguestfs appliance.
4304 Upstream libguestfs, if built from source with all
4305 requirements satisfied, will support everything.
4306
4307 =item *
4308
4309 This call was added in version C<1.0.80>.  In previous
4310 versions of libguestfs all you could do would be to speculatively
4311 execute a command to find out if the daemon implemented it.
4312 See also C<guestfs_version>.
4313
4314 =back");
4315
4316   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4317    [InitBasicFS, Always, TestOutputBuffer (
4318       [["write_file"; "/src"; "hello, world"; "0"];
4319        ["dd"; "/src"; "/dest"];
4320        ["read_file"; "/dest"]], "hello, world")],
4321    "copy from source to destination using dd",
4322    "\
4323 This command copies from one source device or file C<src>
4324 to another destination device or file C<dest>.  Normally you
4325 would use this to copy to or from a device or partition, for
4326 example to duplicate a filesystem.
4327
4328 If the destination is a device, it must be as large or larger
4329 than the source file or device, otherwise the copy will fail.
4330 This command cannot do partial copies (see C<guestfs_copy_size>).");
4331
4332   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4333    [InitBasicFS, Always, TestOutputInt (
4334       [["write_file"; "/file"; "hello, world"; "0"];
4335        ["filesize"; "/file"]], 12)],
4336    "return the size of the file in bytes",
4337    "\
4338 This command returns the size of C<file> in bytes.
4339
4340 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4341 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4342 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4343
4344   ("lvrename", (RErr, [String "logvol"; String "newlogvol"]), 219, [],
4345    [InitBasicFSonLVM, Always, TestOutputList (
4346       [["lvrename"; "/dev/VG/LV"; "/dev/VG/LV2"];
4347        ["lvs"]], ["/dev/VG/LV2"])],
4348    "rename an LVM logical volume",
4349    "\
4350 Rename a logical volume C<logvol> with the new name C<newlogvol>.");
4351
4352   ("vgrename", (RErr, [String "volgroup"; String "newvolgroup"]), 220, [],
4353    [InitBasicFSonLVM, Always, TestOutputList (
4354       [["umount"; "/"];
4355        ["vg_activate"; "false"; "VG"];
4356        ["vgrename"; "VG"; "VG2"];
4357        ["vg_activate"; "true"; "VG2"];
4358        ["mount_options"; ""; "/dev/VG2/LV"; "/"];
4359        ["vgs"]], ["VG2"])],
4360    "rename an LVM volume group",
4361    "\
4362 Rename a volume group C<volgroup> with the new name C<newvolgroup>.");
4363
4364   ("initrd_cat", (RBufferOut "content", [Pathname "initrdpath"; String "filename"]), 221, [ProtocolLimitWarning],
4365    [InitISOFS, Always, TestOutputBuffer (
4366       [["initrd_cat"; "/initrd"; "known-4"]], "abc\ndef\nghi")],
4367    "list the contents of a single file in an initrd",
4368    "\
4369 This command unpacks the file C<filename> from the initrd file
4370 called C<initrdpath>.  The filename must be given I<without> the
4371 initial C</> character.
4372
4373 For example, in guestfish you could use the following command
4374 to examine the boot script (usually called C</init>)
4375 contained in a Linux initrd or initramfs image:
4376
4377  initrd-cat /boot/initrd-<version>.img init
4378
4379 See also C<guestfs_initrd_list>.");
4380
4381   ("pvuuid", (RString "uuid", [Device "device"]), 222, [],
4382    [],
4383    "get the UUID of a physical volume",
4384    "\
4385 This command returns the UUID of the LVM PV C<device>.");
4386
4387   ("vguuid", (RString "uuid", [String "vgname"]), 223, [],
4388    [],
4389    "get the UUID of a volume group",
4390    "\
4391 This command returns the UUID of the LVM VG named C<vgname>.");
4392
4393   ("lvuuid", (RString "uuid", [Device "device"]), 224, [],
4394    [],
4395    "get the UUID of a logical volume",
4396    "\
4397 This command returns the UUID of the LVM LV C<device>.");
4398
4399   ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [],
4400    [],
4401    "get the PV UUIDs containing the volume group",
4402    "\
4403 Given a VG called C<vgname>, this returns the UUIDs of all
4404 the physical volumes that this volume group resides on.
4405
4406 You can use this along with C<guestfs_pvs> and C<guestfs_pvuuid>
4407 calls to associate physical volumes and volume groups.
4408
4409 See also C<guestfs_vglvuuids>.");
4410
4411   ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [],
4412    [],
4413    "get the LV UUIDs of all LVs in the volume group",
4414    "\
4415 Given a VG called C<vgname>, this returns the UUIDs of all
4416 the logical volumes created in this volume group.
4417
4418 You can use this along with C<guestfs_lvs> and C<guestfs_lvuuid>
4419 calls to associate logical volumes and volume groups.
4420
4421 See also C<guestfs_vgpvuuids>.");
4422
4423   ("copy_size", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"; Int64 "size"]), 227, [],
4424    [InitBasicFS, Always, TestOutputBuffer (
4425       [["write_file"; "/src"; "hello, world"; "0"];
4426        ["copy_size"; "/src"; "/dest"; "5"];
4427        ["read_file"; "/dest"]], "hello")],
4428    "copy size bytes from source to destination using dd",
4429    "\
4430 This command copies exactly C<size> bytes from one source device
4431 or file C<src> to another destination device or file C<dest>.
4432
4433 Note this will fail if the source is too short or if the destination
4434 is not large enough.");
4435
4436   ("zero_device", (RErr, [Device "device"]), 228, [DangerWillRobinson],
4437    [InitBasicFSonLVM, Always, TestRun (
4438       [["zero_device"; "/dev/VG/LV"]])],
4439    "write zeroes to an entire device",
4440    "\
4441 This command writes zeroes over the entire C<device>.  Compare
4442 with C<guestfs_zero> which just zeroes the first few blocks of
4443 a device.");
4444
4445   ("txz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 229, [],
4446    [InitBasicFS, Always, TestOutput (
4447       [["txz_in"; "../images/helloworld.tar.xz"; "/"];
4448        ["cat"; "/hello"]], "hello\n")],
4449    "unpack compressed tarball to directory",
4450    "\
4451 This command uploads and unpacks local file C<tarball> (an
4452 I<xz compressed> tar file) into C<directory>.");
4453
4454   ("txz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 230, [],
4455    [],
4456    "pack directory into compressed tarball",
4457    "\
4458 This command packs the contents of C<directory> and downloads
4459 it to local file C<tarball> (as an xz compressed tar archive).");
4460
4461   ("ntfsresize", (RErr, [Device "device"]), 231, [Optional "ntfsprogs"],
4462    [],
4463    "resize an NTFS filesystem",
4464    "\
4465 This command resizes an NTFS filesystem, expanding or
4466 shrinking it to the size of the underlying device.
4467 See also L<ntfsresize(8)>.");
4468
4469   ("vgscan", (RErr, []), 232, [],
4470    [InitEmpty, Always, TestRun (
4471       [["vgscan"]])],
4472    "rescan for LVM physical volumes, volume groups and logical volumes",
4473    "\
4474 This rescans all block devices and rebuilds the list of LVM
4475 physical volumes, volume groups and logical volumes.");
4476
4477   ("part_del", (RErr, [Device "device"; Int "partnum"]), 233, [],
4478    [InitEmpty, Always, TestRun (
4479       [["part_init"; "/dev/sda"; "mbr"];
4480        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4481        ["part_del"; "/dev/sda"; "1"]])],
4482    "delete a partition",
4483    "\
4484 This command deletes the partition numbered C<partnum> on C<device>.
4485
4486 Note that in the case of MBR partitioning, deleting an
4487 extended partition also deletes any logical partitions
4488 it contains.");
4489
4490   ("part_get_bootable", (RBool "bootable", [Device "device"; Int "partnum"]), 234, [],
4491    [InitEmpty, Always, TestOutputTrue (
4492       [["part_init"; "/dev/sda"; "mbr"];
4493        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4494        ["part_set_bootable"; "/dev/sda"; "1"; "true"];
4495        ["part_get_bootable"; "/dev/sda"; "1"]])],
4496    "return true if a partition is bootable",
4497    "\
4498 This command returns true if the partition C<partnum> on
4499 C<device> has the bootable flag set.
4500
4501 See also C<guestfs_part_set_bootable>.");
4502
4503   ("part_get_mbr_id", (RInt "idbyte", [Device "device"; Int "partnum"]), 235, [FishOutput FishOutputHexadecimal],
4504    [InitEmpty, Always, TestOutputInt (
4505       [["part_init"; "/dev/sda"; "mbr"];
4506        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4507        ["part_set_mbr_id"; "/dev/sda"; "1"; "0x7f"];
4508        ["part_get_mbr_id"; "/dev/sda"; "1"]], 0x7f)],
4509    "get the MBR type byte (ID byte) from a partition",
4510    "\
4511 Returns the MBR type byte (also known as the ID byte) from
4512 the numbered partition C<partnum>.
4513
4514 Note that only MBR (old DOS-style) partitions have type bytes.
4515 You will get undefined results for other partition table
4516 types (see C<guestfs_part_get_parttype>).");
4517
4518   ("part_set_mbr_id", (RErr, [Device "device"; Int "partnum"; Int "idbyte"]), 236, [],
4519    [], (* tested by part_get_mbr_id *)
4520    "set the MBR type byte (ID byte) of a partition",
4521    "\
4522 Sets the MBR type byte (also known as the ID byte) of
4523 the numbered partition C<partnum> to C<idbyte>.  Note
4524 that the type bytes quoted in most documentation are
4525 in fact hexadecimal numbers, but usually documented
4526 without any leading \"0x\" which might be confusing.
4527
4528 Note that only MBR (old DOS-style) partitions have type bytes.
4529 You will get undefined results for other partition table
4530 types (see C<guestfs_part_get_parttype>).");
4531
4532   ("checksum_device", (RString "checksum", [String "csumtype"; Device "device"]), 237, [],
4533    [InitISOFS, Always, TestOutput (
4534       [["checksum_device"; "md5"; "/dev/sdd"]],
4535       (Digest.to_hex (Digest.file "images/test.iso")))],
4536    "compute MD5, SHAx or CRC checksum of the contents of a device",
4537    "\
4538 This call computes the MD5, SHAx or CRC checksum of the
4539 contents of the device named C<device>.  For the types of
4540 checksums supported see the C<guestfs_checksum> command.");
4541
4542   ("lvresize_free", (RErr, [Device "lv"; Int "percent"]), 238, [Optional "lvm2"],
4543    [InitNone, Always, TestRun (
4544       [["part_disk"; "/dev/sda"; "mbr"];
4545        ["pvcreate"; "/dev/sda1"];
4546        ["vgcreate"; "VG"; "/dev/sda1"];
4547        ["lvcreate"; "LV"; "VG"; "10"];
4548        ["lvresize_free"; "/dev/VG/LV"; "100"]])],
4549    "expand an LV to fill free space",
4550    "\
4551 This expands an existing logical volume C<lv> so that it fills
4552 C<pc>% of the remaining free space in the volume group.  Commonly
4553 you would call this with pc = 100 which expands the logical volume
4554 as much as possible, using all remaining free space in the volume
4555 group.");
4556
4557   ("aug_clear", (RErr, [String "augpath"]), 239, [Optional "augeas"],
4558    [], (* XXX Augeas code needs tests. *)
4559    "clear Augeas path",
4560    "\
4561 Set the value associated with C<path> to C<NULL>.  This
4562 is the same as the L<augtool(1)> C<clear> command.");
4563
4564   ("get_umask", (RInt "mask", []), 240, [FishOutput FishOutputOctal],
4565    [InitEmpty, Always, TestOutputInt (
4566       [["get_umask"]], 0o22)],
4567    "get the current umask",
4568    "\
4569 Return the current umask.  By default the umask is C<022>
4570 unless it has been set by calling C<guestfs_umask>.");
4571
4572   ("debug_upload", (RErr, [FileIn "filename"; String "tmpname"; Int "mode"]), 241, [],
4573    [],
4574    "upload a file to the appliance (internal use only)",
4575    "\
4576 The C<guestfs_debug_upload> command uploads a file to
4577 the libguestfs appliance.
4578
4579 There is no comprehensive help for this command.  You have
4580 to look at the file C<daemon/debug.c> in the libguestfs source
4581 to find out what it is for.");
4582
4583   ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [],
4584    [InitBasicFS, Always, TestOutput (
4585       [["base64_in"; "../images/hello.b64"; "/hello"];
4586        ["cat"; "/hello"]], "hello\n")],
4587    "upload base64-encoded data to file",
4588    "\
4589 This command uploads base64-encoded data from C<base64file>
4590 to C<filename>.");
4591
4592   ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [],
4593    [],
4594    "download file and encode as base64",
4595    "\
4596 This command downloads the contents of C<filename>, writing
4597 it out to local file C<base64file> encoded as base64.");
4598
4599   ("checksums_out", (RErr, [String "csumtype"; Pathname "directory"; FileOut "sumsfile"]), 244, [],
4600    [],
4601    "compute MD5, SHAx or CRC checksum of files in a directory",
4602    "\
4603 This command computes the checksums of all regular files in
4604 C<directory> and then emits a list of those checksums to
4605 the local output file C<sumsfile>.
4606
4607 This can be used for verifying the integrity of a virtual
4608 machine.  However to be properly secure you should pay
4609 attention to the output of the checksum command (it uses
4610 the ones from GNU coreutils).  In particular when the
4611 filename is not printable, coreutils uses a special
4612 backslash syntax.  For more information, see the GNU
4613 coreutils info file.");
4614
4615 ]
4616
4617 let all_functions = non_daemon_functions @ daemon_functions
4618
4619 (* In some places we want the functions to be displayed sorted
4620  * alphabetically, so this is useful:
4621  *)
4622 let all_functions_sorted =
4623   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4624                compare n1 n2) all_functions
4625
4626 (* Field types for structures. *)
4627 type field =
4628   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4629   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4630   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4631   | FUInt32
4632   | FInt32
4633   | FUInt64
4634   | FInt64
4635   | FBytes                      (* Any int measure that counts bytes. *)
4636   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4637   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4638
4639 (* Because we generate extra parsing code for LVM command line tools,
4640  * we have to pull out the LVM columns separately here.
4641  *)
4642 let lvm_pv_cols = [
4643   "pv_name", FString;
4644   "pv_uuid", FUUID;
4645   "pv_fmt", FString;
4646   "pv_size", FBytes;
4647   "dev_size", FBytes;
4648   "pv_free", FBytes;
4649   "pv_used", FBytes;
4650   "pv_attr", FString (* XXX *);
4651   "pv_pe_count", FInt64;
4652   "pv_pe_alloc_count", FInt64;
4653   "pv_tags", FString;
4654   "pe_start", FBytes;
4655   "pv_mda_count", FInt64;
4656   "pv_mda_free", FBytes;
4657   (* Not in Fedora 10:
4658      "pv_mda_size", FBytes;
4659   *)
4660 ]
4661 let lvm_vg_cols = [
4662   "vg_name", FString;
4663   "vg_uuid", FUUID;
4664   "vg_fmt", FString;
4665   "vg_attr", FString (* XXX *);
4666   "vg_size", FBytes;
4667   "vg_free", FBytes;
4668   "vg_sysid", FString;
4669   "vg_extent_size", FBytes;
4670   "vg_extent_count", FInt64;
4671   "vg_free_count", FInt64;
4672   "max_lv", FInt64;
4673   "max_pv", FInt64;
4674   "pv_count", FInt64;
4675   "lv_count", FInt64;
4676   "snap_count", FInt64;
4677   "vg_seqno", FInt64;
4678   "vg_tags", FString;
4679   "vg_mda_count", FInt64;
4680   "vg_mda_free", FBytes;
4681   (* Not in Fedora 10:
4682      "vg_mda_size", FBytes;
4683   *)
4684 ]
4685 let lvm_lv_cols = [
4686   "lv_name", FString;
4687   "lv_uuid", FUUID;
4688   "lv_attr", FString (* XXX *);
4689   "lv_major", FInt64;
4690   "lv_minor", FInt64;
4691   "lv_kernel_major", FInt64;
4692   "lv_kernel_minor", FInt64;
4693   "lv_size", FBytes;
4694   "seg_count", FInt64;
4695   "origin", FString;
4696   "snap_percent", FOptPercent;
4697   "copy_percent", FOptPercent;
4698   "move_pv", FString;
4699   "lv_tags", FString;
4700   "mirror_log", FString;
4701   "modules", FString;
4702 ]
4703
4704 (* Names and fields in all structures (in RStruct and RStructList)
4705  * that we support.
4706  *)
4707 let structs = [
4708   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4709    * not use this struct in any new code.
4710    *)
4711   "int_bool", [
4712     "i", FInt32;                (* for historical compatibility *)
4713     "b", FInt32;                (* for historical compatibility *)
4714   ];
4715
4716   (* LVM PVs, VGs, LVs. *)
4717   "lvm_pv", lvm_pv_cols;
4718   "lvm_vg", lvm_vg_cols;
4719   "lvm_lv", lvm_lv_cols;
4720
4721   (* Column names and types from stat structures.
4722    * NB. Can't use things like 'st_atime' because glibc header files
4723    * define some of these as macros.  Ugh.
4724    *)
4725   "stat", [
4726     "dev", FInt64;
4727     "ino", FInt64;
4728     "mode", FInt64;
4729     "nlink", FInt64;
4730     "uid", FInt64;
4731     "gid", FInt64;
4732     "rdev", FInt64;
4733     "size", FInt64;
4734     "blksize", FInt64;
4735     "blocks", FInt64;
4736     "atime", FInt64;
4737     "mtime", FInt64;
4738     "ctime", FInt64;
4739   ];
4740   "statvfs", [
4741     "bsize", FInt64;
4742     "frsize", FInt64;
4743     "blocks", FInt64;
4744     "bfree", FInt64;
4745     "bavail", FInt64;
4746     "files", FInt64;
4747     "ffree", FInt64;
4748     "favail", FInt64;
4749     "fsid", FInt64;
4750     "flag", FInt64;
4751     "namemax", FInt64;
4752   ];
4753
4754   (* Column names in dirent structure. *)
4755   "dirent", [
4756     "ino", FInt64;
4757     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4758     "ftyp", FChar;
4759     "name", FString;
4760   ];
4761
4762   (* Version numbers. *)
4763   "version", [
4764     "major", FInt64;
4765     "minor", FInt64;
4766     "release", FInt64;
4767     "extra", FString;
4768   ];
4769
4770   (* Extended attribute. *)
4771   "xattr", [
4772     "attrname", FString;
4773     "attrval", FBuffer;
4774   ];
4775
4776   (* Inotify events. *)
4777   "inotify_event", [
4778     "in_wd", FInt64;
4779     "in_mask", FUInt32;
4780     "in_cookie", FUInt32;
4781     "in_name", FString;
4782   ];
4783
4784   (* Partition table entry. *)
4785   "partition", [
4786     "part_num", FInt32;
4787     "part_start", FBytes;
4788     "part_end", FBytes;
4789     "part_size", FBytes;
4790   ];
4791 ] (* end of structs *)
4792
4793 (* Ugh, Java has to be different ..
4794  * These names are also used by the Haskell bindings.
4795  *)
4796 let java_structs = [
4797   "int_bool", "IntBool";
4798   "lvm_pv", "PV";
4799   "lvm_vg", "VG";
4800   "lvm_lv", "LV";
4801   "stat", "Stat";
4802   "statvfs", "StatVFS";
4803   "dirent", "Dirent";
4804   "version", "Version";
4805   "xattr", "XAttr";
4806   "inotify_event", "INotifyEvent";
4807   "partition", "Partition";
4808 ]
4809
4810 (* What structs are actually returned. *)
4811 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4812
4813 (* Returns a list of RStruct/RStructList structs that are returned
4814  * by any function.  Each element of returned list is a pair:
4815  *
4816  * (structname, RStructOnly)
4817  *    == there exists function which returns RStruct (_, structname)
4818  * (structname, RStructListOnly)
4819  *    == there exists function which returns RStructList (_, structname)
4820  * (structname, RStructAndList)
4821  *    == there are functions returning both RStruct (_, structname)
4822  *                                      and RStructList (_, structname)
4823  *)
4824 let rstructs_used_by functions =
4825   (* ||| is a "logical OR" for rstructs_used_t *)
4826   let (|||) a b =
4827     match a, b with
4828     | RStructAndList, _
4829     | _, RStructAndList -> RStructAndList
4830     | RStructOnly, RStructListOnly
4831     | RStructListOnly, RStructOnly -> RStructAndList
4832     | RStructOnly, RStructOnly -> RStructOnly
4833     | RStructListOnly, RStructListOnly -> RStructListOnly
4834   in
4835
4836   let h = Hashtbl.create 13 in
4837
4838   (* if elem->oldv exists, update entry using ||| operator,
4839    * else just add elem->newv to the hash
4840    *)
4841   let update elem newv =
4842     try  let oldv = Hashtbl.find h elem in
4843          Hashtbl.replace h elem (newv ||| oldv)
4844     with Not_found -> Hashtbl.add h elem newv
4845   in
4846
4847   List.iter (
4848     fun (_, style, _, _, _, _, _) ->
4849       match fst style with
4850       | RStruct (_, structname) -> update structname RStructOnly
4851       | RStructList (_, structname) -> update structname RStructListOnly
4852       | _ -> ()
4853   ) functions;
4854
4855   (* return key->values as a list of (key,value) *)
4856   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4857
4858 (* Used for testing language bindings. *)
4859 type callt =
4860   | CallString of string
4861   | CallOptString of string option
4862   | CallStringList of string list
4863   | CallInt of int
4864   | CallInt64 of int64
4865   | CallBool of bool
4866
4867 (* Used to memoize the result of pod2text. *)
4868 let pod2text_memo_filename = "src/.pod2text.data"
4869 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4870   try
4871     let chan = open_in pod2text_memo_filename in
4872     let v = input_value chan in
4873     close_in chan;
4874     v
4875   with
4876     _ -> Hashtbl.create 13
4877 let pod2text_memo_updated () =
4878   let chan = open_out pod2text_memo_filename in
4879   output_value chan pod2text_memo;
4880   close_out chan
4881
4882 (* Useful functions.
4883  * Note we don't want to use any external OCaml libraries which
4884  * makes this a bit harder than it should be.
4885  *)
4886 module StringMap = Map.Make (String)
4887
4888 let failwithf fs = ksprintf failwith fs
4889
4890 let unique = let i = ref 0 in fun () -> incr i; !i
4891
4892 let replace_char s c1 c2 =
4893   let s2 = String.copy s in
4894   let r = ref false in
4895   for i = 0 to String.length s2 - 1 do
4896     if String.unsafe_get s2 i = c1 then (
4897       String.unsafe_set s2 i c2;
4898       r := true
4899     )
4900   done;
4901   if not !r then s else s2
4902
4903 let isspace c =
4904   c = ' '
4905   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4906
4907 let triml ?(test = isspace) str =
4908   let i = ref 0 in
4909   let n = ref (String.length str) in
4910   while !n > 0 && test str.[!i]; do
4911     decr n;
4912     incr i
4913   done;
4914   if !i = 0 then str
4915   else String.sub str !i !n
4916
4917 let trimr ?(test = isspace) str =
4918   let n = ref (String.length str) in
4919   while !n > 0 && test str.[!n-1]; do
4920     decr n
4921   done;
4922   if !n = String.length str then str
4923   else String.sub str 0 !n
4924
4925 let trim ?(test = isspace) str =
4926   trimr ~test (triml ~test str)
4927
4928 let rec find s sub =
4929   let len = String.length s in
4930   let sublen = String.length sub in
4931   let rec loop i =
4932     if i <= len-sublen then (
4933       let rec loop2 j =
4934         if j < sublen then (
4935           if s.[i+j] = sub.[j] then loop2 (j+1)
4936           else -1
4937         ) else
4938           i (* found *)
4939       in
4940       let r = loop2 0 in
4941       if r = -1 then loop (i+1) else r
4942     ) else
4943       -1 (* not found *)
4944   in
4945   loop 0
4946
4947 let rec replace_str s s1 s2 =
4948   let len = String.length s in
4949   let sublen = String.length s1 in
4950   let i = find s s1 in
4951   if i = -1 then s
4952   else (
4953     let s' = String.sub s 0 i in
4954     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4955     s' ^ s2 ^ replace_str s'' s1 s2
4956   )
4957
4958 let rec string_split sep str =
4959   let len = String.length str in
4960   let seplen = String.length sep in
4961   let i = find str sep in
4962   if i = -1 then [str]
4963   else (
4964     let s' = String.sub str 0 i in
4965     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4966     s' :: string_split sep s''
4967   )
4968
4969 let files_equal n1 n2 =
4970   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4971   match Sys.command cmd with
4972   | 0 -> true
4973   | 1 -> false
4974   | i -> failwithf "%s: failed with error code %d" cmd i
4975
4976 let rec filter_map f = function
4977   | [] -> []
4978   | x :: xs ->
4979       match f x with
4980       | Some y -> y :: filter_map f xs
4981       | None -> filter_map f xs
4982
4983 let rec find_map f = function
4984   | [] -> raise Not_found
4985   | x :: xs ->
4986       match f x with
4987       | Some y -> y
4988       | None -> find_map f xs
4989
4990 let iteri f xs =
4991   let rec loop i = function
4992     | [] -> ()
4993     | x :: xs -> f i x; loop (i+1) xs
4994   in
4995   loop 0 xs
4996
4997 let mapi f xs =
4998   let rec loop i = function
4999     | [] -> []
5000     | x :: xs -> let r = f i x in r :: loop (i+1) xs
5001   in
5002   loop 0 xs
5003
5004 let count_chars c str =
5005   let count = ref 0 in
5006   for i = 0 to String.length str - 1 do
5007     if c = String.unsafe_get str i then incr count
5008   done;
5009   !count
5010
5011 let name_of_argt = function
5012   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
5013   | StringList n | DeviceList n | Bool n | Int n | Int64 n
5014   | FileIn n | FileOut n -> n
5015
5016 let java_name_of_struct typ =
5017   try List.assoc typ java_structs
5018   with Not_found ->
5019     failwithf
5020       "java_name_of_struct: no java_structs entry corresponding to %s" typ
5021
5022 let cols_of_struct typ =
5023   try List.assoc typ structs
5024   with Not_found ->
5025     failwithf "cols_of_struct: unknown struct %s" typ
5026
5027 let seq_of_test = function
5028   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
5029   | TestOutputListOfDevices (s, _)
5030   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
5031   | TestOutputTrue s | TestOutputFalse s
5032   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
5033   | TestOutputStruct (s, _)
5034   | TestLastFail s -> s
5035
5036 (* Handling for function flags. *)
5037 let protocol_limit_warning =
5038   "Because of the message protocol, there is a transfer limit
5039 of somewhere between 2MB and 4MB.  See L<guestfs(3)/PROTOCOL LIMITS>."
5040
5041 let danger_will_robinson =
5042   "B<This command is dangerous.  Without careful use you
5043 can easily destroy all your data>."
5044
5045 let deprecation_notice flags =
5046   try
5047     let alt =
5048       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
5049     let txt =
5050       sprintf "This function is deprecated.
5051 In new code, use the C<%s> call instead.
5052
5053 Deprecated functions will not be removed from the API, but the
5054 fact that they are deprecated indicates that there are problems
5055 with correct use of these functions." alt in
5056     Some txt
5057   with
5058     Not_found -> None
5059
5060 (* Create list of optional groups. *)
5061 let optgroups =
5062   let h = Hashtbl.create 13 in
5063   List.iter (
5064     fun (name, _, _, flags, _, _, _) ->
5065       List.iter (
5066         function
5067         | Optional group ->
5068             let names = try Hashtbl.find h group with Not_found -> [] in
5069             Hashtbl.replace h group (name :: names)
5070         | _ -> ()
5071       ) flags
5072   ) daemon_functions;
5073   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
5074   let groups =
5075     List.map (
5076       fun group -> group, List.sort compare (Hashtbl.find h group)
5077     ) groups in
5078   List.sort (fun x y -> compare (fst x) (fst y)) groups
5079
5080 (* Check function names etc. for consistency. *)
5081 let check_functions () =
5082   let contains_uppercase str =
5083     let len = String.length str in
5084     let rec loop i =
5085       if i >= len then false
5086       else (
5087         let c = str.[i] in
5088         if c >= 'A' && c <= 'Z' then true
5089         else loop (i+1)
5090       )
5091     in
5092     loop 0
5093   in
5094
5095   (* Check function names. *)
5096   List.iter (
5097     fun (name, _, _, _, _, _, _) ->
5098       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
5099         failwithf "function name %s does not need 'guestfs' prefix" name;
5100       if name = "" then
5101         failwithf "function name is empty";
5102       if name.[0] < 'a' || name.[0] > 'z' then
5103         failwithf "function name %s must start with lowercase a-z" name;
5104       if String.contains name '-' then
5105         failwithf "function name %s should not contain '-', use '_' instead."
5106           name
5107   ) all_functions;
5108
5109   (* Check function parameter/return names. *)
5110   List.iter (
5111     fun (name, style, _, _, _, _, _) ->
5112       let check_arg_ret_name n =
5113         if contains_uppercase n then
5114           failwithf "%s param/ret %s should not contain uppercase chars"
5115             name n;
5116         if String.contains n '-' || String.contains n '_' then
5117           failwithf "%s param/ret %s should not contain '-' or '_'"
5118             name n;
5119         if n = "value" then
5120           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;
5121         if n = "int" || n = "char" || n = "short" || n = "long" then
5122           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
5123         if n = "i" || n = "n" then
5124           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
5125         if n = "argv" || n = "args" then
5126           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
5127
5128         (* List Haskell, OCaml and C keywords here.
5129          * http://www.haskell.org/haskellwiki/Keywords
5130          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
5131          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
5132          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
5133          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
5134          * Omitting _-containing words, since they're handled above.
5135          * Omitting the OCaml reserved word, "val", is ok,
5136          * and saves us from renaming several parameters.
5137          *)
5138         let reserved = [
5139           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
5140           "char"; "class"; "const"; "constraint"; "continue"; "data";
5141           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
5142           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
5143           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
5144           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
5145           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
5146           "interface";
5147           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
5148           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
5149           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
5150           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
5151           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
5152           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
5153           "volatile"; "when"; "where"; "while";
5154           ] in
5155         if List.mem n reserved then
5156           failwithf "%s has param/ret using reserved word %s" name n;
5157       in
5158
5159       (match fst style with
5160        | RErr -> ()
5161        | RInt n | RInt64 n | RBool n
5162        | RConstString n | RConstOptString n | RString n
5163        | RStringList n | RStruct (n, _) | RStructList (n, _)
5164        | RHashtable n | RBufferOut n ->
5165            check_arg_ret_name n
5166       );
5167       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
5168   ) all_functions;
5169
5170   (* Check short descriptions. *)
5171   List.iter (
5172     fun (name, _, _, _, _, shortdesc, _) ->
5173       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
5174         failwithf "short description of %s should begin with lowercase." name;
5175       let c = shortdesc.[String.length shortdesc-1] in
5176       if c = '\n' || c = '.' then
5177         failwithf "short description of %s should not end with . or \\n." name
5178   ) all_functions;
5179
5180   (* Check long descriptions. *)
5181   List.iter (
5182     fun (name, _, _, _, _, _, longdesc) ->
5183       if longdesc.[String.length longdesc-1] = '\n' then
5184         failwithf "long description of %s should not end with \\n." name
5185   ) all_functions;
5186
5187   (* Check proc_nrs. *)
5188   List.iter (
5189     fun (name, _, proc_nr, _, _, _, _) ->
5190       if proc_nr <= 0 then
5191         failwithf "daemon function %s should have proc_nr > 0" name
5192   ) daemon_functions;
5193
5194   List.iter (
5195     fun (name, _, proc_nr, _, _, _, _) ->
5196       if proc_nr <> -1 then
5197         failwithf "non-daemon function %s should have proc_nr -1" name
5198   ) non_daemon_functions;
5199
5200   let proc_nrs =
5201     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
5202       daemon_functions in
5203   let proc_nrs =
5204     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
5205   let rec loop = function
5206     | [] -> ()
5207     | [_] -> ()
5208     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
5209         loop rest
5210     | (name1,nr1) :: (name2,nr2) :: _ ->
5211         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
5212           name1 name2 nr1 nr2
5213   in
5214   loop proc_nrs;
5215
5216   (* Check tests. *)
5217   List.iter (
5218     function
5219       (* Ignore functions that have no tests.  We generate a
5220        * warning when the user does 'make check' instead.
5221        *)
5222     | name, _, _, _, [], _, _ -> ()
5223     | name, _, _, _, tests, _, _ ->
5224         let funcs =
5225           List.map (
5226             fun (_, _, test) ->
5227               match seq_of_test test with
5228               | [] ->
5229                   failwithf "%s has a test containing an empty sequence" name
5230               | cmds -> List.map List.hd cmds
5231           ) tests in
5232         let funcs = List.flatten funcs in
5233
5234         let tested = List.mem name funcs in
5235
5236         if not tested then
5237           failwithf "function %s has tests but does not test itself" name
5238   ) all_functions
5239
5240 (* 'pr' prints to the current output file. *)
5241 let chan = ref Pervasives.stdout
5242 let lines = ref 0
5243 let pr fs =
5244   ksprintf
5245     (fun str ->
5246        let i = count_chars '\n' str in
5247        lines := !lines + i;
5248        output_string !chan str
5249     ) fs
5250
5251 let copyright_years =
5252   let this_year = 1900 + (localtime (time ())).tm_year in
5253   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
5254
5255 (* Generate a header block in a number of standard styles. *)
5256 type comment_style =
5257     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
5258 type license = GPLv2plus | LGPLv2plus
5259
5260 let generate_header ?(extra_inputs = []) comment license =
5261   let inputs = "src/generator.ml" :: extra_inputs in
5262   let c = match comment with
5263     | CStyle ->         pr "/* "; " *"
5264     | CPlusPlusStyle -> pr "// "; "//"
5265     | HashStyle ->      pr "# ";  "#"
5266     | OCamlStyle ->     pr "(* "; " *"
5267     | HaskellStyle ->   pr "{- "; "  " in
5268   pr "libguestfs generated file\n";
5269   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
5270   List.iter (pr "%s   %s\n" c) inputs;
5271   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
5272   pr "%s\n" c;
5273   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
5274   pr "%s\n" c;
5275   (match license with
5276    | GPLv2plus ->
5277        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
5278        pr "%s it under the terms of the GNU General Public License as published by\n" c;
5279        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
5280        pr "%s (at your option) any later version.\n" c;
5281        pr "%s\n" c;
5282        pr "%s This program is distributed in the hope that it will be useful,\n" c;
5283        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5284        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
5285        pr "%s GNU General Public License for more details.\n" c;
5286        pr "%s\n" c;
5287        pr "%s You should have received a copy of the GNU General Public License along\n" c;
5288        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
5289        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
5290
5291    | LGPLv2plus ->
5292        pr "%s This library is free software; you can redistribute it and/or\n" c;
5293        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
5294        pr "%s License as published by the Free Software Foundation; either\n" c;
5295        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
5296        pr "%s\n" c;
5297        pr "%s This library is distributed in the hope that it will be useful,\n" c;
5298        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5299        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
5300        pr "%s Lesser General Public License for more details.\n" c;
5301        pr "%s\n" c;
5302        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
5303        pr "%s License along with this library; if not, write to the Free Software\n" c;
5304        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
5305   );
5306   (match comment with
5307    | CStyle -> pr " */\n"
5308    | CPlusPlusStyle
5309    | HashStyle -> ()
5310    | OCamlStyle -> pr " *)\n"
5311    | HaskellStyle -> pr "-}\n"
5312   );
5313   pr "\n"
5314
5315 (* Start of main code generation functions below this line. *)
5316
5317 (* Generate the pod documentation for the C API. *)
5318 let rec generate_actions_pod () =
5319   List.iter (
5320     fun (shortname, style, _, flags, _, _, longdesc) ->
5321       if not (List.mem NotInDocs flags) then (
5322         let name = "guestfs_" ^ shortname in
5323         pr "=head2 %s\n\n" name;
5324         pr " ";
5325         generate_prototype ~extern:false ~handle:"g" name style;
5326         pr "\n\n";
5327         pr "%s\n\n" longdesc;
5328         (match fst style with
5329          | RErr ->
5330              pr "This function returns 0 on success or -1 on error.\n\n"
5331          | RInt _ ->
5332              pr "On error this function returns -1.\n\n"
5333          | RInt64 _ ->
5334              pr "On error this function returns -1.\n\n"
5335          | RBool _ ->
5336              pr "This function returns a C truth value on success or -1 on error.\n\n"
5337          | RConstString _ ->
5338              pr "This function returns a string, or NULL on error.
5339 The string is owned by the guest handle and must I<not> be freed.\n\n"
5340          | RConstOptString _ ->
5341              pr "This function returns a string which may be NULL.
5342 There is way to return an error from this function.
5343 The string is owned by the guest handle and must I<not> be freed.\n\n"
5344          | RString _ ->
5345              pr "This function returns a string, or NULL on error.
5346 I<The caller must free the returned string after use>.\n\n"
5347          | RStringList _ ->
5348              pr "This function returns a NULL-terminated array of strings
5349 (like L<environ(3)>), or NULL if there was an error.
5350 I<The caller must free the strings and the array after use>.\n\n"
5351          | RStruct (_, typ) ->
5352              pr "This function returns a C<struct guestfs_%s *>,
5353 or NULL if there was an error.
5354 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
5355          | RStructList (_, typ) ->
5356              pr "This function returns a C<struct guestfs_%s_list *>
5357 (see E<lt>guestfs-structs.hE<gt>),
5358 or NULL if there was an error.
5359 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
5360          | RHashtable _ ->
5361              pr "This function returns a NULL-terminated array of
5362 strings, or NULL if there was an error.
5363 The array of strings will always have length C<2n+1>, where
5364 C<n> keys and values alternate, followed by the trailing NULL entry.
5365 I<The caller must free the strings and the array after use>.\n\n"
5366          | RBufferOut _ ->
5367              pr "This function returns a buffer, or NULL on error.
5368 The size of the returned buffer is written to C<*size_r>.
5369 I<The caller must free the returned buffer after use>.\n\n"
5370         );
5371         if List.mem ProtocolLimitWarning flags then
5372           pr "%s\n\n" protocol_limit_warning;
5373         if List.mem DangerWillRobinson flags then
5374           pr "%s\n\n" danger_will_robinson;
5375         match deprecation_notice flags with
5376         | None -> ()
5377         | Some txt -> pr "%s\n\n" txt
5378       )
5379   ) all_functions_sorted
5380
5381 and generate_structs_pod () =
5382   (* Structs documentation. *)
5383   List.iter (
5384     fun (typ, cols) ->
5385       pr "=head2 guestfs_%s\n" typ;
5386       pr "\n";
5387       pr " struct guestfs_%s {\n" typ;
5388       List.iter (
5389         function
5390         | name, FChar -> pr "   char %s;\n" name
5391         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5392         | name, FInt32 -> pr "   int32_t %s;\n" name
5393         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5394         | name, FInt64 -> pr "   int64_t %s;\n" name
5395         | name, FString -> pr "   char *%s;\n" name
5396         | name, FBuffer ->
5397             pr "   /* The next two fields describe a byte array. */\n";
5398             pr "   uint32_t %s_len;\n" name;
5399             pr "   char *%s;\n" name
5400         | name, FUUID ->
5401             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5402             pr "   char %s[32];\n" name
5403         | name, FOptPercent ->
5404             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5405             pr "   float %s;\n" name
5406       ) cols;
5407       pr " };\n";
5408       pr " \n";
5409       pr " struct guestfs_%s_list {\n" typ;
5410       pr "   uint32_t len; /* Number of elements in list. */\n";
5411       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5412       pr " };\n";
5413       pr " \n";
5414       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5415       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5416         typ typ;
5417       pr "\n"
5418   ) structs
5419
5420 and generate_availability_pod () =
5421   (* Availability documentation. *)
5422   pr "=over 4\n";
5423   pr "\n";
5424   List.iter (
5425     fun (group, functions) ->
5426       pr "=item B<%s>\n" group;
5427       pr "\n";
5428       pr "The following functions:\n";
5429       List.iter (pr "L</guestfs_%s>\n") functions;
5430       pr "\n"
5431   ) optgroups;
5432   pr "=back\n";
5433   pr "\n"
5434
5435 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5436  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5437  *
5438  * We have to use an underscore instead of a dash because otherwise
5439  * rpcgen generates incorrect code.
5440  *
5441  * This header is NOT exported to clients, but see also generate_structs_h.
5442  *)
5443 and generate_xdr () =
5444   generate_header CStyle LGPLv2plus;
5445
5446   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5447   pr "typedef string str<>;\n";
5448   pr "\n";
5449
5450   (* Internal structures. *)
5451   List.iter (
5452     function
5453     | typ, cols ->
5454         pr "struct guestfs_int_%s {\n" typ;
5455         List.iter (function
5456                    | name, FChar -> pr "  char %s;\n" name
5457                    | name, FString -> pr "  string %s<>;\n" name
5458                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5459                    | name, FUUID -> pr "  opaque %s[32];\n" name
5460                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5461                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5462                    | name, FOptPercent -> pr "  float %s;\n" name
5463                   ) cols;
5464         pr "};\n";
5465         pr "\n";
5466         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5467         pr "\n";
5468   ) structs;
5469
5470   List.iter (
5471     fun (shortname, style, _, _, _, _, _) ->
5472       let name = "guestfs_" ^ shortname in
5473
5474       (match snd style with
5475        | [] -> ()
5476        | args ->
5477            pr "struct %s_args {\n" name;
5478            List.iter (
5479              function
5480              | Pathname n | Device n | Dev_or_Path n | String n ->
5481                  pr "  string %s<>;\n" n
5482              | OptString n -> pr "  str *%s;\n" n
5483              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5484              | Bool n -> pr "  bool %s;\n" n
5485              | Int n -> pr "  int %s;\n" n
5486              | Int64 n -> pr "  hyper %s;\n" n
5487              | FileIn _ | FileOut _ -> ()
5488            ) args;
5489            pr "};\n\n"
5490       );
5491       (match fst style with
5492        | RErr -> ()
5493        | RInt n ->
5494            pr "struct %s_ret {\n" name;
5495            pr "  int %s;\n" n;
5496            pr "};\n\n"
5497        | RInt64 n ->
5498            pr "struct %s_ret {\n" name;
5499            pr "  hyper %s;\n" n;
5500            pr "};\n\n"
5501        | RBool n ->
5502            pr "struct %s_ret {\n" name;
5503            pr "  bool %s;\n" n;
5504            pr "};\n\n"
5505        | RConstString _ | RConstOptString _ ->
5506            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5507        | RString n ->
5508            pr "struct %s_ret {\n" name;
5509            pr "  string %s<>;\n" n;
5510            pr "};\n\n"
5511        | RStringList n ->
5512            pr "struct %s_ret {\n" name;
5513            pr "  str %s<>;\n" n;
5514            pr "};\n\n"
5515        | RStruct (n, typ) ->
5516            pr "struct %s_ret {\n" name;
5517            pr "  guestfs_int_%s %s;\n" typ n;
5518            pr "};\n\n"
5519        | RStructList (n, typ) ->
5520            pr "struct %s_ret {\n" name;
5521            pr "  guestfs_int_%s_list %s;\n" typ n;
5522            pr "};\n\n"
5523        | RHashtable n ->
5524            pr "struct %s_ret {\n" name;
5525            pr "  str %s<>;\n" n;
5526            pr "};\n\n"
5527        | RBufferOut n ->
5528            pr "struct %s_ret {\n" name;
5529            pr "  opaque %s<>;\n" n;
5530            pr "};\n\n"
5531       );
5532   ) daemon_functions;
5533
5534   (* Table of procedure numbers. *)
5535   pr "enum guestfs_procedure {\n";
5536   List.iter (
5537     fun (shortname, _, proc_nr, _, _, _, _) ->
5538       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5539   ) daemon_functions;
5540   pr "  GUESTFS_PROC_NR_PROCS\n";
5541   pr "};\n";
5542   pr "\n";
5543
5544   (* Having to choose a maximum message size is annoying for several
5545    * reasons (it limits what we can do in the API), but it (a) makes
5546    * the protocol a lot simpler, and (b) provides a bound on the size
5547    * of the daemon which operates in limited memory space.
5548    *)
5549   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5550   pr "\n";
5551
5552   (* Message header, etc. *)
5553   pr "\
5554 /* The communication protocol is now documented in the guestfs(3)
5555  * manpage.
5556  */
5557
5558 const GUESTFS_PROGRAM = 0x2000F5F5;
5559 const GUESTFS_PROTOCOL_VERSION = 1;
5560
5561 /* These constants must be larger than any possible message length. */
5562 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5563 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5564
5565 enum guestfs_message_direction {
5566   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5567   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5568 };
5569
5570 enum guestfs_message_status {
5571   GUESTFS_STATUS_OK = 0,
5572   GUESTFS_STATUS_ERROR = 1
5573 };
5574
5575 const GUESTFS_ERROR_LEN = 256;
5576
5577 struct guestfs_message_error {
5578   string error_message<GUESTFS_ERROR_LEN>;
5579 };
5580
5581 struct guestfs_message_header {
5582   unsigned prog;                     /* GUESTFS_PROGRAM */
5583   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5584   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5585   guestfs_message_direction direction;
5586   unsigned serial;                   /* message serial number */
5587   guestfs_message_status status;
5588 };
5589
5590 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5591
5592 struct guestfs_chunk {
5593   int cancel;                        /* if non-zero, transfer is cancelled */
5594   /* data size is 0 bytes if the transfer has finished successfully */
5595   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5596 };
5597 "
5598
5599 (* Generate the guestfs-structs.h file. *)
5600 and generate_structs_h () =
5601   generate_header CStyle LGPLv2plus;
5602
5603   (* This is a public exported header file containing various
5604    * structures.  The structures are carefully written to have
5605    * exactly the same in-memory format as the XDR structures that
5606    * we use on the wire to the daemon.  The reason for creating
5607    * copies of these structures here is just so we don't have to
5608    * export the whole of guestfs_protocol.h (which includes much
5609    * unrelated and XDR-dependent stuff that we don't want to be
5610    * public, or required by clients).
5611    *
5612    * To reiterate, we will pass these structures to and from the
5613    * client with a simple assignment or memcpy, so the format
5614    * must be identical to what rpcgen / the RFC defines.
5615    *)
5616
5617   (* Public structures. *)
5618   List.iter (
5619     fun (typ, cols) ->
5620       pr "struct guestfs_%s {\n" typ;
5621       List.iter (
5622         function
5623         | name, FChar -> pr "  char %s;\n" name
5624         | name, FString -> pr "  char *%s;\n" name
5625         | name, FBuffer ->
5626             pr "  uint32_t %s_len;\n" name;
5627             pr "  char *%s;\n" name
5628         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5629         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5630         | name, FInt32 -> pr "  int32_t %s;\n" name
5631         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5632         | name, FInt64 -> pr "  int64_t %s;\n" name
5633         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5634       ) cols;
5635       pr "};\n";
5636       pr "\n";
5637       pr "struct guestfs_%s_list {\n" typ;
5638       pr "  uint32_t len;\n";
5639       pr "  struct guestfs_%s *val;\n" typ;
5640       pr "};\n";
5641       pr "\n";
5642       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5643       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5644       pr "\n"
5645   ) structs
5646
5647 (* Generate the guestfs-actions.h file. *)
5648 and generate_actions_h () =
5649   generate_header CStyle LGPLv2plus;
5650   List.iter (
5651     fun (shortname, style, _, _, _, _, _) ->
5652       let name = "guestfs_" ^ shortname in
5653       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5654         name style
5655   ) all_functions
5656
5657 (* Generate the guestfs-internal-actions.h file. *)
5658 and generate_internal_actions_h () =
5659   generate_header CStyle LGPLv2plus;
5660   List.iter (
5661     fun (shortname, style, _, _, _, _, _) ->
5662       let name = "guestfs__" ^ shortname in
5663       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5664         name style
5665   ) non_daemon_functions
5666
5667 (* Generate the client-side dispatch stubs. *)
5668 and generate_client_actions () =
5669   generate_header CStyle LGPLv2plus;
5670
5671   pr "\
5672 #include <stdio.h>
5673 #include <stdlib.h>
5674 #include <stdint.h>
5675 #include <string.h>
5676 #include <inttypes.h>
5677
5678 #include \"guestfs.h\"
5679 #include \"guestfs-internal.h\"
5680 #include \"guestfs-internal-actions.h\"
5681 #include \"guestfs_protocol.h\"
5682
5683 #define error guestfs_error
5684 //#define perrorf guestfs_perrorf
5685 #define safe_malloc guestfs_safe_malloc
5686 #define safe_realloc guestfs_safe_realloc
5687 //#define safe_strdup guestfs_safe_strdup
5688 #define safe_memdup guestfs_safe_memdup
5689
5690 /* Check the return message from a call for validity. */
5691 static int
5692 check_reply_header (guestfs_h *g,
5693                     const struct guestfs_message_header *hdr,
5694                     unsigned int proc_nr, unsigned int serial)
5695 {
5696   if (hdr->prog != GUESTFS_PROGRAM) {
5697     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5698     return -1;
5699   }
5700   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5701     error (g, \"wrong protocol version (%%d/%%d)\",
5702            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5703     return -1;
5704   }
5705   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5706     error (g, \"unexpected message direction (%%d/%%d)\",
5707            hdr->direction, GUESTFS_DIRECTION_REPLY);
5708     return -1;
5709   }
5710   if (hdr->proc != proc_nr) {
5711     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5712     return -1;
5713   }
5714   if (hdr->serial != serial) {
5715     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5716     return -1;
5717   }
5718
5719   return 0;
5720 }
5721
5722 /* Check we are in the right state to run a high-level action. */
5723 static int
5724 check_state (guestfs_h *g, const char *caller)
5725 {
5726   if (!guestfs__is_ready (g)) {
5727     if (guestfs__is_config (g) || guestfs__is_launching (g))
5728       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5729         caller);
5730     else
5731       error (g, \"%%s called from the wrong state, %%d != READY\",
5732         caller, guestfs__get_state (g));
5733     return -1;
5734   }
5735   return 0;
5736 }
5737
5738 ";
5739
5740   (* Generate code to generate guestfish call traces. *)
5741   let trace_call shortname style =
5742     pr "  if (guestfs__get_trace (g)) {\n";
5743
5744     let needs_i =
5745       List.exists (function
5746                    | StringList _ | DeviceList _ -> true
5747                    | _ -> false) (snd style) in
5748     if needs_i then (
5749       pr "    int i;\n";
5750       pr "\n"
5751     );
5752
5753     pr "    printf (\"%s\");\n" shortname;
5754     List.iter (
5755       function
5756       | String n                        (* strings *)
5757       | Device n
5758       | Pathname n
5759       | Dev_or_Path n
5760       | FileIn n
5761       | FileOut n ->
5762           (* guestfish doesn't support string escaping, so neither do we *)
5763           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5764       | OptString n ->                  (* string option *)
5765           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5766           pr "    else printf (\" null\");\n"
5767       | StringList n
5768       | DeviceList n ->                 (* string list *)
5769           pr "    putchar (' ');\n";
5770           pr "    putchar ('\"');\n";
5771           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5772           pr "      if (i > 0) putchar (' ');\n";
5773           pr "      fputs (%s[i], stdout);\n" n;
5774           pr "    }\n";
5775           pr "    putchar ('\"');\n";
5776       | Bool n ->                       (* boolean *)
5777           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5778       | Int n ->                        (* int *)
5779           pr "    printf (\" %%d\", %s);\n" n
5780       | Int64 n ->
5781           pr "    printf (\" %%\" PRIi64, %s);\n" n
5782     ) (snd style);
5783     pr "    putchar ('\\n');\n";
5784     pr "  }\n";
5785     pr "\n";
5786   in
5787
5788   (* For non-daemon functions, generate a wrapper around each function. *)
5789   List.iter (
5790     fun (shortname, style, _, _, _, _, _) ->
5791       let name = "guestfs_" ^ shortname in
5792
5793       generate_prototype ~extern:false ~semicolon:false ~newline:true
5794         ~handle:"g" name style;
5795       pr "{\n";
5796       trace_call shortname style;
5797       pr "  return guestfs__%s " shortname;
5798       generate_c_call_args ~handle:"g" style;
5799       pr ";\n";
5800       pr "}\n";
5801       pr "\n"
5802   ) non_daemon_functions;
5803
5804   (* Client-side stubs for each function. *)
5805   List.iter (
5806     fun (shortname, style, _, _, _, _, _) ->
5807       let name = "guestfs_" ^ shortname in
5808
5809       (* Generate the action stub. *)
5810       generate_prototype ~extern:false ~semicolon:false ~newline:true
5811         ~handle:"g" name style;
5812
5813       let error_code =
5814         match fst style with
5815         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5816         | RConstString _ | RConstOptString _ ->
5817             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5818         | RString _ | RStringList _
5819         | RStruct _ | RStructList _
5820         | RHashtable _ | RBufferOut _ ->
5821             "NULL" in
5822
5823       pr "{\n";
5824
5825       (match snd style with
5826        | [] -> ()
5827        | _ -> pr "  struct %s_args args;\n" name
5828       );
5829
5830       pr "  guestfs_message_header hdr;\n";
5831       pr "  guestfs_message_error err;\n";
5832       let has_ret =
5833         match fst style with
5834         | RErr -> false
5835         | RConstString _ | RConstOptString _ ->
5836             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5837         | RInt _ | RInt64 _
5838         | RBool _ | RString _ | RStringList _
5839         | RStruct _ | RStructList _
5840         | RHashtable _ | RBufferOut _ ->
5841             pr "  struct %s_ret ret;\n" name;
5842             true in
5843
5844       pr "  int serial;\n";
5845       pr "  int r;\n";
5846       pr "\n";
5847       trace_call shortname style;
5848       pr "  if (check_state (g, \"%s\") == -1) return %s;\n"
5849         shortname error_code;
5850       pr "  guestfs___set_busy (g);\n";
5851       pr "\n";
5852
5853       (* Send the main header and arguments. *)
5854       (match snd style with
5855        | [] ->
5856            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5857              (String.uppercase shortname)
5858        | args ->
5859            List.iter (
5860              function
5861              | Pathname n | Device n | Dev_or_Path n | String n ->
5862                  pr "  args.%s = (char *) %s;\n" n n
5863              | OptString n ->
5864                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5865              | StringList n | DeviceList n ->
5866                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5867                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5868              | Bool n ->
5869                  pr "  args.%s = %s;\n" n n
5870              | Int n ->
5871                  pr "  args.%s = %s;\n" n n
5872              | Int64 n ->
5873                  pr "  args.%s = %s;\n" n n
5874              | FileIn _ | FileOut _ -> ()
5875            ) args;
5876            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5877              (String.uppercase shortname);
5878            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5879              name;
5880       );
5881       pr "  if (serial == -1) {\n";
5882       pr "    guestfs___end_busy (g);\n";
5883       pr "    return %s;\n" error_code;
5884       pr "  }\n";
5885       pr "\n";
5886
5887       (* Send any additional files (FileIn) requested. *)
5888       let need_read_reply_label = ref false in
5889       List.iter (
5890         function
5891         | FileIn n ->
5892             pr "  r = guestfs___send_file (g, %s);\n" n;
5893             pr "  if (r == -1) {\n";
5894             pr "    guestfs___end_busy (g);\n";
5895             pr "    return %s;\n" error_code;
5896             pr "  }\n";
5897             pr "  if (r == -2) /* daemon cancelled */\n";
5898             pr "    goto read_reply;\n";
5899             need_read_reply_label := true;
5900             pr "\n";
5901         | _ -> ()
5902       ) (snd style);
5903
5904       (* Wait for the reply from the remote end. *)
5905       if !need_read_reply_label then pr " read_reply:\n";
5906       pr "  memset (&hdr, 0, sizeof hdr);\n";
5907       pr "  memset (&err, 0, sizeof err);\n";
5908       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5909       pr "\n";
5910       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5911       if not has_ret then
5912         pr "NULL, NULL"
5913       else
5914         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5915       pr ");\n";
5916
5917       pr "  if (r == -1) {\n";
5918       pr "    guestfs___end_busy (g);\n";
5919       pr "    return %s;\n" error_code;
5920       pr "  }\n";
5921       pr "\n";
5922
5923       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5924         (String.uppercase shortname);
5925       pr "    guestfs___end_busy (g);\n";
5926       pr "    return %s;\n" error_code;
5927       pr "  }\n";
5928       pr "\n";
5929
5930       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5931       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5932       pr "    free (err.error_message);\n";
5933       pr "    guestfs___end_busy (g);\n";
5934       pr "    return %s;\n" error_code;
5935       pr "  }\n";
5936       pr "\n";
5937
5938       (* Expecting to receive further files (FileOut)? *)
5939       List.iter (
5940         function
5941         | FileOut n ->
5942             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5943             pr "    guestfs___end_busy (g);\n";
5944             pr "    return %s;\n" error_code;
5945             pr "  }\n";
5946             pr "\n";
5947         | _ -> ()
5948       ) (snd style);
5949
5950       pr "  guestfs___end_busy (g);\n";
5951
5952       (match fst style with
5953        | RErr -> pr "  return 0;\n"
5954        | RInt n | RInt64 n | RBool n ->
5955            pr "  return ret.%s;\n" n
5956        | RConstString _ | RConstOptString _ ->
5957            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5958        | RString n ->
5959            pr "  return ret.%s; /* caller will free */\n" n
5960        | RStringList n | RHashtable n ->
5961            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5962            pr "  ret.%s.%s_val =\n" n n;
5963            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5964            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5965              n n;
5966            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5967            pr "  return ret.%s.%s_val;\n" n n
5968        | RStruct (n, _) ->
5969            pr "  /* caller will free this */\n";
5970            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5971        | RStructList (n, _) ->
5972            pr "  /* caller will free this */\n";
5973            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5974        | RBufferOut n ->
5975            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5976            pr "   * _val might be NULL here.  To make the API saner for\n";
5977            pr "   * callers, we turn this case into a unique pointer (using\n";
5978            pr "   * malloc(1)).\n";
5979            pr "   */\n";
5980            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5981            pr "    *size_r = ret.%s.%s_len;\n" n n;
5982            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5983            pr "  } else {\n";
5984            pr "    free (ret.%s.%s_val);\n" n n;
5985            pr "    char *p = safe_malloc (g, 1);\n";
5986            pr "    *size_r = ret.%s.%s_len;\n" n n;
5987            pr "    return p;\n";
5988            pr "  }\n";
5989       );
5990
5991       pr "}\n\n"
5992   ) daemon_functions;
5993
5994   (* Functions to free structures. *)
5995   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5996   pr " * structure format is identical to the XDR format.  See note in\n";
5997   pr " * generator.ml.\n";
5998   pr " */\n";
5999   pr "\n";
6000
6001   List.iter (
6002     fun (typ, _) ->
6003       pr "void\n";
6004       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
6005       pr "{\n";
6006       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
6007       pr "  free (x);\n";
6008       pr "}\n";
6009       pr "\n";
6010
6011       pr "void\n";
6012       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
6013       pr "{\n";
6014       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
6015       pr "  free (x);\n";
6016       pr "}\n";
6017       pr "\n";
6018
6019   ) structs;
6020
6021 (* Generate daemon/actions.h. *)
6022 and generate_daemon_actions_h () =
6023   generate_header CStyle GPLv2plus;
6024
6025   pr "#include \"../src/guestfs_protocol.h\"\n";
6026   pr "\n";
6027
6028   List.iter (
6029     fun (name, style, _, _, _, _, _) ->
6030       generate_prototype
6031         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
6032         name style;
6033   ) daemon_functions
6034
6035 (* Generate the linker script which controls the visibility of
6036  * symbols in the public ABI and ensures no other symbols get
6037  * exported accidentally.
6038  *)
6039 and generate_linker_script () =
6040   generate_header HashStyle GPLv2plus;
6041
6042   let globals = [
6043     "guestfs_create";
6044     "guestfs_close";
6045     "guestfs_get_error_handler";
6046     "guestfs_get_out_of_memory_handler";
6047     "guestfs_last_error";
6048     "guestfs_set_error_handler";
6049     "guestfs_set_launch_done_callback";
6050     "guestfs_set_log_message_callback";
6051     "guestfs_set_out_of_memory_handler";
6052     "guestfs_set_subprocess_quit_callback";
6053
6054     (* Unofficial parts of the API: the bindings code use these
6055      * functions, so it is useful to export them.
6056      *)
6057     "guestfs_safe_calloc";
6058     "guestfs_safe_malloc";
6059   ] in
6060   let functions =
6061     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
6062       all_functions in
6063   let structs =
6064     List.concat (
6065       List.map (fun (typ, _) ->
6066                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
6067         structs
6068     ) in
6069   let globals = List.sort compare (globals @ functions @ structs) in
6070
6071   pr "{\n";
6072   pr "    global:\n";
6073   List.iter (pr "        %s;\n") globals;
6074   pr "\n";
6075
6076   pr "    local:\n";
6077   pr "        *;\n";
6078   pr "};\n"
6079
6080 (* Generate the server-side stubs. *)
6081 and generate_daemon_actions () =
6082   generate_header CStyle GPLv2plus;
6083
6084   pr "#include <config.h>\n";
6085   pr "\n";
6086   pr "#include <stdio.h>\n";
6087   pr "#include <stdlib.h>\n";
6088   pr "#include <string.h>\n";
6089   pr "#include <inttypes.h>\n";
6090   pr "#include <rpc/types.h>\n";
6091   pr "#include <rpc/xdr.h>\n";
6092   pr "\n";
6093   pr "#include \"daemon.h\"\n";
6094   pr "#include \"c-ctype.h\"\n";
6095   pr "#include \"../src/guestfs_protocol.h\"\n";
6096   pr "#include \"actions.h\"\n";
6097   pr "\n";
6098
6099   List.iter (
6100     fun (name, style, _, _, _, _, _) ->
6101       (* Generate server-side stubs. *)
6102       pr "static void %s_stub (XDR *xdr_in)\n" name;
6103       pr "{\n";
6104       let error_code =
6105         match fst style with
6106         | RErr | RInt _ -> pr "  int r;\n"; "-1"
6107         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6108         | RBool _ -> pr "  int r;\n"; "-1"
6109         | RConstString _ | RConstOptString _ ->
6110             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6111         | RString _ -> pr "  char *r;\n"; "NULL"
6112         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6113         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
6114         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
6115         | RBufferOut _ ->
6116             pr "  size_t size = 1;\n";
6117             pr "  char *r;\n";
6118             "NULL" in
6119
6120       (match snd style with
6121        | [] -> ()
6122        | args ->
6123            pr "  struct guestfs_%s_args args;\n" name;
6124            List.iter (
6125              function
6126              | Device n | Dev_or_Path n
6127              | Pathname n
6128              | String n -> ()
6129              | OptString n -> pr "  char *%s;\n" n
6130              | StringList n | DeviceList n -> pr "  char **%s;\n" n
6131              | Bool n -> pr "  int %s;\n" n
6132              | Int n -> pr "  int %s;\n" n
6133              | Int64 n -> pr "  int64_t %s;\n" n
6134              | FileIn _ | FileOut _ -> ()
6135            ) args
6136       );
6137       pr "\n";
6138
6139       let is_filein =
6140         List.exists (function FileIn _ -> true | _ -> false) (snd style) in
6141
6142       (match snd style with
6143        | [] -> ()
6144        | args ->
6145            pr "  memset (&args, 0, sizeof args);\n";
6146            pr "\n";
6147            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
6148            if is_filein then
6149              pr "    cancel_receive ();\n";
6150            pr "    reply_with_error (\"daemon failed to decode procedure arguments\");\n";
6151            pr "    goto done;\n";
6152            pr "  }\n";
6153            let pr_args n =
6154              pr "  char *%s = args.%s;\n" n n
6155            in
6156            let pr_list_handling_code n =
6157              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
6158              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
6159              pr "  if (%s == NULL) {\n" n;
6160              if is_filein then
6161                pr "    cancel_receive ();\n";
6162              pr "    reply_with_perror (\"realloc\");\n";
6163              pr "    goto done;\n";
6164              pr "  }\n";
6165              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
6166              pr "  args.%s.%s_val = %s;\n" n n n;
6167            in
6168            List.iter (
6169              function
6170              | Pathname n ->
6171                  pr_args n;
6172                  pr "  ABS_PATH (%s, %s, goto done);\n"
6173                    n (if is_filein then "cancel_receive ()" else "");
6174              | Device n ->
6175                  pr_args n;
6176                  pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
6177                    n (if is_filein then "cancel_receive ()" else "");
6178              | Dev_or_Path n ->
6179                  pr_args n;
6180                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
6181                    n (if is_filein then "cancel_receive ()" else "");
6182              | String n -> pr_args n
6183              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
6184              | StringList n ->
6185                  pr_list_handling_code n;
6186              | DeviceList n ->
6187                  pr_list_handling_code n;
6188                  pr "  /* Ensure that each is a device,\n";
6189                  pr "   * and perform device name translation. */\n";
6190                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
6191                  pr "    RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n"
6192                    (if is_filein then "cancel_receive ()" else "");
6193                  pr "  }\n";
6194              | Bool n -> pr "  %s = args.%s;\n" n n
6195              | Int n -> pr "  %s = args.%s;\n" n n
6196              | Int64 n -> pr "  %s = args.%s;\n" n n
6197              | FileIn _ | FileOut _ -> ()
6198            ) args;
6199            pr "\n"
6200       );
6201
6202
6203       (* this is used at least for do_equal *)
6204       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
6205         (* Emit NEED_ROOT just once, even when there are two or
6206            more Pathname args *)
6207         pr "  NEED_ROOT (%s, goto done);\n"
6208           (if is_filein then "cancel_receive ()" else "");
6209       );
6210
6211       (* Don't want to call the impl with any FileIn or FileOut
6212        * parameters, since these go "outside" the RPC protocol.
6213        *)
6214       let args' =
6215         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
6216           (snd style) in
6217       pr "  r = do_%s " name;
6218       generate_c_call_args (fst style, args');
6219       pr ";\n";
6220
6221       (match fst style with
6222        | RErr | RInt _ | RInt64 _ | RBool _
6223        | RConstString _ | RConstOptString _
6224        | RString _ | RStringList _ | RHashtable _
6225        | RStruct (_, _) | RStructList (_, _) ->
6226            pr "  if (r == %s)\n" error_code;
6227            pr "    /* do_%s has already called reply_with_error */\n" name;
6228            pr "    goto done;\n";
6229            pr "\n"
6230        | RBufferOut _ ->
6231            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
6232            pr "   * an ordinary zero-length buffer), so be careful ...\n";
6233            pr "   */\n";
6234            pr "  if (size == 1 && r == %s)\n" error_code;
6235            pr "    /* do_%s has already called reply_with_error */\n" name;
6236            pr "    goto done;\n";
6237            pr "\n"
6238       );
6239
6240       (* If there are any FileOut parameters, then the impl must
6241        * send its own reply.
6242        *)
6243       let no_reply =
6244         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
6245       if no_reply then
6246         pr "  /* do_%s has already sent a reply */\n" name
6247       else (
6248         match fst style with
6249         | RErr -> pr "  reply (NULL, NULL);\n"
6250         | RInt n | RInt64 n | RBool n ->
6251             pr "  struct guestfs_%s_ret ret;\n" name;
6252             pr "  ret.%s = r;\n" n;
6253             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6254               name
6255         | RConstString _ | RConstOptString _ ->
6256             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6257         | RString n ->
6258             pr "  struct guestfs_%s_ret ret;\n" name;
6259             pr "  ret.%s = r;\n" n;
6260             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6261               name;
6262             pr "  free (r);\n"
6263         | RStringList n | RHashtable n ->
6264             pr "  struct guestfs_%s_ret ret;\n" name;
6265             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
6266             pr "  ret.%s.%s_val = r;\n" n n;
6267             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6268               name;
6269             pr "  free_strings (r);\n"
6270         | RStruct (n, _) ->
6271             pr "  struct guestfs_%s_ret ret;\n" name;
6272             pr "  ret.%s = *r;\n" n;
6273             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6274               name;
6275             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6276               name
6277         | RStructList (n, _) ->
6278             pr "  struct guestfs_%s_ret ret;\n" name;
6279             pr "  ret.%s = *r;\n" n;
6280             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6281               name;
6282             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6283               name
6284         | RBufferOut n ->
6285             pr "  struct guestfs_%s_ret ret;\n" name;
6286             pr "  ret.%s.%s_val = r;\n" n n;
6287             pr "  ret.%s.%s_len = size;\n" n n;
6288             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6289               name;
6290             pr "  free (r);\n"
6291       );
6292
6293       (* Free the args. *)
6294       pr "done:\n";
6295       (match snd style with
6296        | [] -> ()
6297        | _ ->
6298            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
6299              name
6300       );
6301       pr "  return;\n";
6302       pr "}\n\n";
6303   ) daemon_functions;
6304
6305   (* Dispatch function. *)
6306   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
6307   pr "{\n";
6308   pr "  switch (proc_nr) {\n";
6309
6310   List.iter (
6311     fun (name, style, _, _, _, _, _) ->
6312       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
6313       pr "      %s_stub (xdr_in);\n" name;
6314       pr "      break;\n"
6315   ) daemon_functions;
6316
6317   pr "    default:\n";
6318   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";
6319   pr "  }\n";
6320   pr "}\n";
6321   pr "\n";
6322
6323   (* LVM columns and tokenization functions. *)
6324   (* XXX This generates crap code.  We should rethink how we
6325    * do this parsing.
6326    *)
6327   List.iter (
6328     function
6329     | typ, cols ->
6330         pr "static const char *lvm_%s_cols = \"%s\";\n"
6331           typ (String.concat "," (List.map fst cols));
6332         pr "\n";
6333
6334         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
6335         pr "{\n";
6336         pr "  char *tok, *p, *next;\n";
6337         pr "  int i, j;\n";
6338         pr "\n";
6339         (*
6340           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
6341           pr "\n";
6342         *)
6343         pr "  if (!str) {\n";
6344         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
6345         pr "    return -1;\n";
6346         pr "  }\n";
6347         pr "  if (!*str || c_isspace (*str)) {\n";
6348         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
6349         pr "    return -1;\n";
6350         pr "  }\n";
6351         pr "  tok = str;\n";
6352         List.iter (
6353           fun (name, coltype) ->
6354             pr "  if (!tok) {\n";
6355             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
6356             pr "    return -1;\n";
6357             pr "  }\n";
6358             pr "  p = strchrnul (tok, ',');\n";
6359             pr "  if (*p) next = p+1; else next = NULL;\n";
6360             pr "  *p = '\\0';\n";
6361             (match coltype with
6362              | FString ->
6363                  pr "  r->%s = strdup (tok);\n" name;
6364                  pr "  if (r->%s == NULL) {\n" name;
6365                  pr "    perror (\"strdup\");\n";
6366                  pr "    return -1;\n";
6367                  pr "  }\n"
6368              | FUUID ->
6369                  pr "  for (i = j = 0; i < 32; ++j) {\n";
6370                  pr "    if (tok[j] == '\\0') {\n";
6371                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
6372                  pr "      return -1;\n";
6373                  pr "    } else if (tok[j] != '-')\n";
6374                  pr "      r->%s[i++] = tok[j];\n" name;
6375                  pr "  }\n";
6376              | FBytes ->
6377                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
6378                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6379                  pr "    return -1;\n";
6380                  pr "  }\n";
6381              | FInt64 ->
6382                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
6383                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6384                  pr "    return -1;\n";
6385                  pr "  }\n";
6386              | FOptPercent ->
6387                  pr "  if (tok[0] == '\\0')\n";
6388                  pr "    r->%s = -1;\n" name;
6389                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
6390                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6391                  pr "    return -1;\n";
6392                  pr "  }\n";
6393              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
6394                  assert false (* can never be an LVM column *)
6395             );
6396             pr "  tok = next;\n";
6397         ) cols;
6398
6399         pr "  if (tok != NULL) {\n";
6400         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6401         pr "    return -1;\n";
6402         pr "  }\n";
6403         pr "  return 0;\n";
6404         pr "}\n";
6405         pr "\n";
6406
6407         pr "guestfs_int_lvm_%s_list *\n" typ;
6408         pr "parse_command_line_%ss (void)\n" typ;
6409         pr "{\n";
6410         pr "  char *out, *err;\n";
6411         pr "  char *p, *pend;\n";
6412         pr "  int r, i;\n";
6413         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6414         pr "  void *newp;\n";
6415         pr "\n";
6416         pr "  ret = malloc (sizeof *ret);\n";
6417         pr "  if (!ret) {\n";
6418         pr "    reply_with_perror (\"malloc\");\n";
6419         pr "    return NULL;\n";
6420         pr "  }\n";
6421         pr "\n";
6422         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6423         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6424         pr "\n";
6425         pr "  r = command (&out, &err,\n";
6426         pr "           \"lvm\", \"%ss\",\n" typ;
6427         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6428         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6429         pr "  if (r == -1) {\n";
6430         pr "    reply_with_error (\"%%s\", err);\n";
6431         pr "    free (out);\n";
6432         pr "    free (err);\n";
6433         pr "    free (ret);\n";
6434         pr "    return NULL;\n";
6435         pr "  }\n";
6436         pr "\n";
6437         pr "  free (err);\n";
6438         pr "\n";
6439         pr "  /* Tokenize each line of the output. */\n";
6440         pr "  p = out;\n";
6441         pr "  i = 0;\n";
6442         pr "  while (p) {\n";
6443         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6444         pr "    if (pend) {\n";
6445         pr "      *pend = '\\0';\n";
6446         pr "      pend++;\n";
6447         pr "    }\n";
6448         pr "\n";
6449         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6450         pr "      p++;\n";
6451         pr "\n";
6452         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6453         pr "      p = pend;\n";
6454         pr "      continue;\n";
6455         pr "    }\n";
6456         pr "\n";
6457         pr "    /* Allocate some space to store this next entry. */\n";
6458         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6459         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6460         pr "    if (newp == NULL) {\n";
6461         pr "      reply_with_perror (\"realloc\");\n";
6462         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6463         pr "      free (ret);\n";
6464         pr "      free (out);\n";
6465         pr "      return NULL;\n";
6466         pr "    }\n";
6467         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6468         pr "\n";
6469         pr "    /* Tokenize the next entry. */\n";
6470         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6471         pr "    if (r == -1) {\n";
6472         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6473         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6474         pr "      free (ret);\n";
6475         pr "      free (out);\n";
6476         pr "      return NULL;\n";
6477         pr "    }\n";
6478         pr "\n";
6479         pr "    ++i;\n";
6480         pr "    p = pend;\n";
6481         pr "  }\n";
6482         pr "\n";
6483         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6484         pr "\n";
6485         pr "  free (out);\n";
6486         pr "  return ret;\n";
6487         pr "}\n"
6488
6489   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6490
6491 (* Generate a list of function names, for debugging in the daemon.. *)
6492 and generate_daemon_names () =
6493   generate_header CStyle GPLv2plus;
6494
6495   pr "#include <config.h>\n";
6496   pr "\n";
6497   pr "#include \"daemon.h\"\n";
6498   pr "\n";
6499
6500   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6501   pr "const char *function_names[] = {\n";
6502   List.iter (
6503     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6504   ) daemon_functions;
6505   pr "};\n";
6506
6507 (* Generate the optional groups for the daemon to implement
6508  * guestfs_available.
6509  *)
6510 and generate_daemon_optgroups_c () =
6511   generate_header CStyle GPLv2plus;
6512
6513   pr "#include <config.h>\n";
6514   pr "\n";
6515   pr "#include \"daemon.h\"\n";
6516   pr "#include \"optgroups.h\"\n";
6517   pr "\n";
6518
6519   pr "struct optgroup optgroups[] = {\n";
6520   List.iter (
6521     fun (group, _) ->
6522       pr "  { \"%s\", optgroup_%s_available },\n" group group
6523   ) optgroups;
6524   pr "  { NULL, NULL }\n";
6525   pr "};\n"
6526
6527 and generate_daemon_optgroups_h () =
6528   generate_header CStyle GPLv2plus;
6529
6530   List.iter (
6531     fun (group, _) ->
6532       pr "extern int optgroup_%s_available (void);\n" group
6533   ) optgroups
6534
6535 (* Generate the tests. *)
6536 and generate_tests () =
6537   generate_header CStyle GPLv2plus;
6538
6539   pr "\
6540 #include <stdio.h>
6541 #include <stdlib.h>
6542 #include <string.h>
6543 #include <unistd.h>
6544 #include <sys/types.h>
6545 #include <fcntl.h>
6546
6547 #include \"guestfs.h\"
6548 #include \"guestfs-internal.h\"
6549
6550 static guestfs_h *g;
6551 static int suppress_error = 0;
6552
6553 static void print_error (guestfs_h *g, void *data, const char *msg)
6554 {
6555   if (!suppress_error)
6556     fprintf (stderr, \"%%s\\n\", msg);
6557 }
6558
6559 /* FIXME: nearly identical code appears in fish.c */
6560 static void print_strings (char *const *argv)
6561 {
6562   int argc;
6563
6564   for (argc = 0; argv[argc] != NULL; ++argc)
6565     printf (\"\\t%%s\\n\", argv[argc]);
6566 }
6567
6568 /*
6569 static void print_table (char const *const *argv)
6570 {
6571   int i;
6572
6573   for (i = 0; argv[i] != NULL; i += 2)
6574     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6575 }
6576 */
6577
6578 ";
6579
6580   (* Generate a list of commands which are not tested anywhere. *)
6581   pr "static void no_test_warnings (void)\n";
6582   pr "{\n";
6583
6584   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6585   List.iter (
6586     fun (_, _, _, _, tests, _, _) ->
6587       let tests = filter_map (
6588         function
6589         | (_, (Always|If _|Unless _), test) -> Some test
6590         | (_, Disabled, _) -> None
6591       ) tests in
6592       let seq = List.concat (List.map seq_of_test tests) in
6593       let cmds_tested = List.map List.hd seq in
6594       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6595   ) all_functions;
6596
6597   List.iter (
6598     fun (name, _, _, _, _, _, _) ->
6599       if not (Hashtbl.mem hash name) then
6600         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6601   ) all_functions;
6602
6603   pr "}\n";
6604   pr "\n";
6605
6606   (* Generate the actual tests.  Note that we generate the tests
6607    * in reverse order, deliberately, so that (in general) the
6608    * newest tests run first.  This makes it quicker and easier to
6609    * debug them.
6610    *)
6611   let test_names =
6612     List.map (
6613       fun (name, _, _, flags, tests, _, _) ->
6614         mapi (generate_one_test name flags) tests
6615     ) (List.rev all_functions) in
6616   let test_names = List.concat test_names in
6617   let nr_tests = List.length test_names in
6618
6619   pr "\
6620 int main (int argc, char *argv[])
6621 {
6622   char c = 0;
6623   unsigned long int n_failed = 0;
6624   const char *filename;
6625   int fd;
6626   int nr_tests, test_num = 0;
6627
6628   setbuf (stdout, NULL);
6629
6630   no_test_warnings ();
6631
6632   g = guestfs_create ();
6633   if (g == NULL) {
6634     printf (\"guestfs_create FAILED\\n\");
6635     exit (EXIT_FAILURE);
6636   }
6637
6638   guestfs_set_error_handler (g, print_error, NULL);
6639
6640   guestfs_set_path (g, \"../appliance\");
6641
6642   filename = \"test1.img\";
6643   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6644   if (fd == -1) {
6645     perror (filename);
6646     exit (EXIT_FAILURE);
6647   }
6648   if (lseek (fd, %d, SEEK_SET) == -1) {
6649     perror (\"lseek\");
6650     close (fd);
6651     unlink (filename);
6652     exit (EXIT_FAILURE);
6653   }
6654   if (write (fd, &c, 1) == -1) {
6655     perror (\"write\");
6656     close (fd);
6657     unlink (filename);
6658     exit (EXIT_FAILURE);
6659   }
6660   if (close (fd) == -1) {
6661     perror (filename);
6662     unlink (filename);
6663     exit (EXIT_FAILURE);
6664   }
6665   if (guestfs_add_drive (g, filename) == -1) {
6666     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6667     exit (EXIT_FAILURE);
6668   }
6669
6670   filename = \"test2.img\";
6671   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6672   if (fd == -1) {
6673     perror (filename);
6674     exit (EXIT_FAILURE);
6675   }
6676   if (lseek (fd, %d, SEEK_SET) == -1) {
6677     perror (\"lseek\");
6678     close (fd);
6679     unlink (filename);
6680     exit (EXIT_FAILURE);
6681   }
6682   if (write (fd, &c, 1) == -1) {
6683     perror (\"write\");
6684     close (fd);
6685     unlink (filename);
6686     exit (EXIT_FAILURE);
6687   }
6688   if (close (fd) == -1) {
6689     perror (filename);
6690     unlink (filename);
6691     exit (EXIT_FAILURE);
6692   }
6693   if (guestfs_add_drive (g, filename) == -1) {
6694     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6695     exit (EXIT_FAILURE);
6696   }
6697
6698   filename = \"test3.img\";
6699   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6700   if (fd == -1) {
6701     perror (filename);
6702     exit (EXIT_FAILURE);
6703   }
6704   if (lseek (fd, %d, SEEK_SET) == -1) {
6705     perror (\"lseek\");
6706     close (fd);
6707     unlink (filename);
6708     exit (EXIT_FAILURE);
6709   }
6710   if (write (fd, &c, 1) == -1) {
6711     perror (\"write\");
6712     close (fd);
6713     unlink (filename);
6714     exit (EXIT_FAILURE);
6715   }
6716   if (close (fd) == -1) {
6717     perror (filename);
6718     unlink (filename);
6719     exit (EXIT_FAILURE);
6720   }
6721   if (guestfs_add_drive (g, filename) == -1) {
6722     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6723     exit (EXIT_FAILURE);
6724   }
6725
6726   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6727     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6728     exit (EXIT_FAILURE);
6729   }
6730
6731   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6732   alarm (600);
6733
6734   if (guestfs_launch (g) == -1) {
6735     printf (\"guestfs_launch FAILED\\n\");
6736     exit (EXIT_FAILURE);
6737   }
6738
6739   /* Cancel previous alarm. */
6740   alarm (0);
6741
6742   nr_tests = %d;
6743
6744 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6745
6746   iteri (
6747     fun i test_name ->
6748       pr "  test_num++;\n";
6749       pr "  if (guestfs_get_verbose (g))\n";
6750       pr "    printf (\"-------------------------------------------------------------------------------\\n\");\n";
6751       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6752       pr "  if (%s () == -1) {\n" test_name;
6753       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6754       pr "    n_failed++;\n";
6755       pr "  }\n";
6756   ) test_names;
6757   pr "\n";
6758
6759   pr "  guestfs_close (g);\n";
6760   pr "  unlink (\"test1.img\");\n";
6761   pr "  unlink (\"test2.img\");\n";
6762   pr "  unlink (\"test3.img\");\n";
6763   pr "\n";
6764
6765   pr "  if (n_failed > 0) {\n";
6766   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6767   pr "    exit (EXIT_FAILURE);\n";
6768   pr "  }\n";
6769   pr "\n";
6770
6771   pr "  exit (EXIT_SUCCESS);\n";
6772   pr "}\n"
6773
6774 and generate_one_test name flags i (init, prereq, test) =
6775   let test_name = sprintf "test_%s_%d" name i in
6776
6777   pr "\
6778 static int %s_skip (void)
6779 {
6780   const char *str;
6781
6782   str = getenv (\"TEST_ONLY\");
6783   if (str)
6784     return strstr (str, \"%s\") == NULL;
6785   str = getenv (\"SKIP_%s\");
6786   if (str && STREQ (str, \"1\")) return 1;
6787   str = getenv (\"SKIP_TEST_%s\");
6788   if (str && STREQ (str, \"1\")) return 1;
6789   return 0;
6790 }
6791
6792 " test_name name (String.uppercase test_name) (String.uppercase name);
6793
6794   (match prereq with
6795    | Disabled | Always -> ()
6796    | If code | Unless code ->
6797        pr "static int %s_prereq (void)\n" test_name;
6798        pr "{\n";
6799        pr "  %s\n" code;
6800        pr "}\n";
6801        pr "\n";
6802   );
6803
6804   pr "\
6805 static int %s (void)
6806 {
6807   if (%s_skip ()) {
6808     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6809     return 0;
6810   }
6811
6812 " test_name test_name test_name;
6813
6814   (* Optional functions should only be tested if the relevant
6815    * support is available in the daemon.
6816    *)
6817   List.iter (
6818     function
6819     | Optional group ->
6820         pr "  {\n";
6821         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6822         pr "    int r;\n";
6823         pr "    suppress_error = 1;\n";
6824         pr "    r = guestfs_available (g, (char **) groups);\n";
6825         pr "    suppress_error = 0;\n";
6826         pr "    if (r == -1) {\n";
6827         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6828         pr "      return 0;\n";
6829         pr "    }\n";
6830         pr "  }\n";
6831     | _ -> ()
6832   ) flags;
6833
6834   (match prereq with
6835    | Disabled ->
6836        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6837    | If _ ->
6838        pr "  if (! %s_prereq ()) {\n" test_name;
6839        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6840        pr "    return 0;\n";
6841        pr "  }\n";
6842        pr "\n";
6843        generate_one_test_body name i test_name init test;
6844    | Unless _ ->
6845        pr "  if (%s_prereq ()) {\n" test_name;
6846        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6847        pr "    return 0;\n";
6848        pr "  }\n";
6849        pr "\n";
6850        generate_one_test_body name i test_name init test;
6851    | Always ->
6852        generate_one_test_body name i test_name init test
6853   );
6854
6855   pr "  return 0;\n";
6856   pr "}\n";
6857   pr "\n";
6858   test_name
6859
6860 and generate_one_test_body name i test_name init test =
6861   (match init with
6862    | InitNone (* XXX at some point, InitNone and InitEmpty became
6863                * folded together as the same thing.  Really we should
6864                * make InitNone do nothing at all, but the tests may
6865                * need to be checked to make sure this is OK.
6866                *)
6867    | InitEmpty ->
6868        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6869        List.iter (generate_test_command_call test_name)
6870          [["blockdev_setrw"; "/dev/sda"];
6871           ["umount_all"];
6872           ["lvm_remove_all"]]
6873    | InitPartition ->
6874        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6875        List.iter (generate_test_command_call test_name)
6876          [["blockdev_setrw"; "/dev/sda"];
6877           ["umount_all"];
6878           ["lvm_remove_all"];
6879           ["part_disk"; "/dev/sda"; "mbr"]]
6880    | InitBasicFS ->
6881        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6882        List.iter (generate_test_command_call test_name)
6883          [["blockdev_setrw"; "/dev/sda"];
6884           ["umount_all"];
6885           ["lvm_remove_all"];
6886           ["part_disk"; "/dev/sda"; "mbr"];
6887           ["mkfs"; "ext2"; "/dev/sda1"];
6888           ["mount_options"; ""; "/dev/sda1"; "/"]]
6889    | InitBasicFSonLVM ->
6890        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6891          test_name;
6892        List.iter (generate_test_command_call test_name)
6893          [["blockdev_setrw"; "/dev/sda"];
6894           ["umount_all"];
6895           ["lvm_remove_all"];
6896           ["part_disk"; "/dev/sda"; "mbr"];
6897           ["pvcreate"; "/dev/sda1"];
6898           ["vgcreate"; "VG"; "/dev/sda1"];
6899           ["lvcreate"; "LV"; "VG"; "8"];
6900           ["mkfs"; "ext2"; "/dev/VG/LV"];
6901           ["mount_options"; ""; "/dev/VG/LV"; "/"]]
6902    | InitISOFS ->
6903        pr "  /* InitISOFS for %s */\n" test_name;
6904        List.iter (generate_test_command_call test_name)
6905          [["blockdev_setrw"; "/dev/sda"];
6906           ["umount_all"];
6907           ["lvm_remove_all"];
6908           ["mount_ro"; "/dev/sdd"; "/"]]
6909   );
6910
6911   let get_seq_last = function
6912     | [] ->
6913         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6914           test_name
6915     | seq ->
6916         let seq = List.rev seq in
6917         List.rev (List.tl seq), List.hd seq
6918   in
6919
6920   match test with
6921   | TestRun seq ->
6922       pr "  /* TestRun for %s (%d) */\n" name i;
6923       List.iter (generate_test_command_call test_name) seq
6924   | TestOutput (seq, expected) ->
6925       pr "  /* TestOutput for %s (%d) */\n" name i;
6926       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6927       let seq, last = get_seq_last seq in
6928       let test () =
6929         pr "    if (STRNEQ (r, expected)) {\n";
6930         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6931         pr "      return -1;\n";
6932         pr "    }\n"
6933       in
6934       List.iter (generate_test_command_call test_name) seq;
6935       generate_test_command_call ~test test_name last
6936   | TestOutputList (seq, expected) ->
6937       pr "  /* TestOutputList for %s (%d) */\n" name i;
6938       let seq, last = get_seq_last seq in
6939       let test () =
6940         iteri (
6941           fun i str ->
6942             pr "    if (!r[%d]) {\n" i;
6943             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6944             pr "      print_strings (r);\n";
6945             pr "      return -1;\n";
6946             pr "    }\n";
6947             pr "    {\n";
6948             pr "      const char *expected = \"%s\";\n" (c_quote str);
6949             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6950             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6951             pr "        return -1;\n";
6952             pr "      }\n";
6953             pr "    }\n"
6954         ) expected;
6955         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6956         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6957           test_name;
6958         pr "      print_strings (r);\n";
6959         pr "      return -1;\n";
6960         pr "    }\n"
6961       in
6962       List.iter (generate_test_command_call test_name) seq;
6963       generate_test_command_call ~test test_name last
6964   | TestOutputListOfDevices (seq, expected) ->
6965       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6966       let seq, last = get_seq_last seq in
6967       let test () =
6968         iteri (
6969           fun i str ->
6970             pr "    if (!r[%d]) {\n" i;
6971             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6972             pr "      print_strings (r);\n";
6973             pr "      return -1;\n";
6974             pr "    }\n";
6975             pr "    {\n";
6976             pr "      const char *expected = \"%s\";\n" (c_quote str);
6977             pr "      r[%d][5] = 's';\n" i;
6978             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6979             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6980             pr "        return -1;\n";
6981             pr "      }\n";
6982             pr "    }\n"
6983         ) expected;
6984         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6985         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6986           test_name;
6987         pr "      print_strings (r);\n";
6988         pr "      return -1;\n";
6989         pr "    }\n"
6990       in
6991       List.iter (generate_test_command_call test_name) seq;
6992       generate_test_command_call ~test test_name last
6993   | TestOutputInt (seq, expected) ->
6994       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6995       let seq, last = get_seq_last seq in
6996       let test () =
6997         pr "    if (r != %d) {\n" expected;
6998         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6999           test_name expected;
7000         pr "               (int) r);\n";
7001         pr "      return -1;\n";
7002         pr "    }\n"
7003       in
7004       List.iter (generate_test_command_call test_name) seq;
7005       generate_test_command_call ~test test_name last
7006   | TestOutputIntOp (seq, op, expected) ->
7007       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
7008       let seq, last = get_seq_last seq in
7009       let test () =
7010         pr "    if (! (r %s %d)) {\n" op expected;
7011         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
7012           test_name op expected;
7013         pr "               (int) r);\n";
7014         pr "      return -1;\n";
7015         pr "    }\n"
7016       in
7017       List.iter (generate_test_command_call test_name) seq;
7018       generate_test_command_call ~test test_name last
7019   | TestOutputTrue seq ->
7020       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
7021       let seq, last = get_seq_last seq in
7022       let test () =
7023         pr "    if (!r) {\n";
7024         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
7025           test_name;
7026         pr "      return -1;\n";
7027         pr "    }\n"
7028       in
7029       List.iter (generate_test_command_call test_name) seq;
7030       generate_test_command_call ~test test_name last
7031   | TestOutputFalse seq ->
7032       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
7033       let seq, last = get_seq_last seq in
7034       let test () =
7035         pr "    if (r) {\n";
7036         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
7037           test_name;
7038         pr "      return -1;\n";
7039         pr "    }\n"
7040       in
7041       List.iter (generate_test_command_call test_name) seq;
7042       generate_test_command_call ~test test_name last
7043   | TestOutputLength (seq, expected) ->
7044       pr "  /* TestOutputLength for %s (%d) */\n" name i;
7045       let seq, last = get_seq_last seq in
7046       let test () =
7047         pr "    int j;\n";
7048         pr "    for (j = 0; j < %d; ++j)\n" expected;
7049         pr "      if (r[j] == NULL) {\n";
7050         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
7051           test_name;
7052         pr "        print_strings (r);\n";
7053         pr "        return -1;\n";
7054         pr "      }\n";
7055         pr "    if (r[j] != NULL) {\n";
7056         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
7057           test_name;
7058         pr "      print_strings (r);\n";
7059         pr "      return -1;\n";
7060         pr "    }\n"
7061       in
7062       List.iter (generate_test_command_call test_name) seq;
7063       generate_test_command_call ~test test_name last
7064   | TestOutputBuffer (seq, expected) ->
7065       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
7066       pr "  const char *expected = \"%s\";\n" (c_quote expected);
7067       let seq, last = get_seq_last seq in
7068       let len = String.length expected in
7069       let test () =
7070         pr "    if (size != %d) {\n" len;
7071         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
7072         pr "      return -1;\n";
7073         pr "    }\n";
7074         pr "    if (STRNEQLEN (r, expected, size)) {\n";
7075         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
7076         pr "      return -1;\n";
7077         pr "    }\n"
7078       in
7079       List.iter (generate_test_command_call test_name) seq;
7080       generate_test_command_call ~test test_name last
7081   | TestOutputStruct (seq, checks) ->
7082       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
7083       let seq, last = get_seq_last seq in
7084       let test () =
7085         List.iter (
7086           function
7087           | CompareWithInt (field, expected) ->
7088               pr "    if (r->%s != %d) {\n" field expected;
7089               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
7090                 test_name field expected;
7091               pr "               (int) r->%s);\n" field;
7092               pr "      return -1;\n";
7093               pr "    }\n"
7094           | CompareWithIntOp (field, op, expected) ->
7095               pr "    if (!(r->%s %s %d)) {\n" field op expected;
7096               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
7097                 test_name field op expected;
7098               pr "               (int) r->%s);\n" field;
7099               pr "      return -1;\n";
7100               pr "    }\n"
7101           | CompareWithString (field, expected) ->
7102               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
7103               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
7104                 test_name field expected;
7105               pr "               r->%s);\n" field;
7106               pr "      return -1;\n";
7107               pr "    }\n"
7108           | CompareFieldsIntEq (field1, field2) ->
7109               pr "    if (r->%s != r->%s) {\n" field1 field2;
7110               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
7111                 test_name field1 field2;
7112               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
7113               pr "      return -1;\n";
7114               pr "    }\n"
7115           | CompareFieldsStrEq (field1, field2) ->
7116               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
7117               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
7118                 test_name field1 field2;
7119               pr "               r->%s, r->%s);\n" field1 field2;
7120               pr "      return -1;\n";
7121               pr "    }\n"
7122         ) checks
7123       in
7124       List.iter (generate_test_command_call test_name) seq;
7125       generate_test_command_call ~test test_name last
7126   | TestLastFail seq ->
7127       pr "  /* TestLastFail for %s (%d) */\n" name i;
7128       let seq, last = get_seq_last seq in
7129       List.iter (generate_test_command_call test_name) seq;
7130       generate_test_command_call test_name ~expect_error:true last
7131
7132 (* Generate the code to run a command, leaving the result in 'r'.
7133  * If you expect to get an error then you should set expect_error:true.
7134  *)
7135 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
7136   match cmd with
7137   | [] -> assert false
7138   | name :: args ->
7139       (* Look up the command to find out what args/ret it has. *)
7140       let style =
7141         try
7142           let _, style, _, _, _, _, _ =
7143             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
7144           style
7145         with Not_found ->
7146           failwithf "%s: in test, command %s was not found" test_name name in
7147
7148       if List.length (snd style) <> List.length args then
7149         failwithf "%s: in test, wrong number of args given to %s"
7150           test_name name;
7151
7152       pr "  {\n";
7153
7154       List.iter (
7155         function
7156         | OptString n, "NULL" -> ()
7157         | Pathname n, arg
7158         | Device n, arg
7159         | Dev_or_Path n, arg
7160         | String n, arg
7161         | OptString n, arg ->
7162             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
7163         | Int _, _
7164         | Int64 _, _
7165         | Bool _, _
7166         | FileIn _, _ | FileOut _, _ -> ()
7167         | StringList n, "" | DeviceList n, "" ->
7168             pr "    const char *const %s[1] = { NULL };\n" n
7169         | StringList n, arg | DeviceList n, arg ->
7170             let strs = string_split " " arg in
7171             iteri (
7172               fun i str ->
7173                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
7174             ) strs;
7175             pr "    const char *const %s[] = {\n" n;
7176             iteri (
7177               fun i _ -> pr "      %s_%d,\n" n i
7178             ) strs;
7179             pr "      NULL\n";
7180             pr "    };\n";
7181       ) (List.combine (snd style) args);
7182
7183       let error_code =
7184         match fst style with
7185         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
7186         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
7187         | RConstString _ | RConstOptString _ ->
7188             pr "    const char *r;\n"; "NULL"
7189         | RString _ -> pr "    char *r;\n"; "NULL"
7190         | RStringList _ | RHashtable _ ->
7191             pr "    char **r;\n";
7192             pr "    int i;\n";
7193             "NULL"
7194         | RStruct (_, typ) ->
7195             pr "    struct guestfs_%s *r;\n" typ; "NULL"
7196         | RStructList (_, typ) ->
7197             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
7198         | RBufferOut _ ->
7199             pr "    char *r;\n";
7200             pr "    size_t size;\n";
7201             "NULL" in
7202
7203       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
7204       pr "    r = guestfs_%s (g" name;
7205
7206       (* Generate the parameters. *)
7207       List.iter (
7208         function
7209         | OptString _, "NULL" -> pr ", NULL"
7210         | Pathname n, _
7211         | Device n, _ | Dev_or_Path n, _
7212         | String n, _
7213         | OptString n, _ ->
7214             pr ", %s" n
7215         | FileIn _, arg | FileOut _, arg ->
7216             pr ", \"%s\"" (c_quote arg)
7217         | StringList n, _ | DeviceList n, _ ->
7218             pr ", (char **) %s" n
7219         | Int _, arg ->
7220             let i =
7221               try int_of_string arg
7222               with Failure "int_of_string" ->
7223                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
7224             pr ", %d" i
7225         | Int64 _, arg ->
7226             let i =
7227               try Int64.of_string arg
7228               with Failure "int_of_string" ->
7229                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
7230             pr ", %Ld" i
7231         | Bool _, arg ->
7232             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
7233       ) (List.combine (snd style) args);
7234
7235       (match fst style with
7236        | RBufferOut _ -> pr ", &size"
7237        | _ -> ()
7238       );
7239
7240       pr ");\n";
7241
7242       if not expect_error then
7243         pr "    if (r == %s)\n" error_code
7244       else
7245         pr "    if (r != %s)\n" error_code;
7246       pr "      return -1;\n";
7247
7248       (* Insert the test code. *)
7249       (match test with
7250        | None -> ()
7251        | Some f -> f ()
7252       );
7253
7254       (match fst style with
7255        | RErr | RInt _ | RInt64 _ | RBool _
7256        | RConstString _ | RConstOptString _ -> ()
7257        | RString _ | RBufferOut _ -> pr "    free (r);\n"
7258        | RStringList _ | RHashtable _ ->
7259            pr "    for (i = 0; r[i] != NULL; ++i)\n";
7260            pr "      free (r[i]);\n";
7261            pr "    free (r);\n"
7262        | RStruct (_, typ) ->
7263            pr "    guestfs_free_%s (r);\n" typ
7264        | RStructList (_, typ) ->
7265            pr "    guestfs_free_%s_list (r);\n" typ
7266       );
7267
7268       pr "  }\n"
7269
7270 and c_quote str =
7271   let str = replace_str str "\r" "\\r" in
7272   let str = replace_str str "\n" "\\n" in
7273   let str = replace_str str "\t" "\\t" in
7274   let str = replace_str str "\000" "\\0" in
7275   str
7276
7277 (* Generate a lot of different functions for guestfish. *)
7278 and generate_fish_cmds () =
7279   generate_header CStyle GPLv2plus;
7280
7281   let all_functions =
7282     List.filter (
7283       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7284     ) all_functions in
7285   let all_functions_sorted =
7286     List.filter (
7287       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7288     ) all_functions_sorted in
7289
7290   pr "#include <config.h>\n";
7291   pr "\n";
7292   pr "#include <stdio.h>\n";
7293   pr "#include <stdlib.h>\n";
7294   pr "#include <string.h>\n";
7295   pr "#include <inttypes.h>\n";
7296   pr "\n";
7297   pr "#include <guestfs.h>\n";
7298   pr "#include \"c-ctype.h\"\n";
7299   pr "#include \"full-write.h\"\n";
7300   pr "#include \"xstrtol.h\"\n";
7301   pr "#include \"fish.h\"\n";
7302   pr "\n";
7303
7304   (* list_commands function, which implements guestfish -h *)
7305   pr "void list_commands (void)\n";
7306   pr "{\n";
7307   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
7308   pr "  list_builtin_commands ();\n";
7309   List.iter (
7310     fun (name, _, _, flags, _, shortdesc, _) ->
7311       let name = replace_char name '_' '-' in
7312       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
7313         name shortdesc
7314   ) all_functions_sorted;
7315   pr "  printf (\"    %%s\\n\",";
7316   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
7317   pr "}\n";
7318   pr "\n";
7319
7320   (* display_command function, which implements guestfish -h cmd *)
7321   pr "void display_command (const char *cmd)\n";
7322   pr "{\n";
7323   List.iter (
7324     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7325       let name2 = 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       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
7330       let synopsis =
7331         match snd style with
7332         | [] -> name2
7333         | args ->
7334             sprintf "%s %s"
7335               name2 (String.concat " " (List.map name_of_argt args)) in
7336
7337       let warnings =
7338         if List.mem ProtocolLimitWarning flags then
7339           ("\n\n" ^ protocol_limit_warning)
7340         else "" in
7341
7342       (* For DangerWillRobinson commands, we should probably have
7343        * guestfish prompt before allowing you to use them (especially
7344        * in interactive mode). XXX
7345        *)
7346       let warnings =
7347         warnings ^
7348           if List.mem DangerWillRobinson flags then
7349             ("\n\n" ^ danger_will_robinson)
7350           else "" in
7351
7352       let warnings =
7353         warnings ^
7354           match deprecation_notice flags with
7355           | None -> ""
7356           | Some txt -> "\n\n" ^ txt in
7357
7358       let describe_alias =
7359         if name <> alias then
7360           sprintf "\n\nYou can use '%s' as an alias for this command." alias
7361         else "" in
7362
7363       pr "  if (";
7364       pr "STRCASEEQ (cmd, \"%s\")" name;
7365       if name <> name2 then
7366         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7367       if name <> alias then
7368         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7369       pr ")\n";
7370       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
7371         name2 shortdesc
7372         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
7373          "=head1 DESCRIPTION\n\n" ^
7374          longdesc ^ warnings ^ describe_alias);
7375       pr "  else\n"
7376   ) all_functions;
7377   pr "    display_builtin_command (cmd);\n";
7378   pr "}\n";
7379   pr "\n";
7380
7381   let emit_print_list_function typ =
7382     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
7383       typ typ typ;
7384     pr "{\n";
7385     pr "  unsigned int i;\n";
7386     pr "\n";
7387     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
7388     pr "    printf (\"[%%d] = {\\n\", i);\n";
7389     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
7390     pr "    printf (\"}\\n\");\n";
7391     pr "  }\n";
7392     pr "}\n";
7393     pr "\n";
7394   in
7395
7396   (* print_* functions *)
7397   List.iter (
7398     fun (typ, cols) ->
7399       let needs_i =
7400         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
7401
7402       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7403       pr "{\n";
7404       if needs_i then (
7405         pr "  unsigned int i;\n";
7406         pr "\n"
7407       );
7408       List.iter (
7409         function
7410         | name, FString ->
7411             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7412         | name, FUUID ->
7413             pr "  printf (\"%%s%s: \", indent);\n" name;
7414             pr "  for (i = 0; i < 32; ++i)\n";
7415             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7416             pr "  printf (\"\\n\");\n"
7417         | name, FBuffer ->
7418             pr "  printf (\"%%s%s: \", indent);\n" name;
7419             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7420             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7421             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7422             pr "    else\n";
7423             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7424             pr "  printf (\"\\n\");\n"
7425         | name, (FUInt64|FBytes) ->
7426             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7427               name typ name
7428         | name, FInt64 ->
7429             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7430               name typ name
7431         | name, FUInt32 ->
7432             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7433               name typ name
7434         | name, FInt32 ->
7435             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7436               name typ name
7437         | name, FChar ->
7438             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7439               name typ name
7440         | name, FOptPercent ->
7441             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7442               typ name name typ name;
7443             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7444       ) cols;
7445       pr "}\n";
7446       pr "\n";
7447   ) structs;
7448
7449   (* Emit a print_TYPE_list function definition only if that function is used. *)
7450   List.iter (
7451     function
7452     | typ, (RStructListOnly | RStructAndList) ->
7453         (* generate the function for typ *)
7454         emit_print_list_function typ
7455     | typ, _ -> () (* empty *)
7456   ) (rstructs_used_by all_functions);
7457
7458   (* Emit a print_TYPE function definition only if that function is used. *)
7459   List.iter (
7460     function
7461     | typ, (RStructOnly | RStructAndList) ->
7462         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7463         pr "{\n";
7464         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7465         pr "}\n";
7466         pr "\n";
7467     | typ, _ -> () (* empty *)
7468   ) (rstructs_used_by all_functions);
7469
7470   (* run_<action> actions *)
7471   List.iter (
7472     fun (name, style, _, flags, _, _, _) ->
7473       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7474       pr "{\n";
7475       (match fst style with
7476        | RErr
7477        | RInt _
7478        | RBool _ -> pr "  int r;\n"
7479        | RInt64 _ -> pr "  int64_t r;\n"
7480        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7481        | RString _ -> pr "  char *r;\n"
7482        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7483        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7484        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7485        | RBufferOut _ ->
7486            pr "  char *r;\n";
7487            pr "  size_t size;\n";
7488       );
7489       List.iter (
7490         function
7491         | Device n
7492         | String n
7493         | OptString n -> pr "  const char *%s;\n" n
7494         | Pathname n
7495         | Dev_or_Path n
7496         | FileIn n
7497         | FileOut n -> pr "  char *%s;\n" n
7498         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7499         | Bool n -> pr "  int %s;\n" n
7500         | Int n -> pr "  int %s;\n" n
7501         | Int64 n -> pr "  int64_t %s;\n" n
7502       ) (snd style);
7503
7504       (* Check and convert parameters. *)
7505       let argc_expected = List.length (snd style) in
7506       pr "  if (argc != %d) {\n" argc_expected;
7507       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7508         argc_expected;
7509       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7510       pr "    return -1;\n";
7511       pr "  }\n";
7512
7513       let parse_integer fn fntyp rtyp range name i =
7514         pr "  {\n";
7515         pr "    strtol_error xerr;\n";
7516         pr "    %s r;\n" fntyp;
7517         pr "\n";
7518         pr "    xerr = %s (argv[%d], NULL, 0, &r, \"\");\n" fn i;
7519         pr "    if (xerr != LONGINT_OK) {\n";
7520         pr "      fprintf (stderr,\n";
7521         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7522         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7523         pr "      return -1;\n";
7524         pr "    }\n";
7525         (match range with
7526          | None -> ()
7527          | Some (min, max, comment) ->
7528              pr "    /* %s */\n" comment;
7529              pr "    if (r < %s || r > %s) {\n" min max;
7530              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7531                name;
7532              pr "      return -1;\n";
7533              pr "    }\n";
7534              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7535         );
7536         pr "    %s = r;\n" name;
7537         pr "  }\n";
7538       in
7539
7540       iteri (
7541         fun i ->
7542           function
7543           | Device name
7544           | String name ->
7545               pr "  %s = argv[%d];\n" name i
7546           | Pathname name
7547           | Dev_or_Path name ->
7548               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7549               pr "  if (%s == NULL) return -1;\n" name
7550           | OptString name ->
7551               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7552                 name i i
7553           | FileIn name ->
7554               pr "  %s = file_in (argv[%d]);\n" name i;
7555               pr "  if (%s == NULL) return -1;\n" name
7556           | FileOut name ->
7557               pr "  %s = file_out (argv[%d]);\n" name i;
7558               pr "  if (%s == NULL) return -1;\n" name
7559           | StringList name | DeviceList name ->
7560               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7561               pr "  if (%s == NULL) return -1;\n" name;
7562           | Bool name ->
7563               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7564           | Int name ->
7565               let range =
7566                 let min = "(-(2LL<<30))"
7567                 and max = "((2LL<<30)-1)"
7568                 and comment =
7569                   "The Int type in the generator is a signed 31 bit int." in
7570                 Some (min, max, comment) in
7571               parse_integer "xstrtoll" "long long" "int" range name i
7572           | Int64 name ->
7573               parse_integer "xstrtoll" "long long" "int64_t" None name i
7574       ) (snd style);
7575
7576       (* Call C API function. *)
7577       pr "  r = guestfs_%s " name;
7578       generate_c_call_args ~handle:"g" style;
7579       pr ";\n";
7580
7581       List.iter (
7582         function
7583         | Device name | String name
7584         | OptString name | Bool name
7585         | Int name | Int64 name -> ()
7586         | Pathname name | Dev_or_Path name | FileOut name ->
7587             pr "  free (%s);\n" name
7588         | FileIn name ->
7589             pr "  free_file_in (%s);\n" name
7590         | StringList name | DeviceList name ->
7591             pr "  free_strings (%s);\n" name
7592       ) (snd style);
7593
7594       (* Any output flags? *)
7595       let fish_output =
7596         let flags = filter_map (
7597           function FishOutput flag -> Some flag | _ -> None
7598         ) flags in
7599         match flags with
7600         | [] -> None
7601         | [f] -> Some f
7602         | _ ->
7603             failwithf "%s: more than one FishOutput flag is not allowed" name in
7604
7605       (* Check return value for errors and display command results. *)
7606       (match fst style with
7607        | RErr -> pr "  return r;\n"
7608        | RInt _ ->
7609            pr "  if (r == -1) return -1;\n";
7610            (match fish_output with
7611             | None ->
7612                 pr "  printf (\"%%d\\n\", r);\n";
7613             | Some FishOutputOctal ->
7614                 pr "  printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n";
7615             | Some FishOutputHexadecimal ->
7616                 pr "  printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7617            pr "  return 0;\n"
7618        | RInt64 _ ->
7619            pr "  if (r == -1) return -1;\n";
7620            (match fish_output with
7621             | None ->
7622                 pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7623             | Some FishOutputOctal ->
7624                 pr "  printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n";
7625             | Some FishOutputHexadecimal ->
7626                 pr "  printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7627            pr "  return 0;\n"
7628        | RBool _ ->
7629            pr "  if (r == -1) return -1;\n";
7630            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7631            pr "  return 0;\n"
7632        | RConstString _ ->
7633            pr "  if (r == NULL) return -1;\n";
7634            pr "  printf (\"%%s\\n\", r);\n";
7635            pr "  return 0;\n"
7636        | RConstOptString _ ->
7637            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7638            pr "  return 0;\n"
7639        | RString _ ->
7640            pr "  if (r == NULL) return -1;\n";
7641            pr "  printf (\"%%s\\n\", r);\n";
7642            pr "  free (r);\n";
7643            pr "  return 0;\n"
7644        | RStringList _ ->
7645            pr "  if (r == NULL) return -1;\n";
7646            pr "  print_strings (r);\n";
7647            pr "  free_strings (r);\n";
7648            pr "  return 0;\n"
7649        | RStruct (_, typ) ->
7650            pr "  if (r == NULL) return -1;\n";
7651            pr "  print_%s (r);\n" typ;
7652            pr "  guestfs_free_%s (r);\n" typ;
7653            pr "  return 0;\n"
7654        | RStructList (_, typ) ->
7655            pr "  if (r == NULL) return -1;\n";
7656            pr "  print_%s_list (r);\n" typ;
7657            pr "  guestfs_free_%s_list (r);\n" typ;
7658            pr "  return 0;\n"
7659        | RHashtable _ ->
7660            pr "  if (r == NULL) return -1;\n";
7661            pr "  print_table (r);\n";
7662            pr "  free_strings (r);\n";
7663            pr "  return 0;\n"
7664        | RBufferOut _ ->
7665            pr "  if (r == NULL) return -1;\n";
7666            pr "  if (full_write (1, r, size) != size) {\n";
7667            pr "    perror (\"write\");\n";
7668            pr "    free (r);\n";
7669            pr "    return -1;\n";
7670            pr "  }\n";
7671            pr "  free (r);\n";
7672            pr "  return 0;\n"
7673       );
7674       pr "}\n";
7675       pr "\n"
7676   ) all_functions;
7677
7678   (* run_action function *)
7679   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7680   pr "{\n";
7681   List.iter (
7682     fun (name, _, _, flags, _, _, _) ->
7683       let name2 = replace_char name '_' '-' in
7684       let alias =
7685         try find_map (function FishAlias n -> Some n | _ -> None) flags
7686         with Not_found -> name in
7687       pr "  if (";
7688       pr "STRCASEEQ (cmd, \"%s\")" name;
7689       if name <> name2 then
7690         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7691       if name <> alias then
7692         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7693       pr ")\n";
7694       pr "    return run_%s (cmd, argc, argv);\n" name;
7695       pr "  else\n";
7696   ) all_functions;
7697   pr "    {\n";
7698   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7699   pr "      if (command_num == 1)\n";
7700   pr "        extended_help_message ();\n";
7701   pr "      return -1;\n";
7702   pr "    }\n";
7703   pr "  return 0;\n";
7704   pr "}\n";
7705   pr "\n"
7706
7707 (* Readline completion for guestfish. *)
7708 and generate_fish_completion () =
7709   generate_header CStyle GPLv2plus;
7710
7711   let all_functions =
7712     List.filter (
7713       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7714     ) all_functions in
7715
7716   pr "\
7717 #include <config.h>
7718
7719 #include <stdio.h>
7720 #include <stdlib.h>
7721 #include <string.h>
7722
7723 #ifdef HAVE_LIBREADLINE
7724 #include <readline/readline.h>
7725 #endif
7726
7727 #include \"fish.h\"
7728
7729 #ifdef HAVE_LIBREADLINE
7730
7731 static const char *const commands[] = {
7732   BUILTIN_COMMANDS_FOR_COMPLETION,
7733 ";
7734
7735   (* Get the commands, including the aliases.  They don't need to be
7736    * sorted - the generator() function just does a dumb linear search.
7737    *)
7738   let commands =
7739     List.map (
7740       fun (name, _, _, flags, _, _, _) ->
7741         let name2 = replace_char name '_' '-' in
7742         let alias =
7743           try find_map (function FishAlias n -> Some n | _ -> None) flags
7744           with Not_found -> name in
7745
7746         if name <> alias then [name2; alias] else [name2]
7747     ) all_functions in
7748   let commands = List.flatten commands in
7749
7750   List.iter (pr "  \"%s\",\n") commands;
7751
7752   pr "  NULL
7753 };
7754
7755 static char *
7756 generator (const char *text, int state)
7757 {
7758   static int index, len;
7759   const char *name;
7760
7761   if (!state) {
7762     index = 0;
7763     len = strlen (text);
7764   }
7765
7766   rl_attempted_completion_over = 1;
7767
7768   while ((name = commands[index]) != NULL) {
7769     index++;
7770     if (STRCASEEQLEN (name, text, len))
7771       return strdup (name);
7772   }
7773
7774   return NULL;
7775 }
7776
7777 #endif /* HAVE_LIBREADLINE */
7778
7779 #ifdef HAVE_RL_COMPLETION_MATCHES
7780 #define RL_COMPLETION_MATCHES rl_completion_matches
7781 #else
7782 #ifdef HAVE_COMPLETION_MATCHES
7783 #define RL_COMPLETION_MATCHES completion_matches
7784 #endif
7785 #endif /* else just fail if we don't have either symbol */
7786
7787 char **
7788 do_completion (const char *text, int start, int end)
7789 {
7790   char **matches = NULL;
7791
7792 #ifdef HAVE_LIBREADLINE
7793   rl_completion_append_character = ' ';
7794
7795   if (start == 0)
7796     matches = RL_COMPLETION_MATCHES (text, generator);
7797   else if (complete_dest_paths)
7798     matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
7799 #endif
7800
7801   return matches;
7802 }
7803 ";
7804
7805 (* Generate the POD documentation for guestfish. *)
7806 and generate_fish_actions_pod () =
7807   let all_functions_sorted =
7808     List.filter (
7809       fun (_, _, _, flags, _, _, _) ->
7810         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7811     ) all_functions_sorted in
7812
7813   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7814
7815   List.iter (
7816     fun (name, style, _, flags, _, _, longdesc) ->
7817       let longdesc =
7818         Str.global_substitute rex (
7819           fun s ->
7820             let sub =
7821               try Str.matched_group 1 s
7822               with Not_found ->
7823                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7824             "C<" ^ replace_char sub '_' '-' ^ ">"
7825         ) longdesc in
7826       let name = replace_char name '_' '-' in
7827       let alias =
7828         try find_map (function FishAlias n -> Some n | _ -> None) flags
7829         with Not_found -> name in
7830
7831       pr "=head2 %s" name;
7832       if name <> alias then
7833         pr " | %s" alias;
7834       pr "\n";
7835       pr "\n";
7836       pr " %s" name;
7837       List.iter (
7838         function
7839         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7840         | OptString n -> pr " %s" n
7841         | StringList n | DeviceList n -> pr " '%s ...'" n
7842         | Bool _ -> pr " true|false"
7843         | Int n -> pr " %s" n
7844         | Int64 n -> pr " %s" n
7845         | FileIn n | FileOut n -> pr " (%s|-)" n
7846       ) (snd style);
7847       pr "\n";
7848       pr "\n";
7849       pr "%s\n\n" longdesc;
7850
7851       if List.exists (function FileIn _ | FileOut _ -> true
7852                       | _ -> false) (snd style) then
7853         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7854
7855       if List.mem ProtocolLimitWarning flags then
7856         pr "%s\n\n" protocol_limit_warning;
7857
7858       if List.mem DangerWillRobinson flags then
7859         pr "%s\n\n" danger_will_robinson;
7860
7861       match deprecation_notice flags with
7862       | None -> ()
7863       | Some txt -> pr "%s\n\n" txt
7864   ) all_functions_sorted
7865
7866 (* Generate a C function prototype. *)
7867 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7868     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7869     ?(prefix = "")
7870     ?handle name style =
7871   if extern then pr "extern ";
7872   if static then pr "static ";
7873   (match fst style with
7874    | RErr -> pr "int "
7875    | RInt _ -> pr "int "
7876    | RInt64 _ -> pr "int64_t "
7877    | RBool _ -> pr "int "
7878    | RConstString _ | RConstOptString _ -> pr "const char *"
7879    | RString _ | RBufferOut _ -> pr "char *"
7880    | RStringList _ | RHashtable _ -> pr "char **"
7881    | RStruct (_, typ) ->
7882        if not in_daemon then pr "struct guestfs_%s *" typ
7883        else pr "guestfs_int_%s *" typ
7884    | RStructList (_, typ) ->
7885        if not in_daemon then pr "struct guestfs_%s_list *" typ
7886        else pr "guestfs_int_%s_list *" typ
7887   );
7888   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7889   pr "%s%s (" prefix name;
7890   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7891     pr "void"
7892   else (
7893     let comma = ref false in
7894     (match handle with
7895      | None -> ()
7896      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7897     );
7898     let next () =
7899       if !comma then (
7900         if single_line then pr ", " else pr ",\n\t\t"
7901       );
7902       comma := true
7903     in
7904     List.iter (
7905       function
7906       | Pathname n
7907       | Device n | Dev_or_Path n
7908       | String n
7909       | OptString n ->
7910           next ();
7911           pr "const char *%s" n
7912       | StringList n | DeviceList n ->
7913           next ();
7914           pr "char *const *%s" n
7915       | Bool n -> next (); pr "int %s" n
7916       | Int n -> next (); pr "int %s" n
7917       | Int64 n -> next (); pr "int64_t %s" n
7918       | FileIn n
7919       | FileOut n ->
7920           if not in_daemon then (next (); pr "const char *%s" n)
7921     ) (snd style);
7922     if is_RBufferOut then (next (); pr "size_t *size_r");
7923   );
7924   pr ")";
7925   if semicolon then pr ";";
7926   if newline then pr "\n"
7927
7928 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7929 and generate_c_call_args ?handle ?(decl = false) style =
7930   pr "(";
7931   let comma = ref false in
7932   let next () =
7933     if !comma then pr ", ";
7934     comma := true
7935   in
7936   (match handle with
7937    | None -> ()
7938    | Some handle -> pr "%s" handle; comma := true
7939   );
7940   List.iter (
7941     fun arg ->
7942       next ();
7943       pr "%s" (name_of_argt arg)
7944   ) (snd style);
7945   (* For RBufferOut calls, add implicit &size parameter. *)
7946   if not decl then (
7947     match fst style with
7948     | RBufferOut _ ->
7949         next ();
7950         pr "&size"
7951     | _ -> ()
7952   );
7953   pr ")"
7954
7955 (* Generate the OCaml bindings interface. *)
7956 and generate_ocaml_mli () =
7957   generate_header OCamlStyle LGPLv2plus;
7958
7959   pr "\
7960 (** For API documentation you should refer to the C API
7961     in the guestfs(3) manual page.  The OCaml API uses almost
7962     exactly the same calls. *)
7963
7964 type t
7965 (** A [guestfs_h] handle. *)
7966
7967 exception Error of string
7968 (** This exception is raised when there is an error. *)
7969
7970 exception Handle_closed of string
7971 (** This exception is raised if you use a {!Guestfs.t} handle
7972     after calling {!close} on it.  The string is the name of
7973     the function. *)
7974
7975 val create : unit -> t
7976 (** Create a {!Guestfs.t} handle. *)
7977
7978 val close : t -> unit
7979 (** Close the {!Guestfs.t} handle and free up all resources used
7980     by it immediately.
7981
7982     Handles are closed by the garbage collector when they become
7983     unreferenced, but callers can call this in order to provide
7984     predictable cleanup. *)
7985
7986 ";
7987   generate_ocaml_structure_decls ();
7988
7989   (* The actions. *)
7990   List.iter (
7991     fun (name, style, _, _, _, shortdesc, _) ->
7992       generate_ocaml_prototype name style;
7993       pr "(** %s *)\n" shortdesc;
7994       pr "\n"
7995   ) all_functions_sorted
7996
7997 (* Generate the OCaml bindings implementation. *)
7998 and generate_ocaml_ml () =
7999   generate_header OCamlStyle LGPLv2plus;
8000
8001   pr "\
8002 type t
8003
8004 exception Error of string
8005 exception Handle_closed of string
8006
8007 external create : unit -> t = \"ocaml_guestfs_create\"
8008 external close : t -> unit = \"ocaml_guestfs_close\"
8009
8010 (* Give the exceptions names, so they can be raised from the C code. *)
8011 let () =
8012   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
8013   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
8014
8015 ";
8016
8017   generate_ocaml_structure_decls ();
8018
8019   (* The actions. *)
8020   List.iter (
8021     fun (name, style, _, _, _, shortdesc, _) ->
8022       generate_ocaml_prototype ~is_external:true name style;
8023   ) all_functions_sorted
8024
8025 (* Generate the OCaml bindings C implementation. *)
8026 and generate_ocaml_c () =
8027   generate_header CStyle LGPLv2plus;
8028
8029   pr "\
8030 #include <stdio.h>
8031 #include <stdlib.h>
8032 #include <string.h>
8033
8034 #include <caml/config.h>
8035 #include <caml/alloc.h>
8036 #include <caml/callback.h>
8037 #include <caml/fail.h>
8038 #include <caml/memory.h>
8039 #include <caml/mlvalues.h>
8040 #include <caml/signals.h>
8041
8042 #include <guestfs.h>
8043
8044 #include \"guestfs_c.h\"
8045
8046 /* Copy a hashtable of string pairs into an assoc-list.  We return
8047  * the list in reverse order, but hashtables aren't supposed to be
8048  * ordered anyway.
8049  */
8050 static CAMLprim value
8051 copy_table (char * const * argv)
8052 {
8053   CAMLparam0 ();
8054   CAMLlocal5 (rv, pairv, kv, vv, cons);
8055   int i;
8056
8057   rv = Val_int (0);
8058   for (i = 0; argv[i] != NULL; i += 2) {
8059     kv = caml_copy_string (argv[i]);
8060     vv = caml_copy_string (argv[i+1]);
8061     pairv = caml_alloc (2, 0);
8062     Store_field (pairv, 0, kv);
8063     Store_field (pairv, 1, vv);
8064     cons = caml_alloc (2, 0);
8065     Store_field (cons, 1, rv);
8066     rv = cons;
8067     Store_field (cons, 0, pairv);
8068   }
8069
8070   CAMLreturn (rv);
8071 }
8072
8073 ";
8074
8075   (* Struct copy functions. *)
8076
8077   let emit_ocaml_copy_list_function typ =
8078     pr "static CAMLprim value\n";
8079     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
8080     pr "{\n";
8081     pr "  CAMLparam0 ();\n";
8082     pr "  CAMLlocal2 (rv, v);\n";
8083     pr "  unsigned int i;\n";
8084     pr "\n";
8085     pr "  if (%ss->len == 0)\n" typ;
8086     pr "    CAMLreturn (Atom (0));\n";
8087     pr "  else {\n";
8088     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
8089     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
8090     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
8091     pr "      caml_modify (&Field (rv, i), v);\n";
8092     pr "    }\n";
8093     pr "    CAMLreturn (rv);\n";
8094     pr "  }\n";
8095     pr "}\n";
8096     pr "\n";
8097   in
8098
8099   List.iter (
8100     fun (typ, cols) ->
8101       let has_optpercent_col =
8102         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
8103
8104       pr "static CAMLprim value\n";
8105       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
8106       pr "{\n";
8107       pr "  CAMLparam0 ();\n";
8108       if has_optpercent_col then
8109         pr "  CAMLlocal3 (rv, v, v2);\n"
8110       else
8111         pr "  CAMLlocal2 (rv, v);\n";
8112       pr "\n";
8113       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
8114       iteri (
8115         fun i col ->
8116           (match col with
8117            | name, FString ->
8118                pr "  v = caml_copy_string (%s->%s);\n" typ name
8119            | name, FBuffer ->
8120                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
8121                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
8122                  typ name typ name
8123            | name, FUUID ->
8124                pr "  v = caml_alloc_string (32);\n";
8125                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
8126            | name, (FBytes|FInt64|FUInt64) ->
8127                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
8128            | name, (FInt32|FUInt32) ->
8129                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
8130            | name, FOptPercent ->
8131                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
8132                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
8133                pr "    v = caml_alloc (1, 0);\n";
8134                pr "    Store_field (v, 0, v2);\n";
8135                pr "  } else /* None */\n";
8136                pr "    v = Val_int (0);\n";
8137            | name, FChar ->
8138                pr "  v = Val_int (%s->%s);\n" typ name
8139           );
8140           pr "  Store_field (rv, %d, v);\n" i
8141       ) cols;
8142       pr "  CAMLreturn (rv);\n";
8143       pr "}\n";
8144       pr "\n";
8145   ) structs;
8146
8147   (* Emit a copy_TYPE_list function definition only if that function is used. *)
8148   List.iter (
8149     function
8150     | typ, (RStructListOnly | RStructAndList) ->
8151         (* generate the function for typ *)
8152         emit_ocaml_copy_list_function typ
8153     | typ, _ -> () (* empty *)
8154   ) (rstructs_used_by all_functions);
8155
8156   (* The wrappers. *)
8157   List.iter (
8158     fun (name, style, _, _, _, _, _) ->
8159       pr "/* Automatically generated wrapper for function\n";
8160       pr " * ";
8161       generate_ocaml_prototype name style;
8162       pr " */\n";
8163       pr "\n";
8164
8165       let params =
8166         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
8167
8168       let needs_extra_vs =
8169         match fst style with RConstOptString _ -> true | _ -> false in
8170
8171       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8172       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
8173       List.iter (pr ", value %s") (List.tl params); pr ");\n";
8174       pr "\n";
8175
8176       pr "CAMLprim value\n";
8177       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
8178       List.iter (pr ", value %s") (List.tl params);
8179       pr ")\n";
8180       pr "{\n";
8181
8182       (match params with
8183        | [p1; p2; p3; p4; p5] ->
8184            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
8185        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
8186            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
8187            pr "  CAMLxparam%d (%s);\n"
8188              (List.length rest) (String.concat ", " rest)
8189        | ps ->
8190            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
8191       );
8192       if not needs_extra_vs then
8193         pr "  CAMLlocal1 (rv);\n"
8194       else
8195         pr "  CAMLlocal3 (rv, v, v2);\n";
8196       pr "\n";
8197
8198       pr "  guestfs_h *g = Guestfs_val (gv);\n";
8199       pr "  if (g == NULL)\n";
8200       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
8201       pr "\n";
8202
8203       List.iter (
8204         function
8205         | Pathname n
8206         | Device n | Dev_or_Path n
8207         | String n
8208         | FileIn n
8209         | FileOut n ->
8210             pr "  const char *%s = String_val (%sv);\n" n n
8211         | OptString n ->
8212             pr "  const char *%s =\n" n;
8213             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
8214               n n
8215         | StringList n | DeviceList n ->
8216             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
8217         | Bool n ->
8218             pr "  int %s = Bool_val (%sv);\n" n n
8219         | Int n ->
8220             pr "  int %s = Int_val (%sv);\n" n n
8221         | Int64 n ->
8222             pr "  int64_t %s = Int64_val (%sv);\n" n n
8223       ) (snd style);
8224       let error_code =
8225         match fst style with
8226         | RErr -> pr "  int r;\n"; "-1"
8227         | RInt _ -> pr "  int r;\n"; "-1"
8228         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8229         | RBool _ -> pr "  int r;\n"; "-1"
8230         | RConstString _ | RConstOptString _ ->
8231             pr "  const char *r;\n"; "NULL"
8232         | RString _ -> pr "  char *r;\n"; "NULL"
8233         | RStringList _ ->
8234             pr "  int i;\n";
8235             pr "  char **r;\n";
8236             "NULL"
8237         | RStruct (_, typ) ->
8238             pr "  struct guestfs_%s *r;\n" typ; "NULL"
8239         | RStructList (_, typ) ->
8240             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8241         | RHashtable _ ->
8242             pr "  int i;\n";
8243             pr "  char **r;\n";
8244             "NULL"
8245         | RBufferOut _ ->
8246             pr "  char *r;\n";
8247             pr "  size_t size;\n";
8248             "NULL" in
8249       pr "\n";
8250
8251       pr "  caml_enter_blocking_section ();\n";
8252       pr "  r = guestfs_%s " name;
8253       generate_c_call_args ~handle:"g" style;
8254       pr ";\n";
8255       pr "  caml_leave_blocking_section ();\n";
8256
8257       List.iter (
8258         function
8259         | StringList n | DeviceList n ->
8260             pr "  ocaml_guestfs_free_strings (%s);\n" n;
8261         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8262         | Bool _ | Int _ | Int64 _
8263         | FileIn _ | FileOut _ -> ()
8264       ) (snd style);
8265
8266       pr "  if (r == %s)\n" error_code;
8267       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
8268       pr "\n";
8269
8270       (match fst style with
8271        | RErr -> pr "  rv = Val_unit;\n"
8272        | RInt _ -> pr "  rv = Val_int (r);\n"
8273        | RInt64 _ ->
8274            pr "  rv = caml_copy_int64 (r);\n"
8275        | RBool _ -> pr "  rv = Val_bool (r);\n"
8276        | RConstString _ ->
8277            pr "  rv = caml_copy_string (r);\n"
8278        | RConstOptString _ ->
8279            pr "  if (r) { /* Some string */\n";
8280            pr "    v = caml_alloc (1, 0);\n";
8281            pr "    v2 = caml_copy_string (r);\n";
8282            pr "    Store_field (v, 0, v2);\n";
8283            pr "  } else /* None */\n";
8284            pr "    v = Val_int (0);\n";
8285        | RString _ ->
8286            pr "  rv = caml_copy_string (r);\n";
8287            pr "  free (r);\n"
8288        | RStringList _ ->
8289            pr "  rv = caml_copy_string_array ((const char **) r);\n";
8290            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8291            pr "  free (r);\n"
8292        | RStruct (_, typ) ->
8293            pr "  rv = copy_%s (r);\n" typ;
8294            pr "  guestfs_free_%s (r);\n" typ;
8295        | RStructList (_, typ) ->
8296            pr "  rv = copy_%s_list (r);\n" typ;
8297            pr "  guestfs_free_%s_list (r);\n" typ;
8298        | RHashtable _ ->
8299            pr "  rv = copy_table (r);\n";
8300            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8301            pr "  free (r);\n";
8302        | RBufferOut _ ->
8303            pr "  rv = caml_alloc_string (size);\n";
8304            pr "  memcpy (String_val (rv), r, size);\n";
8305       );
8306
8307       pr "  CAMLreturn (rv);\n";
8308       pr "}\n";
8309       pr "\n";
8310
8311       if List.length params > 5 then (
8312         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8313         pr "CAMLprim value ";
8314         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
8315         pr "CAMLprim value\n";
8316         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
8317         pr "{\n";
8318         pr "  return ocaml_guestfs_%s (argv[0]" name;
8319         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
8320         pr ");\n";
8321         pr "}\n";
8322         pr "\n"
8323       )
8324   ) all_functions_sorted
8325
8326 and generate_ocaml_structure_decls () =
8327   List.iter (
8328     fun (typ, cols) ->
8329       pr "type %s = {\n" typ;
8330       List.iter (
8331         function
8332         | name, FString -> pr "  %s : string;\n" name
8333         | name, FBuffer -> pr "  %s : string;\n" name
8334         | name, FUUID -> pr "  %s : string;\n" name
8335         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
8336         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
8337         | name, FChar -> pr "  %s : char;\n" name
8338         | name, FOptPercent -> pr "  %s : float option;\n" name
8339       ) cols;
8340       pr "}\n";
8341       pr "\n"
8342   ) structs
8343
8344 and generate_ocaml_prototype ?(is_external = false) name style =
8345   if is_external then pr "external " else pr "val ";
8346   pr "%s : t -> " name;
8347   List.iter (
8348     function
8349     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
8350     | OptString _ -> pr "string option -> "
8351     | StringList _ | DeviceList _ -> pr "string array -> "
8352     | Bool _ -> pr "bool -> "
8353     | Int _ -> pr "int -> "
8354     | Int64 _ -> pr "int64 -> "
8355   ) (snd style);
8356   (match fst style with
8357    | RErr -> pr "unit" (* all errors are turned into exceptions *)
8358    | RInt _ -> pr "int"
8359    | RInt64 _ -> pr "int64"
8360    | RBool _ -> pr "bool"
8361    | RConstString _ -> pr "string"
8362    | RConstOptString _ -> pr "string option"
8363    | RString _ | RBufferOut _ -> pr "string"
8364    | RStringList _ -> pr "string array"
8365    | RStruct (_, typ) -> pr "%s" typ
8366    | RStructList (_, typ) -> pr "%s array" typ
8367    | RHashtable _ -> pr "(string * string) list"
8368   );
8369   if is_external then (
8370     pr " = ";
8371     if List.length (snd style) + 1 > 5 then
8372       pr "\"ocaml_guestfs_%s_byte\" " name;
8373     pr "\"ocaml_guestfs_%s\"" name
8374   );
8375   pr "\n"
8376
8377 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
8378 and generate_perl_xs () =
8379   generate_header CStyle LGPLv2plus;
8380
8381   pr "\
8382 #include \"EXTERN.h\"
8383 #include \"perl.h\"
8384 #include \"XSUB.h\"
8385
8386 #include <guestfs.h>
8387
8388 #ifndef PRId64
8389 #define PRId64 \"lld\"
8390 #endif
8391
8392 static SV *
8393 my_newSVll(long long val) {
8394 #ifdef USE_64_BIT_ALL
8395   return newSViv(val);
8396 #else
8397   char buf[100];
8398   int len;
8399   len = snprintf(buf, 100, \"%%\" PRId64, val);
8400   return newSVpv(buf, len);
8401 #endif
8402 }
8403
8404 #ifndef PRIu64
8405 #define PRIu64 \"llu\"
8406 #endif
8407
8408 static SV *
8409 my_newSVull(unsigned long long val) {
8410 #ifdef USE_64_BIT_ALL
8411   return newSVuv(val);
8412 #else
8413   char buf[100];
8414   int len;
8415   len = snprintf(buf, 100, \"%%\" PRIu64, val);
8416   return newSVpv(buf, len);
8417 #endif
8418 }
8419
8420 /* http://www.perlmonks.org/?node_id=680842 */
8421 static char **
8422 XS_unpack_charPtrPtr (SV *arg) {
8423   char **ret;
8424   AV *av;
8425   I32 i;
8426
8427   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
8428     croak (\"array reference expected\");
8429
8430   av = (AV *)SvRV (arg);
8431   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
8432   if (!ret)
8433     croak (\"malloc failed\");
8434
8435   for (i = 0; i <= av_len (av); i++) {
8436     SV **elem = av_fetch (av, i, 0);
8437
8438     if (!elem || !*elem)
8439       croak (\"missing element in list\");
8440
8441     ret[i] = SvPV_nolen (*elem);
8442   }
8443
8444   ret[i] = NULL;
8445
8446   return ret;
8447 }
8448
8449 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8450
8451 PROTOTYPES: ENABLE
8452
8453 guestfs_h *
8454 _create ()
8455    CODE:
8456       RETVAL = guestfs_create ();
8457       if (!RETVAL)
8458         croak (\"could not create guestfs handle\");
8459       guestfs_set_error_handler (RETVAL, NULL, NULL);
8460  OUTPUT:
8461       RETVAL
8462
8463 void
8464 DESTROY (g)
8465       guestfs_h *g;
8466  PPCODE:
8467       guestfs_close (g);
8468
8469 ";
8470
8471   List.iter (
8472     fun (name, style, _, _, _, _, _) ->
8473       (match fst style with
8474        | RErr -> pr "void\n"
8475        | RInt _ -> pr "SV *\n"
8476        | RInt64 _ -> pr "SV *\n"
8477        | RBool _ -> pr "SV *\n"
8478        | RConstString _ -> pr "SV *\n"
8479        | RConstOptString _ -> pr "SV *\n"
8480        | RString _ -> pr "SV *\n"
8481        | RBufferOut _ -> pr "SV *\n"
8482        | RStringList _
8483        | RStruct _ | RStructList _
8484        | RHashtable _ ->
8485            pr "void\n" (* all lists returned implictly on the stack *)
8486       );
8487       (* Call and arguments. *)
8488       pr "%s " name;
8489       generate_c_call_args ~handle:"g" ~decl:true style;
8490       pr "\n";
8491       pr "      guestfs_h *g;\n";
8492       iteri (
8493         fun i ->
8494           function
8495           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8496               pr "      char *%s;\n" n
8497           | OptString n ->
8498               (* http://www.perlmonks.org/?node_id=554277
8499                * Note that the implicit handle argument means we have
8500                * to add 1 to the ST(x) operator.
8501                *)
8502               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8503           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8504           | Bool n -> pr "      int %s;\n" n
8505           | Int n -> pr "      int %s;\n" n
8506           | Int64 n -> pr "      int64_t %s;\n" n
8507       ) (snd style);
8508
8509       let do_cleanups () =
8510         List.iter (
8511           function
8512           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8513           | Bool _ | Int _ | Int64 _
8514           | FileIn _ | FileOut _ -> ()
8515           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8516         ) (snd style)
8517       in
8518
8519       (* Code. *)
8520       (match fst style with
8521        | RErr ->
8522            pr "PREINIT:\n";
8523            pr "      int r;\n";
8524            pr " PPCODE:\n";
8525            pr "      r = guestfs_%s " name;
8526            generate_c_call_args ~handle:"g" style;
8527            pr ";\n";
8528            do_cleanups ();
8529            pr "      if (r == -1)\n";
8530            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8531        | RInt n
8532        | RBool n ->
8533            pr "PREINIT:\n";
8534            pr "      int %s;\n" n;
8535            pr "   CODE:\n";
8536            pr "      %s = guestfs_%s " n name;
8537            generate_c_call_args ~handle:"g" style;
8538            pr ";\n";
8539            do_cleanups ();
8540            pr "      if (%s == -1)\n" n;
8541            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8542            pr "      RETVAL = newSViv (%s);\n" n;
8543            pr " OUTPUT:\n";
8544            pr "      RETVAL\n"
8545        | RInt64 n ->
8546            pr "PREINIT:\n";
8547            pr "      int64_t %s;\n" n;
8548            pr "   CODE:\n";
8549            pr "      %s = guestfs_%s " n name;
8550            generate_c_call_args ~handle:"g" style;
8551            pr ";\n";
8552            do_cleanups ();
8553            pr "      if (%s == -1)\n" n;
8554            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8555            pr "      RETVAL = my_newSVll (%s);\n" n;
8556            pr " OUTPUT:\n";
8557            pr "      RETVAL\n"
8558        | RConstString n ->
8559            pr "PREINIT:\n";
8560            pr "      const char *%s;\n" n;
8561            pr "   CODE:\n";
8562            pr "      %s = guestfs_%s " n name;
8563            generate_c_call_args ~handle:"g" style;
8564            pr ";\n";
8565            do_cleanups ();
8566            pr "      if (%s == NULL)\n" n;
8567            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8568            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8569            pr " OUTPUT:\n";
8570            pr "      RETVAL\n"
8571        | RConstOptString n ->
8572            pr "PREINIT:\n";
8573            pr "      const char *%s;\n" n;
8574            pr "   CODE:\n";
8575            pr "      %s = guestfs_%s " n name;
8576            generate_c_call_args ~handle:"g" style;
8577            pr ";\n";
8578            do_cleanups ();
8579            pr "      if (%s == NULL)\n" n;
8580            pr "        RETVAL = &PL_sv_undef;\n";
8581            pr "      else\n";
8582            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8583            pr " OUTPUT:\n";
8584            pr "      RETVAL\n"
8585        | RString n ->
8586            pr "PREINIT:\n";
8587            pr "      char *%s;\n" n;
8588            pr "   CODE:\n";
8589            pr "      %s = guestfs_%s " n name;
8590            generate_c_call_args ~handle:"g" style;
8591            pr ";\n";
8592            do_cleanups ();
8593            pr "      if (%s == NULL)\n" n;
8594            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8595            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8596            pr "      free (%s);\n" n;
8597            pr " OUTPUT:\n";
8598            pr "      RETVAL\n"
8599        | RStringList n | RHashtable n ->
8600            pr "PREINIT:\n";
8601            pr "      char **%s;\n" n;
8602            pr "      int i, n;\n";
8603            pr " PPCODE:\n";
8604            pr "      %s = guestfs_%s " n name;
8605            generate_c_call_args ~handle:"g" style;
8606            pr ";\n";
8607            do_cleanups ();
8608            pr "      if (%s == NULL)\n" n;
8609            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8610            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8611            pr "      EXTEND (SP, n);\n";
8612            pr "      for (i = 0; i < n; ++i) {\n";
8613            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8614            pr "        free (%s[i]);\n" n;
8615            pr "      }\n";
8616            pr "      free (%s);\n" n;
8617        | RStruct (n, typ) ->
8618            let cols = cols_of_struct typ in
8619            generate_perl_struct_code typ cols name style n do_cleanups
8620        | RStructList (n, typ) ->
8621            let cols = cols_of_struct typ in
8622            generate_perl_struct_list_code typ cols name style n do_cleanups
8623        | RBufferOut n ->
8624            pr "PREINIT:\n";
8625            pr "      char *%s;\n" n;
8626            pr "      size_t size;\n";
8627            pr "   CODE:\n";
8628            pr "      %s = guestfs_%s " n name;
8629            generate_c_call_args ~handle:"g" style;
8630            pr ";\n";
8631            do_cleanups ();
8632            pr "      if (%s == NULL)\n" n;
8633            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8634            pr "      RETVAL = newSVpvn (%s, size);\n" n;
8635            pr "      free (%s);\n" n;
8636            pr " OUTPUT:\n";
8637            pr "      RETVAL\n"
8638       );
8639
8640       pr "\n"
8641   ) all_functions
8642
8643 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8644   pr "PREINIT:\n";
8645   pr "      struct guestfs_%s_list *%s;\n" typ n;
8646   pr "      int i;\n";
8647   pr "      HV *hv;\n";
8648   pr " PPCODE:\n";
8649   pr "      %s = guestfs_%s " n name;
8650   generate_c_call_args ~handle:"g" style;
8651   pr ";\n";
8652   do_cleanups ();
8653   pr "      if (%s == NULL)\n" n;
8654   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8655   pr "      EXTEND (SP, %s->len);\n" n;
8656   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8657   pr "        hv = newHV ();\n";
8658   List.iter (
8659     function
8660     | name, FString ->
8661         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8662           name (String.length name) n name
8663     | name, FUUID ->
8664         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8665           name (String.length name) n name
8666     | name, FBuffer ->
8667         pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8668           name (String.length name) n name n name
8669     | name, (FBytes|FUInt64) ->
8670         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8671           name (String.length name) n name
8672     | name, FInt64 ->
8673         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8674           name (String.length name) n name
8675     | name, (FInt32|FUInt32) ->
8676         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8677           name (String.length name) n name
8678     | name, FChar ->
8679         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8680           name (String.length name) n name
8681     | name, FOptPercent ->
8682         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8683           name (String.length name) n name
8684   ) cols;
8685   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8686   pr "      }\n";
8687   pr "      guestfs_free_%s_list (%s);\n" typ n
8688
8689 and generate_perl_struct_code typ cols name style n do_cleanups =
8690   pr "PREINIT:\n";
8691   pr "      struct guestfs_%s *%s;\n" typ n;
8692   pr " PPCODE:\n";
8693   pr "      %s = guestfs_%s " n name;
8694   generate_c_call_args ~handle:"g" style;
8695   pr ";\n";
8696   do_cleanups ();
8697   pr "      if (%s == NULL)\n" n;
8698   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8699   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8700   List.iter (
8701     fun ((name, _) as col) ->
8702       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8703
8704       match col with
8705       | name, FString ->
8706           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8707             n name
8708       | name, FBuffer ->
8709           pr "      PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
8710             n name n name
8711       | name, FUUID ->
8712           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8713             n name
8714       | name, (FBytes|FUInt64) ->
8715           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8716             n name
8717       | name, FInt64 ->
8718           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8719             n name
8720       | name, (FInt32|FUInt32) ->
8721           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8722             n name
8723       | name, FChar ->
8724           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8725             n name
8726       | name, FOptPercent ->
8727           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8728             n name
8729   ) cols;
8730   pr "      free (%s);\n" n
8731
8732 (* Generate Sys/Guestfs.pm. *)
8733 and generate_perl_pm () =
8734   generate_header HashStyle LGPLv2plus;
8735
8736   pr "\
8737 =pod
8738
8739 =head1 NAME
8740
8741 Sys::Guestfs - Perl bindings for libguestfs
8742
8743 =head1 SYNOPSIS
8744
8745  use Sys::Guestfs;
8746
8747  my $h = Sys::Guestfs->new ();
8748  $h->add_drive ('guest.img');
8749  $h->launch ();
8750  $h->mount ('/dev/sda1', '/');
8751  $h->touch ('/hello');
8752  $h->sync ();
8753
8754 =head1 DESCRIPTION
8755
8756 The C<Sys::Guestfs> module provides a Perl XS binding to the
8757 libguestfs API for examining and modifying virtual machine
8758 disk images.
8759
8760 Amongst the things this is good for: making batch configuration
8761 changes to guests, getting disk used/free statistics (see also:
8762 virt-df), migrating between virtualization systems (see also:
8763 virt-p2v), performing partial backups, performing partial guest
8764 clones, cloning guests and changing registry/UUID/hostname info, and
8765 much else besides.
8766
8767 Libguestfs uses Linux kernel and qemu code, and can access any type of
8768 guest filesystem that Linux and qemu can, including but not limited
8769 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8770 schemes, qcow, qcow2, vmdk.
8771
8772 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8773 LVs, what filesystem is in each LV, etc.).  It can also run commands
8774 in the context of the guest.  Also you can access filesystems over
8775 FUSE.
8776
8777 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8778 functions for using libguestfs from Perl, including integration
8779 with libvirt.
8780
8781 =head1 ERRORS
8782
8783 All errors turn into calls to C<croak> (see L<Carp(3)>).
8784
8785 =head1 METHODS
8786
8787 =over 4
8788
8789 =cut
8790
8791 package Sys::Guestfs;
8792
8793 use strict;
8794 use warnings;
8795
8796 require XSLoader;
8797 XSLoader::load ('Sys::Guestfs');
8798
8799 =item $h = Sys::Guestfs->new ();
8800
8801 Create a new guestfs handle.
8802
8803 =cut
8804
8805 sub new {
8806   my $proto = shift;
8807   my $class = ref ($proto) || $proto;
8808
8809   my $self = Sys::Guestfs::_create ();
8810   bless $self, $class;
8811   return $self;
8812 }
8813
8814 ";
8815
8816   (* Actions.  We only need to print documentation for these as
8817    * they are pulled in from the XS code automatically.
8818    *)
8819   List.iter (
8820     fun (name, style, _, flags, _, _, longdesc) ->
8821       if not (List.mem NotInDocs flags) then (
8822         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8823         pr "=item ";
8824         generate_perl_prototype name style;
8825         pr "\n\n";
8826         pr "%s\n\n" longdesc;
8827         if List.mem ProtocolLimitWarning flags then
8828           pr "%s\n\n" protocol_limit_warning;
8829         if List.mem DangerWillRobinson flags then
8830           pr "%s\n\n" danger_will_robinson;
8831         match deprecation_notice flags with
8832         | None -> ()
8833         | Some txt -> pr "%s\n\n" txt
8834       )
8835   ) all_functions_sorted;
8836
8837   (* End of file. *)
8838   pr "\
8839 =cut
8840
8841 1;
8842
8843 =back
8844
8845 =head1 COPYRIGHT
8846
8847 Copyright (C) %s Red Hat Inc.
8848
8849 =head1 LICENSE
8850
8851 Please see the file COPYING.LIB for the full license.
8852
8853 =head1 SEE ALSO
8854
8855 L<guestfs(3)>,
8856 L<guestfish(1)>,
8857 L<http://libguestfs.org>,
8858 L<Sys::Guestfs::Lib(3)>.
8859
8860 =cut
8861 " copyright_years
8862
8863 and generate_perl_prototype name style =
8864   (match fst style with
8865    | RErr -> ()
8866    | RBool n
8867    | RInt n
8868    | RInt64 n
8869    | RConstString n
8870    | RConstOptString n
8871    | RString n
8872    | RBufferOut n -> pr "$%s = " n
8873    | RStruct (n,_)
8874    | RHashtable n -> pr "%%%s = " n
8875    | RStringList n
8876    | RStructList (n,_) -> pr "@%s = " n
8877   );
8878   pr "$h->%s (" name;
8879   let comma = ref false in
8880   List.iter (
8881     fun arg ->
8882       if !comma then pr ", ";
8883       comma := true;
8884       match arg with
8885       | Pathname n | Device n | Dev_or_Path n | String n
8886       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8887           pr "$%s" n
8888       | StringList n | DeviceList n ->
8889           pr "\\@%s" n
8890   ) (snd style);
8891   pr ");"
8892
8893 (* Generate Python C module. *)
8894 and generate_python_c () =
8895   generate_header CStyle LGPLv2plus;
8896
8897   pr "\
8898 #include <Python.h>
8899
8900 #include <stdio.h>
8901 #include <stdlib.h>
8902 #include <assert.h>
8903
8904 #include \"guestfs.h\"
8905
8906 typedef struct {
8907   PyObject_HEAD
8908   guestfs_h *g;
8909 } Pyguestfs_Object;
8910
8911 static guestfs_h *
8912 get_handle (PyObject *obj)
8913 {
8914   assert (obj);
8915   assert (obj != Py_None);
8916   return ((Pyguestfs_Object *) obj)->g;
8917 }
8918
8919 static PyObject *
8920 put_handle (guestfs_h *g)
8921 {
8922   assert (g);
8923   return
8924     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8925 }
8926
8927 /* This list should be freed (but not the strings) after use. */
8928 static char **
8929 get_string_list (PyObject *obj)
8930 {
8931   int i, len;
8932   char **r;
8933
8934   assert (obj);
8935
8936   if (!PyList_Check (obj)) {
8937     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8938     return NULL;
8939   }
8940
8941   len = PyList_Size (obj);
8942   r = malloc (sizeof (char *) * (len+1));
8943   if (r == NULL) {
8944     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8945     return NULL;
8946   }
8947
8948   for (i = 0; i < len; ++i)
8949     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8950   r[len] = NULL;
8951
8952   return r;
8953 }
8954
8955 static PyObject *
8956 put_string_list (char * const * const argv)
8957 {
8958   PyObject *list;
8959   int argc, i;
8960
8961   for (argc = 0; argv[argc] != NULL; ++argc)
8962     ;
8963
8964   list = PyList_New (argc);
8965   for (i = 0; i < argc; ++i)
8966     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8967
8968   return list;
8969 }
8970
8971 static PyObject *
8972 put_table (char * const * const argv)
8973 {
8974   PyObject *list, *item;
8975   int argc, i;
8976
8977   for (argc = 0; argv[argc] != NULL; ++argc)
8978     ;
8979
8980   list = PyList_New (argc >> 1);
8981   for (i = 0; i < argc; i += 2) {
8982     item = PyTuple_New (2);
8983     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8984     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8985     PyList_SetItem (list, i >> 1, item);
8986   }
8987
8988   return list;
8989 }
8990
8991 static void
8992 free_strings (char **argv)
8993 {
8994   int argc;
8995
8996   for (argc = 0; argv[argc] != NULL; ++argc)
8997     free (argv[argc]);
8998   free (argv);
8999 }
9000
9001 static PyObject *
9002 py_guestfs_create (PyObject *self, PyObject *args)
9003 {
9004   guestfs_h *g;
9005
9006   g = guestfs_create ();
9007   if (g == NULL) {
9008     PyErr_SetString (PyExc_RuntimeError,
9009                      \"guestfs.create: failed to allocate handle\");
9010     return NULL;
9011   }
9012   guestfs_set_error_handler (g, NULL, NULL);
9013   return put_handle (g);
9014 }
9015
9016 static PyObject *
9017 py_guestfs_close (PyObject *self, PyObject *args)
9018 {
9019   PyObject *py_g;
9020   guestfs_h *g;
9021
9022   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
9023     return NULL;
9024   g = get_handle (py_g);
9025
9026   guestfs_close (g);
9027
9028   Py_INCREF (Py_None);
9029   return Py_None;
9030 }
9031
9032 ";
9033
9034   let emit_put_list_function typ =
9035     pr "static PyObject *\n";
9036     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
9037     pr "{\n";
9038     pr "  PyObject *list;\n";
9039     pr "  int i;\n";
9040     pr "\n";
9041     pr "  list = PyList_New (%ss->len);\n" typ;
9042     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
9043     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
9044     pr "  return list;\n";
9045     pr "};\n";
9046     pr "\n"
9047   in
9048
9049   (* Structures, turned into Python dictionaries. *)
9050   List.iter (
9051     fun (typ, cols) ->
9052       pr "static PyObject *\n";
9053       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
9054       pr "{\n";
9055       pr "  PyObject *dict;\n";
9056       pr "\n";
9057       pr "  dict = PyDict_New ();\n";
9058       List.iter (
9059         function
9060         | name, FString ->
9061             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9062             pr "                        PyString_FromString (%s->%s));\n"
9063               typ name
9064         | name, FBuffer ->
9065             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9066             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
9067               typ name typ name
9068         | name, FUUID ->
9069             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9070             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
9071               typ name
9072         | name, (FBytes|FUInt64) ->
9073             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9074             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
9075               typ name
9076         | name, FInt64 ->
9077             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9078             pr "                        PyLong_FromLongLong (%s->%s));\n"
9079               typ name
9080         | name, FUInt32 ->
9081             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9082             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
9083               typ name
9084         | name, FInt32 ->
9085             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9086             pr "                        PyLong_FromLong (%s->%s));\n"
9087               typ name
9088         | name, FOptPercent ->
9089             pr "  if (%s->%s >= 0)\n" typ name;
9090             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
9091             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
9092               typ name;
9093             pr "  else {\n";
9094             pr "    Py_INCREF (Py_None);\n";
9095             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
9096             pr "  }\n"
9097         | name, FChar ->
9098             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9099             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
9100       ) cols;
9101       pr "  return dict;\n";
9102       pr "};\n";
9103       pr "\n";
9104
9105   ) structs;
9106
9107   (* Emit a put_TYPE_list function definition only if that function is used. *)
9108   List.iter (
9109     function
9110     | typ, (RStructListOnly | RStructAndList) ->
9111         (* generate the function for typ *)
9112         emit_put_list_function typ
9113     | typ, _ -> () (* empty *)
9114   ) (rstructs_used_by all_functions);
9115
9116   (* Python wrapper functions. *)
9117   List.iter (
9118     fun (name, style, _, _, _, _, _) ->
9119       pr "static PyObject *\n";
9120       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
9121       pr "{\n";
9122
9123       pr "  PyObject *py_g;\n";
9124       pr "  guestfs_h *g;\n";
9125       pr "  PyObject *py_r;\n";
9126
9127       let error_code =
9128         match fst style with
9129         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9130         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9131         | RConstString _ | RConstOptString _ ->
9132             pr "  const char *r;\n"; "NULL"
9133         | RString _ -> pr "  char *r;\n"; "NULL"
9134         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9135         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9136         | RStructList (_, typ) ->
9137             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9138         | RBufferOut _ ->
9139             pr "  char *r;\n";
9140             pr "  size_t size;\n";
9141             "NULL" in
9142
9143       List.iter (
9144         function
9145         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9146             pr "  const char *%s;\n" n
9147         | OptString n -> pr "  const char *%s;\n" n
9148         | StringList n | DeviceList n ->
9149             pr "  PyObject *py_%s;\n" n;
9150             pr "  char **%s;\n" n
9151         | Bool n -> pr "  int %s;\n" n
9152         | Int n -> pr "  int %s;\n" n
9153         | Int64 n -> pr "  long long %s;\n" n
9154       ) (snd style);
9155
9156       pr "\n";
9157
9158       (* Convert the parameters. *)
9159       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
9160       List.iter (
9161         function
9162         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
9163         | OptString _ -> pr "z"
9164         | StringList _ | DeviceList _ -> pr "O"
9165         | Bool _ -> pr "i" (* XXX Python has booleans? *)
9166         | Int _ -> pr "i"
9167         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
9168                              * emulate C's int/long/long long in Python?
9169                              *)
9170       ) (snd style);
9171       pr ":guestfs_%s\",\n" name;
9172       pr "                         &py_g";
9173       List.iter (
9174         function
9175         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
9176         | OptString n -> pr ", &%s" n
9177         | StringList n | DeviceList n -> pr ", &py_%s" n
9178         | Bool n -> pr ", &%s" n
9179         | Int n -> pr ", &%s" n
9180         | Int64 n -> pr ", &%s" n
9181       ) (snd style);
9182
9183       pr "))\n";
9184       pr "    return NULL;\n";
9185
9186       pr "  g = get_handle (py_g);\n";
9187       List.iter (
9188         function
9189         | Pathname _ | Device _ | Dev_or_Path _ | String _
9190         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9191         | StringList n | DeviceList n ->
9192             pr "  %s = get_string_list (py_%s);\n" n n;
9193             pr "  if (!%s) return NULL;\n" n
9194       ) (snd style);
9195
9196       pr "\n";
9197
9198       pr "  r = guestfs_%s " name;
9199       generate_c_call_args ~handle:"g" style;
9200       pr ";\n";
9201
9202       List.iter (
9203         function
9204         | Pathname _ | Device _ | Dev_or_Path _ | String _
9205         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9206         | StringList n | DeviceList n ->
9207             pr "  free (%s);\n" n
9208       ) (snd style);
9209
9210       pr "  if (r == %s) {\n" error_code;
9211       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
9212       pr "    return NULL;\n";
9213       pr "  }\n";
9214       pr "\n";
9215
9216       (match fst style with
9217        | RErr ->
9218            pr "  Py_INCREF (Py_None);\n";
9219            pr "  py_r = Py_None;\n"
9220        | RInt _
9221        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
9222        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
9223        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
9224        | RConstOptString _ ->
9225            pr "  if (r)\n";
9226            pr "    py_r = PyString_FromString (r);\n";
9227            pr "  else {\n";
9228            pr "    Py_INCREF (Py_None);\n";
9229            pr "    py_r = Py_None;\n";
9230            pr "  }\n"
9231        | RString _ ->
9232            pr "  py_r = PyString_FromString (r);\n";
9233            pr "  free (r);\n"
9234        | RStringList _ ->
9235            pr "  py_r = put_string_list (r);\n";
9236            pr "  free_strings (r);\n"
9237        | RStruct (_, typ) ->
9238            pr "  py_r = put_%s (r);\n" typ;
9239            pr "  guestfs_free_%s (r);\n" typ
9240        | RStructList (_, typ) ->
9241            pr "  py_r = put_%s_list (r);\n" typ;
9242            pr "  guestfs_free_%s_list (r);\n" typ
9243        | RHashtable n ->
9244            pr "  py_r = put_table (r);\n";
9245            pr "  free_strings (r);\n"
9246        | RBufferOut _ ->
9247            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
9248            pr "  free (r);\n"
9249       );
9250
9251       pr "  return py_r;\n";
9252       pr "}\n";
9253       pr "\n"
9254   ) all_functions;
9255
9256   (* Table of functions. *)
9257   pr "static PyMethodDef methods[] = {\n";
9258   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
9259   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
9260   List.iter (
9261     fun (name, _, _, _, _, _, _) ->
9262       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
9263         name name
9264   ) all_functions;
9265   pr "  { NULL, NULL, 0, NULL }\n";
9266   pr "};\n";
9267   pr "\n";
9268
9269   (* Init function. *)
9270   pr "\
9271 void
9272 initlibguestfsmod (void)
9273 {
9274   static int initialized = 0;
9275
9276   if (initialized) return;
9277   Py_InitModule ((char *) \"libguestfsmod\", methods);
9278   initialized = 1;
9279 }
9280 "
9281
9282 (* Generate Python module. *)
9283 and generate_python_py () =
9284   generate_header HashStyle LGPLv2plus;
9285
9286   pr "\
9287 u\"\"\"Python bindings for libguestfs
9288
9289 import guestfs
9290 g = guestfs.GuestFS ()
9291 g.add_drive (\"guest.img\")
9292 g.launch ()
9293 parts = g.list_partitions ()
9294
9295 The guestfs module provides a Python binding to the libguestfs API
9296 for examining and modifying virtual machine disk images.
9297
9298 Amongst the things this is good for: making batch configuration
9299 changes to guests, getting disk used/free statistics (see also:
9300 virt-df), migrating between virtualization systems (see also:
9301 virt-p2v), performing partial backups, performing partial guest
9302 clones, cloning guests and changing registry/UUID/hostname info, and
9303 much else besides.
9304
9305 Libguestfs uses Linux kernel and qemu code, and can access any type of
9306 guest filesystem that Linux and qemu can, including but not limited
9307 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
9308 schemes, qcow, qcow2, vmdk.
9309
9310 Libguestfs provides ways to enumerate guest storage (eg. partitions,
9311 LVs, what filesystem is in each LV, etc.).  It can also run commands
9312 in the context of the guest.  Also you can access filesystems over
9313 FUSE.
9314
9315 Errors which happen while using the API are turned into Python
9316 RuntimeError exceptions.
9317
9318 To create a guestfs handle you usually have to perform the following
9319 sequence of calls:
9320
9321 # Create the handle, call add_drive at least once, and possibly
9322 # several times if the guest has multiple block devices:
9323 g = guestfs.GuestFS ()
9324 g.add_drive (\"guest.img\")
9325
9326 # Launch the qemu subprocess and wait for it to become ready:
9327 g.launch ()
9328
9329 # Now you can issue commands, for example:
9330 logvols = g.lvs ()
9331
9332 \"\"\"
9333
9334 import libguestfsmod
9335
9336 class GuestFS:
9337     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
9338
9339     def __init__ (self):
9340         \"\"\"Create a new libguestfs handle.\"\"\"
9341         self._o = libguestfsmod.create ()
9342
9343     def __del__ (self):
9344         libguestfsmod.close (self._o)
9345
9346 ";
9347
9348   List.iter (
9349     fun (name, style, _, flags, _, _, longdesc) ->
9350       pr "    def %s " name;
9351       generate_py_call_args ~handle:"self" (snd style);
9352       pr ":\n";
9353
9354       if not (List.mem NotInDocs flags) then (
9355         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9356         let doc =
9357           match fst style with
9358           | RErr | RInt _ | RInt64 _ | RBool _
9359           | RConstOptString _ | RConstString _
9360           | RString _ | RBufferOut _ -> doc
9361           | RStringList _ ->
9362               doc ^ "\n\nThis function returns a list of strings."
9363           | RStruct (_, typ) ->
9364               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
9365           | RStructList (_, typ) ->
9366               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
9367           | RHashtable _ ->
9368               doc ^ "\n\nThis function returns a dictionary." in
9369         let doc =
9370           if List.mem ProtocolLimitWarning flags then
9371             doc ^ "\n\n" ^ protocol_limit_warning
9372           else doc in
9373         let doc =
9374           if List.mem DangerWillRobinson flags then
9375             doc ^ "\n\n" ^ danger_will_robinson
9376           else doc in
9377         let doc =
9378           match deprecation_notice flags with
9379           | None -> doc
9380           | Some txt -> doc ^ "\n\n" ^ txt in
9381         let doc = pod2text ~width:60 name doc in
9382         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
9383         let doc = String.concat "\n        " doc in
9384         pr "        u\"\"\"%s\"\"\"\n" doc;
9385       );
9386       pr "        return libguestfsmod.%s " name;
9387       generate_py_call_args ~handle:"self._o" (snd style);
9388       pr "\n";
9389       pr "\n";
9390   ) all_functions
9391
9392 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
9393 and generate_py_call_args ~handle args =
9394   pr "(%s" handle;
9395   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9396   pr ")"
9397
9398 (* Useful if you need the longdesc POD text as plain text.  Returns a
9399  * list of lines.
9400  *
9401  * Because this is very slow (the slowest part of autogeneration),
9402  * we memoize the results.
9403  *)
9404 and pod2text ~width name longdesc =
9405   let key = width, name, longdesc in
9406   try Hashtbl.find pod2text_memo key
9407   with Not_found ->
9408     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
9409     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
9410     close_out chan;
9411     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
9412     let chan = open_process_in cmd in
9413     let lines = ref [] in
9414     let rec loop i =
9415       let line = input_line chan in
9416       if i = 1 then             (* discard the first line of output *)
9417         loop (i+1)
9418       else (
9419         let line = triml line in
9420         lines := line :: !lines;
9421         loop (i+1)
9422       ) in
9423     let lines = try loop 1 with End_of_file -> List.rev !lines in
9424     unlink filename;
9425     (match close_process_in chan with
9426      | WEXITED 0 -> ()
9427      | WEXITED i ->
9428          failwithf "pod2text: process exited with non-zero status (%d)" i
9429      | WSIGNALED i | WSTOPPED i ->
9430          failwithf "pod2text: process signalled or stopped by signal %d" i
9431     );
9432     Hashtbl.add pod2text_memo key lines;
9433     pod2text_memo_updated ();
9434     lines
9435
9436 (* Generate ruby bindings. *)
9437 and generate_ruby_c () =
9438   generate_header CStyle LGPLv2plus;
9439
9440   pr "\
9441 #include <stdio.h>
9442 #include <stdlib.h>
9443
9444 #include <ruby.h>
9445
9446 #include \"guestfs.h\"
9447
9448 #include \"extconf.h\"
9449
9450 /* For Ruby < 1.9 */
9451 #ifndef RARRAY_LEN
9452 #define RARRAY_LEN(r) (RARRAY((r))->len)
9453 #endif
9454
9455 static VALUE m_guestfs;                 /* guestfs module */
9456 static VALUE c_guestfs;                 /* guestfs_h handle */
9457 static VALUE e_Error;                   /* used for all errors */
9458
9459 static void ruby_guestfs_free (void *p)
9460 {
9461   if (!p) return;
9462   guestfs_close ((guestfs_h *) p);
9463 }
9464
9465 static VALUE ruby_guestfs_create (VALUE m)
9466 {
9467   guestfs_h *g;
9468
9469   g = guestfs_create ();
9470   if (!g)
9471     rb_raise (e_Error, \"failed to create guestfs handle\");
9472
9473   /* Don't print error messages to stderr by default. */
9474   guestfs_set_error_handler (g, NULL, NULL);
9475
9476   /* Wrap it, and make sure the close function is called when the
9477    * handle goes away.
9478    */
9479   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9480 }
9481
9482 static VALUE ruby_guestfs_close (VALUE gv)
9483 {
9484   guestfs_h *g;
9485   Data_Get_Struct (gv, guestfs_h, g);
9486
9487   ruby_guestfs_free (g);
9488   DATA_PTR (gv) = NULL;
9489
9490   return Qnil;
9491 }
9492
9493 ";
9494
9495   List.iter (
9496     fun (name, style, _, _, _, _, _) ->
9497       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9498       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9499       pr ")\n";
9500       pr "{\n";
9501       pr "  guestfs_h *g;\n";
9502       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9503       pr "  if (!g)\n";
9504       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9505         name;
9506       pr "\n";
9507
9508       List.iter (
9509         function
9510         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9511             pr "  Check_Type (%sv, T_STRING);\n" n;
9512             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9513             pr "  if (!%s)\n" n;
9514             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9515             pr "              \"%s\", \"%s\");\n" n name
9516         | OptString n ->
9517             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9518         | StringList n | DeviceList n ->
9519             pr "  char **%s;\n" n;
9520             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9521             pr "  {\n";
9522             pr "    int i, len;\n";
9523             pr "    len = RARRAY_LEN (%sv);\n" n;
9524             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9525               n;
9526             pr "    for (i = 0; i < len; ++i) {\n";
9527             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9528             pr "      %s[i] = StringValueCStr (v);\n" n;
9529             pr "    }\n";
9530             pr "    %s[len] = NULL;\n" n;
9531             pr "  }\n";
9532         | Bool n ->
9533             pr "  int %s = RTEST (%sv);\n" n n
9534         | Int n ->
9535             pr "  int %s = NUM2INT (%sv);\n" n n
9536         | Int64 n ->
9537             pr "  long long %s = NUM2LL (%sv);\n" n n
9538       ) (snd style);
9539       pr "\n";
9540
9541       let error_code =
9542         match fst style with
9543         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9544         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9545         | RConstString _ | RConstOptString _ ->
9546             pr "  const char *r;\n"; "NULL"
9547         | RString _ -> pr "  char *r;\n"; "NULL"
9548         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9549         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9550         | RStructList (_, typ) ->
9551             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9552         | RBufferOut _ ->
9553             pr "  char *r;\n";
9554             pr "  size_t size;\n";
9555             "NULL" in
9556       pr "\n";
9557
9558       pr "  r = guestfs_%s " name;
9559       generate_c_call_args ~handle:"g" style;
9560       pr ";\n";
9561
9562       List.iter (
9563         function
9564         | Pathname _ | Device _ | Dev_or_Path _ | String _
9565         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9566         | StringList n | DeviceList n ->
9567             pr "  free (%s);\n" n
9568       ) (snd style);
9569
9570       pr "  if (r == %s)\n" error_code;
9571       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9572       pr "\n";
9573
9574       (match fst style with
9575        | RErr ->
9576            pr "  return Qnil;\n"
9577        | RInt _ | RBool _ ->
9578            pr "  return INT2NUM (r);\n"
9579        | RInt64 _ ->
9580            pr "  return ULL2NUM (r);\n"
9581        | RConstString _ ->
9582            pr "  return rb_str_new2 (r);\n";
9583        | RConstOptString _ ->
9584            pr "  if (r)\n";
9585            pr "    return rb_str_new2 (r);\n";
9586            pr "  else\n";
9587            pr "    return Qnil;\n";
9588        | RString _ ->
9589            pr "  VALUE rv = rb_str_new2 (r);\n";
9590            pr "  free (r);\n";
9591            pr "  return rv;\n";
9592        | RStringList _ ->
9593            pr "  int i, len = 0;\n";
9594            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9595            pr "  VALUE rv = rb_ary_new2 (len);\n";
9596            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9597            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9598            pr "    free (r[i]);\n";
9599            pr "  }\n";
9600            pr "  free (r);\n";
9601            pr "  return rv;\n"
9602        | RStruct (_, typ) ->
9603            let cols = cols_of_struct typ in
9604            generate_ruby_struct_code typ cols
9605        | RStructList (_, typ) ->
9606            let cols = cols_of_struct typ in
9607            generate_ruby_struct_list_code typ cols
9608        | RHashtable _ ->
9609            pr "  VALUE rv = rb_hash_new ();\n";
9610            pr "  int i;\n";
9611            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9612            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9613            pr "    free (r[i]);\n";
9614            pr "    free (r[i+1]);\n";
9615            pr "  }\n";
9616            pr "  free (r);\n";
9617            pr "  return rv;\n"
9618        | RBufferOut _ ->
9619            pr "  VALUE rv = rb_str_new (r, size);\n";
9620            pr "  free (r);\n";
9621            pr "  return rv;\n";
9622       );
9623
9624       pr "}\n";
9625       pr "\n"
9626   ) all_functions;
9627
9628   pr "\
9629 /* Initialize the module. */
9630 void Init__guestfs ()
9631 {
9632   m_guestfs = rb_define_module (\"Guestfs\");
9633   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9634   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9635
9636   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9637   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9638
9639 ";
9640   (* Define the rest of the methods. *)
9641   List.iter (
9642     fun (name, style, _, _, _, _, _) ->
9643       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9644       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9645   ) all_functions;
9646
9647   pr "}\n"
9648
9649 (* Ruby code to return a struct. *)
9650 and generate_ruby_struct_code typ cols =
9651   pr "  VALUE rv = rb_hash_new ();\n";
9652   List.iter (
9653     function
9654     | name, FString ->
9655         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9656     | name, FBuffer ->
9657         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9658     | name, FUUID ->
9659         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9660     | name, (FBytes|FUInt64) ->
9661         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9662     | name, FInt64 ->
9663         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9664     | name, FUInt32 ->
9665         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9666     | name, FInt32 ->
9667         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9668     | name, FOptPercent ->
9669         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9670     | name, FChar -> (* XXX wrong? *)
9671         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9672   ) cols;
9673   pr "  guestfs_free_%s (r);\n" typ;
9674   pr "  return rv;\n"
9675
9676 (* Ruby code to return a struct list. *)
9677 and generate_ruby_struct_list_code typ cols =
9678   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9679   pr "  int i;\n";
9680   pr "  for (i = 0; i < r->len; ++i) {\n";
9681   pr "    VALUE hv = rb_hash_new ();\n";
9682   List.iter (
9683     function
9684     | name, FString ->
9685         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9686     | name, FBuffer ->
9687         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
9688     | name, FUUID ->
9689         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9690     | name, (FBytes|FUInt64) ->
9691         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9692     | name, FInt64 ->
9693         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9694     | name, FUInt32 ->
9695         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9696     | name, FInt32 ->
9697         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9698     | name, FOptPercent ->
9699         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9700     | name, FChar -> (* XXX wrong? *)
9701         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9702   ) cols;
9703   pr "    rb_ary_push (rv, hv);\n";
9704   pr "  }\n";
9705   pr "  guestfs_free_%s_list (r);\n" typ;
9706   pr "  return rv;\n"
9707
9708 (* Generate Java bindings GuestFS.java file. *)
9709 and generate_java_java () =
9710   generate_header CStyle LGPLv2plus;
9711
9712   pr "\
9713 package com.redhat.et.libguestfs;
9714
9715 import java.util.HashMap;
9716 import com.redhat.et.libguestfs.LibGuestFSException;
9717 import com.redhat.et.libguestfs.PV;
9718 import com.redhat.et.libguestfs.VG;
9719 import com.redhat.et.libguestfs.LV;
9720 import com.redhat.et.libguestfs.Stat;
9721 import com.redhat.et.libguestfs.StatVFS;
9722 import com.redhat.et.libguestfs.IntBool;
9723 import com.redhat.et.libguestfs.Dirent;
9724
9725 /**
9726  * The GuestFS object is a libguestfs handle.
9727  *
9728  * @author rjones
9729  */
9730 public class GuestFS {
9731   // Load the native code.
9732   static {
9733     System.loadLibrary (\"guestfs_jni\");
9734   }
9735
9736   /**
9737    * The native guestfs_h pointer.
9738    */
9739   long g;
9740
9741   /**
9742    * Create a libguestfs handle.
9743    *
9744    * @throws LibGuestFSException
9745    */
9746   public GuestFS () throws LibGuestFSException
9747   {
9748     g = _create ();
9749   }
9750   private native long _create () throws LibGuestFSException;
9751
9752   /**
9753    * Close a libguestfs handle.
9754    *
9755    * You can also leave handles to be collected by the garbage
9756    * collector, but this method ensures that the resources used
9757    * by the handle are freed up immediately.  If you call any
9758    * other methods after closing the handle, you will get an
9759    * exception.
9760    *
9761    * @throws LibGuestFSException
9762    */
9763   public void close () throws LibGuestFSException
9764   {
9765     if (g != 0)
9766       _close (g);
9767     g = 0;
9768   }
9769   private native void _close (long g) throws LibGuestFSException;
9770
9771   public void finalize () throws LibGuestFSException
9772   {
9773     close ();
9774   }
9775
9776 ";
9777
9778   List.iter (
9779     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9780       if not (List.mem NotInDocs flags); then (
9781         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9782         let doc =
9783           if List.mem ProtocolLimitWarning flags then
9784             doc ^ "\n\n" ^ protocol_limit_warning
9785           else doc in
9786         let doc =
9787           if List.mem DangerWillRobinson flags then
9788             doc ^ "\n\n" ^ danger_will_robinson
9789           else doc in
9790         let doc =
9791           match deprecation_notice flags with
9792           | None -> doc
9793           | Some txt -> doc ^ "\n\n" ^ txt in
9794         let doc = pod2text ~width:60 name doc in
9795         let doc = List.map (            (* RHBZ#501883 *)
9796           function
9797           | "" -> "<p>"
9798           | nonempty -> nonempty
9799         ) doc in
9800         let doc = String.concat "\n   * " doc in
9801
9802         pr "  /**\n";
9803         pr "   * %s\n" shortdesc;
9804         pr "   * <p>\n";
9805         pr "   * %s\n" doc;
9806         pr "   * @throws LibGuestFSException\n";
9807         pr "   */\n";
9808         pr "  ";
9809       );
9810       generate_java_prototype ~public:true ~semicolon:false name style;
9811       pr "\n";
9812       pr "  {\n";
9813       pr "    if (g == 0)\n";
9814       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9815         name;
9816       pr "    ";
9817       if fst style <> RErr then pr "return ";
9818       pr "_%s " name;
9819       generate_java_call_args ~handle:"g" (snd style);
9820       pr ";\n";
9821       pr "  }\n";
9822       pr "  ";
9823       generate_java_prototype ~privat:true ~native:true name style;
9824       pr "\n";
9825       pr "\n";
9826   ) all_functions;
9827
9828   pr "}\n"
9829
9830 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9831 and generate_java_call_args ~handle args =
9832   pr "(%s" handle;
9833   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9834   pr ")"
9835
9836 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9837     ?(semicolon=true) name style =
9838   if privat then pr "private ";
9839   if public then pr "public ";
9840   if native then pr "native ";
9841
9842   (* return type *)
9843   (match fst style with
9844    | RErr -> pr "void ";
9845    | RInt _ -> pr "int ";
9846    | RInt64 _ -> pr "long ";
9847    | RBool _ -> pr "boolean ";
9848    | RConstString _ | RConstOptString _ | RString _
9849    | RBufferOut _ -> pr "String ";
9850    | RStringList _ -> pr "String[] ";
9851    | RStruct (_, typ) ->
9852        let name = java_name_of_struct typ in
9853        pr "%s " name;
9854    | RStructList (_, typ) ->
9855        let name = java_name_of_struct typ in
9856        pr "%s[] " name;
9857    | RHashtable _ -> pr "HashMap<String,String> ";
9858   );
9859
9860   if native then pr "_%s " name else pr "%s " name;
9861   pr "(";
9862   let needs_comma = ref false in
9863   if native then (
9864     pr "long g";
9865     needs_comma := true
9866   );
9867
9868   (* args *)
9869   List.iter (
9870     fun arg ->
9871       if !needs_comma then pr ", ";
9872       needs_comma := true;
9873
9874       match arg with
9875       | Pathname n
9876       | Device n | Dev_or_Path n
9877       | String n
9878       | OptString n
9879       | FileIn n
9880       | FileOut n ->
9881           pr "String %s" n
9882       | StringList n | DeviceList n ->
9883           pr "String[] %s" n
9884       | Bool n ->
9885           pr "boolean %s" n
9886       | Int n ->
9887           pr "int %s" n
9888       | Int64 n ->
9889           pr "long %s" n
9890   ) (snd style);
9891
9892   pr ")\n";
9893   pr "    throws LibGuestFSException";
9894   if semicolon then pr ";"
9895
9896 and generate_java_struct jtyp cols () =
9897   generate_header CStyle LGPLv2plus;
9898
9899   pr "\
9900 package com.redhat.et.libguestfs;
9901
9902 /**
9903  * Libguestfs %s structure.
9904  *
9905  * @author rjones
9906  * @see GuestFS
9907  */
9908 public class %s {
9909 " jtyp jtyp;
9910
9911   List.iter (
9912     function
9913     | name, FString
9914     | name, FUUID
9915     | name, FBuffer -> pr "  public String %s;\n" name
9916     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9917     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9918     | name, FChar -> pr "  public char %s;\n" name
9919     | name, FOptPercent ->
9920         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9921         pr "  public float %s;\n" name
9922   ) cols;
9923
9924   pr "}\n"
9925
9926 and generate_java_c () =
9927   generate_header CStyle LGPLv2plus;
9928
9929   pr "\
9930 #include <stdio.h>
9931 #include <stdlib.h>
9932 #include <string.h>
9933
9934 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9935 #include \"guestfs.h\"
9936
9937 /* Note that this function returns.  The exception is not thrown
9938  * until after the wrapper function returns.
9939  */
9940 static void
9941 throw_exception (JNIEnv *env, const char *msg)
9942 {
9943   jclass cl;
9944   cl = (*env)->FindClass (env,
9945                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9946   (*env)->ThrowNew (env, cl, msg);
9947 }
9948
9949 JNIEXPORT jlong JNICALL
9950 Java_com_redhat_et_libguestfs_GuestFS__1create
9951   (JNIEnv *env, jobject obj)
9952 {
9953   guestfs_h *g;
9954
9955   g = guestfs_create ();
9956   if (g == NULL) {
9957     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9958     return 0;
9959   }
9960   guestfs_set_error_handler (g, NULL, NULL);
9961   return (jlong) (long) g;
9962 }
9963
9964 JNIEXPORT void JNICALL
9965 Java_com_redhat_et_libguestfs_GuestFS__1close
9966   (JNIEnv *env, jobject obj, jlong jg)
9967 {
9968   guestfs_h *g = (guestfs_h *) (long) jg;
9969   guestfs_close (g);
9970 }
9971
9972 ";
9973
9974   List.iter (
9975     fun (name, style, _, _, _, _, _) ->
9976       pr "JNIEXPORT ";
9977       (match fst style with
9978        | RErr -> pr "void ";
9979        | RInt _ -> pr "jint ";
9980        | RInt64 _ -> pr "jlong ";
9981        | RBool _ -> pr "jboolean ";
9982        | RConstString _ | RConstOptString _ | RString _
9983        | RBufferOut _ -> pr "jstring ";
9984        | RStruct _ | RHashtable _ ->
9985            pr "jobject ";
9986        | RStringList _ | RStructList _ ->
9987            pr "jobjectArray ";
9988       );
9989       pr "JNICALL\n";
9990       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9991       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9992       pr "\n";
9993       pr "  (JNIEnv *env, jobject obj, jlong jg";
9994       List.iter (
9995         function
9996         | Pathname n
9997         | Device n | Dev_or_Path n
9998         | String n
9999         | OptString n
10000         | FileIn n
10001         | FileOut n ->
10002             pr ", jstring j%s" n
10003         | StringList n | DeviceList n ->
10004             pr ", jobjectArray j%s" n
10005         | Bool n ->
10006             pr ", jboolean j%s" n
10007         | Int n ->
10008             pr ", jint j%s" n
10009         | Int64 n ->
10010             pr ", jlong j%s" n
10011       ) (snd style);
10012       pr ")\n";
10013       pr "{\n";
10014       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
10015       let error_code, no_ret =
10016         match fst style with
10017         | RErr -> pr "  int r;\n"; "-1", ""
10018         | RBool _
10019         | RInt _ -> pr "  int r;\n"; "-1", "0"
10020         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
10021         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10022         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10023         | RString _ ->
10024             pr "  jstring jr;\n";
10025             pr "  char *r;\n"; "NULL", "NULL"
10026         | RStringList _ ->
10027             pr "  jobjectArray jr;\n";
10028             pr "  int r_len;\n";
10029             pr "  jclass cl;\n";
10030             pr "  jstring jstr;\n";
10031             pr "  char **r;\n"; "NULL", "NULL"
10032         | RStruct (_, typ) ->
10033             pr "  jobject jr;\n";
10034             pr "  jclass cl;\n";
10035             pr "  jfieldID fl;\n";
10036             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
10037         | RStructList (_, typ) ->
10038             pr "  jobjectArray jr;\n";
10039             pr "  jclass cl;\n";
10040             pr "  jfieldID fl;\n";
10041             pr "  jobject jfl;\n";
10042             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
10043         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
10044         | RBufferOut _ ->
10045             pr "  jstring jr;\n";
10046             pr "  char *r;\n";
10047             pr "  size_t size;\n";
10048             "NULL", "NULL" in
10049       List.iter (
10050         function
10051         | Pathname n
10052         | Device n | Dev_or_Path n
10053         | String n
10054         | OptString n
10055         | FileIn n
10056         | FileOut n ->
10057             pr "  const char *%s;\n" n
10058         | StringList n | DeviceList n ->
10059             pr "  int %s_len;\n" n;
10060             pr "  const char **%s;\n" n
10061         | Bool n
10062         | Int n ->
10063             pr "  int %s;\n" n
10064         | Int64 n ->
10065             pr "  int64_t %s;\n" n
10066       ) (snd style);
10067
10068       let needs_i =
10069         (match fst style with
10070          | RStringList _ | RStructList _ -> true
10071          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
10072          | RConstOptString _
10073          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
10074           List.exists (function
10075                        | StringList _ -> true
10076                        | DeviceList _ -> true
10077                        | _ -> false) (snd style) in
10078       if needs_i then
10079         pr "  int i;\n";
10080
10081       pr "\n";
10082
10083       (* Get the parameters. *)
10084       List.iter (
10085         function
10086         | Pathname n
10087         | Device n | Dev_or_Path n
10088         | String n
10089         | FileIn n
10090         | FileOut n ->
10091             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
10092         | OptString n ->
10093             (* This is completely undocumented, but Java null becomes
10094              * a NULL parameter.
10095              *)
10096             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
10097         | StringList n | DeviceList n ->
10098             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
10099             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
10100             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10101             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10102               n;
10103             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
10104             pr "  }\n";
10105             pr "  %s[%s_len] = NULL;\n" n n;
10106         | Bool n
10107         | Int n
10108         | Int64 n ->
10109             pr "  %s = j%s;\n" n n
10110       ) (snd style);
10111
10112       (* Make the call. *)
10113       pr "  r = guestfs_%s " name;
10114       generate_c_call_args ~handle:"g" style;
10115       pr ";\n";
10116
10117       (* Release the parameters. *)
10118       List.iter (
10119         function
10120         | Pathname n
10121         | Device n | Dev_or_Path n
10122         | String n
10123         | FileIn n
10124         | FileOut n ->
10125             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10126         | OptString n ->
10127             pr "  if (j%s)\n" n;
10128             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10129         | StringList n | DeviceList n ->
10130             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10131             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10132               n;
10133             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
10134             pr "  }\n";
10135             pr "  free (%s);\n" n
10136         | Bool n
10137         | Int n
10138         | Int64 n -> ()
10139       ) (snd style);
10140
10141       (* Check for errors. *)
10142       pr "  if (r == %s) {\n" error_code;
10143       pr "    throw_exception (env, guestfs_last_error (g));\n";
10144       pr "    return %s;\n" no_ret;
10145       pr "  }\n";
10146
10147       (* Return value. *)
10148       (match fst style with
10149        | RErr -> ()
10150        | RInt _ -> pr "  return (jint) r;\n"
10151        | RBool _ -> pr "  return (jboolean) r;\n"
10152        | RInt64 _ -> pr "  return (jlong) r;\n"
10153        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
10154        | RConstOptString _ ->
10155            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
10156        | RString _ ->
10157            pr "  jr = (*env)->NewStringUTF (env, r);\n";
10158            pr "  free (r);\n";
10159            pr "  return jr;\n"
10160        | RStringList _ ->
10161            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
10162            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
10163            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
10164            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
10165            pr "  for (i = 0; i < r_len; ++i) {\n";
10166            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
10167            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
10168            pr "    free (r[i]);\n";
10169            pr "  }\n";
10170            pr "  free (r);\n";
10171            pr "  return jr;\n"
10172        | RStruct (_, typ) ->
10173            let jtyp = java_name_of_struct typ in
10174            let cols = cols_of_struct typ in
10175            generate_java_struct_return typ jtyp cols
10176        | RStructList (_, typ) ->
10177            let jtyp = java_name_of_struct typ in
10178            let cols = cols_of_struct typ in
10179            generate_java_struct_list_return typ jtyp cols
10180        | RHashtable _ ->
10181            (* XXX *)
10182            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
10183            pr "  return NULL;\n"
10184        | RBufferOut _ ->
10185            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
10186            pr "  free (r);\n";
10187            pr "  return jr;\n"
10188       );
10189
10190       pr "}\n";
10191       pr "\n"
10192   ) all_functions
10193
10194 and generate_java_struct_return typ jtyp cols =
10195   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10196   pr "  jr = (*env)->AllocObject (env, cl);\n";
10197   List.iter (
10198     function
10199     | name, FString ->
10200         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10201         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
10202     | name, FUUID ->
10203         pr "  {\n";
10204         pr "    char s[33];\n";
10205         pr "    memcpy (s, r->%s, 32);\n" name;
10206         pr "    s[32] = 0;\n";
10207         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10208         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10209         pr "  }\n";
10210     | name, FBuffer ->
10211         pr "  {\n";
10212         pr "    int len = r->%s_len;\n" name;
10213         pr "    char s[len+1];\n";
10214         pr "    memcpy (s, r->%s, len);\n" name;
10215         pr "    s[len] = 0;\n";
10216         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10217         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10218         pr "  }\n";
10219     | name, (FBytes|FUInt64|FInt64) ->
10220         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10221         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10222     | name, (FUInt32|FInt32) ->
10223         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10224         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10225     | name, FOptPercent ->
10226         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10227         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
10228     | name, FChar ->
10229         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10230         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10231   ) cols;
10232   pr "  free (r);\n";
10233   pr "  return jr;\n"
10234
10235 and generate_java_struct_list_return typ jtyp cols =
10236   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10237   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
10238   pr "  for (i = 0; i < r->len; ++i) {\n";
10239   pr "    jfl = (*env)->AllocObject (env, cl);\n";
10240   List.iter (
10241     function
10242     | name, FString ->
10243         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10244         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
10245     | name, FUUID ->
10246         pr "    {\n";
10247         pr "      char s[33];\n";
10248         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
10249         pr "      s[32] = 0;\n";
10250         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10251         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10252         pr "    }\n";
10253     | name, FBuffer ->
10254         pr "    {\n";
10255         pr "      int len = r->val[i].%s_len;\n" name;
10256         pr "      char s[len+1];\n";
10257         pr "      memcpy (s, r->val[i].%s, len);\n" name;
10258         pr "      s[len] = 0;\n";
10259         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10260         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10261         pr "    }\n";
10262     | name, (FBytes|FUInt64|FInt64) ->
10263         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10264         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10265     | name, (FUInt32|FInt32) ->
10266         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10267         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10268     | name, FOptPercent ->
10269         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10270         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
10271     | name, FChar ->
10272         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10273         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10274   ) cols;
10275   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
10276   pr "  }\n";
10277   pr "  guestfs_free_%s_list (r);\n" typ;
10278   pr "  return jr;\n"
10279
10280 and generate_java_makefile_inc () =
10281   generate_header HashStyle GPLv2plus;
10282
10283   pr "java_built_sources = \\\n";
10284   List.iter (
10285     fun (typ, jtyp) ->
10286         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
10287   ) java_structs;
10288   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
10289
10290 and generate_haskell_hs () =
10291   generate_header HaskellStyle LGPLv2plus;
10292
10293   (* XXX We only know how to generate partial FFI for Haskell
10294    * at the moment.  Please help out!
10295    *)
10296   let can_generate style =
10297     match style with
10298     | RErr, _
10299     | RInt _, _
10300     | RInt64 _, _ -> true
10301     | RBool _, _
10302     | RConstString _, _
10303     | RConstOptString _, _
10304     | RString _, _
10305     | RStringList _, _
10306     | RStruct _, _
10307     | RStructList _, _
10308     | RHashtable _, _
10309     | RBufferOut _, _ -> false in
10310
10311   pr "\
10312 {-# INCLUDE <guestfs.h> #-}
10313 {-# LANGUAGE ForeignFunctionInterface #-}
10314
10315 module Guestfs (
10316   create";
10317
10318   (* List out the names of the actions we want to export. *)
10319   List.iter (
10320     fun (name, style, _, _, _, _, _) ->
10321       if can_generate style then pr ",\n  %s" name
10322   ) all_functions;
10323
10324   pr "
10325   ) where
10326
10327 -- Unfortunately some symbols duplicate ones already present
10328 -- in Prelude.  We don't know which, so we hard-code a list
10329 -- here.
10330 import Prelude hiding (truncate)
10331
10332 import Foreign
10333 import Foreign.C
10334 import Foreign.C.Types
10335 import IO
10336 import Control.Exception
10337 import Data.Typeable
10338
10339 data GuestfsS = GuestfsS            -- represents the opaque C struct
10340 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
10341 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
10342
10343 -- XXX define properly later XXX
10344 data PV = PV
10345 data VG = VG
10346 data LV = LV
10347 data IntBool = IntBool
10348 data Stat = Stat
10349 data StatVFS = StatVFS
10350 data Hashtable = Hashtable
10351
10352 foreign import ccall unsafe \"guestfs_create\" c_create
10353   :: IO GuestfsP
10354 foreign import ccall unsafe \"&guestfs_close\" c_close
10355   :: FunPtr (GuestfsP -> IO ())
10356 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
10357   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
10358
10359 create :: IO GuestfsH
10360 create = do
10361   p <- c_create
10362   c_set_error_handler p nullPtr nullPtr
10363   h <- newForeignPtr c_close p
10364   return h
10365
10366 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
10367   :: GuestfsP -> IO CString
10368
10369 -- last_error :: GuestfsH -> IO (Maybe String)
10370 -- last_error h = do
10371 --   str <- withForeignPtr h (\\p -> c_last_error p)
10372 --   maybePeek peekCString str
10373
10374 last_error :: GuestfsH -> IO (String)
10375 last_error h = do
10376   str <- withForeignPtr h (\\p -> c_last_error p)
10377   if (str == nullPtr)
10378     then return \"no error\"
10379     else peekCString str
10380
10381 ";
10382
10383   (* Generate wrappers for each foreign function. *)
10384   List.iter (
10385     fun (name, style, _, _, _, _, _) ->
10386       if can_generate style then (
10387         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
10388         pr "  :: ";
10389         generate_haskell_prototype ~handle:"GuestfsP" style;
10390         pr "\n";
10391         pr "\n";
10392         pr "%s :: " name;
10393         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
10394         pr "\n";
10395         pr "%s %s = do\n" name
10396           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
10397         pr "  r <- ";
10398         (* Convert pointer arguments using with* functions. *)
10399         List.iter (
10400           function
10401           | FileIn n
10402           | FileOut n
10403           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
10404           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
10405           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
10406           | Bool _ | Int _ | Int64 _ -> ()
10407         ) (snd style);
10408         (* Convert integer arguments. *)
10409         let args =
10410           List.map (
10411             function
10412             | Bool n -> sprintf "(fromBool %s)" n
10413             | Int n -> sprintf "(fromIntegral %s)" n
10414             | Int64 n -> sprintf "(fromIntegral %s)" n
10415             | FileIn n | FileOut n
10416             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
10417           ) (snd style) in
10418         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
10419           (String.concat " " ("p" :: args));
10420         (match fst style with
10421          | RErr | RInt _ | RInt64 _ | RBool _ ->
10422              pr "  if (r == -1)\n";
10423              pr "    then do\n";
10424              pr "      err <- last_error h\n";
10425              pr "      fail err\n";
10426          | RConstString _ | RConstOptString _ | RString _
10427          | RStringList _ | RStruct _
10428          | RStructList _ | RHashtable _ | RBufferOut _ ->
10429              pr "  if (r == nullPtr)\n";
10430              pr "    then do\n";
10431              pr "      err <- last_error h\n";
10432              pr "      fail err\n";
10433         );
10434         (match fst style with
10435          | RErr ->
10436              pr "    else return ()\n"
10437          | RInt _ ->
10438              pr "    else return (fromIntegral r)\n"
10439          | RInt64 _ ->
10440              pr "    else return (fromIntegral r)\n"
10441          | RBool _ ->
10442              pr "    else return (toBool r)\n"
10443          | RConstString _
10444          | RConstOptString _
10445          | RString _
10446          | RStringList _
10447          | RStruct _
10448          | RStructList _
10449          | RHashtable _
10450          | RBufferOut _ ->
10451              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10452         );
10453         pr "\n";
10454       )
10455   ) all_functions
10456
10457 and generate_haskell_prototype ~handle ?(hs = false) style =
10458   pr "%s -> " handle;
10459   let string = if hs then "String" else "CString" in
10460   let int = if hs then "Int" else "CInt" in
10461   let bool = if hs then "Bool" else "CInt" in
10462   let int64 = if hs then "Integer" else "Int64" in
10463   List.iter (
10464     fun arg ->
10465       (match arg with
10466        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10467        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10468        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10469        | Bool _ -> pr "%s" bool
10470        | Int _ -> pr "%s" int
10471        | Int64 _ -> pr "%s" int
10472        | FileIn _ -> pr "%s" string
10473        | FileOut _ -> pr "%s" string
10474       );
10475       pr " -> ";
10476   ) (snd style);
10477   pr "IO (";
10478   (match fst style with
10479    | RErr -> if not hs then pr "CInt"
10480    | RInt _ -> pr "%s" int
10481    | RInt64 _ -> pr "%s" int64
10482    | RBool _ -> pr "%s" bool
10483    | RConstString _ -> pr "%s" string
10484    | RConstOptString _ -> pr "Maybe %s" string
10485    | RString _ -> pr "%s" string
10486    | RStringList _ -> pr "[%s]" string
10487    | RStruct (_, typ) ->
10488        let name = java_name_of_struct typ in
10489        pr "%s" name
10490    | RStructList (_, typ) ->
10491        let name = java_name_of_struct typ in
10492        pr "[%s]" name
10493    | RHashtable _ -> pr "Hashtable"
10494    | RBufferOut _ -> pr "%s" string
10495   );
10496   pr ")"
10497
10498 and generate_csharp () =
10499   generate_header CPlusPlusStyle LGPLv2plus;
10500
10501   (* XXX Make this configurable by the C# assembly users. *)
10502   let library = "libguestfs.so.0" in
10503
10504   pr "\
10505 // These C# bindings are highly experimental at present.
10506 //
10507 // Firstly they only work on Linux (ie. Mono).  In order to get them
10508 // to work on Windows (ie. .Net) you would need to port the library
10509 // itself to Windows first.
10510 //
10511 // The second issue is that some calls are known to be incorrect and
10512 // can cause Mono to segfault.  Particularly: calls which pass or
10513 // return string[], or return any structure value.  This is because
10514 // we haven't worked out the correct way to do this from C#.
10515 //
10516 // The third issue is that when compiling you get a lot of warnings.
10517 // We are not sure whether the warnings are important or not.
10518 //
10519 // Fourthly we do not routinely build or test these bindings as part
10520 // of the make && make check cycle, which means that regressions might
10521 // go unnoticed.
10522 //
10523 // Suggestions and patches are welcome.
10524
10525 // To compile:
10526 //
10527 // gmcs Libguestfs.cs
10528 // mono Libguestfs.exe
10529 //
10530 // (You'll probably want to add a Test class / static main function
10531 // otherwise this won't do anything useful).
10532
10533 using System;
10534 using System.IO;
10535 using System.Runtime.InteropServices;
10536 using System.Runtime.Serialization;
10537 using System.Collections;
10538
10539 namespace Guestfs
10540 {
10541   class Error : System.ApplicationException
10542   {
10543     public Error (string message) : base (message) {}
10544     protected Error (SerializationInfo info, StreamingContext context) {}
10545   }
10546
10547   class Guestfs
10548   {
10549     IntPtr _handle;
10550
10551     [DllImport (\"%s\")]
10552     static extern IntPtr guestfs_create ();
10553
10554     public Guestfs ()
10555     {
10556       _handle = guestfs_create ();
10557       if (_handle == IntPtr.Zero)
10558         throw new Error (\"could not create guestfs handle\");
10559     }
10560
10561     [DllImport (\"%s\")]
10562     static extern void guestfs_close (IntPtr h);
10563
10564     ~Guestfs ()
10565     {
10566       guestfs_close (_handle);
10567     }
10568
10569     [DllImport (\"%s\")]
10570     static extern string guestfs_last_error (IntPtr h);
10571
10572 " library library library;
10573
10574   (* Generate C# structure bindings.  We prefix struct names with
10575    * underscore because C# cannot have conflicting struct names and
10576    * method names (eg. "class stat" and "stat").
10577    *)
10578   List.iter (
10579     fun (typ, cols) ->
10580       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10581       pr "    public class _%s {\n" typ;
10582       List.iter (
10583         function
10584         | name, FChar -> pr "      char %s;\n" name
10585         | name, FString -> pr "      string %s;\n" name
10586         | name, FBuffer ->
10587             pr "      uint %s_len;\n" name;
10588             pr "      string %s;\n" name
10589         | name, FUUID ->
10590             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10591             pr "      string %s;\n" name
10592         | name, FUInt32 -> pr "      uint %s;\n" name
10593         | name, FInt32 -> pr "      int %s;\n" name
10594         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10595         | name, FInt64 -> pr "      long %s;\n" name
10596         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10597       ) cols;
10598       pr "    }\n";
10599       pr "\n"
10600   ) structs;
10601
10602   (* Generate C# function bindings. *)
10603   List.iter (
10604     fun (name, style, _, _, _, shortdesc, _) ->
10605       let rec csharp_return_type () =
10606         match fst style with
10607         | RErr -> "void"
10608         | RBool n -> "bool"
10609         | RInt n -> "int"
10610         | RInt64 n -> "long"
10611         | RConstString n
10612         | RConstOptString n
10613         | RString n
10614         | RBufferOut n -> "string"
10615         | RStruct (_,n) -> "_" ^ n
10616         | RHashtable n -> "Hashtable"
10617         | RStringList n -> "string[]"
10618         | RStructList (_,n) -> sprintf "_%s[]" n
10619
10620       and c_return_type () =
10621         match fst style with
10622         | RErr
10623         | RBool _
10624         | RInt _ -> "int"
10625         | RInt64 _ -> "long"
10626         | RConstString _
10627         | RConstOptString _
10628         | RString _
10629         | RBufferOut _ -> "string"
10630         | RStruct (_,n) -> "_" ^ n
10631         | RHashtable _
10632         | RStringList _ -> "string[]"
10633         | RStructList (_,n) -> sprintf "_%s[]" n
10634
10635       and c_error_comparison () =
10636         match fst style with
10637         | RErr
10638         | RBool _
10639         | RInt _
10640         | RInt64 _ -> "== -1"
10641         | RConstString _
10642         | RConstOptString _
10643         | RString _
10644         | RBufferOut _
10645         | RStruct (_,_)
10646         | RHashtable _
10647         | RStringList _
10648         | RStructList (_,_) -> "== null"
10649
10650       and generate_extern_prototype () =
10651         pr "    static extern %s guestfs_%s (IntPtr h"
10652           (c_return_type ()) name;
10653         List.iter (
10654           function
10655           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10656           | FileIn n | FileOut n ->
10657               pr ", [In] string %s" n
10658           | StringList n | DeviceList n ->
10659               pr ", [In] string[] %s" n
10660           | Bool n ->
10661               pr ", bool %s" n
10662           | Int n ->
10663               pr ", int %s" n
10664           | Int64 n ->
10665               pr ", long %s" n
10666         ) (snd style);
10667         pr ");\n"
10668
10669       and generate_public_prototype () =
10670         pr "    public %s %s (" (csharp_return_type ()) name;
10671         let comma = ref false in
10672         let next () =
10673           if !comma then pr ", ";
10674           comma := true
10675         in
10676         List.iter (
10677           function
10678           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10679           | FileIn n | FileOut n ->
10680               next (); pr "string %s" n
10681           | StringList n | DeviceList n ->
10682               next (); pr "string[] %s" n
10683           | Bool n ->
10684               next (); pr "bool %s" n
10685           | Int n ->
10686               next (); pr "int %s" n
10687           | Int64 n ->
10688               next (); pr "long %s" n
10689         ) (snd style);
10690         pr ")\n"
10691
10692       and generate_call () =
10693         pr "guestfs_%s (_handle" name;
10694         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10695         pr ");\n";
10696       in
10697
10698       pr "    [DllImport (\"%s\")]\n" library;
10699       generate_extern_prototype ();
10700       pr "\n";
10701       pr "    /// <summary>\n";
10702       pr "    /// %s\n" shortdesc;
10703       pr "    /// </summary>\n";
10704       generate_public_prototype ();
10705       pr "    {\n";
10706       pr "      %s r;\n" (c_return_type ());
10707       pr "      r = ";
10708       generate_call ();
10709       pr "      if (r %s)\n" (c_error_comparison ());
10710       pr "        throw new Error (guestfs_last_error (_handle));\n";
10711       (match fst style with
10712        | RErr -> ()
10713        | RBool _ ->
10714            pr "      return r != 0 ? true : false;\n"
10715        | RHashtable _ ->
10716            pr "      Hashtable rr = new Hashtable ();\n";
10717            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10718            pr "        rr.Add (r[i], r[i+1]);\n";
10719            pr "      return rr;\n"
10720        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10721        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10722        | RStructList _ ->
10723            pr "      return r;\n"
10724       );
10725       pr "    }\n";
10726       pr "\n";
10727   ) all_functions_sorted;
10728
10729   pr "  }
10730 }
10731 "
10732
10733 and generate_bindtests () =
10734   generate_header CStyle LGPLv2plus;
10735
10736   pr "\
10737 #include <stdio.h>
10738 #include <stdlib.h>
10739 #include <inttypes.h>
10740 #include <string.h>
10741
10742 #include \"guestfs.h\"
10743 #include \"guestfs-internal.h\"
10744 #include \"guestfs-internal-actions.h\"
10745 #include \"guestfs_protocol.h\"
10746
10747 #define error guestfs_error
10748 #define safe_calloc guestfs_safe_calloc
10749 #define safe_malloc guestfs_safe_malloc
10750
10751 static void
10752 print_strings (char *const *argv)
10753 {
10754   int argc;
10755
10756   printf (\"[\");
10757   for (argc = 0; argv[argc] != NULL; ++argc) {
10758     if (argc > 0) printf (\", \");
10759     printf (\"\\\"%%s\\\"\", argv[argc]);
10760   }
10761   printf (\"]\\n\");
10762 }
10763
10764 /* The test0 function prints its parameters to stdout. */
10765 ";
10766
10767   let test0, tests =
10768     match test_functions with
10769     | [] -> assert false
10770     | test0 :: tests -> test0, tests in
10771
10772   let () =
10773     let (name, style, _, _, _, _, _) = test0 in
10774     generate_prototype ~extern:false ~semicolon:false ~newline:true
10775       ~handle:"g" ~prefix:"guestfs__" name style;
10776     pr "{\n";
10777     List.iter (
10778       function
10779       | Pathname n
10780       | Device n | Dev_or_Path n
10781       | String n
10782       | FileIn n
10783       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10784       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10785       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10786       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10787       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10788       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10789     ) (snd style);
10790     pr "  /* Java changes stdout line buffering so we need this: */\n";
10791     pr "  fflush (stdout);\n";
10792     pr "  return 0;\n";
10793     pr "}\n";
10794     pr "\n" in
10795
10796   List.iter (
10797     fun (name, style, _, _, _, _, _) ->
10798       if String.sub name (String.length name - 3) 3 <> "err" then (
10799         pr "/* Test normal return. */\n";
10800         generate_prototype ~extern:false ~semicolon:false ~newline:true
10801           ~handle:"g" ~prefix:"guestfs__" name style;
10802         pr "{\n";
10803         (match fst style with
10804          | RErr ->
10805              pr "  return 0;\n"
10806          | RInt _ ->
10807              pr "  int r;\n";
10808              pr "  sscanf (val, \"%%d\", &r);\n";
10809              pr "  return r;\n"
10810          | RInt64 _ ->
10811              pr "  int64_t r;\n";
10812              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10813              pr "  return r;\n"
10814          | RBool _ ->
10815              pr "  return STREQ (val, \"true\");\n"
10816          | RConstString _
10817          | RConstOptString _ ->
10818              (* Can't return the input string here.  Return a static
10819               * string so we ensure we get a segfault if the caller
10820               * tries to free it.
10821               *)
10822              pr "  return \"static string\";\n"
10823          | RString _ ->
10824              pr "  return strdup (val);\n"
10825          | RStringList _ ->
10826              pr "  char **strs;\n";
10827              pr "  int n, i;\n";
10828              pr "  sscanf (val, \"%%d\", &n);\n";
10829              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10830              pr "  for (i = 0; i < n; ++i) {\n";
10831              pr "    strs[i] = safe_malloc (g, 16);\n";
10832              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10833              pr "  }\n";
10834              pr "  strs[n] = NULL;\n";
10835              pr "  return strs;\n"
10836          | RStruct (_, typ) ->
10837              pr "  struct guestfs_%s *r;\n" typ;
10838              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10839              pr "  return r;\n"
10840          | RStructList (_, typ) ->
10841              pr "  struct guestfs_%s_list *r;\n" typ;
10842              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10843              pr "  sscanf (val, \"%%d\", &r->len);\n";
10844              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10845              pr "  return r;\n"
10846          | RHashtable _ ->
10847              pr "  char **strs;\n";
10848              pr "  int n, i;\n";
10849              pr "  sscanf (val, \"%%d\", &n);\n";
10850              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10851              pr "  for (i = 0; i < n; ++i) {\n";
10852              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10853              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10854              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10855              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10856              pr "  }\n";
10857              pr "  strs[n*2] = NULL;\n";
10858              pr "  return strs;\n"
10859          | RBufferOut _ ->
10860              pr "  return strdup (val);\n"
10861         );
10862         pr "}\n";
10863         pr "\n"
10864       ) else (
10865         pr "/* Test error return. */\n";
10866         generate_prototype ~extern:false ~semicolon:false ~newline:true
10867           ~handle:"g" ~prefix:"guestfs__" name style;
10868         pr "{\n";
10869         pr "  error (g, \"error\");\n";
10870         (match fst style with
10871          | RErr | RInt _ | RInt64 _ | RBool _ ->
10872              pr "  return -1;\n"
10873          | RConstString _ | RConstOptString _
10874          | RString _ | RStringList _ | RStruct _
10875          | RStructList _
10876          | RHashtable _
10877          | RBufferOut _ ->
10878              pr "  return NULL;\n"
10879         );
10880         pr "}\n";
10881         pr "\n"
10882       )
10883   ) tests
10884
10885 and generate_ocaml_bindtests () =
10886   generate_header OCamlStyle GPLv2plus;
10887
10888   pr "\
10889 let () =
10890   let g = Guestfs.create () in
10891 ";
10892
10893   let mkargs args =
10894     String.concat " " (
10895       List.map (
10896         function
10897         | CallString s -> "\"" ^ s ^ "\""
10898         | CallOptString None -> "None"
10899         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10900         | CallStringList xs ->
10901             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10902         | CallInt i when i >= 0 -> string_of_int i
10903         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10904         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10905         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10906         | CallBool b -> string_of_bool b
10907       ) args
10908     )
10909   in
10910
10911   generate_lang_bindtests (
10912     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10913   );
10914
10915   pr "print_endline \"EOF\"\n"
10916
10917 and generate_perl_bindtests () =
10918   pr "#!/usr/bin/perl -w\n";
10919   generate_header HashStyle GPLv2plus;
10920
10921   pr "\
10922 use strict;
10923
10924 use Sys::Guestfs;
10925
10926 my $g = Sys::Guestfs->new ();
10927 ";
10928
10929   let mkargs args =
10930     String.concat ", " (
10931       List.map (
10932         function
10933         | CallString s -> "\"" ^ s ^ "\""
10934         | CallOptString None -> "undef"
10935         | CallOptString (Some s) -> sprintf "\"%s\"" s
10936         | CallStringList xs ->
10937             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10938         | CallInt i -> string_of_int i
10939         | CallInt64 i -> Int64.to_string i
10940         | CallBool b -> if b then "1" else "0"
10941       ) args
10942     )
10943   in
10944
10945   generate_lang_bindtests (
10946     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10947   );
10948
10949   pr "print \"EOF\\n\"\n"
10950
10951 and generate_python_bindtests () =
10952   generate_header HashStyle GPLv2plus;
10953
10954   pr "\
10955 import guestfs
10956
10957 g = guestfs.GuestFS ()
10958 ";
10959
10960   let mkargs args =
10961     String.concat ", " (
10962       List.map (
10963         function
10964         | CallString s -> "\"" ^ s ^ "\""
10965         | CallOptString None -> "None"
10966         | CallOptString (Some s) -> sprintf "\"%s\"" s
10967         | CallStringList xs ->
10968             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10969         | CallInt i -> string_of_int i
10970         | CallInt64 i -> Int64.to_string i
10971         | CallBool b -> if b then "1" else "0"
10972       ) args
10973     )
10974   in
10975
10976   generate_lang_bindtests (
10977     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10978   );
10979
10980   pr "print \"EOF\"\n"
10981
10982 and generate_ruby_bindtests () =
10983   generate_header HashStyle GPLv2plus;
10984
10985   pr "\
10986 require 'guestfs'
10987
10988 g = Guestfs::create()
10989 ";
10990
10991   let mkargs args =
10992     String.concat ", " (
10993       List.map (
10994         function
10995         | CallString s -> "\"" ^ s ^ "\""
10996         | CallOptString None -> "nil"
10997         | CallOptString (Some s) -> sprintf "\"%s\"" s
10998         | CallStringList xs ->
10999             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11000         | CallInt i -> string_of_int i
11001         | CallInt64 i -> Int64.to_string i
11002         | CallBool b -> string_of_bool b
11003       ) args
11004     )
11005   in
11006
11007   generate_lang_bindtests (
11008     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
11009   );
11010
11011   pr "print \"EOF\\n\"\n"
11012
11013 and generate_java_bindtests () =
11014   generate_header CStyle GPLv2plus;
11015
11016   pr "\
11017 import com.redhat.et.libguestfs.*;
11018
11019 public class Bindtests {
11020     public static void main (String[] argv)
11021     {
11022         try {
11023             GuestFS g = new GuestFS ();
11024 ";
11025
11026   let mkargs args =
11027     String.concat ", " (
11028       List.map (
11029         function
11030         | CallString s -> "\"" ^ s ^ "\""
11031         | CallOptString None -> "null"
11032         | CallOptString (Some s) -> sprintf "\"%s\"" s
11033         | CallStringList xs ->
11034             "new String[]{" ^
11035               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
11036         | CallInt i -> string_of_int i
11037         | CallInt64 i -> Int64.to_string i
11038         | CallBool b -> string_of_bool b
11039       ) args
11040     )
11041   in
11042
11043   generate_lang_bindtests (
11044     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
11045   );
11046
11047   pr "
11048             System.out.println (\"EOF\");
11049         }
11050         catch (Exception exn) {
11051             System.err.println (exn);
11052             System.exit (1);
11053         }
11054     }
11055 }
11056 "
11057
11058 and generate_haskell_bindtests () =
11059   generate_header HaskellStyle GPLv2plus;
11060
11061   pr "\
11062 module Bindtests where
11063 import qualified Guestfs
11064
11065 main = do
11066   g <- Guestfs.create
11067 ";
11068
11069   let mkargs args =
11070     String.concat " " (
11071       List.map (
11072         function
11073         | CallString s -> "\"" ^ s ^ "\""
11074         | CallOptString None -> "Nothing"
11075         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
11076         | CallStringList xs ->
11077             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11078         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
11079         | CallInt i -> string_of_int i
11080         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
11081         | CallInt64 i -> Int64.to_string i
11082         | CallBool true -> "True"
11083         | CallBool false -> "False"
11084       ) args
11085     )
11086   in
11087
11088   generate_lang_bindtests (
11089     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
11090   );
11091
11092   pr "  putStrLn \"EOF\"\n"
11093
11094 (* Language-independent bindings tests - we do it this way to
11095  * ensure there is parity in testing bindings across all languages.
11096  *)
11097 and generate_lang_bindtests call =
11098   call "test0" [CallString "abc"; CallOptString (Some "def");
11099                 CallStringList []; CallBool false;
11100                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11101   call "test0" [CallString "abc"; CallOptString None;
11102                 CallStringList []; CallBool false;
11103                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11104   call "test0" [CallString ""; CallOptString (Some "def");
11105                 CallStringList []; CallBool false;
11106                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11107   call "test0" [CallString ""; CallOptString (Some "");
11108                 CallStringList []; CallBool false;
11109                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11110   call "test0" [CallString "abc"; CallOptString (Some "def");
11111                 CallStringList ["1"]; CallBool false;
11112                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11113   call "test0" [CallString "abc"; CallOptString (Some "def");
11114                 CallStringList ["1"; "2"]; CallBool false;
11115                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11116   call "test0" [CallString "abc"; CallOptString (Some "def");
11117                 CallStringList ["1"]; CallBool true;
11118                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11119   call "test0" [CallString "abc"; CallOptString (Some "def");
11120                 CallStringList ["1"]; CallBool false;
11121                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
11122   call "test0" [CallString "abc"; CallOptString (Some "def");
11123                 CallStringList ["1"]; CallBool false;
11124                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
11125   call "test0" [CallString "abc"; CallOptString (Some "def");
11126                 CallStringList ["1"]; CallBool false;
11127                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
11128   call "test0" [CallString "abc"; CallOptString (Some "def");
11129                 CallStringList ["1"]; CallBool false;
11130                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
11131   call "test0" [CallString "abc"; CallOptString (Some "def");
11132                 CallStringList ["1"]; CallBool false;
11133                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
11134   call "test0" [CallString "abc"; CallOptString (Some "def");
11135                 CallStringList ["1"]; CallBool false;
11136                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
11137
11138 (* XXX Add here tests of the return and error functions. *)
11139
11140 (* Code to generator bindings for virt-inspector.  Currently only
11141  * implemented for OCaml code (for virt-p2v 2.0).
11142  *)
11143 let rng_input = "inspector/virt-inspector.rng"
11144
11145 (* Read the input file and parse it into internal structures.  This is
11146  * by no means a complete RELAX NG parser, but is just enough to be
11147  * able to parse the specific input file.
11148  *)
11149 type rng =
11150   | Element of string * rng list        (* <element name=name/> *)
11151   | Attribute of string * rng list        (* <attribute name=name/> *)
11152   | Interleave of rng list                (* <interleave/> *)
11153   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
11154   | OneOrMore of rng                        (* <oneOrMore/> *)
11155   | Optional of rng                        (* <optional/> *)
11156   | Choice of string list                (* <choice><value/>*</choice> *)
11157   | Value of string                        (* <value>str</value> *)
11158   | Text                                (* <text/> *)
11159
11160 let rec string_of_rng = function
11161   | Element (name, xs) ->
11162       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11163   | Attribute (name, xs) ->
11164       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11165   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
11166   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
11167   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
11168   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
11169   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
11170   | Value value -> "Value \"" ^ value ^ "\""
11171   | Text -> "Text"
11172
11173 and string_of_rng_list xs =
11174   String.concat ", " (List.map string_of_rng xs)
11175
11176 let rec parse_rng ?defines context = function
11177   | [] -> []
11178   | Xml.Element ("element", ["name", name], children) :: rest ->
11179       Element (name, parse_rng ?defines context children)
11180       :: parse_rng ?defines context rest
11181   | Xml.Element ("attribute", ["name", name], children) :: rest ->
11182       Attribute (name, parse_rng ?defines context children)
11183       :: parse_rng ?defines context rest
11184   | Xml.Element ("interleave", [], children) :: rest ->
11185       Interleave (parse_rng ?defines context children)
11186       :: parse_rng ?defines context rest
11187   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
11188       let rng = parse_rng ?defines context [child] in
11189       (match rng with
11190        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
11191        | _ ->
11192            failwithf "%s: <zeroOrMore> contains more than one child element"
11193              context
11194       )
11195   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
11196       let rng = parse_rng ?defines context [child] in
11197       (match rng with
11198        | [child] -> OneOrMore child :: parse_rng ?defines context rest
11199        | _ ->
11200            failwithf "%s: <oneOrMore> contains more than one child element"
11201              context
11202       )
11203   | Xml.Element ("optional", [], [child]) :: rest ->
11204       let rng = parse_rng ?defines context [child] in
11205       (match rng with
11206        | [child] -> Optional child :: parse_rng ?defines context rest
11207        | _ ->
11208            failwithf "%s: <optional> contains more than one child element"
11209              context
11210       )
11211   | Xml.Element ("choice", [], children) :: rest ->
11212       let values = List.map (
11213         function Xml.Element ("value", [], [Xml.PCData value]) -> value
11214         | _ ->
11215             failwithf "%s: can't handle anything except <value> in <choice>"
11216               context
11217       ) children in
11218       Choice values
11219       :: parse_rng ?defines context rest
11220   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
11221       Value value :: parse_rng ?defines context rest
11222   | Xml.Element ("text", [], []) :: rest ->
11223       Text :: parse_rng ?defines context rest
11224   | Xml.Element ("ref", ["name", name], []) :: rest ->
11225       (* Look up the reference.  Because of limitations in this parser,
11226        * we can't handle arbitrarily nested <ref> yet.  You can only
11227        * use <ref> from inside <start>.
11228        *)
11229       (match defines with
11230        | None ->
11231            failwithf "%s: contains <ref>, but no refs are defined yet" context
11232        | Some map ->
11233            let rng = StringMap.find name map in
11234            rng @ parse_rng ?defines context rest
11235       )
11236   | x :: _ ->
11237       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
11238
11239 let grammar =
11240   let xml = Xml.parse_file rng_input in
11241   match xml with
11242   | Xml.Element ("grammar", _,
11243                  Xml.Element ("start", _, gram) :: defines) ->
11244       (* The <define/> elements are referenced in the <start> section,
11245        * so build a map of those first.
11246        *)
11247       let defines = List.fold_left (
11248         fun map ->
11249           function Xml.Element ("define", ["name", name], defn) ->
11250             StringMap.add name defn map
11251           | _ ->
11252               failwithf "%s: expected <define name=name/>" rng_input
11253       ) StringMap.empty defines in
11254       let defines = StringMap.mapi parse_rng defines in
11255
11256       (* Parse the <start> clause, passing the defines. *)
11257       parse_rng ~defines "<start>" gram
11258   | _ ->
11259       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
11260         rng_input
11261
11262 let name_of_field = function
11263   | Element (name, _) | Attribute (name, _)
11264   | ZeroOrMore (Element (name, _))
11265   | OneOrMore (Element (name, _))
11266   | Optional (Element (name, _)) -> name
11267   | Optional (Attribute (name, _)) -> name
11268   | Text -> (* an unnamed field in an element *)
11269       "data"
11270   | rng ->
11271       failwithf "name_of_field failed at: %s" (string_of_rng rng)
11272
11273 (* At the moment this function only generates OCaml types.  However we
11274  * should parameterize it later so it can generate types/structs in a
11275  * variety of languages.
11276  *)
11277 let generate_types xs =
11278   (* A simple type is one that can be printed out directly, eg.
11279    * "string option".  A complex type is one which has a name and has
11280    * to be defined via another toplevel definition, eg. a struct.
11281    *
11282    * generate_type generates code for either simple or complex types.
11283    * In the simple case, it returns the string ("string option").  In
11284    * the complex case, it returns the name ("mountpoint").  In the
11285    * complex case it has to print out the definition before returning,
11286    * so it should only be called when we are at the beginning of a
11287    * new line (BOL context).
11288    *)
11289   let rec generate_type = function
11290     | Text ->                                (* string *)
11291         "string", true
11292     | Choice values ->                        (* [`val1|`val2|...] *)
11293         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
11294     | ZeroOrMore rng ->                        (* <rng> list *)
11295         let t, is_simple = generate_type rng in
11296         t ^ " list (* 0 or more *)", is_simple
11297     | OneOrMore rng ->                        (* <rng> list *)
11298         let t, is_simple = generate_type rng in
11299         t ^ " list (* 1 or more *)", is_simple
11300                                         (* virt-inspector hack: bool *)
11301     | Optional (Attribute (name, [Value "1"])) ->
11302         "bool", true
11303     | Optional rng ->                        (* <rng> list *)
11304         let t, is_simple = generate_type rng in
11305         t ^ " option", is_simple
11306                                         (* type name = { fields ... } *)
11307     | Element (name, fields) when is_attrs_interleave fields ->
11308         generate_type_struct name (get_attrs_interleave fields)
11309     | Element (name, [field])                (* type name = field *)
11310     | Attribute (name, [field]) ->
11311         let t, is_simple = generate_type field in
11312         if is_simple then (t, true)
11313         else (
11314           pr "type %s = %s\n" name t;
11315           name, false
11316         )
11317     | Element (name, fields) ->              (* type name = { fields ... } *)
11318         generate_type_struct name fields
11319     | rng ->
11320         failwithf "generate_type failed at: %s" (string_of_rng rng)
11321
11322   and is_attrs_interleave = function
11323     | [Interleave _] -> true
11324     | Attribute _ :: fields -> is_attrs_interleave fields
11325     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11326     | _ -> false
11327
11328   and get_attrs_interleave = function
11329     | [Interleave fields] -> fields
11330     | ((Attribute _) as field) :: fields
11331     | ((Optional (Attribute _)) as field) :: fields ->
11332         field :: get_attrs_interleave fields
11333     | _ -> assert false
11334
11335   and generate_types xs =
11336     List.iter (fun x -> ignore (generate_type x)) xs
11337
11338   and generate_type_struct name fields =
11339     (* Calculate the types of the fields first.  We have to do this
11340      * before printing anything so we are still in BOL context.
11341      *)
11342     let types = List.map fst (List.map generate_type fields) in
11343
11344     (* Special case of a struct containing just a string and another
11345      * field.  Turn it into an assoc list.
11346      *)
11347     match types with
11348     | ["string"; other] ->
11349         let fname1, fname2 =
11350           match fields with
11351           | [f1; f2] -> name_of_field f1, name_of_field f2
11352           | _ -> assert false in
11353         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
11354         name, false
11355
11356     | types ->
11357         pr "type %s = {\n" name;
11358         List.iter (
11359           fun (field, ftype) ->
11360             let fname = name_of_field field in
11361             pr "  %s_%s : %s;\n" name fname ftype
11362         ) (List.combine fields types);
11363         pr "}\n";
11364         (* Return the name of this type, and
11365          * false because it's not a simple type.
11366          *)
11367         name, false
11368   in
11369
11370   generate_types xs
11371
11372 let generate_parsers xs =
11373   (* As for generate_type above, generate_parser makes a parser for
11374    * some type, and returns the name of the parser it has generated.
11375    * Because it (may) need to print something, it should always be
11376    * called in BOL context.
11377    *)
11378   let rec generate_parser = function
11379     | Text ->                                (* string *)
11380         "string_child_or_empty"
11381     | Choice values ->                        (* [`val1|`val2|...] *)
11382         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
11383           (String.concat "|"
11384              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
11385     | ZeroOrMore rng ->                        (* <rng> list *)
11386         let pa = generate_parser rng in
11387         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11388     | OneOrMore rng ->                        (* <rng> list *)
11389         let pa = generate_parser rng in
11390         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11391                                         (* virt-inspector hack: bool *)
11392     | Optional (Attribute (name, [Value "1"])) ->
11393         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
11394     | Optional rng ->                        (* <rng> list *)
11395         let pa = generate_parser rng in
11396         sprintf "(function None -> None | Some x -> Some (%s x))" pa
11397                                         (* type name = { fields ... } *)
11398     | Element (name, fields) when is_attrs_interleave fields ->
11399         generate_parser_struct name (get_attrs_interleave fields)
11400     | Element (name, [field]) ->        (* type name = field *)
11401         let pa = generate_parser field in
11402         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11403         pr "let %s =\n" parser_name;
11404         pr "  %s\n" pa;
11405         pr "let parse_%s = %s\n" name parser_name;
11406         parser_name
11407     | Attribute (name, [field]) ->
11408         let pa = generate_parser field in
11409         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11410         pr "let %s =\n" parser_name;
11411         pr "  %s\n" pa;
11412         pr "let parse_%s = %s\n" name parser_name;
11413         parser_name
11414     | Element (name, fields) ->              (* type name = { fields ... } *)
11415         generate_parser_struct name ([], fields)
11416     | rng ->
11417         failwithf "generate_parser failed at: %s" (string_of_rng rng)
11418
11419   and is_attrs_interleave = function
11420     | [Interleave _] -> true
11421     | Attribute _ :: fields -> is_attrs_interleave fields
11422     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11423     | _ -> false
11424
11425   and get_attrs_interleave = function
11426     | [Interleave fields] -> [], fields
11427     | ((Attribute _) as field) :: fields
11428     | ((Optional (Attribute _)) as field) :: fields ->
11429         let attrs, interleaves = get_attrs_interleave fields in
11430         (field :: attrs), interleaves
11431     | _ -> assert false
11432
11433   and generate_parsers xs =
11434     List.iter (fun x -> ignore (generate_parser x)) xs
11435
11436   and generate_parser_struct name (attrs, interleaves) =
11437     (* Generate parsers for the fields first.  We have to do this
11438      * before printing anything so we are still in BOL context.
11439      *)
11440     let fields = attrs @ interleaves in
11441     let pas = List.map generate_parser fields in
11442
11443     (* Generate an intermediate tuple from all the fields first.
11444      * If the type is just a string + another field, then we will
11445      * return this directly, otherwise it is turned into a record.
11446      *
11447      * RELAX NG note: This code treats <interleave> and plain lists of
11448      * fields the same.  In other words, it doesn't bother enforcing
11449      * any ordering of fields in the XML.
11450      *)
11451     pr "let parse_%s x =\n" name;
11452     pr "  let t = (\n    ";
11453     let comma = ref false in
11454     List.iter (
11455       fun x ->
11456         if !comma then pr ",\n    ";
11457         comma := true;
11458         match x with
11459         | Optional (Attribute (fname, [field])), pa ->
11460             pr "%s x" pa
11461         | Optional (Element (fname, [field])), pa ->
11462             pr "%s (optional_child %S x)" pa fname
11463         | Attribute (fname, [Text]), _ ->
11464             pr "attribute %S x" fname
11465         | (ZeroOrMore _ | OneOrMore _), pa ->
11466             pr "%s x" pa
11467         | Text, pa ->
11468             pr "%s x" pa
11469         | (field, pa) ->
11470             let fname = name_of_field field in
11471             pr "%s (child %S x)" pa fname
11472     ) (List.combine fields pas);
11473     pr "\n  ) in\n";
11474
11475     (match fields with
11476      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11477          pr "  t\n"
11478
11479      | _ ->
11480          pr "  (Obj.magic t : %s)\n" name
11481 (*
11482          List.iter (
11483            function
11484            | (Optional (Attribute (fname, [field])), pa) ->
11485                pr "  %s_%s =\n" name fname;
11486                pr "    %s x;\n" pa
11487            | (Optional (Element (fname, [field])), pa) ->
11488                pr "  %s_%s =\n" name fname;
11489                pr "    (let x = optional_child %S x in\n" fname;
11490                pr "     %s x);\n" pa
11491            | (field, pa) ->
11492                let fname = name_of_field field in
11493                pr "  %s_%s =\n" name fname;
11494                pr "    (let x = child %S x in\n" fname;
11495                pr "     %s x);\n" pa
11496          ) (List.combine fields pas);
11497          pr "}\n"
11498 *)
11499     );
11500     sprintf "parse_%s" name
11501   in
11502
11503   generate_parsers xs
11504
11505 (* Generate ocaml/guestfs_inspector.mli. *)
11506 let generate_ocaml_inspector_mli () =
11507   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11508
11509   pr "\
11510 (** This is an OCaml language binding to the external [virt-inspector]
11511     program.
11512
11513     For more information, please read the man page [virt-inspector(1)].
11514 *)
11515
11516 ";
11517
11518   generate_types grammar;
11519   pr "(** The nested information returned from the {!inspect} function. *)\n";
11520   pr "\n";
11521
11522   pr "\
11523 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11524 (** To inspect a libvirt domain called [name], pass a singleton
11525     list: [inspect [name]].  When using libvirt only, you may
11526     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11527
11528     To inspect a disk image or images, pass a list of the filenames
11529     of the disk images: [inspect filenames]
11530
11531     This function inspects the given guest or disk images and
11532     returns a list of operating system(s) found and a large amount
11533     of information about them.  In the vast majority of cases,
11534     a virtual machine only contains a single operating system.
11535
11536     If the optional [~xml] parameter is given, then this function
11537     skips running the external virt-inspector program and just
11538     parses the given XML directly (which is expected to be XML
11539     produced from a previous run of virt-inspector).  The list of
11540     names and connect URI are ignored in this case.
11541
11542     This function can throw a wide variety of exceptions, for example
11543     if the external virt-inspector program cannot be found, or if
11544     it doesn't generate valid XML.
11545 *)
11546 "
11547
11548 (* Generate ocaml/guestfs_inspector.ml. *)
11549 let generate_ocaml_inspector_ml () =
11550   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11551
11552   pr "open Unix\n";
11553   pr "\n";
11554
11555   generate_types grammar;
11556   pr "\n";
11557
11558   pr "\
11559 (* Misc functions which are used by the parser code below. *)
11560 let first_child = function
11561   | Xml.Element (_, _, c::_) -> c
11562   | Xml.Element (name, _, []) ->
11563       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11564   | Xml.PCData str ->
11565       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11566
11567 let string_child_or_empty = function
11568   | Xml.Element (_, _, [Xml.PCData s]) -> s
11569   | Xml.Element (_, _, []) -> \"\"
11570   | Xml.Element (x, _, _) ->
11571       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11572                 x ^ \" instead\")
11573   | Xml.PCData str ->
11574       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11575
11576 let optional_child name xml =
11577   let children = Xml.children xml in
11578   try
11579     Some (List.find (function
11580                      | Xml.Element (n, _, _) when n = name -> true
11581                      | _ -> false) children)
11582   with
11583     Not_found -> None
11584
11585 let child name xml =
11586   match optional_child name xml with
11587   | Some c -> c
11588   | None ->
11589       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11590
11591 let attribute name xml =
11592   try Xml.attrib xml name
11593   with Xml.No_attribute _ ->
11594     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11595
11596 ";
11597
11598   generate_parsers grammar;
11599   pr "\n";
11600
11601   pr "\
11602 (* Run external virt-inspector, then use parser to parse the XML. *)
11603 let inspect ?connect ?xml names =
11604   let xml =
11605     match xml with
11606     | None ->
11607         if names = [] then invalid_arg \"inspect: no names given\";
11608         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11609           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11610           names in
11611         let cmd = List.map Filename.quote cmd in
11612         let cmd = String.concat \" \" cmd in
11613         let chan = open_process_in cmd in
11614         let xml = Xml.parse_in chan in
11615         (match close_process_in chan with
11616          | WEXITED 0 -> ()
11617          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11618          | WSIGNALED i | WSTOPPED i ->
11619              failwith (\"external virt-inspector command died or stopped on sig \" ^
11620                        string_of_int i)
11621         );
11622         xml
11623     | Some doc ->
11624         Xml.parse_string doc in
11625   parse_operatingsystems xml
11626 "
11627
11628 (* This is used to generate the src/MAX_PROC_NR file which
11629  * contains the maximum procedure number, a surrogate for the
11630  * ABI version number.  See src/Makefile.am for the details.
11631  *)
11632 and generate_max_proc_nr () =
11633   let proc_nrs = List.map (
11634     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11635   ) daemon_functions in
11636
11637   let max_proc_nr = List.fold_left max 0 proc_nrs in
11638
11639   pr "%d\n" max_proc_nr
11640
11641 let output_to filename k =
11642   let filename_new = filename ^ ".new" in
11643   chan := open_out filename_new;
11644   k ();
11645   close_out !chan;
11646   chan := Pervasives.stdout;
11647
11648   (* Is the new file different from the current file? *)
11649   if Sys.file_exists filename && files_equal filename filename_new then
11650     unlink filename_new                 (* same, so skip it *)
11651   else (
11652     (* different, overwrite old one *)
11653     (try chmod filename 0o644 with Unix_error _ -> ());
11654     rename filename_new filename;
11655     chmod filename 0o444;
11656     printf "written %s\n%!" filename;
11657   )
11658
11659 let perror msg = function
11660   | Unix_error (err, _, _) ->
11661       eprintf "%s: %s\n" msg (error_message err)
11662   | exn ->
11663       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11664
11665 (* Main program. *)
11666 let () =
11667   let lock_fd =
11668     try openfile "HACKING" [O_RDWR] 0
11669     with
11670     | Unix_error (ENOENT, _, _) ->
11671         eprintf "\
11672 You are probably running this from the wrong directory.
11673 Run it from the top source directory using the command
11674   src/generator.ml
11675 ";
11676         exit 1
11677     | exn ->
11678         perror "open: HACKING" exn;
11679         exit 1 in
11680
11681   (* Acquire a lock so parallel builds won't try to run the generator
11682    * twice at the same time.  Subsequent builds will wait for the first
11683    * one to finish.  Note the lock is released implicitly when the
11684    * program exits.
11685    *)
11686   (try lockf lock_fd F_LOCK 1
11687    with exn ->
11688      perror "lock: HACKING" exn;
11689      exit 1);
11690
11691   check_functions ();
11692
11693   output_to "src/guestfs_protocol.x" generate_xdr;
11694   output_to "src/guestfs-structs.h" generate_structs_h;
11695   output_to "src/guestfs-actions.h" generate_actions_h;
11696   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11697   output_to "src/guestfs-actions.c" generate_client_actions;
11698   output_to "src/guestfs-bindtests.c" generate_bindtests;
11699   output_to "src/guestfs-structs.pod" generate_structs_pod;
11700   output_to "src/guestfs-actions.pod" generate_actions_pod;
11701   output_to "src/guestfs-availability.pod" generate_availability_pod;
11702   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11703   output_to "src/libguestfs.syms" generate_linker_script;
11704   output_to "daemon/actions.h" generate_daemon_actions_h;
11705   output_to "daemon/stubs.c" generate_daemon_actions;
11706   output_to "daemon/names.c" generate_daemon_names;
11707   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11708   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11709   output_to "capitests/tests.c" generate_tests;
11710   output_to "fish/cmds.c" generate_fish_cmds;
11711   output_to "fish/completion.c" generate_fish_completion;
11712   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11713   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11714   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11715   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11716   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11717   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11718   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11719   output_to "perl/Guestfs.xs" generate_perl_xs;
11720   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11721   output_to "perl/bindtests.pl" generate_perl_bindtests;
11722   output_to "python/guestfs-py.c" generate_python_c;
11723   output_to "python/guestfs.py" generate_python_py;
11724   output_to "python/bindtests.py" generate_python_bindtests;
11725   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11726   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11727   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11728
11729   List.iter (
11730     fun (typ, jtyp) ->
11731       let cols = cols_of_struct typ in
11732       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11733       output_to filename (generate_java_struct jtyp cols);
11734   ) java_structs;
11735
11736   output_to "java/Makefile.inc" generate_java_makefile_inc;
11737   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11738   output_to "java/Bindtests.java" generate_java_bindtests;
11739   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11740   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11741   output_to "csharp/Libguestfs.cs" generate_csharp;
11742
11743   (* Always generate this file last, and unconditionally.  It's used
11744    * by the Makefile to know when we must re-run the generator.
11745    *)
11746   let chan = open_out "src/stamp-generator" in
11747   fprintf chan "1\n";
11748   close_out chan;
11749
11750   printf "generated %d lines of code\n" !lines