6de2c7f267a2fa6a568b4ade7110f303f033dda4
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009-2010 Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *)
19
20 (* This script generates a large amount of code and documentation for
21  * all the daemon actions.
22  * 
23  * To add a new action there are only two files you need to change,
24  * this one to describe the interface (see the big table of
25  * 'daemon_functions' below), and daemon/<somefile>.c to write the
26  * implementation.
27  * 
28  * After editing this file, run it (./src/generator.ml) to regenerate
29  * all the output files.  'make' will rerun this automatically when
30  * necessary.  Note that if you are using a separate build directory
31  * you must run generator.ml from the _source_ directory.
32  * 
33  * IMPORTANT: This script should NOT print any warnings.  If it prints
34  * warnings, you should treat them as errors.
35  *
36  * OCaml tips:
37  * (1) In emacs, install tuareg-mode to display and format OCaml code
38  * correctly.  'vim' comes with a good OCaml editing mode by default.
39  * (2) Read the resources at http://ocaml-tutorial.org/
40  *)
41
42 #load "unix.cma";;
43 #load "str.cma";;
44 #directory "+xml-light";;
45 #load "xml-light.cma";;
46
47 open Unix
48 open Printf
49
50 type style = ret * args
51 and ret =
52     (* "RErr" as a return value means an int used as a simple error
53      * indication, ie. 0 or -1.
54      *)
55   | RErr
56
57     (* "RInt" as a return value means an int which is -1 for error
58      * or any value >= 0 on success.  Only use this for smallish
59      * positive ints (0 <= i < 2^30).
60      *)
61   | RInt of string
62
63     (* "RInt64" is the same as RInt, but is guaranteed to be able
64      * to return a full 64 bit value, _except_ that -1 means error
65      * (so -1 cannot be a valid, non-error return value).
66      *)
67   | RInt64 of string
68
69     (* "RBool" is a bool return value which can be true/false or
70      * -1 for error.
71      *)
72   | RBool of string
73
74     (* "RConstString" is a string that refers to a constant value.
75      * The return value must NOT be NULL (since NULL indicates
76      * an error).
77      *
78      * Try to avoid using this.  In particular you cannot use this
79      * for values returned from the daemon, because there is no
80      * thread-safe way to return them in the C API.
81      *)
82   | RConstString of string
83
84     (* "RConstOptString" is an even more broken version of
85      * "RConstString".  The returned string may be NULL and there
86      * is no way to return an error indication.  Avoid using this!
87      *)
88   | RConstOptString of string
89
90     (* "RString" is a returned string.  It must NOT be NULL, since
91      * a NULL return indicates an error.  The caller frees this.
92      *)
93   | RString of string
94
95     (* "RStringList" is a list of strings.  No string in the list
96      * can be NULL.  The caller frees the strings and the array.
97      *)
98   | RStringList of string
99
100     (* "RStruct" is a function which returns a single named structure
101      * or an error indication (in C, a struct, and in other languages
102      * with varying representations, but usually very efficient).  See
103      * after the function list below for the structures.
104      *)
105   | RStruct of string * string          (* name of retval, name of struct *)
106
107     (* "RStructList" is a function which returns either a list/array
108      * of structures (could be zero-length), or an error indication.
109      *)
110   | RStructList of string * string      (* name of retval, name of struct *)
111
112     (* Key-value pairs of untyped strings.  Turns into a hashtable or
113      * dictionary in languages which support it.  DON'T use this as a
114      * general "bucket" for results.  Prefer a stronger typed return
115      * value if one is available, or write a custom struct.  Don't use
116      * this if the list could potentially be very long, since it is
117      * inefficient.  Keys should be unique.  NULLs are not permitted.
118      *)
119   | RHashtable of string
120
121     (* "RBufferOut" is handled almost exactly like RString, but
122      * it allows the string to contain arbitrary 8 bit data including
123      * ASCII NUL.  In the C API this causes an implicit extra parameter
124      * to be added of type <size_t *size_r>.  The extra parameter
125      * returns the actual size of the return buffer in bytes.
126      *
127      * Other programming languages support strings with arbitrary 8 bit
128      * data.
129      *
130      * At the RPC layer we have to use the opaque<> type instead of
131      * string<>.  Returned data is still limited to the max message
132      * size (ie. ~ 2 MB).
133      *)
134   | RBufferOut of string
135
136 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
137
138     (* Note in future we should allow a "variable args" parameter as
139      * the final parameter, to allow commands like
140      *   chmod mode file [file(s)...]
141      * This is not implemented yet, but many commands (such as chmod)
142      * are currently defined with the argument order keeping this future
143      * possibility in mind.
144      *)
145 and argt =
146   | String of string    (* const char *name, cannot be NULL *)
147   | Device of string    (* /dev device name, cannot be NULL *)
148   | Pathname of string  (* file name, cannot be NULL *)
149   | Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
150   | OptString of string (* const char *name, may be NULL *)
151   | StringList of string(* list of strings (each string cannot be NULL) *)
152   | DeviceList of string(* list of Device names (each cannot be NULL) *)
153   | Bool of string      (* boolean *)
154   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
155   | Int64 of string     (* any 64 bit int *)
156     (* These are treated as filenames (simple string parameters) in
157      * the C API and bindings.  But in the RPC protocol, we transfer
158      * the actual file content up to or down from the daemon.
159      * FileIn: local machine -> daemon (in request)
160      * FileOut: daemon -> local machine (in reply)
161      * In guestfish (only), the special name "-" means read from
162      * stdin or write to stdout.
163      *)
164   | FileIn of string
165   | FileOut of string
166 (* Not implemented:
167     (* Opaque buffer which can contain arbitrary 8 bit data.
168      * In the C API, this is expressed as <char *, int> pair.
169      * Most other languages have a string type which can contain
170      * ASCII NUL.  We use whatever type is appropriate for each
171      * language.
172      * Buffers are limited by the total message size.  To transfer
173      * large blocks of data, use FileIn/FileOut parameters instead.
174      * To return an arbitrary buffer, use RBufferOut.
175      *)
176   | BufferIn of string
177 *)
178
179 type flags =
180   | ProtocolLimitWarning  (* display warning about protocol size limits *)
181   | DangerWillRobinson    (* flags particularly dangerous commands *)
182   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
183   | FishAction of string  (* call this function in guestfish *)
184   | NotInFish             (* do not export via guestfish *)
185   | NotInDocs             (* do not add this function to documentation *)
186   | DeprecatedBy of string (* function is deprecated, use .. instead *)
187   | Optional of string    (* function is part of an optional group *)
188
189 (* You can supply zero or as many tests as you want per API call.
190  *
191  * Note that the test environment has 3 block devices, of size 500MB,
192  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
193  * a fourth ISO block device with some known files on it (/dev/sdd).
194  *
195  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
196  * Number of cylinders was 63 for IDE emulated disks with precisely
197  * the same size.  How exactly this is calculated is a mystery.
198  *
199  * The ISO block device (/dev/sdd) comes from images/test.iso.
200  *
201  * To be able to run the tests in a reasonable amount of time,
202  * the virtual machine and block devices are reused between tests.
203  * So don't try testing kill_subprocess :-x
204  *
205  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
206  *
207  * Don't assume anything about the previous contents of the block
208  * devices.  Use 'Init*' to create some initial scenarios.
209  *
210  * You can add a prerequisite clause to any individual test.  This
211  * is a run-time check, which, if it fails, causes the test to be
212  * skipped.  Useful if testing a command which might not work on
213  * all variations of libguestfs builds.  A test that has prerequisite
214  * of 'Always' is run unconditionally.
215  *
216  * In addition, packagers can skip individual tests by setting the
217  * environment variables:     eg:
218  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
219  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
220  *)
221 type tests = (test_init * test_prereq * test) list
222 and test =
223     (* Run the command sequence and just expect nothing to fail. *)
224   | TestRun of seq
225
226     (* Run the command sequence and expect the output of the final
227      * command to be the string.
228      *)
229   | TestOutput of seq * string
230
231     (* Run the command sequence and expect the output of the final
232      * command to be the list of strings.
233      *)
234   | TestOutputList of seq * string list
235
236     (* Run the command sequence and expect the output of the final
237      * command to be the list of block devices (could be either
238      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
239      * character of each string).
240      *)
241   | TestOutputListOfDevices of seq * string list
242
243     (* Run the command sequence and expect the output of the final
244      * command to be the integer.
245      *)
246   | TestOutputInt of seq * int
247
248     (* Run the command sequence and expect the output of the final
249      * command to be <op> <int>, eg. ">=", "1".
250      *)
251   | TestOutputIntOp of seq * string * int
252
253     (* Run the command sequence and expect the output of the final
254      * command to be a true value (!= 0 or != NULL).
255      *)
256   | TestOutputTrue of seq
257
258     (* Run the command sequence and expect the output of the final
259      * command to be a false value (== 0 or == NULL, but not an error).
260      *)
261   | TestOutputFalse of seq
262
263     (* Run the command sequence and expect the output of the final
264      * command to be a list of the given length (but don't care about
265      * content).
266      *)
267   | TestOutputLength of seq * int
268
269     (* Run the command sequence and expect the output of the final
270      * command to be a buffer (RBufferOut), ie. string + size.
271      *)
272   | TestOutputBuffer of seq * string
273
274     (* Run the command sequence and expect the output of the final
275      * command to be a structure.
276      *)
277   | TestOutputStruct of seq * test_field_compare list
278
279     (* Run the command sequence and expect the final command (only)
280      * to fail.
281      *)
282   | TestLastFail of seq
283
284 and test_field_compare =
285   | CompareWithInt of string * int
286   | CompareWithIntOp of string * string * int
287   | CompareWithString of string * string
288   | CompareFieldsIntEq of string * string
289   | CompareFieldsStrEq of string * string
290
291 (* Test prerequisites. *)
292 and test_prereq =
293     (* Test always runs. *)
294   | Always
295
296     (* Test is currently disabled - eg. it fails, or it tests some
297      * unimplemented feature.
298      *)
299   | Disabled
300
301     (* 'string' is some C code (a function body) that should return
302      * true or false.  The test will run if the code returns true.
303      *)
304   | If of string
305
306     (* As for 'If' but the test runs _unless_ the code returns true. *)
307   | Unless of string
308
309 (* Some initial scenarios for testing. *)
310 and test_init =
311     (* Do nothing, block devices could contain random stuff including
312      * LVM PVs, and some filesystems might be mounted.  This is usually
313      * a bad idea.
314      *)
315   | InitNone
316
317     (* Block devices are empty and no filesystems are mounted. *)
318   | InitEmpty
319
320     (* /dev/sda contains a single partition /dev/sda1, with random
321      * content.  /dev/sdb and /dev/sdc may have random content.
322      * No LVM.
323      *)
324   | InitPartition
325
326     (* /dev/sda contains a single partition /dev/sda1, which is formatted
327      * as ext2, empty [except for lost+found] and mounted on /.
328      * /dev/sdb and /dev/sdc may have random content.
329      * No LVM.
330      *)
331   | InitBasicFS
332
333     (* /dev/sda:
334      *   /dev/sda1 (is a PV):
335      *     /dev/VG/LV (size 8MB):
336      *       formatted as ext2, empty [except for lost+found], mounted on /
337      * /dev/sdb and /dev/sdc may have random content.
338      *)
339   | InitBasicFSonLVM
340
341     (* /dev/sdd (the ISO, see images/ directory in source)
342      * is mounted on /
343      *)
344   | InitISOFS
345
346 (* Sequence of commands for testing. *)
347 and seq = cmd list
348 and cmd = string list
349
350 (* Note about long descriptions: When referring to another
351  * action, use the format C<guestfs_other> (ie. the full name of
352  * the C function).  This will be replaced as appropriate in other
353  * language bindings.
354  *
355  * Apart from that, long descriptions are just perldoc paragraphs.
356  *)
357
358 (* Generate a random UUID (used in tests). *)
359 let uuidgen () =
360   let chan = open_process_in "uuidgen" in
361   let uuid = input_line chan in
362   (match close_process_in chan with
363    | WEXITED 0 -> ()
364    | WEXITED _ ->
365        failwith "uuidgen: process exited with non-zero status"
366    | WSIGNALED _ | WSTOPPED _ ->
367        failwith "uuidgen: process signalled or stopped by signal"
368   );
369   uuid
370
371 (* These test functions are used in the language binding tests. *)
372
373 let test_all_args = [
374   String "str";
375   OptString "optstr";
376   StringList "strlist";
377   Bool "b";
378   Int "integer";
379   Int64 "integer64";
380   FileIn "filein";
381   FileOut "fileout";
382 ]
383
384 let test_all_rets = [
385   (* except for RErr, which is tested thoroughly elsewhere *)
386   "test0rint",         RInt "valout";
387   "test0rint64",       RInt64 "valout";
388   "test0rbool",        RBool "valout";
389   "test0rconststring", RConstString "valout";
390   "test0rconstoptstring", RConstOptString "valout";
391   "test0rstring",      RString "valout";
392   "test0rstringlist",  RStringList "valout";
393   "test0rstruct",      RStruct ("valout", "lvm_pv");
394   "test0rstructlist",  RStructList ("valout", "lvm_pv");
395   "test0rhashtable",   RHashtable "valout";
396 ]
397
398 let test_functions = [
399   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
400    [],
401    "internal test function - do not use",
402    "\
403 This is an internal test function which is used to test whether
404 the automatically generated bindings can handle every possible
405 parameter type correctly.
406
407 It echos the contents of each parameter to stdout.
408
409 You probably don't want to call this function.");
410 ] @ List.flatten (
411   List.map (
412     fun (name, ret) ->
413       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
414         [],
415         "internal test function - do not use",
416         "\
417 This is an internal test function which is used to test whether
418 the automatically generated bindings can handle every possible
419 return type correctly.
420
421 It converts string C<val> to the return type.
422
423 You probably don't want to call this function.");
424        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
425         [],
426         "internal test function - do not use",
427         "\
428 This is an internal test function which is used to test whether
429 the automatically generated bindings can handle every possible
430 return type correctly.
431
432 This function always returns an error.
433
434 You probably don't want to call this function.")]
435   ) test_all_rets
436 )
437
438 (* non_daemon_functions are any functions which don't get processed
439  * in the daemon, eg. functions for setting and getting local
440  * configuration values.
441  *)
442
443 let non_daemon_functions = test_functions @ [
444   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
445    [],
446    "launch the qemu subprocess",
447    "\
448 Internally libguestfs is implemented by running a virtual machine
449 using L<qemu(1)>.
450
451 You should call this after configuring the handle
452 (eg. adding drives) but before performing any actions.");
453
454   ("wait_ready", (RErr, []), -1, [NotInFish],
455    [],
456    "wait until the qemu subprocess launches (no op)",
457    "\
458 This function is a no op.
459
460 In versions of the API E<lt> 1.0.71 you had to call this function
461 just after calling C<guestfs_launch> to wait for the launch
462 to complete.  However this is no longer necessary because
463 C<guestfs_launch> now does the waiting.
464
465 If you see any calls to this function in code then you can just
466 remove them, unless you want to retain compatibility with older
467 versions of the API.");
468
469   ("kill_subprocess", (RErr, []), -1, [],
470    [],
471    "kill the qemu subprocess",
472    "\
473 This kills the qemu subprocess.  You should never need to call this.");
474
475   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
476    [],
477    "add an image to examine or modify",
478    "\
479 This function adds a virtual machine disk image C<filename> to the
480 guest.  The first time you call this function, the disk appears as IDE
481 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
482 so on.
483
484 You don't necessarily need to be root when using libguestfs.  However
485 you obviously do need sufficient permissions to access the filename
486 for whatever operations you want to perform (ie. read access if you
487 just want to read the image or write access if you want to modify the
488 image).
489
490 This is equivalent to the qemu parameter
491 C<-drive file=filename,cache=off,if=...>.
492 C<cache=off> is omitted in cases where it is not supported by
493 the underlying filesystem.
494
495 Note that this call checks for the existence of C<filename>.  This
496 stops you from specifying other types of drive which are supported
497 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
498 the general C<guestfs_config> call instead.");
499
500   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
501    [],
502    "add a CD-ROM disk image to examine",
503    "\
504 This function adds a virtual CD-ROM disk image to the guest.
505
506 This is equivalent to the qemu parameter C<-cdrom filename>.
507
508 Note that this call checks for the existence of C<filename>.  This
509 stops you from specifying other types of drive which are supported
510 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
511 the general C<guestfs_config> call instead.");
512
513   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
514    [],
515    "add a drive in snapshot mode (read-only)",
516    "\
517 This adds a drive in snapshot mode, making it effectively
518 read-only.
519
520 Note that writes to the device are allowed, and will be seen for
521 the duration of the guestfs handle, but they are written
522 to a temporary file which is discarded as soon as the guestfs
523 handle is closed.  We don't currently have any method to enable
524 changes to be committed, although qemu can support this.
525
526 This is equivalent to the qemu parameter
527 C<-drive file=filename,snapshot=on,if=...>.
528
529 Note that this call checks for the existence of C<filename>.  This
530 stops you from specifying other types of drive which are supported
531 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
532 the general C<guestfs_config> call instead.");
533
534   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
535    [],
536    "add qemu parameters",
537    "\
538 This can be used to add arbitrary qemu command line parameters
539 of the form C<-param value>.  Actually it's not quite arbitrary - we
540 prevent you from setting some parameters which would interfere with
541 parameters that we use.
542
543 The first character of C<param> string must be a C<-> (dash).
544
545 C<value> can be NULL.");
546
547   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
548    [],
549    "set the qemu binary",
550    "\
551 Set the qemu binary that we will use.
552
553 The default is chosen when the library was compiled by the
554 configure script.
555
556 You can also override this by setting the C<LIBGUESTFS_QEMU>
557 environment variable.
558
559 Setting C<qemu> to C<NULL> restores the default qemu binary.");
560
561   ("get_qemu", (RConstString "qemu", []), -1, [],
562    [InitNone, Always, TestRun (
563       [["get_qemu"]])],
564    "get the qemu binary",
565    "\
566 Return the current qemu binary.
567
568 This is always non-NULL.  If it wasn't set already, then this will
569 return the default qemu binary name.");
570
571   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
572    [],
573    "set the search path",
574    "\
575 Set the path that libguestfs searches for kernel and initrd.img.
576
577 The default is C<$libdir/guestfs> unless overridden by setting
578 C<LIBGUESTFS_PATH> environment variable.
579
580 Setting C<path> to C<NULL> restores the default path.");
581
582   ("get_path", (RConstString "path", []), -1, [],
583    [InitNone, Always, TestRun (
584       [["get_path"]])],
585    "get the search path",
586    "\
587 Return the current search path.
588
589 This is always non-NULL.  If it wasn't set already, then this will
590 return the default path.");
591
592   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
593    [],
594    "add options to kernel command line",
595    "\
596 This function is used to add additional options to the
597 guest kernel command line.
598
599 The default is C<NULL> unless overridden by setting
600 C<LIBGUESTFS_APPEND> environment variable.
601
602 Setting C<append> to C<NULL> means I<no> additional options
603 are passed (libguestfs always adds a few of its own).");
604
605   ("get_append", (RConstOptString "append", []), -1, [],
606    (* This cannot be tested with the current framework.  The
607     * function can return NULL in normal operations, which the
608     * test framework interprets as an error.
609     *)
610    [],
611    "get the additional kernel options",
612    "\
613 Return the additional kernel options which are added to the
614 guest kernel command line.
615
616 If C<NULL> then no options are added.");
617
618   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
619    [],
620    "set autosync mode",
621    "\
622 If C<autosync> is true, this enables autosync.  Libguestfs will make a
623 best effort attempt to run C<guestfs_umount_all> followed by
624 C<guestfs_sync> when the handle is closed
625 (also if the program exits without closing handles).
626
627 This is disabled by default (except in guestfish where it is
628 enabled by default).");
629
630   ("get_autosync", (RBool "autosync", []), -1, [],
631    [InitNone, Always, TestRun (
632       [["get_autosync"]])],
633    "get autosync mode",
634    "\
635 Get the autosync flag.");
636
637   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
638    [],
639    "set verbose mode",
640    "\
641 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
642
643 Verbose messages are disabled unless the environment variable
644 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
645
646   ("get_verbose", (RBool "verbose", []), -1, [],
647    [],
648    "get verbose mode",
649    "\
650 This returns the verbose messages flag.");
651
652   ("is_ready", (RBool "ready", []), -1, [],
653    [InitNone, Always, TestOutputTrue (
654       [["is_ready"]])],
655    "is ready to accept commands",
656    "\
657 This returns true iff this handle is ready to accept commands
658 (in the C<READY> state).
659
660 For more information on states, see L<guestfs(3)>.");
661
662   ("is_config", (RBool "config", []), -1, [],
663    [InitNone, Always, TestOutputFalse (
664       [["is_config"]])],
665    "is in configuration state",
666    "\
667 This returns true iff this handle is being configured
668 (in the C<CONFIG> state).
669
670 For more information on states, see L<guestfs(3)>.");
671
672   ("is_launching", (RBool "launching", []), -1, [],
673    [InitNone, Always, TestOutputFalse (
674       [["is_launching"]])],
675    "is launching subprocess",
676    "\
677 This returns true iff this handle is launching the subprocess
678 (in the C<LAUNCHING> state).
679
680 For more information on states, see L<guestfs(3)>.");
681
682   ("is_busy", (RBool "busy", []), -1, [],
683    [InitNone, Always, TestOutputFalse (
684       [["is_busy"]])],
685    "is busy processing a command",
686    "\
687 This returns true iff this handle is busy processing a command
688 (in the C<BUSY> state).
689
690 For more information on states, see L<guestfs(3)>.");
691
692   ("get_state", (RInt "state", []), -1, [],
693    [],
694    "get the current state",
695    "\
696 This returns the current state as an opaque integer.  This is
697 only useful for printing debug and internal error messages.
698
699 For more information on states, see L<guestfs(3)>.");
700
701   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
702    [InitNone, Always, TestOutputInt (
703       [["set_memsize"; "500"];
704        ["get_memsize"]], 500)],
705    "set memory allocated to the qemu subprocess",
706    "\
707 This sets the memory size in megabytes allocated to the
708 qemu subprocess.  This only has any effect if called before
709 C<guestfs_launch>.
710
711 You can also change this by setting the environment
712 variable C<LIBGUESTFS_MEMSIZE> before the handle is
713 created.
714
715 For more information on the architecture of libguestfs,
716 see L<guestfs(3)>.");
717
718   ("get_memsize", (RInt "memsize", []), -1, [],
719    [InitNone, Always, TestOutputIntOp (
720       [["get_memsize"]], ">=", 256)],
721    "get memory allocated to the qemu subprocess",
722    "\
723 This gets the memory size in megabytes allocated to the
724 qemu subprocess.
725
726 If C<guestfs_set_memsize> was not called
727 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
728 then this returns the compiled-in default value for memsize.
729
730 For more information on the architecture of libguestfs,
731 see L<guestfs(3)>.");
732
733   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
734    [InitNone, Always, TestOutputIntOp (
735       [["get_pid"]], ">=", 1)],
736    "get PID of qemu subprocess",
737    "\
738 Return the process ID of the qemu subprocess.  If there is no
739 qemu subprocess, then this will return an error.
740
741 This is an internal call used for debugging and testing.");
742
743   ("version", (RStruct ("version", "version"), []), -1, [],
744    [InitNone, Always, TestOutputStruct (
745       [["version"]], [CompareWithInt ("major", 1)])],
746    "get the library version number",
747    "\
748 Return the libguestfs version number that the program is linked
749 against.
750
751 Note that because of dynamic linking this is not necessarily
752 the version of libguestfs that you compiled against.  You can
753 compile the program, and then at runtime dynamically link
754 against a completely different C<libguestfs.so> library.
755
756 This call was added in version C<1.0.58>.  In previous
757 versions of libguestfs there was no way to get the version
758 number.  From C code you can use ELF weak linking tricks to find out if
759 this symbol exists (if it doesn't, then it's an earlier version).
760
761 The call returns a structure with four elements.  The first
762 three (C<major>, C<minor> and C<release>) are numbers and
763 correspond to the usual version triplet.  The fourth element
764 (C<extra>) is a string and is normally empty, but may be
765 used for distro-specific information.
766
767 To construct the original version string:
768 C<$major.$minor.$release$extra>
769
770 I<Note:> Don't use this call to test for availability
771 of features.  Distro backports makes this unreliable.  Use
772 C<guestfs_available> instead.");
773
774   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
775    [InitNone, Always, TestOutputTrue (
776       [["set_selinux"; "true"];
777        ["get_selinux"]])],
778    "set SELinux enabled or disabled at appliance boot",
779    "\
780 This sets the selinux flag that is passed to the appliance
781 at boot time.  The default is C<selinux=0> (disabled).
782
783 Note that if SELinux is enabled, it is always in
784 Permissive mode (C<enforcing=0>).
785
786 For more information on the architecture of libguestfs,
787 see L<guestfs(3)>.");
788
789   ("get_selinux", (RBool "selinux", []), -1, [],
790    [],
791    "get SELinux enabled flag",
792    "\
793 This returns the current setting of the selinux flag which
794 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
795
796 For more information on the architecture of libguestfs,
797 see L<guestfs(3)>.");
798
799   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
800    [InitNone, Always, TestOutputFalse (
801       [["set_trace"; "false"];
802        ["get_trace"]])],
803    "enable or disable command traces",
804    "\
805 If the command trace flag is set to 1, then commands are
806 printed on stdout before they are executed in a format
807 which is very similar to the one used by guestfish.  In
808 other words, you can run a program with this enabled, and
809 you will get out a script which you can feed to guestfish
810 to perform the same set of actions.
811
812 If you want to trace C API calls into libguestfs (and
813 other libraries) then possibly a better way is to use
814 the external ltrace(1) command.
815
816 Command traces are disabled unless the environment variable
817 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
818
819   ("get_trace", (RBool "trace", []), -1, [],
820    [],
821    "get command trace enabled flag",
822    "\
823 Return the command trace flag.");
824
825   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
826    [InitNone, Always, TestOutputFalse (
827       [["set_direct"; "false"];
828        ["get_direct"]])],
829    "enable or disable direct appliance mode",
830    "\
831 If the direct appliance mode flag is enabled, then stdin and
832 stdout are passed directly through to the appliance once it
833 is launched.
834
835 One consequence of this is that log messages aren't caught
836 by the library and handled by C<guestfs_set_log_message_callback>,
837 but go straight to stdout.
838
839 You probably don't want to use this unless you know what you
840 are doing.
841
842 The default is disabled.");
843
844   ("get_direct", (RBool "direct", []), -1, [],
845    [],
846    "get direct appliance mode flag",
847    "\
848 Return the direct appliance mode flag.");
849
850   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
851    [InitNone, Always, TestOutputTrue (
852       [["set_recovery_proc"; "true"];
853        ["get_recovery_proc"]])],
854    "enable or disable the recovery process",
855    "\
856 If this is called with the parameter C<false> then
857 C<guestfs_launch> does not create a recovery process.  The
858 purpose of the recovery process is to stop runaway qemu
859 processes in the case where the main program aborts abruptly.
860
861 This only has any effect if called before C<guestfs_launch>,
862 and the default is true.
863
864 About the only time when you would want to disable this is
865 if the main process will fork itself into the background
866 (\"daemonize\" itself).  In this case the recovery process
867 thinks that the main program has disappeared and so kills
868 qemu, which is not very helpful.");
869
870   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
871    [],
872    "get recovery process enabled flag",
873    "\
874 Return the recovery process enabled flag.");
875
876 ]
877
878 (* daemon_functions are any functions which cause some action
879  * to take place in the daemon.
880  *)
881
882 let daemon_functions = [
883   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
884    [InitEmpty, Always, TestOutput (
885       [["part_disk"; "/dev/sda"; "mbr"];
886        ["mkfs"; "ext2"; "/dev/sda1"];
887        ["mount"; "/dev/sda1"; "/"];
888        ["write_file"; "/new"; "new file contents"; "0"];
889        ["cat"; "/new"]], "new file contents")],
890    "mount a guest disk at a position in the filesystem",
891    "\
892 Mount a guest disk at a position in the filesystem.  Block devices
893 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
894 the guest.  If those block devices contain partitions, they will have
895 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
896 names can be used.
897
898 The rules are the same as for L<mount(2)>:  A filesystem must
899 first be mounted on C</> before others can be mounted.  Other
900 filesystems can only be mounted on directories which already
901 exist.
902
903 The mounted filesystem is writable, if we have sufficient permissions
904 on the underlying device.
905
906 The filesystem options C<sync> and C<noatime> are set with this
907 call, in order to improve reliability.");
908
909   ("sync", (RErr, []), 2, [],
910    [ InitEmpty, Always, TestRun [["sync"]]],
911    "sync disks, writes are flushed through to the disk image",
912    "\
913 This syncs the disk, so that any writes are flushed through to the
914 underlying disk image.
915
916 You should always call this if you have modified a disk image, before
917 closing the handle.");
918
919   ("touch", (RErr, [Pathname "path"]), 3, [],
920    [InitBasicFS, Always, TestOutputTrue (
921       [["touch"; "/new"];
922        ["exists"; "/new"]])],
923    "update file timestamps or create a new file",
924    "\
925 Touch acts like the L<touch(1)> command.  It can be used to
926 update the timestamps on a file, or, if the file does not exist,
927 to create a new zero-length file.");
928
929   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
930    [InitISOFS, Always, TestOutput (
931       [["cat"; "/known-2"]], "abcdef\n")],
932    "list the contents of a file",
933    "\
934 Return the contents of the file named C<path>.
935
936 Note that this function cannot correctly handle binary files
937 (specifically, files containing C<\\0> character which is treated
938 as end of string).  For those you need to use the C<guestfs_read_file>
939 or C<guestfs_download> functions which have a more complex interface.");
940
941   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
942    [], (* XXX Tricky to test because it depends on the exact format
943         * of the 'ls -l' command, which changes between F10 and F11.
944         *)
945    "list the files in a directory (long format)",
946    "\
947 List the files in C<directory> (relative to the root directory,
948 there is no cwd) in the format of 'ls -la'.
949
950 This command is mostly useful for interactive sessions.  It
951 is I<not> intended that you try to parse the output string.");
952
953   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
954    [InitBasicFS, Always, TestOutputList (
955       [["touch"; "/new"];
956        ["touch"; "/newer"];
957        ["touch"; "/newest"];
958        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
959    "list the files in a directory",
960    "\
961 List the files in C<directory> (relative to the root directory,
962 there is no cwd).  The '.' and '..' entries are not returned, but
963 hidden files are shown.
964
965 This command is mostly useful for interactive sessions.  Programs
966 should probably use C<guestfs_readdir> instead.");
967
968   ("list_devices", (RStringList "devices", []), 7, [],
969    [InitEmpty, Always, TestOutputListOfDevices (
970       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
971    "list the block devices",
972    "\
973 List all the block devices.
974
975 The full block device names are returned, eg. C</dev/sda>");
976
977   ("list_partitions", (RStringList "partitions", []), 8, [],
978    [InitBasicFS, Always, TestOutputListOfDevices (
979       [["list_partitions"]], ["/dev/sda1"]);
980     InitEmpty, Always, TestOutputListOfDevices (
981       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
982        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
983    "list the partitions",
984    "\
985 List all the partitions detected on all block devices.
986
987 The full partition device names are returned, eg. C</dev/sda1>
988
989 This does not return logical volumes.  For that you will need to
990 call C<guestfs_lvs>.");
991
992   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
993    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
994       [["pvs"]], ["/dev/sda1"]);
995     InitEmpty, Always, TestOutputListOfDevices (
996       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
997        ["pvcreate"; "/dev/sda1"];
998        ["pvcreate"; "/dev/sda2"];
999        ["pvcreate"; "/dev/sda3"];
1000        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1001    "list the LVM physical volumes (PVs)",
1002    "\
1003 List all the physical volumes detected.  This is the equivalent
1004 of the L<pvs(8)> command.
1005
1006 This returns a list of just the device names that contain
1007 PVs (eg. C</dev/sda2>).
1008
1009 See also C<guestfs_pvs_full>.");
1010
1011   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1012    [InitBasicFSonLVM, Always, TestOutputList (
1013       [["vgs"]], ["VG"]);
1014     InitEmpty, Always, TestOutputList (
1015       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1016        ["pvcreate"; "/dev/sda1"];
1017        ["pvcreate"; "/dev/sda2"];
1018        ["pvcreate"; "/dev/sda3"];
1019        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1020        ["vgcreate"; "VG2"; "/dev/sda3"];
1021        ["vgs"]], ["VG1"; "VG2"])],
1022    "list the LVM volume groups (VGs)",
1023    "\
1024 List all the volumes groups detected.  This is the equivalent
1025 of the L<vgs(8)> command.
1026
1027 This returns a list of just the volume group names that were
1028 detected (eg. C<VolGroup00>).
1029
1030 See also C<guestfs_vgs_full>.");
1031
1032   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1033    [InitBasicFSonLVM, Always, TestOutputList (
1034       [["lvs"]], ["/dev/VG/LV"]);
1035     InitEmpty, Always, TestOutputList (
1036       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1037        ["pvcreate"; "/dev/sda1"];
1038        ["pvcreate"; "/dev/sda2"];
1039        ["pvcreate"; "/dev/sda3"];
1040        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1041        ["vgcreate"; "VG2"; "/dev/sda3"];
1042        ["lvcreate"; "LV1"; "VG1"; "50"];
1043        ["lvcreate"; "LV2"; "VG1"; "50"];
1044        ["lvcreate"; "LV3"; "VG2"; "50"];
1045        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1046    "list the LVM logical volumes (LVs)",
1047    "\
1048 List all the logical volumes detected.  This is the equivalent
1049 of the L<lvs(8)> command.
1050
1051 This returns a list of the logical volume device names
1052 (eg. C</dev/VolGroup00/LogVol00>).
1053
1054 See also C<guestfs_lvs_full>.");
1055
1056   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1057    [], (* XXX how to test? *)
1058    "list the LVM physical volumes (PVs)",
1059    "\
1060 List all the physical volumes detected.  This is the equivalent
1061 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1062
1063   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1064    [], (* XXX how to test? *)
1065    "list the LVM volume groups (VGs)",
1066    "\
1067 List all the volumes groups detected.  This is the equivalent
1068 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1069
1070   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1071    [], (* XXX how to test? *)
1072    "list the LVM logical volumes (LVs)",
1073    "\
1074 List all the logical volumes detected.  This is the equivalent
1075 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1076
1077   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1078    [InitISOFS, Always, TestOutputList (
1079       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1080     InitISOFS, Always, TestOutputList (
1081       [["read_lines"; "/empty"]], [])],
1082    "read file as lines",
1083    "\
1084 Return the contents of the file named C<path>.
1085
1086 The file contents are returned as a list of lines.  Trailing
1087 C<LF> and C<CRLF> character sequences are I<not> returned.
1088
1089 Note that this function cannot correctly handle binary files
1090 (specifically, files containing C<\\0> character which is treated
1091 as end of line).  For those you need to use the C<guestfs_read_file>
1092 function which has a more complex interface.");
1093
1094   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1095    [], (* XXX Augeas code needs tests. *)
1096    "create a new Augeas handle",
1097    "\
1098 Create a new Augeas handle for editing configuration files.
1099 If there was any previous Augeas handle associated with this
1100 guestfs session, then it is closed.
1101
1102 You must call this before using any other C<guestfs_aug_*>
1103 commands.
1104
1105 C<root> is the filesystem root.  C<root> must not be NULL,
1106 use C</> instead.
1107
1108 The flags are the same as the flags defined in
1109 E<lt>augeas.hE<gt>, the logical I<or> of the following
1110 integers:
1111
1112 =over 4
1113
1114 =item C<AUG_SAVE_BACKUP> = 1
1115
1116 Keep the original file with a C<.augsave> extension.
1117
1118 =item C<AUG_SAVE_NEWFILE> = 2
1119
1120 Save changes into a file with extension C<.augnew>, and
1121 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1122
1123 =item C<AUG_TYPE_CHECK> = 4
1124
1125 Typecheck lenses (can be expensive).
1126
1127 =item C<AUG_NO_STDINC> = 8
1128
1129 Do not use standard load path for modules.
1130
1131 =item C<AUG_SAVE_NOOP> = 16
1132
1133 Make save a no-op, just record what would have been changed.
1134
1135 =item C<AUG_NO_LOAD> = 32
1136
1137 Do not load the tree in C<guestfs_aug_init>.
1138
1139 =back
1140
1141 To close the handle, you can call C<guestfs_aug_close>.
1142
1143 To find out more about Augeas, see L<http://augeas.net/>.");
1144
1145   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1146    [], (* XXX Augeas code needs tests. *)
1147    "close the current Augeas handle",
1148    "\
1149 Close the current Augeas handle and free up any resources
1150 used by it.  After calling this, you have to call
1151 C<guestfs_aug_init> again before you can use any other
1152 Augeas functions.");
1153
1154   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1155    [], (* XXX Augeas code needs tests. *)
1156    "define an Augeas variable",
1157    "\
1158 Defines an Augeas variable C<name> whose value is the result
1159 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1160 undefined.
1161
1162 On success this returns the number of nodes in C<expr>, or
1163 C<0> if C<expr> evaluates to something which is not a nodeset.");
1164
1165   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1166    [], (* XXX Augeas code needs tests. *)
1167    "define an Augeas node",
1168    "\
1169 Defines a variable C<name> whose value is the result of
1170 evaluating C<expr>.
1171
1172 If C<expr> evaluates to an empty nodeset, a node is created,
1173 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1174 C<name> will be the nodeset containing that single node.
1175
1176 On success this returns a pair containing the
1177 number of nodes in the nodeset, and a boolean flag
1178 if a node was created.");
1179
1180   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1181    [], (* XXX Augeas code needs tests. *)
1182    "look up the value of an Augeas path",
1183    "\
1184 Look up the value associated with C<path>.  If C<path>
1185 matches exactly one node, the C<value> is returned.");
1186
1187   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1188    [], (* XXX Augeas code needs tests. *)
1189    "set Augeas path to value",
1190    "\
1191 Set the value associated with C<path> to C<value>.");
1192
1193   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1194    [], (* XXX Augeas code needs tests. *)
1195    "insert a sibling Augeas node",
1196    "\
1197 Create a new sibling C<label> for C<path>, inserting it into
1198 the tree before or after C<path> (depending on the boolean
1199 flag C<before>).
1200
1201 C<path> must match exactly one existing node in the tree, and
1202 C<label> must be a label, ie. not contain C</>, C<*> or end
1203 with a bracketed index C<[N]>.");
1204
1205   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1206    [], (* XXX Augeas code needs tests. *)
1207    "remove an Augeas path",
1208    "\
1209 Remove C<path> and all of its children.
1210
1211 On success this returns the number of entries which were removed.");
1212
1213   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1214    [], (* XXX Augeas code needs tests. *)
1215    "move Augeas node",
1216    "\
1217 Move the node C<src> to C<dest>.  C<src> must match exactly
1218 one node.  C<dest> is overwritten if it exists.");
1219
1220   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1221    [], (* XXX Augeas code needs tests. *)
1222    "return Augeas nodes which match augpath",
1223    "\
1224 Returns a list of paths which match the path expression C<path>.
1225 The returned paths are sufficiently qualified so that they match
1226 exactly one node in the current tree.");
1227
1228   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1229    [], (* XXX Augeas code needs tests. *)
1230    "write all pending Augeas changes to disk",
1231    "\
1232 This writes all pending changes to disk.
1233
1234 The flags which were passed to C<guestfs_aug_init> affect exactly
1235 how files are saved.");
1236
1237   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1238    [], (* XXX Augeas code needs tests. *)
1239    "load files into the tree",
1240    "\
1241 Load files into the tree.
1242
1243 See C<aug_load> in the Augeas documentation for the full gory
1244 details.");
1245
1246   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1247    [], (* XXX Augeas code needs tests. *)
1248    "list Augeas nodes under augpath",
1249    "\
1250 This is just a shortcut for listing C<guestfs_aug_match>
1251 C<path/*> and sorting the resulting nodes into alphabetical order.");
1252
1253   ("rm", (RErr, [Pathname "path"]), 29, [],
1254    [InitBasicFS, Always, TestRun
1255       [["touch"; "/new"];
1256        ["rm"; "/new"]];
1257     InitBasicFS, Always, TestLastFail
1258       [["rm"; "/new"]];
1259     InitBasicFS, Always, TestLastFail
1260       [["mkdir"; "/new"];
1261        ["rm"; "/new"]]],
1262    "remove a file",
1263    "\
1264 Remove the single file C<path>.");
1265
1266   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1267    [InitBasicFS, Always, TestRun
1268       [["mkdir"; "/new"];
1269        ["rmdir"; "/new"]];
1270     InitBasicFS, Always, TestLastFail
1271       [["rmdir"; "/new"]];
1272     InitBasicFS, Always, TestLastFail
1273       [["touch"; "/new"];
1274        ["rmdir"; "/new"]]],
1275    "remove a directory",
1276    "\
1277 Remove the single directory C<path>.");
1278
1279   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1280    [InitBasicFS, Always, TestOutputFalse
1281       [["mkdir"; "/new"];
1282        ["mkdir"; "/new/foo"];
1283        ["touch"; "/new/foo/bar"];
1284        ["rm_rf"; "/new"];
1285        ["exists"; "/new"]]],
1286    "remove a file or directory recursively",
1287    "\
1288 Remove the file or directory C<path>, recursively removing the
1289 contents if its a directory.  This is like the C<rm -rf> shell
1290 command.");
1291
1292   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1293    [InitBasicFS, Always, TestOutputTrue
1294       [["mkdir"; "/new"];
1295        ["is_dir"; "/new"]];
1296     InitBasicFS, Always, TestLastFail
1297       [["mkdir"; "/new/foo/bar"]]],
1298    "create a directory",
1299    "\
1300 Create a directory named C<path>.");
1301
1302   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1303    [InitBasicFS, Always, TestOutputTrue
1304       [["mkdir_p"; "/new/foo/bar"];
1305        ["is_dir"; "/new/foo/bar"]];
1306     InitBasicFS, Always, TestOutputTrue
1307       [["mkdir_p"; "/new/foo/bar"];
1308        ["is_dir"; "/new/foo"]];
1309     InitBasicFS, Always, TestOutputTrue
1310       [["mkdir_p"; "/new/foo/bar"];
1311        ["is_dir"; "/new"]];
1312     (* Regression tests for RHBZ#503133: *)
1313     InitBasicFS, Always, TestRun
1314       [["mkdir"; "/new"];
1315        ["mkdir_p"; "/new"]];
1316     InitBasicFS, Always, TestLastFail
1317       [["touch"; "/new"];
1318        ["mkdir_p"; "/new"]]],
1319    "create a directory and parents",
1320    "\
1321 Create a directory named C<path>, creating any parent directories
1322 as necessary.  This is like the C<mkdir -p> shell command.");
1323
1324   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1325    [], (* XXX Need stat command to test *)
1326    "change file mode",
1327    "\
1328 Change the mode (permissions) of C<path> to C<mode>.  Only
1329 numeric modes are supported.
1330
1331 I<Note>: When using this command from guestfish, C<mode>
1332 by default would be decimal, unless you prefix it with
1333 C<0> to get octal, ie. use C<0700> not C<700>.");
1334
1335   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1336    [], (* XXX Need stat command to test *)
1337    "change file owner and group",
1338    "\
1339 Change the file owner to C<owner> and group to C<group>.
1340
1341 Only numeric uid and gid are supported.  If you want to use
1342 names, you will need to locate and parse the password file
1343 yourself (Augeas support makes this relatively easy).");
1344
1345   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1346    [InitISOFS, Always, TestOutputTrue (
1347       [["exists"; "/empty"]]);
1348     InitISOFS, Always, TestOutputTrue (
1349       [["exists"; "/directory"]])],
1350    "test if file or directory exists",
1351    "\
1352 This returns C<true> if and only if there is a file, directory
1353 (or anything) with the given C<path> name.
1354
1355 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1356
1357   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1358    [InitISOFS, Always, TestOutputTrue (
1359       [["is_file"; "/known-1"]]);
1360     InitISOFS, Always, TestOutputFalse (
1361       [["is_file"; "/directory"]])],
1362    "test if file exists",
1363    "\
1364 This returns C<true> if and only if there is a file
1365 with the given C<path> name.  Note that it returns false for
1366 other objects like directories.
1367
1368 See also C<guestfs_stat>.");
1369
1370   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1371    [InitISOFS, Always, TestOutputFalse (
1372       [["is_dir"; "/known-3"]]);
1373     InitISOFS, Always, TestOutputTrue (
1374       [["is_dir"; "/directory"]])],
1375    "test if file exists",
1376    "\
1377 This returns C<true> if and only if there is a directory
1378 with the given C<path> name.  Note that it returns false for
1379 other objects like files.
1380
1381 See also C<guestfs_stat>.");
1382
1383   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1384    [InitEmpty, Always, TestOutputListOfDevices (
1385       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1386        ["pvcreate"; "/dev/sda1"];
1387        ["pvcreate"; "/dev/sda2"];
1388        ["pvcreate"; "/dev/sda3"];
1389        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1390    "create an LVM physical volume",
1391    "\
1392 This creates an LVM physical volume on the named C<device>,
1393 where C<device> should usually be a partition name such
1394 as C</dev/sda1>.");
1395
1396   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1397    [InitEmpty, Always, TestOutputList (
1398       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1399        ["pvcreate"; "/dev/sda1"];
1400        ["pvcreate"; "/dev/sda2"];
1401        ["pvcreate"; "/dev/sda3"];
1402        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1403        ["vgcreate"; "VG2"; "/dev/sda3"];
1404        ["vgs"]], ["VG1"; "VG2"])],
1405    "create an LVM volume group",
1406    "\
1407 This creates an LVM volume group called C<volgroup>
1408 from the non-empty list of physical volumes C<physvols>.");
1409
1410   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1411    [InitEmpty, Always, TestOutputList (
1412       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1413        ["pvcreate"; "/dev/sda1"];
1414        ["pvcreate"; "/dev/sda2"];
1415        ["pvcreate"; "/dev/sda3"];
1416        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1417        ["vgcreate"; "VG2"; "/dev/sda3"];
1418        ["lvcreate"; "LV1"; "VG1"; "50"];
1419        ["lvcreate"; "LV2"; "VG1"; "50"];
1420        ["lvcreate"; "LV3"; "VG2"; "50"];
1421        ["lvcreate"; "LV4"; "VG2"; "50"];
1422        ["lvcreate"; "LV5"; "VG2"; "50"];
1423        ["lvs"]],
1424       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1425        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1426    "create an LVM volume group",
1427    "\
1428 This creates an LVM volume group called C<logvol>
1429 on the volume group C<volgroup>, with C<size> megabytes.");
1430
1431   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1432    [InitEmpty, Always, TestOutput (
1433       [["part_disk"; "/dev/sda"; "mbr"];
1434        ["mkfs"; "ext2"; "/dev/sda1"];
1435        ["mount"; "/dev/sda1"; "/"];
1436        ["write_file"; "/new"; "new file contents"; "0"];
1437        ["cat"; "/new"]], "new file contents")],
1438    "make a filesystem",
1439    "\
1440 This creates a filesystem on C<device> (usually a partition
1441 or LVM logical volume).  The filesystem type is C<fstype>, for
1442 example C<ext3>.");
1443
1444   ("sfdisk", (RErr, [Device "device";
1445                      Int "cyls"; Int "heads"; Int "sectors";
1446                      StringList "lines"]), 43, [DangerWillRobinson],
1447    [],
1448    "create partitions on a block device",
1449    "\
1450 This is a direct interface to the L<sfdisk(8)> program for creating
1451 partitions on block devices.
1452
1453 C<device> should be a block device, for example C</dev/sda>.
1454
1455 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1456 and sectors on the device, which are passed directly to sfdisk as
1457 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1458 of these, then the corresponding parameter is omitted.  Usually for
1459 'large' disks, you can just pass C<0> for these, but for small
1460 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1461 out the right geometry and you will need to tell it.
1462
1463 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1464 information refer to the L<sfdisk(8)> manpage.
1465
1466 To create a single partition occupying the whole disk, you would
1467 pass C<lines> as a single element list, when the single element being
1468 the string C<,> (comma).
1469
1470 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1471 C<guestfs_part_init>");
1472
1473   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1474    [InitBasicFS, Always, TestOutput (
1475       [["write_file"; "/new"; "new file contents"; "0"];
1476        ["cat"; "/new"]], "new file contents");
1477     InitBasicFS, Always, TestOutput (
1478       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1479        ["cat"; "/new"]], "\nnew file contents\n");
1480     InitBasicFS, Always, TestOutput (
1481       [["write_file"; "/new"; "\n\n"; "0"];
1482        ["cat"; "/new"]], "\n\n");
1483     InitBasicFS, Always, TestOutput (
1484       [["write_file"; "/new"; ""; "0"];
1485        ["cat"; "/new"]], "");
1486     InitBasicFS, Always, TestOutput (
1487       [["write_file"; "/new"; "\n\n\n"; "0"];
1488        ["cat"; "/new"]], "\n\n\n");
1489     InitBasicFS, Always, TestOutput (
1490       [["write_file"; "/new"; "\n"; "0"];
1491        ["cat"; "/new"]], "\n")],
1492    "create a file",
1493    "\
1494 This call creates a file called C<path>.  The contents of the
1495 file is the string C<content> (which can contain any 8 bit data),
1496 with length C<size>.
1497
1498 As a special case, if C<size> is C<0>
1499 then the length is calculated using C<strlen> (so in this case
1500 the content cannot contain embedded ASCII NULs).
1501
1502 I<NB.> Owing to a bug, writing content containing ASCII NUL
1503 characters does I<not> work, even if the length is specified.
1504 We hope to resolve this bug in a future version.  In the meantime
1505 use C<guestfs_upload>.");
1506
1507   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1508    [InitEmpty, Always, TestOutputListOfDevices (
1509       [["part_disk"; "/dev/sda"; "mbr"];
1510        ["mkfs"; "ext2"; "/dev/sda1"];
1511        ["mount"; "/dev/sda1"; "/"];
1512        ["mounts"]], ["/dev/sda1"]);
1513     InitEmpty, Always, TestOutputList (
1514       [["part_disk"; "/dev/sda"; "mbr"];
1515        ["mkfs"; "ext2"; "/dev/sda1"];
1516        ["mount"; "/dev/sda1"; "/"];
1517        ["umount"; "/"];
1518        ["mounts"]], [])],
1519    "unmount a filesystem",
1520    "\
1521 This unmounts the given filesystem.  The filesystem may be
1522 specified either by its mountpoint (path) or the device which
1523 contains the filesystem.");
1524
1525   ("mounts", (RStringList "devices", []), 46, [],
1526    [InitBasicFS, Always, TestOutputListOfDevices (
1527       [["mounts"]], ["/dev/sda1"])],
1528    "show mounted filesystems",
1529    "\
1530 This returns the list of currently mounted filesystems.  It returns
1531 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1532
1533 Some internal mounts are not shown.
1534
1535 See also: C<guestfs_mountpoints>");
1536
1537   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1538    [InitBasicFS, Always, TestOutputList (
1539       [["umount_all"];
1540        ["mounts"]], []);
1541     (* check that umount_all can unmount nested mounts correctly: *)
1542     InitEmpty, Always, TestOutputList (
1543       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1544        ["mkfs"; "ext2"; "/dev/sda1"];
1545        ["mkfs"; "ext2"; "/dev/sda2"];
1546        ["mkfs"; "ext2"; "/dev/sda3"];
1547        ["mount"; "/dev/sda1"; "/"];
1548        ["mkdir"; "/mp1"];
1549        ["mount"; "/dev/sda2"; "/mp1"];
1550        ["mkdir"; "/mp1/mp2"];
1551        ["mount"; "/dev/sda3"; "/mp1/mp2"];
1552        ["mkdir"; "/mp1/mp2/mp3"];
1553        ["umount_all"];
1554        ["mounts"]], [])],
1555    "unmount all filesystems",
1556    "\
1557 This unmounts all mounted filesystems.
1558
1559 Some internal mounts are not unmounted by this call.");
1560
1561   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1562    [],
1563    "remove all LVM LVs, VGs and PVs",
1564    "\
1565 This command removes all LVM logical volumes, volume groups
1566 and physical volumes.");
1567
1568   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1569    [InitISOFS, Always, TestOutput (
1570       [["file"; "/empty"]], "empty");
1571     InitISOFS, Always, TestOutput (
1572       [["file"; "/known-1"]], "ASCII text");
1573     InitISOFS, Always, TestLastFail (
1574       [["file"; "/notexists"]])],
1575    "determine file type",
1576    "\
1577 This call uses the standard L<file(1)> command to determine
1578 the type or contents of the file.  This also works on devices,
1579 for example to find out whether a partition contains a filesystem.
1580
1581 This call will also transparently look inside various types
1582 of compressed file.
1583
1584 The exact command which runs is C<file -zbsL path>.  Note in
1585 particular that the filename is not prepended to the output
1586 (the C<-b> option).");
1587
1588   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1589    [InitBasicFS, Always, TestOutput (
1590       [["upload"; "test-command"; "/test-command"];
1591        ["chmod"; "0o755"; "/test-command"];
1592        ["command"; "/test-command 1"]], "Result1");
1593     InitBasicFS, Always, TestOutput (
1594       [["upload"; "test-command"; "/test-command"];
1595        ["chmod"; "0o755"; "/test-command"];
1596        ["command"; "/test-command 2"]], "Result2\n");
1597     InitBasicFS, Always, TestOutput (
1598       [["upload"; "test-command"; "/test-command"];
1599        ["chmod"; "0o755"; "/test-command"];
1600        ["command"; "/test-command 3"]], "\nResult3");
1601     InitBasicFS, Always, TestOutput (
1602       [["upload"; "test-command"; "/test-command"];
1603        ["chmod"; "0o755"; "/test-command"];
1604        ["command"; "/test-command 4"]], "\nResult4\n");
1605     InitBasicFS, Always, TestOutput (
1606       [["upload"; "test-command"; "/test-command"];
1607        ["chmod"; "0o755"; "/test-command"];
1608        ["command"; "/test-command 5"]], "\nResult5\n\n");
1609     InitBasicFS, Always, TestOutput (
1610       [["upload"; "test-command"; "/test-command"];
1611        ["chmod"; "0o755"; "/test-command"];
1612        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1613     InitBasicFS, Always, TestOutput (
1614       [["upload"; "test-command"; "/test-command"];
1615        ["chmod"; "0o755"; "/test-command"];
1616        ["command"; "/test-command 7"]], "");
1617     InitBasicFS, Always, TestOutput (
1618       [["upload"; "test-command"; "/test-command"];
1619        ["chmod"; "0o755"; "/test-command"];
1620        ["command"; "/test-command 8"]], "\n");
1621     InitBasicFS, Always, TestOutput (
1622       [["upload"; "test-command"; "/test-command"];
1623        ["chmod"; "0o755"; "/test-command"];
1624        ["command"; "/test-command 9"]], "\n\n");
1625     InitBasicFS, Always, TestOutput (
1626       [["upload"; "test-command"; "/test-command"];
1627        ["chmod"; "0o755"; "/test-command"];
1628        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1629     InitBasicFS, Always, TestOutput (
1630       [["upload"; "test-command"; "/test-command"];
1631        ["chmod"; "0o755"; "/test-command"];
1632        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1633     InitBasicFS, Always, TestLastFail (
1634       [["upload"; "test-command"; "/test-command"];
1635        ["chmod"; "0o755"; "/test-command"];
1636        ["command"; "/test-command"]])],
1637    "run a command from the guest filesystem",
1638    "\
1639 This call runs a command from the guest filesystem.  The
1640 filesystem must be mounted, and must contain a compatible
1641 operating system (ie. something Linux, with the same
1642 or compatible processor architecture).
1643
1644 The single parameter is an argv-style list of arguments.
1645 The first element is the name of the program to run.
1646 Subsequent elements are parameters.  The list must be
1647 non-empty (ie. must contain a program name).  Note that
1648 the command runs directly, and is I<not> invoked via
1649 the shell (see C<guestfs_sh>).
1650
1651 The return value is anything printed to I<stdout> by
1652 the command.
1653
1654 If the command returns a non-zero exit status, then
1655 this function returns an error message.  The error message
1656 string is the content of I<stderr> from the command.
1657
1658 The C<$PATH> environment variable will contain at least
1659 C</usr/bin> and C</bin>.  If you require a program from
1660 another location, you should provide the full path in the
1661 first parameter.
1662
1663 Shared libraries and data files required by the program
1664 must be available on filesystems which are mounted in the
1665 correct places.  It is the caller's responsibility to ensure
1666 all filesystems that are needed are mounted at the right
1667 locations.");
1668
1669   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1670    [InitBasicFS, Always, TestOutputList (
1671       [["upload"; "test-command"; "/test-command"];
1672        ["chmod"; "0o755"; "/test-command"];
1673        ["command_lines"; "/test-command 1"]], ["Result1"]);
1674     InitBasicFS, Always, TestOutputList (
1675       [["upload"; "test-command"; "/test-command"];
1676        ["chmod"; "0o755"; "/test-command"];
1677        ["command_lines"; "/test-command 2"]], ["Result2"]);
1678     InitBasicFS, Always, TestOutputList (
1679       [["upload"; "test-command"; "/test-command"];
1680        ["chmod"; "0o755"; "/test-command"];
1681        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1682     InitBasicFS, Always, TestOutputList (
1683       [["upload"; "test-command"; "/test-command"];
1684        ["chmod"; "0o755"; "/test-command"];
1685        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1686     InitBasicFS, Always, TestOutputList (
1687       [["upload"; "test-command"; "/test-command"];
1688        ["chmod"; "0o755"; "/test-command"];
1689        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1690     InitBasicFS, Always, TestOutputList (
1691       [["upload"; "test-command"; "/test-command"];
1692        ["chmod"; "0o755"; "/test-command"];
1693        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1694     InitBasicFS, Always, TestOutputList (
1695       [["upload"; "test-command"; "/test-command"];
1696        ["chmod"; "0o755"; "/test-command"];
1697        ["command_lines"; "/test-command 7"]], []);
1698     InitBasicFS, Always, TestOutputList (
1699       [["upload"; "test-command"; "/test-command"];
1700        ["chmod"; "0o755"; "/test-command"];
1701        ["command_lines"; "/test-command 8"]], [""]);
1702     InitBasicFS, Always, TestOutputList (
1703       [["upload"; "test-command"; "/test-command"];
1704        ["chmod"; "0o755"; "/test-command"];
1705        ["command_lines"; "/test-command 9"]], ["";""]);
1706     InitBasicFS, Always, TestOutputList (
1707       [["upload"; "test-command"; "/test-command"];
1708        ["chmod"; "0o755"; "/test-command"];
1709        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1710     InitBasicFS, Always, TestOutputList (
1711       [["upload"; "test-command"; "/test-command"];
1712        ["chmod"; "0o755"; "/test-command"];
1713        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1714    "run a command, returning lines",
1715    "\
1716 This is the same as C<guestfs_command>, but splits the
1717 result into a list of lines.
1718
1719 See also: C<guestfs_sh_lines>");
1720
1721   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1722    [InitISOFS, Always, TestOutputStruct (
1723       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1724    "get file information",
1725    "\
1726 Returns file information for the given C<path>.
1727
1728 This is the same as the C<stat(2)> system call.");
1729
1730   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1731    [InitISOFS, Always, TestOutputStruct (
1732       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1733    "get file information for a symbolic link",
1734    "\
1735 Returns file information for the given C<path>.
1736
1737 This is the same as C<guestfs_stat> except that if C<path>
1738 is a symbolic link, then the link is stat-ed, not the file it
1739 refers to.
1740
1741 This is the same as the C<lstat(2)> system call.");
1742
1743   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1744    [InitISOFS, Always, TestOutputStruct (
1745       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1746    "get file system statistics",
1747    "\
1748 Returns file system statistics for any mounted file system.
1749 C<path> should be a file or directory in the mounted file system
1750 (typically it is the mount point itself, but it doesn't need to be).
1751
1752 This is the same as the C<statvfs(2)> system call.");
1753
1754   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1755    [], (* XXX test *)
1756    "get ext2/ext3/ext4 superblock details",
1757    "\
1758 This returns the contents of the ext2, ext3 or ext4 filesystem
1759 superblock on C<device>.
1760
1761 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1762 manpage for more details.  The list of fields returned isn't
1763 clearly defined, and depends on both the version of C<tune2fs>
1764 that libguestfs was built against, and the filesystem itself.");
1765
1766   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1767    [InitEmpty, Always, TestOutputTrue (
1768       [["blockdev_setro"; "/dev/sda"];
1769        ["blockdev_getro"; "/dev/sda"]])],
1770    "set block device to read-only",
1771    "\
1772 Sets the block device named C<device> to read-only.
1773
1774 This uses the L<blockdev(8)> command.");
1775
1776   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1777    [InitEmpty, Always, TestOutputFalse (
1778       [["blockdev_setrw"; "/dev/sda"];
1779        ["blockdev_getro"; "/dev/sda"]])],
1780    "set block device to read-write",
1781    "\
1782 Sets the block device named C<device> to read-write.
1783
1784 This uses the L<blockdev(8)> command.");
1785
1786   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1787    [InitEmpty, Always, TestOutputTrue (
1788       [["blockdev_setro"; "/dev/sda"];
1789        ["blockdev_getro"; "/dev/sda"]])],
1790    "is block device set to read-only",
1791    "\
1792 Returns a boolean indicating if the block device is read-only
1793 (true if read-only, false if not).
1794
1795 This uses the L<blockdev(8)> command.");
1796
1797   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1798    [InitEmpty, Always, TestOutputInt (
1799       [["blockdev_getss"; "/dev/sda"]], 512)],
1800    "get sectorsize of block device",
1801    "\
1802 This returns the size of sectors on a block device.
1803 Usually 512, but can be larger for modern devices.
1804
1805 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1806 for that).
1807
1808 This uses the L<blockdev(8)> command.");
1809
1810   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1811    [InitEmpty, Always, TestOutputInt (
1812       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1813    "get blocksize of block device",
1814    "\
1815 This returns the block size of a device.
1816
1817 (Note this is different from both I<size in blocks> and
1818 I<filesystem block size>).
1819
1820 This uses the L<blockdev(8)> command.");
1821
1822   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1823    [], (* XXX test *)
1824    "set blocksize of block device",
1825    "\
1826 This sets the block size of a device.
1827
1828 (Note this is different from both I<size in blocks> and
1829 I<filesystem block size>).
1830
1831 This uses the L<blockdev(8)> command.");
1832
1833   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1834    [InitEmpty, Always, TestOutputInt (
1835       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1836    "get total size of device in 512-byte sectors",
1837    "\
1838 This returns the size of the device in units of 512-byte sectors
1839 (even if the sectorsize isn't 512 bytes ... weird).
1840
1841 See also C<guestfs_blockdev_getss> for the real sector size of
1842 the device, and C<guestfs_blockdev_getsize64> for the more
1843 useful I<size in bytes>.
1844
1845 This uses the L<blockdev(8)> command.");
1846
1847   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1848    [InitEmpty, Always, TestOutputInt (
1849       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1850    "get total size of device in bytes",
1851    "\
1852 This returns the size of the device in bytes.
1853
1854 See also C<guestfs_blockdev_getsz>.
1855
1856 This uses the L<blockdev(8)> command.");
1857
1858   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1859    [InitEmpty, Always, TestRun
1860       [["blockdev_flushbufs"; "/dev/sda"]]],
1861    "flush device buffers",
1862    "\
1863 This tells the kernel to flush internal buffers associated
1864 with C<device>.
1865
1866 This uses the L<blockdev(8)> command.");
1867
1868   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1869    [InitEmpty, Always, TestRun
1870       [["blockdev_rereadpt"; "/dev/sda"]]],
1871    "reread partition table",
1872    "\
1873 Reread the partition table on C<device>.
1874
1875 This uses the L<blockdev(8)> command.");
1876
1877   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1878    [InitBasicFS, Always, TestOutput (
1879       (* Pick a file from cwd which isn't likely to change. *)
1880       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1881        ["checksum"; "md5"; "/COPYING.LIB"]],
1882       Digest.to_hex (Digest.file "COPYING.LIB"))],
1883    "upload a file from the local machine",
1884    "\
1885 Upload local file C<filename> to C<remotefilename> on the
1886 filesystem.
1887
1888 C<filename> can also be a named pipe.
1889
1890 See also C<guestfs_download>.");
1891
1892   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1893    [InitBasicFS, Always, TestOutput (
1894       (* Pick a file from cwd which isn't likely to change. *)
1895       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1896        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1897        ["upload"; "testdownload.tmp"; "/upload"];
1898        ["checksum"; "md5"; "/upload"]],
1899       Digest.to_hex (Digest.file "COPYING.LIB"))],
1900    "download a file to the local machine",
1901    "\
1902 Download file C<remotefilename> and save it as C<filename>
1903 on the local machine.
1904
1905 C<filename> can also be a named pipe.
1906
1907 See also C<guestfs_upload>, C<guestfs_cat>.");
1908
1909   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1910    [InitISOFS, Always, TestOutput (
1911       [["checksum"; "crc"; "/known-3"]], "2891671662");
1912     InitISOFS, Always, TestLastFail (
1913       [["checksum"; "crc"; "/notexists"]]);
1914     InitISOFS, Always, TestOutput (
1915       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1916     InitISOFS, Always, TestOutput (
1917       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1918     InitISOFS, Always, TestOutput (
1919       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1920     InitISOFS, Always, TestOutput (
1921       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1922     InitISOFS, Always, TestOutput (
1923       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1924     InitISOFS, Always, TestOutput (
1925       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1926    "compute MD5, SHAx or CRC checksum of file",
1927    "\
1928 This call computes the MD5, SHAx or CRC checksum of the
1929 file named C<path>.
1930
1931 The type of checksum to compute is given by the C<csumtype>
1932 parameter which must have one of the following values:
1933
1934 =over 4
1935
1936 =item C<crc>
1937
1938 Compute the cyclic redundancy check (CRC) specified by POSIX
1939 for the C<cksum> command.
1940
1941 =item C<md5>
1942
1943 Compute the MD5 hash (using the C<md5sum> program).
1944
1945 =item C<sha1>
1946
1947 Compute the SHA1 hash (using the C<sha1sum> program).
1948
1949 =item C<sha224>
1950
1951 Compute the SHA224 hash (using the C<sha224sum> program).
1952
1953 =item C<sha256>
1954
1955 Compute the SHA256 hash (using the C<sha256sum> program).
1956
1957 =item C<sha384>
1958
1959 Compute the SHA384 hash (using the C<sha384sum> program).
1960
1961 =item C<sha512>
1962
1963 Compute the SHA512 hash (using the C<sha512sum> program).
1964
1965 =back
1966
1967 The checksum is returned as a printable string.");
1968
1969   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1970    [InitBasicFS, Always, TestOutput (
1971       [["tar_in"; "../images/helloworld.tar"; "/"];
1972        ["cat"; "/hello"]], "hello\n")],
1973    "unpack tarfile to directory",
1974    "\
1975 This command uploads and unpacks local file C<tarfile> (an
1976 I<uncompressed> tar file) into C<directory>.
1977
1978 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1979
1980   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1981    [],
1982    "pack directory into tarfile",
1983    "\
1984 This command packs the contents of C<directory> and downloads
1985 it to local file C<tarfile>.
1986
1987 To download a compressed tarball, use C<guestfs_tgz_out>.");
1988
1989   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1990    [InitBasicFS, Always, TestOutput (
1991       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1992        ["cat"; "/hello"]], "hello\n")],
1993    "unpack compressed tarball to directory",
1994    "\
1995 This command uploads and unpacks local file C<tarball> (a
1996 I<gzip compressed> tar file) into C<directory>.
1997
1998 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1999
2000   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
2001    [],
2002    "pack directory into compressed tarball",
2003    "\
2004 This command packs the contents of C<directory> and downloads
2005 it to local file C<tarball>.
2006
2007 To download an uncompressed tarball, use C<guestfs_tar_out>.");
2008
2009   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
2010    [InitBasicFS, Always, TestLastFail (
2011       [["umount"; "/"];
2012        ["mount_ro"; "/dev/sda1"; "/"];
2013        ["touch"; "/new"]]);
2014     InitBasicFS, Always, TestOutput (
2015       [["write_file"; "/new"; "data"; "0"];
2016        ["umount"; "/"];
2017        ["mount_ro"; "/dev/sda1"; "/"];
2018        ["cat"; "/new"]], "data")],
2019    "mount a guest disk, read-only",
2020    "\
2021 This is the same as the C<guestfs_mount> command, but it
2022 mounts the filesystem with the read-only (I<-o ro>) flag.");
2023
2024   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
2025    [],
2026    "mount a guest disk with mount options",
2027    "\
2028 This is the same as the C<guestfs_mount> command, but it
2029 allows you to set the mount options as for the
2030 L<mount(8)> I<-o> flag.");
2031
2032   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2033    [],
2034    "mount a guest disk with mount options and vfstype",
2035    "\
2036 This is the same as the C<guestfs_mount> command, but it
2037 allows you to set both the mount options and the vfstype
2038 as for the L<mount(8)> I<-o> and I<-t> flags.");
2039
2040   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2041    [],
2042    "debugging and internals",
2043    "\
2044 The C<guestfs_debug> command exposes some internals of
2045 C<guestfsd> (the guestfs daemon) that runs inside the
2046 qemu subprocess.
2047
2048 There is no comprehensive help for this command.  You have
2049 to look at the file C<daemon/debug.c> in the libguestfs source
2050 to find out what you can do.");
2051
2052   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2053    [InitEmpty, Always, TestOutputList (
2054       [["part_disk"; "/dev/sda"; "mbr"];
2055        ["pvcreate"; "/dev/sda1"];
2056        ["vgcreate"; "VG"; "/dev/sda1"];
2057        ["lvcreate"; "LV1"; "VG"; "50"];
2058        ["lvcreate"; "LV2"; "VG"; "50"];
2059        ["lvremove"; "/dev/VG/LV1"];
2060        ["lvs"]], ["/dev/VG/LV2"]);
2061     InitEmpty, Always, TestOutputList (
2062       [["part_disk"; "/dev/sda"; "mbr"];
2063        ["pvcreate"; "/dev/sda1"];
2064        ["vgcreate"; "VG"; "/dev/sda1"];
2065        ["lvcreate"; "LV1"; "VG"; "50"];
2066        ["lvcreate"; "LV2"; "VG"; "50"];
2067        ["lvremove"; "/dev/VG"];
2068        ["lvs"]], []);
2069     InitEmpty, Always, TestOutputList (
2070       [["part_disk"; "/dev/sda"; "mbr"];
2071        ["pvcreate"; "/dev/sda1"];
2072        ["vgcreate"; "VG"; "/dev/sda1"];
2073        ["lvcreate"; "LV1"; "VG"; "50"];
2074        ["lvcreate"; "LV2"; "VG"; "50"];
2075        ["lvremove"; "/dev/VG"];
2076        ["vgs"]], ["VG"])],
2077    "remove an LVM logical volume",
2078    "\
2079 Remove an LVM logical volume C<device>, where C<device> is
2080 the path to the LV, such as C</dev/VG/LV>.
2081
2082 You can also remove all LVs in a volume group by specifying
2083 the VG name, C</dev/VG>.");
2084
2085   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2086    [InitEmpty, Always, TestOutputList (
2087       [["part_disk"; "/dev/sda"; "mbr"];
2088        ["pvcreate"; "/dev/sda1"];
2089        ["vgcreate"; "VG"; "/dev/sda1"];
2090        ["lvcreate"; "LV1"; "VG"; "50"];
2091        ["lvcreate"; "LV2"; "VG"; "50"];
2092        ["vgremove"; "VG"];
2093        ["lvs"]], []);
2094     InitEmpty, Always, TestOutputList (
2095       [["part_disk"; "/dev/sda"; "mbr"];
2096        ["pvcreate"; "/dev/sda1"];
2097        ["vgcreate"; "VG"; "/dev/sda1"];
2098        ["lvcreate"; "LV1"; "VG"; "50"];
2099        ["lvcreate"; "LV2"; "VG"; "50"];
2100        ["vgremove"; "VG"];
2101        ["vgs"]], [])],
2102    "remove an LVM volume group",
2103    "\
2104 Remove an LVM volume group C<vgname>, (for example C<VG>).
2105
2106 This also forcibly removes all logical volumes in the volume
2107 group (if any).");
2108
2109   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2110    [InitEmpty, Always, TestOutputListOfDevices (
2111       [["part_disk"; "/dev/sda"; "mbr"];
2112        ["pvcreate"; "/dev/sda1"];
2113        ["vgcreate"; "VG"; "/dev/sda1"];
2114        ["lvcreate"; "LV1"; "VG"; "50"];
2115        ["lvcreate"; "LV2"; "VG"; "50"];
2116        ["vgremove"; "VG"];
2117        ["pvremove"; "/dev/sda1"];
2118        ["lvs"]], []);
2119     InitEmpty, Always, TestOutputListOfDevices (
2120       [["part_disk"; "/dev/sda"; "mbr"];
2121        ["pvcreate"; "/dev/sda1"];
2122        ["vgcreate"; "VG"; "/dev/sda1"];
2123        ["lvcreate"; "LV1"; "VG"; "50"];
2124        ["lvcreate"; "LV2"; "VG"; "50"];
2125        ["vgremove"; "VG"];
2126        ["pvremove"; "/dev/sda1"];
2127        ["vgs"]], []);
2128     InitEmpty, Always, TestOutputListOfDevices (
2129       [["part_disk"; "/dev/sda"; "mbr"];
2130        ["pvcreate"; "/dev/sda1"];
2131        ["vgcreate"; "VG"; "/dev/sda1"];
2132        ["lvcreate"; "LV1"; "VG"; "50"];
2133        ["lvcreate"; "LV2"; "VG"; "50"];
2134        ["vgremove"; "VG"];
2135        ["pvremove"; "/dev/sda1"];
2136        ["pvs"]], [])],
2137    "remove an LVM physical volume",
2138    "\
2139 This wipes a physical volume C<device> so that LVM will no longer
2140 recognise it.
2141
2142 The implementation uses the C<pvremove> command which refuses to
2143 wipe physical volumes that contain any volume groups, so you have
2144 to remove those first.");
2145
2146   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2147    [InitBasicFS, Always, TestOutput (
2148       [["set_e2label"; "/dev/sda1"; "testlabel"];
2149        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2150    "set the ext2/3/4 filesystem label",
2151    "\
2152 This sets the ext2/3/4 filesystem label of the filesystem on
2153 C<device> to C<label>.  Filesystem labels are limited to
2154 16 characters.
2155
2156 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2157 to return the existing label on a filesystem.");
2158
2159   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2160    [],
2161    "get the ext2/3/4 filesystem label",
2162    "\
2163 This returns the ext2/3/4 filesystem label of the filesystem on
2164 C<device>.");
2165
2166   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2167    (let uuid = uuidgen () in
2168     [InitBasicFS, Always, TestOutput (
2169        [["set_e2uuid"; "/dev/sda1"; uuid];
2170         ["get_e2uuid"; "/dev/sda1"]], uuid);
2171      InitBasicFS, Always, TestOutput (
2172        [["set_e2uuid"; "/dev/sda1"; "clear"];
2173         ["get_e2uuid"; "/dev/sda1"]], "");
2174      (* We can't predict what UUIDs will be, so just check the commands run. *)
2175      InitBasicFS, Always, TestRun (
2176        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2177      InitBasicFS, Always, TestRun (
2178        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2179    "set the ext2/3/4 filesystem UUID",
2180    "\
2181 This sets the ext2/3/4 filesystem UUID of the filesystem on
2182 C<device> to C<uuid>.  The format of the UUID and alternatives
2183 such as C<clear>, C<random> and C<time> are described in the
2184 L<tune2fs(8)> manpage.
2185
2186 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2187 to return the existing UUID of a filesystem.");
2188
2189   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2190    [],
2191    "get the ext2/3/4 filesystem UUID",
2192    "\
2193 This returns the ext2/3/4 filesystem UUID of the filesystem on
2194 C<device>.");
2195
2196   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [],
2197    [InitBasicFS, Always, TestOutputInt (
2198       [["umount"; "/dev/sda1"];
2199        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2200     InitBasicFS, Always, TestOutputInt (
2201       [["umount"; "/dev/sda1"];
2202        ["zero"; "/dev/sda1"];
2203        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2204    "run the filesystem checker",
2205    "\
2206 This runs the filesystem checker (fsck) on C<device> which
2207 should have filesystem type C<fstype>.
2208
2209 The returned integer is the status.  See L<fsck(8)> for the
2210 list of status codes from C<fsck>.
2211
2212 Notes:
2213
2214 =over 4
2215
2216 =item *
2217
2218 Multiple status codes can be summed together.
2219
2220 =item *
2221
2222 A non-zero return code can mean \"success\", for example if
2223 errors have been corrected on the filesystem.
2224
2225 =item *
2226
2227 Checking or repairing NTFS volumes is not supported
2228 (by linux-ntfs).
2229
2230 =back
2231
2232 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2233
2234   ("zero", (RErr, [Device "device"]), 85, [],
2235    [InitBasicFS, Always, TestOutput (
2236       [["umount"; "/dev/sda1"];
2237        ["zero"; "/dev/sda1"];
2238        ["file"; "/dev/sda1"]], "data")],
2239    "write zeroes to the device",
2240    "\
2241 This command writes zeroes over the first few blocks of C<device>.
2242
2243 How many blocks are zeroed isn't specified (but it's I<not> enough
2244 to securely wipe the device).  It should be sufficient to remove
2245 any partition tables, filesystem superblocks and so on.
2246
2247 See also: C<guestfs_scrub_device>.");
2248
2249   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2250    (* Test disabled because grub-install incompatible with virtio-blk driver.
2251     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2252     *)
2253    [InitBasicFS, Disabled, TestOutputTrue (
2254       [["grub_install"; "/"; "/dev/sda1"];
2255        ["is_dir"; "/boot"]])],
2256    "install GRUB",
2257    "\
2258 This command installs GRUB (the Grand Unified Bootloader) on
2259 C<device>, with the root directory being C<root>.");
2260
2261   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2262    [InitBasicFS, Always, TestOutput (
2263       [["write_file"; "/old"; "file content"; "0"];
2264        ["cp"; "/old"; "/new"];
2265        ["cat"; "/new"]], "file content");
2266     InitBasicFS, Always, TestOutputTrue (
2267       [["write_file"; "/old"; "file content"; "0"];
2268        ["cp"; "/old"; "/new"];
2269        ["is_file"; "/old"]]);
2270     InitBasicFS, Always, TestOutput (
2271       [["write_file"; "/old"; "file content"; "0"];
2272        ["mkdir"; "/dir"];
2273        ["cp"; "/old"; "/dir/new"];
2274        ["cat"; "/dir/new"]], "file content")],
2275    "copy a file",
2276    "\
2277 This copies a file from C<src> to C<dest> where C<dest> is
2278 either a destination filename or destination directory.");
2279
2280   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2281    [InitBasicFS, Always, TestOutput (
2282       [["mkdir"; "/olddir"];
2283        ["mkdir"; "/newdir"];
2284        ["write_file"; "/olddir/file"; "file content"; "0"];
2285        ["cp_a"; "/olddir"; "/newdir"];
2286        ["cat"; "/newdir/olddir/file"]], "file content")],
2287    "copy a file or directory recursively",
2288    "\
2289 This copies a file or directory from C<src> to C<dest>
2290 recursively using the C<cp -a> command.");
2291
2292   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2293    [InitBasicFS, Always, TestOutput (
2294       [["write_file"; "/old"; "file content"; "0"];
2295        ["mv"; "/old"; "/new"];
2296        ["cat"; "/new"]], "file content");
2297     InitBasicFS, Always, TestOutputFalse (
2298       [["write_file"; "/old"; "file content"; "0"];
2299        ["mv"; "/old"; "/new"];
2300        ["is_file"; "/old"]])],
2301    "move a file",
2302    "\
2303 This moves a file from C<src> to C<dest> where C<dest> is
2304 either a destination filename or destination directory.");
2305
2306   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2307    [InitEmpty, Always, TestRun (
2308       [["drop_caches"; "3"]])],
2309    "drop kernel page cache, dentries and inodes",
2310    "\
2311 This instructs the guest kernel to drop its page cache,
2312 and/or dentries and inode caches.  The parameter C<whattodrop>
2313 tells the kernel what precisely to drop, see
2314 L<http://linux-mm.org/Drop_Caches>
2315
2316 Setting C<whattodrop> to 3 should drop everything.
2317
2318 This automatically calls L<sync(2)> before the operation,
2319 so that the maximum guest memory is freed.");
2320
2321   ("dmesg", (RString "kmsgs", []), 91, [],
2322    [InitEmpty, Always, TestRun (
2323       [["dmesg"]])],
2324    "return kernel messages",
2325    "\
2326 This returns the kernel messages (C<dmesg> output) from
2327 the guest kernel.  This is sometimes useful for extended
2328 debugging of problems.
2329
2330 Another way to get the same information is to enable
2331 verbose messages with C<guestfs_set_verbose> or by setting
2332 the environment variable C<LIBGUESTFS_DEBUG=1> before
2333 running the program.");
2334
2335   ("ping_daemon", (RErr, []), 92, [],
2336    [InitEmpty, Always, TestRun (
2337       [["ping_daemon"]])],
2338    "ping the guest daemon",
2339    "\
2340 This is a test probe into the guestfs daemon running inside
2341 the qemu subprocess.  Calling this function checks that the
2342 daemon responds to the ping message, without affecting the daemon
2343 or attached block device(s) in any other way.");
2344
2345   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2346    [InitBasicFS, Always, TestOutputTrue (
2347       [["write_file"; "/file1"; "contents of a file"; "0"];
2348        ["cp"; "/file1"; "/file2"];
2349        ["equal"; "/file1"; "/file2"]]);
2350     InitBasicFS, Always, TestOutputFalse (
2351       [["write_file"; "/file1"; "contents of a file"; "0"];
2352        ["write_file"; "/file2"; "contents of another file"; "0"];
2353        ["equal"; "/file1"; "/file2"]]);
2354     InitBasicFS, Always, TestLastFail (
2355       [["equal"; "/file1"; "/file2"]])],
2356    "test if two files have equal contents",
2357    "\
2358 This compares the two files C<file1> and C<file2> and returns
2359 true if their content is exactly equal, or false otherwise.
2360
2361 The external L<cmp(1)> program is used for the comparison.");
2362
2363   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2364    [InitISOFS, Always, TestOutputList (
2365       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2366     InitISOFS, Always, TestOutputList (
2367       [["strings"; "/empty"]], [])],
2368    "print the printable strings in a file",
2369    "\
2370 This runs the L<strings(1)> command on a file and returns
2371 the list of printable strings found.");
2372
2373   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2374    [InitISOFS, Always, TestOutputList (
2375       [["strings_e"; "b"; "/known-5"]], []);
2376     InitBasicFS, Disabled, TestOutputList (
2377       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2378        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2379    "print the printable strings in a file",
2380    "\
2381 This is like the C<guestfs_strings> command, but allows you to
2382 specify the encoding.
2383
2384 See the L<strings(1)> manpage for the full list of encodings.
2385
2386 Commonly useful encodings are C<l> (lower case L) which will
2387 show strings inside Windows/x86 files.
2388
2389 The returned strings are transcoded to UTF-8.");
2390
2391   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2392    [InitISOFS, Always, TestOutput (
2393       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2394     (* Test for RHBZ#501888c2 regression which caused large hexdump
2395      * commands to segfault.
2396      *)
2397     InitISOFS, Always, TestRun (
2398       [["hexdump"; "/100krandom"]])],
2399    "dump a file in hexadecimal",
2400    "\
2401 This runs C<hexdump -C> on the given C<path>.  The result is
2402 the human-readable, canonical hex dump of the file.");
2403
2404   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2405    [InitNone, Always, TestOutput (
2406       [["part_disk"; "/dev/sda"; "mbr"];
2407        ["mkfs"; "ext3"; "/dev/sda1"];
2408        ["mount"; "/dev/sda1"; "/"];
2409        ["write_file"; "/new"; "test file"; "0"];
2410        ["umount"; "/dev/sda1"];
2411        ["zerofree"; "/dev/sda1"];
2412        ["mount"; "/dev/sda1"; "/"];
2413        ["cat"; "/new"]], "test file")],
2414    "zero unused inodes and disk blocks on ext2/3 filesystem",
2415    "\
2416 This runs the I<zerofree> program on C<device>.  This program
2417 claims to zero unused inodes and disk blocks on an ext2/3
2418 filesystem, thus making it possible to compress the filesystem
2419 more effectively.
2420
2421 You should B<not> run this program if the filesystem is
2422 mounted.
2423
2424 It is possible that using this program can damage the filesystem
2425 or data on the filesystem.");
2426
2427   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2428    [],
2429    "resize an LVM physical volume",
2430    "\
2431 This resizes (expands or shrinks) an existing LVM physical
2432 volume to match the new size of the underlying device.");
2433
2434   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2435                        Int "cyls"; Int "heads"; Int "sectors";
2436                        String "line"]), 99, [DangerWillRobinson],
2437    [],
2438    "modify a single partition on a block device",
2439    "\
2440 This runs L<sfdisk(8)> option to modify just the single
2441 partition C<n> (note: C<n> counts from 1).
2442
2443 For other parameters, see C<guestfs_sfdisk>.  You should usually
2444 pass C<0> for the cyls/heads/sectors parameters.
2445
2446 See also: C<guestfs_part_add>");
2447
2448   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2449    [],
2450    "display the partition table",
2451    "\
2452 This displays the partition table on C<device>, in the
2453 human-readable output of the L<sfdisk(8)> command.  It is
2454 not intended to be parsed.
2455
2456 See also: C<guestfs_part_list>");
2457
2458   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2459    [],
2460    "display the kernel geometry",
2461    "\
2462 This displays the kernel's idea of the geometry of C<device>.
2463
2464 The result is in human-readable format, and not designed to
2465 be parsed.");
2466
2467   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2468    [],
2469    "display the disk geometry from the partition table",
2470    "\
2471 This displays the disk geometry of C<device> read from the
2472 partition table.  Especially in the case where the underlying
2473 block device has been resized, this can be different from the
2474 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2475
2476 The result is in human-readable format, and not designed to
2477 be parsed.");
2478
2479   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2480    [],
2481    "activate or deactivate all volume groups",
2482    "\
2483 This command activates or (if C<activate> is false) deactivates
2484 all logical volumes in all volume groups.
2485 If activated, then they are made known to the
2486 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2487 then those devices disappear.
2488
2489 This command is the same as running C<vgchange -a y|n>");
2490
2491   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2492    [],
2493    "activate or deactivate some volume groups",
2494    "\
2495 This command activates or (if C<activate> is false) deactivates
2496 all logical volumes in the listed volume groups C<volgroups>.
2497 If activated, then they are made known to the
2498 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2499 then those devices disappear.
2500
2501 This command is the same as running C<vgchange -a y|n volgroups...>
2502
2503 Note that if C<volgroups> is an empty list then B<all> volume groups
2504 are activated or deactivated.");
2505
2506   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2507    [InitNone, Always, TestOutput (
2508       [["part_disk"; "/dev/sda"; "mbr"];
2509        ["pvcreate"; "/dev/sda1"];
2510        ["vgcreate"; "VG"; "/dev/sda1"];
2511        ["lvcreate"; "LV"; "VG"; "10"];
2512        ["mkfs"; "ext2"; "/dev/VG/LV"];
2513        ["mount"; "/dev/VG/LV"; "/"];
2514        ["write_file"; "/new"; "test content"; "0"];
2515        ["umount"; "/"];
2516        ["lvresize"; "/dev/VG/LV"; "20"];
2517        ["e2fsck_f"; "/dev/VG/LV"];
2518        ["resize2fs"; "/dev/VG/LV"];
2519        ["mount"; "/dev/VG/LV"; "/"];
2520        ["cat"; "/new"]], "test content")],
2521    "resize an LVM logical volume",
2522    "\
2523 This resizes (expands or shrinks) an existing LVM logical
2524 volume to C<mbytes>.  When reducing, data in the reduced part
2525 is lost.");
2526
2527   ("resize2fs", (RErr, [Device "device"]), 106, [],
2528    [], (* lvresize tests this *)
2529    "resize an ext2/ext3 filesystem",
2530    "\
2531 This resizes an ext2 or ext3 filesystem to match the size of
2532 the underlying device.
2533
2534 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2535 on the C<device> before calling this command.  For unknown reasons
2536 C<resize2fs> sometimes gives an error about this and sometimes not.
2537 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2538 calling this function.");
2539
2540   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2541    [InitBasicFS, Always, TestOutputList (
2542       [["find"; "/"]], ["lost+found"]);
2543     InitBasicFS, Always, TestOutputList (
2544       [["touch"; "/a"];
2545        ["mkdir"; "/b"];
2546        ["touch"; "/b/c"];
2547        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2548     InitBasicFS, Always, TestOutputList (
2549       [["mkdir_p"; "/a/b/c"];
2550        ["touch"; "/a/b/c/d"];
2551        ["find"; "/a/b/"]], ["c"; "c/d"])],
2552    "find all files and directories",
2553    "\
2554 This command lists out all files and directories, recursively,
2555 starting at C<directory>.  It is essentially equivalent to
2556 running the shell command C<find directory -print> but some
2557 post-processing happens on the output, described below.
2558
2559 This returns a list of strings I<without any prefix>.  Thus
2560 if the directory structure was:
2561
2562  /tmp/a
2563  /tmp/b
2564  /tmp/c/d
2565
2566 then the returned list from C<guestfs_find> C</tmp> would be
2567 4 elements:
2568
2569  a
2570  b
2571  c
2572  c/d
2573
2574 If C<directory> is not a directory, then this command returns
2575 an error.
2576
2577 The returned list is sorted.
2578
2579 See also C<guestfs_find0>.");
2580
2581   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2582    [], (* lvresize tests this *)
2583    "check an ext2/ext3 filesystem",
2584    "\
2585 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2586 filesystem checker on C<device>, noninteractively (C<-p>),
2587 even if the filesystem appears to be clean (C<-f>).
2588
2589 This command is only needed because of C<guestfs_resize2fs>
2590 (q.v.).  Normally you should use C<guestfs_fsck>.");
2591
2592   ("sleep", (RErr, [Int "secs"]), 109, [],
2593    [InitNone, Always, TestRun (
2594       [["sleep"; "1"]])],
2595    "sleep for some seconds",
2596    "\
2597 Sleep for C<secs> seconds.");
2598
2599   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2600    [InitNone, Always, TestOutputInt (
2601       [["part_disk"; "/dev/sda"; "mbr"];
2602        ["mkfs"; "ntfs"; "/dev/sda1"];
2603        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2604     InitNone, Always, TestOutputInt (
2605       [["part_disk"; "/dev/sda"; "mbr"];
2606        ["mkfs"; "ext2"; "/dev/sda1"];
2607        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2608    "probe NTFS volume",
2609    "\
2610 This command runs the L<ntfs-3g.probe(8)> command which probes
2611 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2612 be mounted read-write, and some cannot be mounted at all).
2613
2614 C<rw> is a boolean flag.  Set it to true if you want to test
2615 if the volume can be mounted read-write.  Set it to false if
2616 you want to test if the volume can be mounted read-only.
2617
2618 The return value is an integer which C<0> if the operation
2619 would succeed, or some non-zero value documented in the
2620 L<ntfs-3g.probe(8)> manual page.");
2621
2622   ("sh", (RString "output", [String "command"]), 111, [],
2623    [], (* XXX needs tests *)
2624    "run a command via the shell",
2625    "\
2626 This call runs a command from the guest filesystem via the
2627 guest's C</bin/sh>.
2628
2629 This is like C<guestfs_command>, but passes the command to:
2630
2631  /bin/sh -c \"command\"
2632
2633 Depending on the guest's shell, this usually results in
2634 wildcards being expanded, shell expressions being interpolated
2635 and so on.
2636
2637 All the provisos about C<guestfs_command> apply to this call.");
2638
2639   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2640    [], (* XXX needs tests *)
2641    "run a command via the shell returning lines",
2642    "\
2643 This is the same as C<guestfs_sh>, but splits the result
2644 into a list of lines.
2645
2646 See also: C<guestfs_command_lines>");
2647
2648   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2649    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2650     * code in stubs.c, since all valid glob patterns must start with "/".
2651     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2652     *)
2653    [InitBasicFS, Always, TestOutputList (
2654       [["mkdir_p"; "/a/b/c"];
2655        ["touch"; "/a/b/c/d"];
2656        ["touch"; "/a/b/c/e"];
2657        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2658     InitBasicFS, Always, TestOutputList (
2659       [["mkdir_p"; "/a/b/c"];
2660        ["touch"; "/a/b/c/d"];
2661        ["touch"; "/a/b/c/e"];
2662        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2663     InitBasicFS, Always, TestOutputList (
2664       [["mkdir_p"; "/a/b/c"];
2665        ["touch"; "/a/b/c/d"];
2666        ["touch"; "/a/b/c/e"];
2667        ["glob_expand"; "/a/*/x/*"]], [])],
2668    "expand a wildcard path",
2669    "\
2670 This command searches for all the pathnames matching
2671 C<pattern> according to the wildcard expansion rules
2672 used by the shell.
2673
2674 If no paths match, then this returns an empty list
2675 (note: not an error).
2676
2677 It is just a wrapper around the C L<glob(3)> function
2678 with flags C<GLOB_MARK|GLOB_BRACE>.
2679 See that manual page for more details.");
2680
2681   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2682    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2683       [["scrub_device"; "/dev/sdc"]])],
2684    "scrub (securely wipe) a device",
2685    "\
2686 This command writes patterns over C<device> to make data retrieval
2687 more difficult.
2688
2689 It is an interface to the L<scrub(1)> program.  See that
2690 manual page for more details.");
2691
2692   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2693    [InitBasicFS, Always, TestRun (
2694       [["write_file"; "/file"; "content"; "0"];
2695        ["scrub_file"; "/file"]])],
2696    "scrub (securely wipe) a file",
2697    "\
2698 This command writes patterns over a file to make data retrieval
2699 more difficult.
2700
2701 The file is I<removed> after scrubbing.
2702
2703 It is an interface to the L<scrub(1)> program.  See that
2704 manual page for more details.");
2705
2706   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2707    [], (* XXX needs testing *)
2708    "scrub (securely wipe) free space",
2709    "\
2710 This command creates the directory C<dir> and then fills it
2711 with files until the filesystem is full, and scrubs the files
2712 as for C<guestfs_scrub_file>, and deletes them.
2713 The intention is to scrub any free space on the partition
2714 containing C<dir>.
2715
2716 It is an interface to the L<scrub(1)> program.  See that
2717 manual page for more details.");
2718
2719   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2720    [InitBasicFS, Always, TestRun (
2721       [["mkdir"; "/tmp"];
2722        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2723    "create a temporary directory",
2724    "\
2725 This command creates a temporary directory.  The
2726 C<template> parameter should be a full pathname for the
2727 temporary directory name with the final six characters being
2728 \"XXXXXX\".
2729
2730 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2731 the second one being suitable for Windows filesystems.
2732
2733 The name of the temporary directory that was created
2734 is returned.
2735
2736 The temporary directory is created with mode 0700
2737 and is owned by root.
2738
2739 The caller is responsible for deleting the temporary
2740 directory and its contents after use.
2741
2742 See also: L<mkdtemp(3)>");
2743
2744   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2745    [InitISOFS, Always, TestOutputInt (
2746       [["wc_l"; "/10klines"]], 10000)],
2747    "count lines in a file",
2748    "\
2749 This command counts the lines in a file, using the
2750 C<wc -l> external command.");
2751
2752   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2753    [InitISOFS, Always, TestOutputInt (
2754       [["wc_w"; "/10klines"]], 10000)],
2755    "count words in a file",
2756    "\
2757 This command counts the words in a file, using the
2758 C<wc -w> external command.");
2759
2760   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2761    [InitISOFS, Always, TestOutputInt (
2762       [["wc_c"; "/100kallspaces"]], 102400)],
2763    "count characters in a file",
2764    "\
2765 This command counts the characters in a file, using the
2766 C<wc -c> external command.");
2767
2768   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2769    [InitISOFS, Always, TestOutputList (
2770       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2771    "return first 10 lines of a file",
2772    "\
2773 This command returns up to the first 10 lines of a file as
2774 a list of strings.");
2775
2776   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2777    [InitISOFS, Always, TestOutputList (
2778       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2779     InitISOFS, Always, TestOutputList (
2780       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2781     InitISOFS, Always, TestOutputList (
2782       [["head_n"; "0"; "/10klines"]], [])],
2783    "return first N lines of a file",
2784    "\
2785 If the parameter C<nrlines> is a positive number, this returns the first
2786 C<nrlines> lines of the file C<path>.
2787
2788 If the parameter C<nrlines> is a negative number, this returns lines
2789 from the file C<path>, excluding the last C<nrlines> lines.
2790
2791 If the parameter C<nrlines> is zero, this returns an empty list.");
2792
2793   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2794    [InitISOFS, Always, TestOutputList (
2795       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2796    "return last 10 lines of a file",
2797    "\
2798 This command returns up to the last 10 lines of a file as
2799 a list of strings.");
2800
2801   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2802    [InitISOFS, Always, TestOutputList (
2803       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2804     InitISOFS, Always, TestOutputList (
2805       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2806     InitISOFS, Always, TestOutputList (
2807       [["tail_n"; "0"; "/10klines"]], [])],
2808    "return last N lines of a file",
2809    "\
2810 If the parameter C<nrlines> is a positive number, this returns the last
2811 C<nrlines> lines of the file C<path>.
2812
2813 If the parameter C<nrlines> is a negative number, this returns lines
2814 from the file C<path>, starting with the C<-nrlines>th line.
2815
2816 If the parameter C<nrlines> is zero, this returns an empty list.");
2817
2818   ("df", (RString "output", []), 125, [],
2819    [], (* XXX Tricky to test because it depends on the exact format
2820         * of the 'df' command and other imponderables.
2821         *)
2822    "report file system disk space usage",
2823    "\
2824 This command runs the C<df> command to report disk space used.
2825
2826 This command is mostly useful for interactive sessions.  It
2827 is I<not> intended that you try to parse the output string.
2828 Use C<statvfs> from programs.");
2829
2830   ("df_h", (RString "output", []), 126, [],
2831    [], (* XXX Tricky to test because it depends on the exact format
2832         * of the 'df' command and other imponderables.
2833         *)
2834    "report file system disk space usage (human readable)",
2835    "\
2836 This command runs the C<df -h> command to report disk space used
2837 in human-readable format.
2838
2839 This command is mostly useful for interactive sessions.  It
2840 is I<not> intended that you try to parse the output string.
2841 Use C<statvfs> from programs.");
2842
2843   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2844    [InitISOFS, Always, TestOutputInt (
2845       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2846    "estimate file space usage",
2847    "\
2848 This command runs the C<du -s> command to estimate file space
2849 usage for C<path>.
2850
2851 C<path> can be a file or a directory.  If C<path> is a directory
2852 then the estimate includes the contents of the directory and all
2853 subdirectories (recursively).
2854
2855 The result is the estimated size in I<kilobytes>
2856 (ie. units of 1024 bytes).");
2857
2858   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2859    [InitISOFS, Always, TestOutputList (
2860       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2861    "list files in an initrd",
2862    "\
2863 This command lists out files contained in an initrd.
2864
2865 The files are listed without any initial C</> character.  The
2866 files are listed in the order they appear (not necessarily
2867 alphabetical).  Directory names are listed as separate items.
2868
2869 Old Linux kernels (2.4 and earlier) used a compressed ext2
2870 filesystem as initrd.  We I<only> support the newer initramfs
2871 format (compressed cpio files).");
2872
2873   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2874    [],
2875    "mount a file using the loop device",
2876    "\
2877 This command lets you mount C<file> (a filesystem image
2878 in a file) on a mount point.  It is entirely equivalent to
2879 the command C<mount -o loop file mountpoint>.");
2880
2881   ("mkswap", (RErr, [Device "device"]), 130, [],
2882    [InitEmpty, Always, TestRun (
2883       [["part_disk"; "/dev/sda"; "mbr"];
2884        ["mkswap"; "/dev/sda1"]])],
2885    "create a swap partition",
2886    "\
2887 Create a swap partition on C<device>.");
2888
2889   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2890    [InitEmpty, Always, TestRun (
2891       [["part_disk"; "/dev/sda"; "mbr"];
2892        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2893    "create a swap partition with a label",
2894    "\
2895 Create a swap partition on C<device> with label C<label>.
2896
2897 Note that you cannot attach a swap label to a block device
2898 (eg. C</dev/sda>), just to a partition.  This appears to be
2899 a limitation of the kernel or swap tools.");
2900
2901   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
2902    (let uuid = uuidgen () in
2903     [InitEmpty, Always, TestRun (
2904        [["part_disk"; "/dev/sda"; "mbr"];
2905         ["mkswap_U"; uuid; "/dev/sda1"]])]),
2906    "create a swap partition with an explicit UUID",
2907    "\
2908 Create a swap partition on C<device> with UUID C<uuid>.");
2909
2910   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
2911    [InitBasicFS, Always, TestOutputStruct (
2912       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2913        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2914        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2915     InitBasicFS, Always, TestOutputStruct (
2916       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2917        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2918    "make block, character or FIFO devices",
2919    "\
2920 This call creates block or character special devices, or
2921 named pipes (FIFOs).
2922
2923 The C<mode> parameter should be the mode, using the standard
2924 constants.  C<devmajor> and C<devminor> are the
2925 device major and minor numbers, only used when creating block
2926 and character special devices.");
2927
2928   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
2929    [InitBasicFS, Always, TestOutputStruct (
2930       [["mkfifo"; "0o777"; "/node"];
2931        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2932    "make FIFO (named pipe)",
2933    "\
2934 This call creates a FIFO (named pipe) called C<path> with
2935 mode C<mode>.  It is just a convenient wrapper around
2936 C<guestfs_mknod>.");
2937
2938   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
2939    [InitBasicFS, Always, TestOutputStruct (
2940       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2941        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2942    "make block device node",
2943    "\
2944 This call creates a block device node called C<path> with
2945 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2946 It is just a convenient wrapper around C<guestfs_mknod>.");
2947
2948   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
2949    [InitBasicFS, Always, TestOutputStruct (
2950       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2951        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2952    "make char device node",
2953    "\
2954 This call creates a char device node called C<path> with
2955 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2956 It is just a convenient wrapper around C<guestfs_mknod>.");
2957
2958   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2959    [], (* XXX umask is one of those stateful things that we should
2960         * reset between each test.
2961         *)
2962    "set file mode creation mask (umask)",
2963    "\
2964 This function sets the mask used for creating new files and
2965 device nodes to C<mask & 0777>.
2966
2967 Typical umask values would be C<022> which creates new files
2968 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2969 C<002> which creates new files with permissions like
2970 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2971
2972 The default umask is C<022>.  This is important because it
2973 means that directories and device nodes will be created with
2974 C<0644> or C<0755> mode even if you specify C<0777>.
2975
2976 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2977
2978 This call returns the previous umask.");
2979
2980   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
2981    [],
2982    "read directories entries",
2983    "\
2984 This returns the list of directory entries in directory C<dir>.
2985
2986 All entries in the directory are returned, including C<.> and
2987 C<..>.  The entries are I<not> sorted, but returned in the same
2988 order as the underlying filesystem.
2989
2990 Also this call returns basic file type information about each
2991 file.  The C<ftyp> field will contain one of the following characters:
2992
2993 =over 4
2994
2995 =item 'b'
2996
2997 Block special
2998
2999 =item 'c'
3000
3001 Char special
3002
3003 =item 'd'
3004
3005 Directory
3006
3007 =item 'f'
3008
3009 FIFO (named pipe)
3010
3011 =item 'l'
3012
3013 Symbolic link
3014
3015 =item 'r'
3016
3017 Regular file
3018
3019 =item 's'
3020
3021 Socket
3022
3023 =item 'u'
3024
3025 Unknown file type
3026
3027 =item '?'
3028
3029 The L<readdir(3)> returned a C<d_type> field with an
3030 unexpected value
3031
3032 =back
3033
3034 This function is primarily intended for use by programs.  To
3035 get a simple list of names, use C<guestfs_ls>.  To get a printable
3036 directory for human consumption, use C<guestfs_ll>.");
3037
3038   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3039    [],
3040    "create partitions on a block device",
3041    "\
3042 This is a simplified interface to the C<guestfs_sfdisk>
3043 command, where partition sizes are specified in megabytes
3044 only (rounded to the nearest cylinder) and you don't need
3045 to specify the cyls, heads and sectors parameters which
3046 were rarely if ever used anyway.
3047
3048 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3049 and C<guestfs_part_disk>");
3050
3051   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3052    [],
3053    "determine file type inside a compressed file",
3054    "\
3055 This command runs C<file> after first decompressing C<path>
3056 using C<method>.
3057
3058 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3059
3060 Since 1.0.63, use C<guestfs_file> instead which can now
3061 process compressed files.");
3062
3063   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3064    [],
3065    "list extended attributes of a file or directory",
3066    "\
3067 This call lists the extended attributes of the file or directory
3068 C<path>.
3069
3070 At the system call level, this is a combination of the
3071 L<listxattr(2)> and L<getxattr(2)> calls.
3072
3073 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3074
3075   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3076    [],
3077    "list extended attributes of a file or directory",
3078    "\
3079 This is the same as C<guestfs_getxattrs>, but if C<path>
3080 is a symbolic link, then it returns the extended attributes
3081 of the link itself.");
3082
3083   ("setxattr", (RErr, [String "xattr";
3084                        String "val"; Int "vallen"; (* will be BufferIn *)
3085                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3086    [],
3087    "set extended attribute of a file or directory",
3088    "\
3089 This call sets the extended attribute named C<xattr>
3090 of the file C<path> to the value C<val> (of length C<vallen>).
3091 The value is arbitrary 8 bit data.
3092
3093 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3094
3095   ("lsetxattr", (RErr, [String "xattr";
3096                         String "val"; Int "vallen"; (* will be BufferIn *)
3097                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3098    [],
3099    "set extended attribute of a file or directory",
3100    "\
3101 This is the same as C<guestfs_setxattr>, but if C<path>
3102 is a symbolic link, then it sets an extended attribute
3103 of the link itself.");
3104
3105   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3106    [],
3107    "remove extended attribute of a file or directory",
3108    "\
3109 This call removes the extended attribute named C<xattr>
3110 of the file C<path>.
3111
3112 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3113
3114   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3115    [],
3116    "remove extended attribute of a file or directory",
3117    "\
3118 This is the same as C<guestfs_removexattr>, but if C<path>
3119 is a symbolic link, then it removes an extended attribute
3120 of the link itself.");
3121
3122   ("mountpoints", (RHashtable "mps", []), 147, [],
3123    [],
3124    "show mountpoints",
3125    "\
3126 This call is similar to C<guestfs_mounts>.  That call returns
3127 a list of devices.  This one returns a hash table (map) of
3128 device name to directory where the device is mounted.");
3129
3130   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3131    (* This is a special case: while you would expect a parameter
3132     * of type "Pathname", that doesn't work, because it implies
3133     * NEED_ROOT in the generated calling code in stubs.c, and
3134     * this function cannot use NEED_ROOT.
3135     *)
3136    [],
3137    "create a mountpoint",
3138    "\
3139 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3140 specialized calls that can be used to create extra mountpoints
3141 before mounting the first filesystem.
3142
3143 These calls are I<only> necessary in some very limited circumstances,
3144 mainly the case where you want to mount a mix of unrelated and/or
3145 read-only filesystems together.
3146
3147 For example, live CDs often contain a \"Russian doll\" nest of
3148 filesystems, an ISO outer layer, with a squashfs image inside, with
3149 an ext2/3 image inside that.  You can unpack this as follows
3150 in guestfish:
3151
3152  add-ro Fedora-11-i686-Live.iso
3153  run
3154  mkmountpoint /cd
3155  mkmountpoint /squash
3156  mkmountpoint /ext3
3157  mount /dev/sda /cd
3158  mount-loop /cd/LiveOS/squashfs.img /squash
3159  mount-loop /squash/LiveOS/ext3fs.img /ext3
3160
3161 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3162
3163   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3164    [],
3165    "remove a mountpoint",
3166    "\
3167 This calls removes a mountpoint that was previously created
3168 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3169 for full details.");
3170
3171   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3172    [InitISOFS, Always, TestOutputBuffer (
3173       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3174    "read a file",
3175    "\
3176 This calls returns the contents of the file C<path> as a
3177 buffer.
3178
3179 Unlike C<guestfs_cat>, this function can correctly
3180 handle files that contain embedded ASCII NUL characters.
3181 However unlike C<guestfs_download>, this function is limited
3182 in the total size of file that can be handled.");
3183
3184   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3185    [InitISOFS, Always, TestOutputList (
3186       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3187     InitISOFS, Always, TestOutputList (
3188       [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3189    "return lines matching a pattern",
3190    "\
3191 This calls the external C<grep> program and returns the
3192 matching lines.");
3193
3194   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3195    [InitISOFS, Always, TestOutputList (
3196       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3197    "return lines matching a pattern",
3198    "\
3199 This calls the external C<egrep> program and returns the
3200 matching lines.");
3201
3202   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3203    [InitISOFS, Always, TestOutputList (
3204       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3205    "return lines matching a pattern",
3206    "\
3207 This calls the external C<fgrep> program and returns the
3208 matching lines.");
3209
3210   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3211    [InitISOFS, Always, TestOutputList (
3212       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3213    "return lines matching a pattern",
3214    "\
3215 This calls the external C<grep -i> program and returns the
3216 matching lines.");
3217
3218   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3219    [InitISOFS, Always, TestOutputList (
3220       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3221    "return lines matching a pattern",
3222    "\
3223 This calls the external C<egrep -i> program and returns the
3224 matching lines.");
3225
3226   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3227    [InitISOFS, Always, TestOutputList (
3228       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3229    "return lines matching a pattern",
3230    "\
3231 This calls the external C<fgrep -i> program and returns the
3232 matching lines.");
3233
3234   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3235    [InitISOFS, Always, TestOutputList (
3236       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3237    "return lines matching a pattern",
3238    "\
3239 This calls the external C<zgrep> program and returns the
3240 matching lines.");
3241
3242   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3243    [InitISOFS, Always, TestOutputList (
3244       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3245    "return lines matching a pattern",
3246    "\
3247 This calls the external C<zegrep> program and returns the
3248 matching lines.");
3249
3250   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3251    [InitISOFS, Always, TestOutputList (
3252       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3253    "return lines matching a pattern",
3254    "\
3255 This calls the external C<zfgrep> program and returns the
3256 matching lines.");
3257
3258   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3259    [InitISOFS, Always, TestOutputList (
3260       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3261    "return lines matching a pattern",
3262    "\
3263 This calls the external C<zgrep -i> program and returns the
3264 matching lines.");
3265
3266   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3267    [InitISOFS, Always, TestOutputList (
3268       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3269    "return lines matching a pattern",
3270    "\
3271 This calls the external C<zegrep -i> program and returns the
3272 matching lines.");
3273
3274   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3275    [InitISOFS, Always, TestOutputList (
3276       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3277    "return lines matching a pattern",
3278    "\
3279 This calls the external C<zfgrep -i> program and returns the
3280 matching lines.");
3281
3282   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3283    [InitISOFS, Always, TestOutput (
3284       [["realpath"; "/../directory"]], "/directory")],
3285    "canonicalized absolute pathname",
3286    "\
3287 Return the canonicalized absolute pathname of C<path>.  The
3288 returned path has no C<.>, C<..> or symbolic link path elements.");
3289
3290   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3291    [InitBasicFS, Always, TestOutputStruct (
3292       [["touch"; "/a"];
3293        ["ln"; "/a"; "/b"];
3294        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3295    "create a hard link",
3296    "\
3297 This command creates a hard link using the C<ln> command.");
3298
3299   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3300    [InitBasicFS, Always, TestOutputStruct (
3301       [["touch"; "/a"];
3302        ["touch"; "/b"];
3303        ["ln_f"; "/a"; "/b"];
3304        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3305    "create a hard link",
3306    "\
3307 This command creates a hard link using the C<ln -f> command.
3308 The C<-f> option removes the link (C<linkname>) if it exists already.");
3309
3310   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3311    [InitBasicFS, Always, TestOutputStruct (
3312       [["touch"; "/a"];
3313        ["ln_s"; "a"; "/b"];
3314        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3315    "create a symbolic link",
3316    "\
3317 This command creates a symbolic link using the C<ln -s> command.");
3318
3319   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3320    [InitBasicFS, Always, TestOutput (
3321       [["mkdir_p"; "/a/b"];
3322        ["touch"; "/a/b/c"];
3323        ["ln_sf"; "../d"; "/a/b/c"];
3324        ["readlink"; "/a/b/c"]], "../d")],
3325    "create a symbolic link",
3326    "\
3327 This command creates a symbolic link using the C<ln -sf> command,
3328 The C<-f> option removes the link (C<linkname>) if it exists already.");
3329
3330   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3331    [] (* XXX tested above *),
3332    "read the target of a symbolic link",
3333    "\
3334 This command reads the target of a symbolic link.");
3335
3336   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3337    [InitBasicFS, Always, TestOutputStruct (
3338       [["fallocate"; "/a"; "1000000"];
3339        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3340    "preallocate a file in the guest filesystem",
3341    "\
3342 This command preallocates a file (containing zero bytes) named
3343 C<path> of size C<len> bytes.  If the file exists already, it
3344 is overwritten.
3345
3346 Do not confuse this with the guestfish-specific
3347 C<alloc> command which allocates a file in the host and
3348 attaches it as a device.");
3349
3350   ("swapon_device", (RErr, [Device "device"]), 170, [],
3351    [InitPartition, Always, TestRun (
3352       [["mkswap"; "/dev/sda1"];
3353        ["swapon_device"; "/dev/sda1"];
3354        ["swapoff_device"; "/dev/sda1"]])],
3355    "enable swap on device",
3356    "\
3357 This command enables the libguestfs appliance to use the
3358 swap device or partition named C<device>.  The increased
3359 memory is made available for all commands, for example
3360 those run using C<guestfs_command> or C<guestfs_sh>.
3361
3362 Note that you should not swap to existing guest swap
3363 partitions unless you know what you are doing.  They may
3364 contain hibernation information, or other information that
3365 the guest doesn't want you to trash.  You also risk leaking
3366 information about the host to the guest this way.  Instead,
3367 attach a new host device to the guest and swap on that.");
3368
3369   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3370    [], (* XXX tested by swapon_device *)
3371    "disable swap on device",
3372    "\
3373 This command disables the libguestfs appliance swap
3374 device or partition named C<device>.
3375 See C<guestfs_swapon_device>.");
3376
3377   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3378    [InitBasicFS, Always, TestRun (
3379       [["fallocate"; "/swap"; "8388608"];
3380        ["mkswap_file"; "/swap"];
3381        ["swapon_file"; "/swap"];
3382        ["swapoff_file"; "/swap"]])],
3383    "enable swap on file",
3384    "\
3385 This command enables swap to a file.
3386 See C<guestfs_swapon_device> for other notes.");
3387
3388   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3389    [], (* XXX tested by swapon_file *)
3390    "disable swap on file",
3391    "\
3392 This command disables the libguestfs appliance swap on file.");
3393
3394   ("swapon_label", (RErr, [String "label"]), 174, [],
3395    [InitEmpty, Always, TestRun (
3396       [["part_disk"; "/dev/sdb"; "mbr"];
3397        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3398        ["swapon_label"; "swapit"];
3399        ["swapoff_label"; "swapit"];
3400        ["zero"; "/dev/sdb"];
3401        ["blockdev_rereadpt"; "/dev/sdb"]])],
3402    "enable swap on labeled swap partition",
3403    "\
3404 This command enables swap to a labeled swap partition.
3405 See C<guestfs_swapon_device> for other notes.");
3406
3407   ("swapoff_label", (RErr, [String "label"]), 175, [],
3408    [], (* XXX tested by swapon_label *)
3409    "disable swap on labeled swap partition",
3410    "\
3411 This command disables the libguestfs appliance swap on
3412 labeled swap partition.");
3413
3414   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3415    (let uuid = uuidgen () in
3416     [InitEmpty, Always, TestRun (
3417        [["mkswap_U"; uuid; "/dev/sdb"];
3418         ["swapon_uuid"; uuid];
3419         ["swapoff_uuid"; uuid]])]),
3420    "enable swap on swap partition by UUID",
3421    "\
3422 This command enables swap to a swap partition with the given UUID.
3423 See C<guestfs_swapon_device> for other notes.");
3424
3425   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3426    [], (* XXX tested by swapon_uuid *)
3427    "disable swap on swap partition by UUID",
3428    "\
3429 This command disables the libguestfs appliance swap partition
3430 with the given UUID.");
3431
3432   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3433    [InitBasicFS, Always, TestRun (
3434       [["fallocate"; "/swap"; "8388608"];
3435        ["mkswap_file"; "/swap"]])],
3436    "create a swap file",
3437    "\
3438 Create a swap file.
3439
3440 This command just writes a swap file signature to an existing
3441 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3442
3443   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3444    [InitISOFS, Always, TestRun (
3445       [["inotify_init"; "0"]])],
3446    "create an inotify handle",
3447    "\
3448 This command creates a new inotify handle.
3449 The inotify subsystem can be used to notify events which happen to
3450 objects in the guest filesystem.
3451
3452 C<maxevents> is the maximum number of events which will be
3453 queued up between calls to C<guestfs_inotify_read> or
3454 C<guestfs_inotify_files>.
3455 If this is passed as C<0>, then the kernel (or previously set)
3456 default is used.  For Linux 2.6.29 the default was 16384 events.
3457 Beyond this limit, the kernel throws away events, but records
3458 the fact that it threw them away by setting a flag
3459 C<IN_Q_OVERFLOW> in the returned structure list (see
3460 C<guestfs_inotify_read>).
3461
3462 Before any events are generated, you have to add some
3463 watches to the internal watch list.  See:
3464 C<guestfs_inotify_add_watch>,
3465 C<guestfs_inotify_rm_watch> and
3466 C<guestfs_inotify_watch_all>.
3467
3468 Queued up events should be read periodically by calling
3469 C<guestfs_inotify_read>
3470 (or C<guestfs_inotify_files> which is just a helpful
3471 wrapper around C<guestfs_inotify_read>).  If you don't
3472 read the events out often enough then you risk the internal
3473 queue overflowing.
3474
3475 The handle should be closed after use by calling
3476 C<guestfs_inotify_close>.  This also removes any
3477 watches automatically.
3478
3479 See also L<inotify(7)> for an overview of the inotify interface
3480 as exposed by the Linux kernel, which is roughly what we expose
3481 via libguestfs.  Note that there is one global inotify handle
3482 per libguestfs instance.");
3483
3484   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3485    [InitBasicFS, Always, TestOutputList (
3486       [["inotify_init"; "0"];
3487        ["inotify_add_watch"; "/"; "1073741823"];
3488        ["touch"; "/a"];
3489        ["touch"; "/b"];
3490        ["inotify_files"]], ["a"; "b"])],
3491    "add an inotify watch",
3492    "\
3493 Watch C<path> for the events listed in C<mask>.
3494
3495 Note that if C<path> is a directory then events within that
3496 directory are watched, but this does I<not> happen recursively
3497 (in subdirectories).
3498
3499 Note for non-C or non-Linux callers: the inotify events are
3500 defined by the Linux kernel ABI and are listed in
3501 C</usr/include/sys/inotify.h>.");
3502
3503   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3504    [],
3505    "remove an inotify watch",
3506    "\
3507 Remove a previously defined inotify watch.
3508 See C<guestfs_inotify_add_watch>.");
3509
3510   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3511    [],
3512    "return list of inotify events",
3513    "\
3514 Return the complete queue of events that have happened
3515 since the previous read call.
3516
3517 If no events have happened, this returns an empty list.
3518
3519 I<Note>: In order to make sure that all events have been
3520 read, you must call this function repeatedly until it
3521 returns an empty list.  The reason is that the call will
3522 read events up to the maximum appliance-to-host message
3523 size and leave remaining events in the queue.");
3524
3525   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3526    [],
3527    "return list of watched files that had events",
3528    "\
3529 This function is a helpful wrapper around C<guestfs_inotify_read>
3530 which just returns a list of pathnames of objects that were
3531 touched.  The returned pathnames are sorted and deduplicated.");
3532
3533   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3534    [],
3535    "close the inotify handle",
3536    "\
3537 This closes the inotify handle which was previously
3538 opened by inotify_init.  It removes all watches, throws
3539 away any pending events, and deallocates all resources.");
3540
3541   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3542    [],
3543    "set SELinux security context",
3544    "\
3545 This sets the SELinux security context of the daemon
3546 to the string C<context>.
3547
3548 See the documentation about SELINUX in L<guestfs(3)>.");
3549
3550   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3551    [],
3552    "get SELinux security context",
3553    "\
3554 This gets the SELinux security context of the daemon.
3555
3556 See the documentation about SELINUX in L<guestfs(3)>,
3557 and C<guestfs_setcon>");
3558
3559   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3560    [InitEmpty, Always, TestOutput (
3561       [["part_disk"; "/dev/sda"; "mbr"];
3562        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3563        ["mount"; "/dev/sda1"; "/"];
3564        ["write_file"; "/new"; "new file contents"; "0"];
3565        ["cat"; "/new"]], "new file contents")],
3566    "make a filesystem with block size",
3567    "\
3568 This call is similar to C<guestfs_mkfs>, but it allows you to
3569 control the block size of the resulting filesystem.  Supported
3570 block sizes depend on the filesystem type, but typically they
3571 are C<1024>, C<2048> or C<4096> only.");
3572
3573   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3574    [InitEmpty, Always, TestOutput (
3575       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3576        ["mke2journal"; "4096"; "/dev/sda1"];
3577        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3578        ["mount"; "/dev/sda2"; "/"];
3579        ["write_file"; "/new"; "new file contents"; "0"];
3580        ["cat"; "/new"]], "new file contents")],
3581    "make ext2/3/4 external journal",
3582    "\
3583 This creates an ext2 external journal on C<device>.  It is equivalent
3584 to the command:
3585
3586  mke2fs -O journal_dev -b blocksize device");
3587
3588   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3589    [InitEmpty, Always, TestOutput (
3590       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3591        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3592        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3593        ["mount"; "/dev/sda2"; "/"];
3594        ["write_file"; "/new"; "new file contents"; "0"];
3595        ["cat"; "/new"]], "new file contents")],
3596    "make ext2/3/4 external journal with label",
3597    "\
3598 This creates an ext2 external journal on C<device> with label C<label>.");
3599
3600   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3601    (let uuid = uuidgen () in
3602     [InitEmpty, Always, TestOutput (
3603        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3604         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3605         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3606         ["mount"; "/dev/sda2"; "/"];
3607         ["write_file"; "/new"; "new file contents"; "0"];
3608         ["cat"; "/new"]], "new file contents")]),
3609    "make ext2/3/4 external journal with UUID",
3610    "\
3611 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3612
3613   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3614    [],
3615    "make ext2/3/4 filesystem with external journal",
3616    "\
3617 This creates an ext2/3/4 filesystem on C<device> with
3618 an external journal on C<journal>.  It is equivalent
3619 to the command:
3620
3621  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3622
3623 See also C<guestfs_mke2journal>.");
3624
3625   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3626    [],
3627    "make ext2/3/4 filesystem with external journal",
3628    "\
3629 This creates an ext2/3/4 filesystem on C<device> with
3630 an external journal on the journal labeled C<label>.
3631
3632 See also C<guestfs_mke2journal_L>.");
3633
3634   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3635    [],
3636    "make ext2/3/4 filesystem with external journal",
3637    "\
3638 This creates an ext2/3/4 filesystem on C<device> with
3639 an external journal on the journal with UUID C<uuid>.
3640
3641 See also C<guestfs_mke2journal_U>.");
3642
3643   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3644    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3645    "load a kernel module",
3646    "\
3647 This loads a kernel module in the appliance.
3648
3649 The kernel module must have been whitelisted when libguestfs
3650 was built (see C<appliance/kmod.whitelist.in> in the source).");
3651
3652   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3653    [InitNone, Always, TestOutput (
3654       [["echo_daemon"; "This is a test"]], "This is a test"
3655     )],
3656    "echo arguments back to the client",
3657    "\
3658 This command concatenate the list of C<words> passed with single spaces between
3659 them and returns the resulting string.
3660
3661 You can use this command to test the connection through to the daemon.
3662
3663 See also C<guestfs_ping_daemon>.");
3664
3665   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3666    [], (* There is a regression test for this. *)
3667    "find all files and directories, returning NUL-separated list",
3668    "\
3669 This command lists out all files and directories, recursively,
3670 starting at C<directory>, placing the resulting list in the
3671 external file called C<files>.
3672
3673 This command works the same way as C<guestfs_find> with the
3674 following exceptions:
3675
3676 =over 4
3677
3678 =item *
3679
3680 The resulting list is written to an external file.
3681
3682 =item *
3683
3684 Items (filenames) in the result are separated
3685 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3686
3687 =item *
3688
3689 This command is not limited in the number of names that it
3690 can return.
3691
3692 =item *
3693
3694 The result list is not sorted.
3695
3696 =back");
3697
3698   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3699    [InitISOFS, Always, TestOutput (
3700       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3701     InitISOFS, Always, TestOutput (
3702       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3703     InitISOFS, Always, TestOutput (
3704       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3705     InitISOFS, Always, TestLastFail (
3706       [["case_sensitive_path"; "/Known-1/"]]);
3707     InitBasicFS, Always, TestOutput (
3708       [["mkdir"; "/a"];
3709        ["mkdir"; "/a/bbb"];
3710        ["touch"; "/a/bbb/c"];
3711        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3712     InitBasicFS, Always, TestOutput (
3713       [["mkdir"; "/a"];
3714        ["mkdir"; "/a/bbb"];
3715        ["touch"; "/a/bbb/c"];
3716        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3717     InitBasicFS, Always, TestLastFail (
3718       [["mkdir"; "/a"];
3719        ["mkdir"; "/a/bbb"];
3720        ["touch"; "/a/bbb/c"];
3721        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3722    "return true path on case-insensitive filesystem",
3723    "\
3724 This can be used to resolve case insensitive paths on
3725 a filesystem which is case sensitive.  The use case is
3726 to resolve paths which you have read from Windows configuration
3727 files or the Windows Registry, to the true path.
3728
3729 The command handles a peculiarity of the Linux ntfs-3g
3730 filesystem driver (and probably others), which is that although
3731 the underlying filesystem is case-insensitive, the driver
3732 exports the filesystem to Linux as case-sensitive.
3733
3734 One consequence of this is that special directories such
3735 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3736 (or other things) depending on the precise details of how
3737 they were created.  In Windows itself this would not be
3738 a problem.
3739
3740 Bug or feature?  You decide:
3741 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3742
3743 This function resolves the true case of each element in the
3744 path and returns the case-sensitive path.
3745
3746 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3747 might return C<\"/WINDOWS/system32\"> (the exact return value
3748 would depend on details of how the directories were originally
3749 created under Windows).
3750
3751 I<Note>:
3752 This function does not handle drive names, backslashes etc.
3753
3754 See also C<guestfs_realpath>.");
3755
3756   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3757    [InitBasicFS, Always, TestOutput (
3758       [["vfs_type"; "/dev/sda1"]], "ext2")],
3759    "get the Linux VFS type corresponding to a mounted device",
3760    "\
3761 This command gets the block device type corresponding to
3762 a mounted device called C<device>.
3763
3764 Usually the result is the name of the Linux VFS module that
3765 is used to mount this device (probably determined automatically
3766 if you used the C<guestfs_mount> call).");
3767
3768   ("truncate", (RErr, [Pathname "path"]), 199, [],
3769    [InitBasicFS, Always, TestOutputStruct (
3770       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3771        ["truncate"; "/test"];
3772        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3773    "truncate a file to zero size",
3774    "\
3775 This command truncates C<path> to a zero-length file.  The
3776 file must exist already.");
3777
3778   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3779    [InitBasicFS, Always, TestOutputStruct (
3780       [["touch"; "/test"];
3781        ["truncate_size"; "/test"; "1000"];
3782        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3783    "truncate a file to a particular size",
3784    "\
3785 This command truncates C<path> to size C<size> bytes.  The file
3786 must exist already.  If the file is smaller than C<size> then
3787 the file is extended to the required size with null bytes.");
3788
3789   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3790    [InitBasicFS, Always, TestOutputStruct (
3791       [["touch"; "/test"];
3792        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3793        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3794    "set timestamp of a file with nanosecond precision",
3795    "\
3796 This command sets the timestamps of a file with nanosecond
3797 precision.
3798
3799 C<atsecs, atnsecs> are the last access time (atime) in secs and
3800 nanoseconds from the epoch.
3801
3802 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3803 secs and nanoseconds from the epoch.
3804
3805 If the C<*nsecs> field contains the special value C<-1> then
3806 the corresponding timestamp is set to the current time.  (The
3807 C<*secs> field is ignored in this case).
3808
3809 If the C<*nsecs> field contains the special value C<-2> then
3810 the corresponding timestamp is left unchanged.  (The
3811 C<*secs> field is ignored in this case).");
3812
3813   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3814    [InitBasicFS, Always, TestOutputStruct (
3815       [["mkdir_mode"; "/test"; "0o111"];
3816        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3817    "create a directory with a particular mode",
3818    "\
3819 This command creates a directory, setting the initial permissions
3820 of the directory to C<mode>.  See also C<guestfs_mkdir>.");
3821
3822   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3823    [], (* XXX *)
3824    "change file owner and group",
3825    "\
3826 Change the file owner to C<owner> and group to C<group>.
3827 This is like C<guestfs_chown> but if C<path> is a symlink then
3828 the link itself is changed, not the target.
3829
3830 Only numeric uid and gid are supported.  If you want to use
3831 names, you will need to locate and parse the password file
3832 yourself (Augeas support makes this relatively easy).");
3833
3834   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3835    [], (* XXX *)
3836    "lstat on multiple files",
3837    "\
3838 This call allows you to perform the C<guestfs_lstat> operation
3839 on multiple files, where all files are in the directory C<path>.
3840 C<names> is the list of files from this directory.
3841
3842 On return you get a list of stat structs, with a one-to-one
3843 correspondence to the C<names> list.  If any name did not exist
3844 or could not be lstat'd, then the C<ino> field of that structure
3845 is set to C<-1>.
3846
3847 This call is intended for programs that want to efficiently
3848 list a directory contents without making many round-trips.
3849 See also C<guestfs_lxattrlist> for a similarly efficient call
3850 for getting extended attributes.  Very long directory listings
3851 might cause the protocol message size to be exceeded, causing
3852 this call to fail.  The caller must split up such requests
3853 into smaller groups of names.");
3854
3855   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3856    [], (* XXX *)
3857    "lgetxattr on multiple files",
3858    "\
3859 This call allows you to get the extended attributes
3860 of multiple files, where all files are in the directory C<path>.
3861 C<names> is the list of files from this directory.
3862
3863 On return you get a flat list of xattr structs which must be
3864 interpreted sequentially.  The first xattr struct always has a zero-length
3865 C<attrname>.  C<attrval> in this struct is zero-length
3866 to indicate there was an error doing C<lgetxattr> for this
3867 file, I<or> is a C string which is a decimal number
3868 (the number of following attributes for this file, which could
3869 be C<\"0\">).  Then after the first xattr struct are the
3870 zero or more attributes for the first named file.
3871 This repeats for the second and subsequent files.
3872
3873 This call is intended for programs that want to efficiently
3874 list a directory contents without making many round-trips.
3875 See also C<guestfs_lstatlist> for a similarly efficient call
3876 for getting standard stats.  Very long directory listings
3877 might cause the protocol message size to be exceeded, causing
3878 this call to fail.  The caller must split up such requests
3879 into smaller groups of names.");
3880
3881   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
3882    [], (* XXX *)
3883    "readlink on multiple files",
3884    "\
3885 This call allows you to do a C<readlink> operation
3886 on multiple files, where all files are in the directory C<path>.
3887 C<names> is the list of files from this directory.
3888
3889 On return you get a list of strings, with a one-to-one
3890 correspondence to the C<names> list.  Each string is the
3891 value of the symbol link.
3892
3893 If the C<readlink(2)> operation fails on any name, then
3894 the corresponding result string is the empty string C<\"\">.
3895 However the whole operation is completed even if there
3896 were C<readlink(2)> errors, and so you can call this
3897 function with names where you don't know if they are
3898 symbolic links already (albeit slightly less efficient).
3899
3900 This call is intended for programs that want to efficiently
3901 list a directory contents without making many round-trips.
3902 Very long directory listings might cause the protocol
3903 message size to be exceeded, causing
3904 this call to fail.  The caller must split up such requests
3905 into smaller groups of names.");
3906
3907   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
3908    [InitISOFS, Always, TestOutputBuffer (
3909       [["pread"; "/known-4"; "1"; "3"]], "\n");
3910     InitISOFS, Always, TestOutputBuffer (
3911       [["pread"; "/empty"; "0"; "100"]], "")],
3912    "read part of a file",
3913    "\
3914 This command lets you read part of a file.  It reads C<count>
3915 bytes of the file, starting at C<offset>, from file C<path>.
3916
3917 This may read fewer bytes than requested.  For further details
3918 see the L<pread(2)> system call.");
3919
3920   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
3921    [InitEmpty, Always, TestRun (
3922       [["part_init"; "/dev/sda"; "gpt"]])],
3923    "create an empty partition table",
3924    "\
3925 This creates an empty partition table on C<device> of one of the
3926 partition types listed below.  Usually C<parttype> should be
3927 either C<msdos> or C<gpt> (for large disks).
3928
3929 Initially there are no partitions.  Following this, you should
3930 call C<guestfs_part_add> for each partition required.
3931
3932 Possible values for C<parttype> are:
3933
3934 =over 4
3935
3936 =item B<efi> | B<gpt>
3937
3938 Intel EFI / GPT partition table.
3939
3940 This is recommended for >= 2 TB partitions that will be accessed
3941 from Linux and Intel-based Mac OS X.  It also has limited backwards
3942 compatibility with the C<mbr> format.
3943
3944 =item B<mbr> | B<msdos>
3945
3946 The standard PC \"Master Boot Record\" (MBR) format used
3947 by MS-DOS and Windows.  This partition type will B<only> work
3948 for device sizes up to 2 TB.  For large disks we recommend
3949 using C<gpt>.
3950
3951 =back
3952
3953 Other partition table types that may work but are not
3954 supported include:
3955
3956 =over 4
3957
3958 =item B<aix>
3959
3960 AIX disk labels.
3961
3962 =item B<amiga> | B<rdb>
3963
3964 Amiga \"Rigid Disk Block\" format.
3965
3966 =item B<bsd>
3967
3968 BSD disk labels.
3969
3970 =item B<dasd>
3971
3972 DASD, used on IBM mainframes.
3973
3974 =item B<dvh>
3975
3976 MIPS/SGI volumes.
3977
3978 =item B<mac>
3979
3980 Old Mac partition format.  Modern Macs use C<gpt>.
3981
3982 =item B<pc98>
3983
3984 NEC PC-98 format, common in Japan apparently.
3985
3986 =item B<sun>
3987
3988 Sun disk labels.
3989
3990 =back");
3991
3992   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
3993    [InitEmpty, Always, TestRun (
3994       [["part_init"; "/dev/sda"; "mbr"];
3995        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
3996     InitEmpty, Always, TestRun (
3997       [["part_init"; "/dev/sda"; "gpt"];
3998        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
3999        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
4000     InitEmpty, Always, TestRun (
4001       [["part_init"; "/dev/sda"; "mbr"];
4002        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
4003        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4004        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4005        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4006    "add a partition to the device",
4007    "\
4008 This command adds a partition to C<device>.  If there is no partition
4009 table on the device, call C<guestfs_part_init> first.
4010
4011 The C<prlogex> parameter is the type of partition.  Normally you
4012 should pass C<p> or C<primary> here, but MBR partition tables also
4013 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4014 types.
4015
4016 C<startsect> and C<endsect> are the start and end of the partition
4017 in I<sectors>.  C<endsect> may be negative, which means it counts
4018 backwards from the end of the disk (C<-1> is the last sector).
4019
4020 Creating a partition which covers the whole disk is not so easy.
4021 Use C<guestfs_part_disk> to do that.");
4022
4023   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4024    [InitEmpty, Always, TestRun (
4025       [["part_disk"; "/dev/sda"; "mbr"]]);
4026     InitEmpty, Always, TestRun (
4027       [["part_disk"; "/dev/sda"; "gpt"]])],
4028    "partition whole disk with a single primary partition",
4029    "\
4030 This command is simply a combination of C<guestfs_part_init>
4031 followed by C<guestfs_part_add> to create a single primary partition
4032 covering the whole disk.
4033
4034 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4035 but other possible values are described in C<guestfs_part_init>.");
4036
4037   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4038    [InitEmpty, Always, TestRun (
4039       [["part_disk"; "/dev/sda"; "mbr"];
4040        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4041    "make a partition bootable",
4042    "\
4043 This sets the bootable flag on partition numbered C<partnum> on
4044 device C<device>.  Note that partitions are numbered from 1.
4045
4046 The bootable flag is used by some PC BIOSes to determine which
4047 partition to boot from.  It is by no means universally recognized,
4048 and in any case if your operating system installed a boot
4049 sector on the device itself, then that takes precedence.");
4050
4051   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4052    [InitEmpty, Always, TestRun (
4053       [["part_disk"; "/dev/sda"; "gpt"];
4054        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4055    "set partition name",
4056    "\
4057 This sets the partition name on partition numbered C<partnum> on
4058 device C<device>.  Note that partitions are numbered from 1.
4059
4060 The partition name can only be set on certain types of partition
4061 table.  This works on C<gpt> but not on C<mbr> partitions.");
4062
4063   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4064    [], (* XXX Add a regression test for this. *)
4065    "list partitions on a device",
4066    "\
4067 This command parses the partition table on C<device> and
4068 returns the list of partitions found.
4069
4070 The fields in the returned structure are:
4071
4072 =over 4
4073
4074 =item B<part_num>
4075
4076 Partition number, counting from 1.
4077
4078 =item B<part_start>
4079
4080 Start of the partition I<in bytes>.  To get sectors you have to
4081 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4082
4083 =item B<part_end>
4084
4085 End of the partition in bytes.
4086
4087 =item B<part_size>
4088
4089 Size of the partition in bytes.
4090
4091 =back");
4092
4093   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4094    [InitEmpty, Always, TestOutput (
4095       [["part_disk"; "/dev/sda"; "gpt"];
4096        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4097    "get the partition table type",
4098    "\
4099 This command examines the partition table on C<device> and
4100 returns the partition table type (format) being used.
4101
4102 Common return values include: C<msdos> (a DOS/Windows style MBR
4103 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4104 values are possible, although unusual.  See C<guestfs_part_init>
4105 for a full list.");
4106
4107   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4108    [InitBasicFS, Always, TestOutputBuffer (
4109       [["fill"; "0x63"; "10"; "/test"];
4110        ["read_file"; "/test"]], "cccccccccc")],
4111    "fill a file with octets",
4112    "\
4113 This command creates a new file called C<path>.  The initial
4114 content of the file is C<len> octets of C<c>, where C<c>
4115 must be a number in the range C<[0..255]>.
4116
4117 To fill a file with zero bytes (sparsely), it is
4118 much more efficient to use C<guestfs_truncate_size>.");
4119
4120   ("available", (RErr, [StringList "groups"]), 216, [],
4121    [InitNone, Always, TestRun [["available"; ""]]],
4122    "test availability of some parts of the API",
4123    "\
4124 This command is used to check the availability of some
4125 groups of functionality in the appliance, which not all builds of
4126 the libguestfs appliance will be able to provide.
4127
4128 The libguestfs groups, and the functions that those
4129 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4130
4131 The argument C<groups> is a list of group names, eg:
4132 C<[\"inotify\", \"augeas\"]> would check for the availability of
4133 the Linux inotify functions and Augeas (configuration file
4134 editing) functions.
4135
4136 The command returns no error if I<all> requested groups are available.
4137
4138 It fails with an error if one or more of the requested
4139 groups is unavailable in the appliance.
4140
4141 If an unknown group name is included in the
4142 list of groups then an error is always returned.
4143
4144 I<Notes:>
4145
4146 =over 4
4147
4148 =item *
4149
4150 You must call C<guestfs_launch> before calling this function.
4151
4152 The reason is because we don't know what groups are
4153 supported by the appliance/daemon until it is running and can
4154 be queried.
4155
4156 =item *
4157
4158 If a group of functions is available, this does not necessarily
4159 mean that they will work.  You still have to check for errors
4160 when calling individual API functions even if they are
4161 available.
4162
4163 =item *
4164
4165 It is usually the job of distro packagers to build
4166 complete functionality into the libguestfs appliance.
4167 Upstream libguestfs, if built from source with all
4168 requirements satisfied, will support everything.
4169
4170 =item *
4171
4172 This call was added in version C<1.0.80>.  In previous
4173 versions of libguestfs all you could do would be to speculatively
4174 execute a command to find out if the daemon implemented it.
4175 See also C<guestfs_version>.
4176
4177 =back");
4178
4179   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4180    [InitBasicFS, Always, TestOutputBuffer (
4181       [["write_file"; "/src"; "hello, world"; "0"];
4182        ["dd"; "/src"; "/dest"];
4183        ["read_file"; "/dest"]], "hello, world")],
4184    "copy from source to destination using dd",
4185    "\
4186 This command copies from one source device or file C<src>
4187 to another destination device or file C<dest>.  Normally you
4188 would use this to copy to or from a device or partition, for
4189 example to duplicate a filesystem.
4190
4191 If the destination is a device, it must be as large or larger
4192 than the source file or device, otherwise the copy will fail.
4193 This command cannot do partial copies.");
4194
4195   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4196    [InitBasicFS, Always, TestOutputInt (
4197       [["write_file"; "/file"; "hello, world"; "0"];
4198        ["filesize"; "/file"]], 12)],
4199    "return the size of the file in bytes",
4200    "\
4201 This command returns the size of C<file> in bytes.
4202
4203 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4204 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4205 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4206
4207   ("lvrename", (RErr, [String "logvol"; String "newlogvol"]), 219, [],
4208    [InitBasicFSonLVM, Always, TestOutputList (
4209       [["lvrename"; "/dev/VG/LV"; "/dev/VG/LV2"];
4210        ["lvs"]], ["/dev/VG/LV2"])],
4211    "rename an LVM logical volume",
4212    "\
4213 Rename a logical volume C<logvol> with the new name C<newlogvol>.");
4214
4215   ("vgrename", (RErr, [String "volgroup"; String "newvolgroup"]), 220, [],
4216    [InitBasicFSonLVM, Always, TestOutputList (
4217       [["umount"; "/"];
4218        ["vg_activate"; "false"; "VG"];
4219        ["vgrename"; "VG"; "VG2"];
4220        ["vg_activate"; "true"; "VG2"];
4221        ["mount"; "/dev/VG2/LV"; "/"];
4222        ["vgs"]], ["VG2"])],
4223    "rename an LVM volume group",
4224    "\
4225 Rename a volume group C<volgroup> with the new name C<newvolgroup>.");
4226
4227 ]
4228
4229 let all_functions = non_daemon_functions @ daemon_functions
4230
4231 (* In some places we want the functions to be displayed sorted
4232  * alphabetically, so this is useful:
4233  *)
4234 let all_functions_sorted =
4235   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4236                compare n1 n2) all_functions
4237
4238 (* Field types for structures. *)
4239 type field =
4240   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4241   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4242   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4243   | FUInt32
4244   | FInt32
4245   | FUInt64
4246   | FInt64
4247   | FBytes                      (* Any int measure that counts bytes. *)
4248   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4249   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4250
4251 (* Because we generate extra parsing code for LVM command line tools,
4252  * we have to pull out the LVM columns separately here.
4253  *)
4254 let lvm_pv_cols = [
4255   "pv_name", FString;
4256   "pv_uuid", FUUID;
4257   "pv_fmt", FString;
4258   "pv_size", FBytes;
4259   "dev_size", FBytes;
4260   "pv_free", FBytes;
4261   "pv_used", FBytes;
4262   "pv_attr", FString (* XXX *);
4263   "pv_pe_count", FInt64;
4264   "pv_pe_alloc_count", FInt64;
4265   "pv_tags", FString;
4266   "pe_start", FBytes;
4267   "pv_mda_count", FInt64;
4268   "pv_mda_free", FBytes;
4269   (* Not in Fedora 10:
4270      "pv_mda_size", FBytes;
4271   *)
4272 ]
4273 let lvm_vg_cols = [
4274   "vg_name", FString;
4275   "vg_uuid", FUUID;
4276   "vg_fmt", FString;
4277   "vg_attr", FString (* XXX *);
4278   "vg_size", FBytes;
4279   "vg_free", FBytes;
4280   "vg_sysid", FString;
4281   "vg_extent_size", FBytes;
4282   "vg_extent_count", FInt64;
4283   "vg_free_count", FInt64;
4284   "max_lv", FInt64;
4285   "max_pv", FInt64;
4286   "pv_count", FInt64;
4287   "lv_count", FInt64;
4288   "snap_count", FInt64;
4289   "vg_seqno", FInt64;
4290   "vg_tags", FString;
4291   "vg_mda_count", FInt64;
4292   "vg_mda_free", FBytes;
4293   (* Not in Fedora 10:
4294      "vg_mda_size", FBytes;
4295   *)
4296 ]
4297 let lvm_lv_cols = [
4298   "lv_name", FString;
4299   "lv_uuid", FUUID;
4300   "lv_attr", FString (* XXX *);
4301   "lv_major", FInt64;
4302   "lv_minor", FInt64;
4303   "lv_kernel_major", FInt64;
4304   "lv_kernel_minor", FInt64;
4305   "lv_size", FBytes;
4306   "seg_count", FInt64;
4307   "origin", FString;
4308   "snap_percent", FOptPercent;
4309   "copy_percent", FOptPercent;
4310   "move_pv", FString;
4311   "lv_tags", FString;
4312   "mirror_log", FString;
4313   "modules", FString;
4314 ]
4315
4316 (* Names and fields in all structures (in RStruct and RStructList)
4317  * that we support.
4318  *)
4319 let structs = [
4320   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4321    * not use this struct in any new code.
4322    *)
4323   "int_bool", [
4324     "i", FInt32;                (* for historical compatibility *)
4325     "b", FInt32;                (* for historical compatibility *)
4326   ];
4327
4328   (* LVM PVs, VGs, LVs. *)
4329   "lvm_pv", lvm_pv_cols;
4330   "lvm_vg", lvm_vg_cols;
4331   "lvm_lv", lvm_lv_cols;
4332
4333   (* Column names and types from stat structures.
4334    * NB. Can't use things like 'st_atime' because glibc header files
4335    * define some of these as macros.  Ugh.
4336    *)
4337   "stat", [
4338     "dev", FInt64;
4339     "ino", FInt64;
4340     "mode", FInt64;
4341     "nlink", FInt64;
4342     "uid", FInt64;
4343     "gid", FInt64;
4344     "rdev", FInt64;
4345     "size", FInt64;
4346     "blksize", FInt64;
4347     "blocks", FInt64;
4348     "atime", FInt64;
4349     "mtime", FInt64;
4350     "ctime", FInt64;
4351   ];
4352   "statvfs", [
4353     "bsize", FInt64;
4354     "frsize", FInt64;
4355     "blocks", FInt64;
4356     "bfree", FInt64;
4357     "bavail", FInt64;
4358     "files", FInt64;
4359     "ffree", FInt64;
4360     "favail", FInt64;
4361     "fsid", FInt64;
4362     "flag", FInt64;
4363     "namemax", FInt64;
4364   ];
4365
4366   (* Column names in dirent structure. *)
4367   "dirent", [
4368     "ino", FInt64;
4369     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4370     "ftyp", FChar;
4371     "name", FString;
4372   ];
4373
4374   (* Version numbers. *)
4375   "version", [
4376     "major", FInt64;
4377     "minor", FInt64;
4378     "release", FInt64;
4379     "extra", FString;
4380   ];
4381
4382   (* Extended attribute. *)
4383   "xattr", [
4384     "attrname", FString;
4385     "attrval", FBuffer;
4386   ];
4387
4388   (* Inotify events. *)
4389   "inotify_event", [
4390     "in_wd", FInt64;
4391     "in_mask", FUInt32;
4392     "in_cookie", FUInt32;
4393     "in_name", FString;
4394   ];
4395
4396   (* Partition table entry. *)
4397   "partition", [
4398     "part_num", FInt32;
4399     "part_start", FBytes;
4400     "part_end", FBytes;
4401     "part_size", FBytes;
4402   ];
4403 ] (* end of structs *)
4404
4405 (* Ugh, Java has to be different ..
4406  * These names are also used by the Haskell bindings.
4407  *)
4408 let java_structs = [
4409   "int_bool", "IntBool";
4410   "lvm_pv", "PV";
4411   "lvm_vg", "VG";
4412   "lvm_lv", "LV";
4413   "stat", "Stat";
4414   "statvfs", "StatVFS";
4415   "dirent", "Dirent";
4416   "version", "Version";
4417   "xattr", "XAttr";
4418   "inotify_event", "INotifyEvent";
4419   "partition", "Partition";
4420 ]
4421
4422 (* What structs are actually returned. *)
4423 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4424
4425 (* Returns a list of RStruct/RStructList structs that are returned
4426  * by any function.  Each element of returned list is a pair:
4427  *
4428  * (structname, RStructOnly)
4429  *    == there exists function which returns RStruct (_, structname)
4430  * (structname, RStructListOnly)
4431  *    == there exists function which returns RStructList (_, structname)
4432  * (structname, RStructAndList)
4433  *    == there are functions returning both RStruct (_, structname)
4434  *                                      and RStructList (_, structname)
4435  *)
4436 let rstructs_used_by functions =
4437   (* ||| is a "logical OR" for rstructs_used_t *)
4438   let (|||) a b =
4439     match a, b with
4440     | RStructAndList, _
4441     | _, RStructAndList -> RStructAndList
4442     | RStructOnly, RStructListOnly
4443     | RStructListOnly, RStructOnly -> RStructAndList
4444     | RStructOnly, RStructOnly -> RStructOnly
4445     | RStructListOnly, RStructListOnly -> RStructListOnly
4446   in
4447
4448   let h = Hashtbl.create 13 in
4449
4450   (* if elem->oldv exists, update entry using ||| operator,
4451    * else just add elem->newv to the hash
4452    *)
4453   let update elem newv =
4454     try  let oldv = Hashtbl.find h elem in
4455          Hashtbl.replace h elem (newv ||| oldv)
4456     with Not_found -> Hashtbl.add h elem newv
4457   in
4458
4459   List.iter (
4460     fun (_, style, _, _, _, _, _) ->
4461       match fst style with
4462       | RStruct (_, structname) -> update structname RStructOnly
4463       | RStructList (_, structname) -> update structname RStructListOnly
4464       | _ -> ()
4465   ) functions;
4466
4467   (* return key->values as a list of (key,value) *)
4468   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4469
4470 (* Used for testing language bindings. *)
4471 type callt =
4472   | CallString of string
4473   | CallOptString of string option
4474   | CallStringList of string list
4475   | CallInt of int
4476   | CallInt64 of int64
4477   | CallBool of bool
4478
4479 (* Used to memoize the result of pod2text. *)
4480 let pod2text_memo_filename = "src/.pod2text.data"
4481 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4482   try
4483     let chan = open_in pod2text_memo_filename in
4484     let v = input_value chan in
4485     close_in chan;
4486     v
4487   with
4488     _ -> Hashtbl.create 13
4489 let pod2text_memo_updated () =
4490   let chan = open_out pod2text_memo_filename in
4491   output_value chan pod2text_memo;
4492   close_out chan
4493
4494 (* Useful functions.
4495  * Note we don't want to use any external OCaml libraries which
4496  * makes this a bit harder than it should be.
4497  *)
4498 module StringMap = Map.Make (String)
4499
4500 let failwithf fs = ksprintf failwith fs
4501
4502 let unique = let i = ref 0 in fun () -> incr i; !i
4503
4504 let replace_char s c1 c2 =
4505   let s2 = String.copy s in
4506   let r = ref false in
4507   for i = 0 to String.length s2 - 1 do
4508     if String.unsafe_get s2 i = c1 then (
4509       String.unsafe_set s2 i c2;
4510       r := true
4511     )
4512   done;
4513   if not !r then s else s2
4514
4515 let isspace c =
4516   c = ' '
4517   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4518
4519 let triml ?(test = isspace) str =
4520   let i = ref 0 in
4521   let n = ref (String.length str) in
4522   while !n > 0 && test str.[!i]; do
4523     decr n;
4524     incr i
4525   done;
4526   if !i = 0 then str
4527   else String.sub str !i !n
4528
4529 let trimr ?(test = isspace) str =
4530   let n = ref (String.length str) in
4531   while !n > 0 && test str.[!n-1]; do
4532     decr n
4533   done;
4534   if !n = String.length str then str
4535   else String.sub str 0 !n
4536
4537 let trim ?(test = isspace) str =
4538   trimr ~test (triml ~test str)
4539
4540 let rec find s sub =
4541   let len = String.length s in
4542   let sublen = String.length sub in
4543   let rec loop i =
4544     if i <= len-sublen then (
4545       let rec loop2 j =
4546         if j < sublen then (
4547           if s.[i+j] = sub.[j] then loop2 (j+1)
4548           else -1
4549         ) else
4550           i (* found *)
4551       in
4552       let r = loop2 0 in
4553       if r = -1 then loop (i+1) else r
4554     ) else
4555       -1 (* not found *)
4556   in
4557   loop 0
4558
4559 let rec replace_str s s1 s2 =
4560   let len = String.length s in
4561   let sublen = String.length s1 in
4562   let i = find s s1 in
4563   if i = -1 then s
4564   else (
4565     let s' = String.sub s 0 i in
4566     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4567     s' ^ s2 ^ replace_str s'' s1 s2
4568   )
4569
4570 let rec string_split sep str =
4571   let len = String.length str in
4572   let seplen = String.length sep in
4573   let i = find str sep in
4574   if i = -1 then [str]
4575   else (
4576     let s' = String.sub str 0 i in
4577     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4578     s' :: string_split sep s''
4579   )
4580
4581 let files_equal n1 n2 =
4582   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4583   match Sys.command cmd with
4584   | 0 -> true
4585   | 1 -> false
4586   | i -> failwithf "%s: failed with error code %d" cmd i
4587
4588 let rec filter_map f = function
4589   | [] -> []
4590   | x :: xs ->
4591       match f x with
4592       | Some y -> y :: filter_map f xs
4593       | None -> filter_map f xs
4594
4595 let rec find_map f = function
4596   | [] -> raise Not_found
4597   | x :: xs ->
4598       match f x with
4599       | Some y -> y
4600       | None -> find_map f xs
4601
4602 let iteri f xs =
4603   let rec loop i = function
4604     | [] -> ()
4605     | x :: xs -> f i x; loop (i+1) xs
4606   in
4607   loop 0 xs
4608
4609 let mapi f xs =
4610   let rec loop i = function
4611     | [] -> []
4612     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4613   in
4614   loop 0 xs
4615
4616 let count_chars c str =
4617   let count = ref 0 in
4618   for i = 0 to String.length str - 1 do
4619     if c = String.unsafe_get str i then incr count
4620   done;
4621   !count
4622
4623 let name_of_argt = function
4624   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4625   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4626   | FileIn n | FileOut n -> n
4627
4628 let java_name_of_struct typ =
4629   try List.assoc typ java_structs
4630   with Not_found ->
4631     failwithf
4632       "java_name_of_struct: no java_structs entry corresponding to %s" typ
4633
4634 let cols_of_struct typ =
4635   try List.assoc typ structs
4636   with Not_found ->
4637     failwithf "cols_of_struct: unknown struct %s" typ
4638
4639 let seq_of_test = function
4640   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
4641   | TestOutputListOfDevices (s, _)
4642   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
4643   | TestOutputTrue s | TestOutputFalse s
4644   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
4645   | TestOutputStruct (s, _)
4646   | TestLastFail s -> s
4647
4648 (* Handling for function flags. *)
4649 let protocol_limit_warning =
4650   "Because of the message protocol, there is a transfer limit
4651 of somewhere between 2MB and 4MB.  To transfer large files you should use
4652 FTP."
4653
4654 let danger_will_robinson =
4655   "B<This command is dangerous.  Without careful use you
4656 can easily destroy all your data>."
4657
4658 let deprecation_notice flags =
4659   try
4660     let alt =
4661       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
4662     let txt =
4663       sprintf "This function is deprecated.
4664 In new code, use the C<%s> call instead.
4665
4666 Deprecated functions will not be removed from the API, but the
4667 fact that they are deprecated indicates that there are problems
4668 with correct use of these functions." alt in
4669     Some txt
4670   with
4671     Not_found -> None
4672
4673 (* Create list of optional groups. *)
4674 let optgroups =
4675   let h = Hashtbl.create 13 in
4676   List.iter (
4677     fun (name, _, _, flags, _, _, _) ->
4678       List.iter (
4679         function
4680         | Optional group ->
4681             let names = try Hashtbl.find h group with Not_found -> [] in
4682             Hashtbl.replace h group (name :: names)
4683         | _ -> ()
4684       ) flags
4685   ) daemon_functions;
4686   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
4687   let groups =
4688     List.map (
4689       fun group -> group, List.sort compare (Hashtbl.find h group)
4690     ) groups in
4691   List.sort (fun x y -> compare (fst x) (fst y)) groups
4692
4693 (* Check function names etc. for consistency. *)
4694 let check_functions () =
4695   let contains_uppercase str =
4696     let len = String.length str in
4697     let rec loop i =
4698       if i >= len then false
4699       else (
4700         let c = str.[i] in
4701         if c >= 'A' && c <= 'Z' then true
4702         else loop (i+1)
4703       )
4704     in
4705     loop 0
4706   in
4707
4708   (* Check function names. *)
4709   List.iter (
4710     fun (name, _, _, _, _, _, _) ->
4711       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
4712         failwithf "function name %s does not need 'guestfs' prefix" name;
4713       if name = "" then
4714         failwithf "function name is empty";
4715       if name.[0] < 'a' || name.[0] > 'z' then
4716         failwithf "function name %s must start with lowercase a-z" name;
4717       if String.contains name '-' then
4718         failwithf "function name %s should not contain '-', use '_' instead."
4719           name
4720   ) all_functions;
4721
4722   (* Check function parameter/return names. *)
4723   List.iter (
4724     fun (name, style, _, _, _, _, _) ->
4725       let check_arg_ret_name n =
4726         if contains_uppercase n then
4727           failwithf "%s param/ret %s should not contain uppercase chars"
4728             name n;
4729         if String.contains n '-' || String.contains n '_' then
4730           failwithf "%s param/ret %s should not contain '-' or '_'"
4731             name n;
4732         if n = "value" then
4733           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;
4734         if n = "int" || n = "char" || n = "short" || n = "long" then
4735           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
4736         if n = "i" || n = "n" then
4737           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
4738         if n = "argv" || n = "args" then
4739           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
4740
4741         (* List Haskell, OCaml and C keywords here.
4742          * http://www.haskell.org/haskellwiki/Keywords
4743          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
4744          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
4745          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
4746          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
4747          * Omitting _-containing words, since they're handled above.
4748          * Omitting the OCaml reserved word, "val", is ok,
4749          * and saves us from renaming several parameters.
4750          *)
4751         let reserved = [
4752           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
4753           "char"; "class"; "const"; "constraint"; "continue"; "data";
4754           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
4755           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
4756           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
4757           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
4758           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
4759           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
4760           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
4761           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
4762           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
4763           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
4764           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
4765           "volatile"; "when"; "where"; "while";
4766           ] in
4767         if List.mem n reserved then
4768           failwithf "%s has param/ret using reserved word %s" name n;
4769       in
4770
4771       (match fst style with
4772        | RErr -> ()
4773        | RInt n | RInt64 n | RBool n
4774        | RConstString n | RConstOptString n | RString n
4775        | RStringList n | RStruct (n, _) | RStructList (n, _)
4776        | RHashtable n | RBufferOut n ->
4777            check_arg_ret_name n
4778       );
4779       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
4780   ) all_functions;
4781
4782   (* Check short descriptions. *)
4783   List.iter (
4784     fun (name, _, _, _, _, shortdesc, _) ->
4785       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
4786         failwithf "short description of %s should begin with lowercase." name;
4787       let c = shortdesc.[String.length shortdesc-1] in
4788       if c = '\n' || c = '.' then
4789         failwithf "short description of %s should not end with . or \\n." name
4790   ) all_functions;
4791
4792   (* Check long dscriptions. *)
4793   List.iter (
4794     fun (name, _, _, _, _, _, longdesc) ->
4795       if longdesc.[String.length longdesc-1] = '\n' then
4796         failwithf "long description of %s should not end with \\n." name
4797   ) all_functions;
4798
4799   (* Check proc_nrs. *)
4800   List.iter (
4801     fun (name, _, proc_nr, _, _, _, _) ->
4802       if proc_nr <= 0 then
4803         failwithf "daemon function %s should have proc_nr > 0" name
4804   ) daemon_functions;
4805
4806   List.iter (
4807     fun (name, _, proc_nr, _, _, _, _) ->
4808       if proc_nr <> -1 then
4809         failwithf "non-daemon function %s should have proc_nr -1" name
4810   ) non_daemon_functions;
4811
4812   let proc_nrs =
4813     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
4814       daemon_functions in
4815   let proc_nrs =
4816     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
4817   let rec loop = function
4818     | [] -> ()
4819     | [_] -> ()
4820     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
4821         loop rest
4822     | (name1,nr1) :: (name2,nr2) :: _ ->
4823         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
4824           name1 name2 nr1 nr2
4825   in
4826   loop proc_nrs;
4827
4828   (* Check tests. *)
4829   List.iter (
4830     function
4831       (* Ignore functions that have no tests.  We generate a
4832        * warning when the user does 'make check' instead.
4833        *)
4834     | name, _, _, _, [], _, _ -> ()
4835     | name, _, _, _, tests, _, _ ->
4836         let funcs =
4837           List.map (
4838             fun (_, _, test) ->
4839               match seq_of_test test with
4840               | [] ->
4841                   failwithf "%s has a test containing an empty sequence" name
4842               | cmds -> List.map List.hd cmds
4843           ) tests in
4844         let funcs = List.flatten funcs in
4845
4846         let tested = List.mem name funcs in
4847
4848         if not tested then
4849           failwithf "function %s has tests but does not test itself" name
4850   ) all_functions
4851
4852 (* 'pr' prints to the current output file. *)
4853 let chan = ref Pervasives.stdout
4854 let lines = ref 0
4855 let pr fs =
4856   ksprintf
4857     (fun str ->
4858        let i = count_chars '\n' str in
4859        lines := !lines + i;
4860        output_string !chan str
4861     ) fs
4862
4863 let copyright_years =
4864   let this_year = 1900 + (localtime (time ())).tm_year in
4865   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
4866
4867 (* Generate a header block in a number of standard styles. *)
4868 type comment_style =
4869     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
4870 type license = GPLv2plus | LGPLv2plus
4871
4872 let generate_header ?(extra_inputs = []) comment license =
4873   let inputs = "src/generator.ml" :: extra_inputs in
4874   let c = match comment with
4875     | CStyle ->         pr "/* "; " *"
4876     | CPlusPlusStyle -> pr "// "; "//"
4877     | HashStyle ->      pr "# ";  "#"
4878     | OCamlStyle ->     pr "(* "; " *"
4879     | HaskellStyle ->   pr "{- "; "  " in
4880   pr "libguestfs generated file\n";
4881   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
4882   List.iter (pr "%s   %s\n" c) inputs;
4883   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
4884   pr "%s\n" c;
4885   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
4886   pr "%s\n" c;
4887   (match license with
4888    | GPLv2plus ->
4889        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
4890        pr "%s it under the terms of the GNU General Public License as published by\n" c;
4891        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
4892        pr "%s (at your option) any later version.\n" c;
4893        pr "%s\n" c;
4894        pr "%s This program is distributed in the hope that it will be useful,\n" c;
4895        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4896        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
4897        pr "%s GNU General Public License for more details.\n" c;
4898        pr "%s\n" c;
4899        pr "%s You should have received a copy of the GNU General Public License along\n" c;
4900        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
4901        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
4902
4903    | LGPLv2plus ->
4904        pr "%s This library is free software; you can redistribute it and/or\n" c;
4905        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
4906        pr "%s License as published by the Free Software Foundation; either\n" c;
4907        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
4908        pr "%s\n" c;
4909        pr "%s This library is distributed in the hope that it will be useful,\n" c;
4910        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4911        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
4912        pr "%s Lesser General Public License for more details.\n" c;
4913        pr "%s\n" c;
4914        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
4915        pr "%s License along with this library; if not, write to the Free Software\n" c;
4916        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
4917   );
4918   (match comment with
4919    | CStyle -> pr " */\n"
4920    | CPlusPlusStyle
4921    | HashStyle -> ()
4922    | OCamlStyle -> pr " *)\n"
4923    | HaskellStyle -> pr "-}\n"
4924   );
4925   pr "\n"
4926
4927 (* Start of main code generation functions below this line. *)
4928
4929 (* Generate the pod documentation for the C API. *)
4930 let rec generate_actions_pod () =
4931   List.iter (
4932     fun (shortname, style, _, flags, _, _, longdesc) ->
4933       if not (List.mem NotInDocs flags) then (
4934         let name = "guestfs_" ^ shortname in
4935         pr "=head2 %s\n\n" name;
4936         pr " ";
4937         generate_prototype ~extern:false ~handle:"handle" name style;
4938         pr "\n\n";
4939         pr "%s\n\n" longdesc;
4940         (match fst style with
4941          | RErr ->
4942              pr "This function returns 0 on success or -1 on error.\n\n"
4943          | RInt _ ->
4944              pr "On error this function returns -1.\n\n"
4945          | RInt64 _ ->
4946              pr "On error this function returns -1.\n\n"
4947          | RBool _ ->
4948              pr "This function returns a C truth value on success or -1 on error.\n\n"
4949          | RConstString _ ->
4950              pr "This function returns a string, or NULL on error.
4951 The string is owned by the guest handle and must I<not> be freed.\n\n"
4952          | RConstOptString _ ->
4953              pr "This function returns a string which may be NULL.
4954 There is way to return an error from this function.
4955 The string is owned by the guest handle and must I<not> be freed.\n\n"
4956          | RString _ ->
4957              pr "This function returns a string, or NULL on error.
4958 I<The caller must free the returned string after use>.\n\n"
4959          | RStringList _ ->
4960              pr "This function returns a NULL-terminated array of strings
4961 (like L<environ(3)>), or NULL if there was an error.
4962 I<The caller must free the strings and the array after use>.\n\n"
4963          | RStruct (_, typ) ->
4964              pr "This function returns a C<struct guestfs_%s *>,
4965 or NULL if there was an error.
4966 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
4967          | RStructList (_, typ) ->
4968              pr "This function returns a C<struct guestfs_%s_list *>
4969 (see E<lt>guestfs-structs.hE<gt>),
4970 or NULL if there was an error.
4971 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
4972          | RHashtable _ ->
4973              pr "This function returns a NULL-terminated array of
4974 strings, or NULL if there was an error.
4975 The array of strings will always have length C<2n+1>, where
4976 C<n> keys and values alternate, followed by the trailing NULL entry.
4977 I<The caller must free the strings and the array after use>.\n\n"
4978          | RBufferOut _ ->
4979              pr "This function returns a buffer, or NULL on error.
4980 The size of the returned buffer is written to C<*size_r>.
4981 I<The caller must free the returned buffer after use>.\n\n"
4982         );
4983         if List.mem ProtocolLimitWarning flags then
4984           pr "%s\n\n" protocol_limit_warning;
4985         if List.mem DangerWillRobinson flags then
4986           pr "%s\n\n" danger_will_robinson;
4987         match deprecation_notice flags with
4988         | None -> ()
4989         | Some txt -> pr "%s\n\n" txt
4990       )
4991   ) all_functions_sorted
4992
4993 and generate_structs_pod () =
4994   (* Structs documentation. *)
4995   List.iter (
4996     fun (typ, cols) ->
4997       pr "=head2 guestfs_%s\n" typ;
4998       pr "\n";
4999       pr " struct guestfs_%s {\n" typ;
5000       List.iter (
5001         function
5002         | name, FChar -> pr "   char %s;\n" name
5003         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5004         | name, FInt32 -> pr "   int32_t %s;\n" name
5005         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5006         | name, FInt64 -> pr "   int64_t %s;\n" name
5007         | name, FString -> pr "   char *%s;\n" name
5008         | name, FBuffer ->
5009             pr "   /* The next two fields describe a byte array. */\n";
5010             pr "   uint32_t %s_len;\n" name;
5011             pr "   char *%s;\n" name
5012         | name, FUUID ->
5013             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5014             pr "   char %s[32];\n" name
5015         | name, FOptPercent ->
5016             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5017             pr "   float %s;\n" name
5018       ) cols;
5019       pr " };\n";
5020       pr " \n";
5021       pr " struct guestfs_%s_list {\n" typ;
5022       pr "   uint32_t len; /* Number of elements in list. */\n";
5023       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5024       pr " };\n";
5025       pr " \n";
5026       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5027       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5028         typ typ;
5029       pr "\n"
5030   ) structs
5031
5032 and generate_availability_pod () =
5033   (* Availability documentation. *)
5034   pr "=over 4\n";
5035   pr "\n";
5036   List.iter (
5037     fun (group, functions) ->
5038       pr "=item B<%s>\n" group;
5039       pr "\n";
5040       pr "The following functions:\n";
5041       List.iter (pr "L</guestfs_%s>\n") functions;
5042       pr "\n"
5043   ) optgroups;
5044   pr "=back\n";
5045   pr "\n"
5046
5047 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5048  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5049  *
5050  * We have to use an underscore instead of a dash because otherwise
5051  * rpcgen generates incorrect code.
5052  *
5053  * This header is NOT exported to clients, but see also generate_structs_h.
5054  *)
5055 and generate_xdr () =
5056   generate_header CStyle LGPLv2plus;
5057
5058   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5059   pr "typedef string str<>;\n";
5060   pr "\n";
5061
5062   (* Internal structures. *)
5063   List.iter (
5064     function
5065     | typ, cols ->
5066         pr "struct guestfs_int_%s {\n" typ;
5067         List.iter (function
5068                    | name, FChar -> pr "  char %s;\n" name
5069                    | name, FString -> pr "  string %s<>;\n" name
5070                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5071                    | name, FUUID -> pr "  opaque %s[32];\n" name
5072                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5073                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5074                    | name, FOptPercent -> pr "  float %s;\n" name
5075                   ) cols;
5076         pr "};\n";
5077         pr "\n";
5078         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5079         pr "\n";
5080   ) structs;
5081
5082   List.iter (
5083     fun (shortname, style, _, _, _, _, _) ->
5084       let name = "guestfs_" ^ shortname in
5085
5086       (match snd style with
5087        | [] -> ()
5088        | args ->
5089            pr "struct %s_args {\n" name;
5090            List.iter (
5091              function
5092              | Pathname n | Device n | Dev_or_Path n | String n ->
5093                  pr "  string %s<>;\n" n
5094              | OptString n -> pr "  str *%s;\n" n
5095              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5096              | Bool n -> pr "  bool %s;\n" n
5097              | Int n -> pr "  int %s;\n" n
5098              | Int64 n -> pr "  hyper %s;\n" n
5099              | FileIn _ | FileOut _ -> ()
5100            ) args;
5101            pr "};\n\n"
5102       );
5103       (match fst style with
5104        | RErr -> ()
5105        | RInt n ->
5106            pr "struct %s_ret {\n" name;
5107            pr "  int %s;\n" n;
5108            pr "};\n\n"
5109        | RInt64 n ->
5110            pr "struct %s_ret {\n" name;
5111            pr "  hyper %s;\n" n;
5112            pr "};\n\n"
5113        | RBool n ->
5114            pr "struct %s_ret {\n" name;
5115            pr "  bool %s;\n" n;
5116            pr "};\n\n"
5117        | RConstString _ | RConstOptString _ ->
5118            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5119        | RString n ->
5120            pr "struct %s_ret {\n" name;
5121            pr "  string %s<>;\n" n;
5122            pr "};\n\n"
5123        | RStringList n ->
5124            pr "struct %s_ret {\n" name;
5125            pr "  str %s<>;\n" n;
5126            pr "};\n\n"
5127        | RStruct (n, typ) ->
5128            pr "struct %s_ret {\n" name;
5129            pr "  guestfs_int_%s %s;\n" typ n;
5130            pr "};\n\n"
5131        | RStructList (n, typ) ->
5132            pr "struct %s_ret {\n" name;
5133            pr "  guestfs_int_%s_list %s;\n" typ n;
5134            pr "};\n\n"
5135        | RHashtable n ->
5136            pr "struct %s_ret {\n" name;
5137            pr "  str %s<>;\n" n;
5138            pr "};\n\n"
5139        | RBufferOut n ->
5140            pr "struct %s_ret {\n" name;
5141            pr "  opaque %s<>;\n" n;
5142            pr "};\n\n"
5143       );
5144   ) daemon_functions;
5145
5146   (* Table of procedure numbers. *)
5147   pr "enum guestfs_procedure {\n";
5148   List.iter (
5149     fun (shortname, _, proc_nr, _, _, _, _) ->
5150       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5151   ) daemon_functions;
5152   pr "  GUESTFS_PROC_NR_PROCS\n";
5153   pr "};\n";
5154   pr "\n";
5155
5156   (* Having to choose a maximum message size is annoying for several
5157    * reasons (it limits what we can do in the API), but it (a) makes
5158    * the protocol a lot simpler, and (b) provides a bound on the size
5159    * of the daemon which operates in limited memory space.  For large
5160    * file transfers you should use FTP.
5161    *)
5162   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5163   pr "\n";
5164
5165   (* Message header, etc. *)
5166   pr "\
5167 /* The communication protocol is now documented in the guestfs(3)
5168  * manpage.
5169  */
5170
5171 const GUESTFS_PROGRAM = 0x2000F5F5;
5172 const GUESTFS_PROTOCOL_VERSION = 1;
5173
5174 /* These constants must be larger than any possible message length. */
5175 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5176 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5177
5178 enum guestfs_message_direction {
5179   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5180   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5181 };
5182
5183 enum guestfs_message_status {
5184   GUESTFS_STATUS_OK = 0,
5185   GUESTFS_STATUS_ERROR = 1
5186 };
5187
5188 const GUESTFS_ERROR_LEN = 256;
5189
5190 struct guestfs_message_error {
5191   string error_message<GUESTFS_ERROR_LEN>;
5192 };
5193
5194 struct guestfs_message_header {
5195   unsigned prog;                     /* GUESTFS_PROGRAM */
5196   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5197   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5198   guestfs_message_direction direction;
5199   unsigned serial;                   /* message serial number */
5200   guestfs_message_status status;
5201 };
5202
5203 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5204
5205 struct guestfs_chunk {
5206   int cancel;                        /* if non-zero, transfer is cancelled */
5207   /* data size is 0 bytes if the transfer has finished successfully */
5208   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5209 };
5210 "
5211
5212 (* Generate the guestfs-structs.h file. *)
5213 and generate_structs_h () =
5214   generate_header CStyle LGPLv2plus;
5215
5216   (* This is a public exported header file containing various
5217    * structures.  The structures are carefully written to have
5218    * exactly the same in-memory format as the XDR structures that
5219    * we use on the wire to the daemon.  The reason for creating
5220    * copies of these structures here is just so we don't have to
5221    * export the whole of guestfs_protocol.h (which includes much
5222    * unrelated and XDR-dependent stuff that we don't want to be
5223    * public, or required by clients).
5224    *
5225    * To reiterate, we will pass these structures to and from the
5226    * client with a simple assignment or memcpy, so the format
5227    * must be identical to what rpcgen / the RFC defines.
5228    *)
5229
5230   (* Public structures. *)
5231   List.iter (
5232     fun (typ, cols) ->
5233       pr "struct guestfs_%s {\n" typ;
5234       List.iter (
5235         function
5236         | name, FChar -> pr "  char %s;\n" name
5237         | name, FString -> pr "  char *%s;\n" name
5238         | name, FBuffer ->
5239             pr "  uint32_t %s_len;\n" name;
5240             pr "  char *%s;\n" name
5241         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5242         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5243         | name, FInt32 -> pr "  int32_t %s;\n" name
5244         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5245         | name, FInt64 -> pr "  int64_t %s;\n" name
5246         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5247       ) cols;
5248       pr "};\n";
5249       pr "\n";
5250       pr "struct guestfs_%s_list {\n" typ;
5251       pr "  uint32_t len;\n";
5252       pr "  struct guestfs_%s *val;\n" typ;
5253       pr "};\n";
5254       pr "\n";
5255       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5256       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5257       pr "\n"
5258   ) structs
5259
5260 (* Generate the guestfs-actions.h file. *)
5261 and generate_actions_h () =
5262   generate_header CStyle LGPLv2plus;
5263   List.iter (
5264     fun (shortname, style, _, _, _, _, _) ->
5265       let name = "guestfs_" ^ shortname in
5266       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5267         name style
5268   ) all_functions
5269
5270 (* Generate the guestfs-internal-actions.h file. *)
5271 and generate_internal_actions_h () =
5272   generate_header CStyle LGPLv2plus;
5273   List.iter (
5274     fun (shortname, style, _, _, _, _, _) ->
5275       let name = "guestfs__" ^ shortname in
5276       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5277         name style
5278   ) non_daemon_functions
5279
5280 (* Generate the client-side dispatch stubs. *)
5281 and generate_client_actions () =
5282   generate_header CStyle LGPLv2plus;
5283
5284   pr "\
5285 #include <stdio.h>
5286 #include <stdlib.h>
5287 #include <stdint.h>
5288 #include <inttypes.h>
5289
5290 #include \"guestfs.h\"
5291 #include \"guestfs-internal.h\"
5292 #include \"guestfs-internal-actions.h\"
5293 #include \"guestfs_protocol.h\"
5294
5295 #define error guestfs_error
5296 //#define perrorf guestfs_perrorf
5297 #define safe_malloc guestfs_safe_malloc
5298 #define safe_realloc guestfs_safe_realloc
5299 //#define safe_strdup guestfs_safe_strdup
5300 #define safe_memdup guestfs_safe_memdup
5301
5302 /* Check the return message from a call for validity. */
5303 static int
5304 check_reply_header (guestfs_h *g,
5305                     const struct guestfs_message_header *hdr,
5306                     unsigned int proc_nr, unsigned int serial)
5307 {
5308   if (hdr->prog != GUESTFS_PROGRAM) {
5309     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5310     return -1;
5311   }
5312   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5313     error (g, \"wrong protocol version (%%d/%%d)\",
5314            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5315     return -1;
5316   }
5317   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5318     error (g, \"unexpected message direction (%%d/%%d)\",
5319            hdr->direction, GUESTFS_DIRECTION_REPLY);
5320     return -1;
5321   }
5322   if (hdr->proc != proc_nr) {
5323     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5324     return -1;
5325   }
5326   if (hdr->serial != serial) {
5327     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5328     return -1;
5329   }
5330
5331   return 0;
5332 }
5333
5334 /* Check we are in the right state to run a high-level action. */
5335 static int
5336 check_state (guestfs_h *g, const char *caller)
5337 {
5338   if (!guestfs__is_ready (g)) {
5339     if (guestfs__is_config (g) || guestfs__is_launching (g))
5340       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5341         caller);
5342     else
5343       error (g, \"%%s called from the wrong state, %%d != READY\",
5344         caller, guestfs__get_state (g));
5345     return -1;
5346   }
5347   return 0;
5348 }
5349
5350 ";
5351
5352   (* Generate code to generate guestfish call traces. *)
5353   let trace_call shortname style =
5354     pr "  if (guestfs__get_trace (g)) {\n";
5355
5356     let needs_i =
5357       List.exists (function
5358                    | StringList _ | DeviceList _ -> true
5359                    | _ -> false) (snd style) in
5360     if needs_i then (
5361       pr "    int i;\n";
5362       pr "\n"
5363     );
5364
5365     pr "    printf (\"%s\");\n" shortname;
5366     List.iter (
5367       function
5368       | String n                        (* strings *)
5369       | Device n
5370       | Pathname n
5371       | Dev_or_Path n
5372       | FileIn n
5373       | FileOut n ->
5374           (* guestfish doesn't support string escaping, so neither do we *)
5375           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5376       | OptString n ->                  (* string option *)
5377           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5378           pr "    else printf (\" null\");\n"
5379       | StringList n
5380       | DeviceList n ->                 (* string list *)
5381           pr "    putchar (' ');\n";
5382           pr "    putchar ('\"');\n";
5383           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5384           pr "      if (i > 0) putchar (' ');\n";
5385           pr "      fputs (%s[i], stdout);\n" n;
5386           pr "    }\n";
5387           pr "    putchar ('\"');\n";
5388       | Bool n ->                       (* boolean *)
5389           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5390       | Int n ->                        (* int *)
5391           pr "    printf (\" %%d\", %s);\n" n
5392       | Int64 n ->
5393           pr "    printf (\" %%\" PRIi64, %s);\n" n
5394     ) (snd style);
5395     pr "    putchar ('\\n');\n";
5396     pr "  }\n";
5397     pr "\n";
5398   in
5399
5400   (* For non-daemon functions, generate a wrapper around each function. *)
5401   List.iter (
5402     fun (shortname, style, _, _, _, _, _) ->
5403       let name = "guestfs_" ^ shortname in
5404
5405       generate_prototype ~extern:false ~semicolon:false ~newline:true
5406         ~handle:"g" name style;
5407       pr "{\n";
5408       trace_call shortname style;
5409       pr "  return guestfs__%s " shortname;
5410       generate_c_call_args ~handle:"g" style;
5411       pr ";\n";
5412       pr "}\n";
5413       pr "\n"
5414   ) non_daemon_functions;
5415
5416   (* Client-side stubs for each function. *)
5417   List.iter (
5418     fun (shortname, style, _, _, _, _, _) ->
5419       let name = "guestfs_" ^ shortname in
5420
5421       (* Generate the action stub. *)
5422       generate_prototype ~extern:false ~semicolon:false ~newline:true
5423         ~handle:"g" name style;
5424
5425       let error_code =
5426         match fst style with
5427         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5428         | RConstString _ | RConstOptString _ ->
5429             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5430         | RString _ | RStringList _
5431         | RStruct _ | RStructList _
5432         | RHashtable _ | RBufferOut _ ->
5433             "NULL" in
5434
5435       pr "{\n";
5436
5437       (match snd style with
5438        | [] -> ()
5439        | _ -> pr "  struct %s_args args;\n" name
5440       );
5441
5442       pr "  guestfs_message_header hdr;\n";
5443       pr "  guestfs_message_error err;\n";
5444       let has_ret =
5445         match fst style with
5446         | RErr -> false
5447         | RConstString _ | RConstOptString _ ->
5448             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5449         | RInt _ | RInt64 _
5450         | RBool _ | RString _ | RStringList _
5451         | RStruct _ | RStructList _
5452         | RHashtable _ | RBufferOut _ ->
5453             pr "  struct %s_ret ret;\n" name;
5454             true in
5455
5456       pr "  int serial;\n";
5457       pr "  int r;\n";
5458       pr "\n";
5459       trace_call shortname style;
5460       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
5461       pr "  guestfs___set_busy (g);\n";
5462       pr "\n";
5463
5464       (* Send the main header and arguments. *)
5465       (match snd style with
5466        | [] ->
5467            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5468              (String.uppercase shortname)
5469        | args ->
5470            List.iter (
5471              function
5472              | Pathname n | Device n | Dev_or_Path n | String n ->
5473                  pr "  args.%s = (char *) %s;\n" n n
5474              | OptString n ->
5475                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5476              | StringList n | DeviceList n ->
5477                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5478                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5479              | Bool n ->
5480                  pr "  args.%s = %s;\n" n n
5481              | Int n ->
5482                  pr "  args.%s = %s;\n" n n
5483              | Int64 n ->
5484                  pr "  args.%s = %s;\n" n n
5485              | FileIn _ | FileOut _ -> ()
5486            ) args;
5487            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5488              (String.uppercase shortname);
5489            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5490              name;
5491       );
5492       pr "  if (serial == -1) {\n";
5493       pr "    guestfs___end_busy (g);\n";
5494       pr "    return %s;\n" error_code;
5495       pr "  }\n";
5496       pr "\n";
5497
5498       (* Send any additional files (FileIn) requested. *)
5499       let need_read_reply_label = ref false in
5500       List.iter (
5501         function
5502         | FileIn n ->
5503             pr "  r = guestfs___send_file (g, %s);\n" n;
5504             pr "  if (r == -1) {\n";
5505             pr "    guestfs___end_busy (g);\n";
5506             pr "    return %s;\n" error_code;
5507             pr "  }\n";
5508             pr "  if (r == -2) /* daemon cancelled */\n";
5509             pr "    goto read_reply;\n";
5510             need_read_reply_label := true;
5511             pr "\n";
5512         | _ -> ()
5513       ) (snd style);
5514
5515       (* Wait for the reply from the remote end. *)
5516       if !need_read_reply_label then pr " read_reply:\n";
5517       pr "  memset (&hdr, 0, sizeof hdr);\n";
5518       pr "  memset (&err, 0, sizeof err);\n";
5519       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5520       pr "\n";
5521       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5522       if not has_ret then
5523         pr "NULL, NULL"
5524       else
5525         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5526       pr ");\n";
5527
5528       pr "  if (r == -1) {\n";
5529       pr "    guestfs___end_busy (g);\n";
5530       pr "    return %s;\n" error_code;
5531       pr "  }\n";
5532       pr "\n";
5533
5534       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5535         (String.uppercase shortname);
5536       pr "    guestfs___end_busy (g);\n";
5537       pr "    return %s;\n" error_code;
5538       pr "  }\n";
5539       pr "\n";
5540
5541       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5542       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5543       pr "    free (err.error_message);\n";
5544       pr "    guestfs___end_busy (g);\n";
5545       pr "    return %s;\n" error_code;
5546       pr "  }\n";
5547       pr "\n";
5548
5549       (* Expecting to receive further files (FileOut)? *)
5550       List.iter (
5551         function
5552         | FileOut n ->
5553             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5554             pr "    guestfs___end_busy (g);\n";
5555             pr "    return %s;\n" error_code;
5556             pr "  }\n";
5557             pr "\n";
5558         | _ -> ()
5559       ) (snd style);
5560
5561       pr "  guestfs___end_busy (g);\n";
5562
5563       (match fst style with
5564        | RErr -> pr "  return 0;\n"
5565        | RInt n | RInt64 n | RBool n ->
5566            pr "  return ret.%s;\n" n
5567        | RConstString _ | RConstOptString _ ->
5568            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5569        | RString n ->
5570            pr "  return ret.%s; /* caller will free */\n" n
5571        | RStringList n | RHashtable n ->
5572            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5573            pr "  ret.%s.%s_val =\n" n n;
5574            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5575            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5576              n n;
5577            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5578            pr "  return ret.%s.%s_val;\n" n n
5579        | RStruct (n, _) ->
5580            pr "  /* caller will free this */\n";
5581            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5582        | RStructList (n, _) ->
5583            pr "  /* caller will free this */\n";
5584            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5585        | RBufferOut n ->
5586            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5587            pr "   * _val might be NULL here.  To make the API saner for\n";
5588            pr "   * callers, we turn this case into a unique pointer (using\n";
5589            pr "   * malloc(1)).\n";
5590            pr "   */\n";
5591            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5592            pr "    *size_r = ret.%s.%s_len;\n" n n;
5593            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5594            pr "  } else {\n";
5595            pr "    free (ret.%s.%s_val);\n" n n;
5596            pr "    char *p = safe_malloc (g, 1);\n";
5597            pr "    *size_r = ret.%s.%s_len;\n" n n;
5598            pr "    return p;\n";
5599            pr "  }\n";
5600       );
5601
5602       pr "}\n\n"
5603   ) daemon_functions;
5604
5605   (* Functions to free structures. *)
5606   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5607   pr " * structure format is identical to the XDR format.  See note in\n";
5608   pr " * generator.ml.\n";
5609   pr " */\n";
5610   pr "\n";
5611
5612   List.iter (
5613     fun (typ, _) ->
5614       pr "void\n";
5615       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5616       pr "{\n";
5617       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5618       pr "  free (x);\n";
5619       pr "}\n";
5620       pr "\n";
5621
5622       pr "void\n";
5623       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5624       pr "{\n";
5625       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
5626       pr "  free (x);\n";
5627       pr "}\n";
5628       pr "\n";
5629
5630   ) structs;
5631
5632 (* Generate daemon/actions.h. *)
5633 and generate_daemon_actions_h () =
5634   generate_header CStyle GPLv2plus;
5635
5636   pr "#include \"../src/guestfs_protocol.h\"\n";
5637   pr "\n";
5638
5639   List.iter (
5640     fun (name, style, _, _, _, _, _) ->
5641       generate_prototype
5642         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
5643         name style;
5644   ) daemon_functions
5645
5646 (* Generate the linker script which controls the visibility of
5647  * symbols in the public ABI and ensures no other symbols get
5648  * exported accidentally.
5649  *)
5650 and generate_linker_script () =
5651   generate_header HashStyle GPLv2plus;
5652
5653   let globals = [
5654     "guestfs_create";
5655     "guestfs_close";
5656     "guestfs_get_error_handler";
5657     "guestfs_get_out_of_memory_handler";
5658     "guestfs_last_error";
5659     "guestfs_set_error_handler";
5660     "guestfs_set_launch_done_callback";
5661     "guestfs_set_log_message_callback";
5662     "guestfs_set_out_of_memory_handler";
5663     "guestfs_set_subprocess_quit_callback";
5664
5665     (* Unofficial parts of the API: the bindings code use these
5666      * functions, so it is useful to export them.
5667      *)
5668     "guestfs_safe_calloc";
5669     "guestfs_safe_malloc";
5670   ] in
5671   let functions =
5672     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
5673       all_functions in
5674   let structs =
5675     List.concat (
5676       List.map (fun (typ, _) ->
5677                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
5678         structs
5679     ) in
5680   let globals = List.sort compare (globals @ functions @ structs) in
5681
5682   pr "{\n";
5683   pr "    global:\n";
5684   List.iter (pr "        %s;\n") globals;
5685   pr "\n";
5686
5687   pr "    local:\n";
5688   pr "        *;\n";
5689   pr "};\n"
5690
5691 (* Generate the server-side stubs. *)
5692 and generate_daemon_actions () =
5693   generate_header CStyle GPLv2plus;
5694
5695   pr "#include <config.h>\n";
5696   pr "\n";
5697   pr "#include <stdio.h>\n";
5698   pr "#include <stdlib.h>\n";
5699   pr "#include <string.h>\n";
5700   pr "#include <inttypes.h>\n";
5701   pr "#include <rpc/types.h>\n";
5702   pr "#include <rpc/xdr.h>\n";
5703   pr "\n";
5704   pr "#include \"daemon.h\"\n";
5705   pr "#include \"c-ctype.h\"\n";
5706   pr "#include \"../src/guestfs_protocol.h\"\n";
5707   pr "#include \"actions.h\"\n";
5708   pr "\n";
5709
5710   List.iter (
5711     fun (name, style, _, _, _, _, _) ->
5712       (* Generate server-side stubs. *)
5713       pr "static void %s_stub (XDR *xdr_in)\n" name;
5714       pr "{\n";
5715       let error_code =
5716         match fst style with
5717         | RErr | RInt _ -> pr "  int r;\n"; "-1"
5718         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5719         | RBool _ -> pr "  int r;\n"; "-1"
5720         | RConstString _ | RConstOptString _ ->
5721             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5722         | RString _ -> pr "  char *r;\n"; "NULL"
5723         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5724         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
5725         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
5726         | RBufferOut _ ->
5727             pr "  size_t size = 1;\n";
5728             pr "  char *r;\n";
5729             "NULL" in
5730
5731       (match snd style with
5732        | [] -> ()
5733        | args ->
5734            pr "  struct guestfs_%s_args args;\n" name;
5735            List.iter (
5736              function
5737              | Device n | Dev_or_Path n
5738              | Pathname n
5739              | String n -> ()
5740              | OptString n -> pr "  char *%s;\n" n
5741              | StringList n | DeviceList n -> pr "  char **%s;\n" n
5742              | Bool n -> pr "  int %s;\n" n
5743              | Int n -> pr "  int %s;\n" n
5744              | Int64 n -> pr "  int64_t %s;\n" n
5745              | FileIn _ | FileOut _ -> ()
5746            ) args
5747       );
5748       pr "\n";
5749
5750       (match snd style with
5751        | [] -> ()
5752        | args ->
5753            pr "  memset (&args, 0, sizeof args);\n";
5754            pr "\n";
5755            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
5756            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
5757            pr "    return;\n";
5758            pr "  }\n";
5759            let pr_args n =
5760              pr "  char *%s = args.%s;\n" n n
5761            in
5762            let pr_list_handling_code n =
5763              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
5764              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
5765              pr "  if (%s == NULL) {\n" n;
5766              pr "    reply_with_perror (\"realloc\");\n";
5767              pr "    goto done;\n";
5768              pr "  }\n";
5769              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
5770              pr "  args.%s.%s_val = %s;\n" n n n;
5771            in
5772            List.iter (
5773              function
5774              | Pathname n ->
5775                  pr_args n;
5776                  pr "  ABS_PATH (%s, goto done);\n" n;
5777              | Device n ->
5778                  pr_args n;
5779                  pr "  RESOLVE_DEVICE (%s, goto done);\n" n;
5780              | Dev_or_Path n ->
5781                  pr_args n;
5782                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n;
5783              | String n -> pr_args n
5784              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
5785              | StringList n ->
5786                  pr_list_handling_code n;
5787              | DeviceList n ->
5788                  pr_list_handling_code n;
5789                  pr "  /* Ensure that each is a device,\n";
5790                  pr "   * and perform device name translation. */\n";
5791                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
5792                  pr "    RESOLVE_DEVICE (physvols[pvi], goto done);\n";
5793                  pr "  }\n";
5794              | Bool n -> pr "  %s = args.%s;\n" n n
5795              | Int n -> pr "  %s = args.%s;\n" n n
5796              | Int64 n -> pr "  %s = args.%s;\n" n n
5797              | FileIn _ | FileOut _ -> ()
5798            ) args;
5799            pr "\n"
5800       );
5801
5802
5803       (* this is used at least for do_equal *)
5804       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
5805         (* Emit NEED_ROOT just once, even when there are two or
5806            more Pathname args *)
5807         pr "  NEED_ROOT (goto done);\n";
5808       );
5809
5810       (* Don't want to call the impl with any FileIn or FileOut
5811        * parameters, since these go "outside" the RPC protocol.
5812        *)
5813       let args' =
5814         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
5815           (snd style) in
5816       pr "  r = do_%s " name;
5817       generate_c_call_args (fst style, args');
5818       pr ";\n";
5819
5820       (match fst style with
5821        | RErr | RInt _ | RInt64 _ | RBool _
5822        | RConstString _ | RConstOptString _
5823        | RString _ | RStringList _ | RHashtable _
5824        | RStruct (_, _) | RStructList (_, _) ->
5825            pr "  if (r == %s)\n" error_code;
5826            pr "    /* do_%s has already called reply_with_error */\n" name;
5827            pr "    goto done;\n";
5828            pr "\n"
5829        | RBufferOut _ ->
5830            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
5831            pr "   * an ordinary zero-length buffer), so be careful ...\n";
5832            pr "   */\n";
5833            pr "  if (size == 1 && r == %s)\n" error_code;
5834            pr "    /* do_%s has already called reply_with_error */\n" name;
5835            pr "    goto done;\n";
5836            pr "\n"
5837       );
5838
5839       (* If there are any FileOut parameters, then the impl must
5840        * send its own reply.
5841        *)
5842       let no_reply =
5843         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
5844       if no_reply then
5845         pr "  /* do_%s has already sent a reply */\n" name
5846       else (
5847         match fst style with
5848         | RErr -> pr "  reply (NULL, NULL);\n"
5849         | RInt n | RInt64 n | RBool n ->
5850             pr "  struct guestfs_%s_ret ret;\n" name;
5851             pr "  ret.%s = r;\n" n;
5852             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5853               name
5854         | RConstString _ | RConstOptString _ ->
5855             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5856         | RString n ->
5857             pr "  struct guestfs_%s_ret ret;\n" name;
5858             pr "  ret.%s = r;\n" n;
5859             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5860               name;
5861             pr "  free (r);\n"
5862         | RStringList n | RHashtable n ->
5863             pr "  struct guestfs_%s_ret ret;\n" name;
5864             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
5865             pr "  ret.%s.%s_val = r;\n" n n;
5866             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5867               name;
5868             pr "  free_strings (r);\n"
5869         | RStruct (n, _) ->
5870             pr "  struct guestfs_%s_ret ret;\n" name;
5871             pr "  ret.%s = *r;\n" n;
5872             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5873               name;
5874             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5875               name
5876         | RStructList (n, _) ->
5877             pr "  struct guestfs_%s_ret ret;\n" name;
5878             pr "  ret.%s = *r;\n" n;
5879             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5880               name;
5881             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5882               name
5883         | RBufferOut n ->
5884             pr "  struct guestfs_%s_ret ret;\n" name;
5885             pr "  ret.%s.%s_val = r;\n" n n;
5886             pr "  ret.%s.%s_len = size;\n" n n;
5887             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5888               name;
5889             pr "  free (r);\n"
5890       );
5891
5892       (* Free the args. *)
5893       (match snd style with
5894        | [] ->
5895            pr "done: ;\n";
5896        | _ ->
5897            pr "done:\n";
5898            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
5899              name
5900       );
5901
5902       pr "}\n\n";
5903   ) daemon_functions;
5904
5905   (* Dispatch function. *)
5906   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
5907   pr "{\n";
5908   pr "  switch (proc_nr) {\n";
5909
5910   List.iter (
5911     fun (name, style, _, _, _, _, _) ->
5912       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
5913       pr "      %s_stub (xdr_in);\n" name;
5914       pr "      break;\n"
5915   ) daemon_functions;
5916
5917   pr "    default:\n";
5918   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";
5919   pr "  }\n";
5920   pr "}\n";
5921   pr "\n";
5922
5923   (* LVM columns and tokenization functions. *)
5924   (* XXX This generates crap code.  We should rethink how we
5925    * do this parsing.
5926    *)
5927   List.iter (
5928     function
5929     | typ, cols ->
5930         pr "static const char *lvm_%s_cols = \"%s\";\n"
5931           typ (String.concat "," (List.map fst cols));
5932         pr "\n";
5933
5934         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
5935         pr "{\n";
5936         pr "  char *tok, *p, *next;\n";
5937         pr "  int i, j;\n";
5938         pr "\n";
5939         (*
5940           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
5941           pr "\n";
5942         *)
5943         pr "  if (!str) {\n";
5944         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
5945         pr "    return -1;\n";
5946         pr "  }\n";
5947         pr "  if (!*str || c_isspace (*str)) {\n";
5948         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
5949         pr "    return -1;\n";
5950         pr "  }\n";
5951         pr "  tok = str;\n";
5952         List.iter (
5953           fun (name, coltype) ->
5954             pr "  if (!tok) {\n";
5955             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
5956             pr "    return -1;\n";
5957             pr "  }\n";
5958             pr "  p = strchrnul (tok, ',');\n";
5959             pr "  if (*p) next = p+1; else next = NULL;\n";
5960             pr "  *p = '\\0';\n";
5961             (match coltype with
5962              | FString ->
5963                  pr "  r->%s = strdup (tok);\n" name;
5964                  pr "  if (r->%s == NULL) {\n" name;
5965                  pr "    perror (\"strdup\");\n";
5966                  pr "    return -1;\n";
5967                  pr "  }\n"
5968              | FUUID ->
5969                  pr "  for (i = j = 0; i < 32; ++j) {\n";
5970                  pr "    if (tok[j] == '\\0') {\n";
5971                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
5972                  pr "      return -1;\n";
5973                  pr "    } else if (tok[j] != '-')\n";
5974                  pr "      r->%s[i++] = tok[j];\n" name;
5975                  pr "  }\n";
5976              | FBytes ->
5977                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
5978                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5979                  pr "    return -1;\n";
5980                  pr "  }\n";
5981              | FInt64 ->
5982                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
5983                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5984                  pr "    return -1;\n";
5985                  pr "  }\n";
5986              | FOptPercent ->
5987                  pr "  if (tok[0] == '\\0')\n";
5988                  pr "    r->%s = -1;\n" name;
5989                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
5990                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5991                  pr "    return -1;\n";
5992                  pr "  }\n";
5993              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
5994                  assert false (* can never be an LVM column *)
5995             );
5996             pr "  tok = next;\n";
5997         ) cols;
5998
5999         pr "  if (tok != NULL) {\n";
6000         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6001         pr "    return -1;\n";
6002         pr "  }\n";
6003         pr "  return 0;\n";
6004         pr "}\n";
6005         pr "\n";
6006
6007         pr "guestfs_int_lvm_%s_list *\n" typ;
6008         pr "parse_command_line_%ss (void)\n" typ;
6009         pr "{\n";
6010         pr "  char *out, *err;\n";
6011         pr "  char *p, *pend;\n";
6012         pr "  int r, i;\n";
6013         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6014         pr "  void *newp;\n";
6015         pr "\n";
6016         pr "  ret = malloc (sizeof *ret);\n";
6017         pr "  if (!ret) {\n";
6018         pr "    reply_with_perror (\"malloc\");\n";
6019         pr "    return NULL;\n";
6020         pr "  }\n";
6021         pr "\n";
6022         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6023         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6024         pr "\n";
6025         pr "  r = command (&out, &err,\n";
6026         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
6027         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6028         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6029         pr "  if (r == -1) {\n";
6030         pr "    reply_with_error (\"%%s\", err);\n";
6031         pr "    free (out);\n";
6032         pr "    free (err);\n";
6033         pr "    free (ret);\n";
6034         pr "    return NULL;\n";
6035         pr "  }\n";
6036         pr "\n";
6037         pr "  free (err);\n";
6038         pr "\n";
6039         pr "  /* Tokenize each line of the output. */\n";
6040         pr "  p = out;\n";
6041         pr "  i = 0;\n";
6042         pr "  while (p) {\n";
6043         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6044         pr "    if (pend) {\n";
6045         pr "      *pend = '\\0';\n";
6046         pr "      pend++;\n";
6047         pr "    }\n";
6048         pr "\n";
6049         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6050         pr "      p++;\n";
6051         pr "\n";
6052         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6053         pr "      p = pend;\n";
6054         pr "      continue;\n";
6055         pr "    }\n";
6056         pr "\n";
6057         pr "    /* Allocate some space to store this next entry. */\n";
6058         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6059         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6060         pr "    if (newp == NULL) {\n";
6061         pr "      reply_with_perror (\"realloc\");\n";
6062         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6063         pr "      free (ret);\n";
6064         pr "      free (out);\n";
6065         pr "      return NULL;\n";
6066         pr "    }\n";
6067         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6068         pr "\n";
6069         pr "    /* Tokenize the next entry. */\n";
6070         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6071         pr "    if (r == -1) {\n";
6072         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6073         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6074         pr "      free (ret);\n";
6075         pr "      free (out);\n";
6076         pr "      return NULL;\n";
6077         pr "    }\n";
6078         pr "\n";
6079         pr "    ++i;\n";
6080         pr "    p = pend;\n";
6081         pr "  }\n";
6082         pr "\n";
6083         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6084         pr "\n";
6085         pr "  free (out);\n";
6086         pr "  return ret;\n";
6087         pr "}\n"
6088
6089   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6090
6091 (* Generate a list of function names, for debugging in the daemon.. *)
6092 and generate_daemon_names () =
6093   generate_header CStyle GPLv2plus;
6094
6095   pr "#include <config.h>\n";
6096   pr "\n";
6097   pr "#include \"daemon.h\"\n";
6098   pr "\n";
6099
6100   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6101   pr "const char *function_names[] = {\n";
6102   List.iter (
6103     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6104   ) daemon_functions;
6105   pr "};\n";
6106
6107 (* Generate the optional groups for the daemon to implement
6108  * guestfs_available.
6109  *)
6110 and generate_daemon_optgroups_c () =
6111   generate_header CStyle GPLv2plus;
6112
6113   pr "#include <config.h>\n";
6114   pr "\n";
6115   pr "#include \"daemon.h\"\n";
6116   pr "#include \"optgroups.h\"\n";
6117   pr "\n";
6118
6119   pr "struct optgroup optgroups[] = {\n";
6120   List.iter (
6121     fun (group, _) ->
6122       pr "  { \"%s\", optgroup_%s_available },\n" group group
6123   ) optgroups;
6124   pr "  { NULL, NULL }\n";
6125   pr "};\n"
6126
6127 and generate_daemon_optgroups_h () =
6128   generate_header CStyle GPLv2plus;
6129
6130   List.iter (
6131     fun (group, _) ->
6132       pr "extern int optgroup_%s_available (void);\n" group
6133   ) optgroups
6134
6135 (* Generate the tests. *)
6136 and generate_tests () =
6137   generate_header CStyle GPLv2plus;
6138
6139   pr "\
6140 #include <stdio.h>
6141 #include <stdlib.h>
6142 #include <string.h>
6143 #include <unistd.h>
6144 #include <sys/types.h>
6145 #include <fcntl.h>
6146
6147 #include \"guestfs.h\"
6148 #include \"guestfs-internal.h\"
6149
6150 static guestfs_h *g;
6151 static int suppress_error = 0;
6152
6153 static void print_error (guestfs_h *g, void *data, const char *msg)
6154 {
6155   if (!suppress_error)
6156     fprintf (stderr, \"%%s\\n\", msg);
6157 }
6158
6159 /* FIXME: nearly identical code appears in fish.c */
6160 static void print_strings (char *const *argv)
6161 {
6162   int argc;
6163
6164   for (argc = 0; argv[argc] != NULL; ++argc)
6165     printf (\"\\t%%s\\n\", argv[argc]);
6166 }
6167
6168 /*
6169 static void print_table (char const *const *argv)
6170 {
6171   int i;
6172
6173   for (i = 0; argv[i] != NULL; i += 2)
6174     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6175 }
6176 */
6177
6178 ";
6179
6180   (* Generate a list of commands which are not tested anywhere. *)
6181   pr "static void no_test_warnings (void)\n";
6182   pr "{\n";
6183
6184   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6185   List.iter (
6186     fun (_, _, _, _, tests, _, _) ->
6187       let tests = filter_map (
6188         function
6189         | (_, (Always|If _|Unless _), test) -> Some test
6190         | (_, Disabled, _) -> None
6191       ) tests in
6192       let seq = List.concat (List.map seq_of_test tests) in
6193       let cmds_tested = List.map List.hd seq in
6194       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6195   ) all_functions;
6196
6197   List.iter (
6198     fun (name, _, _, _, _, _, _) ->
6199       if not (Hashtbl.mem hash name) then
6200         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6201   ) all_functions;
6202
6203   pr "}\n";
6204   pr "\n";
6205
6206   (* Generate the actual tests.  Note that we generate the tests
6207    * in reverse order, deliberately, so that (in general) the
6208    * newest tests run first.  This makes it quicker and easier to
6209    * debug them.
6210    *)
6211   let test_names =
6212     List.map (
6213       fun (name, _, _, flags, tests, _, _) ->
6214         mapi (generate_one_test name flags) tests
6215     ) (List.rev all_functions) in
6216   let test_names = List.concat test_names in
6217   let nr_tests = List.length test_names in
6218
6219   pr "\
6220 int main (int argc, char *argv[])
6221 {
6222   char c = 0;
6223   unsigned long int n_failed = 0;
6224   const char *filename;
6225   int fd;
6226   int nr_tests, test_num = 0;
6227
6228   setbuf (stdout, NULL);
6229
6230   no_test_warnings ();
6231
6232   g = guestfs_create ();
6233   if (g == NULL) {
6234     printf (\"guestfs_create FAILED\\n\");
6235     exit (EXIT_FAILURE);
6236   }
6237
6238   guestfs_set_error_handler (g, print_error, NULL);
6239
6240   guestfs_set_path (g, \"../appliance\");
6241
6242   filename = \"test1.img\";
6243   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6244   if (fd == -1) {
6245     perror (filename);
6246     exit (EXIT_FAILURE);
6247   }
6248   if (lseek (fd, %d, SEEK_SET) == -1) {
6249     perror (\"lseek\");
6250     close (fd);
6251     unlink (filename);
6252     exit (EXIT_FAILURE);
6253   }
6254   if (write (fd, &c, 1) == -1) {
6255     perror (\"write\");
6256     close (fd);
6257     unlink (filename);
6258     exit (EXIT_FAILURE);
6259   }
6260   if (close (fd) == -1) {
6261     perror (filename);
6262     unlink (filename);
6263     exit (EXIT_FAILURE);
6264   }
6265   if (guestfs_add_drive (g, filename) == -1) {
6266     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6267     exit (EXIT_FAILURE);
6268   }
6269
6270   filename = \"test2.img\";
6271   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6272   if (fd == -1) {
6273     perror (filename);
6274     exit (EXIT_FAILURE);
6275   }
6276   if (lseek (fd, %d, SEEK_SET) == -1) {
6277     perror (\"lseek\");
6278     close (fd);
6279     unlink (filename);
6280     exit (EXIT_FAILURE);
6281   }
6282   if (write (fd, &c, 1) == -1) {
6283     perror (\"write\");
6284     close (fd);
6285     unlink (filename);
6286     exit (EXIT_FAILURE);
6287   }
6288   if (close (fd) == -1) {
6289     perror (filename);
6290     unlink (filename);
6291     exit (EXIT_FAILURE);
6292   }
6293   if (guestfs_add_drive (g, filename) == -1) {
6294     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6295     exit (EXIT_FAILURE);
6296   }
6297
6298   filename = \"test3.img\";
6299   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6300   if (fd == -1) {
6301     perror (filename);
6302     exit (EXIT_FAILURE);
6303   }
6304   if (lseek (fd, %d, SEEK_SET) == -1) {
6305     perror (\"lseek\");
6306     close (fd);
6307     unlink (filename);
6308     exit (EXIT_FAILURE);
6309   }
6310   if (write (fd, &c, 1) == -1) {
6311     perror (\"write\");
6312     close (fd);
6313     unlink (filename);
6314     exit (EXIT_FAILURE);
6315   }
6316   if (close (fd) == -1) {
6317     perror (filename);
6318     unlink (filename);
6319     exit (EXIT_FAILURE);
6320   }
6321   if (guestfs_add_drive (g, filename) == -1) {
6322     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6323     exit (EXIT_FAILURE);
6324   }
6325
6326   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6327     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6328     exit (EXIT_FAILURE);
6329   }
6330
6331   if (guestfs_launch (g) == -1) {
6332     printf (\"guestfs_launch FAILED\\n\");
6333     exit (EXIT_FAILURE);
6334   }
6335
6336   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6337   alarm (600);
6338
6339   /* Cancel previous alarm. */
6340   alarm (0);
6341
6342   nr_tests = %d;
6343
6344 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6345
6346   iteri (
6347     fun i test_name ->
6348       pr "  test_num++;\n";
6349       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6350       pr "  if (%s () == -1) {\n" test_name;
6351       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6352       pr "    n_failed++;\n";
6353       pr "  }\n";
6354   ) test_names;
6355   pr "\n";
6356
6357   pr "  guestfs_close (g);\n";
6358   pr "  unlink (\"test1.img\");\n";
6359   pr "  unlink (\"test2.img\");\n";
6360   pr "  unlink (\"test3.img\");\n";
6361   pr "\n";
6362
6363   pr "  if (n_failed > 0) {\n";
6364   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6365   pr "    exit (EXIT_FAILURE);\n";
6366   pr "  }\n";
6367   pr "\n";
6368
6369   pr "  exit (EXIT_SUCCESS);\n";
6370   pr "}\n"
6371
6372 and generate_one_test name flags i (init, prereq, test) =
6373   let test_name = sprintf "test_%s_%d" name i in
6374
6375   pr "\
6376 static int %s_skip (void)
6377 {
6378   const char *str;
6379
6380   str = getenv (\"TEST_ONLY\");
6381   if (str)
6382     return strstr (str, \"%s\") == NULL;
6383   str = getenv (\"SKIP_%s\");
6384   if (str && STREQ (str, \"1\")) return 1;
6385   str = getenv (\"SKIP_TEST_%s\");
6386   if (str && STREQ (str, \"1\")) return 1;
6387   return 0;
6388 }
6389
6390 " test_name name (String.uppercase test_name) (String.uppercase name);
6391
6392   (match prereq with
6393    | Disabled | Always -> ()
6394    | If code | Unless code ->
6395        pr "static int %s_prereq (void)\n" test_name;
6396        pr "{\n";
6397        pr "  %s\n" code;
6398        pr "}\n";
6399        pr "\n";
6400   );
6401
6402   pr "\
6403 static int %s (void)
6404 {
6405   if (%s_skip ()) {
6406     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6407     return 0;
6408   }
6409
6410 " test_name test_name test_name;
6411
6412   (* Optional functions should only be tested if the relevant
6413    * support is available in the daemon.
6414    *)
6415   List.iter (
6416     function
6417     | Optional group ->
6418         pr "  {\n";
6419         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6420         pr "    int r;\n";
6421         pr "    suppress_error = 1;\n";
6422         pr "    r = guestfs_available (g, (char **) groups);\n";
6423         pr "    suppress_error = 0;\n";
6424         pr "    if (r == -1) {\n";
6425         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6426         pr "      return 0;\n";
6427         pr "    }\n";
6428         pr "  }\n";
6429     | _ -> ()
6430   ) flags;
6431
6432   (match prereq with
6433    | Disabled ->
6434        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6435    | If _ ->
6436        pr "  if (! %s_prereq ()) {\n" test_name;
6437        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6438        pr "    return 0;\n";
6439        pr "  }\n";
6440        pr "\n";
6441        generate_one_test_body name i test_name init test;
6442    | Unless _ ->
6443        pr "  if (%s_prereq ()) {\n" test_name;
6444        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6445        pr "    return 0;\n";
6446        pr "  }\n";
6447        pr "\n";
6448        generate_one_test_body name i test_name init test;
6449    | Always ->
6450        generate_one_test_body name i test_name init test
6451   );
6452
6453   pr "  return 0;\n";
6454   pr "}\n";
6455   pr "\n";
6456   test_name
6457
6458 and generate_one_test_body name i test_name init test =
6459   (match init with
6460    | InitNone (* XXX at some point, InitNone and InitEmpty became
6461                * folded together as the same thing.  Really we should
6462                * make InitNone do nothing at all, but the tests may
6463                * need to be checked to make sure this is OK.
6464                *)
6465    | InitEmpty ->
6466        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6467        List.iter (generate_test_command_call test_name)
6468          [["blockdev_setrw"; "/dev/sda"];
6469           ["umount_all"];
6470           ["lvm_remove_all"]]
6471    | InitPartition ->
6472        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6473        List.iter (generate_test_command_call test_name)
6474          [["blockdev_setrw"; "/dev/sda"];
6475           ["umount_all"];
6476           ["lvm_remove_all"];
6477           ["part_disk"; "/dev/sda"; "mbr"]]
6478    | InitBasicFS ->
6479        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6480        List.iter (generate_test_command_call test_name)
6481          [["blockdev_setrw"; "/dev/sda"];
6482           ["umount_all"];
6483           ["lvm_remove_all"];
6484           ["part_disk"; "/dev/sda"; "mbr"];
6485           ["mkfs"; "ext2"; "/dev/sda1"];
6486           ["mount"; "/dev/sda1"; "/"]]
6487    | InitBasicFSonLVM ->
6488        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6489          test_name;
6490        List.iter (generate_test_command_call test_name)
6491          [["blockdev_setrw"; "/dev/sda"];
6492           ["umount_all"];
6493           ["lvm_remove_all"];
6494           ["part_disk"; "/dev/sda"; "mbr"];
6495           ["pvcreate"; "/dev/sda1"];
6496           ["vgcreate"; "VG"; "/dev/sda1"];
6497           ["lvcreate"; "LV"; "VG"; "8"];
6498           ["mkfs"; "ext2"; "/dev/VG/LV"];
6499           ["mount"; "/dev/VG/LV"; "/"]]
6500    | InitISOFS ->
6501        pr "  /* InitISOFS for %s */\n" test_name;
6502        List.iter (generate_test_command_call test_name)
6503          [["blockdev_setrw"; "/dev/sda"];
6504           ["umount_all"];
6505           ["lvm_remove_all"];
6506           ["mount_ro"; "/dev/sdd"; "/"]]
6507   );
6508
6509   let get_seq_last = function
6510     | [] ->
6511         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6512           test_name
6513     | seq ->
6514         let seq = List.rev seq in
6515         List.rev (List.tl seq), List.hd seq
6516   in
6517
6518   match test with
6519   | TestRun seq ->
6520       pr "  /* TestRun for %s (%d) */\n" name i;
6521       List.iter (generate_test_command_call test_name) seq
6522   | TestOutput (seq, expected) ->
6523       pr "  /* TestOutput for %s (%d) */\n" name i;
6524       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6525       let seq, last = get_seq_last seq in
6526       let test () =
6527         pr "    if (STRNEQ (r, expected)) {\n";
6528         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6529         pr "      return -1;\n";
6530         pr "    }\n"
6531       in
6532       List.iter (generate_test_command_call test_name) seq;
6533       generate_test_command_call ~test test_name last
6534   | TestOutputList (seq, expected) ->
6535       pr "  /* TestOutputList for %s (%d) */\n" name i;
6536       let seq, last = get_seq_last seq in
6537       let test () =
6538         iteri (
6539           fun i str ->
6540             pr "    if (!r[%d]) {\n" i;
6541             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6542             pr "      print_strings (r);\n";
6543             pr "      return -1;\n";
6544             pr "    }\n";
6545             pr "    {\n";
6546             pr "      const char *expected = \"%s\";\n" (c_quote str);
6547             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6548             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6549             pr "        return -1;\n";
6550             pr "      }\n";
6551             pr "    }\n"
6552         ) expected;
6553         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6554         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6555           test_name;
6556         pr "      print_strings (r);\n";
6557         pr "      return -1;\n";
6558         pr "    }\n"
6559       in
6560       List.iter (generate_test_command_call test_name) seq;
6561       generate_test_command_call ~test test_name last
6562   | TestOutputListOfDevices (seq, expected) ->
6563       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6564       let seq, last = get_seq_last seq in
6565       let test () =
6566         iteri (
6567           fun i str ->
6568             pr "    if (!r[%d]) {\n" i;
6569             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6570             pr "      print_strings (r);\n";
6571             pr "      return -1;\n";
6572             pr "    }\n";
6573             pr "    {\n";
6574             pr "      const char *expected = \"%s\";\n" (c_quote str);
6575             pr "      r[%d][5] = 's';\n" i;
6576             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6577             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6578             pr "        return -1;\n";
6579             pr "      }\n";
6580             pr "    }\n"
6581         ) expected;
6582         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6583         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6584           test_name;
6585         pr "      print_strings (r);\n";
6586         pr "      return -1;\n";
6587         pr "    }\n"
6588       in
6589       List.iter (generate_test_command_call test_name) seq;
6590       generate_test_command_call ~test test_name last
6591   | TestOutputInt (seq, expected) ->
6592       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6593       let seq, last = get_seq_last seq in
6594       let test () =
6595         pr "    if (r != %d) {\n" expected;
6596         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6597           test_name expected;
6598         pr "               (int) r);\n";
6599         pr "      return -1;\n";
6600         pr "    }\n"
6601       in
6602       List.iter (generate_test_command_call test_name) seq;
6603       generate_test_command_call ~test test_name last
6604   | TestOutputIntOp (seq, op, expected) ->
6605       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6606       let seq, last = get_seq_last seq in
6607       let test () =
6608         pr "    if (! (r %s %d)) {\n" op expected;
6609         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6610           test_name op expected;
6611         pr "               (int) r);\n";
6612         pr "      return -1;\n";
6613         pr "    }\n"
6614       in
6615       List.iter (generate_test_command_call test_name) seq;
6616       generate_test_command_call ~test test_name last
6617   | TestOutputTrue seq ->
6618       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
6619       let seq, last = get_seq_last seq in
6620       let test () =
6621         pr "    if (!r) {\n";
6622         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
6623           test_name;
6624         pr "      return -1;\n";
6625         pr "    }\n"
6626       in
6627       List.iter (generate_test_command_call test_name) seq;
6628       generate_test_command_call ~test test_name last
6629   | TestOutputFalse seq ->
6630       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
6631       let seq, last = get_seq_last seq in
6632       let test () =
6633         pr "    if (r) {\n";
6634         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
6635           test_name;
6636         pr "      return -1;\n";
6637         pr "    }\n"
6638       in
6639       List.iter (generate_test_command_call test_name) seq;
6640       generate_test_command_call ~test test_name last
6641   | TestOutputLength (seq, expected) ->
6642       pr "  /* TestOutputLength for %s (%d) */\n" name i;
6643       let seq, last = get_seq_last seq in
6644       let test () =
6645         pr "    int j;\n";
6646         pr "    for (j = 0; j < %d; ++j)\n" expected;
6647         pr "      if (r[j] == NULL) {\n";
6648         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
6649           test_name;
6650         pr "        print_strings (r);\n";
6651         pr "        return -1;\n";
6652         pr "      }\n";
6653         pr "    if (r[j] != NULL) {\n";
6654         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
6655           test_name;
6656         pr "      print_strings (r);\n";
6657         pr "      return -1;\n";
6658         pr "    }\n"
6659       in
6660       List.iter (generate_test_command_call test_name) seq;
6661       generate_test_command_call ~test test_name last
6662   | TestOutputBuffer (seq, expected) ->
6663       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
6664       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6665       let seq, last = get_seq_last seq in
6666       let len = String.length expected in
6667       let test () =
6668         pr "    if (size != %d) {\n" len;
6669         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
6670         pr "      return -1;\n";
6671         pr "    }\n";
6672         pr "    if (STRNEQLEN (r, expected, size)) {\n";
6673         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6674         pr "      return -1;\n";
6675         pr "    }\n"
6676       in
6677       List.iter (generate_test_command_call test_name) seq;
6678       generate_test_command_call ~test test_name last
6679   | TestOutputStruct (seq, checks) ->
6680       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
6681       let seq, last = get_seq_last seq in
6682       let test () =
6683         List.iter (
6684           function
6685           | CompareWithInt (field, expected) ->
6686               pr "    if (r->%s != %d) {\n" field expected;
6687               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
6688                 test_name field expected;
6689               pr "               (int) r->%s);\n" field;
6690               pr "      return -1;\n";
6691               pr "    }\n"
6692           | CompareWithIntOp (field, op, expected) ->
6693               pr "    if (!(r->%s %s %d)) {\n" field op expected;
6694               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
6695                 test_name field op expected;
6696               pr "               (int) r->%s);\n" field;
6697               pr "      return -1;\n";
6698               pr "    }\n"
6699           | CompareWithString (field, expected) ->
6700               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
6701               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
6702                 test_name field expected;
6703               pr "               r->%s);\n" field;
6704               pr "      return -1;\n";
6705               pr "    }\n"
6706           | CompareFieldsIntEq (field1, field2) ->
6707               pr "    if (r->%s != r->%s) {\n" field1 field2;
6708               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
6709                 test_name field1 field2;
6710               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
6711               pr "      return -1;\n";
6712               pr "    }\n"
6713           | CompareFieldsStrEq (field1, field2) ->
6714               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
6715               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
6716                 test_name field1 field2;
6717               pr "               r->%s, r->%s);\n" field1 field2;
6718               pr "      return -1;\n";
6719               pr "    }\n"
6720         ) checks
6721       in
6722       List.iter (generate_test_command_call test_name) seq;
6723       generate_test_command_call ~test test_name last
6724   | TestLastFail seq ->
6725       pr "  /* TestLastFail for %s (%d) */\n" name i;
6726       let seq, last = get_seq_last seq in
6727       List.iter (generate_test_command_call test_name) seq;
6728       generate_test_command_call test_name ~expect_error:true last
6729
6730 (* Generate the code to run a command, leaving the result in 'r'.
6731  * If you expect to get an error then you should set expect_error:true.
6732  *)
6733 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
6734   match cmd with
6735   | [] -> assert false
6736   | name :: args ->
6737       (* Look up the command to find out what args/ret it has. *)
6738       let style =
6739         try
6740           let _, style, _, _, _, _, _ =
6741             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
6742           style
6743         with Not_found ->
6744           failwithf "%s: in test, command %s was not found" test_name name in
6745
6746       if List.length (snd style) <> List.length args then
6747         failwithf "%s: in test, wrong number of args given to %s"
6748           test_name name;
6749
6750       pr "  {\n";
6751
6752       List.iter (
6753         function
6754         | OptString n, "NULL" -> ()
6755         | Pathname n, arg
6756         | Device n, arg
6757         | Dev_or_Path n, arg
6758         | String n, arg
6759         | OptString n, arg ->
6760             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
6761         | Int _, _
6762         | Int64 _, _
6763         | Bool _, _
6764         | FileIn _, _ | FileOut _, _ -> ()
6765         | StringList n, "" | DeviceList n, "" ->
6766             pr "    const char *const %s[1] = { NULL };\n" n
6767         | StringList n, arg | DeviceList n, arg ->
6768             let strs = string_split " " arg in
6769             iteri (
6770               fun i str ->
6771                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
6772             ) strs;
6773             pr "    const char *const %s[] = {\n" n;
6774             iteri (
6775               fun i _ -> pr "      %s_%d,\n" n i
6776             ) strs;
6777             pr "      NULL\n";
6778             pr "    };\n";
6779       ) (List.combine (snd style) args);
6780
6781       let error_code =
6782         match fst style with
6783         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
6784         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
6785         | RConstString _ | RConstOptString _ ->
6786             pr "    const char *r;\n"; "NULL"
6787         | RString _ -> pr "    char *r;\n"; "NULL"
6788         | RStringList _ | RHashtable _ ->
6789             pr "    char **r;\n";
6790             pr "    int i;\n";
6791             "NULL"
6792         | RStruct (_, typ) ->
6793             pr "    struct guestfs_%s *r;\n" typ; "NULL"
6794         | RStructList (_, typ) ->
6795             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
6796         | RBufferOut _ ->
6797             pr "    char *r;\n";
6798             pr "    size_t size;\n";
6799             "NULL" in
6800
6801       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
6802       pr "    r = guestfs_%s (g" name;
6803
6804       (* Generate the parameters. *)
6805       List.iter (
6806         function
6807         | OptString _, "NULL" -> pr ", NULL"
6808         | Pathname n, _
6809         | Device n, _ | Dev_or_Path n, _
6810         | String n, _
6811         | OptString n, _ ->
6812             pr ", %s" n
6813         | FileIn _, arg | FileOut _, arg ->
6814             pr ", \"%s\"" (c_quote arg)
6815         | StringList n, _ | DeviceList n, _ ->
6816             pr ", (char **) %s" n
6817         | Int _, arg ->
6818             let i =
6819               try int_of_string arg
6820               with Failure "int_of_string" ->
6821                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
6822             pr ", %d" i
6823         | Int64 _, arg ->
6824             let i =
6825               try Int64.of_string arg
6826               with Failure "int_of_string" ->
6827                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
6828             pr ", %Ld" i
6829         | Bool _, arg ->
6830             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
6831       ) (List.combine (snd style) args);
6832
6833       (match fst style with
6834        | RBufferOut _ -> pr ", &size"
6835        | _ -> ()
6836       );
6837
6838       pr ");\n";
6839
6840       if not expect_error then
6841         pr "    if (r == %s)\n" error_code
6842       else
6843         pr "    if (r != %s)\n" error_code;
6844       pr "      return -1;\n";
6845
6846       (* Insert the test code. *)
6847       (match test with
6848        | None -> ()
6849        | Some f -> f ()
6850       );
6851
6852       (match fst style with
6853        | RErr | RInt _ | RInt64 _ | RBool _
6854        | RConstString _ | RConstOptString _ -> ()
6855        | RString _ | RBufferOut _ -> pr "    free (r);\n"
6856        | RStringList _ | RHashtable _ ->
6857            pr "    for (i = 0; r[i] != NULL; ++i)\n";
6858            pr "      free (r[i]);\n";
6859            pr "    free (r);\n"
6860        | RStruct (_, typ) ->
6861            pr "    guestfs_free_%s (r);\n" typ
6862        | RStructList (_, typ) ->
6863            pr "    guestfs_free_%s_list (r);\n" typ
6864       );
6865
6866       pr "  }\n"
6867
6868 and c_quote str =
6869   let str = replace_str str "\r" "\\r" in
6870   let str = replace_str str "\n" "\\n" in
6871   let str = replace_str str "\t" "\\t" in
6872   let str = replace_str str "\000" "\\0" in
6873   str
6874
6875 (* Generate a lot of different functions for guestfish. *)
6876 and generate_fish_cmds () =
6877   generate_header CStyle GPLv2plus;
6878
6879   let all_functions =
6880     List.filter (
6881       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6882     ) all_functions in
6883   let all_functions_sorted =
6884     List.filter (
6885       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6886     ) all_functions_sorted in
6887
6888   pr "#include <config.h>\n";
6889   pr "\n";
6890   pr "#include <stdio.h>\n";
6891   pr "#include <stdlib.h>\n";
6892   pr "#include <string.h>\n";
6893   pr "#include <inttypes.h>\n";
6894   pr "\n";
6895   pr "#include <guestfs.h>\n";
6896   pr "#include \"c-ctype.h\"\n";
6897   pr "#include \"full-write.h\"\n";
6898   pr "#include \"xstrtol.h\"\n";
6899   pr "#include \"fish.h\"\n";
6900   pr "\n";
6901
6902   (* list_commands function, which implements guestfish -h *)
6903   pr "void list_commands (void)\n";
6904   pr "{\n";
6905   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
6906   pr "  list_builtin_commands ();\n";
6907   List.iter (
6908     fun (name, _, _, flags, _, shortdesc, _) ->
6909       let name = replace_char name '_' '-' in
6910       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
6911         name shortdesc
6912   ) all_functions_sorted;
6913   pr "  printf (\"    %%s\\n\",";
6914   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
6915   pr "}\n";
6916   pr "\n";
6917
6918   (* display_command function, which implements guestfish -h cmd *)
6919   pr "void display_command (const char *cmd)\n";
6920   pr "{\n";
6921   List.iter (
6922     fun (name, style, _, flags, _, shortdesc, longdesc) ->
6923       let name2 = replace_char name '_' '-' in
6924       let alias =
6925         try find_map (function FishAlias n -> Some n | _ -> None) flags
6926         with Not_found -> name in
6927       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
6928       let synopsis =
6929         match snd style with
6930         | [] -> name2
6931         | args ->
6932             sprintf "%s %s"
6933               name2 (String.concat " " (List.map name_of_argt args)) in
6934
6935       let warnings =
6936         if List.mem ProtocolLimitWarning flags then
6937           ("\n\n" ^ protocol_limit_warning)
6938         else "" in
6939
6940       (* For DangerWillRobinson commands, we should probably have
6941        * guestfish prompt before allowing you to use them (especially
6942        * in interactive mode). XXX
6943        *)
6944       let warnings =
6945         warnings ^
6946           if List.mem DangerWillRobinson flags then
6947             ("\n\n" ^ danger_will_robinson)
6948           else "" in
6949
6950       let warnings =
6951         warnings ^
6952           match deprecation_notice flags with
6953           | None -> ""
6954           | Some txt -> "\n\n" ^ txt in
6955
6956       let describe_alias =
6957         if name <> alias then
6958           sprintf "\n\nYou can use '%s' as an alias for this command." alias
6959         else "" in
6960
6961       pr "  if (";
6962       pr "STRCASEEQ (cmd, \"%s\")" name;
6963       if name <> name2 then
6964         pr " || STRCASEEQ (cmd, \"%s\")" name2;
6965       if name <> alias then
6966         pr " || STRCASEEQ (cmd, \"%s\")" alias;
6967       pr ")\n";
6968       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
6969         name2 shortdesc
6970         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
6971          "=head1 DESCRIPTION\n\n" ^
6972          longdesc ^ warnings ^ describe_alias);
6973       pr "  else\n"
6974   ) all_functions;
6975   pr "    display_builtin_command (cmd);\n";
6976   pr "}\n";
6977   pr "\n";
6978
6979   let emit_print_list_function typ =
6980     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
6981       typ typ typ;
6982     pr "{\n";
6983     pr "  unsigned int i;\n";
6984     pr "\n";
6985     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
6986     pr "    printf (\"[%%d] = {\\n\", i);\n";
6987     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
6988     pr "    printf (\"}\\n\");\n";
6989     pr "  }\n";
6990     pr "}\n";
6991     pr "\n";
6992   in
6993
6994   (* print_* functions *)
6995   List.iter (
6996     fun (typ, cols) ->
6997       let needs_i =
6998         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
6999
7000       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7001       pr "{\n";
7002       if needs_i then (
7003         pr "  unsigned int i;\n";
7004         pr "\n"
7005       );
7006       List.iter (
7007         function
7008         | name, FString ->
7009             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7010         | name, FUUID ->
7011             pr "  printf (\"%%s%s: \", indent);\n" name;
7012             pr "  for (i = 0; i < 32; ++i)\n";
7013             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7014             pr "  printf (\"\\n\");\n"
7015         | name, FBuffer ->
7016             pr "  printf (\"%%s%s: \", indent);\n" name;
7017             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7018             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7019             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7020             pr "    else\n";
7021             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7022             pr "  printf (\"\\n\");\n"
7023         | name, (FUInt64|FBytes) ->
7024             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7025               name typ name
7026         | name, FInt64 ->
7027             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7028               name typ name
7029         | name, FUInt32 ->
7030             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7031               name typ name
7032         | name, FInt32 ->
7033             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7034               name typ name
7035         | name, FChar ->
7036             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7037               name typ name
7038         | name, FOptPercent ->
7039             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7040               typ name name typ name;
7041             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7042       ) cols;
7043       pr "}\n";
7044       pr "\n";
7045   ) structs;
7046
7047   (* Emit a print_TYPE_list function definition only if that function is used. *)
7048   List.iter (
7049     function
7050     | typ, (RStructListOnly | RStructAndList) ->
7051         (* generate the function for typ *)
7052         emit_print_list_function typ
7053     | typ, _ -> () (* empty *)
7054   ) (rstructs_used_by all_functions);
7055
7056   (* Emit a print_TYPE function definition only if that function is used. *)
7057   List.iter (
7058     function
7059     | typ, (RStructOnly | RStructAndList) ->
7060         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7061         pr "{\n";
7062         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7063         pr "}\n";
7064         pr "\n";
7065     | typ, _ -> () (* empty *)
7066   ) (rstructs_used_by all_functions);
7067
7068   (* run_<action> actions *)
7069   List.iter (
7070     fun (name, style, _, flags, _, _, _) ->
7071       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7072       pr "{\n";
7073       (match fst style with
7074        | RErr
7075        | RInt _
7076        | RBool _ -> pr "  int r;\n"
7077        | RInt64 _ -> pr "  int64_t r;\n"
7078        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7079        | RString _ -> pr "  char *r;\n"
7080        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7081        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7082        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7083        | RBufferOut _ ->
7084            pr "  char *r;\n";
7085            pr "  size_t size;\n";
7086       );
7087       List.iter (
7088         function
7089         | Device n
7090         | String n
7091         | OptString n
7092         | FileIn n
7093         | FileOut n -> pr "  const char *%s;\n" n
7094         | Pathname n
7095         | Dev_or_Path n -> pr "  char *%s;\n" n
7096         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7097         | Bool n -> pr "  int %s;\n" n
7098         | Int n -> pr "  int %s;\n" n
7099         | Int64 n -> pr "  int64_t %s;\n" n
7100       ) (snd style);
7101
7102       (* Check and convert parameters. *)
7103       let argc_expected = List.length (snd style) in
7104       pr "  if (argc != %d) {\n" argc_expected;
7105       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7106         argc_expected;
7107       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7108       pr "    return -1;\n";
7109       pr "  }\n";
7110
7111       let parse_integer fn fntyp rtyp range name i =
7112         pr "  {\n";
7113         pr "    strtol_error xerr;\n";
7114         pr "    %s r;\n" fntyp;
7115         pr "\n";
7116         pr "    xerr = %s (argv[%d], NULL, 0, &r, \"\");\n" fn i;
7117         pr "    if (xerr != LONGINT_OK) {\n";
7118         pr "      fprintf (stderr,\n";
7119         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7120         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7121         pr "      return -1;\n";
7122         pr "    }\n";
7123         (match range with
7124          | None -> ()
7125          | Some (min, max, comment) ->
7126              pr "    /* %s */\n" comment;
7127              pr "    if (r < %s || r > %s) {\n" min max;
7128              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7129                name;
7130              pr "      return -1;\n";
7131              pr "    }\n";
7132              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7133         );
7134         pr "    %s = r;\n" name;
7135         pr "  }\n";
7136       in
7137
7138       iteri (
7139         fun i ->
7140           function
7141           | Device name
7142           | String name ->
7143               pr "  %s = argv[%d];\n" name i
7144           | Pathname name
7145           | Dev_or_Path name ->
7146               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7147               pr "  if (%s == NULL) return -1;\n" name
7148           | OptString name ->
7149               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7150                 name i i
7151           | FileIn name ->
7152               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdin\";\n"
7153                 name i i
7154           | FileOut name ->
7155               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdout\";\n"
7156                 name i i
7157           | StringList name | DeviceList name ->
7158               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7159               pr "  if (%s == NULL) return -1;\n" name;
7160           | Bool name ->
7161               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7162           | Int name ->
7163               let range =
7164                 let min = "(-(2LL<<30))"
7165                 and max = "((2LL<<30)-1)"
7166                 and comment =
7167                   "The Int type in the generator is a signed 31 bit int." in
7168                 Some (min, max, comment) in
7169               parse_integer "xstrtol" "long" "int" range name i
7170           | Int64 name ->
7171               parse_integer "xstrtoll" "long long" "int64_t" None name i
7172       ) (snd style);
7173
7174       (* Call C API function. *)
7175       let fn =
7176         try find_map (function FishAction n -> Some n | _ -> None) flags
7177         with Not_found -> sprintf "guestfs_%s" name in
7178       pr "  r = %s " fn;
7179       generate_c_call_args ~handle:"g" style;
7180       pr ";\n";
7181
7182       List.iter (
7183         function
7184         | Device name | String name
7185         | OptString name | FileIn name | FileOut name | Bool name
7186         | Int name | Int64 name -> ()
7187         | Pathname name | Dev_or_Path name ->
7188             pr "  free (%s);\n" name
7189         | StringList name | DeviceList name ->
7190             pr "  free_strings (%s);\n" name
7191       ) (snd style);
7192
7193       (* Check return value for errors and display command results. *)
7194       (match fst style with
7195        | RErr -> pr "  return r;\n"
7196        | RInt _ ->
7197            pr "  if (r == -1) return -1;\n";
7198            pr "  printf (\"%%d\\n\", r);\n";
7199            pr "  return 0;\n"
7200        | RInt64 _ ->
7201            pr "  if (r == -1) return -1;\n";
7202            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7203            pr "  return 0;\n"
7204        | RBool _ ->
7205            pr "  if (r == -1) return -1;\n";
7206            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7207            pr "  return 0;\n"
7208        | RConstString _ ->
7209            pr "  if (r == NULL) return -1;\n";
7210            pr "  printf (\"%%s\\n\", r);\n";
7211            pr "  return 0;\n"
7212        | RConstOptString _ ->
7213            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7214            pr "  return 0;\n"
7215        | RString _ ->
7216            pr "  if (r == NULL) return -1;\n";
7217            pr "  printf (\"%%s\\n\", r);\n";
7218            pr "  free (r);\n";
7219            pr "  return 0;\n"
7220        | RStringList _ ->
7221            pr "  if (r == NULL) return -1;\n";
7222            pr "  print_strings (r);\n";
7223            pr "  free_strings (r);\n";
7224            pr "  return 0;\n"
7225        | RStruct (_, typ) ->
7226            pr "  if (r == NULL) return -1;\n";
7227            pr "  print_%s (r);\n" typ;
7228            pr "  guestfs_free_%s (r);\n" typ;
7229            pr "  return 0;\n"
7230        | RStructList (_, typ) ->
7231            pr "  if (r == NULL) return -1;\n";
7232            pr "  print_%s_list (r);\n" typ;
7233            pr "  guestfs_free_%s_list (r);\n" typ;
7234            pr "  return 0;\n"
7235        | RHashtable _ ->
7236            pr "  if (r == NULL) return -1;\n";
7237            pr "  print_table (r);\n";
7238            pr "  free_strings (r);\n";
7239            pr "  return 0;\n"
7240        | RBufferOut _ ->
7241            pr "  if (r == NULL) return -1;\n";
7242            pr "  if (full_write (1, r, size) != size) {\n";
7243            pr "    perror (\"write\");\n";
7244            pr "    free (r);\n";
7245            pr "    return -1;\n";
7246            pr "  }\n";
7247            pr "  free (r);\n";
7248            pr "  return 0;\n"
7249       );
7250       pr "}\n";
7251       pr "\n"
7252   ) all_functions;
7253
7254   (* run_action function *)
7255   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7256   pr "{\n";
7257   List.iter (
7258     fun (name, _, _, flags, _, _, _) ->
7259       let name2 = replace_char name '_' '-' in
7260       let alias =
7261         try find_map (function FishAlias n -> Some n | _ -> None) flags
7262         with Not_found -> name in
7263       pr "  if (";
7264       pr "STRCASEEQ (cmd, \"%s\")" name;
7265       if name <> name2 then
7266         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7267       if name <> alias then
7268         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7269       pr ")\n";
7270       pr "    return run_%s (cmd, argc, argv);\n" name;
7271       pr "  else\n";
7272   ) all_functions;
7273   pr "    {\n";
7274   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7275   pr "      return -1;\n";
7276   pr "    }\n";
7277   pr "  return 0;\n";
7278   pr "}\n";
7279   pr "\n"
7280
7281 (* Readline completion for guestfish. *)
7282 and generate_fish_completion () =
7283   generate_header CStyle GPLv2plus;
7284
7285   let all_functions =
7286     List.filter (
7287       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7288     ) all_functions in
7289
7290   pr "\
7291 #include <config.h>
7292
7293 #include <stdio.h>
7294 #include <stdlib.h>
7295 #include <string.h>
7296
7297 #ifdef HAVE_LIBREADLINE
7298 #include <readline/readline.h>
7299 #endif
7300
7301 #include \"fish.h\"
7302
7303 #ifdef HAVE_LIBREADLINE
7304
7305 static const char *const commands[] = {
7306   BUILTIN_COMMANDS_FOR_COMPLETION,
7307 ";
7308
7309   (* Get the commands, including the aliases.  They don't need to be
7310    * sorted - the generator() function just does a dumb linear search.
7311    *)
7312   let commands =
7313     List.map (
7314       fun (name, _, _, flags, _, _, _) ->
7315         let name2 = replace_char name '_' '-' in
7316         let alias =
7317           try find_map (function FishAlias n -> Some n | _ -> None) flags
7318           with Not_found -> name in
7319
7320         if name <> alias then [name2; alias] else [name2]
7321     ) all_functions in
7322   let commands = List.flatten commands in
7323
7324   List.iter (pr "  \"%s\",\n") commands;
7325
7326   pr "  NULL
7327 };
7328
7329 static char *
7330 generator (const char *text, int state)
7331 {
7332   static int index, len;
7333   const char *name;
7334
7335   if (!state) {
7336     index = 0;
7337     len = strlen (text);
7338   }
7339
7340   rl_attempted_completion_over = 1;
7341
7342   while ((name = commands[index]) != NULL) {
7343     index++;
7344     if (STRCASEEQLEN (name, text, len))
7345       return strdup (name);
7346   }
7347
7348   return NULL;
7349 }
7350
7351 #endif /* HAVE_LIBREADLINE */
7352
7353 char **do_completion (const char *text, int start, int end)
7354 {
7355   char **matches = NULL;
7356
7357 #ifdef HAVE_LIBREADLINE
7358   rl_completion_append_character = ' ';
7359
7360   if (start == 0)
7361     matches = rl_completion_matches (text, generator);
7362   else if (complete_dest_paths)
7363     matches = rl_completion_matches (text, complete_dest_paths_generator);
7364 #endif
7365
7366   return matches;
7367 }
7368 ";
7369
7370 (* Generate the POD documentation for guestfish. *)
7371 and generate_fish_actions_pod () =
7372   let all_functions_sorted =
7373     List.filter (
7374       fun (_, _, _, flags, _, _, _) ->
7375         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7376     ) all_functions_sorted in
7377
7378   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7379
7380   List.iter (
7381     fun (name, style, _, flags, _, _, longdesc) ->
7382       let longdesc =
7383         Str.global_substitute rex (
7384           fun s ->
7385             let sub =
7386               try Str.matched_group 1 s
7387               with Not_found ->
7388                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7389             "C<" ^ replace_char sub '_' '-' ^ ">"
7390         ) longdesc in
7391       let name = replace_char name '_' '-' in
7392       let alias =
7393         try find_map (function FishAlias n -> Some n | _ -> None) flags
7394         with Not_found -> name in
7395
7396       pr "=head2 %s" name;
7397       if name <> alias then
7398         pr " | %s" alias;
7399       pr "\n";
7400       pr "\n";
7401       pr " %s" name;
7402       List.iter (
7403         function
7404         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7405         | OptString n -> pr " %s" n
7406         | StringList n | DeviceList n -> pr " '%s ...'" n
7407         | Bool _ -> pr " true|false"
7408         | Int n -> pr " %s" n
7409         | Int64 n -> pr " %s" n
7410         | FileIn n | FileOut n -> pr " (%s|-)" n
7411       ) (snd style);
7412       pr "\n";
7413       pr "\n";
7414       pr "%s\n\n" longdesc;
7415
7416       if List.exists (function FileIn _ | FileOut _ -> true
7417                       | _ -> false) (snd style) then
7418         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7419
7420       if List.mem ProtocolLimitWarning flags then
7421         pr "%s\n\n" protocol_limit_warning;
7422
7423       if List.mem DangerWillRobinson flags then
7424         pr "%s\n\n" danger_will_robinson;
7425
7426       match deprecation_notice flags with
7427       | None -> ()
7428       | Some txt -> pr "%s\n\n" txt
7429   ) all_functions_sorted
7430
7431 (* Generate a C function prototype. *)
7432 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7433     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7434     ?(prefix = "")
7435     ?handle name style =
7436   if extern then pr "extern ";
7437   if static then pr "static ";
7438   (match fst style with
7439    | RErr -> pr "int "
7440    | RInt _ -> pr "int "
7441    | RInt64 _ -> pr "int64_t "
7442    | RBool _ -> pr "int "
7443    | RConstString _ | RConstOptString _ -> pr "const char *"
7444    | RString _ | RBufferOut _ -> pr "char *"
7445    | RStringList _ | RHashtable _ -> pr "char **"
7446    | RStruct (_, typ) ->
7447        if not in_daemon then pr "struct guestfs_%s *" typ
7448        else pr "guestfs_int_%s *" typ
7449    | RStructList (_, typ) ->
7450        if not in_daemon then pr "struct guestfs_%s_list *" typ
7451        else pr "guestfs_int_%s_list *" typ
7452   );
7453   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7454   pr "%s%s (" prefix name;
7455   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7456     pr "void"
7457   else (
7458     let comma = ref false in
7459     (match handle with
7460      | None -> ()
7461      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7462     );
7463     let next () =
7464       if !comma then (
7465         if single_line then pr ", " else pr ",\n\t\t"
7466       );
7467       comma := true
7468     in
7469     List.iter (
7470       function
7471       | Pathname n
7472       | Device n | Dev_or_Path n
7473       | String n
7474       | OptString n ->
7475           next ();
7476           pr "const char *%s" n
7477       | StringList n | DeviceList n ->
7478           next ();
7479           pr "char *const *%s" n
7480       | Bool n -> next (); pr "int %s" n
7481       | Int n -> next (); pr "int %s" n
7482       | Int64 n -> next (); pr "int64_t %s" n
7483       | FileIn n
7484       | FileOut n ->
7485           if not in_daemon then (next (); pr "const char *%s" n)
7486     ) (snd style);
7487     if is_RBufferOut then (next (); pr "size_t *size_r");
7488   );
7489   pr ")";
7490   if semicolon then pr ";";
7491   if newline then pr "\n"
7492
7493 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7494 and generate_c_call_args ?handle ?(decl = false) style =
7495   pr "(";
7496   let comma = ref false in
7497   let next () =
7498     if !comma then pr ", ";
7499     comma := true
7500   in
7501   (match handle with
7502    | None -> ()
7503    | Some handle -> pr "%s" handle; comma := true
7504   );
7505   List.iter (
7506     fun arg ->
7507       next ();
7508       pr "%s" (name_of_argt arg)
7509   ) (snd style);
7510   (* For RBufferOut calls, add implicit &size parameter. *)
7511   if not decl then (
7512     match fst style with
7513     | RBufferOut _ ->
7514         next ();
7515         pr "&size"
7516     | _ -> ()
7517   );
7518   pr ")"
7519
7520 (* Generate the OCaml bindings interface. *)
7521 and generate_ocaml_mli () =
7522   generate_header OCamlStyle LGPLv2plus;
7523
7524   pr "\
7525 (** For API documentation you should refer to the C API
7526     in the guestfs(3) manual page.  The OCaml API uses almost
7527     exactly the same calls. *)
7528
7529 type t
7530 (** A [guestfs_h] handle. *)
7531
7532 exception Error of string
7533 (** This exception is raised when there is an error. *)
7534
7535 exception Handle_closed of string
7536 (** This exception is raised if you use a {!Guestfs.t} handle
7537     after calling {!close} on it.  The string is the name of
7538     the function. *)
7539
7540 val create : unit -> t
7541 (** Create a {!Guestfs.t} handle. *)
7542
7543 val close : t -> unit
7544 (** Close the {!Guestfs.t} handle and free up all resources used
7545     by it immediately.
7546
7547     Handles are closed by the garbage collector when they become
7548     unreferenced, but callers can call this in order to provide
7549     predictable cleanup. *)
7550
7551 ";
7552   generate_ocaml_structure_decls ();
7553
7554   (* The actions. *)
7555   List.iter (
7556     fun (name, style, _, _, _, shortdesc, _) ->
7557       generate_ocaml_prototype name style;
7558       pr "(** %s *)\n" shortdesc;
7559       pr "\n"
7560   ) all_functions_sorted
7561
7562 (* Generate the OCaml bindings implementation. *)
7563 and generate_ocaml_ml () =
7564   generate_header OCamlStyle LGPLv2plus;
7565
7566   pr "\
7567 type t
7568
7569 exception Error of string
7570 exception Handle_closed of string
7571
7572 external create : unit -> t = \"ocaml_guestfs_create\"
7573 external close : t -> unit = \"ocaml_guestfs_close\"
7574
7575 (* Give the exceptions names, so they can be raised from the C code. *)
7576 let () =
7577   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
7578   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
7579
7580 ";
7581
7582   generate_ocaml_structure_decls ();
7583
7584   (* The actions. *)
7585   List.iter (
7586     fun (name, style, _, _, _, shortdesc, _) ->
7587       generate_ocaml_prototype ~is_external:true name style;
7588   ) all_functions_sorted
7589
7590 (* Generate the OCaml bindings C implementation. *)
7591 and generate_ocaml_c () =
7592   generate_header CStyle LGPLv2plus;
7593
7594   pr "\
7595 #include <stdio.h>
7596 #include <stdlib.h>
7597 #include <string.h>
7598
7599 #include <caml/config.h>
7600 #include <caml/alloc.h>
7601 #include <caml/callback.h>
7602 #include <caml/fail.h>
7603 #include <caml/memory.h>
7604 #include <caml/mlvalues.h>
7605 #include <caml/signals.h>
7606
7607 #include <guestfs.h>
7608
7609 #include \"guestfs_c.h\"
7610
7611 /* Copy a hashtable of string pairs into an assoc-list.  We return
7612  * the list in reverse order, but hashtables aren't supposed to be
7613  * ordered anyway.
7614  */
7615 static CAMLprim value
7616 copy_table (char * const * argv)
7617 {
7618   CAMLparam0 ();
7619   CAMLlocal5 (rv, pairv, kv, vv, cons);
7620   int i;
7621
7622   rv = Val_int (0);
7623   for (i = 0; argv[i] != NULL; i += 2) {
7624     kv = caml_copy_string (argv[i]);
7625     vv = caml_copy_string (argv[i+1]);
7626     pairv = caml_alloc (2, 0);
7627     Store_field (pairv, 0, kv);
7628     Store_field (pairv, 1, vv);
7629     cons = caml_alloc (2, 0);
7630     Store_field (cons, 1, rv);
7631     rv = cons;
7632     Store_field (cons, 0, pairv);
7633   }
7634
7635   CAMLreturn (rv);
7636 }
7637
7638 ";
7639
7640   (* Struct copy functions. *)
7641
7642   let emit_ocaml_copy_list_function typ =
7643     pr "static CAMLprim value\n";
7644     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
7645     pr "{\n";
7646     pr "  CAMLparam0 ();\n";
7647     pr "  CAMLlocal2 (rv, v);\n";
7648     pr "  unsigned int i;\n";
7649     pr "\n";
7650     pr "  if (%ss->len == 0)\n" typ;
7651     pr "    CAMLreturn (Atom (0));\n";
7652     pr "  else {\n";
7653     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
7654     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
7655     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
7656     pr "      caml_modify (&Field (rv, i), v);\n";
7657     pr "    }\n";
7658     pr "    CAMLreturn (rv);\n";
7659     pr "  }\n";
7660     pr "}\n";
7661     pr "\n";
7662   in
7663
7664   List.iter (
7665     fun (typ, cols) ->
7666       let has_optpercent_col =
7667         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
7668
7669       pr "static CAMLprim value\n";
7670       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
7671       pr "{\n";
7672       pr "  CAMLparam0 ();\n";
7673       if has_optpercent_col then
7674         pr "  CAMLlocal3 (rv, v, v2);\n"
7675       else
7676         pr "  CAMLlocal2 (rv, v);\n";
7677       pr "\n";
7678       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
7679       iteri (
7680         fun i col ->
7681           (match col with
7682            | name, FString ->
7683                pr "  v = caml_copy_string (%s->%s);\n" typ name
7684            | name, FBuffer ->
7685                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
7686                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
7687                  typ name typ name
7688            | name, FUUID ->
7689                pr "  v = caml_alloc_string (32);\n";
7690                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
7691            | name, (FBytes|FInt64|FUInt64) ->
7692                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
7693            | name, (FInt32|FUInt32) ->
7694                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
7695            | name, FOptPercent ->
7696                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
7697                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
7698                pr "    v = caml_alloc (1, 0);\n";
7699                pr "    Store_field (v, 0, v2);\n";
7700                pr "  } else /* None */\n";
7701                pr "    v = Val_int (0);\n";
7702            | name, FChar ->
7703                pr "  v = Val_int (%s->%s);\n" typ name
7704           );
7705           pr "  Store_field (rv, %d, v);\n" i
7706       ) cols;
7707       pr "  CAMLreturn (rv);\n";
7708       pr "}\n";
7709       pr "\n";
7710   ) structs;
7711
7712   (* Emit a copy_TYPE_list function definition only if that function is used. *)
7713   List.iter (
7714     function
7715     | typ, (RStructListOnly | RStructAndList) ->
7716         (* generate the function for typ *)
7717         emit_ocaml_copy_list_function typ
7718     | typ, _ -> () (* empty *)
7719   ) (rstructs_used_by all_functions);
7720
7721   (* The wrappers. *)
7722   List.iter (
7723     fun (name, style, _, _, _, _, _) ->
7724       pr "/* Automatically generated wrapper for function\n";
7725       pr " * ";
7726       generate_ocaml_prototype name style;
7727       pr " */\n";
7728       pr "\n";
7729
7730       let params =
7731         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
7732
7733       let needs_extra_vs =
7734         match fst style with RConstOptString _ -> true | _ -> false in
7735
7736       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7737       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
7738       List.iter (pr ", value %s") (List.tl params); pr ");\n";
7739       pr "\n";
7740
7741       pr "CAMLprim value\n";
7742       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
7743       List.iter (pr ", value %s") (List.tl params);
7744       pr ")\n";
7745       pr "{\n";
7746
7747       (match params with
7748        | [p1; p2; p3; p4; p5] ->
7749            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
7750        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
7751            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
7752            pr "  CAMLxparam%d (%s);\n"
7753              (List.length rest) (String.concat ", " rest)
7754        | ps ->
7755            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
7756       );
7757       if not needs_extra_vs then
7758         pr "  CAMLlocal1 (rv);\n"
7759       else
7760         pr "  CAMLlocal3 (rv, v, v2);\n";
7761       pr "\n";
7762
7763       pr "  guestfs_h *g = Guestfs_val (gv);\n";
7764       pr "  if (g == NULL)\n";
7765       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
7766       pr "\n";
7767
7768       List.iter (
7769         function
7770         | Pathname n
7771         | Device n | Dev_or_Path n
7772         | String n
7773         | FileIn n
7774         | FileOut n ->
7775             pr "  const char *%s = String_val (%sv);\n" n n
7776         | OptString n ->
7777             pr "  const char *%s =\n" n;
7778             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
7779               n n
7780         | StringList n | DeviceList n ->
7781             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
7782         | Bool n ->
7783             pr "  int %s = Bool_val (%sv);\n" n n
7784         | Int n ->
7785             pr "  int %s = Int_val (%sv);\n" n n
7786         | Int64 n ->
7787             pr "  int64_t %s = Int64_val (%sv);\n" n n
7788       ) (snd style);
7789       let error_code =
7790         match fst style with
7791         | RErr -> pr "  int r;\n"; "-1"
7792         | RInt _ -> pr "  int r;\n"; "-1"
7793         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7794         | RBool _ -> pr "  int r;\n"; "-1"
7795         | RConstString _ | RConstOptString _ ->
7796             pr "  const char *r;\n"; "NULL"
7797         | RString _ -> pr "  char *r;\n"; "NULL"
7798         | RStringList _ ->
7799             pr "  int i;\n";
7800             pr "  char **r;\n";
7801             "NULL"
7802         | RStruct (_, typ) ->
7803             pr "  struct guestfs_%s *r;\n" typ; "NULL"
7804         | RStructList (_, typ) ->
7805             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7806         | RHashtable _ ->
7807             pr "  int i;\n";
7808             pr "  char **r;\n";
7809             "NULL"
7810         | RBufferOut _ ->
7811             pr "  char *r;\n";
7812             pr "  size_t size;\n";
7813             "NULL" in
7814       pr "\n";
7815
7816       pr "  caml_enter_blocking_section ();\n";
7817       pr "  r = guestfs_%s " name;
7818       generate_c_call_args ~handle:"g" style;
7819       pr ";\n";
7820       pr "  caml_leave_blocking_section ();\n";
7821
7822       List.iter (
7823         function
7824         | StringList n | DeviceList n ->
7825             pr "  ocaml_guestfs_free_strings (%s);\n" n;
7826         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
7827         | Bool _ | Int _ | Int64 _
7828         | FileIn _ | FileOut _ -> ()
7829       ) (snd style);
7830
7831       pr "  if (r == %s)\n" error_code;
7832       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
7833       pr "\n";
7834
7835       (match fst style with
7836        | RErr -> pr "  rv = Val_unit;\n"
7837        | RInt _ -> pr "  rv = Val_int (r);\n"
7838        | RInt64 _ ->
7839            pr "  rv = caml_copy_int64 (r);\n"
7840        | RBool _ -> pr "  rv = Val_bool (r);\n"
7841        | RConstString _ ->
7842            pr "  rv = caml_copy_string (r);\n"
7843        | RConstOptString _ ->
7844            pr "  if (r) { /* Some string */\n";
7845            pr "    v = caml_alloc (1, 0);\n";
7846            pr "    v2 = caml_copy_string (r);\n";
7847            pr "    Store_field (v, 0, v2);\n";
7848            pr "  } else /* None */\n";
7849            pr "    v = Val_int (0);\n";
7850        | RString _ ->
7851            pr "  rv = caml_copy_string (r);\n";
7852            pr "  free (r);\n"
7853        | RStringList _ ->
7854            pr "  rv = caml_copy_string_array ((const char **) r);\n";
7855            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7856            pr "  free (r);\n"
7857        | RStruct (_, typ) ->
7858            pr "  rv = copy_%s (r);\n" typ;
7859            pr "  guestfs_free_%s (r);\n" typ;
7860        | RStructList (_, typ) ->
7861            pr "  rv = copy_%s_list (r);\n" typ;
7862            pr "  guestfs_free_%s_list (r);\n" typ;
7863        | RHashtable _ ->
7864            pr "  rv = copy_table (r);\n";
7865            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7866            pr "  free (r);\n";
7867        | RBufferOut _ ->
7868            pr "  rv = caml_alloc_string (size);\n";
7869            pr "  memcpy (String_val (rv), r, size);\n";
7870       );
7871
7872       pr "  CAMLreturn (rv);\n";
7873       pr "}\n";
7874       pr "\n";
7875
7876       if List.length params > 5 then (
7877         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7878         pr "CAMLprim value ";
7879         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
7880         pr "CAMLprim value\n";
7881         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
7882         pr "{\n";
7883         pr "  return ocaml_guestfs_%s (argv[0]" name;
7884         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
7885         pr ");\n";
7886         pr "}\n";
7887         pr "\n"
7888       )
7889   ) all_functions_sorted
7890
7891 and generate_ocaml_structure_decls () =
7892   List.iter (
7893     fun (typ, cols) ->
7894       pr "type %s = {\n" typ;
7895       List.iter (
7896         function
7897         | name, FString -> pr "  %s : string;\n" name
7898         | name, FBuffer -> pr "  %s : string;\n" name
7899         | name, FUUID -> pr "  %s : string;\n" name
7900         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
7901         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
7902         | name, FChar -> pr "  %s : char;\n" name
7903         | name, FOptPercent -> pr "  %s : float option;\n" name
7904       ) cols;
7905       pr "}\n";
7906       pr "\n"
7907   ) structs
7908
7909 and generate_ocaml_prototype ?(is_external = false) name style =
7910   if is_external then pr "external " else pr "val ";
7911   pr "%s : t -> " name;
7912   List.iter (
7913     function
7914     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
7915     | OptString _ -> pr "string option -> "
7916     | StringList _ | DeviceList _ -> pr "string array -> "
7917     | Bool _ -> pr "bool -> "
7918     | Int _ -> pr "int -> "
7919     | Int64 _ -> pr "int64 -> "
7920   ) (snd style);
7921   (match fst style with
7922    | RErr -> pr "unit" (* all errors are turned into exceptions *)
7923    | RInt _ -> pr "int"
7924    | RInt64 _ -> pr "int64"
7925    | RBool _ -> pr "bool"
7926    | RConstString _ -> pr "string"
7927    | RConstOptString _ -> pr "string option"
7928    | RString _ | RBufferOut _ -> pr "string"
7929    | RStringList _ -> pr "string array"
7930    | RStruct (_, typ) -> pr "%s" typ
7931    | RStructList (_, typ) -> pr "%s array" typ
7932    | RHashtable _ -> pr "(string * string) list"
7933   );
7934   if is_external then (
7935     pr " = ";
7936     if List.length (snd style) + 1 > 5 then
7937       pr "\"ocaml_guestfs_%s_byte\" " name;
7938     pr "\"ocaml_guestfs_%s\"" name
7939   );
7940   pr "\n"
7941
7942 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
7943 and generate_perl_xs () =
7944   generate_header CStyle LGPLv2plus;
7945
7946   pr "\
7947 #include \"EXTERN.h\"
7948 #include \"perl.h\"
7949 #include \"XSUB.h\"
7950
7951 #include <guestfs.h>
7952
7953 #ifndef PRId64
7954 #define PRId64 \"lld\"
7955 #endif
7956
7957 static SV *
7958 my_newSVll(long long val) {
7959 #ifdef USE_64_BIT_ALL
7960   return newSViv(val);
7961 #else
7962   char buf[100];
7963   int len;
7964   len = snprintf(buf, 100, \"%%\" PRId64, val);
7965   return newSVpv(buf, len);
7966 #endif
7967 }
7968
7969 #ifndef PRIu64
7970 #define PRIu64 \"llu\"
7971 #endif
7972
7973 static SV *
7974 my_newSVull(unsigned long long val) {
7975 #ifdef USE_64_BIT_ALL
7976   return newSVuv(val);
7977 #else
7978   char buf[100];
7979   int len;
7980   len = snprintf(buf, 100, \"%%\" PRIu64, val);
7981   return newSVpv(buf, len);
7982 #endif
7983 }
7984
7985 /* http://www.perlmonks.org/?node_id=680842 */
7986 static char **
7987 XS_unpack_charPtrPtr (SV *arg) {
7988   char **ret;
7989   AV *av;
7990   I32 i;
7991
7992   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
7993     croak (\"array reference expected\");
7994
7995   av = (AV *)SvRV (arg);
7996   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
7997   if (!ret)
7998     croak (\"malloc failed\");
7999
8000   for (i = 0; i <= av_len (av); i++) {
8001     SV **elem = av_fetch (av, i, 0);
8002
8003     if (!elem || !*elem)
8004       croak (\"missing element in list\");
8005
8006     ret[i] = SvPV_nolen (*elem);
8007   }
8008
8009   ret[i] = NULL;
8010
8011   return ret;
8012 }
8013
8014 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8015
8016 PROTOTYPES: ENABLE
8017
8018 guestfs_h *
8019 _create ()
8020    CODE:
8021       RETVAL = guestfs_create ();
8022       if (!RETVAL)
8023         croak (\"could not create guestfs handle\");
8024       guestfs_set_error_handler (RETVAL, NULL, NULL);
8025  OUTPUT:
8026       RETVAL
8027
8028 void
8029 DESTROY (g)
8030       guestfs_h *g;
8031  PPCODE:
8032       guestfs_close (g);
8033
8034 ";
8035
8036   List.iter (
8037     fun (name, style, _, _, _, _, _) ->
8038       (match fst style with
8039        | RErr -> pr "void\n"
8040        | RInt _ -> pr "SV *\n"
8041        | RInt64 _ -> pr "SV *\n"
8042        | RBool _ -> pr "SV *\n"
8043        | RConstString _ -> pr "SV *\n"
8044        | RConstOptString _ -> pr "SV *\n"
8045        | RString _ -> pr "SV *\n"
8046        | RBufferOut _ -> pr "SV *\n"
8047        | RStringList _
8048        | RStruct _ | RStructList _
8049        | RHashtable _ ->
8050            pr "void\n" (* all lists returned implictly on the stack *)
8051       );
8052       (* Call and arguments. *)
8053       pr "%s " name;
8054       generate_c_call_args ~handle:"g" ~decl:true style;
8055       pr "\n";
8056       pr "      guestfs_h *g;\n";
8057       iteri (
8058         fun i ->
8059           function
8060           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8061               pr "      char *%s;\n" n
8062           | OptString n ->
8063               (* http://www.perlmonks.org/?node_id=554277
8064                * Note that the implicit handle argument means we have
8065                * to add 1 to the ST(x) operator.
8066                *)
8067               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8068           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8069           | Bool n -> pr "      int %s;\n" n
8070           | Int n -> pr "      int %s;\n" n
8071           | Int64 n -> pr "      int64_t %s;\n" n
8072       ) (snd style);
8073
8074       let do_cleanups () =
8075         List.iter (
8076           function
8077           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8078           | Bool _ | Int _ | Int64 _
8079           | FileIn _ | FileOut _ -> ()
8080           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8081         ) (snd style)
8082       in
8083
8084       (* Code. *)
8085       (match fst style with
8086        | RErr ->
8087            pr "PREINIT:\n";
8088            pr "      int r;\n";
8089            pr " PPCODE:\n";
8090            pr "      r = guestfs_%s " name;
8091            generate_c_call_args ~handle:"g" style;
8092            pr ";\n";
8093            do_cleanups ();
8094            pr "      if (r == -1)\n";
8095            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8096        | RInt n
8097        | RBool n ->
8098            pr "PREINIT:\n";
8099            pr "      int %s;\n" n;
8100            pr "   CODE:\n";
8101            pr "      %s = guestfs_%s " n name;
8102            generate_c_call_args ~handle:"g" style;
8103            pr ";\n";
8104            do_cleanups ();
8105            pr "      if (%s == -1)\n" n;
8106            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8107            pr "      RETVAL = newSViv (%s);\n" n;
8108            pr " OUTPUT:\n";
8109            pr "      RETVAL\n"
8110        | RInt64 n ->
8111            pr "PREINIT:\n";
8112            pr "      int64_t %s;\n" n;
8113            pr "   CODE:\n";
8114            pr "      %s = guestfs_%s " n name;
8115            generate_c_call_args ~handle:"g" style;
8116            pr ";\n";
8117            do_cleanups ();
8118            pr "      if (%s == -1)\n" n;
8119            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8120            pr "      RETVAL = my_newSVll (%s);\n" n;
8121            pr " OUTPUT:\n";
8122            pr "      RETVAL\n"
8123        | RConstString n ->
8124            pr "PREINIT:\n";
8125            pr "      const char *%s;\n" n;
8126            pr "   CODE:\n";
8127            pr "      %s = guestfs_%s " n name;
8128            generate_c_call_args ~handle:"g" style;
8129            pr ";\n";
8130            do_cleanups ();
8131            pr "      if (%s == NULL)\n" n;
8132            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8133            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8134            pr " OUTPUT:\n";
8135            pr "      RETVAL\n"
8136        | RConstOptString n ->
8137            pr "PREINIT:\n";
8138            pr "      const char *%s;\n" n;
8139            pr "   CODE:\n";
8140            pr "      %s = guestfs_%s " n name;
8141            generate_c_call_args ~handle:"g" style;
8142            pr ";\n";
8143            do_cleanups ();
8144            pr "      if (%s == NULL)\n" n;
8145            pr "        RETVAL = &PL_sv_undef;\n";
8146            pr "      else\n";
8147            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8148            pr " OUTPUT:\n";
8149            pr "      RETVAL\n"
8150        | RString n ->
8151            pr "PREINIT:\n";
8152            pr "      char *%s;\n" n;
8153            pr "   CODE:\n";
8154            pr "      %s = guestfs_%s " n name;
8155            generate_c_call_args ~handle:"g" style;
8156            pr ";\n";
8157            do_cleanups ();
8158            pr "      if (%s == NULL)\n" n;
8159            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8160            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8161            pr "      free (%s);\n" n;
8162            pr " OUTPUT:\n";
8163            pr "      RETVAL\n"
8164        | RStringList n | RHashtable n ->
8165            pr "PREINIT:\n";
8166            pr "      char **%s;\n" n;
8167            pr "      int i, n;\n";
8168            pr " PPCODE:\n";
8169            pr "      %s = guestfs_%s " n name;
8170            generate_c_call_args ~handle:"g" style;
8171            pr ";\n";
8172            do_cleanups ();
8173            pr "      if (%s == NULL)\n" n;
8174            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8175            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8176            pr "      EXTEND (SP, n);\n";
8177            pr "      for (i = 0; i < n; ++i) {\n";
8178            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8179            pr "        free (%s[i]);\n" n;
8180            pr "      }\n";
8181            pr "      free (%s);\n" n;
8182        | RStruct (n, typ) ->
8183            let cols = cols_of_struct typ in
8184            generate_perl_struct_code typ cols name style n do_cleanups
8185        | RStructList (n, typ) ->
8186            let cols = cols_of_struct typ in
8187            generate_perl_struct_list_code typ cols name style n do_cleanups
8188        | RBufferOut n ->
8189            pr "PREINIT:\n";
8190            pr "      char *%s;\n" n;
8191            pr "      size_t size;\n";
8192            pr "   CODE:\n";
8193            pr "      %s = guestfs_%s " n name;
8194            generate_c_call_args ~handle:"g" style;
8195            pr ";\n";
8196            do_cleanups ();
8197            pr "      if (%s == NULL)\n" n;
8198            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8199            pr "      RETVAL = newSVpv (%s, size);\n" n;
8200            pr "      free (%s);\n" n;
8201            pr " OUTPUT:\n";
8202            pr "      RETVAL\n"
8203       );
8204
8205       pr "\n"
8206   ) all_functions
8207
8208 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8209   pr "PREINIT:\n";
8210   pr "      struct guestfs_%s_list *%s;\n" typ n;
8211   pr "      int i;\n";
8212   pr "      HV *hv;\n";
8213   pr " PPCODE:\n";
8214   pr "      %s = guestfs_%s " n name;
8215   generate_c_call_args ~handle:"g" style;
8216   pr ";\n";
8217   do_cleanups ();
8218   pr "      if (%s == NULL)\n" n;
8219   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8220   pr "      EXTEND (SP, %s->len);\n" n;
8221   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8222   pr "        hv = newHV ();\n";
8223   List.iter (
8224     function
8225     | name, FString ->
8226         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8227           name (String.length name) n name
8228     | name, FUUID ->
8229         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8230           name (String.length name) n name
8231     | name, FBuffer ->
8232         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8233           name (String.length name) n name n name
8234     | name, (FBytes|FUInt64) ->
8235         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8236           name (String.length name) n name
8237     | name, FInt64 ->
8238         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8239           name (String.length name) n name
8240     | name, (FInt32|FUInt32) ->
8241         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8242           name (String.length name) n name
8243     | name, FChar ->
8244         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8245           name (String.length name) n name
8246     | name, FOptPercent ->
8247         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8248           name (String.length name) n name
8249   ) cols;
8250   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8251   pr "      }\n";
8252   pr "      guestfs_free_%s_list (%s);\n" typ n
8253
8254 and generate_perl_struct_code typ cols name style n do_cleanups =
8255   pr "PREINIT:\n";
8256   pr "      struct guestfs_%s *%s;\n" typ n;
8257   pr " PPCODE:\n";
8258   pr "      %s = guestfs_%s " n name;
8259   generate_c_call_args ~handle:"g" style;
8260   pr ";\n";
8261   do_cleanups ();
8262   pr "      if (%s == NULL)\n" n;
8263   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8264   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8265   List.iter (
8266     fun ((name, _) as col) ->
8267       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8268
8269       match col with
8270       | name, FString ->
8271           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8272             n name
8273       | name, FBuffer ->
8274           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
8275             n name n name
8276       | name, FUUID ->
8277           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8278             n name
8279       | name, (FBytes|FUInt64) ->
8280           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8281             n name
8282       | name, FInt64 ->
8283           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8284             n name
8285       | name, (FInt32|FUInt32) ->
8286           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8287             n name
8288       | name, FChar ->
8289           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8290             n name
8291       | name, FOptPercent ->
8292           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8293             n name
8294   ) cols;
8295   pr "      free (%s);\n" n
8296
8297 (* Generate Sys/Guestfs.pm. *)
8298 and generate_perl_pm () =
8299   generate_header HashStyle LGPLv2plus;
8300
8301   pr "\
8302 =pod
8303
8304 =head1 NAME
8305
8306 Sys::Guestfs - Perl bindings for libguestfs
8307
8308 =head1 SYNOPSIS
8309
8310  use Sys::Guestfs;
8311
8312  my $h = Sys::Guestfs->new ();
8313  $h->add_drive ('guest.img');
8314  $h->launch ();
8315  $h->mount ('/dev/sda1', '/');
8316  $h->touch ('/hello');
8317  $h->sync ();
8318
8319 =head1 DESCRIPTION
8320
8321 The C<Sys::Guestfs> module provides a Perl XS binding to the
8322 libguestfs API for examining and modifying virtual machine
8323 disk images.
8324
8325 Amongst the things this is good for: making batch configuration
8326 changes to guests, getting disk used/free statistics (see also:
8327 virt-df), migrating between virtualization systems (see also:
8328 virt-p2v), performing partial backups, performing partial guest
8329 clones, cloning guests and changing registry/UUID/hostname info, and
8330 much else besides.
8331
8332 Libguestfs uses Linux kernel and qemu code, and can access any type of
8333 guest filesystem that Linux and qemu can, including but not limited
8334 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8335 schemes, qcow, qcow2, vmdk.
8336
8337 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8338 LVs, what filesystem is in each LV, etc.).  It can also run commands
8339 in the context of the guest.  Also you can access filesystems over FTP.
8340
8341 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8342 functions for using libguestfs from Perl, including integration
8343 with libvirt.
8344
8345 =head1 ERRORS
8346
8347 All errors turn into calls to C<croak> (see L<Carp(3)>).
8348
8349 =head1 METHODS
8350
8351 =over 4
8352
8353 =cut
8354
8355 package Sys::Guestfs;
8356
8357 use strict;
8358 use warnings;
8359
8360 require XSLoader;
8361 XSLoader::load ('Sys::Guestfs');
8362
8363 =item $h = Sys::Guestfs->new ();
8364
8365 Create a new guestfs handle.
8366
8367 =cut
8368
8369 sub new {
8370   my $proto = shift;
8371   my $class = ref ($proto) || $proto;
8372
8373   my $self = Sys::Guestfs::_create ();
8374   bless $self, $class;
8375   return $self;
8376 }
8377
8378 ";
8379
8380   (* Actions.  We only need to print documentation for these as
8381    * they are pulled in from the XS code automatically.
8382    *)
8383   List.iter (
8384     fun (name, style, _, flags, _, _, longdesc) ->
8385       if not (List.mem NotInDocs flags) then (
8386         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8387         pr "=item ";
8388         generate_perl_prototype name style;
8389         pr "\n\n";
8390         pr "%s\n\n" longdesc;
8391         if List.mem ProtocolLimitWarning flags then
8392           pr "%s\n\n" protocol_limit_warning;
8393         if List.mem DangerWillRobinson flags then
8394           pr "%s\n\n" danger_will_robinson;
8395         match deprecation_notice flags with
8396         | None -> ()
8397         | Some txt -> pr "%s\n\n" txt
8398       )
8399   ) all_functions_sorted;
8400
8401   (* End of file. *)
8402   pr "\
8403 =cut
8404
8405 1;
8406
8407 =back
8408
8409 =head1 COPYRIGHT
8410
8411 Copyright (C) %s Red Hat Inc.
8412
8413 =head1 LICENSE
8414
8415 Please see the file COPYING.LIB for the full license.
8416
8417 =head1 SEE ALSO
8418
8419 L<guestfs(3)>,
8420 L<guestfish(1)>,
8421 L<http://libguestfs.org>,
8422 L<Sys::Guestfs::Lib(3)>.
8423
8424 =cut
8425 " copyright_years
8426
8427 and generate_perl_prototype name style =
8428   (match fst style with
8429    | RErr -> ()
8430    | RBool n
8431    | RInt n
8432    | RInt64 n
8433    | RConstString n
8434    | RConstOptString n
8435    | RString n
8436    | RBufferOut n -> pr "$%s = " n
8437    | RStruct (n,_)
8438    | RHashtable n -> pr "%%%s = " n
8439    | RStringList n
8440    | RStructList (n,_) -> pr "@%s = " n
8441   );
8442   pr "$h->%s (" name;
8443   let comma = ref false in
8444   List.iter (
8445     fun arg ->
8446       if !comma then pr ", ";
8447       comma := true;
8448       match arg with
8449       | Pathname n | Device n | Dev_or_Path n | String n
8450       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8451           pr "$%s" n
8452       | StringList n | DeviceList n ->
8453           pr "\\@%s" n
8454   ) (snd style);
8455   pr ");"
8456
8457 (* Generate Python C module. *)
8458 and generate_python_c () =
8459   generate_header CStyle LGPLv2plus;
8460
8461   pr "\
8462 #include <Python.h>
8463
8464 #include <stdio.h>
8465 #include <stdlib.h>
8466 #include <assert.h>
8467
8468 #include \"guestfs.h\"
8469
8470 typedef struct {
8471   PyObject_HEAD
8472   guestfs_h *g;
8473 } Pyguestfs_Object;
8474
8475 static guestfs_h *
8476 get_handle (PyObject *obj)
8477 {
8478   assert (obj);
8479   assert (obj != Py_None);
8480   return ((Pyguestfs_Object *) obj)->g;
8481 }
8482
8483 static PyObject *
8484 put_handle (guestfs_h *g)
8485 {
8486   assert (g);
8487   return
8488     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8489 }
8490
8491 /* This list should be freed (but not the strings) after use. */
8492 static char **
8493 get_string_list (PyObject *obj)
8494 {
8495   int i, len;
8496   char **r;
8497
8498   assert (obj);
8499
8500   if (!PyList_Check (obj)) {
8501     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8502     return NULL;
8503   }
8504
8505   len = PyList_Size (obj);
8506   r = malloc (sizeof (char *) * (len+1));
8507   if (r == NULL) {
8508     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8509     return NULL;
8510   }
8511
8512   for (i = 0; i < len; ++i)
8513     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8514   r[len] = NULL;
8515
8516   return r;
8517 }
8518
8519 static PyObject *
8520 put_string_list (char * const * const argv)
8521 {
8522   PyObject *list;
8523   int argc, i;
8524
8525   for (argc = 0; argv[argc] != NULL; ++argc)
8526     ;
8527
8528   list = PyList_New (argc);
8529   for (i = 0; i < argc; ++i)
8530     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8531
8532   return list;
8533 }
8534
8535 static PyObject *
8536 put_table (char * const * const argv)
8537 {
8538   PyObject *list, *item;
8539   int argc, i;
8540
8541   for (argc = 0; argv[argc] != NULL; ++argc)
8542     ;
8543
8544   list = PyList_New (argc >> 1);
8545   for (i = 0; i < argc; i += 2) {
8546     item = PyTuple_New (2);
8547     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8548     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8549     PyList_SetItem (list, i >> 1, item);
8550   }
8551
8552   return list;
8553 }
8554
8555 static void
8556 free_strings (char **argv)
8557 {
8558   int argc;
8559
8560   for (argc = 0; argv[argc] != NULL; ++argc)
8561     free (argv[argc]);
8562   free (argv);
8563 }
8564
8565 static PyObject *
8566 py_guestfs_create (PyObject *self, PyObject *args)
8567 {
8568   guestfs_h *g;
8569
8570   g = guestfs_create ();
8571   if (g == NULL) {
8572     PyErr_SetString (PyExc_RuntimeError,
8573                      \"guestfs.create: failed to allocate handle\");
8574     return NULL;
8575   }
8576   guestfs_set_error_handler (g, NULL, NULL);
8577   return put_handle (g);
8578 }
8579
8580 static PyObject *
8581 py_guestfs_close (PyObject *self, PyObject *args)
8582 {
8583   PyObject *py_g;
8584   guestfs_h *g;
8585
8586   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
8587     return NULL;
8588   g = get_handle (py_g);
8589
8590   guestfs_close (g);
8591
8592   Py_INCREF (Py_None);
8593   return Py_None;
8594 }
8595
8596 ";
8597
8598   let emit_put_list_function typ =
8599     pr "static PyObject *\n";
8600     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
8601     pr "{\n";
8602     pr "  PyObject *list;\n";
8603     pr "  int i;\n";
8604     pr "\n";
8605     pr "  list = PyList_New (%ss->len);\n" typ;
8606     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
8607     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
8608     pr "  return list;\n";
8609     pr "};\n";
8610     pr "\n"
8611   in
8612
8613   (* Structures, turned into Python dictionaries. *)
8614   List.iter (
8615     fun (typ, cols) ->
8616       pr "static PyObject *\n";
8617       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
8618       pr "{\n";
8619       pr "  PyObject *dict;\n";
8620       pr "\n";
8621       pr "  dict = PyDict_New ();\n";
8622       List.iter (
8623         function
8624         | name, FString ->
8625             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8626             pr "                        PyString_FromString (%s->%s));\n"
8627               typ name
8628         | name, FBuffer ->
8629             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8630             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
8631               typ name typ name
8632         | name, FUUID ->
8633             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8634             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
8635               typ name
8636         | name, (FBytes|FUInt64) ->
8637             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8638             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
8639               typ name
8640         | name, FInt64 ->
8641             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8642             pr "                        PyLong_FromLongLong (%s->%s));\n"
8643               typ name
8644         | name, FUInt32 ->
8645             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8646             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
8647               typ name
8648         | name, FInt32 ->
8649             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8650             pr "                        PyLong_FromLong (%s->%s));\n"
8651               typ name
8652         | name, FOptPercent ->
8653             pr "  if (%s->%s >= 0)\n" typ name;
8654             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
8655             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
8656               typ name;
8657             pr "  else {\n";
8658             pr "    Py_INCREF (Py_None);\n";
8659             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
8660             pr "  }\n"
8661         | name, FChar ->
8662             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8663             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
8664       ) cols;
8665       pr "  return dict;\n";
8666       pr "};\n";
8667       pr "\n";
8668
8669   ) structs;
8670
8671   (* Emit a put_TYPE_list function definition only if that function is used. *)
8672   List.iter (
8673     function
8674     | typ, (RStructListOnly | RStructAndList) ->
8675         (* generate the function for typ *)
8676         emit_put_list_function typ
8677     | typ, _ -> () (* empty *)
8678   ) (rstructs_used_by all_functions);
8679
8680   (* Python wrapper functions. *)
8681   List.iter (
8682     fun (name, style, _, _, _, _, _) ->
8683       pr "static PyObject *\n";
8684       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
8685       pr "{\n";
8686
8687       pr "  PyObject *py_g;\n";
8688       pr "  guestfs_h *g;\n";
8689       pr "  PyObject *py_r;\n";
8690
8691       let error_code =
8692         match fst style with
8693         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
8694         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8695         | RConstString _ | RConstOptString _ ->
8696             pr "  const char *r;\n"; "NULL"
8697         | RString _ -> pr "  char *r;\n"; "NULL"
8698         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
8699         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
8700         | RStructList (_, typ) ->
8701             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8702         | RBufferOut _ ->
8703             pr "  char *r;\n";
8704             pr "  size_t size;\n";
8705             "NULL" in
8706
8707       List.iter (
8708         function
8709         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8710             pr "  const char *%s;\n" n
8711         | OptString n -> pr "  const char *%s;\n" n
8712         | StringList n | DeviceList n ->
8713             pr "  PyObject *py_%s;\n" n;
8714             pr "  char **%s;\n" n
8715         | Bool n -> pr "  int %s;\n" n
8716         | Int n -> pr "  int %s;\n" n
8717         | Int64 n -> pr "  long long %s;\n" n
8718       ) (snd style);
8719
8720       pr "\n";
8721
8722       (* Convert the parameters. *)
8723       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
8724       List.iter (
8725         function
8726         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
8727         | OptString _ -> pr "z"
8728         | StringList _ | DeviceList _ -> pr "O"
8729         | Bool _ -> pr "i" (* XXX Python has booleans? *)
8730         | Int _ -> pr "i"
8731         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
8732                              * emulate C's int/long/long long in Python?
8733                              *)
8734       ) (snd style);
8735       pr ":guestfs_%s\",\n" name;
8736       pr "                         &py_g";
8737       List.iter (
8738         function
8739         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
8740         | OptString n -> pr ", &%s" n
8741         | StringList n | DeviceList n -> pr ", &py_%s" n
8742         | Bool n -> pr ", &%s" n
8743         | Int n -> pr ", &%s" n
8744         | Int64 n -> pr ", &%s" n
8745       ) (snd style);
8746
8747       pr "))\n";
8748       pr "    return NULL;\n";
8749
8750       pr "  g = get_handle (py_g);\n";
8751       List.iter (
8752         function
8753         | Pathname _ | Device _ | Dev_or_Path _ | String _
8754         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8755         | StringList n | DeviceList n ->
8756             pr "  %s = get_string_list (py_%s);\n" n n;
8757             pr "  if (!%s) return NULL;\n" n
8758       ) (snd style);
8759
8760       pr "\n";
8761
8762       pr "  r = guestfs_%s " name;
8763       generate_c_call_args ~handle:"g" style;
8764       pr ";\n";
8765
8766       List.iter (
8767         function
8768         | Pathname _ | Device _ | Dev_or_Path _ | String _
8769         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8770         | StringList n | DeviceList n ->
8771             pr "  free (%s);\n" n
8772       ) (snd style);
8773
8774       pr "  if (r == %s) {\n" error_code;
8775       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
8776       pr "    return NULL;\n";
8777       pr "  }\n";
8778       pr "\n";
8779
8780       (match fst style with
8781        | RErr ->
8782            pr "  Py_INCREF (Py_None);\n";
8783            pr "  py_r = Py_None;\n"
8784        | RInt _
8785        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
8786        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
8787        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
8788        | RConstOptString _ ->
8789            pr "  if (r)\n";
8790            pr "    py_r = PyString_FromString (r);\n";
8791            pr "  else {\n";
8792            pr "    Py_INCREF (Py_None);\n";
8793            pr "    py_r = Py_None;\n";
8794            pr "  }\n"
8795        | RString _ ->
8796            pr "  py_r = PyString_FromString (r);\n";
8797            pr "  free (r);\n"
8798        | RStringList _ ->
8799            pr "  py_r = put_string_list (r);\n";
8800            pr "  free_strings (r);\n"
8801        | RStruct (_, typ) ->
8802            pr "  py_r = put_%s (r);\n" typ;
8803            pr "  guestfs_free_%s (r);\n" typ
8804        | RStructList (_, typ) ->
8805            pr "  py_r = put_%s_list (r);\n" typ;
8806            pr "  guestfs_free_%s_list (r);\n" typ
8807        | RHashtable n ->
8808            pr "  py_r = put_table (r);\n";
8809            pr "  free_strings (r);\n"
8810        | RBufferOut _ ->
8811            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
8812            pr "  free (r);\n"
8813       );
8814
8815       pr "  return py_r;\n";
8816       pr "}\n";
8817       pr "\n"
8818   ) all_functions;
8819
8820   (* Table of functions. *)
8821   pr "static PyMethodDef methods[] = {\n";
8822   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
8823   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
8824   List.iter (
8825     fun (name, _, _, _, _, _, _) ->
8826       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
8827         name name
8828   ) all_functions;
8829   pr "  { NULL, NULL, 0, NULL }\n";
8830   pr "};\n";
8831   pr "\n";
8832
8833   (* Init function. *)
8834   pr "\
8835 void
8836 initlibguestfsmod (void)
8837 {
8838   static int initialized = 0;
8839
8840   if (initialized) return;
8841   Py_InitModule ((char *) \"libguestfsmod\", methods);
8842   initialized = 1;
8843 }
8844 "
8845
8846 (* Generate Python module. *)
8847 and generate_python_py () =
8848   generate_header HashStyle LGPLv2plus;
8849
8850   pr "\
8851 u\"\"\"Python bindings for libguestfs
8852
8853 import guestfs
8854 g = guestfs.GuestFS ()
8855 g.add_drive (\"guest.img\")
8856 g.launch ()
8857 parts = g.list_partitions ()
8858
8859 The guestfs module provides a Python binding to the libguestfs API
8860 for examining and modifying virtual machine disk images.
8861
8862 Amongst the things this is good for: making batch configuration
8863 changes to guests, getting disk used/free statistics (see also:
8864 virt-df), migrating between virtualization systems (see also:
8865 virt-p2v), performing partial backups, performing partial guest
8866 clones, cloning guests and changing registry/UUID/hostname info, and
8867 much else besides.
8868
8869 Libguestfs uses Linux kernel and qemu code, and can access any type of
8870 guest filesystem that Linux and qemu can, including but not limited
8871 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8872 schemes, qcow, qcow2, vmdk.
8873
8874 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8875 LVs, what filesystem is in each LV, etc.).  It can also run commands
8876 in the context of the guest.  Also you can access filesystems over FTP.
8877
8878 Errors which happen while using the API are turned into Python
8879 RuntimeError exceptions.
8880
8881 To create a guestfs handle you usually have to perform the following
8882 sequence of calls:
8883
8884 # Create the handle, call add_drive at least once, and possibly
8885 # several times if the guest has multiple block devices:
8886 g = guestfs.GuestFS ()
8887 g.add_drive (\"guest.img\")
8888
8889 # Launch the qemu subprocess and wait for it to become ready:
8890 g.launch ()
8891
8892 # Now you can issue commands, for example:
8893 logvols = g.lvs ()
8894
8895 \"\"\"
8896
8897 import libguestfsmod
8898
8899 class GuestFS:
8900     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
8901
8902     def __init__ (self):
8903         \"\"\"Create a new libguestfs handle.\"\"\"
8904         self._o = libguestfsmod.create ()
8905
8906     def __del__ (self):
8907         libguestfsmod.close (self._o)
8908
8909 ";
8910
8911   List.iter (
8912     fun (name, style, _, flags, _, _, longdesc) ->
8913       pr "    def %s " name;
8914       generate_py_call_args ~handle:"self" (snd style);
8915       pr ":\n";
8916
8917       if not (List.mem NotInDocs flags) then (
8918         let doc = replace_str longdesc "C<guestfs_" "C<g." in
8919         let doc =
8920           match fst style with
8921           | RErr | RInt _ | RInt64 _ | RBool _
8922           | RConstOptString _ | RConstString _
8923           | RString _ | RBufferOut _ -> doc
8924           | RStringList _ ->
8925               doc ^ "\n\nThis function returns a list of strings."
8926           | RStruct (_, typ) ->
8927               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
8928           | RStructList (_, typ) ->
8929               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
8930           | RHashtable _ ->
8931               doc ^ "\n\nThis function returns a dictionary." in
8932         let doc =
8933           if List.mem ProtocolLimitWarning flags then
8934             doc ^ "\n\n" ^ protocol_limit_warning
8935           else doc in
8936         let doc =
8937           if List.mem DangerWillRobinson flags then
8938             doc ^ "\n\n" ^ danger_will_robinson
8939           else doc in
8940         let doc =
8941           match deprecation_notice flags with
8942           | None -> doc
8943           | Some txt -> doc ^ "\n\n" ^ txt in
8944         let doc = pod2text ~width:60 name doc in
8945         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
8946         let doc = String.concat "\n        " doc in
8947         pr "        u\"\"\"%s\"\"\"\n" doc;
8948       );
8949       pr "        return libguestfsmod.%s " name;
8950       generate_py_call_args ~handle:"self._o" (snd style);
8951       pr "\n";
8952       pr "\n";
8953   ) all_functions
8954
8955 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
8956 and generate_py_call_args ~handle args =
8957   pr "(%s" handle;
8958   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
8959   pr ")"
8960
8961 (* Useful if you need the longdesc POD text as plain text.  Returns a
8962  * list of lines.
8963  *
8964  * Because this is very slow (the slowest part of autogeneration),
8965  * we memoize the results.
8966  *)
8967 and pod2text ~width name longdesc =
8968   let key = width, name, longdesc in
8969   try Hashtbl.find pod2text_memo key
8970   with Not_found ->
8971     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
8972     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
8973     close_out chan;
8974     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
8975     let chan = open_process_in cmd in
8976     let lines = ref [] in
8977     let rec loop i =
8978       let line = input_line chan in
8979       if i = 1 then             (* discard the first line of output *)
8980         loop (i+1)
8981       else (
8982         let line = triml line in
8983         lines := line :: !lines;
8984         loop (i+1)
8985       ) in
8986     let lines = try loop 1 with End_of_file -> List.rev !lines in
8987     unlink filename;
8988     (match close_process_in chan with
8989      | WEXITED 0 -> ()
8990      | WEXITED i ->
8991          failwithf "pod2text: process exited with non-zero status (%d)" i
8992      | WSIGNALED i | WSTOPPED i ->
8993          failwithf "pod2text: process signalled or stopped by signal %d" i
8994     );
8995     Hashtbl.add pod2text_memo key lines;
8996     pod2text_memo_updated ();
8997     lines
8998
8999 (* Generate ruby bindings. *)
9000 and generate_ruby_c () =
9001   generate_header CStyle LGPLv2plus;
9002
9003   pr "\
9004 #include <stdio.h>
9005 #include <stdlib.h>
9006
9007 #include <ruby.h>
9008
9009 #include \"guestfs.h\"
9010
9011 #include \"extconf.h\"
9012
9013 /* For Ruby < 1.9 */
9014 #ifndef RARRAY_LEN
9015 #define RARRAY_LEN(r) (RARRAY((r))->len)
9016 #endif
9017
9018 static VALUE m_guestfs;                 /* guestfs module */
9019 static VALUE c_guestfs;                 /* guestfs_h handle */
9020 static VALUE e_Error;                   /* used for all errors */
9021
9022 static void ruby_guestfs_free (void *p)
9023 {
9024   if (!p) return;
9025   guestfs_close ((guestfs_h *) p);
9026 }
9027
9028 static VALUE ruby_guestfs_create (VALUE m)
9029 {
9030   guestfs_h *g;
9031
9032   g = guestfs_create ();
9033   if (!g)
9034     rb_raise (e_Error, \"failed to create guestfs handle\");
9035
9036   /* Don't print error messages to stderr by default. */
9037   guestfs_set_error_handler (g, NULL, NULL);
9038
9039   /* Wrap it, and make sure the close function is called when the
9040    * handle goes away.
9041    */
9042   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9043 }
9044
9045 static VALUE ruby_guestfs_close (VALUE gv)
9046 {
9047   guestfs_h *g;
9048   Data_Get_Struct (gv, guestfs_h, g);
9049
9050   ruby_guestfs_free (g);
9051   DATA_PTR (gv) = NULL;
9052
9053   return Qnil;
9054 }
9055
9056 ";
9057
9058   List.iter (
9059     fun (name, style, _, _, _, _, _) ->
9060       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9061       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9062       pr ")\n";
9063       pr "{\n";
9064       pr "  guestfs_h *g;\n";
9065       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9066       pr "  if (!g)\n";
9067       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9068         name;
9069       pr "\n";
9070
9071       List.iter (
9072         function
9073         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9074             pr "  Check_Type (%sv, T_STRING);\n" n;
9075             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9076             pr "  if (!%s)\n" n;
9077             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9078             pr "              \"%s\", \"%s\");\n" n name
9079         | OptString n ->
9080             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9081         | StringList n | DeviceList n ->
9082             pr "  char **%s;\n" n;
9083             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9084             pr "  {\n";
9085             pr "    int i, len;\n";
9086             pr "    len = RARRAY_LEN (%sv);\n" n;
9087             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9088               n;
9089             pr "    for (i = 0; i < len; ++i) {\n";
9090             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9091             pr "      %s[i] = StringValueCStr (v);\n" n;
9092             pr "    }\n";
9093             pr "    %s[len] = NULL;\n" n;
9094             pr "  }\n";
9095         | Bool n ->
9096             pr "  int %s = RTEST (%sv);\n" n n
9097         | Int n ->
9098             pr "  int %s = NUM2INT (%sv);\n" n n
9099         | Int64 n ->
9100             pr "  long long %s = NUM2LL (%sv);\n" n n
9101       ) (snd style);
9102       pr "\n";
9103
9104       let error_code =
9105         match fst style with
9106         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9107         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9108         | RConstString _ | RConstOptString _ ->
9109             pr "  const char *r;\n"; "NULL"
9110         | RString _ -> pr "  char *r;\n"; "NULL"
9111         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9112         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9113         | RStructList (_, typ) ->
9114             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9115         | RBufferOut _ ->
9116             pr "  char *r;\n";
9117             pr "  size_t size;\n";
9118             "NULL" in
9119       pr "\n";
9120
9121       pr "  r = guestfs_%s " name;
9122       generate_c_call_args ~handle:"g" style;
9123       pr ";\n";
9124
9125       List.iter (
9126         function
9127         | Pathname _ | Device _ | Dev_or_Path _ | String _
9128         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9129         | StringList n | DeviceList n ->
9130             pr "  free (%s);\n" n
9131       ) (snd style);
9132
9133       pr "  if (r == %s)\n" error_code;
9134       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9135       pr "\n";
9136
9137       (match fst style with
9138        | RErr ->
9139            pr "  return Qnil;\n"
9140        | RInt _ | RBool _ ->
9141            pr "  return INT2NUM (r);\n"
9142        | RInt64 _ ->
9143            pr "  return ULL2NUM (r);\n"
9144        | RConstString _ ->
9145            pr "  return rb_str_new2 (r);\n";
9146        | RConstOptString _ ->
9147            pr "  if (r)\n";
9148            pr "    return rb_str_new2 (r);\n";
9149            pr "  else\n";
9150            pr "    return Qnil;\n";
9151        | RString _ ->
9152            pr "  VALUE rv = rb_str_new2 (r);\n";
9153            pr "  free (r);\n";
9154            pr "  return rv;\n";
9155        | RStringList _ ->
9156            pr "  int i, len = 0;\n";
9157            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9158            pr "  VALUE rv = rb_ary_new2 (len);\n";
9159            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9160            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9161            pr "    free (r[i]);\n";
9162            pr "  }\n";
9163            pr "  free (r);\n";
9164            pr "  return rv;\n"
9165        | RStruct (_, typ) ->
9166            let cols = cols_of_struct typ in
9167            generate_ruby_struct_code typ cols
9168        | RStructList (_, typ) ->
9169            let cols = cols_of_struct typ in
9170            generate_ruby_struct_list_code typ cols
9171        | RHashtable _ ->
9172            pr "  VALUE rv = rb_hash_new ();\n";
9173            pr "  int i;\n";
9174            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9175            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9176            pr "    free (r[i]);\n";
9177            pr "    free (r[i+1]);\n";
9178            pr "  }\n";
9179            pr "  free (r);\n";
9180            pr "  return rv;\n"
9181        | RBufferOut _ ->
9182            pr "  VALUE rv = rb_str_new (r, size);\n";
9183            pr "  free (r);\n";
9184            pr "  return rv;\n";
9185       );
9186
9187       pr "}\n";
9188       pr "\n"
9189   ) all_functions;
9190
9191   pr "\
9192 /* Initialize the module. */
9193 void Init__guestfs ()
9194 {
9195   m_guestfs = rb_define_module (\"Guestfs\");
9196   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9197   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9198
9199   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9200   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9201
9202 ";
9203   (* Define the rest of the methods. *)
9204   List.iter (
9205     fun (name, style, _, _, _, _, _) ->
9206       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9207       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9208   ) all_functions;
9209
9210   pr "}\n"
9211
9212 (* Ruby code to return a struct. *)
9213 and generate_ruby_struct_code typ cols =
9214   pr "  VALUE rv = rb_hash_new ();\n";
9215   List.iter (
9216     function
9217     | name, FString ->
9218         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9219     | name, FBuffer ->
9220         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9221     | name, FUUID ->
9222         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9223     | name, (FBytes|FUInt64) ->
9224         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9225     | name, FInt64 ->
9226         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9227     | name, FUInt32 ->
9228         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9229     | name, FInt32 ->
9230         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9231     | name, FOptPercent ->
9232         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9233     | name, FChar -> (* XXX wrong? *)
9234         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9235   ) cols;
9236   pr "  guestfs_free_%s (r);\n" typ;
9237   pr "  return rv;\n"
9238
9239 (* Ruby code to return a struct list. *)
9240 and generate_ruby_struct_list_code typ cols =
9241   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9242   pr "  int i;\n";
9243   pr "  for (i = 0; i < r->len; ++i) {\n";
9244   pr "    VALUE hv = rb_hash_new ();\n";
9245   List.iter (
9246     function
9247     | name, FString ->
9248         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9249     | name, FBuffer ->
9250         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
9251     | name, FUUID ->
9252         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9253     | name, (FBytes|FUInt64) ->
9254         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9255     | name, FInt64 ->
9256         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9257     | name, FUInt32 ->
9258         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9259     | name, FInt32 ->
9260         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9261     | name, FOptPercent ->
9262         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9263     | name, FChar -> (* XXX wrong? *)
9264         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9265   ) cols;
9266   pr "    rb_ary_push (rv, hv);\n";
9267   pr "  }\n";
9268   pr "  guestfs_free_%s_list (r);\n" typ;
9269   pr "  return rv;\n"
9270
9271 (* Generate Java bindings GuestFS.java file. *)
9272 and generate_java_java () =
9273   generate_header CStyle LGPLv2plus;
9274
9275   pr "\
9276 package com.redhat.et.libguestfs;
9277
9278 import java.util.HashMap;
9279 import com.redhat.et.libguestfs.LibGuestFSException;
9280 import com.redhat.et.libguestfs.PV;
9281 import com.redhat.et.libguestfs.VG;
9282 import com.redhat.et.libguestfs.LV;
9283 import com.redhat.et.libguestfs.Stat;
9284 import com.redhat.et.libguestfs.StatVFS;
9285 import com.redhat.et.libguestfs.IntBool;
9286 import com.redhat.et.libguestfs.Dirent;
9287
9288 /**
9289  * The GuestFS object is a libguestfs handle.
9290  *
9291  * @author rjones
9292  */
9293 public class GuestFS {
9294   // Load the native code.
9295   static {
9296     System.loadLibrary (\"guestfs_jni\");
9297   }
9298
9299   /**
9300    * The native guestfs_h pointer.
9301    */
9302   long g;
9303
9304   /**
9305    * Create a libguestfs handle.
9306    *
9307    * @throws LibGuestFSException
9308    */
9309   public GuestFS () throws LibGuestFSException
9310   {
9311     g = _create ();
9312   }
9313   private native long _create () throws LibGuestFSException;
9314
9315   /**
9316    * Close a libguestfs handle.
9317    *
9318    * You can also leave handles to be collected by the garbage
9319    * collector, but this method ensures that the resources used
9320    * by the handle are freed up immediately.  If you call any
9321    * other methods after closing the handle, you will get an
9322    * exception.
9323    *
9324    * @throws LibGuestFSException
9325    */
9326   public void close () throws LibGuestFSException
9327   {
9328     if (g != 0)
9329       _close (g);
9330     g = 0;
9331   }
9332   private native void _close (long g) throws LibGuestFSException;
9333
9334   public void finalize () throws LibGuestFSException
9335   {
9336     close ();
9337   }
9338
9339 ";
9340
9341   List.iter (
9342     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9343       if not (List.mem NotInDocs flags); then (
9344         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9345         let doc =
9346           if List.mem ProtocolLimitWarning flags then
9347             doc ^ "\n\n" ^ protocol_limit_warning
9348           else doc in
9349         let doc =
9350           if List.mem DangerWillRobinson flags then
9351             doc ^ "\n\n" ^ danger_will_robinson
9352           else doc in
9353         let doc =
9354           match deprecation_notice flags with
9355           | None -> doc
9356           | Some txt -> doc ^ "\n\n" ^ txt in
9357         let doc = pod2text ~width:60 name doc in
9358         let doc = List.map (            (* RHBZ#501883 *)
9359           function
9360           | "" -> "<p>"
9361           | nonempty -> nonempty
9362         ) doc in
9363         let doc = String.concat "\n   * " doc in
9364
9365         pr "  /**\n";
9366         pr "   * %s\n" shortdesc;
9367         pr "   * <p>\n";
9368         pr "   * %s\n" doc;
9369         pr "   * @throws LibGuestFSException\n";
9370         pr "   */\n";
9371         pr "  ";
9372       );
9373       generate_java_prototype ~public:true ~semicolon:false name style;
9374       pr "\n";
9375       pr "  {\n";
9376       pr "    if (g == 0)\n";
9377       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9378         name;
9379       pr "    ";
9380       if fst style <> RErr then pr "return ";
9381       pr "_%s " name;
9382       generate_java_call_args ~handle:"g" (snd style);
9383       pr ";\n";
9384       pr "  }\n";
9385       pr "  ";
9386       generate_java_prototype ~privat:true ~native:true name style;
9387       pr "\n";
9388       pr "\n";
9389   ) all_functions;
9390
9391   pr "}\n"
9392
9393 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9394 and generate_java_call_args ~handle args =
9395   pr "(%s" handle;
9396   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9397   pr ")"
9398
9399 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9400     ?(semicolon=true) name style =
9401   if privat then pr "private ";
9402   if public then pr "public ";
9403   if native then pr "native ";
9404
9405   (* return type *)
9406   (match fst style with
9407    | RErr -> pr "void ";
9408    | RInt _ -> pr "int ";
9409    | RInt64 _ -> pr "long ";
9410    | RBool _ -> pr "boolean ";
9411    | RConstString _ | RConstOptString _ | RString _
9412    | RBufferOut _ -> pr "String ";
9413    | RStringList _ -> pr "String[] ";
9414    | RStruct (_, typ) ->
9415        let name = java_name_of_struct typ in
9416        pr "%s " name;
9417    | RStructList (_, typ) ->
9418        let name = java_name_of_struct typ in
9419        pr "%s[] " name;
9420    | RHashtable _ -> pr "HashMap<String,String> ";
9421   );
9422
9423   if native then pr "_%s " name else pr "%s " name;
9424   pr "(";
9425   let needs_comma = ref false in
9426   if native then (
9427     pr "long g";
9428     needs_comma := true
9429   );
9430
9431   (* args *)
9432   List.iter (
9433     fun arg ->
9434       if !needs_comma then pr ", ";
9435       needs_comma := true;
9436
9437       match arg with
9438       | Pathname n
9439       | Device n | Dev_or_Path n
9440       | String n
9441       | OptString n
9442       | FileIn n
9443       | FileOut n ->
9444           pr "String %s" n
9445       | StringList n | DeviceList n ->
9446           pr "String[] %s" n
9447       | Bool n ->
9448           pr "boolean %s" n
9449       | Int n ->
9450           pr "int %s" n
9451       | Int64 n ->
9452           pr "long %s" n
9453   ) (snd style);
9454
9455   pr ")\n";
9456   pr "    throws LibGuestFSException";
9457   if semicolon then pr ";"
9458
9459 and generate_java_struct jtyp cols () =
9460   generate_header CStyle LGPLv2plus;
9461
9462   pr "\
9463 package com.redhat.et.libguestfs;
9464
9465 /**
9466  * Libguestfs %s structure.
9467  *
9468  * @author rjones
9469  * @see GuestFS
9470  */
9471 public class %s {
9472 " jtyp jtyp;
9473
9474   List.iter (
9475     function
9476     | name, FString
9477     | name, FUUID
9478     | name, FBuffer -> pr "  public String %s;\n" name
9479     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9480     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9481     | name, FChar -> pr "  public char %s;\n" name
9482     | name, FOptPercent ->
9483         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9484         pr "  public float %s;\n" name
9485   ) cols;
9486
9487   pr "}\n"
9488
9489 and generate_java_c () =
9490   generate_header CStyle LGPLv2plus;
9491
9492   pr "\
9493 #include <stdio.h>
9494 #include <stdlib.h>
9495 #include <string.h>
9496
9497 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9498 #include \"guestfs.h\"
9499
9500 /* Note that this function returns.  The exception is not thrown
9501  * until after the wrapper function returns.
9502  */
9503 static void
9504 throw_exception (JNIEnv *env, const char *msg)
9505 {
9506   jclass cl;
9507   cl = (*env)->FindClass (env,
9508                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9509   (*env)->ThrowNew (env, cl, msg);
9510 }
9511
9512 JNIEXPORT jlong JNICALL
9513 Java_com_redhat_et_libguestfs_GuestFS__1create
9514   (JNIEnv *env, jobject obj)
9515 {
9516   guestfs_h *g;
9517
9518   g = guestfs_create ();
9519   if (g == NULL) {
9520     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9521     return 0;
9522   }
9523   guestfs_set_error_handler (g, NULL, NULL);
9524   return (jlong) (long) g;
9525 }
9526
9527 JNIEXPORT void JNICALL
9528 Java_com_redhat_et_libguestfs_GuestFS__1close
9529   (JNIEnv *env, jobject obj, jlong jg)
9530 {
9531   guestfs_h *g = (guestfs_h *) (long) jg;
9532   guestfs_close (g);
9533 }
9534
9535 ";
9536
9537   List.iter (
9538     fun (name, style, _, _, _, _, _) ->
9539       pr "JNIEXPORT ";
9540       (match fst style with
9541        | RErr -> pr "void ";
9542        | RInt _ -> pr "jint ";
9543        | RInt64 _ -> pr "jlong ";
9544        | RBool _ -> pr "jboolean ";
9545        | RConstString _ | RConstOptString _ | RString _
9546        | RBufferOut _ -> pr "jstring ";
9547        | RStruct _ | RHashtable _ ->
9548            pr "jobject ";
9549        | RStringList _ | RStructList _ ->
9550            pr "jobjectArray ";
9551       );
9552       pr "JNICALL\n";
9553       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9554       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9555       pr "\n";
9556       pr "  (JNIEnv *env, jobject obj, jlong jg";
9557       List.iter (
9558         function
9559         | Pathname n
9560         | Device n | Dev_or_Path n
9561         | String n
9562         | OptString n
9563         | FileIn n
9564         | FileOut n ->
9565             pr ", jstring j%s" n
9566         | StringList n | DeviceList n ->
9567             pr ", jobjectArray j%s" n
9568         | Bool n ->
9569             pr ", jboolean j%s" n
9570         | Int n ->
9571             pr ", jint j%s" n
9572         | Int64 n ->
9573             pr ", jlong j%s" n
9574       ) (snd style);
9575       pr ")\n";
9576       pr "{\n";
9577       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
9578       let error_code, no_ret =
9579         match fst style with
9580         | RErr -> pr "  int r;\n"; "-1", ""
9581         | RBool _
9582         | RInt _ -> pr "  int r;\n"; "-1", "0"
9583         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
9584         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9585         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9586         | RString _ ->
9587             pr "  jstring jr;\n";
9588             pr "  char *r;\n"; "NULL", "NULL"
9589         | RStringList _ ->
9590             pr "  jobjectArray jr;\n";
9591             pr "  int r_len;\n";
9592             pr "  jclass cl;\n";
9593             pr "  jstring jstr;\n";
9594             pr "  char **r;\n"; "NULL", "NULL"
9595         | RStruct (_, typ) ->
9596             pr "  jobject jr;\n";
9597             pr "  jclass cl;\n";
9598             pr "  jfieldID fl;\n";
9599             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
9600         | RStructList (_, typ) ->
9601             pr "  jobjectArray jr;\n";
9602             pr "  jclass cl;\n";
9603             pr "  jfieldID fl;\n";
9604             pr "  jobject jfl;\n";
9605             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
9606         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
9607         | RBufferOut _ ->
9608             pr "  jstring jr;\n";
9609             pr "  char *r;\n";
9610             pr "  size_t size;\n";
9611             "NULL", "NULL" in
9612       List.iter (
9613         function
9614         | Pathname n
9615         | Device n | Dev_or_Path n
9616         | String n
9617         | OptString n
9618         | FileIn n
9619         | FileOut n ->
9620             pr "  const char *%s;\n" n
9621         | StringList n | DeviceList n ->
9622             pr "  int %s_len;\n" n;
9623             pr "  const char **%s;\n" n
9624         | Bool n
9625         | Int n ->
9626             pr "  int %s;\n" n
9627         | Int64 n ->
9628             pr "  int64_t %s;\n" n
9629       ) (snd style);
9630
9631       let needs_i =
9632         (match fst style with
9633          | RStringList _ | RStructList _ -> true
9634          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
9635          | RConstOptString _
9636          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
9637           List.exists (function
9638                        | StringList _ -> true
9639                        | DeviceList _ -> true
9640                        | _ -> false) (snd style) in
9641       if needs_i then
9642         pr "  int i;\n";
9643
9644       pr "\n";
9645
9646       (* Get the parameters. *)
9647       List.iter (
9648         function
9649         | Pathname n
9650         | Device n | Dev_or_Path n
9651         | String n
9652         | FileIn n
9653         | FileOut n ->
9654             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
9655         | OptString n ->
9656             (* This is completely undocumented, but Java null becomes
9657              * a NULL parameter.
9658              *)
9659             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
9660         | StringList n | DeviceList n ->
9661             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
9662             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
9663             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9664             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9665               n;
9666             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
9667             pr "  }\n";
9668             pr "  %s[%s_len] = NULL;\n" n n;
9669         | Bool n
9670         | Int n
9671         | Int64 n ->
9672             pr "  %s = j%s;\n" n n
9673       ) (snd style);
9674
9675       (* Make the call. *)
9676       pr "  r = guestfs_%s " name;
9677       generate_c_call_args ~handle:"g" style;
9678       pr ";\n";
9679
9680       (* Release the parameters. *)
9681       List.iter (
9682         function
9683         | Pathname n
9684         | Device n | Dev_or_Path n
9685         | String n
9686         | FileIn n
9687         | FileOut n ->
9688             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9689         | OptString n ->
9690             pr "  if (j%s)\n" n;
9691             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9692         | StringList n | DeviceList n ->
9693             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9694             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9695               n;
9696             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
9697             pr "  }\n";
9698             pr "  free (%s);\n" n
9699         | Bool n
9700         | Int n
9701         | Int64 n -> ()
9702       ) (snd style);
9703
9704       (* Check for errors. *)
9705       pr "  if (r == %s) {\n" error_code;
9706       pr "    throw_exception (env, guestfs_last_error (g));\n";
9707       pr "    return %s;\n" no_ret;
9708       pr "  }\n";
9709
9710       (* Return value. *)
9711       (match fst style with
9712        | RErr -> ()
9713        | RInt _ -> pr "  return (jint) r;\n"
9714        | RBool _ -> pr "  return (jboolean) r;\n"
9715        | RInt64 _ -> pr "  return (jlong) r;\n"
9716        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
9717        | RConstOptString _ ->
9718            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
9719        | RString _ ->
9720            pr "  jr = (*env)->NewStringUTF (env, r);\n";
9721            pr "  free (r);\n";
9722            pr "  return jr;\n"
9723        | RStringList _ ->
9724            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
9725            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
9726            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
9727            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
9728            pr "  for (i = 0; i < r_len; ++i) {\n";
9729            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
9730            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
9731            pr "    free (r[i]);\n";
9732            pr "  }\n";
9733            pr "  free (r);\n";
9734            pr "  return jr;\n"
9735        | RStruct (_, typ) ->
9736            let jtyp = java_name_of_struct typ in
9737            let cols = cols_of_struct typ in
9738            generate_java_struct_return typ jtyp cols
9739        | RStructList (_, typ) ->
9740            let jtyp = java_name_of_struct typ in
9741            let cols = cols_of_struct typ in
9742            generate_java_struct_list_return typ jtyp cols
9743        | RHashtable _ ->
9744            (* XXX *)
9745            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
9746            pr "  return NULL;\n"
9747        | RBufferOut _ ->
9748            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
9749            pr "  free (r);\n";
9750            pr "  return jr;\n"
9751       );
9752
9753       pr "}\n";
9754       pr "\n"
9755   ) all_functions
9756
9757 and generate_java_struct_return typ jtyp cols =
9758   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9759   pr "  jr = (*env)->AllocObject (env, cl);\n";
9760   List.iter (
9761     function
9762     | name, FString ->
9763         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9764         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
9765     | name, FUUID ->
9766         pr "  {\n";
9767         pr "    char s[33];\n";
9768         pr "    memcpy (s, r->%s, 32);\n" name;
9769         pr "    s[32] = 0;\n";
9770         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9771         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9772         pr "  }\n";
9773     | name, FBuffer ->
9774         pr "  {\n";
9775         pr "    int len = r->%s_len;\n" name;
9776         pr "    char s[len+1];\n";
9777         pr "    memcpy (s, r->%s, len);\n" name;
9778         pr "    s[len] = 0;\n";
9779         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9780         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9781         pr "  }\n";
9782     | name, (FBytes|FUInt64|FInt64) ->
9783         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9784         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9785     | name, (FUInt32|FInt32) ->
9786         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9787         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9788     | name, FOptPercent ->
9789         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9790         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
9791     | name, FChar ->
9792         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9793         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9794   ) cols;
9795   pr "  free (r);\n";
9796   pr "  return jr;\n"
9797
9798 and generate_java_struct_list_return typ jtyp cols =
9799   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9800   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
9801   pr "  for (i = 0; i < r->len; ++i) {\n";
9802   pr "    jfl = (*env)->AllocObject (env, cl);\n";
9803   List.iter (
9804     function
9805     | name, FString ->
9806         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9807         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
9808     | name, FUUID ->
9809         pr "    {\n";
9810         pr "      char s[33];\n";
9811         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
9812         pr "      s[32] = 0;\n";
9813         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9814         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9815         pr "    }\n";
9816     | name, FBuffer ->
9817         pr "    {\n";
9818         pr "      int len = r->val[i].%s_len;\n" name;
9819         pr "      char s[len+1];\n";
9820         pr "      memcpy (s, r->val[i].%s, len);\n" name;
9821         pr "      s[len] = 0;\n";
9822         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9823         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9824         pr "    }\n";
9825     | name, (FBytes|FUInt64|FInt64) ->
9826         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9827         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9828     | name, (FUInt32|FInt32) ->
9829         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9830         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9831     | name, FOptPercent ->
9832         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9833         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
9834     | name, FChar ->
9835         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9836         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9837   ) cols;
9838   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
9839   pr "  }\n";
9840   pr "  guestfs_free_%s_list (r);\n" typ;
9841   pr "  return jr;\n"
9842
9843 and generate_java_makefile_inc () =
9844   generate_header HashStyle GPLv2plus;
9845
9846   pr "java_built_sources = \\\n";
9847   List.iter (
9848     fun (typ, jtyp) ->
9849         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
9850   ) java_structs;
9851   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
9852
9853 and generate_haskell_hs () =
9854   generate_header HaskellStyle LGPLv2plus;
9855
9856   (* XXX We only know how to generate partial FFI for Haskell
9857    * at the moment.  Please help out!
9858    *)
9859   let can_generate style =
9860     match style with
9861     | RErr, _
9862     | RInt _, _
9863     | RInt64 _, _ -> true
9864     | RBool _, _
9865     | RConstString _, _
9866     | RConstOptString _, _
9867     | RString _, _
9868     | RStringList _, _
9869     | RStruct _, _
9870     | RStructList _, _
9871     | RHashtable _, _
9872     | RBufferOut _, _ -> false in
9873
9874   pr "\
9875 {-# INCLUDE <guestfs.h> #-}
9876 {-# LANGUAGE ForeignFunctionInterface #-}
9877
9878 module Guestfs (
9879   create";
9880
9881   (* List out the names of the actions we want to export. *)
9882   List.iter (
9883     fun (name, style, _, _, _, _, _) ->
9884       if can_generate style then pr ",\n  %s" name
9885   ) all_functions;
9886
9887   pr "
9888   ) where
9889
9890 -- Unfortunately some symbols duplicate ones already present
9891 -- in Prelude.  We don't know which, so we hard-code a list
9892 -- here.
9893 import Prelude hiding (truncate)
9894
9895 import Foreign
9896 import Foreign.C
9897 import Foreign.C.Types
9898 import IO
9899 import Control.Exception
9900 import Data.Typeable
9901
9902 data GuestfsS = GuestfsS            -- represents the opaque C struct
9903 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
9904 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
9905
9906 -- XXX define properly later XXX
9907 data PV = PV
9908 data VG = VG
9909 data LV = LV
9910 data IntBool = IntBool
9911 data Stat = Stat
9912 data StatVFS = StatVFS
9913 data Hashtable = Hashtable
9914
9915 foreign import ccall unsafe \"guestfs_create\" c_create
9916   :: IO GuestfsP
9917 foreign import ccall unsafe \"&guestfs_close\" c_close
9918   :: FunPtr (GuestfsP -> IO ())
9919 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
9920   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
9921
9922 create :: IO GuestfsH
9923 create = do
9924   p <- c_create
9925   c_set_error_handler p nullPtr nullPtr
9926   h <- newForeignPtr c_close p
9927   return h
9928
9929 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
9930   :: GuestfsP -> IO CString
9931
9932 -- last_error :: GuestfsH -> IO (Maybe String)
9933 -- last_error h = do
9934 --   str <- withForeignPtr h (\\p -> c_last_error p)
9935 --   maybePeek peekCString str
9936
9937 last_error :: GuestfsH -> IO (String)
9938 last_error h = do
9939   str <- withForeignPtr h (\\p -> c_last_error p)
9940   if (str == nullPtr)
9941     then return \"no error\"
9942     else peekCString str
9943
9944 ";
9945
9946   (* Generate wrappers for each foreign function. *)
9947   List.iter (
9948     fun (name, style, _, _, _, _, _) ->
9949       if can_generate style then (
9950         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
9951         pr "  :: ";
9952         generate_haskell_prototype ~handle:"GuestfsP" style;
9953         pr "\n";
9954         pr "\n";
9955         pr "%s :: " name;
9956         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
9957         pr "\n";
9958         pr "%s %s = do\n" name
9959           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
9960         pr "  r <- ";
9961         (* Convert pointer arguments using with* functions. *)
9962         List.iter (
9963           function
9964           | FileIn n
9965           | FileOut n
9966           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
9967           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
9968           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
9969           | Bool _ | Int _ | Int64 _ -> ()
9970         ) (snd style);
9971         (* Convert integer arguments. *)
9972         let args =
9973           List.map (
9974             function
9975             | Bool n -> sprintf "(fromBool %s)" n
9976             | Int n -> sprintf "(fromIntegral %s)" n
9977             | Int64 n -> sprintf "(fromIntegral %s)" n
9978             | FileIn n | FileOut n
9979             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
9980           ) (snd style) in
9981         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
9982           (String.concat " " ("p" :: args));
9983         (match fst style with
9984          | RErr | RInt _ | RInt64 _ | RBool _ ->
9985              pr "  if (r == -1)\n";
9986              pr "    then do\n";
9987              pr "      err <- last_error h\n";
9988              pr "      fail err\n";
9989          | RConstString _ | RConstOptString _ | RString _
9990          | RStringList _ | RStruct _
9991          | RStructList _ | RHashtable _ | RBufferOut _ ->
9992              pr "  if (r == nullPtr)\n";
9993              pr "    then do\n";
9994              pr "      err <- last_error h\n";
9995              pr "      fail err\n";
9996         );
9997         (match fst style with
9998          | RErr ->
9999              pr "    else return ()\n"
10000          | RInt _ ->
10001              pr "    else return (fromIntegral r)\n"
10002          | RInt64 _ ->
10003              pr "    else return (fromIntegral r)\n"
10004          | RBool _ ->
10005              pr "    else return (toBool r)\n"
10006          | RConstString _
10007          | RConstOptString _
10008          | RString _
10009          | RStringList _
10010          | RStruct _
10011          | RStructList _
10012          | RHashtable _
10013          | RBufferOut _ ->
10014              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10015         );
10016         pr "\n";
10017       )
10018   ) all_functions
10019
10020 and generate_haskell_prototype ~handle ?(hs = false) style =
10021   pr "%s -> " handle;
10022   let string = if hs then "String" else "CString" in
10023   let int = if hs then "Int" else "CInt" in
10024   let bool = if hs then "Bool" else "CInt" in
10025   let int64 = if hs then "Integer" else "Int64" in
10026   List.iter (
10027     fun arg ->
10028       (match arg with
10029        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10030        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10031        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10032        | Bool _ -> pr "%s" bool
10033        | Int _ -> pr "%s" int
10034        | Int64 _ -> pr "%s" int
10035        | FileIn _ -> pr "%s" string
10036        | FileOut _ -> pr "%s" string
10037       );
10038       pr " -> ";
10039   ) (snd style);
10040   pr "IO (";
10041   (match fst style with
10042    | RErr -> if not hs then pr "CInt"
10043    | RInt _ -> pr "%s" int
10044    | RInt64 _ -> pr "%s" int64
10045    | RBool _ -> pr "%s" bool
10046    | RConstString _ -> pr "%s" string
10047    | RConstOptString _ -> pr "Maybe %s" string
10048    | RString _ -> pr "%s" string
10049    | RStringList _ -> pr "[%s]" string
10050    | RStruct (_, typ) ->
10051        let name = java_name_of_struct typ in
10052        pr "%s" name
10053    | RStructList (_, typ) ->
10054        let name = java_name_of_struct typ in
10055        pr "[%s]" name
10056    | RHashtable _ -> pr "Hashtable"
10057    | RBufferOut _ -> pr "%s" string
10058   );
10059   pr ")"
10060
10061 and generate_csharp () =
10062   generate_header CPlusPlusStyle LGPLv2plus;
10063
10064   (* XXX Make this configurable by the C# assembly users. *)
10065   let library = "libguestfs.so.0" in
10066
10067   pr "\
10068 // These C# bindings are highly experimental at present.
10069 //
10070 // Firstly they only work on Linux (ie. Mono).  In order to get them
10071 // to work on Windows (ie. .Net) you would need to port the library
10072 // itself to Windows first.
10073 //
10074 // The second issue is that some calls are known to be incorrect and
10075 // can cause Mono to segfault.  Particularly: calls which pass or
10076 // return string[], or return any structure value.  This is because
10077 // we haven't worked out the correct way to do this from C#.
10078 //
10079 // The third issue is that when compiling you get a lot of warnings.
10080 // We are not sure whether the warnings are important or not.
10081 //
10082 // Fourthly we do not routinely build or test these bindings as part
10083 // of the make && make check cycle, which means that regressions might
10084 // go unnoticed.
10085 //
10086 // Suggestions and patches are welcome.
10087
10088 // To compile:
10089 //
10090 // gmcs Libguestfs.cs
10091 // mono Libguestfs.exe
10092 //
10093 // (You'll probably want to add a Test class / static main function
10094 // otherwise this won't do anything useful).
10095
10096 using System;
10097 using System.IO;
10098 using System.Runtime.InteropServices;
10099 using System.Runtime.Serialization;
10100 using System.Collections;
10101
10102 namespace Guestfs
10103 {
10104   class Error : System.ApplicationException
10105   {
10106     public Error (string message) : base (message) {}
10107     protected Error (SerializationInfo info, StreamingContext context) {}
10108   }
10109
10110   class Guestfs
10111   {
10112     IntPtr _handle;
10113
10114     [DllImport (\"%s\")]
10115     static extern IntPtr guestfs_create ();
10116
10117     public Guestfs ()
10118     {
10119       _handle = guestfs_create ();
10120       if (_handle == IntPtr.Zero)
10121         throw new Error (\"could not create guestfs handle\");
10122     }
10123
10124     [DllImport (\"%s\")]
10125     static extern void guestfs_close (IntPtr h);
10126
10127     ~Guestfs ()
10128     {
10129       guestfs_close (_handle);
10130     }
10131
10132     [DllImport (\"%s\")]
10133     static extern string guestfs_last_error (IntPtr h);
10134
10135 " library library library;
10136
10137   (* Generate C# structure bindings.  We prefix struct names with
10138    * underscore because C# cannot have conflicting struct names and
10139    * method names (eg. "class stat" and "stat").
10140    *)
10141   List.iter (
10142     fun (typ, cols) ->
10143       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10144       pr "    public class _%s {\n" typ;
10145       List.iter (
10146         function
10147         | name, FChar -> pr "      char %s;\n" name
10148         | name, FString -> pr "      string %s;\n" name
10149         | name, FBuffer ->
10150             pr "      uint %s_len;\n" name;
10151             pr "      string %s;\n" name
10152         | name, FUUID ->
10153             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10154             pr "      string %s;\n" name
10155         | name, FUInt32 -> pr "      uint %s;\n" name
10156         | name, FInt32 -> pr "      int %s;\n" name
10157         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10158         | name, FInt64 -> pr "      long %s;\n" name
10159         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10160       ) cols;
10161       pr "    }\n";
10162       pr "\n"
10163   ) structs;
10164
10165   (* Generate C# function bindings. *)
10166   List.iter (
10167     fun (name, style, _, _, _, shortdesc, _) ->
10168       let rec csharp_return_type () =
10169         match fst style with
10170         | RErr -> "void"
10171         | RBool n -> "bool"
10172         | RInt n -> "int"
10173         | RInt64 n -> "long"
10174         | RConstString n
10175         | RConstOptString n
10176         | RString n
10177         | RBufferOut n -> "string"
10178         | RStruct (_,n) -> "_" ^ n
10179         | RHashtable n -> "Hashtable"
10180         | RStringList n -> "string[]"
10181         | RStructList (_,n) -> sprintf "_%s[]" n
10182
10183       and c_return_type () =
10184         match fst style with
10185         | RErr
10186         | RBool _
10187         | RInt _ -> "int"
10188         | RInt64 _ -> "long"
10189         | RConstString _
10190         | RConstOptString _
10191         | RString _
10192         | RBufferOut _ -> "string"
10193         | RStruct (_,n) -> "_" ^ n
10194         | RHashtable _
10195         | RStringList _ -> "string[]"
10196         | RStructList (_,n) -> sprintf "_%s[]" n
10197     
10198       and c_error_comparison () =
10199         match fst style with
10200         | RErr
10201         | RBool _
10202         | RInt _
10203         | RInt64 _ -> "== -1"
10204         | RConstString _
10205         | RConstOptString _
10206         | RString _
10207         | RBufferOut _
10208         | RStruct (_,_)
10209         | RHashtable _
10210         | RStringList _
10211         | RStructList (_,_) -> "== null"
10212     
10213       and generate_extern_prototype () =
10214         pr "    static extern %s guestfs_%s (IntPtr h"
10215           (c_return_type ()) name;
10216         List.iter (
10217           function
10218           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10219           | FileIn n | FileOut n ->
10220               pr ", [In] string %s" n
10221           | StringList n | DeviceList n ->
10222               pr ", [In] string[] %s" n
10223           | Bool n ->
10224               pr ", bool %s" n
10225           | Int n ->
10226               pr ", int %s" n
10227           | Int64 n ->
10228               pr ", long %s" n
10229         ) (snd style);
10230         pr ");\n"
10231
10232       and generate_public_prototype () =
10233         pr "    public %s %s (" (csharp_return_type ()) name;
10234         let comma = ref false in
10235         let next () =
10236           if !comma then pr ", ";
10237           comma := true
10238         in
10239         List.iter (
10240           function
10241           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10242           | FileIn n | FileOut n ->
10243               next (); pr "string %s" n
10244           | StringList n | DeviceList n ->
10245               next (); pr "string[] %s" n
10246           | Bool n ->
10247               next (); pr "bool %s" n
10248           | Int n ->
10249               next (); pr "int %s" n
10250           | Int64 n ->
10251               next (); pr "long %s" n
10252         ) (snd style);
10253         pr ")\n"
10254
10255       and generate_call () =
10256         pr "guestfs_%s (_handle" name;
10257         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10258         pr ");\n";
10259       in
10260
10261       pr "    [DllImport (\"%s\")]\n" library;
10262       generate_extern_prototype ();
10263       pr "\n";
10264       pr "    /// <summary>\n";
10265       pr "    /// %s\n" shortdesc;
10266       pr "    /// </summary>\n";
10267       generate_public_prototype ();
10268       pr "    {\n";
10269       pr "      %s r;\n" (c_return_type ());
10270       pr "      r = ";
10271       generate_call ();
10272       pr "      if (r %s)\n" (c_error_comparison ());
10273       pr "        throw new Error (\"%s: \" + guestfs_last_error (_handle));\n"
10274         name;
10275       (match fst style with
10276        | RErr -> ()
10277        | RBool _ ->
10278            pr "      return r != 0 ? true : false;\n"
10279        | RHashtable _ ->
10280            pr "      Hashtable rr = new Hashtable ();\n";
10281            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10282            pr "        rr.Add (r[i], r[i+1]);\n";
10283            pr "      return rr;\n"
10284        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10285        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10286        | RStructList _ ->
10287            pr "      return r;\n"
10288       );
10289       pr "    }\n";
10290       pr "\n";
10291   ) all_functions_sorted;
10292
10293   pr "  }
10294 }
10295 "
10296
10297 and generate_bindtests () =
10298   generate_header CStyle LGPLv2plus;
10299
10300   pr "\
10301 #include <stdio.h>
10302 #include <stdlib.h>
10303 #include <inttypes.h>
10304 #include <string.h>
10305
10306 #include \"guestfs.h\"
10307 #include \"guestfs-internal.h\"
10308 #include \"guestfs-internal-actions.h\"
10309 #include \"guestfs_protocol.h\"
10310
10311 #define error guestfs_error
10312 #define safe_calloc guestfs_safe_calloc
10313 #define safe_malloc guestfs_safe_malloc
10314
10315 static void
10316 print_strings (char *const *argv)
10317 {
10318   int argc;
10319
10320   printf (\"[\");
10321   for (argc = 0; argv[argc] != NULL; ++argc) {
10322     if (argc > 0) printf (\", \");
10323     printf (\"\\\"%%s\\\"\", argv[argc]);
10324   }
10325   printf (\"]\\n\");
10326 }
10327
10328 /* The test0 function prints its parameters to stdout. */
10329 ";
10330
10331   let test0, tests =
10332     match test_functions with
10333     | [] -> assert false
10334     | test0 :: tests -> test0, tests in
10335
10336   let () =
10337     let (name, style, _, _, _, _, _) = test0 in
10338     generate_prototype ~extern:false ~semicolon:false ~newline:true
10339       ~handle:"g" ~prefix:"guestfs__" name style;
10340     pr "{\n";
10341     List.iter (
10342       function
10343       | Pathname n
10344       | Device n | Dev_or_Path n
10345       | String n
10346       | FileIn n
10347       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10348       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10349       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10350       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10351       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10352       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10353     ) (snd style);
10354     pr "  /* Java changes stdout line buffering so we need this: */\n";
10355     pr "  fflush (stdout);\n";
10356     pr "  return 0;\n";
10357     pr "}\n";
10358     pr "\n" in
10359
10360   List.iter (
10361     fun (name, style, _, _, _, _, _) ->
10362       if String.sub name (String.length name - 3) 3 <> "err" then (
10363         pr "/* Test normal return. */\n";
10364         generate_prototype ~extern:false ~semicolon:false ~newline:true
10365           ~handle:"g" ~prefix:"guestfs__" name style;
10366         pr "{\n";
10367         (match fst style with
10368          | RErr ->
10369              pr "  return 0;\n"
10370          | RInt _ ->
10371              pr "  int r;\n";
10372              pr "  sscanf (val, \"%%d\", &r);\n";
10373              pr "  return r;\n"
10374          | RInt64 _ ->
10375              pr "  int64_t r;\n";
10376              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10377              pr "  return r;\n"
10378          | RBool _ ->
10379              pr "  return STREQ (val, \"true\");\n"
10380          | RConstString _
10381          | RConstOptString _ ->
10382              (* Can't return the input string here.  Return a static
10383               * string so we ensure we get a segfault if the caller
10384               * tries to free it.
10385               *)
10386              pr "  return \"static string\";\n"
10387          | RString _ ->
10388              pr "  return strdup (val);\n"
10389          | RStringList _ ->
10390              pr "  char **strs;\n";
10391              pr "  int n, i;\n";
10392              pr "  sscanf (val, \"%%d\", &n);\n";
10393              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10394              pr "  for (i = 0; i < n; ++i) {\n";
10395              pr "    strs[i] = safe_malloc (g, 16);\n";
10396              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10397              pr "  }\n";
10398              pr "  strs[n] = NULL;\n";
10399              pr "  return strs;\n"
10400          | RStruct (_, typ) ->
10401              pr "  struct guestfs_%s *r;\n" typ;
10402              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10403              pr "  return r;\n"
10404          | RStructList (_, typ) ->
10405              pr "  struct guestfs_%s_list *r;\n" typ;
10406              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10407              pr "  sscanf (val, \"%%d\", &r->len);\n";
10408              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10409              pr "  return r;\n"
10410          | RHashtable _ ->
10411              pr "  char **strs;\n";
10412              pr "  int n, i;\n";
10413              pr "  sscanf (val, \"%%d\", &n);\n";
10414              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10415              pr "  for (i = 0; i < n; ++i) {\n";
10416              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10417              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10418              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10419              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10420              pr "  }\n";
10421              pr "  strs[n*2] = NULL;\n";
10422              pr "  return strs;\n"
10423          | RBufferOut _ ->
10424              pr "  return strdup (val);\n"
10425         );
10426         pr "}\n";
10427         pr "\n"
10428       ) else (
10429         pr "/* Test error return. */\n";
10430         generate_prototype ~extern:false ~semicolon:false ~newline:true
10431           ~handle:"g" ~prefix:"guestfs__" name style;
10432         pr "{\n";
10433         pr "  error (g, \"error\");\n";
10434         (match fst style with
10435          | RErr | RInt _ | RInt64 _ | RBool _ ->
10436              pr "  return -1;\n"
10437          | RConstString _ | RConstOptString _
10438          | RString _ | RStringList _ | RStruct _
10439          | RStructList _
10440          | RHashtable _
10441          | RBufferOut _ ->
10442              pr "  return NULL;\n"
10443         );
10444         pr "}\n";
10445         pr "\n"
10446       )
10447   ) tests
10448
10449 and generate_ocaml_bindtests () =
10450   generate_header OCamlStyle GPLv2plus;
10451
10452   pr "\
10453 let () =
10454   let g = Guestfs.create () in
10455 ";
10456
10457   let mkargs args =
10458     String.concat " " (
10459       List.map (
10460         function
10461         | CallString s -> "\"" ^ s ^ "\""
10462         | CallOptString None -> "None"
10463         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10464         | CallStringList xs ->
10465             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10466         | CallInt i when i >= 0 -> string_of_int i
10467         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10468         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10469         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10470         | CallBool b -> string_of_bool b
10471       ) args
10472     )
10473   in
10474
10475   generate_lang_bindtests (
10476     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10477   );
10478
10479   pr "print_endline \"EOF\"\n"
10480
10481 and generate_perl_bindtests () =
10482   pr "#!/usr/bin/perl -w\n";
10483   generate_header HashStyle GPLv2plus;
10484
10485   pr "\
10486 use strict;
10487
10488 use Sys::Guestfs;
10489
10490 my $g = Sys::Guestfs->new ();
10491 ";
10492
10493   let mkargs args =
10494     String.concat ", " (
10495       List.map (
10496         function
10497         | CallString s -> "\"" ^ s ^ "\""
10498         | CallOptString None -> "undef"
10499         | CallOptString (Some s) -> sprintf "\"%s\"" s
10500         | CallStringList xs ->
10501             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10502         | CallInt i -> string_of_int i
10503         | CallInt64 i -> Int64.to_string i
10504         | CallBool b -> if b then "1" else "0"
10505       ) args
10506     )
10507   in
10508
10509   generate_lang_bindtests (
10510     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10511   );
10512
10513   pr "print \"EOF\\n\"\n"
10514
10515 and generate_python_bindtests () =
10516   generate_header HashStyle GPLv2plus;
10517
10518   pr "\
10519 import guestfs
10520
10521 g = guestfs.GuestFS ()
10522 ";
10523
10524   let mkargs args =
10525     String.concat ", " (
10526       List.map (
10527         function
10528         | CallString s -> "\"" ^ s ^ "\""
10529         | CallOptString None -> "None"
10530         | CallOptString (Some s) -> sprintf "\"%s\"" s
10531         | CallStringList xs ->
10532             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10533         | CallInt i -> string_of_int i
10534         | CallInt64 i -> Int64.to_string i
10535         | CallBool b -> if b then "1" else "0"
10536       ) args
10537     )
10538   in
10539
10540   generate_lang_bindtests (
10541     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10542   );
10543
10544   pr "print \"EOF\"\n"
10545
10546 and generate_ruby_bindtests () =
10547   generate_header HashStyle GPLv2plus;
10548
10549   pr "\
10550 require 'guestfs'
10551
10552 g = Guestfs::create()
10553 ";
10554
10555   let mkargs args =
10556     String.concat ", " (
10557       List.map (
10558         function
10559         | CallString s -> "\"" ^ s ^ "\""
10560         | CallOptString None -> "nil"
10561         | CallOptString (Some s) -> sprintf "\"%s\"" s
10562         | CallStringList xs ->
10563             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10564         | CallInt i -> string_of_int i
10565         | CallInt64 i -> Int64.to_string i
10566         | CallBool b -> string_of_bool b
10567       ) args
10568     )
10569   in
10570
10571   generate_lang_bindtests (
10572     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10573   );
10574
10575   pr "print \"EOF\\n\"\n"
10576
10577 and generate_java_bindtests () =
10578   generate_header CStyle GPLv2plus;
10579
10580   pr "\
10581 import com.redhat.et.libguestfs.*;
10582
10583 public class Bindtests {
10584     public static void main (String[] argv)
10585     {
10586         try {
10587             GuestFS g = new GuestFS ();
10588 ";
10589
10590   let mkargs args =
10591     String.concat ", " (
10592       List.map (
10593         function
10594         | CallString s -> "\"" ^ s ^ "\""
10595         | CallOptString None -> "null"
10596         | CallOptString (Some s) -> sprintf "\"%s\"" s
10597         | CallStringList xs ->
10598             "new String[]{" ^
10599               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
10600         | CallInt i -> string_of_int i
10601         | CallInt64 i -> Int64.to_string i
10602         | CallBool b -> string_of_bool b
10603       ) args
10604     )
10605   in
10606
10607   generate_lang_bindtests (
10608     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
10609   );
10610
10611   pr "
10612             System.out.println (\"EOF\");
10613         }
10614         catch (Exception exn) {
10615             System.err.println (exn);
10616             System.exit (1);
10617         }
10618     }
10619 }
10620 "
10621
10622 and generate_haskell_bindtests () =
10623   generate_header HaskellStyle GPLv2plus;
10624
10625   pr "\
10626 module Bindtests where
10627 import qualified Guestfs
10628
10629 main = do
10630   g <- Guestfs.create
10631 ";
10632
10633   let mkargs args =
10634     String.concat " " (
10635       List.map (
10636         function
10637         | CallString s -> "\"" ^ s ^ "\""
10638         | CallOptString None -> "Nothing"
10639         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
10640         | CallStringList xs ->
10641             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10642         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
10643         | CallInt i -> string_of_int i
10644         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
10645         | CallInt64 i -> Int64.to_string i
10646         | CallBool true -> "True"
10647         | CallBool false -> "False"
10648       ) args
10649     )
10650   in
10651
10652   generate_lang_bindtests (
10653     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
10654   );
10655
10656   pr "  putStrLn \"EOF\"\n"
10657
10658 (* Language-independent bindings tests - we do it this way to
10659  * ensure there is parity in testing bindings across all languages.
10660  *)
10661 and generate_lang_bindtests call =
10662   call "test0" [CallString "abc"; CallOptString (Some "def");
10663                 CallStringList []; CallBool false;
10664                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10665   call "test0" [CallString "abc"; CallOptString None;
10666                 CallStringList []; CallBool false;
10667                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10668   call "test0" [CallString ""; CallOptString (Some "def");
10669                 CallStringList []; CallBool false;
10670                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10671   call "test0" [CallString ""; CallOptString (Some "");
10672                 CallStringList []; CallBool false;
10673                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10674   call "test0" [CallString "abc"; CallOptString (Some "def");
10675                 CallStringList ["1"]; CallBool false;
10676                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10677   call "test0" [CallString "abc"; CallOptString (Some "def");
10678                 CallStringList ["1"; "2"]; CallBool false;
10679                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10680   call "test0" [CallString "abc"; CallOptString (Some "def");
10681                 CallStringList ["1"]; CallBool true;
10682                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10683   call "test0" [CallString "abc"; CallOptString (Some "def");
10684                 CallStringList ["1"]; CallBool false;
10685                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
10686   call "test0" [CallString "abc"; CallOptString (Some "def");
10687                 CallStringList ["1"]; CallBool false;
10688                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
10689   call "test0" [CallString "abc"; CallOptString (Some "def");
10690                 CallStringList ["1"]; CallBool false;
10691                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
10692   call "test0" [CallString "abc"; CallOptString (Some "def");
10693                 CallStringList ["1"]; CallBool false;
10694                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
10695   call "test0" [CallString "abc"; CallOptString (Some "def");
10696                 CallStringList ["1"]; CallBool false;
10697                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
10698   call "test0" [CallString "abc"; CallOptString (Some "def");
10699                 CallStringList ["1"]; CallBool false;
10700                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
10701
10702 (* XXX Add here tests of the return and error functions. *)
10703
10704 (* Code to generator bindings for virt-inspector.  Currently only
10705  * implemented for OCaml code (for virt-p2v 2.0).
10706  *)
10707 let rng_input = "inspector/virt-inspector.rng"
10708
10709 (* Read the input file and parse it into internal structures.  This is
10710  * by no means a complete RELAX NG parser, but is just enough to be
10711  * able to parse the specific input file.
10712  *)
10713 type rng =
10714   | Element of string * rng list        (* <element name=name/> *)
10715   | Attribute of string * rng list        (* <attribute name=name/> *)
10716   | Interleave of rng list                (* <interleave/> *)
10717   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
10718   | OneOrMore of rng                        (* <oneOrMore/> *)
10719   | Optional of rng                        (* <optional/> *)
10720   | Choice of string list                (* <choice><value/>*</choice> *)
10721   | Value of string                        (* <value>str</value> *)
10722   | Text                                (* <text/> *)
10723
10724 let rec string_of_rng = function
10725   | Element (name, xs) ->
10726       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10727   | Attribute (name, xs) ->
10728       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10729   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
10730   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
10731   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
10732   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
10733   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
10734   | Value value -> "Value \"" ^ value ^ "\""
10735   | Text -> "Text"
10736
10737 and string_of_rng_list xs =
10738   String.concat ", " (List.map string_of_rng xs)
10739
10740 let rec parse_rng ?defines context = function
10741   | [] -> []
10742   | Xml.Element ("element", ["name", name], children) :: rest ->
10743       Element (name, parse_rng ?defines context children)
10744       :: parse_rng ?defines context rest
10745   | Xml.Element ("attribute", ["name", name], children) :: rest ->
10746       Attribute (name, parse_rng ?defines context children)
10747       :: parse_rng ?defines context rest
10748   | Xml.Element ("interleave", [], children) :: rest ->
10749       Interleave (parse_rng ?defines context children)
10750       :: parse_rng ?defines context rest
10751   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
10752       let rng = parse_rng ?defines context [child] in
10753       (match rng with
10754        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
10755        | _ ->
10756            failwithf "%s: <zeroOrMore> contains more than one child element"
10757              context
10758       )
10759   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
10760       let rng = parse_rng ?defines context [child] in
10761       (match rng with
10762        | [child] -> OneOrMore child :: parse_rng ?defines context rest
10763        | _ ->
10764            failwithf "%s: <oneOrMore> contains more than one child element"
10765              context
10766       )
10767   | Xml.Element ("optional", [], [child]) :: rest ->
10768       let rng = parse_rng ?defines context [child] in
10769       (match rng with
10770        | [child] -> Optional child :: parse_rng ?defines context rest
10771        | _ ->
10772            failwithf "%s: <optional> contains more than one child element"
10773              context
10774       )
10775   | Xml.Element ("choice", [], children) :: rest ->
10776       let values = List.map (
10777         function Xml.Element ("value", [], [Xml.PCData value]) -> value
10778         | _ ->
10779             failwithf "%s: can't handle anything except <value> in <choice>"
10780               context
10781       ) children in
10782       Choice values
10783       :: parse_rng ?defines context rest
10784   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
10785       Value value :: parse_rng ?defines context rest
10786   | Xml.Element ("text", [], []) :: rest ->
10787       Text :: parse_rng ?defines context rest
10788   | Xml.Element ("ref", ["name", name], []) :: rest ->
10789       (* Look up the reference.  Because of limitations in this parser,
10790        * we can't handle arbitrarily nested <ref> yet.  You can only
10791        * use <ref> from inside <start>.
10792        *)
10793       (match defines with
10794        | None ->
10795            failwithf "%s: contains <ref>, but no refs are defined yet" context
10796        | Some map ->
10797            let rng = StringMap.find name map in
10798            rng @ parse_rng ?defines context rest
10799       )
10800   | x :: _ ->
10801       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
10802
10803 let grammar =
10804   let xml = Xml.parse_file rng_input in
10805   match xml with
10806   | Xml.Element ("grammar", _,
10807                  Xml.Element ("start", _, gram) :: defines) ->
10808       (* The <define/> elements are referenced in the <start> section,
10809        * so build a map of those first.
10810        *)
10811       let defines = List.fold_left (
10812         fun map ->
10813           function Xml.Element ("define", ["name", name], defn) ->
10814             StringMap.add name defn map
10815           | _ ->
10816               failwithf "%s: expected <define name=name/>" rng_input
10817       ) StringMap.empty defines in
10818       let defines = StringMap.mapi parse_rng defines in
10819
10820       (* Parse the <start> clause, passing the defines. *)
10821       parse_rng ~defines "<start>" gram
10822   | _ ->
10823       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
10824         rng_input
10825
10826 let name_of_field = function
10827   | Element (name, _) | Attribute (name, _)
10828   | ZeroOrMore (Element (name, _))
10829   | OneOrMore (Element (name, _))
10830   | Optional (Element (name, _)) -> name
10831   | Optional (Attribute (name, _)) -> name
10832   | Text -> (* an unnamed field in an element *)
10833       "data"
10834   | rng ->
10835       failwithf "name_of_field failed at: %s" (string_of_rng rng)
10836
10837 (* At the moment this function only generates OCaml types.  However we
10838  * should parameterize it later so it can generate types/structs in a
10839  * variety of languages.
10840  *)
10841 let generate_types xs =
10842   (* A simple type is one that can be printed out directly, eg.
10843    * "string option".  A complex type is one which has a name and has
10844    * to be defined via another toplevel definition, eg. a struct.
10845    *
10846    * generate_type generates code for either simple or complex types.
10847    * In the simple case, it returns the string ("string option").  In
10848    * the complex case, it returns the name ("mountpoint").  In the
10849    * complex case it has to print out the definition before returning,
10850    * so it should only be called when we are at the beginning of a
10851    * new line (BOL context).
10852    *)
10853   let rec generate_type = function
10854     | Text ->                                (* string *)
10855         "string", true
10856     | Choice values ->                        (* [`val1|`val2|...] *)
10857         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
10858     | ZeroOrMore rng ->                        (* <rng> list *)
10859         let t, is_simple = generate_type rng in
10860         t ^ " list (* 0 or more *)", is_simple
10861     | OneOrMore rng ->                        (* <rng> list *)
10862         let t, is_simple = generate_type rng in
10863         t ^ " list (* 1 or more *)", is_simple
10864                                         (* virt-inspector hack: bool *)
10865     | Optional (Attribute (name, [Value "1"])) ->
10866         "bool", true
10867     | Optional rng ->                        (* <rng> list *)
10868         let t, is_simple = generate_type rng in
10869         t ^ " option", is_simple
10870                                         (* type name = { fields ... } *)
10871     | Element (name, fields) when is_attrs_interleave fields ->
10872         generate_type_struct name (get_attrs_interleave fields)
10873     | Element (name, [field])                (* type name = field *)
10874     | Attribute (name, [field]) ->
10875         let t, is_simple = generate_type field in
10876         if is_simple then (t, true)
10877         else (
10878           pr "type %s = %s\n" name t;
10879           name, false
10880         )
10881     | Element (name, fields) ->              (* type name = { fields ... } *)
10882         generate_type_struct name fields
10883     | rng ->
10884         failwithf "generate_type failed at: %s" (string_of_rng rng)
10885
10886   and is_attrs_interleave = function
10887     | [Interleave _] -> true
10888     | Attribute _ :: fields -> is_attrs_interleave fields
10889     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
10890     | _ -> false
10891
10892   and get_attrs_interleave = function
10893     | [Interleave fields] -> fields
10894     | ((Attribute _) as field) :: fields
10895     | ((Optional (Attribute _)) as field) :: fields ->
10896         field :: get_attrs_interleave fields
10897     | _ -> assert false
10898
10899   and generate_types xs =
10900     List.iter (fun x -> ignore (generate_type x)) xs
10901
10902   and generate_type_struct name fields =
10903     (* Calculate the types of the fields first.  We have to do this
10904      * before printing anything so we are still in BOL context.
10905      *)
10906     let types = List.map fst (List.map generate_type fields) in
10907
10908     (* Special case of a struct containing just a string and another
10909      * field.  Turn it into an assoc list.
10910      *)
10911     match types with
10912     | ["string"; other] ->
10913         let fname1, fname2 =
10914           match fields with
10915           | [f1; f2] -> name_of_field f1, name_of_field f2
10916           | _ -> assert false in
10917         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
10918         name, false
10919
10920     | types ->
10921         pr "type %s = {\n" name;
10922         List.iter (
10923           fun (field, ftype) ->
10924             let fname = name_of_field field in
10925             pr "  %s_%s : %s;\n" name fname ftype
10926         ) (List.combine fields types);
10927         pr "}\n";
10928         (* Return the name of this type, and
10929          * false because it's not a simple type.
10930          *)
10931         name, false
10932   in
10933
10934   generate_types xs
10935
10936 let generate_parsers xs =
10937   (* As for generate_type above, generate_parser makes a parser for
10938    * some type, and returns the name of the parser it has generated.
10939    * Because it (may) need to print something, it should always be
10940    * called in BOL context.
10941    *)
10942   let rec generate_parser = function
10943     | Text ->                                (* string *)
10944         "string_child_or_empty"
10945     | Choice values ->                        (* [`val1|`val2|...] *)
10946         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
10947           (String.concat "|"
10948              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
10949     | ZeroOrMore rng ->                        (* <rng> list *)
10950         let pa = generate_parser rng in
10951         sprintf "(fun x -> List.map %s (Xml.children x))" pa
10952     | OneOrMore rng ->                        (* <rng> list *)
10953         let pa = generate_parser rng in
10954         sprintf "(fun x -> List.map %s (Xml.children x))" pa
10955                                         (* virt-inspector hack: bool *)
10956     | Optional (Attribute (name, [Value "1"])) ->
10957         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
10958     | Optional rng ->                        (* <rng> list *)
10959         let pa = generate_parser rng in
10960         sprintf "(function None -> None | Some x -> Some (%s x))" pa
10961                                         (* type name = { fields ... } *)
10962     | Element (name, fields) when is_attrs_interleave fields ->
10963         generate_parser_struct name (get_attrs_interleave fields)
10964     | Element (name, [field]) ->        (* type name = field *)
10965         let pa = generate_parser field in
10966         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
10967         pr "let %s =\n" parser_name;
10968         pr "  %s\n" pa;
10969         pr "let parse_%s = %s\n" name parser_name;
10970         parser_name
10971     | Attribute (name, [field]) ->
10972         let pa = generate_parser field in
10973         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
10974         pr "let %s =\n" parser_name;
10975         pr "  %s\n" pa;
10976         pr "let parse_%s = %s\n" name parser_name;
10977         parser_name
10978     | Element (name, fields) ->              (* type name = { fields ... } *)
10979         generate_parser_struct name ([], fields)
10980     | rng ->
10981         failwithf "generate_parser failed at: %s" (string_of_rng rng)
10982
10983   and is_attrs_interleave = function
10984     | [Interleave _] -> true
10985     | Attribute _ :: fields -> is_attrs_interleave fields
10986     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
10987     | _ -> false
10988
10989   and get_attrs_interleave = function
10990     | [Interleave fields] -> [], fields
10991     | ((Attribute _) as field) :: fields
10992     | ((Optional (Attribute _)) as field) :: fields ->
10993         let attrs, interleaves = get_attrs_interleave fields in
10994         (field :: attrs), interleaves
10995     | _ -> assert false
10996
10997   and generate_parsers xs =
10998     List.iter (fun x -> ignore (generate_parser x)) xs
10999
11000   and generate_parser_struct name (attrs, interleaves) =
11001     (* Generate parsers for the fields first.  We have to do this
11002      * before printing anything so we are still in BOL context.
11003      *)
11004     let fields = attrs @ interleaves in
11005     let pas = List.map generate_parser fields in
11006
11007     (* Generate an intermediate tuple from all the fields first.
11008      * If the type is just a string + another field, then we will
11009      * return this directly, otherwise it is turned into a record.
11010      *
11011      * RELAX NG note: This code treats <interleave> and plain lists of
11012      * fields the same.  In other words, it doesn't bother enforcing
11013      * any ordering of fields in the XML.
11014      *)
11015     pr "let parse_%s x =\n" name;
11016     pr "  let t = (\n    ";
11017     let comma = ref false in
11018     List.iter (
11019       fun x ->
11020         if !comma then pr ",\n    ";
11021         comma := true;
11022         match x with
11023         | Optional (Attribute (fname, [field])), pa ->
11024             pr "%s x" pa
11025         | Optional (Element (fname, [field])), pa ->
11026             pr "%s (optional_child %S x)" pa fname
11027         | Attribute (fname, [Text]), _ ->
11028             pr "attribute %S x" fname
11029         | (ZeroOrMore _ | OneOrMore _), pa ->
11030             pr "%s x" pa
11031         | Text, pa ->
11032             pr "%s x" pa
11033         | (field, pa) ->
11034             let fname = name_of_field field in
11035             pr "%s (child %S x)" pa fname
11036     ) (List.combine fields pas);
11037     pr "\n  ) in\n";
11038
11039     (match fields with
11040      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11041          pr "  t\n"
11042
11043      | _ ->
11044          pr "  (Obj.magic t : %s)\n" name
11045 (*
11046          List.iter (
11047            function
11048            | (Optional (Attribute (fname, [field])), pa) ->
11049                pr "  %s_%s =\n" name fname;
11050                pr "    %s x;\n" pa
11051            | (Optional (Element (fname, [field])), pa) ->
11052                pr "  %s_%s =\n" name fname;
11053                pr "    (let x = optional_child %S x in\n" fname;
11054                pr "     %s x);\n" pa
11055            | (field, pa) ->
11056                let fname = name_of_field field in
11057                pr "  %s_%s =\n" name fname;
11058                pr "    (let x = child %S x in\n" fname;
11059                pr "     %s x);\n" pa
11060          ) (List.combine fields pas);
11061          pr "}\n"
11062 *)
11063     );
11064     sprintf "parse_%s" name
11065   in
11066
11067   generate_parsers xs
11068
11069 (* Generate ocaml/guestfs_inspector.mli. *)
11070 let generate_ocaml_inspector_mli () =
11071   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11072
11073   pr "\
11074 (** This is an OCaml language binding to the external [virt-inspector]
11075     program.
11076
11077     For more information, please read the man page [virt-inspector(1)].
11078 *)
11079
11080 ";
11081
11082   generate_types grammar;
11083   pr "(** The nested information returned from the {!inspect} function. *)\n";
11084   pr "\n";
11085
11086   pr "\
11087 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11088 (** To inspect a libvirt domain called [name], pass a singleton
11089     list: [inspect [name]].  When using libvirt only, you may
11090     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11091
11092     To inspect a disk image or images, pass a list of the filenames
11093     of the disk images: [inspect filenames]
11094
11095     This function inspects the given guest or disk images and
11096     returns a list of operating system(s) found and a large amount
11097     of information about them.  In the vast majority of cases,
11098     a virtual machine only contains a single operating system.
11099
11100     If the optional [~xml] parameter is given, then this function
11101     skips running the external virt-inspector program and just
11102     parses the given XML directly (which is expected to be XML
11103     produced from a previous run of virt-inspector).  The list of
11104     names and connect URI are ignored in this case.
11105
11106     This function can throw a wide variety of exceptions, for example
11107     if the external virt-inspector program cannot be found, or if
11108     it doesn't generate valid XML.
11109 *)
11110 "
11111
11112 (* Generate ocaml/guestfs_inspector.ml. *)
11113 let generate_ocaml_inspector_ml () =
11114   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11115
11116   pr "open Unix\n";
11117   pr "\n";
11118
11119   generate_types grammar;
11120   pr "\n";
11121
11122   pr "\
11123 (* Misc functions which are used by the parser code below. *)
11124 let first_child = function
11125   | Xml.Element (_, _, c::_) -> c
11126   | Xml.Element (name, _, []) ->
11127       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11128   | Xml.PCData str ->
11129       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11130
11131 let string_child_or_empty = function
11132   | Xml.Element (_, _, [Xml.PCData s]) -> s
11133   | Xml.Element (_, _, []) -> \"\"
11134   | Xml.Element (x, _, _) ->
11135       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11136                 x ^ \" instead\")
11137   | Xml.PCData str ->
11138       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11139
11140 let optional_child name xml =
11141   let children = Xml.children xml in
11142   try
11143     Some (List.find (function
11144                      | Xml.Element (n, _, _) when n = name -> true
11145                      | _ -> false) children)
11146   with
11147     Not_found -> None
11148
11149 let child name xml =
11150   match optional_child name xml with
11151   | Some c -> c
11152   | None ->
11153       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11154
11155 let attribute name xml =
11156   try Xml.attrib xml name
11157   with Xml.No_attribute _ ->
11158     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11159
11160 ";
11161
11162   generate_parsers grammar;
11163   pr "\n";
11164
11165   pr "\
11166 (* Run external virt-inspector, then use parser to parse the XML. *)
11167 let inspect ?connect ?xml names =
11168   let xml =
11169     match xml with
11170     | None ->
11171         if names = [] then invalid_arg \"inspect: no names given\";
11172         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11173           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11174           names in
11175         let cmd = List.map Filename.quote cmd in
11176         let cmd = String.concat \" \" cmd in
11177         let chan = open_process_in cmd in
11178         let xml = Xml.parse_in chan in
11179         (match close_process_in chan with
11180          | WEXITED 0 -> ()
11181          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11182          | WSIGNALED i | WSTOPPED i ->
11183              failwith (\"external virt-inspector command died or stopped on sig \" ^
11184                        string_of_int i)
11185         );
11186         xml
11187     | Some doc ->
11188         Xml.parse_string doc in
11189   parse_operatingsystems xml
11190 "
11191
11192 (* This is used to generate the src/MAX_PROC_NR file which
11193  * contains the maximum procedure number, a surrogate for the
11194  * ABI version number.  See src/Makefile.am for the details.
11195  *)
11196 and generate_max_proc_nr () =
11197   let proc_nrs = List.map (
11198     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11199   ) daemon_functions in
11200
11201   let max_proc_nr = List.fold_left max 0 proc_nrs in
11202
11203   pr "%d\n" max_proc_nr
11204
11205 let output_to filename k =
11206   let filename_new = filename ^ ".new" in
11207   chan := open_out filename_new;
11208   k ();
11209   close_out !chan;
11210   chan := Pervasives.stdout;
11211
11212   (* Is the new file different from the current file? *)
11213   if Sys.file_exists filename && files_equal filename filename_new then
11214     unlink filename_new                 (* same, so skip it *)
11215   else (
11216     (* different, overwrite old one *)
11217     (try chmod filename 0o644 with Unix_error _ -> ());
11218     rename filename_new filename;
11219     chmod filename 0o444;
11220     printf "written %s\n%!" filename;
11221   )
11222
11223 let perror msg = function
11224   | Unix_error (err, _, _) ->
11225       eprintf "%s: %s\n" msg (error_message err)
11226   | exn ->
11227       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11228
11229 (* Main program. *)
11230 let () =
11231   let lock_fd =
11232     try openfile "HACKING" [O_RDWR] 0
11233     with
11234     | Unix_error (ENOENT, _, _) ->
11235         eprintf "\
11236 You are probably running this from the wrong directory.
11237 Run it from the top source directory using the command
11238   src/generator.ml
11239 ";
11240         exit 1
11241     | exn ->
11242         perror "open: HACKING" exn;
11243         exit 1 in
11244
11245   (* Acquire a lock so parallel builds won't try to run the generator
11246    * twice at the same time.  Subsequent builds will wait for the first
11247    * one to finish.  Note the lock is released implicitly when the
11248    * program exits.
11249    *)
11250   (try lockf lock_fd F_LOCK 1
11251    with exn ->
11252      perror "lock: HACKING" exn;
11253      exit 1);
11254
11255   check_functions ();
11256
11257   output_to "src/guestfs_protocol.x" generate_xdr;
11258   output_to "src/guestfs-structs.h" generate_structs_h;
11259   output_to "src/guestfs-actions.h" generate_actions_h;
11260   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11261   output_to "src/guestfs-actions.c" generate_client_actions;
11262   output_to "src/guestfs-bindtests.c" generate_bindtests;
11263   output_to "src/guestfs-structs.pod" generate_structs_pod;
11264   output_to "src/guestfs-actions.pod" generate_actions_pod;
11265   output_to "src/guestfs-availability.pod" generate_availability_pod;
11266   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11267   output_to "src/libguestfs.syms" generate_linker_script;
11268   output_to "daemon/actions.h" generate_daemon_actions_h;
11269   output_to "daemon/stubs.c" generate_daemon_actions;
11270   output_to "daemon/names.c" generate_daemon_names;
11271   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11272   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11273   output_to "capitests/tests.c" generate_tests;
11274   output_to "fish/cmds.c" generate_fish_cmds;
11275   output_to "fish/completion.c" generate_fish_completion;
11276   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11277   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11278   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11279   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11280   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11281   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11282   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11283   output_to "perl/Guestfs.xs" generate_perl_xs;
11284   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11285   output_to "perl/bindtests.pl" generate_perl_bindtests;
11286   output_to "python/guestfs-py.c" generate_python_c;
11287   output_to "python/guestfs.py" generate_python_py;
11288   output_to "python/bindtests.py" generate_python_bindtests;
11289   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11290   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11291   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11292
11293   List.iter (
11294     fun (typ, jtyp) ->
11295       let cols = cols_of_struct typ in
11296       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11297       output_to filename (generate_java_struct jtyp cols);
11298   ) java_structs;
11299
11300   output_to "java/Makefile.inc" generate_java_makefile_inc;
11301   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11302   output_to "java/Bindtests.java" generate_java_bindtests;
11303   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11304   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11305   output_to "csharp/Libguestfs.cs" generate_csharp;
11306
11307   (* Always generate this file last, and unconditionally.  It's used
11308    * by the Makefile to know when we must re-run the generator.
11309    *)
11310   let chan = open_out "src/stamp-generator" in
11311   fprintf chan "1\n";
11312   close_out chan;
11313
11314   printf "generated %d lines of code\n" !lines