generator: Print total lines of generated code.
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009-2010 Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *)
19
20 (* This script generates a large amount of code and documentation for
21  * all the daemon actions.
22  * 
23  * To add a new action there are only two files you need to change,
24  * this one to describe the interface (see the big table of
25  * 'daemon_functions' below), and daemon/<somefile>.c to write the
26  * implementation.
27  * 
28  * After editing this file, run it (./src/generator.ml) to regenerate
29  * all the output files.  'make' will rerun this automatically when
30  * necessary.  Note that if you are using a separate build directory
31  * you must run generator.ml from the _source_ directory.
32  * 
33  * IMPORTANT: This script should NOT print any warnings.  If it prints
34  * warnings, you should treat them as errors.
35  *
36  * OCaml tips:
37  * (1) In emacs, install tuareg-mode to display and format OCaml code
38  * correctly.  'vim' comes with a good OCaml editing mode by default.
39  * (2) Read the resources at http://ocaml-tutorial.org/
40  *)
41
42 #load "unix.cma";;
43 #load "str.cma";;
44 #directory "+xml-light";;
45 #load "xml-light.cma";;
46
47 open Unix
48 open Printf
49
50 type style = ret * args
51 and ret =
52     (* "RErr" as a return value means an int used as a simple error
53      * indication, ie. 0 or -1.
54      *)
55   | RErr
56
57     (* "RInt" as a return value means an int which is -1 for error
58      * or any value >= 0 on success.  Only use this for smallish
59      * positive ints (0 <= i < 2^30).
60      *)
61   | RInt of string
62
63     (* "RInt64" is the same as RInt, but is guaranteed to be able
64      * to return a full 64 bit value, _except_ that -1 means error
65      * (so -1 cannot be a valid, non-error return value).
66      *)
67   | RInt64 of string
68
69     (* "RBool" is a bool return value which can be true/false or
70      * -1 for error.
71      *)
72   | RBool of string
73
74     (* "RConstString" is a string that refers to a constant value.
75      * The return value must NOT be NULL (since NULL indicates
76      * an error).
77      *
78      * Try to avoid using this.  In particular you cannot use this
79      * for values returned from the daemon, because there is no
80      * thread-safe way to return them in the C API.
81      *)
82   | RConstString of string
83
84     (* "RConstOptString" is an even more broken version of
85      * "RConstString".  The returned string may be NULL and there
86      * is no way to return an error indication.  Avoid using this!
87      *)
88   | RConstOptString of string
89
90     (* "RString" is a returned string.  It must NOT be NULL, since
91      * a NULL return indicates an error.  The caller frees this.
92      *)
93   | RString of string
94
95     (* "RStringList" is a list of strings.  No string in the list
96      * can be NULL.  The caller frees the strings and the array.
97      *)
98   | RStringList of string
99
100     (* "RStruct" is a function which returns a single named structure
101      * or an error indication (in C, a struct, and in other languages
102      * with varying representations, but usually very efficient).  See
103      * after the function list below for the structures.
104      *)
105   | RStruct of string * string          (* name of retval, name of struct *)
106
107     (* "RStructList" is a function which returns either a list/array
108      * of structures (could be zero-length), or an error indication.
109      *)
110   | RStructList of string * string      (* name of retval, name of struct *)
111
112     (* Key-value pairs of untyped strings.  Turns into a hashtable or
113      * dictionary in languages which support it.  DON'T use this as a
114      * general "bucket" for results.  Prefer a stronger typed return
115      * value if one is available, or write a custom struct.  Don't use
116      * this if the list could potentially be very long, since it is
117      * inefficient.  Keys should be unique.  NULLs are not permitted.
118      *)
119   | RHashtable of string
120
121     (* "RBufferOut" is handled almost exactly like RString, but
122      * it allows the string to contain arbitrary 8 bit data including
123      * ASCII NUL.  In the C API this causes an implicit extra parameter
124      * to be added of type <size_t *size_r>.  The extra parameter
125      * returns the actual size of the return buffer in bytes.
126      *
127      * Other programming languages support strings with arbitrary 8 bit
128      * data.
129      *
130      * At the RPC layer we have to use the opaque<> type instead of
131      * string<>.  Returned data is still limited to the max message
132      * size (ie. ~ 2 MB).
133      *)
134   | RBufferOut of string
135
136 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
137
138     (* Note in future we should allow a "variable args" parameter as
139      * the final parameter, to allow commands like
140      *   chmod mode file [file(s)...]
141      * This is not implemented yet, but many commands (such as chmod)
142      * are currently defined with the argument order keeping this future
143      * possibility in mind.
144      *)
145 and argt =
146   | String of string    (* const char *name, cannot be NULL *)
147   | Device of string    (* /dev device name, cannot be NULL *)
148   | Pathname of string  (* file name, cannot be NULL *)
149   | Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
150   | OptString of string (* const char *name, may be NULL *)
151   | StringList of string(* list of strings (each string cannot be NULL) *)
152   | DeviceList of string(* list of Device names (each cannot be NULL) *)
153   | Bool of string      (* boolean *)
154   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
155   | Int64 of string     (* any 64 bit int *)
156     (* These are treated as filenames (simple string parameters) in
157      * the C API and bindings.  But in the RPC protocol, we transfer
158      * the actual file content up to or down from the daemon.
159      * FileIn: local machine -> daemon (in request)
160      * FileOut: daemon -> local machine (in reply)
161      * In guestfish (only), the special name "-" means read from
162      * stdin or write to stdout.
163      *)
164   | FileIn of string
165   | FileOut of string
166 (* Not implemented:
167     (* Opaque buffer which can contain arbitrary 8 bit data.
168      * In the C API, this is expressed as <char *, int> pair.
169      * Most other languages have a string type which can contain
170      * ASCII NUL.  We use whatever type is appropriate for each
171      * language.
172      * Buffers are limited by the total message size.  To transfer
173      * large blocks of data, use FileIn/FileOut parameters instead.
174      * To return an arbitrary buffer, use RBufferOut.
175      *)
176   | BufferIn of string
177 *)
178
179 type flags =
180   | ProtocolLimitWarning  (* display warning about protocol size limits *)
181   | DangerWillRobinson    (* flags particularly dangerous commands *)
182   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
183   | FishAction of string  (* call this function in guestfish *)
184   | NotInFish             (* do not export via guestfish *)
185   | NotInDocs             (* do not add this function to documentation *)
186   | DeprecatedBy of string (* function is deprecated, use .. instead *)
187   | Optional of string    (* function is part of an optional group *)
188
189 (* You can supply zero or as many tests as you want per API call.
190  *
191  * Note that the test environment has 3 block devices, of size 500MB,
192  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
193  * a fourth ISO block device with some known files on it (/dev/sdd).
194  *
195  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
196  * Number of cylinders was 63 for IDE emulated disks with precisely
197  * the same size.  How exactly this is calculated is a mystery.
198  *
199  * The ISO block device (/dev/sdd) comes from images/test.iso.
200  *
201  * To be able to run the tests in a reasonable amount of time,
202  * the virtual machine and block devices are reused between tests.
203  * So don't try testing kill_subprocess :-x
204  *
205  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
206  *
207  * Don't assume anything about the previous contents of the block
208  * devices.  Use 'Init*' to create some initial scenarios.
209  *
210  * You can add a prerequisite clause to any individual test.  This
211  * is a run-time check, which, if it fails, causes the test to be
212  * skipped.  Useful if testing a command which might not work on
213  * all variations of libguestfs builds.  A test that has prerequisite
214  * of 'Always' is run unconditionally.
215  *
216  * In addition, packagers can skip individual tests by setting the
217  * environment variables:     eg:
218  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
219  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
220  *)
221 type tests = (test_init * test_prereq * test) list
222 and test =
223     (* Run the command sequence and just expect nothing to fail. *)
224   | TestRun of seq
225
226     (* Run the command sequence and expect the output of the final
227      * command to be the string.
228      *)
229   | TestOutput of seq * string
230
231     (* Run the command sequence and expect the output of the final
232      * command to be the list of strings.
233      *)
234   | TestOutputList of seq * string list
235
236     (* Run the command sequence and expect the output of the final
237      * command to be the list of block devices (could be either
238      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
239      * character of each string).
240      *)
241   | TestOutputListOfDevices of seq * string list
242
243     (* Run the command sequence and expect the output of the final
244      * command to be the integer.
245      *)
246   | TestOutputInt of seq * int
247
248     (* Run the command sequence and expect the output of the final
249      * command to be <op> <int>, eg. ">=", "1".
250      *)
251   | TestOutputIntOp of seq * string * int
252
253     (* Run the command sequence and expect the output of the final
254      * command to be a true value (!= 0 or != NULL).
255      *)
256   | TestOutputTrue of seq
257
258     (* Run the command sequence and expect the output of the final
259      * command to be a false value (== 0 or == NULL, but not an error).
260      *)
261   | TestOutputFalse of seq
262
263     (* Run the command sequence and expect the output of the final
264      * command to be a list of the given length (but don't care about
265      * content).
266      *)
267   | TestOutputLength of seq * int
268
269     (* Run the command sequence and expect the output of the final
270      * command to be a buffer (RBufferOut), ie. string + size.
271      *)
272   | TestOutputBuffer of seq * string
273
274     (* Run the command sequence and expect the output of the final
275      * command to be a structure.
276      *)
277   | TestOutputStruct of seq * test_field_compare list
278
279     (* Run the command sequence and expect the final command (only)
280      * to fail.
281      *)
282   | TestLastFail of seq
283
284 and test_field_compare =
285   | CompareWithInt of string * int
286   | CompareWithIntOp of string * string * int
287   | CompareWithString of string * string
288   | CompareFieldsIntEq of string * string
289   | CompareFieldsStrEq of string * string
290
291 (* Test prerequisites. *)
292 and test_prereq =
293     (* Test always runs. *)
294   | Always
295
296     (* Test is currently disabled - eg. it fails, or it tests some
297      * unimplemented feature.
298      *)
299   | Disabled
300
301     (* 'string' is some C code (a function body) that should return
302      * true or false.  The test will run if the code returns true.
303      *)
304   | If of string
305
306     (* As for 'If' but the test runs _unless_ the code returns true. *)
307   | Unless of string
308
309 (* Some initial scenarios for testing. *)
310 and test_init =
311     (* Do nothing, block devices could contain random stuff including
312      * LVM PVs, and some filesystems might be mounted.  This is usually
313      * a bad idea.
314      *)
315   | InitNone
316
317     (* Block devices are empty and no filesystems are mounted. *)
318   | InitEmpty
319
320     (* /dev/sda contains a single partition /dev/sda1, with random
321      * content.  /dev/sdb and /dev/sdc may have random content.
322      * No LVM.
323      *)
324   | InitPartition
325
326     (* /dev/sda contains a single partition /dev/sda1, which is formatted
327      * as ext2, empty [except for lost+found] and mounted on /.
328      * /dev/sdb and /dev/sdc may have random content.
329      * No LVM.
330      *)
331   | InitBasicFS
332
333     (* /dev/sda:
334      *   /dev/sda1 (is a PV):
335      *     /dev/VG/LV (size 8MB):
336      *       formatted as ext2, empty [except for lost+found], mounted on /
337      * /dev/sdb and /dev/sdc may have random content.
338      *)
339   | InitBasicFSonLVM
340
341     (* /dev/sdd (the ISO, see images/ directory in source)
342      * is mounted on /
343      *)
344   | InitISOFS
345
346 (* Sequence of commands for testing. *)
347 and seq = cmd list
348 and cmd = string list
349
350 (* Note about long descriptions: When referring to another
351  * action, use the format C<guestfs_other> (ie. the full name of
352  * the C function).  This will be replaced as appropriate in other
353  * language bindings.
354  *
355  * Apart from that, long descriptions are just perldoc paragraphs.
356  *)
357
358 (* Generate a random UUID (used in tests). *)
359 let uuidgen () =
360   let chan = open_process_in "uuidgen" in
361   let uuid = input_line chan in
362   (match close_process_in chan with
363    | WEXITED 0 -> ()
364    | WEXITED _ ->
365        failwith "uuidgen: process exited with non-zero status"
366    | WSIGNALED _ | WSTOPPED _ ->
367        failwith "uuidgen: process signalled or stopped by signal"
368   );
369   uuid
370
371 (* These test functions are used in the language binding tests. *)
372
373 let test_all_args = [
374   String "str";
375   OptString "optstr";
376   StringList "strlist";
377   Bool "b";
378   Int "integer";
379   Int64 "integer64";
380   FileIn "filein";
381   FileOut "fileout";
382 ]
383
384 let test_all_rets = [
385   (* except for RErr, which is tested thoroughly elsewhere *)
386   "test0rint",         RInt "valout";
387   "test0rint64",       RInt64 "valout";
388   "test0rbool",        RBool "valout";
389   "test0rconststring", RConstString "valout";
390   "test0rconstoptstring", RConstOptString "valout";
391   "test0rstring",      RString "valout";
392   "test0rstringlist",  RStringList "valout";
393   "test0rstruct",      RStruct ("valout", "lvm_pv");
394   "test0rstructlist",  RStructList ("valout", "lvm_pv");
395   "test0rhashtable",   RHashtable "valout";
396 ]
397
398 let test_functions = [
399   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
400    [],
401    "internal test function - do not use",
402    "\
403 This is an internal test function which is used to test whether
404 the automatically generated bindings can handle every possible
405 parameter type correctly.
406
407 It echos the contents of each parameter to stdout.
408
409 You probably don't want to call this function.");
410 ] @ List.flatten (
411   List.map (
412     fun (name, ret) ->
413       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
414         [],
415         "internal test function - do not use",
416         "\
417 This is an internal test function which is used to test whether
418 the automatically generated bindings can handle every possible
419 return type correctly.
420
421 It converts string C<val> to the return type.
422
423 You probably don't want to call this function.");
424        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
425         [],
426         "internal test function - do not use",
427         "\
428 This is an internal test function which is used to test whether
429 the automatically generated bindings can handle every possible
430 return type correctly.
431
432 This function always returns an error.
433
434 You probably don't want to call this function.")]
435   ) test_all_rets
436 )
437
438 (* non_daemon_functions are any functions which don't get processed
439  * in the daemon, eg. functions for setting and getting local
440  * configuration values.
441  *)
442
443 let non_daemon_functions = test_functions @ [
444   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
445    [],
446    "launch the qemu subprocess",
447    "\
448 Internally libguestfs is implemented by running a virtual machine
449 using L<qemu(1)>.
450
451 You should call this after configuring the handle
452 (eg. adding drives) but before performing any actions.");
453
454   ("wait_ready", (RErr, []), -1, [NotInFish],
455    [],
456    "wait until the qemu subprocess launches (no op)",
457    "\
458 This function is a no op.
459
460 In versions of the API E<lt> 1.0.71 you had to call this function
461 just after calling C<guestfs_launch> to wait for the launch
462 to complete.  However this is no longer necessary because
463 C<guestfs_launch> now does the waiting.
464
465 If you see any calls to this function in code then you can just
466 remove them, unless you want to retain compatibility with older
467 versions of the API.");
468
469   ("kill_subprocess", (RErr, []), -1, [],
470    [],
471    "kill the qemu subprocess",
472    "\
473 This kills the qemu subprocess.  You should never need to call this.");
474
475   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
476    [],
477    "add an image to examine or modify",
478    "\
479 This function adds a virtual machine disk image C<filename> to the
480 guest.  The first time you call this function, the disk appears as IDE
481 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
482 so on.
483
484 You don't necessarily need to be root when using libguestfs.  However
485 you obviously do need sufficient permissions to access the filename
486 for whatever operations you want to perform (ie. read access if you
487 just want to read the image or write access if you want to modify the
488 image).
489
490 This is equivalent to the qemu parameter
491 C<-drive file=filename,cache=off,if=...>.
492 C<cache=off> is omitted in cases where it is not supported by
493 the underlying filesystem.
494
495 Note that this call checks for the existence of C<filename>.  This
496 stops you from specifying other types of drive which are supported
497 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
498 the general C<guestfs_config> call instead.");
499
500   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
501    [],
502    "add a CD-ROM disk image to examine",
503    "\
504 This function adds a virtual CD-ROM disk image to the guest.
505
506 This is equivalent to the qemu parameter C<-cdrom filename>.
507
508 Note that this call checks for the existence of C<filename>.  This
509 stops you from specifying other types of drive which are supported
510 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
511 the general C<guestfs_config> call instead.");
512
513   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
514    [],
515    "add a drive in snapshot mode (read-only)",
516    "\
517 This adds a drive in snapshot mode, making it effectively
518 read-only.
519
520 Note that writes to the device are allowed, and will be seen for
521 the duration of the guestfs handle, but they are written
522 to a temporary file which is discarded as soon as the guestfs
523 handle is closed.  We don't currently have any method to enable
524 changes to be committed, although qemu can support this.
525
526 This is equivalent to the qemu parameter
527 C<-drive file=filename,snapshot=on,if=...>.
528
529 Note that this call checks for the existence of C<filename>.  This
530 stops you from specifying other types of drive which are supported
531 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
532 the general C<guestfs_config> call instead.");
533
534   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
535    [],
536    "add qemu parameters",
537    "\
538 This can be used to add arbitrary qemu command line parameters
539 of the form C<-param value>.  Actually it's not quite arbitrary - we
540 prevent you from setting some parameters which would interfere with
541 parameters that we use.
542
543 The first character of C<param> string must be a C<-> (dash).
544
545 C<value> can be NULL.");
546
547   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
548    [],
549    "set the qemu binary",
550    "\
551 Set the qemu binary that we will use.
552
553 The default is chosen when the library was compiled by the
554 configure script.
555
556 You can also override this by setting the C<LIBGUESTFS_QEMU>
557 environment variable.
558
559 Setting C<qemu> to C<NULL> restores the default qemu binary.");
560
561   ("get_qemu", (RConstString "qemu", []), -1, [],
562    [InitNone, Always, TestRun (
563       [["get_qemu"]])],
564    "get the qemu binary",
565    "\
566 Return the current qemu binary.
567
568 This is always non-NULL.  If it wasn't set already, then this will
569 return the default qemu binary name.");
570
571   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
572    [],
573    "set the search path",
574    "\
575 Set the path that libguestfs searches for kernel and initrd.img.
576
577 The default is C<$libdir/guestfs> unless overridden by setting
578 C<LIBGUESTFS_PATH> environment variable.
579
580 Setting C<path> to C<NULL> restores the default path.");
581
582   ("get_path", (RConstString "path", []), -1, [],
583    [InitNone, Always, TestRun (
584       [["get_path"]])],
585    "get the search path",
586    "\
587 Return the current search path.
588
589 This is always non-NULL.  If it wasn't set already, then this will
590 return the default path.");
591
592   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
593    [],
594    "add options to kernel command line",
595    "\
596 This function is used to add additional options to the
597 guest kernel command line.
598
599 The default is C<NULL> unless overridden by setting
600 C<LIBGUESTFS_APPEND> environment variable.
601
602 Setting C<append> to C<NULL> means I<no> additional options
603 are passed (libguestfs always adds a few of its own).");
604
605   ("get_append", (RConstOptString "append", []), -1, [],
606    (* This cannot be tested with the current framework.  The
607     * function can return NULL in normal operations, which the
608     * test framework interprets as an error.
609     *)
610    [],
611    "get the additional kernel options",
612    "\
613 Return the additional kernel options which are added to the
614 guest kernel command line.
615
616 If C<NULL> then no options are added.");
617
618   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
619    [],
620    "set autosync mode",
621    "\
622 If C<autosync> is true, this enables autosync.  Libguestfs will make a
623 best effort attempt to run C<guestfs_umount_all> followed by
624 C<guestfs_sync> when the handle is closed
625 (also if the program exits without closing handles).
626
627 This is disabled by default (except in guestfish where it is
628 enabled by default).");
629
630   ("get_autosync", (RBool "autosync", []), -1, [],
631    [InitNone, Always, TestRun (
632       [["get_autosync"]])],
633    "get autosync mode",
634    "\
635 Get the autosync flag.");
636
637   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
638    [],
639    "set verbose mode",
640    "\
641 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
642
643 Verbose messages are disabled unless the environment variable
644 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
645
646   ("get_verbose", (RBool "verbose", []), -1, [],
647    [],
648    "get verbose mode",
649    "\
650 This returns the verbose messages flag.");
651
652   ("is_ready", (RBool "ready", []), -1, [],
653    [InitNone, Always, TestOutputTrue (
654       [["is_ready"]])],
655    "is ready to accept commands",
656    "\
657 This returns true iff this handle is ready to accept commands
658 (in the C<READY> state).
659
660 For more information on states, see L<guestfs(3)>.");
661
662   ("is_config", (RBool "config", []), -1, [],
663    [InitNone, Always, TestOutputFalse (
664       [["is_config"]])],
665    "is in configuration state",
666    "\
667 This returns true iff this handle is being configured
668 (in the C<CONFIG> state).
669
670 For more information on states, see L<guestfs(3)>.");
671
672   ("is_launching", (RBool "launching", []), -1, [],
673    [InitNone, Always, TestOutputFalse (
674       [["is_launching"]])],
675    "is launching subprocess",
676    "\
677 This returns true iff this handle is launching the subprocess
678 (in the C<LAUNCHING> state).
679
680 For more information on states, see L<guestfs(3)>.");
681
682   ("is_busy", (RBool "busy", []), -1, [],
683    [InitNone, Always, TestOutputFalse (
684       [["is_busy"]])],
685    "is busy processing a command",
686    "\
687 This returns true iff this handle is busy processing a command
688 (in the C<BUSY> state).
689
690 For more information on states, see L<guestfs(3)>.");
691
692   ("get_state", (RInt "state", []), -1, [],
693    [],
694    "get the current state",
695    "\
696 This returns the current state as an opaque integer.  This is
697 only useful for printing debug and internal error messages.
698
699 For more information on states, see L<guestfs(3)>.");
700
701   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
702    [InitNone, Always, TestOutputInt (
703       [["set_memsize"; "500"];
704        ["get_memsize"]], 500)],
705    "set memory allocated to the qemu subprocess",
706    "\
707 This sets the memory size in megabytes allocated to the
708 qemu subprocess.  This only has any effect if called before
709 C<guestfs_launch>.
710
711 You can also change this by setting the environment
712 variable C<LIBGUESTFS_MEMSIZE> before the handle is
713 created.
714
715 For more information on the architecture of libguestfs,
716 see L<guestfs(3)>.");
717
718   ("get_memsize", (RInt "memsize", []), -1, [],
719    [InitNone, Always, TestOutputIntOp (
720       [["get_memsize"]], ">=", 256)],
721    "get memory allocated to the qemu subprocess",
722    "\
723 This gets the memory size in megabytes allocated to the
724 qemu subprocess.
725
726 If C<guestfs_set_memsize> was not called
727 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
728 then this returns the compiled-in default value for memsize.
729
730 For more information on the architecture of libguestfs,
731 see L<guestfs(3)>.");
732
733   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
734    [InitNone, Always, TestOutputIntOp (
735       [["get_pid"]], ">=", 1)],
736    "get PID of qemu subprocess",
737    "\
738 Return the process ID of the qemu subprocess.  If there is no
739 qemu subprocess, then this will return an error.
740
741 This is an internal call used for debugging and testing.");
742
743   ("version", (RStruct ("version", "version"), []), -1, [],
744    [InitNone, Always, TestOutputStruct (
745       [["version"]], [CompareWithInt ("major", 1)])],
746    "get the library version number",
747    "\
748 Return the libguestfs version number that the program is linked
749 against.
750
751 Note that because of dynamic linking this is not necessarily
752 the version of libguestfs that you compiled against.  You can
753 compile the program, and then at runtime dynamically link
754 against a completely different C<libguestfs.so> library.
755
756 This call was added in version C<1.0.58>.  In previous
757 versions of libguestfs there was no way to get the version
758 number.  From C code you can use ELF weak linking tricks to find out if
759 this symbol exists (if it doesn't, then it's an earlier version).
760
761 The call returns a structure with four elements.  The first
762 three (C<major>, C<minor> and C<release>) are numbers and
763 correspond to the usual version triplet.  The fourth element
764 (C<extra>) is a string and is normally empty, but may be
765 used for distro-specific information.
766
767 To construct the original version string:
768 C<$major.$minor.$release$extra>
769
770 I<Note:> Don't use this call to test for availability
771 of features.  Distro backports makes this unreliable.  Use
772 C<guestfs_available> instead.");
773
774   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
775    [InitNone, Always, TestOutputTrue (
776       [["set_selinux"; "true"];
777        ["get_selinux"]])],
778    "set SELinux enabled or disabled at appliance boot",
779    "\
780 This sets the selinux flag that is passed to the appliance
781 at boot time.  The default is C<selinux=0> (disabled).
782
783 Note that if SELinux is enabled, it is always in
784 Permissive mode (C<enforcing=0>).
785
786 For more information on the architecture of libguestfs,
787 see L<guestfs(3)>.");
788
789   ("get_selinux", (RBool "selinux", []), -1, [],
790    [],
791    "get SELinux enabled flag",
792    "\
793 This returns the current setting of the selinux flag which
794 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
795
796 For more information on the architecture of libguestfs,
797 see L<guestfs(3)>.");
798
799   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
800    [InitNone, Always, TestOutputFalse (
801       [["set_trace"; "false"];
802        ["get_trace"]])],
803    "enable or disable command traces",
804    "\
805 If the command trace flag is set to 1, then commands are
806 printed on stdout before they are executed in a format
807 which is very similar to the one used by guestfish.  In
808 other words, you can run a program with this enabled, and
809 you will get out a script which you can feed to guestfish
810 to perform the same set of actions.
811
812 If you want to trace C API calls into libguestfs (and
813 other libraries) then possibly a better way is to use
814 the external ltrace(1) command.
815
816 Command traces are disabled unless the environment variable
817 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
818
819   ("get_trace", (RBool "trace", []), -1, [],
820    [],
821    "get command trace enabled flag",
822    "\
823 Return the command trace flag.");
824
825   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
826    [InitNone, Always, TestOutputFalse (
827       [["set_direct"; "false"];
828        ["get_direct"]])],
829    "enable or disable direct appliance mode",
830    "\
831 If the direct appliance mode flag is enabled, then stdin and
832 stdout are passed directly through to the appliance once it
833 is launched.
834
835 One consequence of this is that log messages aren't caught
836 by the library and handled by C<guestfs_set_log_message_callback>,
837 but go straight to stdout.
838
839 You probably don't want to use this unless you know what you
840 are doing.
841
842 The default is disabled.");
843
844   ("get_direct", (RBool "direct", []), -1, [],
845    [],
846    "get direct appliance mode flag",
847    "\
848 Return the direct appliance mode flag.");
849
850   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
851    [InitNone, Always, TestOutputTrue (
852       [["set_recovery_proc"; "true"];
853        ["get_recovery_proc"]])],
854    "enable or disable the recovery process",
855    "\
856 If this is called with the parameter C<false> then
857 C<guestfs_launch> does not create a recovery process.  The
858 purpose of the recovery process is to stop runaway qemu
859 processes in the case where the main program aborts abruptly.
860
861 This only has any effect if called before C<guestfs_launch>,
862 and the default is true.
863
864 About the only time when you would want to disable this is
865 if the main process will fork itself into the background
866 (\"daemonize\" itself).  In this case the recovery process
867 thinks that the main program has disappeared and so kills
868 qemu, which is not very helpful.");
869
870   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
871    [],
872    "get recovery process enabled flag",
873    "\
874 Return the recovery process enabled flag.");
875
876 ]
877
878 (* daemon_functions are any functions which cause some action
879  * to take place in the daemon.
880  *)
881
882 let daemon_functions = [
883   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
884    [InitEmpty, Always, TestOutput (
885       [["part_disk"; "/dev/sda"; "mbr"];
886        ["mkfs"; "ext2"; "/dev/sda1"];
887        ["mount"; "/dev/sda1"; "/"];
888        ["write_file"; "/new"; "new file contents"; "0"];
889        ["cat"; "/new"]], "new file contents")],
890    "mount a guest disk at a position in the filesystem",
891    "\
892 Mount a guest disk at a position in the filesystem.  Block devices
893 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
894 the guest.  If those block devices contain partitions, they will have
895 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
896 names can be used.
897
898 The rules are the same as for L<mount(2)>:  A filesystem must
899 first be mounted on C</> before others can be mounted.  Other
900 filesystems can only be mounted on directories which already
901 exist.
902
903 The mounted filesystem is writable, if we have sufficient permissions
904 on the underlying device.
905
906 The filesystem options C<sync> and C<noatime> are set with this
907 call, in order to improve reliability.");
908
909   ("sync", (RErr, []), 2, [],
910    [ InitEmpty, Always, TestRun [["sync"]]],
911    "sync disks, writes are flushed through to the disk image",
912    "\
913 This syncs the disk, so that any writes are flushed through to the
914 underlying disk image.
915
916 You should always call this if you have modified a disk image, before
917 closing the handle.");
918
919   ("touch", (RErr, [Pathname "path"]), 3, [],
920    [InitBasicFS, Always, TestOutputTrue (
921       [["touch"; "/new"];
922        ["exists"; "/new"]])],
923    "update file timestamps or create a new file",
924    "\
925 Touch acts like the L<touch(1)> command.  It can be used to
926 update the timestamps on a file, or, if the file does not exist,
927 to create a new zero-length file.");
928
929   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
930    [InitISOFS, Always, TestOutput (
931       [["cat"; "/known-2"]], "abcdef\n")],
932    "list the contents of a file",
933    "\
934 Return the contents of the file named C<path>.
935
936 Note that this function cannot correctly handle binary files
937 (specifically, files containing C<\\0> character which is treated
938 as end of string).  For those you need to use the C<guestfs_read_file>
939 or C<guestfs_download> functions which have a more complex interface.");
940
941   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
942    [], (* XXX Tricky to test because it depends on the exact format
943         * of the 'ls -l' command, which changes between F10 and F11.
944         *)
945    "list the files in a directory (long format)",
946    "\
947 List the files in C<directory> (relative to the root directory,
948 there is no cwd) in the format of 'ls -la'.
949
950 This command is mostly useful for interactive sessions.  It
951 is I<not> intended that you try to parse the output string.");
952
953   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
954    [InitBasicFS, Always, TestOutputList (
955       [["touch"; "/new"];
956        ["touch"; "/newer"];
957        ["touch"; "/newest"];
958        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
959    "list the files in a directory",
960    "\
961 List the files in C<directory> (relative to the root directory,
962 there is no cwd).  The '.' and '..' entries are not returned, but
963 hidden files are shown.
964
965 This command is mostly useful for interactive sessions.  Programs
966 should probably use C<guestfs_readdir> instead.");
967
968   ("list_devices", (RStringList "devices", []), 7, [],
969    [InitEmpty, Always, TestOutputListOfDevices (
970       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
971    "list the block devices",
972    "\
973 List all the block devices.
974
975 The full block device names are returned, eg. C</dev/sda>");
976
977   ("list_partitions", (RStringList "partitions", []), 8, [],
978    [InitBasicFS, Always, TestOutputListOfDevices (
979       [["list_partitions"]], ["/dev/sda1"]);
980     InitEmpty, Always, TestOutputListOfDevices (
981       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
982        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
983    "list the partitions",
984    "\
985 List all the partitions detected on all block devices.
986
987 The full partition device names are returned, eg. C</dev/sda1>
988
989 This does not return logical volumes.  For that you will need to
990 call C<guestfs_lvs>.");
991
992   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
993    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
994       [["pvs"]], ["/dev/sda1"]);
995     InitEmpty, Always, TestOutputListOfDevices (
996       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
997        ["pvcreate"; "/dev/sda1"];
998        ["pvcreate"; "/dev/sda2"];
999        ["pvcreate"; "/dev/sda3"];
1000        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1001    "list the LVM physical volumes (PVs)",
1002    "\
1003 List all the physical volumes detected.  This is the equivalent
1004 of the L<pvs(8)> command.
1005
1006 This returns a list of just the device names that contain
1007 PVs (eg. C</dev/sda2>).
1008
1009 See also C<guestfs_pvs_full>.");
1010
1011   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1012    [InitBasicFSonLVM, Always, TestOutputList (
1013       [["vgs"]], ["VG"]);
1014     InitEmpty, Always, TestOutputList (
1015       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1016        ["pvcreate"; "/dev/sda1"];
1017        ["pvcreate"; "/dev/sda2"];
1018        ["pvcreate"; "/dev/sda3"];
1019        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1020        ["vgcreate"; "VG2"; "/dev/sda3"];
1021        ["vgs"]], ["VG1"; "VG2"])],
1022    "list the LVM volume groups (VGs)",
1023    "\
1024 List all the volumes groups detected.  This is the equivalent
1025 of the L<vgs(8)> command.
1026
1027 This returns a list of just the volume group names that were
1028 detected (eg. C<VolGroup00>).
1029
1030 See also C<guestfs_vgs_full>.");
1031
1032   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1033    [InitBasicFSonLVM, Always, TestOutputList (
1034       [["lvs"]], ["/dev/VG/LV"]);
1035     InitEmpty, Always, TestOutputList (
1036       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1037        ["pvcreate"; "/dev/sda1"];
1038        ["pvcreate"; "/dev/sda2"];
1039        ["pvcreate"; "/dev/sda3"];
1040        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1041        ["vgcreate"; "VG2"; "/dev/sda3"];
1042        ["lvcreate"; "LV1"; "VG1"; "50"];
1043        ["lvcreate"; "LV2"; "VG1"; "50"];
1044        ["lvcreate"; "LV3"; "VG2"; "50"];
1045        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1046    "list the LVM logical volumes (LVs)",
1047    "\
1048 List all the logical volumes detected.  This is the equivalent
1049 of the L<lvs(8)> command.
1050
1051 This returns a list of the logical volume device names
1052 (eg. C</dev/VolGroup00/LogVol00>).
1053
1054 See also C<guestfs_lvs_full>.");
1055
1056   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1057    [], (* XXX how to test? *)
1058    "list the LVM physical volumes (PVs)",
1059    "\
1060 List all the physical volumes detected.  This is the equivalent
1061 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1062
1063   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1064    [], (* XXX how to test? *)
1065    "list the LVM volume groups (VGs)",
1066    "\
1067 List all the volumes groups detected.  This is the equivalent
1068 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1069
1070   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1071    [], (* XXX how to test? *)
1072    "list the LVM logical volumes (LVs)",
1073    "\
1074 List all the logical volumes detected.  This is the equivalent
1075 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1076
1077   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1078    [InitISOFS, Always, TestOutputList (
1079       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1080     InitISOFS, Always, TestOutputList (
1081       [["read_lines"; "/empty"]], [])],
1082    "read file as lines",
1083    "\
1084 Return the contents of the file named C<path>.
1085
1086 The file contents are returned as a list of lines.  Trailing
1087 C<LF> and C<CRLF> character sequences are I<not> returned.
1088
1089 Note that this function cannot correctly handle binary files
1090 (specifically, files containing C<\\0> character which is treated
1091 as end of line).  For those you need to use the C<guestfs_read_file>
1092 function which has a more complex interface.");
1093
1094   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1095    [], (* XXX Augeas code needs tests. *)
1096    "create a new Augeas handle",
1097    "\
1098 Create a new Augeas handle for editing configuration files.
1099 If there was any previous Augeas handle associated with this
1100 guestfs session, then it is closed.
1101
1102 You must call this before using any other C<guestfs_aug_*>
1103 commands.
1104
1105 C<root> is the filesystem root.  C<root> must not be NULL,
1106 use C</> instead.
1107
1108 The flags are the same as the flags defined in
1109 E<lt>augeas.hE<gt>, the logical I<or> of the following
1110 integers:
1111
1112 =over 4
1113
1114 =item C<AUG_SAVE_BACKUP> = 1
1115
1116 Keep the original file with a C<.augsave> extension.
1117
1118 =item C<AUG_SAVE_NEWFILE> = 2
1119
1120 Save changes into a file with extension C<.augnew>, and
1121 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1122
1123 =item C<AUG_TYPE_CHECK> = 4
1124
1125 Typecheck lenses (can be expensive).
1126
1127 =item C<AUG_NO_STDINC> = 8
1128
1129 Do not use standard load path for modules.
1130
1131 =item C<AUG_SAVE_NOOP> = 16
1132
1133 Make save a no-op, just record what would have been changed.
1134
1135 =item C<AUG_NO_LOAD> = 32
1136
1137 Do not load the tree in C<guestfs_aug_init>.
1138
1139 =back
1140
1141 To close the handle, you can call C<guestfs_aug_close>.
1142
1143 To find out more about Augeas, see L<http://augeas.net/>.");
1144
1145   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1146    [], (* XXX Augeas code needs tests. *)
1147    "close the current Augeas handle",
1148    "\
1149 Close the current Augeas handle and free up any resources
1150 used by it.  After calling this, you have to call
1151 C<guestfs_aug_init> again before you can use any other
1152 Augeas functions.");
1153
1154   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1155    [], (* XXX Augeas code needs tests. *)
1156    "define an Augeas variable",
1157    "\
1158 Defines an Augeas variable C<name> whose value is the result
1159 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1160 undefined.
1161
1162 On success this returns the number of nodes in C<expr>, or
1163 C<0> if C<expr> evaluates to something which is not a nodeset.");
1164
1165   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1166    [], (* XXX Augeas code needs tests. *)
1167    "define an Augeas node",
1168    "\
1169 Defines a variable C<name> whose value is the result of
1170 evaluating C<expr>.
1171
1172 If C<expr> evaluates to an empty nodeset, a node is created,
1173 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1174 C<name> will be the nodeset containing that single node.
1175
1176 On success this returns a pair containing the
1177 number of nodes in the nodeset, and a boolean flag
1178 if a node was created.");
1179
1180   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1181    [], (* XXX Augeas code needs tests. *)
1182    "look up the value of an Augeas path",
1183    "\
1184 Look up the value associated with C<path>.  If C<path>
1185 matches exactly one node, the C<value> is returned.");
1186
1187   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1188    [], (* XXX Augeas code needs tests. *)
1189    "set Augeas path to value",
1190    "\
1191 Set the value associated with C<path> to C<value>.");
1192
1193   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1194    [], (* XXX Augeas code needs tests. *)
1195    "insert a sibling Augeas node",
1196    "\
1197 Create a new sibling C<label> for C<path>, inserting it into
1198 the tree before or after C<path> (depending on the boolean
1199 flag C<before>).
1200
1201 C<path> must match exactly one existing node in the tree, and
1202 C<label> must be a label, ie. not contain C</>, C<*> or end
1203 with a bracketed index C<[N]>.");
1204
1205   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1206    [], (* XXX Augeas code needs tests. *)
1207    "remove an Augeas path",
1208    "\
1209 Remove C<path> and all of its children.
1210
1211 On success this returns the number of entries which were removed.");
1212
1213   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1214    [], (* XXX Augeas code needs tests. *)
1215    "move Augeas node",
1216    "\
1217 Move the node C<src> to C<dest>.  C<src> must match exactly
1218 one node.  C<dest> is overwritten if it exists.");
1219
1220   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1221    [], (* XXX Augeas code needs tests. *)
1222    "return Augeas nodes which match augpath",
1223    "\
1224 Returns a list of paths which match the path expression C<path>.
1225 The returned paths are sufficiently qualified so that they match
1226 exactly one node in the current tree.");
1227
1228   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1229    [], (* XXX Augeas code needs tests. *)
1230    "write all pending Augeas changes to disk",
1231    "\
1232 This writes all pending changes to disk.
1233
1234 The flags which were passed to C<guestfs_aug_init> affect exactly
1235 how files are saved.");
1236
1237   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1238    [], (* XXX Augeas code needs tests. *)
1239    "load files into the tree",
1240    "\
1241 Load files into the tree.
1242
1243 See C<aug_load> in the Augeas documentation for the full gory
1244 details.");
1245
1246   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1247    [], (* XXX Augeas code needs tests. *)
1248    "list Augeas nodes under augpath",
1249    "\
1250 This is just a shortcut for listing C<guestfs_aug_match>
1251 C<path/*> and sorting the resulting nodes into alphabetical order.");
1252
1253   ("rm", (RErr, [Pathname "path"]), 29, [],
1254    [InitBasicFS, Always, TestRun
1255       [["touch"; "/new"];
1256        ["rm"; "/new"]];
1257     InitBasicFS, Always, TestLastFail
1258       [["rm"; "/new"]];
1259     InitBasicFS, Always, TestLastFail
1260       [["mkdir"; "/new"];
1261        ["rm"; "/new"]]],
1262    "remove a file",
1263    "\
1264 Remove the single file C<path>.");
1265
1266   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1267    [InitBasicFS, Always, TestRun
1268       [["mkdir"; "/new"];
1269        ["rmdir"; "/new"]];
1270     InitBasicFS, Always, TestLastFail
1271       [["rmdir"; "/new"]];
1272     InitBasicFS, Always, TestLastFail
1273       [["touch"; "/new"];
1274        ["rmdir"; "/new"]]],
1275    "remove a directory",
1276    "\
1277 Remove the single directory C<path>.");
1278
1279   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1280    [InitBasicFS, Always, TestOutputFalse
1281       [["mkdir"; "/new"];
1282        ["mkdir"; "/new/foo"];
1283        ["touch"; "/new/foo/bar"];
1284        ["rm_rf"; "/new"];
1285        ["exists"; "/new"]]],
1286    "remove a file or directory recursively",
1287    "\
1288 Remove the file or directory C<path>, recursively removing the
1289 contents if its a directory.  This is like the C<rm -rf> shell
1290 command.");
1291
1292   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1293    [InitBasicFS, Always, TestOutputTrue
1294       [["mkdir"; "/new"];
1295        ["is_dir"; "/new"]];
1296     InitBasicFS, Always, TestLastFail
1297       [["mkdir"; "/new/foo/bar"]]],
1298    "create a directory",
1299    "\
1300 Create a directory named C<path>.");
1301
1302   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1303    [InitBasicFS, Always, TestOutputTrue
1304       [["mkdir_p"; "/new/foo/bar"];
1305        ["is_dir"; "/new/foo/bar"]];
1306     InitBasicFS, Always, TestOutputTrue
1307       [["mkdir_p"; "/new/foo/bar"];
1308        ["is_dir"; "/new/foo"]];
1309     InitBasicFS, Always, TestOutputTrue
1310       [["mkdir_p"; "/new/foo/bar"];
1311        ["is_dir"; "/new"]];
1312     (* Regression tests for RHBZ#503133: *)
1313     InitBasicFS, Always, TestRun
1314       [["mkdir"; "/new"];
1315        ["mkdir_p"; "/new"]];
1316     InitBasicFS, Always, TestLastFail
1317       [["touch"; "/new"];
1318        ["mkdir_p"; "/new"]]],
1319    "create a directory and parents",
1320    "\
1321 Create a directory named C<path>, creating any parent directories
1322 as necessary.  This is like the C<mkdir -p> shell command.");
1323
1324   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1325    [], (* XXX Need stat command to test *)
1326    "change file mode",
1327    "\
1328 Change the mode (permissions) of C<path> to C<mode>.  Only
1329 numeric modes are supported.");
1330
1331   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1332    [], (* XXX Need stat command to test *)
1333    "change file owner and group",
1334    "\
1335 Change the file owner to C<owner> and group to C<group>.
1336
1337 Only numeric uid and gid are supported.  If you want to use
1338 names, you will need to locate and parse the password file
1339 yourself (Augeas support makes this relatively easy).");
1340
1341   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1342    [InitISOFS, Always, TestOutputTrue (
1343       [["exists"; "/empty"]]);
1344     InitISOFS, Always, TestOutputTrue (
1345       [["exists"; "/directory"]])],
1346    "test if file or directory exists",
1347    "\
1348 This returns C<true> if and only if there is a file, directory
1349 (or anything) with the given C<path> name.
1350
1351 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1352
1353   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1354    [InitISOFS, Always, TestOutputTrue (
1355       [["is_file"; "/known-1"]]);
1356     InitISOFS, Always, TestOutputFalse (
1357       [["is_file"; "/directory"]])],
1358    "test if file exists",
1359    "\
1360 This returns C<true> if and only if there is a file
1361 with the given C<path> name.  Note that it returns false for
1362 other objects like directories.
1363
1364 See also C<guestfs_stat>.");
1365
1366   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1367    [InitISOFS, Always, TestOutputFalse (
1368       [["is_dir"; "/known-3"]]);
1369     InitISOFS, Always, TestOutputTrue (
1370       [["is_dir"; "/directory"]])],
1371    "test if file exists",
1372    "\
1373 This returns C<true> if and only if there is a directory
1374 with the given C<path> name.  Note that it returns false for
1375 other objects like files.
1376
1377 See also C<guestfs_stat>.");
1378
1379   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1380    [InitEmpty, Always, TestOutputListOfDevices (
1381       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1382        ["pvcreate"; "/dev/sda1"];
1383        ["pvcreate"; "/dev/sda2"];
1384        ["pvcreate"; "/dev/sda3"];
1385        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1386    "create an LVM physical volume",
1387    "\
1388 This creates an LVM physical volume on the named C<device>,
1389 where C<device> should usually be a partition name such
1390 as C</dev/sda1>.");
1391
1392   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1393    [InitEmpty, Always, TestOutputList (
1394       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1395        ["pvcreate"; "/dev/sda1"];
1396        ["pvcreate"; "/dev/sda2"];
1397        ["pvcreate"; "/dev/sda3"];
1398        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1399        ["vgcreate"; "VG2"; "/dev/sda3"];
1400        ["vgs"]], ["VG1"; "VG2"])],
1401    "create an LVM volume group",
1402    "\
1403 This creates an LVM volume group called C<volgroup>
1404 from the non-empty list of physical volumes C<physvols>.");
1405
1406   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1407    [InitEmpty, Always, TestOutputList (
1408       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1409        ["pvcreate"; "/dev/sda1"];
1410        ["pvcreate"; "/dev/sda2"];
1411        ["pvcreate"; "/dev/sda3"];
1412        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1413        ["vgcreate"; "VG2"; "/dev/sda3"];
1414        ["lvcreate"; "LV1"; "VG1"; "50"];
1415        ["lvcreate"; "LV2"; "VG1"; "50"];
1416        ["lvcreate"; "LV3"; "VG2"; "50"];
1417        ["lvcreate"; "LV4"; "VG2"; "50"];
1418        ["lvcreate"; "LV5"; "VG2"; "50"];
1419        ["lvs"]],
1420       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1421        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1422    "create an LVM volume group",
1423    "\
1424 This creates an LVM volume group called C<logvol>
1425 on the volume group C<volgroup>, with C<size> megabytes.");
1426
1427   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1428    [InitEmpty, Always, TestOutput (
1429       [["part_disk"; "/dev/sda"; "mbr"];
1430        ["mkfs"; "ext2"; "/dev/sda1"];
1431        ["mount"; "/dev/sda1"; "/"];
1432        ["write_file"; "/new"; "new file contents"; "0"];
1433        ["cat"; "/new"]], "new file contents")],
1434    "make a filesystem",
1435    "\
1436 This creates a filesystem on C<device> (usually a partition
1437 or LVM logical volume).  The filesystem type is C<fstype>, for
1438 example C<ext3>.");
1439
1440   ("sfdisk", (RErr, [Device "device";
1441                      Int "cyls"; Int "heads"; Int "sectors";
1442                      StringList "lines"]), 43, [DangerWillRobinson],
1443    [],
1444    "create partitions on a block device",
1445    "\
1446 This is a direct interface to the L<sfdisk(8)> program for creating
1447 partitions on block devices.
1448
1449 C<device> should be a block device, for example C</dev/sda>.
1450
1451 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1452 and sectors on the device, which are passed directly to sfdisk as
1453 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1454 of these, then the corresponding parameter is omitted.  Usually for
1455 'large' disks, you can just pass C<0> for these, but for small
1456 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1457 out the right geometry and you will need to tell it.
1458
1459 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1460 information refer to the L<sfdisk(8)> manpage.
1461
1462 To create a single partition occupying the whole disk, you would
1463 pass C<lines> as a single element list, when the single element being
1464 the string C<,> (comma).
1465
1466 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1467 C<guestfs_part_init>");
1468
1469   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1470    [InitBasicFS, Always, TestOutput (
1471       [["write_file"; "/new"; "new file contents"; "0"];
1472        ["cat"; "/new"]], "new file contents");
1473     InitBasicFS, Always, TestOutput (
1474       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1475        ["cat"; "/new"]], "\nnew file contents\n");
1476     InitBasicFS, Always, TestOutput (
1477       [["write_file"; "/new"; "\n\n"; "0"];
1478        ["cat"; "/new"]], "\n\n");
1479     InitBasicFS, Always, TestOutput (
1480       [["write_file"; "/new"; ""; "0"];
1481        ["cat"; "/new"]], "");
1482     InitBasicFS, Always, TestOutput (
1483       [["write_file"; "/new"; "\n\n\n"; "0"];
1484        ["cat"; "/new"]], "\n\n\n");
1485     InitBasicFS, Always, TestOutput (
1486       [["write_file"; "/new"; "\n"; "0"];
1487        ["cat"; "/new"]], "\n")],
1488    "create a file",
1489    "\
1490 This call creates a file called C<path>.  The contents of the
1491 file is the string C<content> (which can contain any 8 bit data),
1492 with length C<size>.
1493
1494 As a special case, if C<size> is C<0>
1495 then the length is calculated using C<strlen> (so in this case
1496 the content cannot contain embedded ASCII NULs).
1497
1498 I<NB.> Owing to a bug, writing content containing ASCII NUL
1499 characters does I<not> work, even if the length is specified.
1500 We hope to resolve this bug in a future version.  In the meantime
1501 use C<guestfs_upload>.");
1502
1503   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1504    [InitEmpty, Always, TestOutputListOfDevices (
1505       [["part_disk"; "/dev/sda"; "mbr"];
1506        ["mkfs"; "ext2"; "/dev/sda1"];
1507        ["mount"; "/dev/sda1"; "/"];
1508        ["mounts"]], ["/dev/sda1"]);
1509     InitEmpty, Always, TestOutputList (
1510       [["part_disk"; "/dev/sda"; "mbr"];
1511        ["mkfs"; "ext2"; "/dev/sda1"];
1512        ["mount"; "/dev/sda1"; "/"];
1513        ["umount"; "/"];
1514        ["mounts"]], [])],
1515    "unmount a filesystem",
1516    "\
1517 This unmounts the given filesystem.  The filesystem may be
1518 specified either by its mountpoint (path) or the device which
1519 contains the filesystem.");
1520
1521   ("mounts", (RStringList "devices", []), 46, [],
1522    [InitBasicFS, Always, TestOutputListOfDevices (
1523       [["mounts"]], ["/dev/sda1"])],
1524    "show mounted filesystems",
1525    "\
1526 This returns the list of currently mounted filesystems.  It returns
1527 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1528
1529 Some internal mounts are not shown.
1530
1531 See also: C<guestfs_mountpoints>");
1532
1533   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1534    [InitBasicFS, Always, TestOutputList (
1535       [["umount_all"];
1536        ["mounts"]], []);
1537     (* check that umount_all can unmount nested mounts correctly: *)
1538     InitEmpty, Always, TestOutputList (
1539       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1540        ["mkfs"; "ext2"; "/dev/sda1"];
1541        ["mkfs"; "ext2"; "/dev/sda2"];
1542        ["mkfs"; "ext2"; "/dev/sda3"];
1543        ["mount"; "/dev/sda1"; "/"];
1544        ["mkdir"; "/mp1"];
1545        ["mount"; "/dev/sda2"; "/mp1"];
1546        ["mkdir"; "/mp1/mp2"];
1547        ["mount"; "/dev/sda3"; "/mp1/mp2"];
1548        ["mkdir"; "/mp1/mp2/mp3"];
1549        ["umount_all"];
1550        ["mounts"]], [])],
1551    "unmount all filesystems",
1552    "\
1553 This unmounts all mounted filesystems.
1554
1555 Some internal mounts are not unmounted by this call.");
1556
1557   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1558    [],
1559    "remove all LVM LVs, VGs and PVs",
1560    "\
1561 This command removes all LVM logical volumes, volume groups
1562 and physical volumes.");
1563
1564   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1565    [InitISOFS, Always, TestOutput (
1566       [["file"; "/empty"]], "empty");
1567     InitISOFS, Always, TestOutput (
1568       [["file"; "/known-1"]], "ASCII text");
1569     InitISOFS, Always, TestLastFail (
1570       [["file"; "/notexists"]])],
1571    "determine file type",
1572    "\
1573 This call uses the standard L<file(1)> command to determine
1574 the type or contents of the file.  This also works on devices,
1575 for example to find out whether a partition contains a filesystem.
1576
1577 This call will also transparently look inside various types
1578 of compressed file.
1579
1580 The exact command which runs is C<file -zbsL path>.  Note in
1581 particular that the filename is not prepended to the output
1582 (the C<-b> option).");
1583
1584   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1585    [InitBasicFS, Always, TestOutput (
1586       [["upload"; "test-command"; "/test-command"];
1587        ["chmod"; "0o755"; "/test-command"];
1588        ["command"; "/test-command 1"]], "Result1");
1589     InitBasicFS, Always, TestOutput (
1590       [["upload"; "test-command"; "/test-command"];
1591        ["chmod"; "0o755"; "/test-command"];
1592        ["command"; "/test-command 2"]], "Result2\n");
1593     InitBasicFS, Always, TestOutput (
1594       [["upload"; "test-command"; "/test-command"];
1595        ["chmod"; "0o755"; "/test-command"];
1596        ["command"; "/test-command 3"]], "\nResult3");
1597     InitBasicFS, Always, TestOutput (
1598       [["upload"; "test-command"; "/test-command"];
1599        ["chmod"; "0o755"; "/test-command"];
1600        ["command"; "/test-command 4"]], "\nResult4\n");
1601     InitBasicFS, Always, TestOutput (
1602       [["upload"; "test-command"; "/test-command"];
1603        ["chmod"; "0o755"; "/test-command"];
1604        ["command"; "/test-command 5"]], "\nResult5\n\n");
1605     InitBasicFS, Always, TestOutput (
1606       [["upload"; "test-command"; "/test-command"];
1607        ["chmod"; "0o755"; "/test-command"];
1608        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1609     InitBasicFS, Always, TestOutput (
1610       [["upload"; "test-command"; "/test-command"];
1611        ["chmod"; "0o755"; "/test-command"];
1612        ["command"; "/test-command 7"]], "");
1613     InitBasicFS, Always, TestOutput (
1614       [["upload"; "test-command"; "/test-command"];
1615        ["chmod"; "0o755"; "/test-command"];
1616        ["command"; "/test-command 8"]], "\n");
1617     InitBasicFS, Always, TestOutput (
1618       [["upload"; "test-command"; "/test-command"];
1619        ["chmod"; "0o755"; "/test-command"];
1620        ["command"; "/test-command 9"]], "\n\n");
1621     InitBasicFS, Always, TestOutput (
1622       [["upload"; "test-command"; "/test-command"];
1623        ["chmod"; "0o755"; "/test-command"];
1624        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1625     InitBasicFS, Always, TestOutput (
1626       [["upload"; "test-command"; "/test-command"];
1627        ["chmod"; "0o755"; "/test-command"];
1628        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1629     InitBasicFS, Always, TestLastFail (
1630       [["upload"; "test-command"; "/test-command"];
1631        ["chmod"; "0o755"; "/test-command"];
1632        ["command"; "/test-command"]])],
1633    "run a command from the guest filesystem",
1634    "\
1635 This call runs a command from the guest filesystem.  The
1636 filesystem must be mounted, and must contain a compatible
1637 operating system (ie. something Linux, with the same
1638 or compatible processor architecture).
1639
1640 The single parameter is an argv-style list of arguments.
1641 The first element is the name of the program to run.
1642 Subsequent elements are parameters.  The list must be
1643 non-empty (ie. must contain a program name).  Note that
1644 the command runs directly, and is I<not> invoked via
1645 the shell (see C<guestfs_sh>).
1646
1647 The return value is anything printed to I<stdout> by
1648 the command.
1649
1650 If the command returns a non-zero exit status, then
1651 this function returns an error message.  The error message
1652 string is the content of I<stderr> from the command.
1653
1654 The C<$PATH> environment variable will contain at least
1655 C</usr/bin> and C</bin>.  If you require a program from
1656 another location, you should provide the full path in the
1657 first parameter.
1658
1659 Shared libraries and data files required by the program
1660 must be available on filesystems which are mounted in the
1661 correct places.  It is the caller's responsibility to ensure
1662 all filesystems that are needed are mounted at the right
1663 locations.");
1664
1665   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1666    [InitBasicFS, Always, TestOutputList (
1667       [["upload"; "test-command"; "/test-command"];
1668        ["chmod"; "0o755"; "/test-command"];
1669        ["command_lines"; "/test-command 1"]], ["Result1"]);
1670     InitBasicFS, Always, TestOutputList (
1671       [["upload"; "test-command"; "/test-command"];
1672        ["chmod"; "0o755"; "/test-command"];
1673        ["command_lines"; "/test-command 2"]], ["Result2"]);
1674     InitBasicFS, Always, TestOutputList (
1675       [["upload"; "test-command"; "/test-command"];
1676        ["chmod"; "0o755"; "/test-command"];
1677        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1678     InitBasicFS, Always, TestOutputList (
1679       [["upload"; "test-command"; "/test-command"];
1680        ["chmod"; "0o755"; "/test-command"];
1681        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1682     InitBasicFS, Always, TestOutputList (
1683       [["upload"; "test-command"; "/test-command"];
1684        ["chmod"; "0o755"; "/test-command"];
1685        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1686     InitBasicFS, Always, TestOutputList (
1687       [["upload"; "test-command"; "/test-command"];
1688        ["chmod"; "0o755"; "/test-command"];
1689        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1690     InitBasicFS, Always, TestOutputList (
1691       [["upload"; "test-command"; "/test-command"];
1692        ["chmod"; "0o755"; "/test-command"];
1693        ["command_lines"; "/test-command 7"]], []);
1694     InitBasicFS, Always, TestOutputList (
1695       [["upload"; "test-command"; "/test-command"];
1696        ["chmod"; "0o755"; "/test-command"];
1697        ["command_lines"; "/test-command 8"]], [""]);
1698     InitBasicFS, Always, TestOutputList (
1699       [["upload"; "test-command"; "/test-command"];
1700        ["chmod"; "0o755"; "/test-command"];
1701        ["command_lines"; "/test-command 9"]], ["";""]);
1702     InitBasicFS, Always, TestOutputList (
1703       [["upload"; "test-command"; "/test-command"];
1704        ["chmod"; "0o755"; "/test-command"];
1705        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1706     InitBasicFS, Always, TestOutputList (
1707       [["upload"; "test-command"; "/test-command"];
1708        ["chmod"; "0o755"; "/test-command"];
1709        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1710    "run a command, returning lines",
1711    "\
1712 This is the same as C<guestfs_command>, but splits the
1713 result into a list of lines.
1714
1715 See also: C<guestfs_sh_lines>");
1716
1717   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1718    [InitISOFS, Always, TestOutputStruct (
1719       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1720    "get file information",
1721    "\
1722 Returns file information for the given C<path>.
1723
1724 This is the same as the C<stat(2)> system call.");
1725
1726   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1727    [InitISOFS, Always, TestOutputStruct (
1728       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1729    "get file information for a symbolic link",
1730    "\
1731 Returns file information for the given C<path>.
1732
1733 This is the same as C<guestfs_stat> except that if C<path>
1734 is a symbolic link, then the link is stat-ed, not the file it
1735 refers to.
1736
1737 This is the same as the C<lstat(2)> system call.");
1738
1739   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1740    [InitISOFS, Always, TestOutputStruct (
1741       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1742    "get file system statistics",
1743    "\
1744 Returns file system statistics for any mounted file system.
1745 C<path> should be a file or directory in the mounted file system
1746 (typically it is the mount point itself, but it doesn't need to be).
1747
1748 This is the same as the C<statvfs(2)> system call.");
1749
1750   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1751    [], (* XXX test *)
1752    "get ext2/ext3/ext4 superblock details",
1753    "\
1754 This returns the contents of the ext2, ext3 or ext4 filesystem
1755 superblock on C<device>.
1756
1757 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1758 manpage for more details.  The list of fields returned isn't
1759 clearly defined, and depends on both the version of C<tune2fs>
1760 that libguestfs was built against, and the filesystem itself.");
1761
1762   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1763    [InitEmpty, Always, TestOutputTrue (
1764       [["blockdev_setro"; "/dev/sda"];
1765        ["blockdev_getro"; "/dev/sda"]])],
1766    "set block device to read-only",
1767    "\
1768 Sets the block device named C<device> to read-only.
1769
1770 This uses the L<blockdev(8)> command.");
1771
1772   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1773    [InitEmpty, Always, TestOutputFalse (
1774       [["blockdev_setrw"; "/dev/sda"];
1775        ["blockdev_getro"; "/dev/sda"]])],
1776    "set block device to read-write",
1777    "\
1778 Sets the block device named C<device> to read-write.
1779
1780 This uses the L<blockdev(8)> command.");
1781
1782   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1783    [InitEmpty, Always, TestOutputTrue (
1784       [["blockdev_setro"; "/dev/sda"];
1785        ["blockdev_getro"; "/dev/sda"]])],
1786    "is block device set to read-only",
1787    "\
1788 Returns a boolean indicating if the block device is read-only
1789 (true if read-only, false if not).
1790
1791 This uses the L<blockdev(8)> command.");
1792
1793   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1794    [InitEmpty, Always, TestOutputInt (
1795       [["blockdev_getss"; "/dev/sda"]], 512)],
1796    "get sectorsize of block device",
1797    "\
1798 This returns the size of sectors on a block device.
1799 Usually 512, but can be larger for modern devices.
1800
1801 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1802 for that).
1803
1804 This uses the L<blockdev(8)> command.");
1805
1806   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1807    [InitEmpty, Always, TestOutputInt (
1808       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1809    "get blocksize of block device",
1810    "\
1811 This returns the block size of a device.
1812
1813 (Note this is different from both I<size in blocks> and
1814 I<filesystem block size>).
1815
1816 This uses the L<blockdev(8)> command.");
1817
1818   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1819    [], (* XXX test *)
1820    "set blocksize of block device",
1821    "\
1822 This sets the block size of a device.
1823
1824 (Note this is different from both I<size in blocks> and
1825 I<filesystem block size>).
1826
1827 This uses the L<blockdev(8)> command.");
1828
1829   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1830    [InitEmpty, Always, TestOutputInt (
1831       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1832    "get total size of device in 512-byte sectors",
1833    "\
1834 This returns the size of the device in units of 512-byte sectors
1835 (even if the sectorsize isn't 512 bytes ... weird).
1836
1837 See also C<guestfs_blockdev_getss> for the real sector size of
1838 the device, and C<guestfs_blockdev_getsize64> for the more
1839 useful I<size in bytes>.
1840
1841 This uses the L<blockdev(8)> command.");
1842
1843   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1844    [InitEmpty, Always, TestOutputInt (
1845       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1846    "get total size of device in bytes",
1847    "\
1848 This returns the size of the device in bytes.
1849
1850 See also C<guestfs_blockdev_getsz>.
1851
1852 This uses the L<blockdev(8)> command.");
1853
1854   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1855    [InitEmpty, Always, TestRun
1856       [["blockdev_flushbufs"; "/dev/sda"]]],
1857    "flush device buffers",
1858    "\
1859 This tells the kernel to flush internal buffers associated
1860 with C<device>.
1861
1862 This uses the L<blockdev(8)> command.");
1863
1864   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1865    [InitEmpty, Always, TestRun
1866       [["blockdev_rereadpt"; "/dev/sda"]]],
1867    "reread partition table",
1868    "\
1869 Reread the partition table on C<device>.
1870
1871 This uses the L<blockdev(8)> command.");
1872
1873   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1874    [InitBasicFS, Always, TestOutput (
1875       (* Pick a file from cwd which isn't likely to change. *)
1876       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1877        ["checksum"; "md5"; "/COPYING.LIB"]],
1878       Digest.to_hex (Digest.file "COPYING.LIB"))],
1879    "upload a file from the local machine",
1880    "\
1881 Upload local file C<filename> to C<remotefilename> on the
1882 filesystem.
1883
1884 C<filename> can also be a named pipe.
1885
1886 See also C<guestfs_download>.");
1887
1888   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1889    [InitBasicFS, Always, TestOutput (
1890       (* Pick a file from cwd which isn't likely to change. *)
1891       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1892        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1893        ["upload"; "testdownload.tmp"; "/upload"];
1894        ["checksum"; "md5"; "/upload"]],
1895       Digest.to_hex (Digest.file "COPYING.LIB"))],
1896    "download a file to the local machine",
1897    "\
1898 Download file C<remotefilename> and save it as C<filename>
1899 on the local machine.
1900
1901 C<filename> can also be a named pipe.
1902
1903 See also C<guestfs_upload>, C<guestfs_cat>.");
1904
1905   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1906    [InitISOFS, Always, TestOutput (
1907       [["checksum"; "crc"; "/known-3"]], "2891671662");
1908     InitISOFS, Always, TestLastFail (
1909       [["checksum"; "crc"; "/notexists"]]);
1910     InitISOFS, Always, TestOutput (
1911       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1912     InitISOFS, Always, TestOutput (
1913       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1914     InitISOFS, Always, TestOutput (
1915       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1916     InitISOFS, Always, TestOutput (
1917       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1918     InitISOFS, Always, TestOutput (
1919       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1920     InitISOFS, Always, TestOutput (
1921       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1922    "compute MD5, SHAx or CRC checksum of file",
1923    "\
1924 This call computes the MD5, SHAx or CRC checksum of the
1925 file named C<path>.
1926
1927 The type of checksum to compute is given by the C<csumtype>
1928 parameter which must have one of the following values:
1929
1930 =over 4
1931
1932 =item C<crc>
1933
1934 Compute the cyclic redundancy check (CRC) specified by POSIX
1935 for the C<cksum> command.
1936
1937 =item C<md5>
1938
1939 Compute the MD5 hash (using the C<md5sum> program).
1940
1941 =item C<sha1>
1942
1943 Compute the SHA1 hash (using the C<sha1sum> program).
1944
1945 =item C<sha224>
1946
1947 Compute the SHA224 hash (using the C<sha224sum> program).
1948
1949 =item C<sha256>
1950
1951 Compute the SHA256 hash (using the C<sha256sum> program).
1952
1953 =item C<sha384>
1954
1955 Compute the SHA384 hash (using the C<sha384sum> program).
1956
1957 =item C<sha512>
1958
1959 Compute the SHA512 hash (using the C<sha512sum> program).
1960
1961 =back
1962
1963 The checksum is returned as a printable string.");
1964
1965   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1966    [InitBasicFS, Always, TestOutput (
1967       [["tar_in"; "../images/helloworld.tar"; "/"];
1968        ["cat"; "/hello"]], "hello\n")],
1969    "unpack tarfile to directory",
1970    "\
1971 This command uploads and unpacks local file C<tarfile> (an
1972 I<uncompressed> tar file) into C<directory>.
1973
1974 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1975
1976   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1977    [],
1978    "pack directory into tarfile",
1979    "\
1980 This command packs the contents of C<directory> and downloads
1981 it to local file C<tarfile>.
1982
1983 To download a compressed tarball, use C<guestfs_tgz_out>.");
1984
1985   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1986    [InitBasicFS, Always, TestOutput (
1987       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1988        ["cat"; "/hello"]], "hello\n")],
1989    "unpack compressed tarball to directory",
1990    "\
1991 This command uploads and unpacks local file C<tarball> (a
1992 I<gzip compressed> tar file) into C<directory>.
1993
1994 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1995
1996   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
1997    [],
1998    "pack directory into compressed tarball",
1999    "\
2000 This command packs the contents of C<directory> and downloads
2001 it to local file C<tarball>.
2002
2003 To download an uncompressed tarball, use C<guestfs_tar_out>.");
2004
2005   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
2006    [InitBasicFS, Always, TestLastFail (
2007       [["umount"; "/"];
2008        ["mount_ro"; "/dev/sda1"; "/"];
2009        ["touch"; "/new"]]);
2010     InitBasicFS, Always, TestOutput (
2011       [["write_file"; "/new"; "data"; "0"];
2012        ["umount"; "/"];
2013        ["mount_ro"; "/dev/sda1"; "/"];
2014        ["cat"; "/new"]], "data")],
2015    "mount a guest disk, read-only",
2016    "\
2017 This is the same as the C<guestfs_mount> command, but it
2018 mounts the filesystem with the read-only (I<-o ro>) flag.");
2019
2020   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
2021    [],
2022    "mount a guest disk with mount options",
2023    "\
2024 This is the same as the C<guestfs_mount> command, but it
2025 allows you to set the mount options as for the
2026 L<mount(8)> I<-o> flag.");
2027
2028   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2029    [],
2030    "mount a guest disk with mount options and vfstype",
2031    "\
2032 This is the same as the C<guestfs_mount> command, but it
2033 allows you to set both the mount options and the vfstype
2034 as for the L<mount(8)> I<-o> and I<-t> flags.");
2035
2036   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2037    [],
2038    "debugging and internals",
2039    "\
2040 The C<guestfs_debug> command exposes some internals of
2041 C<guestfsd> (the guestfs daemon) that runs inside the
2042 qemu subprocess.
2043
2044 There is no comprehensive help for this command.  You have
2045 to look at the file C<daemon/debug.c> in the libguestfs source
2046 to find out what you can do.");
2047
2048   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2049    [InitEmpty, Always, TestOutputList (
2050       [["part_disk"; "/dev/sda"; "mbr"];
2051        ["pvcreate"; "/dev/sda1"];
2052        ["vgcreate"; "VG"; "/dev/sda1"];
2053        ["lvcreate"; "LV1"; "VG"; "50"];
2054        ["lvcreate"; "LV2"; "VG"; "50"];
2055        ["lvremove"; "/dev/VG/LV1"];
2056        ["lvs"]], ["/dev/VG/LV2"]);
2057     InitEmpty, Always, TestOutputList (
2058       [["part_disk"; "/dev/sda"; "mbr"];
2059        ["pvcreate"; "/dev/sda1"];
2060        ["vgcreate"; "VG"; "/dev/sda1"];
2061        ["lvcreate"; "LV1"; "VG"; "50"];
2062        ["lvcreate"; "LV2"; "VG"; "50"];
2063        ["lvremove"; "/dev/VG"];
2064        ["lvs"]], []);
2065     InitEmpty, Always, TestOutputList (
2066       [["part_disk"; "/dev/sda"; "mbr"];
2067        ["pvcreate"; "/dev/sda1"];
2068        ["vgcreate"; "VG"; "/dev/sda1"];
2069        ["lvcreate"; "LV1"; "VG"; "50"];
2070        ["lvcreate"; "LV2"; "VG"; "50"];
2071        ["lvremove"; "/dev/VG"];
2072        ["vgs"]], ["VG"])],
2073    "remove an LVM logical volume",
2074    "\
2075 Remove an LVM logical volume C<device>, where C<device> is
2076 the path to the LV, such as C</dev/VG/LV>.
2077
2078 You can also remove all LVs in a volume group by specifying
2079 the VG name, C</dev/VG>.");
2080
2081   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2082    [InitEmpty, Always, TestOutputList (
2083       [["part_disk"; "/dev/sda"; "mbr"];
2084        ["pvcreate"; "/dev/sda1"];
2085        ["vgcreate"; "VG"; "/dev/sda1"];
2086        ["lvcreate"; "LV1"; "VG"; "50"];
2087        ["lvcreate"; "LV2"; "VG"; "50"];
2088        ["vgremove"; "VG"];
2089        ["lvs"]], []);
2090     InitEmpty, Always, TestOutputList (
2091       [["part_disk"; "/dev/sda"; "mbr"];
2092        ["pvcreate"; "/dev/sda1"];
2093        ["vgcreate"; "VG"; "/dev/sda1"];
2094        ["lvcreate"; "LV1"; "VG"; "50"];
2095        ["lvcreate"; "LV2"; "VG"; "50"];
2096        ["vgremove"; "VG"];
2097        ["vgs"]], [])],
2098    "remove an LVM volume group",
2099    "\
2100 Remove an LVM volume group C<vgname>, (for example C<VG>).
2101
2102 This also forcibly removes all logical volumes in the volume
2103 group (if any).");
2104
2105   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2106    [InitEmpty, Always, TestOutputListOfDevices (
2107       [["part_disk"; "/dev/sda"; "mbr"];
2108        ["pvcreate"; "/dev/sda1"];
2109        ["vgcreate"; "VG"; "/dev/sda1"];
2110        ["lvcreate"; "LV1"; "VG"; "50"];
2111        ["lvcreate"; "LV2"; "VG"; "50"];
2112        ["vgremove"; "VG"];
2113        ["pvremove"; "/dev/sda1"];
2114        ["lvs"]], []);
2115     InitEmpty, Always, TestOutputListOfDevices (
2116       [["part_disk"; "/dev/sda"; "mbr"];
2117        ["pvcreate"; "/dev/sda1"];
2118        ["vgcreate"; "VG"; "/dev/sda1"];
2119        ["lvcreate"; "LV1"; "VG"; "50"];
2120        ["lvcreate"; "LV2"; "VG"; "50"];
2121        ["vgremove"; "VG"];
2122        ["pvremove"; "/dev/sda1"];
2123        ["vgs"]], []);
2124     InitEmpty, Always, TestOutputListOfDevices (
2125       [["part_disk"; "/dev/sda"; "mbr"];
2126        ["pvcreate"; "/dev/sda1"];
2127        ["vgcreate"; "VG"; "/dev/sda1"];
2128        ["lvcreate"; "LV1"; "VG"; "50"];
2129        ["lvcreate"; "LV2"; "VG"; "50"];
2130        ["vgremove"; "VG"];
2131        ["pvremove"; "/dev/sda1"];
2132        ["pvs"]], [])],
2133    "remove an LVM physical volume",
2134    "\
2135 This wipes a physical volume C<device> so that LVM will no longer
2136 recognise it.
2137
2138 The implementation uses the C<pvremove> command which refuses to
2139 wipe physical volumes that contain any volume groups, so you have
2140 to remove those first.");
2141
2142   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2143    [InitBasicFS, Always, TestOutput (
2144       [["set_e2label"; "/dev/sda1"; "testlabel"];
2145        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2146    "set the ext2/3/4 filesystem label",
2147    "\
2148 This sets the ext2/3/4 filesystem label of the filesystem on
2149 C<device> to C<label>.  Filesystem labels are limited to
2150 16 characters.
2151
2152 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2153 to return the existing label on a filesystem.");
2154
2155   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2156    [],
2157    "get the ext2/3/4 filesystem label",
2158    "\
2159 This returns the ext2/3/4 filesystem label of the filesystem on
2160 C<device>.");
2161
2162   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2163    (let uuid = uuidgen () in
2164     [InitBasicFS, Always, TestOutput (
2165        [["set_e2uuid"; "/dev/sda1"; uuid];
2166         ["get_e2uuid"; "/dev/sda1"]], uuid);
2167      InitBasicFS, Always, TestOutput (
2168        [["set_e2uuid"; "/dev/sda1"; "clear"];
2169         ["get_e2uuid"; "/dev/sda1"]], "");
2170      (* We can't predict what UUIDs will be, so just check the commands run. *)
2171      InitBasicFS, Always, TestRun (
2172        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2173      InitBasicFS, Always, TestRun (
2174        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2175    "set the ext2/3/4 filesystem UUID",
2176    "\
2177 This sets the ext2/3/4 filesystem UUID of the filesystem on
2178 C<device> to C<uuid>.  The format of the UUID and alternatives
2179 such as C<clear>, C<random> and C<time> are described in the
2180 L<tune2fs(8)> manpage.
2181
2182 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2183 to return the existing UUID of a filesystem.");
2184
2185   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2186    [],
2187    "get the ext2/3/4 filesystem UUID",
2188    "\
2189 This returns the ext2/3/4 filesystem UUID of the filesystem on
2190 C<device>.");
2191
2192   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [],
2193    [InitBasicFS, Always, TestOutputInt (
2194       [["umount"; "/dev/sda1"];
2195        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2196     InitBasicFS, Always, TestOutputInt (
2197       [["umount"; "/dev/sda1"];
2198        ["zero"; "/dev/sda1"];
2199        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2200    "run the filesystem checker",
2201    "\
2202 This runs the filesystem checker (fsck) on C<device> which
2203 should have filesystem type C<fstype>.
2204
2205 The returned integer is the status.  See L<fsck(8)> for the
2206 list of status codes from C<fsck>.
2207
2208 Notes:
2209
2210 =over 4
2211
2212 =item *
2213
2214 Multiple status codes can be summed together.
2215
2216 =item *
2217
2218 A non-zero return code can mean \"success\", for example if
2219 errors have been corrected on the filesystem.
2220
2221 =item *
2222
2223 Checking or repairing NTFS volumes is not supported
2224 (by linux-ntfs).
2225
2226 =back
2227
2228 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2229
2230   ("zero", (RErr, [Device "device"]), 85, [],
2231    [InitBasicFS, Always, TestOutput (
2232       [["umount"; "/dev/sda1"];
2233        ["zero"; "/dev/sda1"];
2234        ["file"; "/dev/sda1"]], "data")],
2235    "write zeroes to the device",
2236    "\
2237 This command writes zeroes over the first few blocks of C<device>.
2238
2239 How many blocks are zeroed isn't specified (but it's I<not> enough
2240 to securely wipe the device).  It should be sufficient to remove
2241 any partition tables, filesystem superblocks and so on.
2242
2243 See also: C<guestfs_scrub_device>.");
2244
2245   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2246    (* Test disabled because grub-install incompatible with virtio-blk driver.
2247     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2248     *)
2249    [InitBasicFS, Disabled, TestOutputTrue (
2250       [["grub_install"; "/"; "/dev/sda1"];
2251        ["is_dir"; "/boot"]])],
2252    "install GRUB",
2253    "\
2254 This command installs GRUB (the Grand Unified Bootloader) on
2255 C<device>, with the root directory being C<root>.");
2256
2257   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2258    [InitBasicFS, Always, TestOutput (
2259       [["write_file"; "/old"; "file content"; "0"];
2260        ["cp"; "/old"; "/new"];
2261        ["cat"; "/new"]], "file content");
2262     InitBasicFS, Always, TestOutputTrue (
2263       [["write_file"; "/old"; "file content"; "0"];
2264        ["cp"; "/old"; "/new"];
2265        ["is_file"; "/old"]]);
2266     InitBasicFS, Always, TestOutput (
2267       [["write_file"; "/old"; "file content"; "0"];
2268        ["mkdir"; "/dir"];
2269        ["cp"; "/old"; "/dir/new"];
2270        ["cat"; "/dir/new"]], "file content")],
2271    "copy a file",
2272    "\
2273 This copies a file from C<src> to C<dest> where C<dest> is
2274 either a destination filename or destination directory.");
2275
2276   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2277    [InitBasicFS, Always, TestOutput (
2278       [["mkdir"; "/olddir"];
2279        ["mkdir"; "/newdir"];
2280        ["write_file"; "/olddir/file"; "file content"; "0"];
2281        ["cp_a"; "/olddir"; "/newdir"];
2282        ["cat"; "/newdir/olddir/file"]], "file content")],
2283    "copy a file or directory recursively",
2284    "\
2285 This copies a file or directory from C<src> to C<dest>
2286 recursively using the C<cp -a> command.");
2287
2288   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2289    [InitBasicFS, Always, TestOutput (
2290       [["write_file"; "/old"; "file content"; "0"];
2291        ["mv"; "/old"; "/new"];
2292        ["cat"; "/new"]], "file content");
2293     InitBasicFS, Always, TestOutputFalse (
2294       [["write_file"; "/old"; "file content"; "0"];
2295        ["mv"; "/old"; "/new"];
2296        ["is_file"; "/old"]])],
2297    "move a file",
2298    "\
2299 This moves a file from C<src> to C<dest> where C<dest> is
2300 either a destination filename or destination directory.");
2301
2302   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2303    [InitEmpty, Always, TestRun (
2304       [["drop_caches"; "3"]])],
2305    "drop kernel page cache, dentries and inodes",
2306    "\
2307 This instructs the guest kernel to drop its page cache,
2308 and/or dentries and inode caches.  The parameter C<whattodrop>
2309 tells the kernel what precisely to drop, see
2310 L<http://linux-mm.org/Drop_Caches>
2311
2312 Setting C<whattodrop> to 3 should drop everything.
2313
2314 This automatically calls L<sync(2)> before the operation,
2315 so that the maximum guest memory is freed.");
2316
2317   ("dmesg", (RString "kmsgs", []), 91, [],
2318    [InitEmpty, Always, TestRun (
2319       [["dmesg"]])],
2320    "return kernel messages",
2321    "\
2322 This returns the kernel messages (C<dmesg> output) from
2323 the guest kernel.  This is sometimes useful for extended
2324 debugging of problems.
2325
2326 Another way to get the same information is to enable
2327 verbose messages with C<guestfs_set_verbose> or by setting
2328 the environment variable C<LIBGUESTFS_DEBUG=1> before
2329 running the program.");
2330
2331   ("ping_daemon", (RErr, []), 92, [],
2332    [InitEmpty, Always, TestRun (
2333       [["ping_daemon"]])],
2334    "ping the guest daemon",
2335    "\
2336 This is a test probe into the guestfs daemon running inside
2337 the qemu subprocess.  Calling this function checks that the
2338 daemon responds to the ping message, without affecting the daemon
2339 or attached block device(s) in any other way.");
2340
2341   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2342    [InitBasicFS, Always, TestOutputTrue (
2343       [["write_file"; "/file1"; "contents of a file"; "0"];
2344        ["cp"; "/file1"; "/file2"];
2345        ["equal"; "/file1"; "/file2"]]);
2346     InitBasicFS, Always, TestOutputFalse (
2347       [["write_file"; "/file1"; "contents of a file"; "0"];
2348        ["write_file"; "/file2"; "contents of another file"; "0"];
2349        ["equal"; "/file1"; "/file2"]]);
2350     InitBasicFS, Always, TestLastFail (
2351       [["equal"; "/file1"; "/file2"]])],
2352    "test if two files have equal contents",
2353    "\
2354 This compares the two files C<file1> and C<file2> and returns
2355 true if their content is exactly equal, or false otherwise.
2356
2357 The external L<cmp(1)> program is used for the comparison.");
2358
2359   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2360    [InitISOFS, Always, TestOutputList (
2361       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2362     InitISOFS, Always, TestOutputList (
2363       [["strings"; "/empty"]], [])],
2364    "print the printable strings in a file",
2365    "\
2366 This runs the L<strings(1)> command on a file and returns
2367 the list of printable strings found.");
2368
2369   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2370    [InitISOFS, Always, TestOutputList (
2371       [["strings_e"; "b"; "/known-5"]], []);
2372     InitBasicFS, Disabled, TestOutputList (
2373       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2374        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2375    "print the printable strings in a file",
2376    "\
2377 This is like the C<guestfs_strings> command, but allows you to
2378 specify the encoding.
2379
2380 See the L<strings(1)> manpage for the full list of encodings.
2381
2382 Commonly useful encodings are C<l> (lower case L) which will
2383 show strings inside Windows/x86 files.
2384
2385 The returned strings are transcoded to UTF-8.");
2386
2387   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2388    [InitISOFS, Always, TestOutput (
2389       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2390     (* Test for RHBZ#501888c2 regression which caused large hexdump
2391      * commands to segfault.
2392      *)
2393     InitISOFS, Always, TestRun (
2394       [["hexdump"; "/100krandom"]])],
2395    "dump a file in hexadecimal",
2396    "\
2397 This runs C<hexdump -C> on the given C<path>.  The result is
2398 the human-readable, canonical hex dump of the file.");
2399
2400   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2401    [InitNone, Always, TestOutput (
2402       [["part_disk"; "/dev/sda"; "mbr"];
2403        ["mkfs"; "ext3"; "/dev/sda1"];
2404        ["mount"; "/dev/sda1"; "/"];
2405        ["write_file"; "/new"; "test file"; "0"];
2406        ["umount"; "/dev/sda1"];
2407        ["zerofree"; "/dev/sda1"];
2408        ["mount"; "/dev/sda1"; "/"];
2409        ["cat"; "/new"]], "test file")],
2410    "zero unused inodes and disk blocks on ext2/3 filesystem",
2411    "\
2412 This runs the I<zerofree> program on C<device>.  This program
2413 claims to zero unused inodes and disk blocks on an ext2/3
2414 filesystem, thus making it possible to compress the filesystem
2415 more effectively.
2416
2417 You should B<not> run this program if the filesystem is
2418 mounted.
2419
2420 It is possible that using this program can damage the filesystem
2421 or data on the filesystem.");
2422
2423   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2424    [],
2425    "resize an LVM physical volume",
2426    "\
2427 This resizes (expands or shrinks) an existing LVM physical
2428 volume to match the new size of the underlying device.");
2429
2430   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2431                        Int "cyls"; Int "heads"; Int "sectors";
2432                        String "line"]), 99, [DangerWillRobinson],
2433    [],
2434    "modify a single partition on a block device",
2435    "\
2436 This runs L<sfdisk(8)> option to modify just the single
2437 partition C<n> (note: C<n> counts from 1).
2438
2439 For other parameters, see C<guestfs_sfdisk>.  You should usually
2440 pass C<0> for the cyls/heads/sectors parameters.
2441
2442 See also: C<guestfs_part_add>");
2443
2444   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2445    [],
2446    "display the partition table",
2447    "\
2448 This displays the partition table on C<device>, in the
2449 human-readable output of the L<sfdisk(8)> command.  It is
2450 not intended to be parsed.
2451
2452 See also: C<guestfs_part_list>");
2453
2454   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2455    [],
2456    "display the kernel geometry",
2457    "\
2458 This displays the kernel's idea of the geometry of C<device>.
2459
2460 The result is in human-readable format, and not designed to
2461 be parsed.");
2462
2463   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2464    [],
2465    "display the disk geometry from the partition table",
2466    "\
2467 This displays the disk geometry of C<device> read from the
2468 partition table.  Especially in the case where the underlying
2469 block device has been resized, this can be different from the
2470 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2471
2472 The result is in human-readable format, and not designed to
2473 be parsed.");
2474
2475   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2476    [],
2477    "activate or deactivate all volume groups",
2478    "\
2479 This command activates or (if C<activate> is false) deactivates
2480 all logical volumes in all volume groups.
2481 If activated, then they are made known to the
2482 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2483 then those devices disappear.
2484
2485 This command is the same as running C<vgchange -a y|n>");
2486
2487   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2488    [],
2489    "activate or deactivate some volume groups",
2490    "\
2491 This command activates or (if C<activate> is false) deactivates
2492 all logical volumes in the listed volume groups C<volgroups>.
2493 If activated, then they are made known to the
2494 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2495 then those devices disappear.
2496
2497 This command is the same as running C<vgchange -a y|n volgroups...>
2498
2499 Note that if C<volgroups> is an empty list then B<all> volume groups
2500 are activated or deactivated.");
2501
2502   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2503    [InitNone, Always, TestOutput (
2504       [["part_disk"; "/dev/sda"; "mbr"];
2505        ["pvcreate"; "/dev/sda1"];
2506        ["vgcreate"; "VG"; "/dev/sda1"];
2507        ["lvcreate"; "LV"; "VG"; "10"];
2508        ["mkfs"; "ext2"; "/dev/VG/LV"];
2509        ["mount"; "/dev/VG/LV"; "/"];
2510        ["write_file"; "/new"; "test content"; "0"];
2511        ["umount"; "/"];
2512        ["lvresize"; "/dev/VG/LV"; "20"];
2513        ["e2fsck_f"; "/dev/VG/LV"];
2514        ["resize2fs"; "/dev/VG/LV"];
2515        ["mount"; "/dev/VG/LV"; "/"];
2516        ["cat"; "/new"]], "test content")],
2517    "resize an LVM logical volume",
2518    "\
2519 This resizes (expands or shrinks) an existing LVM logical
2520 volume to C<mbytes>.  When reducing, data in the reduced part
2521 is lost.");
2522
2523   ("resize2fs", (RErr, [Device "device"]), 106, [],
2524    [], (* lvresize tests this *)
2525    "resize an ext2/ext3 filesystem",
2526    "\
2527 This resizes an ext2 or ext3 filesystem to match the size of
2528 the underlying device.
2529
2530 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2531 on the C<device> before calling this command.  For unknown reasons
2532 C<resize2fs> sometimes gives an error about this and sometimes not.
2533 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2534 calling this function.");
2535
2536   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2537    [InitBasicFS, Always, TestOutputList (
2538       [["find"; "/"]], ["lost+found"]);
2539     InitBasicFS, Always, TestOutputList (
2540       [["touch"; "/a"];
2541        ["mkdir"; "/b"];
2542        ["touch"; "/b/c"];
2543        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2544     InitBasicFS, Always, TestOutputList (
2545       [["mkdir_p"; "/a/b/c"];
2546        ["touch"; "/a/b/c/d"];
2547        ["find"; "/a/b/"]], ["c"; "c/d"])],
2548    "find all files and directories",
2549    "\
2550 This command lists out all files and directories, recursively,
2551 starting at C<directory>.  It is essentially equivalent to
2552 running the shell command C<find directory -print> but some
2553 post-processing happens on the output, described below.
2554
2555 This returns a list of strings I<without any prefix>.  Thus
2556 if the directory structure was:
2557
2558  /tmp/a
2559  /tmp/b
2560  /tmp/c/d
2561
2562 then the returned list from C<guestfs_find> C</tmp> would be
2563 4 elements:
2564
2565  a
2566  b
2567  c
2568  c/d
2569
2570 If C<directory> is not a directory, then this command returns
2571 an error.
2572
2573 The returned list is sorted.
2574
2575 See also C<guestfs_find0>.");
2576
2577   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2578    [], (* lvresize tests this *)
2579    "check an ext2/ext3 filesystem",
2580    "\
2581 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2582 filesystem checker on C<device>, noninteractively (C<-p>),
2583 even if the filesystem appears to be clean (C<-f>).
2584
2585 This command is only needed because of C<guestfs_resize2fs>
2586 (q.v.).  Normally you should use C<guestfs_fsck>.");
2587
2588   ("sleep", (RErr, [Int "secs"]), 109, [],
2589    [InitNone, Always, TestRun (
2590       [["sleep"; "1"]])],
2591    "sleep for some seconds",
2592    "\
2593 Sleep for C<secs> seconds.");
2594
2595   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2596    [InitNone, Always, TestOutputInt (
2597       [["part_disk"; "/dev/sda"; "mbr"];
2598        ["mkfs"; "ntfs"; "/dev/sda1"];
2599        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2600     InitNone, Always, TestOutputInt (
2601       [["part_disk"; "/dev/sda"; "mbr"];
2602        ["mkfs"; "ext2"; "/dev/sda1"];
2603        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2604    "probe NTFS volume",
2605    "\
2606 This command runs the L<ntfs-3g.probe(8)> command which probes
2607 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2608 be mounted read-write, and some cannot be mounted at all).
2609
2610 C<rw> is a boolean flag.  Set it to true if you want to test
2611 if the volume can be mounted read-write.  Set it to false if
2612 you want to test if the volume can be mounted read-only.
2613
2614 The return value is an integer which C<0> if the operation
2615 would succeed, or some non-zero value documented in the
2616 L<ntfs-3g.probe(8)> manual page.");
2617
2618   ("sh", (RString "output", [String "command"]), 111, [],
2619    [], (* XXX needs tests *)
2620    "run a command via the shell",
2621    "\
2622 This call runs a command from the guest filesystem via the
2623 guest's C</bin/sh>.
2624
2625 This is like C<guestfs_command>, but passes the command to:
2626
2627  /bin/sh -c \"command\"
2628
2629 Depending on the guest's shell, this usually results in
2630 wildcards being expanded, shell expressions being interpolated
2631 and so on.
2632
2633 All the provisos about C<guestfs_command> apply to this call.");
2634
2635   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2636    [], (* XXX needs tests *)
2637    "run a command via the shell returning lines",
2638    "\
2639 This is the same as C<guestfs_sh>, but splits the result
2640 into a list of lines.
2641
2642 See also: C<guestfs_command_lines>");
2643
2644   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2645    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2646     * code in stubs.c, since all valid glob patterns must start with "/".
2647     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2648     *)
2649    [InitBasicFS, Always, TestOutputList (
2650       [["mkdir_p"; "/a/b/c"];
2651        ["touch"; "/a/b/c/d"];
2652        ["touch"; "/a/b/c/e"];
2653        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2654     InitBasicFS, Always, TestOutputList (
2655       [["mkdir_p"; "/a/b/c"];
2656        ["touch"; "/a/b/c/d"];
2657        ["touch"; "/a/b/c/e"];
2658        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2659     InitBasicFS, Always, TestOutputList (
2660       [["mkdir_p"; "/a/b/c"];
2661        ["touch"; "/a/b/c/d"];
2662        ["touch"; "/a/b/c/e"];
2663        ["glob_expand"; "/a/*/x/*"]], [])],
2664    "expand a wildcard path",
2665    "\
2666 This command searches for all the pathnames matching
2667 C<pattern> according to the wildcard expansion rules
2668 used by the shell.
2669
2670 If no paths match, then this returns an empty list
2671 (note: not an error).
2672
2673 It is just a wrapper around the C L<glob(3)> function
2674 with flags C<GLOB_MARK|GLOB_BRACE>.
2675 See that manual page for more details.");
2676
2677   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2678    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2679       [["scrub_device"; "/dev/sdc"]])],
2680    "scrub (securely wipe) a device",
2681    "\
2682 This command writes patterns over C<device> to make data retrieval
2683 more difficult.
2684
2685 It is an interface to the L<scrub(1)> program.  See that
2686 manual page for more details.");
2687
2688   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2689    [InitBasicFS, Always, TestRun (
2690       [["write_file"; "/file"; "content"; "0"];
2691        ["scrub_file"; "/file"]])],
2692    "scrub (securely wipe) a file",
2693    "\
2694 This command writes patterns over a file to make data retrieval
2695 more difficult.
2696
2697 The file is I<removed> after scrubbing.
2698
2699 It is an interface to the L<scrub(1)> program.  See that
2700 manual page for more details.");
2701
2702   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2703    [], (* XXX needs testing *)
2704    "scrub (securely wipe) free space",
2705    "\
2706 This command creates the directory C<dir> and then fills it
2707 with files until the filesystem is full, and scrubs the files
2708 as for C<guestfs_scrub_file>, and deletes them.
2709 The intention is to scrub any free space on the partition
2710 containing C<dir>.
2711
2712 It is an interface to the L<scrub(1)> program.  See that
2713 manual page for more details.");
2714
2715   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2716    [InitBasicFS, Always, TestRun (
2717       [["mkdir"; "/tmp"];
2718        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2719    "create a temporary directory",
2720    "\
2721 This command creates a temporary directory.  The
2722 C<template> parameter should be a full pathname for the
2723 temporary directory name with the final six characters being
2724 \"XXXXXX\".
2725
2726 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2727 the second one being suitable for Windows filesystems.
2728
2729 The name of the temporary directory that was created
2730 is returned.
2731
2732 The temporary directory is created with mode 0700
2733 and is owned by root.
2734
2735 The caller is responsible for deleting the temporary
2736 directory and its contents after use.
2737
2738 See also: L<mkdtemp(3)>");
2739
2740   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2741    [InitISOFS, Always, TestOutputInt (
2742       [["wc_l"; "/10klines"]], 10000)],
2743    "count lines in a file",
2744    "\
2745 This command counts the lines in a file, using the
2746 C<wc -l> external command.");
2747
2748   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2749    [InitISOFS, Always, TestOutputInt (
2750       [["wc_w"; "/10klines"]], 10000)],
2751    "count words in a file",
2752    "\
2753 This command counts the words in a file, using the
2754 C<wc -w> external command.");
2755
2756   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2757    [InitISOFS, Always, TestOutputInt (
2758       [["wc_c"; "/100kallspaces"]], 102400)],
2759    "count characters in a file",
2760    "\
2761 This command counts the characters in a file, using the
2762 C<wc -c> external command.");
2763
2764   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2765    [InitISOFS, Always, TestOutputList (
2766       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2767    "return first 10 lines of a file",
2768    "\
2769 This command returns up to the first 10 lines of a file as
2770 a list of strings.");
2771
2772   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2773    [InitISOFS, Always, TestOutputList (
2774       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2775     InitISOFS, Always, TestOutputList (
2776       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2777     InitISOFS, Always, TestOutputList (
2778       [["head_n"; "0"; "/10klines"]], [])],
2779    "return first N lines of a file",
2780    "\
2781 If the parameter C<nrlines> is a positive number, this returns the first
2782 C<nrlines> lines of the file C<path>.
2783
2784 If the parameter C<nrlines> is a negative number, this returns lines
2785 from the file C<path>, excluding the last C<nrlines> lines.
2786
2787 If the parameter C<nrlines> is zero, this returns an empty list.");
2788
2789   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2790    [InitISOFS, Always, TestOutputList (
2791       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2792    "return last 10 lines of a file",
2793    "\
2794 This command returns up to the last 10 lines of a file as
2795 a list of strings.");
2796
2797   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2798    [InitISOFS, Always, TestOutputList (
2799       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2800     InitISOFS, Always, TestOutputList (
2801       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2802     InitISOFS, Always, TestOutputList (
2803       [["tail_n"; "0"; "/10klines"]], [])],
2804    "return last N lines of a file",
2805    "\
2806 If the parameter C<nrlines> is a positive number, this returns the last
2807 C<nrlines> lines of the file C<path>.
2808
2809 If the parameter C<nrlines> is a negative number, this returns lines
2810 from the file C<path>, starting with the C<-nrlines>th line.
2811
2812 If the parameter C<nrlines> is zero, this returns an empty list.");
2813
2814   ("df", (RString "output", []), 125, [],
2815    [], (* XXX Tricky to test because it depends on the exact format
2816         * of the 'df' command and other imponderables.
2817         *)
2818    "report file system disk space usage",
2819    "\
2820 This command runs the C<df> command to report disk space used.
2821
2822 This command is mostly useful for interactive sessions.  It
2823 is I<not> intended that you try to parse the output string.
2824 Use C<statvfs> from programs.");
2825
2826   ("df_h", (RString "output", []), 126, [],
2827    [], (* XXX Tricky to test because it depends on the exact format
2828         * of the 'df' command and other imponderables.
2829         *)
2830    "report file system disk space usage (human readable)",
2831    "\
2832 This command runs the C<df -h> command to report disk space used
2833 in human-readable format.
2834
2835 This command is mostly useful for interactive sessions.  It
2836 is I<not> intended that you try to parse the output string.
2837 Use C<statvfs> from programs.");
2838
2839   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2840    [InitISOFS, Always, TestOutputInt (
2841       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2842    "estimate file space usage",
2843    "\
2844 This command runs the C<du -s> command to estimate file space
2845 usage for C<path>.
2846
2847 C<path> can be a file or a directory.  If C<path> is a directory
2848 then the estimate includes the contents of the directory and all
2849 subdirectories (recursively).
2850
2851 The result is the estimated size in I<kilobytes>
2852 (ie. units of 1024 bytes).");
2853
2854   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2855    [InitISOFS, Always, TestOutputList (
2856       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2857    "list files in an initrd",
2858    "\
2859 This command lists out files contained in an initrd.
2860
2861 The files are listed without any initial C</> character.  The
2862 files are listed in the order they appear (not necessarily
2863 alphabetical).  Directory names are listed as separate items.
2864
2865 Old Linux kernels (2.4 and earlier) used a compressed ext2
2866 filesystem as initrd.  We I<only> support the newer initramfs
2867 format (compressed cpio files).");
2868
2869   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2870    [],
2871    "mount a file using the loop device",
2872    "\
2873 This command lets you mount C<file> (a filesystem image
2874 in a file) on a mount point.  It is entirely equivalent to
2875 the command C<mount -o loop file mountpoint>.");
2876
2877   ("mkswap", (RErr, [Device "device"]), 130, [],
2878    [InitEmpty, Always, TestRun (
2879       [["part_disk"; "/dev/sda"; "mbr"];
2880        ["mkswap"; "/dev/sda1"]])],
2881    "create a swap partition",
2882    "\
2883 Create a swap partition on C<device>.");
2884
2885   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2886    [InitEmpty, Always, TestRun (
2887       [["part_disk"; "/dev/sda"; "mbr"];
2888        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2889    "create a swap partition with a label",
2890    "\
2891 Create a swap partition on C<device> with label C<label>.
2892
2893 Note that you cannot attach a swap label to a block device
2894 (eg. C</dev/sda>), just to a partition.  This appears to be
2895 a limitation of the kernel or swap tools.");
2896
2897   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
2898    (let uuid = uuidgen () in
2899     [InitEmpty, Always, TestRun (
2900        [["part_disk"; "/dev/sda"; "mbr"];
2901         ["mkswap_U"; uuid; "/dev/sda1"]])]),
2902    "create a swap partition with an explicit UUID",
2903    "\
2904 Create a swap partition on C<device> with UUID C<uuid>.");
2905
2906   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
2907    [InitBasicFS, Always, TestOutputStruct (
2908       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2909        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2910        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2911     InitBasicFS, Always, TestOutputStruct (
2912       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2913        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2914    "make block, character or FIFO devices",
2915    "\
2916 This call creates block or character special devices, or
2917 named pipes (FIFOs).
2918
2919 The C<mode> parameter should be the mode, using the standard
2920 constants.  C<devmajor> and C<devminor> are the
2921 device major and minor numbers, only used when creating block
2922 and character special devices.");
2923
2924   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
2925    [InitBasicFS, Always, TestOutputStruct (
2926       [["mkfifo"; "0o777"; "/node"];
2927        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2928    "make FIFO (named pipe)",
2929    "\
2930 This call creates a FIFO (named pipe) called C<path> with
2931 mode C<mode>.  It is just a convenient wrapper around
2932 C<guestfs_mknod>.");
2933
2934   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
2935    [InitBasicFS, Always, TestOutputStruct (
2936       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2937        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2938    "make block device node",
2939    "\
2940 This call creates a block device node called C<path> with
2941 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2942 It is just a convenient wrapper around C<guestfs_mknod>.");
2943
2944   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
2945    [InitBasicFS, Always, TestOutputStruct (
2946       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2947        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2948    "make char device node",
2949    "\
2950 This call creates a char device node called C<path> with
2951 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2952 It is just a convenient wrapper around C<guestfs_mknod>.");
2953
2954   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2955    [], (* XXX umask is one of those stateful things that we should
2956         * reset between each test.
2957         *)
2958    "set file mode creation mask (umask)",
2959    "\
2960 This function sets the mask used for creating new files and
2961 device nodes to C<mask & 0777>.
2962
2963 Typical umask values would be C<022> which creates new files
2964 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2965 C<002> which creates new files with permissions like
2966 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2967
2968 The default umask is C<022>.  This is important because it
2969 means that directories and device nodes will be created with
2970 C<0644> or C<0755> mode even if you specify C<0777>.
2971
2972 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2973
2974 This call returns the previous umask.");
2975
2976   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
2977    [],
2978    "read directories entries",
2979    "\
2980 This returns the list of directory entries in directory C<dir>.
2981
2982 All entries in the directory are returned, including C<.> and
2983 C<..>.  The entries are I<not> sorted, but returned in the same
2984 order as the underlying filesystem.
2985
2986 Also this call returns basic file type information about each
2987 file.  The C<ftyp> field will contain one of the following characters:
2988
2989 =over 4
2990
2991 =item 'b'
2992
2993 Block special
2994
2995 =item 'c'
2996
2997 Char special
2998
2999 =item 'd'
3000
3001 Directory
3002
3003 =item 'f'
3004
3005 FIFO (named pipe)
3006
3007 =item 'l'
3008
3009 Symbolic link
3010
3011 =item 'r'
3012
3013 Regular file
3014
3015 =item 's'
3016
3017 Socket
3018
3019 =item 'u'
3020
3021 Unknown file type
3022
3023 =item '?'
3024
3025 The L<readdir(3)> returned a C<d_type> field with an
3026 unexpected value
3027
3028 =back
3029
3030 This function is primarily intended for use by programs.  To
3031 get a simple list of names, use C<guestfs_ls>.  To get a printable
3032 directory for human consumption, use C<guestfs_ll>.");
3033
3034   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3035    [],
3036    "create partitions on a block device",
3037    "\
3038 This is a simplified interface to the C<guestfs_sfdisk>
3039 command, where partition sizes are specified in megabytes
3040 only (rounded to the nearest cylinder) and you don't need
3041 to specify the cyls, heads and sectors parameters which
3042 were rarely if ever used anyway.
3043
3044 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3045 and C<guestfs_part_disk>");
3046
3047   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3048    [],
3049    "determine file type inside a compressed file",
3050    "\
3051 This command runs C<file> after first decompressing C<path>
3052 using C<method>.
3053
3054 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3055
3056 Since 1.0.63, use C<guestfs_file> instead which can now
3057 process compressed files.");
3058
3059   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3060    [],
3061    "list extended attributes of a file or directory",
3062    "\
3063 This call lists the extended attributes of the file or directory
3064 C<path>.
3065
3066 At the system call level, this is a combination of the
3067 L<listxattr(2)> and L<getxattr(2)> calls.
3068
3069 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3070
3071   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3072    [],
3073    "list extended attributes of a file or directory",
3074    "\
3075 This is the same as C<guestfs_getxattrs>, but if C<path>
3076 is a symbolic link, then it returns the extended attributes
3077 of the link itself.");
3078
3079   ("setxattr", (RErr, [String "xattr";
3080                        String "val"; Int "vallen"; (* will be BufferIn *)
3081                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3082    [],
3083    "set extended attribute of a file or directory",
3084    "\
3085 This call sets the extended attribute named C<xattr>
3086 of the file C<path> to the value C<val> (of length C<vallen>).
3087 The value is arbitrary 8 bit data.
3088
3089 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3090
3091   ("lsetxattr", (RErr, [String "xattr";
3092                         String "val"; Int "vallen"; (* will be BufferIn *)
3093                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3094    [],
3095    "set extended attribute of a file or directory",
3096    "\
3097 This is the same as C<guestfs_setxattr>, but if C<path>
3098 is a symbolic link, then it sets an extended attribute
3099 of the link itself.");
3100
3101   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3102    [],
3103    "remove extended attribute of a file or directory",
3104    "\
3105 This call removes the extended attribute named C<xattr>
3106 of the file C<path>.
3107
3108 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3109
3110   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3111    [],
3112    "remove extended attribute of a file or directory",
3113    "\
3114 This is the same as C<guestfs_removexattr>, but if C<path>
3115 is a symbolic link, then it removes an extended attribute
3116 of the link itself.");
3117
3118   ("mountpoints", (RHashtable "mps", []), 147, [],
3119    [],
3120    "show mountpoints",
3121    "\
3122 This call is similar to C<guestfs_mounts>.  That call returns
3123 a list of devices.  This one returns a hash table (map) of
3124 device name to directory where the device is mounted.");
3125
3126   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3127    (* This is a special case: while you would expect a parameter
3128     * of type "Pathname", that doesn't work, because it implies
3129     * NEED_ROOT in the generated calling code in stubs.c, and
3130     * this function cannot use NEED_ROOT.
3131     *)
3132    [],
3133    "create a mountpoint",
3134    "\
3135 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3136 specialized calls that can be used to create extra mountpoints
3137 before mounting the first filesystem.
3138
3139 These calls are I<only> necessary in some very limited circumstances,
3140 mainly the case where you want to mount a mix of unrelated and/or
3141 read-only filesystems together.
3142
3143 For example, live CDs often contain a \"Russian doll\" nest of
3144 filesystems, an ISO outer layer, with a squashfs image inside, with
3145 an ext2/3 image inside that.  You can unpack this as follows
3146 in guestfish:
3147
3148  add-ro Fedora-11-i686-Live.iso
3149  run
3150  mkmountpoint /cd
3151  mkmountpoint /squash
3152  mkmountpoint /ext3
3153  mount /dev/sda /cd
3154  mount-loop /cd/LiveOS/squashfs.img /squash
3155  mount-loop /squash/LiveOS/ext3fs.img /ext3
3156
3157 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3158
3159   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3160    [],
3161    "remove a mountpoint",
3162    "\
3163 This calls removes a mountpoint that was previously created
3164 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3165 for full details.");
3166
3167   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3168    [InitISOFS, Always, TestOutputBuffer (
3169       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3170    "read a file",
3171    "\
3172 This calls returns the contents of the file C<path> as a
3173 buffer.
3174
3175 Unlike C<guestfs_cat>, this function can correctly
3176 handle files that contain embedded ASCII NUL characters.
3177 However unlike C<guestfs_download>, this function is limited
3178 in the total size of file that can be handled.");
3179
3180   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3181    [InitISOFS, Always, TestOutputList (
3182       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3183     InitISOFS, Always, TestOutputList (
3184       [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3185    "return lines matching a pattern",
3186    "\
3187 This calls the external C<grep> program and returns the
3188 matching lines.");
3189
3190   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3191    [InitISOFS, Always, TestOutputList (
3192       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3193    "return lines matching a pattern",
3194    "\
3195 This calls the external C<egrep> program and returns the
3196 matching lines.");
3197
3198   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3199    [InitISOFS, Always, TestOutputList (
3200       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3201    "return lines matching a pattern",
3202    "\
3203 This calls the external C<fgrep> program and returns the
3204 matching lines.");
3205
3206   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3207    [InitISOFS, Always, TestOutputList (
3208       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3209    "return lines matching a pattern",
3210    "\
3211 This calls the external C<grep -i> program and returns the
3212 matching lines.");
3213
3214   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3215    [InitISOFS, Always, TestOutputList (
3216       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3217    "return lines matching a pattern",
3218    "\
3219 This calls the external C<egrep -i> program and returns the
3220 matching lines.");
3221
3222   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3223    [InitISOFS, Always, TestOutputList (
3224       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3225    "return lines matching a pattern",
3226    "\
3227 This calls the external C<fgrep -i> program and returns the
3228 matching lines.");
3229
3230   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3231    [InitISOFS, Always, TestOutputList (
3232       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3233    "return lines matching a pattern",
3234    "\
3235 This calls the external C<zgrep> program and returns the
3236 matching lines.");
3237
3238   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3239    [InitISOFS, Always, TestOutputList (
3240       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3241    "return lines matching a pattern",
3242    "\
3243 This calls the external C<zegrep> program and returns the
3244 matching lines.");
3245
3246   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3247    [InitISOFS, Always, TestOutputList (
3248       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3249    "return lines matching a pattern",
3250    "\
3251 This calls the external C<zfgrep> program and returns the
3252 matching lines.");
3253
3254   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3255    [InitISOFS, Always, TestOutputList (
3256       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3257    "return lines matching a pattern",
3258    "\
3259 This calls the external C<zgrep -i> program and returns the
3260 matching lines.");
3261
3262   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3263    [InitISOFS, Always, TestOutputList (
3264       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3265    "return lines matching a pattern",
3266    "\
3267 This calls the external C<zegrep -i> program and returns the
3268 matching lines.");
3269
3270   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3271    [InitISOFS, Always, TestOutputList (
3272       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3273    "return lines matching a pattern",
3274    "\
3275 This calls the external C<zfgrep -i> program and returns the
3276 matching lines.");
3277
3278   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3279    [InitISOFS, Always, TestOutput (
3280       [["realpath"; "/../directory"]], "/directory")],
3281    "canonicalized absolute pathname",
3282    "\
3283 Return the canonicalized absolute pathname of C<path>.  The
3284 returned path has no C<.>, C<..> or symbolic link path elements.");
3285
3286   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3287    [InitBasicFS, Always, TestOutputStruct (
3288       [["touch"; "/a"];
3289        ["ln"; "/a"; "/b"];
3290        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3291    "create a hard link",
3292    "\
3293 This command creates a hard link using the C<ln> command.");
3294
3295   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3296    [InitBasicFS, Always, TestOutputStruct (
3297       [["touch"; "/a"];
3298        ["touch"; "/b"];
3299        ["ln_f"; "/a"; "/b"];
3300        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3301    "create a hard link",
3302    "\
3303 This command creates a hard link using the C<ln -f> command.
3304 The C<-f> option removes the link (C<linkname>) if it exists already.");
3305
3306   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3307    [InitBasicFS, Always, TestOutputStruct (
3308       [["touch"; "/a"];
3309        ["ln_s"; "a"; "/b"];
3310        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3311    "create a symbolic link",
3312    "\
3313 This command creates a symbolic link using the C<ln -s> command.");
3314
3315   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3316    [InitBasicFS, Always, TestOutput (
3317       [["mkdir_p"; "/a/b"];
3318        ["touch"; "/a/b/c"];
3319        ["ln_sf"; "../d"; "/a/b/c"];
3320        ["readlink"; "/a/b/c"]], "../d")],
3321    "create a symbolic link",
3322    "\
3323 This command creates a symbolic link using the C<ln -sf> command,
3324 The C<-f> option removes the link (C<linkname>) if it exists already.");
3325
3326   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3327    [] (* XXX tested above *),
3328    "read the target of a symbolic link",
3329    "\
3330 This command reads the target of a symbolic link.");
3331
3332   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3333    [InitBasicFS, Always, TestOutputStruct (
3334       [["fallocate"; "/a"; "1000000"];
3335        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3336    "preallocate a file in the guest filesystem",
3337    "\
3338 This command preallocates a file (containing zero bytes) named
3339 C<path> of size C<len> bytes.  If the file exists already, it
3340 is overwritten.
3341
3342 Do not confuse this with the guestfish-specific
3343 C<alloc> command which allocates a file in the host and
3344 attaches it as a device.");
3345
3346   ("swapon_device", (RErr, [Device "device"]), 170, [],
3347    [InitPartition, Always, TestRun (
3348       [["mkswap"; "/dev/sda1"];
3349        ["swapon_device"; "/dev/sda1"];
3350        ["swapoff_device"; "/dev/sda1"]])],
3351    "enable swap on device",
3352    "\
3353 This command enables the libguestfs appliance to use the
3354 swap device or partition named C<device>.  The increased
3355 memory is made available for all commands, for example
3356 those run using C<guestfs_command> or C<guestfs_sh>.
3357
3358 Note that you should not swap to existing guest swap
3359 partitions unless you know what you are doing.  They may
3360 contain hibernation information, or other information that
3361 the guest doesn't want you to trash.  You also risk leaking
3362 information about the host to the guest this way.  Instead,
3363 attach a new host device to the guest and swap on that.");
3364
3365   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3366    [], (* XXX tested by swapon_device *)
3367    "disable swap on device",
3368    "\
3369 This command disables the libguestfs appliance swap
3370 device or partition named C<device>.
3371 See C<guestfs_swapon_device>.");
3372
3373   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3374    [InitBasicFS, Always, TestRun (
3375       [["fallocate"; "/swap"; "8388608"];
3376        ["mkswap_file"; "/swap"];
3377        ["swapon_file"; "/swap"];
3378        ["swapoff_file"; "/swap"]])],
3379    "enable swap on file",
3380    "\
3381 This command enables swap to a file.
3382 See C<guestfs_swapon_device> for other notes.");
3383
3384   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3385    [], (* XXX tested by swapon_file *)
3386    "disable swap on file",
3387    "\
3388 This command disables the libguestfs appliance swap on file.");
3389
3390   ("swapon_label", (RErr, [String "label"]), 174, [],
3391    [InitEmpty, Always, TestRun (
3392       [["part_disk"; "/dev/sdb"; "mbr"];
3393        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3394        ["swapon_label"; "swapit"];
3395        ["swapoff_label"; "swapit"];
3396        ["zero"; "/dev/sdb"];
3397        ["blockdev_rereadpt"; "/dev/sdb"]])],
3398    "enable swap on labeled swap partition",
3399    "\
3400 This command enables swap to a labeled swap partition.
3401 See C<guestfs_swapon_device> for other notes.");
3402
3403   ("swapoff_label", (RErr, [String "label"]), 175, [],
3404    [], (* XXX tested by swapon_label *)
3405    "disable swap on labeled swap partition",
3406    "\
3407 This command disables the libguestfs appliance swap on
3408 labeled swap partition.");
3409
3410   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3411    (let uuid = uuidgen () in
3412     [InitEmpty, Always, TestRun (
3413        [["mkswap_U"; uuid; "/dev/sdb"];
3414         ["swapon_uuid"; uuid];
3415         ["swapoff_uuid"; uuid]])]),
3416    "enable swap on swap partition by UUID",
3417    "\
3418 This command enables swap to a swap partition with the given UUID.
3419 See C<guestfs_swapon_device> for other notes.");
3420
3421   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3422    [], (* XXX tested by swapon_uuid *)
3423    "disable swap on swap partition by UUID",
3424    "\
3425 This command disables the libguestfs appliance swap partition
3426 with the given UUID.");
3427
3428   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3429    [InitBasicFS, Always, TestRun (
3430       [["fallocate"; "/swap"; "8388608"];
3431        ["mkswap_file"; "/swap"]])],
3432    "create a swap file",
3433    "\
3434 Create a swap file.
3435
3436 This command just writes a swap file signature to an existing
3437 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3438
3439   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3440    [InitISOFS, Always, TestRun (
3441       [["inotify_init"; "0"]])],
3442    "create an inotify handle",
3443    "\
3444 This command creates a new inotify handle.
3445 The inotify subsystem can be used to notify events which happen to
3446 objects in the guest filesystem.
3447
3448 C<maxevents> is the maximum number of events which will be
3449 queued up between calls to C<guestfs_inotify_read> or
3450 C<guestfs_inotify_files>.
3451 If this is passed as C<0>, then the kernel (or previously set)
3452 default is used.  For Linux 2.6.29 the default was 16384 events.
3453 Beyond this limit, the kernel throws away events, but records
3454 the fact that it threw them away by setting a flag
3455 C<IN_Q_OVERFLOW> in the returned structure list (see
3456 C<guestfs_inotify_read>).
3457
3458 Before any events are generated, you have to add some
3459 watches to the internal watch list.  See:
3460 C<guestfs_inotify_add_watch>,
3461 C<guestfs_inotify_rm_watch> and
3462 C<guestfs_inotify_watch_all>.
3463
3464 Queued up events should be read periodically by calling
3465 C<guestfs_inotify_read>
3466 (or C<guestfs_inotify_files> which is just a helpful
3467 wrapper around C<guestfs_inotify_read>).  If you don't
3468 read the events out often enough then you risk the internal
3469 queue overflowing.
3470
3471 The handle should be closed after use by calling
3472 C<guestfs_inotify_close>.  This also removes any
3473 watches automatically.
3474
3475 See also L<inotify(7)> for an overview of the inotify interface
3476 as exposed by the Linux kernel, which is roughly what we expose
3477 via libguestfs.  Note that there is one global inotify handle
3478 per libguestfs instance.");
3479
3480   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3481    [InitBasicFS, Always, TestOutputList (
3482       [["inotify_init"; "0"];
3483        ["inotify_add_watch"; "/"; "1073741823"];
3484        ["touch"; "/a"];
3485        ["touch"; "/b"];
3486        ["inotify_files"]], ["a"; "b"])],
3487    "add an inotify watch",
3488    "\
3489 Watch C<path> for the events listed in C<mask>.
3490
3491 Note that if C<path> is a directory then events within that
3492 directory are watched, but this does I<not> happen recursively
3493 (in subdirectories).
3494
3495 Note for non-C or non-Linux callers: the inotify events are
3496 defined by the Linux kernel ABI and are listed in
3497 C</usr/include/sys/inotify.h>.");
3498
3499   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3500    [],
3501    "remove an inotify watch",
3502    "\
3503 Remove a previously defined inotify watch.
3504 See C<guestfs_inotify_add_watch>.");
3505
3506   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3507    [],
3508    "return list of inotify events",
3509    "\
3510 Return the complete queue of events that have happened
3511 since the previous read call.
3512
3513 If no events have happened, this returns an empty list.
3514
3515 I<Note>: In order to make sure that all events have been
3516 read, you must call this function repeatedly until it
3517 returns an empty list.  The reason is that the call will
3518 read events up to the maximum appliance-to-host message
3519 size and leave remaining events in the queue.");
3520
3521   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3522    [],
3523    "return list of watched files that had events",
3524    "\
3525 This function is a helpful wrapper around C<guestfs_inotify_read>
3526 which just returns a list of pathnames of objects that were
3527 touched.  The returned pathnames are sorted and deduplicated.");
3528
3529   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3530    [],
3531    "close the inotify handle",
3532    "\
3533 This closes the inotify handle which was previously
3534 opened by inotify_init.  It removes all watches, throws
3535 away any pending events, and deallocates all resources.");
3536
3537   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3538    [],
3539    "set SELinux security context",
3540    "\
3541 This sets the SELinux security context of the daemon
3542 to the string C<context>.
3543
3544 See the documentation about SELINUX in L<guestfs(3)>.");
3545
3546   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3547    [],
3548    "get SELinux security context",
3549    "\
3550 This gets the SELinux security context of the daemon.
3551
3552 See the documentation about SELINUX in L<guestfs(3)>,
3553 and C<guestfs_setcon>");
3554
3555   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3556    [InitEmpty, Always, TestOutput (
3557       [["part_disk"; "/dev/sda"; "mbr"];
3558        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3559        ["mount"; "/dev/sda1"; "/"];
3560        ["write_file"; "/new"; "new file contents"; "0"];
3561        ["cat"; "/new"]], "new file contents")],
3562    "make a filesystem with block size",
3563    "\
3564 This call is similar to C<guestfs_mkfs>, but it allows you to
3565 control the block size of the resulting filesystem.  Supported
3566 block sizes depend on the filesystem type, but typically they
3567 are C<1024>, C<2048> or C<4096> only.");
3568
3569   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3570    [InitEmpty, Always, TestOutput (
3571       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3572        ["mke2journal"; "4096"; "/dev/sda1"];
3573        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3574        ["mount"; "/dev/sda2"; "/"];
3575        ["write_file"; "/new"; "new file contents"; "0"];
3576        ["cat"; "/new"]], "new file contents")],
3577    "make ext2/3/4 external journal",
3578    "\
3579 This creates an ext2 external journal on C<device>.  It is equivalent
3580 to the command:
3581
3582  mke2fs -O journal_dev -b blocksize device");
3583
3584   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3585    [InitEmpty, Always, TestOutput (
3586       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3587        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3588        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3589        ["mount"; "/dev/sda2"; "/"];
3590        ["write_file"; "/new"; "new file contents"; "0"];
3591        ["cat"; "/new"]], "new file contents")],
3592    "make ext2/3/4 external journal with label",
3593    "\
3594 This creates an ext2 external journal on C<device> with label C<label>.");
3595
3596   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3597    (let uuid = uuidgen () in
3598     [InitEmpty, Always, TestOutput (
3599        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3600         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3601         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3602         ["mount"; "/dev/sda2"; "/"];
3603         ["write_file"; "/new"; "new file contents"; "0"];
3604         ["cat"; "/new"]], "new file contents")]),
3605    "make ext2/3/4 external journal with UUID",
3606    "\
3607 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3608
3609   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3610    [],
3611    "make ext2/3/4 filesystem with external journal",
3612    "\
3613 This creates an ext2/3/4 filesystem on C<device> with
3614 an external journal on C<journal>.  It is equivalent
3615 to the command:
3616
3617  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3618
3619 See also C<guestfs_mke2journal>.");
3620
3621   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3622    [],
3623    "make ext2/3/4 filesystem with external journal",
3624    "\
3625 This creates an ext2/3/4 filesystem on C<device> with
3626 an external journal on the journal labeled C<label>.
3627
3628 See also C<guestfs_mke2journal_L>.");
3629
3630   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3631    [],
3632    "make ext2/3/4 filesystem with external journal",
3633    "\
3634 This creates an ext2/3/4 filesystem on C<device> with
3635 an external journal on the journal with UUID C<uuid>.
3636
3637 See also C<guestfs_mke2journal_U>.");
3638
3639   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3640    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3641    "load a kernel module",
3642    "\
3643 This loads a kernel module in the appliance.
3644
3645 The kernel module must have been whitelisted when libguestfs
3646 was built (see C<appliance/kmod.whitelist.in> in the source).");
3647
3648   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3649    [InitNone, Always, TestOutput (
3650       [["echo_daemon"; "This is a test"]], "This is a test"
3651     )],
3652    "echo arguments back to the client",
3653    "\
3654 This command concatenate the list of C<words> passed with single spaces between
3655 them and returns the resulting string.
3656
3657 You can use this command to test the connection through to the daemon.
3658
3659 See also C<guestfs_ping_daemon>.");
3660
3661   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3662    [], (* There is a regression test for this. *)
3663    "find all files and directories, returning NUL-separated list",
3664    "\
3665 This command lists out all files and directories, recursively,
3666 starting at C<directory>, placing the resulting list in the
3667 external file called C<files>.
3668
3669 This command works the same way as C<guestfs_find> with the
3670 following exceptions:
3671
3672 =over 4
3673
3674 =item *
3675
3676 The resulting list is written to an external file.
3677
3678 =item *
3679
3680 Items (filenames) in the result are separated
3681 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3682
3683 =item *
3684
3685 This command is not limited in the number of names that it
3686 can return.
3687
3688 =item *
3689
3690 The result list is not sorted.
3691
3692 =back");
3693
3694   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3695    [InitISOFS, Always, TestOutput (
3696       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3697     InitISOFS, Always, TestOutput (
3698       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3699     InitISOFS, Always, TestOutput (
3700       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3701     InitISOFS, Always, TestLastFail (
3702       [["case_sensitive_path"; "/Known-1/"]]);
3703     InitBasicFS, Always, TestOutput (
3704       [["mkdir"; "/a"];
3705        ["mkdir"; "/a/bbb"];
3706        ["touch"; "/a/bbb/c"];
3707        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3708     InitBasicFS, Always, TestOutput (
3709       [["mkdir"; "/a"];
3710        ["mkdir"; "/a/bbb"];
3711        ["touch"; "/a/bbb/c"];
3712        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3713     InitBasicFS, Always, TestLastFail (
3714       [["mkdir"; "/a"];
3715        ["mkdir"; "/a/bbb"];
3716        ["touch"; "/a/bbb/c"];
3717        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3718    "return true path on case-insensitive filesystem",
3719    "\
3720 This can be used to resolve case insensitive paths on
3721 a filesystem which is case sensitive.  The use case is
3722 to resolve paths which you have read from Windows configuration
3723 files or the Windows Registry, to the true path.
3724
3725 The command handles a peculiarity of the Linux ntfs-3g
3726 filesystem driver (and probably others), which is that although
3727 the underlying filesystem is case-insensitive, the driver
3728 exports the filesystem to Linux as case-sensitive.
3729
3730 One consequence of this is that special directories such
3731 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3732 (or other things) depending on the precise details of how
3733 they were created.  In Windows itself this would not be
3734 a problem.
3735
3736 Bug or feature?  You decide:
3737 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3738
3739 This function resolves the true case of each element in the
3740 path and returns the case-sensitive path.
3741
3742 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3743 might return C<\"/WINDOWS/system32\"> (the exact return value
3744 would depend on details of how the directories were originally
3745 created under Windows).
3746
3747 I<Note>:
3748 This function does not handle drive names, backslashes etc.
3749
3750 See also C<guestfs_realpath>.");
3751
3752   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3753    [InitBasicFS, Always, TestOutput (
3754       [["vfs_type"; "/dev/sda1"]], "ext2")],
3755    "get the Linux VFS type corresponding to a mounted device",
3756    "\
3757 This command gets the block device type corresponding to
3758 a mounted device called C<device>.
3759
3760 Usually the result is the name of the Linux VFS module that
3761 is used to mount this device (probably determined automatically
3762 if you used the C<guestfs_mount> call).");
3763
3764   ("truncate", (RErr, [Pathname "path"]), 199, [],
3765    [InitBasicFS, Always, TestOutputStruct (
3766       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3767        ["truncate"; "/test"];
3768        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3769    "truncate a file to zero size",
3770    "\
3771 This command truncates C<path> to a zero-length file.  The
3772 file must exist already.");
3773
3774   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3775    [InitBasicFS, Always, TestOutputStruct (
3776       [["touch"; "/test"];
3777        ["truncate_size"; "/test"; "1000"];
3778        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3779    "truncate a file to a particular size",
3780    "\
3781 This command truncates C<path> to size C<size> bytes.  The file
3782 must exist already.  If the file is smaller than C<size> then
3783 the file is extended to the required size with null bytes.");
3784
3785   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3786    [InitBasicFS, Always, TestOutputStruct (
3787       [["touch"; "/test"];
3788        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3789        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3790    "set timestamp of a file with nanosecond precision",
3791    "\
3792 This command sets the timestamps of a file with nanosecond
3793 precision.
3794
3795 C<atsecs, atnsecs> are the last access time (atime) in secs and
3796 nanoseconds from the epoch.
3797
3798 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3799 secs and nanoseconds from the epoch.
3800
3801 If the C<*nsecs> field contains the special value C<-1> then
3802 the corresponding timestamp is set to the current time.  (The
3803 C<*secs> field is ignored in this case).
3804
3805 If the C<*nsecs> field contains the special value C<-2> then
3806 the corresponding timestamp is left unchanged.  (The
3807 C<*secs> field is ignored in this case).");
3808
3809   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3810    [InitBasicFS, Always, TestOutputStruct (
3811       [["mkdir_mode"; "/test"; "0o111"];
3812        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3813    "create a directory with a particular mode",
3814    "\
3815 This command creates a directory, setting the initial permissions
3816 of the directory to C<mode>.  See also C<guestfs_mkdir>.");
3817
3818   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3819    [], (* XXX *)
3820    "change file owner and group",
3821    "\
3822 Change the file owner to C<owner> and group to C<group>.
3823 This is like C<guestfs_chown> but if C<path> is a symlink then
3824 the link itself is changed, not the target.
3825
3826 Only numeric uid and gid are supported.  If you want to use
3827 names, you will need to locate and parse the password file
3828 yourself (Augeas support makes this relatively easy).");
3829
3830   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3831    [], (* XXX *)
3832    "lstat on multiple files",
3833    "\
3834 This call allows you to perform the C<guestfs_lstat> operation
3835 on multiple files, where all files are in the directory C<path>.
3836 C<names> is the list of files from this directory.
3837
3838 On return you get a list of stat structs, with a one-to-one
3839 correspondence to the C<names> list.  If any name did not exist
3840 or could not be lstat'd, then the C<ino> field of that structure
3841 is set to C<-1>.
3842
3843 This call is intended for programs that want to efficiently
3844 list a directory contents without making many round-trips.
3845 See also C<guestfs_lxattrlist> for a similarly efficient call
3846 for getting extended attributes.  Very long directory listings
3847 might cause the protocol message size to be exceeded, causing
3848 this call to fail.  The caller must split up such requests
3849 into smaller groups of names.");
3850
3851   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3852    [], (* XXX *)
3853    "lgetxattr on multiple files",
3854    "\
3855 This call allows you to get the extended attributes
3856 of multiple files, where all files are in the directory C<path>.
3857 C<names> is the list of files from this directory.
3858
3859 On return you get a flat list of xattr structs which must be
3860 interpreted sequentially.  The first xattr struct always has a zero-length
3861 C<attrname>.  C<attrval> in this struct is zero-length
3862 to indicate there was an error doing C<lgetxattr> for this
3863 file, I<or> is a C string which is a decimal number
3864 (the number of following attributes for this file, which could
3865 be C<\"0\">).  Then after the first xattr struct are the
3866 zero or more attributes for the first named file.
3867 This repeats for the second and subsequent files.
3868
3869 This call is intended for programs that want to efficiently
3870 list a directory contents without making many round-trips.
3871 See also C<guestfs_lstatlist> for a similarly efficient call
3872 for getting standard stats.  Very long directory listings
3873 might cause the protocol message size to be exceeded, causing
3874 this call to fail.  The caller must split up such requests
3875 into smaller groups of names.");
3876
3877   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
3878    [], (* XXX *)
3879    "readlink on multiple files",
3880    "\
3881 This call allows you to do a C<readlink> operation
3882 on multiple files, where all files are in the directory C<path>.
3883 C<names> is the list of files from this directory.
3884
3885 On return you get a list of strings, with a one-to-one
3886 correspondence to the C<names> list.  Each string is the
3887 value of the symbol link.
3888
3889 If the C<readlink(2)> operation fails on any name, then
3890 the corresponding result string is the empty string C<\"\">.
3891 However the whole operation is completed even if there
3892 were C<readlink(2)> errors, and so you can call this
3893 function with names where you don't know if they are
3894 symbolic links already (albeit slightly less efficient).
3895
3896 This call is intended for programs that want to efficiently
3897 list a directory contents without making many round-trips.
3898 Very long directory listings might cause the protocol
3899 message size to be exceeded, causing
3900 this call to fail.  The caller must split up such requests
3901 into smaller groups of names.");
3902
3903   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
3904    [InitISOFS, Always, TestOutputBuffer (
3905       [["pread"; "/known-4"; "1"; "3"]], "\n");
3906     InitISOFS, Always, TestOutputBuffer (
3907       [["pread"; "/empty"; "0"; "100"]], "")],
3908    "read part of a file",
3909    "\
3910 This command lets you read part of a file.  It reads C<count>
3911 bytes of the file, starting at C<offset>, from file C<path>.
3912
3913 This may read fewer bytes than requested.  For further details
3914 see the L<pread(2)> system call.");
3915
3916   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
3917    [InitEmpty, Always, TestRun (
3918       [["part_init"; "/dev/sda"; "gpt"]])],
3919    "create an empty partition table",
3920    "\
3921 This creates an empty partition table on C<device> of one of the
3922 partition types listed below.  Usually C<parttype> should be
3923 either C<msdos> or C<gpt> (for large disks).
3924
3925 Initially there are no partitions.  Following this, you should
3926 call C<guestfs_part_add> for each partition required.
3927
3928 Possible values for C<parttype> are:
3929
3930 =over 4
3931
3932 =item B<efi> | B<gpt>
3933
3934 Intel EFI / GPT partition table.
3935
3936 This is recommended for >= 2 TB partitions that will be accessed
3937 from Linux and Intel-based Mac OS X.  It also has limited backwards
3938 compatibility with the C<mbr> format.
3939
3940 =item B<mbr> | B<msdos>
3941
3942 The standard PC \"Master Boot Record\" (MBR) format used
3943 by MS-DOS and Windows.  This partition type will B<only> work
3944 for device sizes up to 2 TB.  For large disks we recommend
3945 using C<gpt>.
3946
3947 =back
3948
3949 Other partition table types that may work but are not
3950 supported include:
3951
3952 =over 4
3953
3954 =item B<aix>
3955
3956 AIX disk labels.
3957
3958 =item B<amiga> | B<rdb>
3959
3960 Amiga \"Rigid Disk Block\" format.
3961
3962 =item B<bsd>
3963
3964 BSD disk labels.
3965
3966 =item B<dasd>
3967
3968 DASD, used on IBM mainframes.
3969
3970 =item B<dvh>
3971
3972 MIPS/SGI volumes.
3973
3974 =item B<mac>
3975
3976 Old Mac partition format.  Modern Macs use C<gpt>.
3977
3978 =item B<pc98>
3979
3980 NEC PC-98 format, common in Japan apparently.
3981
3982 =item B<sun>
3983
3984 Sun disk labels.
3985
3986 =back");
3987
3988   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
3989    [InitEmpty, Always, TestRun (
3990       [["part_init"; "/dev/sda"; "mbr"];
3991        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
3992     InitEmpty, Always, TestRun (
3993       [["part_init"; "/dev/sda"; "gpt"];
3994        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
3995        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
3996     InitEmpty, Always, TestRun (
3997       [["part_init"; "/dev/sda"; "mbr"];
3998        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
3999        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4000        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4001        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4002    "add a partition to the device",
4003    "\
4004 This command adds a partition to C<device>.  If there is no partition
4005 table on the device, call C<guestfs_part_init> first.
4006
4007 The C<prlogex> parameter is the type of partition.  Normally you
4008 should pass C<p> or C<primary> here, but MBR partition tables also
4009 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4010 types.
4011
4012 C<startsect> and C<endsect> are the start and end of the partition
4013 in I<sectors>.  C<endsect> may be negative, which means it counts
4014 backwards from the end of the disk (C<-1> is the last sector).
4015
4016 Creating a partition which covers the whole disk is not so easy.
4017 Use C<guestfs_part_disk> to do that.");
4018
4019   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4020    [InitEmpty, Always, TestRun (
4021       [["part_disk"; "/dev/sda"; "mbr"]]);
4022     InitEmpty, Always, TestRun (
4023       [["part_disk"; "/dev/sda"; "gpt"]])],
4024    "partition whole disk with a single primary partition",
4025    "\
4026 This command is simply a combination of C<guestfs_part_init>
4027 followed by C<guestfs_part_add> to create a single primary partition
4028 covering the whole disk.
4029
4030 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4031 but other possible values are described in C<guestfs_part_init>.");
4032
4033   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4034    [InitEmpty, Always, TestRun (
4035       [["part_disk"; "/dev/sda"; "mbr"];
4036        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4037    "make a partition bootable",
4038    "\
4039 This sets the bootable flag on partition numbered C<partnum> on
4040 device C<device>.  Note that partitions are numbered from 1.
4041
4042 The bootable flag is used by some PC BIOSes to determine which
4043 partition to boot from.  It is by no means universally recognized,
4044 and in any case if your operating system installed a boot
4045 sector on the device itself, then that takes precedence.");
4046
4047   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4048    [InitEmpty, Always, TestRun (
4049       [["part_disk"; "/dev/sda"; "gpt"];
4050        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4051    "set partition name",
4052    "\
4053 This sets the partition name on partition numbered C<partnum> on
4054 device C<device>.  Note that partitions are numbered from 1.
4055
4056 The partition name can only be set on certain types of partition
4057 table.  This works on C<gpt> but not on C<mbr> partitions.");
4058
4059   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4060    [], (* XXX Add a regression test for this. *)
4061    "list partitions on a device",
4062    "\
4063 This command parses the partition table on C<device> and
4064 returns the list of partitions found.
4065
4066 The fields in the returned structure are:
4067
4068 =over 4
4069
4070 =item B<part_num>
4071
4072 Partition number, counting from 1.
4073
4074 =item B<part_start>
4075
4076 Start of the partition I<in bytes>.  To get sectors you have to
4077 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4078
4079 =item B<part_end>
4080
4081 End of the partition in bytes.
4082
4083 =item B<part_size>
4084
4085 Size of the partition in bytes.
4086
4087 =back");
4088
4089   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4090    [InitEmpty, Always, TestOutput (
4091       [["part_disk"; "/dev/sda"; "gpt"];
4092        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4093    "get the partition table type",
4094    "\
4095 This command examines the partition table on C<device> and
4096 returns the partition table type (format) being used.
4097
4098 Common return values include: C<msdos> (a DOS/Windows style MBR
4099 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4100 values are possible, although unusual.  See C<guestfs_part_init>
4101 for a full list.");
4102
4103   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4104    [InitBasicFS, Always, TestOutputBuffer (
4105       [["fill"; "0x63"; "10"; "/test"];
4106        ["read_file"; "/test"]], "cccccccccc")],
4107    "fill a file with octets",
4108    "\
4109 This command creates a new file called C<path>.  The initial
4110 content of the file is C<len> octets of C<c>, where C<c>
4111 must be a number in the range C<[0..255]>.
4112
4113 To fill a file with zero bytes (sparsely), it is
4114 much more efficient to use C<guestfs_truncate_size>.");
4115
4116   ("available", (RErr, [StringList "groups"]), 216, [],
4117    [InitNone, Always, TestRun [["available"; ""]]],
4118    "test availability of some parts of the API",
4119    "\
4120 This command is used to check the availability of some
4121 groups of functionality in the appliance, which not all builds of
4122 the libguestfs appliance will be able to provide.
4123
4124 The libguestfs groups, and the functions that those
4125 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4126
4127 The argument C<groups> is a list of group names, eg:
4128 C<[\"inotify\", \"augeas\"]> would check for the availability of
4129 the Linux inotify functions and Augeas (configuration file
4130 editing) functions.
4131
4132 The command returns no error if I<all> requested groups are available.
4133
4134 It fails with an error if one or more of the requested
4135 groups is unavailable in the appliance.
4136
4137 If an unknown group name is included in the
4138 list of groups then an error is always returned.
4139
4140 I<Notes:>
4141
4142 =over 4
4143
4144 =item *
4145
4146 You must call C<guestfs_launch> before calling this function.
4147
4148 The reason is because we don't know what groups are
4149 supported by the appliance/daemon until it is running and can
4150 be queried.
4151
4152 =item *
4153
4154 If a group of functions is available, this does not necessarily
4155 mean that they will work.  You still have to check for errors
4156 when calling individual API functions even if they are
4157 available.
4158
4159 =item *
4160
4161 It is usually the job of distro packagers to build
4162 complete functionality into the libguestfs appliance.
4163 Upstream libguestfs, if built from source with all
4164 requirements satisfied, will support everything.
4165
4166 =item *
4167
4168 This call was added in version C<1.0.80>.  In previous
4169 versions of libguestfs all you could do would be to speculatively
4170 execute a command to find out if the daemon implemented it.
4171 See also C<guestfs_version>.
4172
4173 =back");
4174
4175   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4176    [InitBasicFS, Always, TestOutputBuffer (
4177       [["write_file"; "/src"; "hello, world"; "0"];
4178        ["dd"; "/src"; "/dest"];
4179        ["read_file"; "/dest"]], "hello, world")],
4180    "copy from source to destination using dd",
4181    "\
4182 This command copies from one source device or file C<src>
4183 to another destination device or file C<dest>.  Normally you
4184 would use this to copy to or from a device or partition, for
4185 example to duplicate a filesystem.
4186
4187 If the destination is a device, it must be as large or larger
4188 than the source file or device, otherwise the copy will fail.
4189 This command cannot do partial copies.");
4190
4191 ]
4192
4193 let all_functions = non_daemon_functions @ daemon_functions
4194
4195 (* In some places we want the functions to be displayed sorted
4196  * alphabetically, so this is useful:
4197  *)
4198 let all_functions_sorted =
4199   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4200                compare n1 n2) all_functions
4201
4202 (* Field types for structures. *)
4203 type field =
4204   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4205   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4206   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4207   | FUInt32
4208   | FInt32
4209   | FUInt64
4210   | FInt64
4211   | FBytes                      (* Any int measure that counts bytes. *)
4212   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4213   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4214
4215 (* Because we generate extra parsing code for LVM command line tools,
4216  * we have to pull out the LVM columns separately here.
4217  *)
4218 let lvm_pv_cols = [
4219   "pv_name", FString;
4220   "pv_uuid", FUUID;
4221   "pv_fmt", FString;
4222   "pv_size", FBytes;
4223   "dev_size", FBytes;
4224   "pv_free", FBytes;
4225   "pv_used", FBytes;
4226   "pv_attr", FString (* XXX *);
4227   "pv_pe_count", FInt64;
4228   "pv_pe_alloc_count", FInt64;
4229   "pv_tags", FString;
4230   "pe_start", FBytes;
4231   "pv_mda_count", FInt64;
4232   "pv_mda_free", FBytes;
4233   (* Not in Fedora 10:
4234      "pv_mda_size", FBytes;
4235   *)
4236 ]
4237 let lvm_vg_cols = [
4238   "vg_name", FString;
4239   "vg_uuid", FUUID;
4240   "vg_fmt", FString;
4241   "vg_attr", FString (* XXX *);
4242   "vg_size", FBytes;
4243   "vg_free", FBytes;
4244   "vg_sysid", FString;
4245   "vg_extent_size", FBytes;
4246   "vg_extent_count", FInt64;
4247   "vg_free_count", FInt64;
4248   "max_lv", FInt64;
4249   "max_pv", FInt64;
4250   "pv_count", FInt64;
4251   "lv_count", FInt64;
4252   "snap_count", FInt64;
4253   "vg_seqno", FInt64;
4254   "vg_tags", FString;
4255   "vg_mda_count", FInt64;
4256   "vg_mda_free", FBytes;
4257   (* Not in Fedora 10:
4258      "vg_mda_size", FBytes;
4259   *)
4260 ]
4261 let lvm_lv_cols = [
4262   "lv_name", FString;
4263   "lv_uuid", FUUID;
4264   "lv_attr", FString (* XXX *);
4265   "lv_major", FInt64;
4266   "lv_minor", FInt64;
4267   "lv_kernel_major", FInt64;
4268   "lv_kernel_minor", FInt64;
4269   "lv_size", FBytes;
4270   "seg_count", FInt64;
4271   "origin", FString;
4272   "snap_percent", FOptPercent;
4273   "copy_percent", FOptPercent;
4274   "move_pv", FString;
4275   "lv_tags", FString;
4276   "mirror_log", FString;
4277   "modules", FString;
4278 ]
4279
4280 (* Names and fields in all structures (in RStruct and RStructList)
4281  * that we support.
4282  *)
4283 let structs = [
4284   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4285    * not use this struct in any new code.
4286    *)
4287   "int_bool", [
4288     "i", FInt32;                (* for historical compatibility *)
4289     "b", FInt32;                (* for historical compatibility *)
4290   ];
4291
4292   (* LVM PVs, VGs, LVs. *)
4293   "lvm_pv", lvm_pv_cols;
4294   "lvm_vg", lvm_vg_cols;
4295   "lvm_lv", lvm_lv_cols;
4296
4297   (* Column names and types from stat structures.
4298    * NB. Can't use things like 'st_atime' because glibc header files
4299    * define some of these as macros.  Ugh.
4300    *)
4301   "stat", [
4302     "dev", FInt64;
4303     "ino", FInt64;
4304     "mode", FInt64;
4305     "nlink", FInt64;
4306     "uid", FInt64;
4307     "gid", FInt64;
4308     "rdev", FInt64;
4309     "size", FInt64;
4310     "blksize", FInt64;
4311     "blocks", FInt64;
4312     "atime", FInt64;
4313     "mtime", FInt64;
4314     "ctime", FInt64;
4315   ];
4316   "statvfs", [
4317     "bsize", FInt64;
4318     "frsize", FInt64;
4319     "blocks", FInt64;
4320     "bfree", FInt64;
4321     "bavail", FInt64;
4322     "files", FInt64;
4323     "ffree", FInt64;
4324     "favail", FInt64;
4325     "fsid", FInt64;
4326     "flag", FInt64;
4327     "namemax", FInt64;
4328   ];
4329
4330   (* Column names in dirent structure. *)
4331   "dirent", [
4332     "ino", FInt64;
4333     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4334     "ftyp", FChar;
4335     "name", FString;
4336   ];
4337
4338   (* Version numbers. *)
4339   "version", [
4340     "major", FInt64;
4341     "minor", FInt64;
4342     "release", FInt64;
4343     "extra", FString;
4344   ];
4345
4346   (* Extended attribute. *)
4347   "xattr", [
4348     "attrname", FString;
4349     "attrval", FBuffer;
4350   ];
4351
4352   (* Inotify events. *)
4353   "inotify_event", [
4354     "in_wd", FInt64;
4355     "in_mask", FUInt32;
4356     "in_cookie", FUInt32;
4357     "in_name", FString;
4358   ];
4359
4360   (* Partition table entry. *)
4361   "partition", [
4362     "part_num", FInt32;
4363     "part_start", FBytes;
4364     "part_end", FBytes;
4365     "part_size", FBytes;
4366   ];
4367 ] (* end of structs *)
4368
4369 (* Ugh, Java has to be different ..
4370  * These names are also used by the Haskell bindings.
4371  *)
4372 let java_structs = [
4373   "int_bool", "IntBool";
4374   "lvm_pv", "PV";
4375   "lvm_vg", "VG";
4376   "lvm_lv", "LV";
4377   "stat", "Stat";
4378   "statvfs", "StatVFS";
4379   "dirent", "Dirent";
4380   "version", "Version";
4381   "xattr", "XAttr";
4382   "inotify_event", "INotifyEvent";
4383   "partition", "Partition";
4384 ]
4385
4386 (* What structs are actually returned. *)
4387 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4388
4389 (* Returns a list of RStruct/RStructList structs that are returned
4390  * by any function.  Each element of returned list is a pair:
4391  *
4392  * (structname, RStructOnly)
4393  *    == there exists function which returns RStruct (_, structname)
4394  * (structname, RStructListOnly)
4395  *    == there exists function which returns RStructList (_, structname)
4396  * (structname, RStructAndList)
4397  *    == there are functions returning both RStruct (_, structname)
4398  *                                      and RStructList (_, structname)
4399  *)
4400 let rstructs_used_by functions =
4401   (* ||| is a "logical OR" for rstructs_used_t *)
4402   let (|||) a b =
4403     match a, b with
4404     | RStructAndList, _
4405     | _, RStructAndList -> RStructAndList
4406     | RStructOnly, RStructListOnly
4407     | RStructListOnly, RStructOnly -> RStructAndList
4408     | RStructOnly, RStructOnly -> RStructOnly
4409     | RStructListOnly, RStructListOnly -> RStructListOnly
4410   in
4411
4412   let h = Hashtbl.create 13 in
4413
4414   (* if elem->oldv exists, update entry using ||| operator,
4415    * else just add elem->newv to the hash
4416    *)
4417   let update elem newv =
4418     try  let oldv = Hashtbl.find h elem in
4419          Hashtbl.replace h elem (newv ||| oldv)
4420     with Not_found -> Hashtbl.add h elem newv
4421   in
4422
4423   List.iter (
4424     fun (_, style, _, _, _, _, _) ->
4425       match fst style with
4426       | RStruct (_, structname) -> update structname RStructOnly
4427       | RStructList (_, structname) -> update structname RStructListOnly
4428       | _ -> ()
4429   ) functions;
4430
4431   (* return key->values as a list of (key,value) *)
4432   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4433
4434 (* Used for testing language bindings. *)
4435 type callt =
4436   | CallString of string
4437   | CallOptString of string option
4438   | CallStringList of string list
4439   | CallInt of int
4440   | CallInt64 of int64
4441   | CallBool of bool
4442
4443 (* Used to memoize the result of pod2text. *)
4444 let pod2text_memo_filename = "src/.pod2text.data"
4445 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4446   try
4447     let chan = open_in pod2text_memo_filename in
4448     let v = input_value chan in
4449     close_in chan;
4450     v
4451   with
4452     _ -> Hashtbl.create 13
4453 let pod2text_memo_updated () =
4454   let chan = open_out pod2text_memo_filename in
4455   output_value chan pod2text_memo;
4456   close_out chan
4457
4458 (* Useful functions.
4459  * Note we don't want to use any external OCaml libraries which
4460  * makes this a bit harder than it should be.
4461  *)
4462 module StringMap = Map.Make (String)
4463
4464 let failwithf fs = ksprintf failwith fs
4465
4466 let unique = let i = ref 0 in fun () -> incr i; !i
4467
4468 let replace_char s c1 c2 =
4469   let s2 = String.copy s in
4470   let r = ref false in
4471   for i = 0 to String.length s2 - 1 do
4472     if String.unsafe_get s2 i = c1 then (
4473       String.unsafe_set s2 i c2;
4474       r := true
4475     )
4476   done;
4477   if not !r then s else s2
4478
4479 let isspace c =
4480   c = ' '
4481   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4482
4483 let triml ?(test = isspace) str =
4484   let i = ref 0 in
4485   let n = ref (String.length str) in
4486   while !n > 0 && test str.[!i]; do
4487     decr n;
4488     incr i
4489   done;
4490   if !i = 0 then str
4491   else String.sub str !i !n
4492
4493 let trimr ?(test = isspace) str =
4494   let n = ref (String.length str) in
4495   while !n > 0 && test str.[!n-1]; do
4496     decr n
4497   done;
4498   if !n = String.length str then str
4499   else String.sub str 0 !n
4500
4501 let trim ?(test = isspace) str =
4502   trimr ~test (triml ~test str)
4503
4504 let rec find s sub =
4505   let len = String.length s in
4506   let sublen = String.length sub in
4507   let rec loop i =
4508     if i <= len-sublen then (
4509       let rec loop2 j =
4510         if j < sublen then (
4511           if s.[i+j] = sub.[j] then loop2 (j+1)
4512           else -1
4513         ) else
4514           i (* found *)
4515       in
4516       let r = loop2 0 in
4517       if r = -1 then loop (i+1) else r
4518     ) else
4519       -1 (* not found *)
4520   in
4521   loop 0
4522
4523 let rec replace_str s s1 s2 =
4524   let len = String.length s in
4525   let sublen = String.length s1 in
4526   let i = find s s1 in
4527   if i = -1 then s
4528   else (
4529     let s' = String.sub s 0 i in
4530     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4531     s' ^ s2 ^ replace_str s'' s1 s2
4532   )
4533
4534 let rec string_split sep str =
4535   let len = String.length str in
4536   let seplen = String.length sep in
4537   let i = find str sep in
4538   if i = -1 then [str]
4539   else (
4540     let s' = String.sub str 0 i in
4541     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4542     s' :: string_split sep s''
4543   )
4544
4545 let files_equal n1 n2 =
4546   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4547   match Sys.command cmd with
4548   | 0 -> true
4549   | 1 -> false
4550   | i -> failwithf "%s: failed with error code %d" cmd i
4551
4552 let rec filter_map f = function
4553   | [] -> []
4554   | x :: xs ->
4555       match f x with
4556       | Some y -> y :: filter_map f xs
4557       | None -> filter_map f xs
4558
4559 let rec find_map f = function
4560   | [] -> raise Not_found
4561   | x :: xs ->
4562       match f x with
4563       | Some y -> y
4564       | None -> find_map f xs
4565
4566 let iteri f xs =
4567   let rec loop i = function
4568     | [] -> ()
4569     | x :: xs -> f i x; loop (i+1) xs
4570   in
4571   loop 0 xs
4572
4573 let mapi f xs =
4574   let rec loop i = function
4575     | [] -> []
4576     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4577   in
4578   loop 0 xs
4579
4580 let count_chars c str =
4581   let count = ref 0 in
4582   for i = 0 to String.length str - 1 do
4583     if c = String.unsafe_get str i then incr count
4584   done;
4585   !count
4586
4587 let name_of_argt = function
4588   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4589   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4590   | FileIn n | FileOut n -> n
4591
4592 let java_name_of_struct typ =
4593   try List.assoc typ java_structs
4594   with Not_found ->
4595     failwithf
4596       "java_name_of_struct: no java_structs entry corresponding to %s" typ
4597
4598 let cols_of_struct typ =
4599   try List.assoc typ structs
4600   with Not_found ->
4601     failwithf "cols_of_struct: unknown struct %s" typ
4602
4603 let seq_of_test = function
4604   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
4605   | TestOutputListOfDevices (s, _)
4606   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
4607   | TestOutputTrue s | TestOutputFalse s
4608   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
4609   | TestOutputStruct (s, _)
4610   | TestLastFail s -> s
4611
4612 (* Handling for function flags. *)
4613 let protocol_limit_warning =
4614   "Because of the message protocol, there is a transfer limit
4615 of somewhere between 2MB and 4MB.  To transfer large files you should use
4616 FTP."
4617
4618 let danger_will_robinson =
4619   "B<This command is dangerous.  Without careful use you
4620 can easily destroy all your data>."
4621
4622 let deprecation_notice flags =
4623   try
4624     let alt =
4625       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
4626     let txt =
4627       sprintf "This function is deprecated.
4628 In new code, use the C<%s> call instead.
4629
4630 Deprecated functions will not be removed from the API, but the
4631 fact that they are deprecated indicates that there are problems
4632 with correct use of these functions." alt in
4633     Some txt
4634   with
4635     Not_found -> None
4636
4637 (* Create list of optional groups. *)
4638 let optgroups =
4639   let h = Hashtbl.create 13 in
4640   List.iter (
4641     fun (name, _, _, flags, _, _, _) ->
4642       List.iter (
4643         function
4644         | Optional group ->
4645             let names = try Hashtbl.find h group with Not_found -> [] in
4646             Hashtbl.replace h group (name :: names)
4647         | _ -> ()
4648       ) flags
4649   ) daemon_functions;
4650   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
4651   let groups =
4652     List.map (
4653       fun group -> group, List.sort compare (Hashtbl.find h group)
4654     ) groups in
4655   List.sort (fun x y -> compare (fst x) (fst y)) groups
4656
4657 (* Check function names etc. for consistency. *)
4658 let check_functions () =
4659   let contains_uppercase str =
4660     let len = String.length str in
4661     let rec loop i =
4662       if i >= len then false
4663       else (
4664         let c = str.[i] in
4665         if c >= 'A' && c <= 'Z' then true
4666         else loop (i+1)
4667       )
4668     in
4669     loop 0
4670   in
4671
4672   (* Check function names. *)
4673   List.iter (
4674     fun (name, _, _, _, _, _, _) ->
4675       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
4676         failwithf "function name %s does not need 'guestfs' prefix" name;
4677       if name = "" then
4678         failwithf "function name is empty";
4679       if name.[0] < 'a' || name.[0] > 'z' then
4680         failwithf "function name %s must start with lowercase a-z" name;
4681       if String.contains name '-' then
4682         failwithf "function name %s should not contain '-', use '_' instead."
4683           name
4684   ) all_functions;
4685
4686   (* Check function parameter/return names. *)
4687   List.iter (
4688     fun (name, style, _, _, _, _, _) ->
4689       let check_arg_ret_name n =
4690         if contains_uppercase n then
4691           failwithf "%s param/ret %s should not contain uppercase chars"
4692             name n;
4693         if String.contains n '-' || String.contains n '_' then
4694           failwithf "%s param/ret %s should not contain '-' or '_'"
4695             name n;
4696         if n = "value" then
4697           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;
4698         if n = "int" || n = "char" || n = "short" || n = "long" then
4699           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
4700         if n = "i" || n = "n" then
4701           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
4702         if n = "argv" || n = "args" then
4703           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
4704
4705         (* List Haskell, OCaml and C keywords here.
4706          * http://www.haskell.org/haskellwiki/Keywords
4707          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
4708          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
4709          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
4710          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
4711          * Omitting _-containing words, since they're handled above.
4712          * Omitting the OCaml reserved word, "val", is ok,
4713          * and saves us from renaming several parameters.
4714          *)
4715         let reserved = [
4716           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
4717           "char"; "class"; "const"; "constraint"; "continue"; "data";
4718           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
4719           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
4720           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
4721           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
4722           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
4723           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
4724           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
4725           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
4726           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
4727           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
4728           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
4729           "volatile"; "when"; "where"; "while";
4730           ] in
4731         if List.mem n reserved then
4732           failwithf "%s has param/ret using reserved word %s" name n;
4733       in
4734
4735       (match fst style with
4736        | RErr -> ()
4737        | RInt n | RInt64 n | RBool n
4738        | RConstString n | RConstOptString n | RString n
4739        | RStringList n | RStruct (n, _) | RStructList (n, _)
4740        | RHashtable n | RBufferOut n ->
4741            check_arg_ret_name n
4742       );
4743       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
4744   ) all_functions;
4745
4746   (* Check short descriptions. *)
4747   List.iter (
4748     fun (name, _, _, _, _, shortdesc, _) ->
4749       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
4750         failwithf "short description of %s should begin with lowercase." name;
4751       let c = shortdesc.[String.length shortdesc-1] in
4752       if c = '\n' || c = '.' then
4753         failwithf "short description of %s should not end with . or \\n." name
4754   ) all_functions;
4755
4756   (* Check long dscriptions. *)
4757   List.iter (
4758     fun (name, _, _, _, _, _, longdesc) ->
4759       if longdesc.[String.length longdesc-1] = '\n' then
4760         failwithf "long description of %s should not end with \\n." name
4761   ) all_functions;
4762
4763   (* Check proc_nrs. *)
4764   List.iter (
4765     fun (name, _, proc_nr, _, _, _, _) ->
4766       if proc_nr <= 0 then
4767         failwithf "daemon function %s should have proc_nr > 0" name
4768   ) daemon_functions;
4769
4770   List.iter (
4771     fun (name, _, proc_nr, _, _, _, _) ->
4772       if proc_nr <> -1 then
4773         failwithf "non-daemon function %s should have proc_nr -1" name
4774   ) non_daemon_functions;
4775
4776   let proc_nrs =
4777     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
4778       daemon_functions in
4779   let proc_nrs =
4780     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
4781   let rec loop = function
4782     | [] -> ()
4783     | [_] -> ()
4784     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
4785         loop rest
4786     | (name1,nr1) :: (name2,nr2) :: _ ->
4787         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
4788           name1 name2 nr1 nr2
4789   in
4790   loop proc_nrs;
4791
4792   (* Check tests. *)
4793   List.iter (
4794     function
4795       (* Ignore functions that have no tests.  We generate a
4796        * warning when the user does 'make check' instead.
4797        *)
4798     | name, _, _, _, [], _, _ -> ()
4799     | name, _, _, _, tests, _, _ ->
4800         let funcs =
4801           List.map (
4802             fun (_, _, test) ->
4803               match seq_of_test test with
4804               | [] ->
4805                   failwithf "%s has a test containing an empty sequence" name
4806               | cmds -> List.map List.hd cmds
4807           ) tests in
4808         let funcs = List.flatten funcs in
4809
4810         let tested = List.mem name funcs in
4811
4812         if not tested then
4813           failwithf "function %s has tests but does not test itself" name
4814   ) all_functions
4815
4816 (* 'pr' prints to the current output file. *)
4817 let chan = ref Pervasives.stdout
4818 let lines = ref 0
4819 let pr fs =
4820   ksprintf
4821     (fun str ->
4822        let i = count_chars '\n' str in
4823        lines := !lines + i;
4824        output_string !chan str
4825     ) fs
4826
4827 let copyright_years =
4828   let this_year = 1900 + (localtime (time ())).tm_year in
4829   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
4830
4831 (* Generate a header block in a number of standard styles. *)
4832 type comment_style =
4833     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
4834 type license = GPLv2plus | LGPLv2plus
4835
4836 let generate_header ?(extra_inputs = []) comment license =
4837   let inputs = "src/generator.ml" :: extra_inputs in
4838   let c = match comment with
4839     | CStyle ->         pr "/* "; " *"
4840     | CPlusPlusStyle -> pr "// "; "//"
4841     | HashStyle ->      pr "# ";  "#"
4842     | OCamlStyle ->     pr "(* "; " *"
4843     | HaskellStyle ->   pr "{- "; "  " in
4844   pr "libguestfs generated file\n";
4845   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
4846   List.iter (pr "%s   %s\n" c) inputs;
4847   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
4848   pr "%s\n" c;
4849   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
4850   pr "%s\n" c;
4851   (match license with
4852    | GPLv2plus ->
4853        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
4854        pr "%s it under the terms of the GNU General Public License as published by\n" c;
4855        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
4856        pr "%s (at your option) any later version.\n" c;
4857        pr "%s\n" c;
4858        pr "%s This program is distributed in the hope that it will be useful,\n" c;
4859        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4860        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
4861        pr "%s GNU General Public License for more details.\n" c;
4862        pr "%s\n" c;
4863        pr "%s You should have received a copy of the GNU General Public License along\n" c;
4864        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
4865        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
4866
4867    | LGPLv2plus ->
4868        pr "%s This library is free software; you can redistribute it and/or\n" c;
4869        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
4870        pr "%s License as published by the Free Software Foundation; either\n" c;
4871        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
4872        pr "%s\n" c;
4873        pr "%s This library is distributed in the hope that it will be useful,\n" c;
4874        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4875        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
4876        pr "%s Lesser General Public License for more details.\n" c;
4877        pr "%s\n" c;
4878        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
4879        pr "%s License along with this library; if not, write to the Free Software\n" c;
4880        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
4881   );
4882   (match comment with
4883    | CStyle -> pr " */\n"
4884    | CPlusPlusStyle
4885    | HashStyle -> ()
4886    | OCamlStyle -> pr " *)\n"
4887    | HaskellStyle -> pr "-}\n"
4888   );
4889   pr "\n"
4890
4891 (* Start of main code generation functions below this line. *)
4892
4893 (* Generate the pod documentation for the C API. *)
4894 let rec generate_actions_pod () =
4895   List.iter (
4896     fun (shortname, style, _, flags, _, _, longdesc) ->
4897       if not (List.mem NotInDocs flags) then (
4898         let name = "guestfs_" ^ shortname in
4899         pr "=head2 %s\n\n" name;
4900         pr " ";
4901         generate_prototype ~extern:false ~handle:"handle" name style;
4902         pr "\n\n";
4903         pr "%s\n\n" longdesc;
4904         (match fst style with
4905          | RErr ->
4906              pr "This function returns 0 on success or -1 on error.\n\n"
4907          | RInt _ ->
4908              pr "On error this function returns -1.\n\n"
4909          | RInt64 _ ->
4910              pr "On error this function returns -1.\n\n"
4911          | RBool _ ->
4912              pr "This function returns a C truth value on success or -1 on error.\n\n"
4913          | RConstString _ ->
4914              pr "This function returns a string, or NULL on error.
4915 The string is owned by the guest handle and must I<not> be freed.\n\n"
4916          | RConstOptString _ ->
4917              pr "This function returns a string which may be NULL.
4918 There is way to return an error from this function.
4919 The string is owned by the guest handle and must I<not> be freed.\n\n"
4920          | RString _ ->
4921              pr "This function returns a string, or NULL on error.
4922 I<The caller must free the returned string after use>.\n\n"
4923          | RStringList _ ->
4924              pr "This function returns a NULL-terminated array of strings
4925 (like L<environ(3)>), or NULL if there was an error.
4926 I<The caller must free the strings and the array after use>.\n\n"
4927          | RStruct (_, typ) ->
4928              pr "This function returns a C<struct guestfs_%s *>,
4929 or NULL if there was an error.
4930 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
4931          | RStructList (_, typ) ->
4932              pr "This function returns a C<struct guestfs_%s_list *>
4933 (see E<lt>guestfs-structs.hE<gt>),
4934 or NULL if there was an error.
4935 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
4936          | RHashtable _ ->
4937              pr "This function returns a NULL-terminated array of
4938 strings, or NULL if there was an error.
4939 The array of strings will always have length C<2n+1>, where
4940 C<n> keys and values alternate, followed by the trailing NULL entry.
4941 I<The caller must free the strings and the array after use>.\n\n"
4942          | RBufferOut _ ->
4943              pr "This function returns a buffer, or NULL on error.
4944 The size of the returned buffer is written to C<*size_r>.
4945 I<The caller must free the returned buffer after use>.\n\n"
4946         );
4947         if List.mem ProtocolLimitWarning flags then
4948           pr "%s\n\n" protocol_limit_warning;
4949         if List.mem DangerWillRobinson flags then
4950           pr "%s\n\n" danger_will_robinson;
4951         match deprecation_notice flags with
4952         | None -> ()
4953         | Some txt -> pr "%s\n\n" txt
4954       )
4955   ) all_functions_sorted
4956
4957 and generate_structs_pod () =
4958   (* Structs documentation. *)
4959   List.iter (
4960     fun (typ, cols) ->
4961       pr "=head2 guestfs_%s\n" typ;
4962       pr "\n";
4963       pr " struct guestfs_%s {\n" typ;
4964       List.iter (
4965         function
4966         | name, FChar -> pr "   char %s;\n" name
4967         | name, FUInt32 -> pr "   uint32_t %s;\n" name
4968         | name, FInt32 -> pr "   int32_t %s;\n" name
4969         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
4970         | name, FInt64 -> pr "   int64_t %s;\n" name
4971         | name, FString -> pr "   char *%s;\n" name
4972         | name, FBuffer ->
4973             pr "   /* The next two fields describe a byte array. */\n";
4974             pr "   uint32_t %s_len;\n" name;
4975             pr "   char *%s;\n" name
4976         | name, FUUID ->
4977             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
4978             pr "   char %s[32];\n" name
4979         | name, FOptPercent ->
4980             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
4981             pr "   float %s;\n" name
4982       ) cols;
4983       pr " };\n";
4984       pr " \n";
4985       pr " struct guestfs_%s_list {\n" typ;
4986       pr "   uint32_t len; /* Number of elements in list. */\n";
4987       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
4988       pr " };\n";
4989       pr " \n";
4990       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
4991       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
4992         typ typ;
4993       pr "\n"
4994   ) structs
4995
4996 and generate_availability_pod () =
4997   (* Availability documentation. *)
4998   pr "=over 4\n";
4999   pr "\n";
5000   List.iter (
5001     fun (group, functions) ->
5002       pr "=item B<%s>\n" group;
5003       pr "\n";
5004       pr "The following functions:\n";
5005       List.iter (pr "L</guestfs_%s>\n") functions;
5006       pr "\n"
5007   ) optgroups;
5008   pr "=back\n";
5009   pr "\n"
5010
5011 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5012  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5013  *
5014  * We have to use an underscore instead of a dash because otherwise
5015  * rpcgen generates incorrect code.
5016  *
5017  * This header is NOT exported to clients, but see also generate_structs_h.
5018  *)
5019 and generate_xdr () =
5020   generate_header CStyle LGPLv2plus;
5021
5022   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5023   pr "typedef string str<>;\n";
5024   pr "\n";
5025
5026   (* Internal structures. *)
5027   List.iter (
5028     function
5029     | typ, cols ->
5030         pr "struct guestfs_int_%s {\n" typ;
5031         List.iter (function
5032                    | name, FChar -> pr "  char %s;\n" name
5033                    | name, FString -> pr "  string %s<>;\n" name
5034                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5035                    | name, FUUID -> pr "  opaque %s[32];\n" name
5036                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5037                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5038                    | name, FOptPercent -> pr "  float %s;\n" name
5039                   ) cols;
5040         pr "};\n";
5041         pr "\n";
5042         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5043         pr "\n";
5044   ) structs;
5045
5046   List.iter (
5047     fun (shortname, style, _, _, _, _, _) ->
5048       let name = "guestfs_" ^ shortname in
5049
5050       (match snd style with
5051        | [] -> ()
5052        | args ->
5053            pr "struct %s_args {\n" name;
5054            List.iter (
5055              function
5056              | Pathname n | Device n | Dev_or_Path n | String n ->
5057                  pr "  string %s<>;\n" n
5058              | OptString n -> pr "  str *%s;\n" n
5059              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5060              | Bool n -> pr "  bool %s;\n" n
5061              | Int n -> pr "  int %s;\n" n
5062              | Int64 n -> pr "  hyper %s;\n" n
5063              | FileIn _ | FileOut _ -> ()
5064            ) args;
5065            pr "};\n\n"
5066       );
5067       (match fst style with
5068        | RErr -> ()
5069        | RInt n ->
5070            pr "struct %s_ret {\n" name;
5071            pr "  int %s;\n" n;
5072            pr "};\n\n"
5073        | RInt64 n ->
5074            pr "struct %s_ret {\n" name;
5075            pr "  hyper %s;\n" n;
5076            pr "};\n\n"
5077        | RBool n ->
5078            pr "struct %s_ret {\n" name;
5079            pr "  bool %s;\n" n;
5080            pr "};\n\n"
5081        | RConstString _ | RConstOptString _ ->
5082            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5083        | RString n ->
5084            pr "struct %s_ret {\n" name;
5085            pr "  string %s<>;\n" n;
5086            pr "};\n\n"
5087        | RStringList n ->
5088            pr "struct %s_ret {\n" name;
5089            pr "  str %s<>;\n" n;
5090            pr "};\n\n"
5091        | RStruct (n, typ) ->
5092            pr "struct %s_ret {\n" name;
5093            pr "  guestfs_int_%s %s;\n" typ n;
5094            pr "};\n\n"
5095        | RStructList (n, typ) ->
5096            pr "struct %s_ret {\n" name;
5097            pr "  guestfs_int_%s_list %s;\n" typ n;
5098            pr "};\n\n"
5099        | RHashtable n ->
5100            pr "struct %s_ret {\n" name;
5101            pr "  str %s<>;\n" n;
5102            pr "};\n\n"
5103        | RBufferOut n ->
5104            pr "struct %s_ret {\n" name;
5105            pr "  opaque %s<>;\n" n;
5106            pr "};\n\n"
5107       );
5108   ) daemon_functions;
5109
5110   (* Table of procedure numbers. *)
5111   pr "enum guestfs_procedure {\n";
5112   List.iter (
5113     fun (shortname, _, proc_nr, _, _, _, _) ->
5114       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5115   ) daemon_functions;
5116   pr "  GUESTFS_PROC_NR_PROCS\n";
5117   pr "};\n";
5118   pr "\n";
5119
5120   (* Having to choose a maximum message size is annoying for several
5121    * reasons (it limits what we can do in the API), but it (a) makes
5122    * the protocol a lot simpler, and (b) provides a bound on the size
5123    * of the daemon which operates in limited memory space.  For large
5124    * file transfers you should use FTP.
5125    *)
5126   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5127   pr "\n";
5128
5129   (* Message header, etc. *)
5130   pr "\
5131 /* The communication protocol is now documented in the guestfs(3)
5132  * manpage.
5133  */
5134
5135 const GUESTFS_PROGRAM = 0x2000F5F5;
5136 const GUESTFS_PROTOCOL_VERSION = 1;
5137
5138 /* These constants must be larger than any possible message length. */
5139 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5140 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5141
5142 enum guestfs_message_direction {
5143   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5144   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5145 };
5146
5147 enum guestfs_message_status {
5148   GUESTFS_STATUS_OK = 0,
5149   GUESTFS_STATUS_ERROR = 1
5150 };
5151
5152 const GUESTFS_ERROR_LEN = 256;
5153
5154 struct guestfs_message_error {
5155   string error_message<GUESTFS_ERROR_LEN>;
5156 };
5157
5158 struct guestfs_message_header {
5159   unsigned prog;                     /* GUESTFS_PROGRAM */
5160   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5161   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5162   guestfs_message_direction direction;
5163   unsigned serial;                   /* message serial number */
5164   guestfs_message_status status;
5165 };
5166
5167 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5168
5169 struct guestfs_chunk {
5170   int cancel;                        /* if non-zero, transfer is cancelled */
5171   /* data size is 0 bytes if the transfer has finished successfully */
5172   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5173 };
5174 "
5175
5176 (* Generate the guestfs-structs.h file. *)
5177 and generate_structs_h () =
5178   generate_header CStyle LGPLv2plus;
5179
5180   (* This is a public exported header file containing various
5181    * structures.  The structures are carefully written to have
5182    * exactly the same in-memory format as the XDR structures that
5183    * we use on the wire to the daemon.  The reason for creating
5184    * copies of these structures here is just so we don't have to
5185    * export the whole of guestfs_protocol.h (which includes much
5186    * unrelated and XDR-dependent stuff that we don't want to be
5187    * public, or required by clients).
5188    *
5189    * To reiterate, we will pass these structures to and from the
5190    * client with a simple assignment or memcpy, so the format
5191    * must be identical to what rpcgen / the RFC defines.
5192    *)
5193
5194   (* Public structures. *)
5195   List.iter (
5196     fun (typ, cols) ->
5197       pr "struct guestfs_%s {\n" typ;
5198       List.iter (
5199         function
5200         | name, FChar -> pr "  char %s;\n" name
5201         | name, FString -> pr "  char *%s;\n" name
5202         | name, FBuffer ->
5203             pr "  uint32_t %s_len;\n" name;
5204             pr "  char *%s;\n" name
5205         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5206         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5207         | name, FInt32 -> pr "  int32_t %s;\n" name
5208         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5209         | name, FInt64 -> pr "  int64_t %s;\n" name
5210         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5211       ) cols;
5212       pr "};\n";
5213       pr "\n";
5214       pr "struct guestfs_%s_list {\n" typ;
5215       pr "  uint32_t len;\n";
5216       pr "  struct guestfs_%s *val;\n" typ;
5217       pr "};\n";
5218       pr "\n";
5219       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5220       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5221       pr "\n"
5222   ) structs
5223
5224 (* Generate the guestfs-actions.h file. *)
5225 and generate_actions_h () =
5226   generate_header CStyle LGPLv2plus;
5227   List.iter (
5228     fun (shortname, style, _, _, _, _, _) ->
5229       let name = "guestfs_" ^ shortname in
5230       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5231         name style
5232   ) all_functions
5233
5234 (* Generate the guestfs-internal-actions.h file. *)
5235 and generate_internal_actions_h () =
5236   generate_header CStyle LGPLv2plus;
5237   List.iter (
5238     fun (shortname, style, _, _, _, _, _) ->
5239       let name = "guestfs__" ^ shortname in
5240       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5241         name style
5242   ) non_daemon_functions
5243
5244 (* Generate the client-side dispatch stubs. *)
5245 and generate_client_actions () =
5246   generate_header CStyle LGPLv2plus;
5247
5248   pr "\
5249 #include <stdio.h>
5250 #include <stdlib.h>
5251 #include <stdint.h>
5252 #include <inttypes.h>
5253
5254 #include \"guestfs.h\"
5255 #include \"guestfs-internal.h\"
5256 #include \"guestfs-internal-actions.h\"
5257 #include \"guestfs_protocol.h\"
5258
5259 #define error guestfs_error
5260 //#define perrorf guestfs_perrorf
5261 #define safe_malloc guestfs_safe_malloc
5262 #define safe_realloc guestfs_safe_realloc
5263 //#define safe_strdup guestfs_safe_strdup
5264 #define safe_memdup guestfs_safe_memdup
5265
5266 /* Check the return message from a call for validity. */
5267 static int
5268 check_reply_header (guestfs_h *g,
5269                     const struct guestfs_message_header *hdr,
5270                     unsigned int proc_nr, unsigned int serial)
5271 {
5272   if (hdr->prog != GUESTFS_PROGRAM) {
5273     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5274     return -1;
5275   }
5276   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5277     error (g, \"wrong protocol version (%%d/%%d)\",
5278            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5279     return -1;
5280   }
5281   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5282     error (g, \"unexpected message direction (%%d/%%d)\",
5283            hdr->direction, GUESTFS_DIRECTION_REPLY);
5284     return -1;
5285   }
5286   if (hdr->proc != proc_nr) {
5287     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5288     return -1;
5289   }
5290   if (hdr->serial != serial) {
5291     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5292     return -1;
5293   }
5294
5295   return 0;
5296 }
5297
5298 /* Check we are in the right state to run a high-level action. */
5299 static int
5300 check_state (guestfs_h *g, const char *caller)
5301 {
5302   if (!guestfs__is_ready (g)) {
5303     if (guestfs__is_config (g) || guestfs__is_launching (g))
5304       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5305         caller);
5306     else
5307       error (g, \"%%s called from the wrong state, %%d != READY\",
5308         caller, guestfs__get_state (g));
5309     return -1;
5310   }
5311   return 0;
5312 }
5313
5314 ";
5315
5316   (* Generate code to generate guestfish call traces. *)
5317   let trace_call shortname style =
5318     pr "  if (guestfs__get_trace (g)) {\n";
5319
5320     let needs_i =
5321       List.exists (function
5322                    | StringList _ | DeviceList _ -> true
5323                    | _ -> false) (snd style) in
5324     if needs_i then (
5325       pr "    int i;\n";
5326       pr "\n"
5327     );
5328
5329     pr "    printf (\"%s\");\n" shortname;
5330     List.iter (
5331       function
5332       | String n                        (* strings *)
5333       | Device n
5334       | Pathname n
5335       | Dev_or_Path n
5336       | FileIn n
5337       | FileOut n ->
5338           (* guestfish doesn't support string escaping, so neither do we *)
5339           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5340       | OptString n ->                  (* string option *)
5341           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5342           pr "    else printf (\" null\");\n"
5343       | StringList n
5344       | DeviceList n ->                 (* string list *)
5345           pr "    putchar (' ');\n";
5346           pr "    putchar ('\"');\n";
5347           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5348           pr "      if (i > 0) putchar (' ');\n";
5349           pr "      fputs (%s[i], stdout);\n" n;
5350           pr "    }\n";
5351           pr "    putchar ('\"');\n";
5352       | Bool n ->                       (* boolean *)
5353           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5354       | Int n ->                        (* int *)
5355           pr "    printf (\" %%d\", %s);\n" n
5356       | Int64 n ->
5357           pr "    printf (\" %%\" PRIi64, %s);\n" n
5358     ) (snd style);
5359     pr "    putchar ('\\n');\n";
5360     pr "  }\n";
5361     pr "\n";
5362   in
5363
5364   (* For non-daemon functions, generate a wrapper around each function. *)
5365   List.iter (
5366     fun (shortname, style, _, _, _, _, _) ->
5367       let name = "guestfs_" ^ shortname in
5368
5369       generate_prototype ~extern:false ~semicolon:false ~newline:true
5370         ~handle:"g" name style;
5371       pr "{\n";
5372       trace_call shortname style;
5373       pr "  return guestfs__%s " shortname;
5374       generate_c_call_args ~handle:"g" style;
5375       pr ";\n";
5376       pr "}\n";
5377       pr "\n"
5378   ) non_daemon_functions;
5379
5380   (* Client-side stubs for each function. *)
5381   List.iter (
5382     fun (shortname, style, _, _, _, _, _) ->
5383       let name = "guestfs_" ^ shortname in
5384
5385       (* Generate the action stub. *)
5386       generate_prototype ~extern:false ~semicolon:false ~newline:true
5387         ~handle:"g" name style;
5388
5389       let error_code =
5390         match fst style with
5391         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5392         | RConstString _ | RConstOptString _ ->
5393             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5394         | RString _ | RStringList _
5395         | RStruct _ | RStructList _
5396         | RHashtable _ | RBufferOut _ ->
5397             "NULL" in
5398
5399       pr "{\n";
5400
5401       (match snd style with
5402        | [] -> ()
5403        | _ -> pr "  struct %s_args args;\n" name
5404       );
5405
5406       pr "  guestfs_message_header hdr;\n";
5407       pr "  guestfs_message_error err;\n";
5408       let has_ret =
5409         match fst style with
5410         | RErr -> false
5411         | RConstString _ | RConstOptString _ ->
5412             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5413         | RInt _ | RInt64 _
5414         | RBool _ | RString _ | RStringList _
5415         | RStruct _ | RStructList _
5416         | RHashtable _ | RBufferOut _ ->
5417             pr "  struct %s_ret ret;\n" name;
5418             true in
5419
5420       pr "  int serial;\n";
5421       pr "  int r;\n";
5422       pr "\n";
5423       trace_call shortname style;
5424       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
5425       pr "  guestfs___set_busy (g);\n";
5426       pr "\n";
5427
5428       (* Send the main header and arguments. *)
5429       (match snd style with
5430        | [] ->
5431            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5432              (String.uppercase shortname)
5433        | args ->
5434            List.iter (
5435              function
5436              | Pathname n | Device n | Dev_or_Path n | String n ->
5437                  pr "  args.%s = (char *) %s;\n" n n
5438              | OptString n ->
5439                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5440              | StringList n | DeviceList n ->
5441                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5442                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5443              | Bool n ->
5444                  pr "  args.%s = %s;\n" n n
5445              | Int n ->
5446                  pr "  args.%s = %s;\n" n n
5447              | Int64 n ->
5448                  pr "  args.%s = %s;\n" n n
5449              | FileIn _ | FileOut _ -> ()
5450            ) args;
5451            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5452              (String.uppercase shortname);
5453            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5454              name;
5455       );
5456       pr "  if (serial == -1) {\n";
5457       pr "    guestfs___end_busy (g);\n";
5458       pr "    return %s;\n" error_code;
5459       pr "  }\n";
5460       pr "\n";
5461
5462       (* Send any additional files (FileIn) requested. *)
5463       let need_read_reply_label = ref false in
5464       List.iter (
5465         function
5466         | FileIn n ->
5467             pr "  r = guestfs___send_file (g, %s);\n" n;
5468             pr "  if (r == -1) {\n";
5469             pr "    guestfs___end_busy (g);\n";
5470             pr "    return %s;\n" error_code;
5471             pr "  }\n";
5472             pr "  if (r == -2) /* daemon cancelled */\n";
5473             pr "    goto read_reply;\n";
5474             need_read_reply_label := true;
5475             pr "\n";
5476         | _ -> ()
5477       ) (snd style);
5478
5479       (* Wait for the reply from the remote end. *)
5480       if !need_read_reply_label then pr " read_reply:\n";
5481       pr "  memset (&hdr, 0, sizeof hdr);\n";
5482       pr "  memset (&err, 0, sizeof err);\n";
5483       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5484       pr "\n";
5485       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5486       if not has_ret then
5487         pr "NULL, NULL"
5488       else
5489         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5490       pr ");\n";
5491
5492       pr "  if (r == -1) {\n";
5493       pr "    guestfs___end_busy (g);\n";
5494       pr "    return %s;\n" error_code;
5495       pr "  }\n";
5496       pr "\n";
5497
5498       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5499         (String.uppercase shortname);
5500       pr "    guestfs___end_busy (g);\n";
5501       pr "    return %s;\n" error_code;
5502       pr "  }\n";
5503       pr "\n";
5504
5505       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5506       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5507       pr "    free (err.error_message);\n";
5508       pr "    guestfs___end_busy (g);\n";
5509       pr "    return %s;\n" error_code;
5510       pr "  }\n";
5511       pr "\n";
5512
5513       (* Expecting to receive further files (FileOut)? *)
5514       List.iter (
5515         function
5516         | FileOut n ->
5517             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5518             pr "    guestfs___end_busy (g);\n";
5519             pr "    return %s;\n" error_code;
5520             pr "  }\n";
5521             pr "\n";
5522         | _ -> ()
5523       ) (snd style);
5524
5525       pr "  guestfs___end_busy (g);\n";
5526
5527       (match fst style with
5528        | RErr -> pr "  return 0;\n"
5529        | RInt n | RInt64 n | RBool n ->
5530            pr "  return ret.%s;\n" n
5531        | RConstString _ | RConstOptString _ ->
5532            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5533        | RString n ->
5534            pr "  return ret.%s; /* caller will free */\n" n
5535        | RStringList n | RHashtable n ->
5536            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5537            pr "  ret.%s.%s_val =\n" n n;
5538            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5539            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5540              n n;
5541            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5542            pr "  return ret.%s.%s_val;\n" n n
5543        | RStruct (n, _) ->
5544            pr "  /* caller will free this */\n";
5545            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5546        | RStructList (n, _) ->
5547            pr "  /* caller will free this */\n";
5548            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5549        | RBufferOut n ->
5550            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5551            pr "   * _val might be NULL here.  To make the API saner for\n";
5552            pr "   * callers, we turn this case into a unique pointer (using\n";
5553            pr "   * malloc(1)).\n";
5554            pr "   */\n";
5555            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5556            pr "    *size_r = ret.%s.%s_len;\n" n n;
5557            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5558            pr "  } else {\n";
5559            pr "    free (ret.%s.%s_val);\n" n n;
5560            pr "    char *p = safe_malloc (g, 1);\n";
5561            pr "    *size_r = ret.%s.%s_len;\n" n n;
5562            pr "    return p;\n";
5563            pr "  }\n";
5564       );
5565
5566       pr "}\n\n"
5567   ) daemon_functions;
5568
5569   (* Functions to free structures. *)
5570   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5571   pr " * structure format is identical to the XDR format.  See note in\n";
5572   pr " * generator.ml.\n";
5573   pr " */\n";
5574   pr "\n";
5575
5576   List.iter (
5577     fun (typ, _) ->
5578       pr "void\n";
5579       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5580       pr "{\n";
5581       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5582       pr "  free (x);\n";
5583       pr "}\n";
5584       pr "\n";
5585
5586       pr "void\n";
5587       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5588       pr "{\n";
5589       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
5590       pr "  free (x);\n";
5591       pr "}\n";
5592       pr "\n";
5593
5594   ) structs;
5595
5596 (* Generate daemon/actions.h. *)
5597 and generate_daemon_actions_h () =
5598   generate_header CStyle GPLv2plus;
5599
5600   pr "#include \"../src/guestfs_protocol.h\"\n";
5601   pr "\n";
5602
5603   List.iter (
5604     fun (name, style, _, _, _, _, _) ->
5605       generate_prototype
5606         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
5607         name style;
5608   ) daemon_functions
5609
5610 (* Generate the server-side stubs. *)
5611 and generate_daemon_actions () =
5612   generate_header CStyle GPLv2plus;
5613
5614   pr "#include <config.h>\n";
5615   pr "\n";
5616   pr "#include <stdio.h>\n";
5617   pr "#include <stdlib.h>\n";
5618   pr "#include <string.h>\n";
5619   pr "#include <inttypes.h>\n";
5620   pr "#include <rpc/types.h>\n";
5621   pr "#include <rpc/xdr.h>\n";
5622   pr "\n";
5623   pr "#include \"daemon.h\"\n";
5624   pr "#include \"c-ctype.h\"\n";
5625   pr "#include \"../src/guestfs_protocol.h\"\n";
5626   pr "#include \"actions.h\"\n";
5627   pr "\n";
5628
5629   List.iter (
5630     fun (name, style, _, _, _, _, _) ->
5631       (* Generate server-side stubs. *)
5632       pr "static void %s_stub (XDR *xdr_in)\n" name;
5633       pr "{\n";
5634       let error_code =
5635         match fst style with
5636         | RErr | RInt _ -> pr "  int r;\n"; "-1"
5637         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5638         | RBool _ -> pr "  int r;\n"; "-1"
5639         | RConstString _ | RConstOptString _ ->
5640             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5641         | RString _ -> pr "  char *r;\n"; "NULL"
5642         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5643         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
5644         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
5645         | RBufferOut _ ->
5646             pr "  size_t size = 1;\n";
5647             pr "  char *r;\n";
5648             "NULL" in
5649
5650       (match snd style with
5651        | [] -> ()
5652        | args ->
5653            pr "  struct guestfs_%s_args args;\n" name;
5654            List.iter (
5655              function
5656              | Device n | Dev_or_Path n
5657              | Pathname n
5658              | String n -> ()
5659              | OptString n -> pr "  char *%s;\n" n
5660              | StringList n | DeviceList n -> pr "  char **%s;\n" n
5661              | Bool n -> pr "  int %s;\n" n
5662              | Int n -> pr "  int %s;\n" n
5663              | Int64 n -> pr "  int64_t %s;\n" n
5664              | FileIn _ | FileOut _ -> ()
5665            ) args
5666       );
5667       pr "\n";
5668
5669       (match snd style with
5670        | [] -> ()
5671        | args ->
5672            pr "  memset (&args, 0, sizeof args);\n";
5673            pr "\n";
5674            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
5675            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
5676            pr "    return;\n";
5677            pr "  }\n";
5678            let pr_args n =
5679              pr "  char *%s = args.%s;\n" n n
5680            in
5681            let pr_list_handling_code n =
5682              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
5683              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
5684              pr "  if (%s == NULL) {\n" n;
5685              pr "    reply_with_perror (\"realloc\");\n";
5686              pr "    goto done;\n";
5687              pr "  }\n";
5688              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
5689              pr "  args.%s.%s_val = %s;\n" n n n;
5690            in
5691            List.iter (
5692              function
5693              | Pathname n ->
5694                  pr_args n;
5695                  pr "  ABS_PATH (%s, goto done);\n" n;
5696              | Device n ->
5697                  pr_args n;
5698                  pr "  RESOLVE_DEVICE (%s, goto done);\n" n;
5699              | Dev_or_Path n ->
5700                  pr_args n;
5701                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n;
5702              | String n -> pr_args n
5703              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
5704              | StringList n ->
5705                  pr_list_handling_code n;
5706              | DeviceList n ->
5707                  pr_list_handling_code n;
5708                  pr "  /* Ensure that each is a device,\n";
5709                  pr "   * and perform device name translation. */\n";
5710                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
5711                  pr "    RESOLVE_DEVICE (physvols[pvi], goto done);\n";
5712                  pr "  }\n";
5713              | Bool n -> pr "  %s = args.%s;\n" n n
5714              | Int n -> pr "  %s = args.%s;\n" n n
5715              | Int64 n -> pr "  %s = args.%s;\n" n n
5716              | FileIn _ | FileOut _ -> ()
5717            ) args;
5718            pr "\n"
5719       );
5720
5721
5722       (* this is used at least for do_equal *)
5723       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
5724         (* Emit NEED_ROOT just once, even when there are two or
5725            more Pathname args *)
5726         pr "  NEED_ROOT (goto done);\n";
5727       );
5728
5729       (* Don't want to call the impl with any FileIn or FileOut
5730        * parameters, since these go "outside" the RPC protocol.
5731        *)
5732       let args' =
5733         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
5734           (snd style) in
5735       pr "  r = do_%s " name;
5736       generate_c_call_args (fst style, args');
5737       pr ";\n";
5738
5739       (match fst style with
5740        | RErr | RInt _ | RInt64 _ | RBool _
5741        | RConstString _ | RConstOptString _
5742        | RString _ | RStringList _ | RHashtable _
5743        | RStruct (_, _) | RStructList (_, _) ->
5744            pr "  if (r == %s)\n" error_code;
5745            pr "    /* do_%s has already called reply_with_error */\n" name;
5746            pr "    goto done;\n";
5747            pr "\n"
5748        | RBufferOut _ ->
5749            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
5750            pr "   * an ordinary zero-length buffer), so be careful ...\n";
5751            pr "   */\n";
5752            pr "  if (size == 1 && r == %s)\n" error_code;
5753            pr "    /* do_%s has already called reply_with_error */\n" name;
5754            pr "    goto done;\n";
5755            pr "\n"
5756       );
5757
5758       (* If there are any FileOut parameters, then the impl must
5759        * send its own reply.
5760        *)
5761       let no_reply =
5762         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
5763       if no_reply then
5764         pr "  /* do_%s has already sent a reply */\n" name
5765       else (
5766         match fst style with
5767         | RErr -> pr "  reply (NULL, NULL);\n"
5768         | RInt n | RInt64 n | RBool n ->
5769             pr "  struct guestfs_%s_ret ret;\n" name;
5770             pr "  ret.%s = r;\n" n;
5771             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5772               name
5773         | RConstString _ | RConstOptString _ ->
5774             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5775         | RString n ->
5776             pr "  struct guestfs_%s_ret ret;\n" name;
5777             pr "  ret.%s = r;\n" n;
5778             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5779               name;
5780             pr "  free (r);\n"
5781         | RStringList n | RHashtable n ->
5782             pr "  struct guestfs_%s_ret ret;\n" name;
5783             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
5784             pr "  ret.%s.%s_val = r;\n" n n;
5785             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5786               name;
5787             pr "  free_strings (r);\n"
5788         | RStruct (n, _) ->
5789             pr "  struct guestfs_%s_ret ret;\n" name;
5790             pr "  ret.%s = *r;\n" n;
5791             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5792               name;
5793             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5794               name
5795         | RStructList (n, _) ->
5796             pr "  struct guestfs_%s_ret ret;\n" name;
5797             pr "  ret.%s = *r;\n" n;
5798             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5799               name;
5800             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5801               name
5802         | RBufferOut n ->
5803             pr "  struct guestfs_%s_ret ret;\n" name;
5804             pr "  ret.%s.%s_val = r;\n" n n;
5805             pr "  ret.%s.%s_len = size;\n" n n;
5806             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5807               name;
5808             pr "  free (r);\n"
5809       );
5810
5811       (* Free the args. *)
5812       (match snd style with
5813        | [] ->
5814            pr "done: ;\n";
5815        | _ ->
5816            pr "done:\n";
5817            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
5818              name
5819       );
5820
5821       pr "}\n\n";
5822   ) daemon_functions;
5823
5824   (* Dispatch function. *)
5825   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
5826   pr "{\n";
5827   pr "  switch (proc_nr) {\n";
5828
5829   List.iter (
5830     fun (name, style, _, _, _, _, _) ->
5831       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
5832       pr "      %s_stub (xdr_in);\n" name;
5833       pr "      break;\n"
5834   ) daemon_functions;
5835
5836   pr "    default:\n";
5837   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";
5838   pr "  }\n";
5839   pr "}\n";
5840   pr "\n";
5841
5842   (* LVM columns and tokenization functions. *)
5843   (* XXX This generates crap code.  We should rethink how we
5844    * do this parsing.
5845    *)
5846   List.iter (
5847     function
5848     | typ, cols ->
5849         pr "static const char *lvm_%s_cols = \"%s\";\n"
5850           typ (String.concat "," (List.map fst cols));
5851         pr "\n";
5852
5853         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
5854         pr "{\n";
5855         pr "  char *tok, *p, *next;\n";
5856         pr "  int i, j;\n";
5857         pr "\n";
5858         (*
5859           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
5860           pr "\n";
5861         *)
5862         pr "  if (!str) {\n";
5863         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
5864         pr "    return -1;\n";
5865         pr "  }\n";
5866         pr "  if (!*str || c_isspace (*str)) {\n";
5867         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
5868         pr "    return -1;\n";
5869         pr "  }\n";
5870         pr "  tok = str;\n";
5871         List.iter (
5872           fun (name, coltype) ->
5873             pr "  if (!tok) {\n";
5874             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
5875             pr "    return -1;\n";
5876             pr "  }\n";
5877             pr "  p = strchrnul (tok, ',');\n";
5878             pr "  if (*p) next = p+1; else next = NULL;\n";
5879             pr "  *p = '\\0';\n";
5880             (match coltype with
5881              | FString ->
5882                  pr "  r->%s = strdup (tok);\n" name;
5883                  pr "  if (r->%s == NULL) {\n" name;
5884                  pr "    perror (\"strdup\");\n";
5885                  pr "    return -1;\n";
5886                  pr "  }\n"
5887              | FUUID ->
5888                  pr "  for (i = j = 0; i < 32; ++j) {\n";
5889                  pr "    if (tok[j] == '\\0') {\n";
5890                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
5891                  pr "      return -1;\n";
5892                  pr "    } else if (tok[j] != '-')\n";
5893                  pr "      r->%s[i++] = tok[j];\n" name;
5894                  pr "  }\n";
5895              | FBytes ->
5896                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
5897                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5898                  pr "    return -1;\n";
5899                  pr "  }\n";
5900              | FInt64 ->
5901                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
5902                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5903                  pr "    return -1;\n";
5904                  pr "  }\n";
5905              | FOptPercent ->
5906                  pr "  if (tok[0] == '\\0')\n";
5907                  pr "    r->%s = -1;\n" name;
5908                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
5909                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5910                  pr "    return -1;\n";
5911                  pr "  }\n";
5912              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
5913                  assert false (* can never be an LVM column *)
5914             );
5915             pr "  tok = next;\n";
5916         ) cols;
5917
5918         pr "  if (tok != NULL) {\n";
5919         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
5920         pr "    return -1;\n";
5921         pr "  }\n";
5922         pr "  return 0;\n";
5923         pr "}\n";
5924         pr "\n";
5925
5926         pr "guestfs_int_lvm_%s_list *\n" typ;
5927         pr "parse_command_line_%ss (void)\n" typ;
5928         pr "{\n";
5929         pr "  char *out, *err;\n";
5930         pr "  char *p, *pend;\n";
5931         pr "  int r, i;\n";
5932         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
5933         pr "  void *newp;\n";
5934         pr "\n";
5935         pr "  ret = malloc (sizeof *ret);\n";
5936         pr "  if (!ret) {\n";
5937         pr "    reply_with_perror (\"malloc\");\n";
5938         pr "    return NULL;\n";
5939         pr "  }\n";
5940         pr "\n";
5941         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
5942         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
5943         pr "\n";
5944         pr "  r = command (&out, &err,\n";
5945         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
5946         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
5947         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
5948         pr "  if (r == -1) {\n";
5949         pr "    reply_with_error (\"%%s\", err);\n";
5950         pr "    free (out);\n";
5951         pr "    free (err);\n";
5952         pr "    free (ret);\n";
5953         pr "    return NULL;\n";
5954         pr "  }\n";
5955         pr "\n";
5956         pr "  free (err);\n";
5957         pr "\n";
5958         pr "  /* Tokenize each line of the output. */\n";
5959         pr "  p = out;\n";
5960         pr "  i = 0;\n";
5961         pr "  while (p) {\n";
5962         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
5963         pr "    if (pend) {\n";
5964         pr "      *pend = '\\0';\n";
5965         pr "      pend++;\n";
5966         pr "    }\n";
5967         pr "\n";
5968         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
5969         pr "      p++;\n";
5970         pr "\n";
5971         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
5972         pr "      p = pend;\n";
5973         pr "      continue;\n";
5974         pr "    }\n";
5975         pr "\n";
5976         pr "    /* Allocate some space to store this next entry. */\n";
5977         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
5978         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
5979         pr "    if (newp == NULL) {\n";
5980         pr "      reply_with_perror (\"realloc\");\n";
5981         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5982         pr "      free (ret);\n";
5983         pr "      free (out);\n";
5984         pr "      return NULL;\n";
5985         pr "    }\n";
5986         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
5987         pr "\n";
5988         pr "    /* Tokenize the next entry. */\n";
5989         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
5990         pr "    if (r == -1) {\n";
5991         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
5992         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5993         pr "      free (ret);\n";
5994         pr "      free (out);\n";
5995         pr "      return NULL;\n";
5996         pr "    }\n";
5997         pr "\n";
5998         pr "    ++i;\n";
5999         pr "    p = pend;\n";
6000         pr "  }\n";
6001         pr "\n";
6002         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6003         pr "\n";
6004         pr "  free (out);\n";
6005         pr "  return ret;\n";
6006         pr "}\n"
6007
6008   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6009
6010 (* Generate a list of function names, for debugging in the daemon.. *)
6011 and generate_daemon_names () =
6012   generate_header CStyle GPLv2plus;
6013
6014   pr "#include <config.h>\n";
6015   pr "\n";
6016   pr "#include \"daemon.h\"\n";
6017   pr "\n";
6018
6019   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6020   pr "const char *function_names[] = {\n";
6021   List.iter (
6022     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6023   ) daemon_functions;
6024   pr "};\n";
6025
6026 (* Generate the optional groups for the daemon to implement
6027  * guestfs_available.
6028  *)
6029 and generate_daemon_optgroups_c () =
6030   generate_header CStyle GPLv2plus;
6031
6032   pr "#include <config.h>\n";
6033   pr "\n";
6034   pr "#include \"daemon.h\"\n";
6035   pr "#include \"optgroups.h\"\n";
6036   pr "\n";
6037
6038   pr "struct optgroup optgroups[] = {\n";
6039   List.iter (
6040     fun (group, _) ->
6041       pr "  { \"%s\", optgroup_%s_available },\n" group group
6042   ) optgroups;
6043   pr "  { NULL, NULL }\n";
6044   pr "};\n"
6045
6046 and generate_daemon_optgroups_h () =
6047   generate_header CStyle GPLv2plus;
6048
6049   List.iter (
6050     fun (group, _) ->
6051       pr "extern int optgroup_%s_available (void);\n" group
6052   ) optgroups
6053
6054 (* Generate the tests. *)
6055 and generate_tests () =
6056   generate_header CStyle GPLv2plus;
6057
6058   pr "\
6059 #include <stdio.h>
6060 #include <stdlib.h>
6061 #include <string.h>
6062 #include <unistd.h>
6063 #include <sys/types.h>
6064 #include <fcntl.h>
6065
6066 #include \"guestfs.h\"
6067 #include \"guestfs-internal.h\"
6068
6069 static guestfs_h *g;
6070 static int suppress_error = 0;
6071
6072 static void print_error (guestfs_h *g, void *data, const char *msg)
6073 {
6074   if (!suppress_error)
6075     fprintf (stderr, \"%%s\\n\", msg);
6076 }
6077
6078 /* FIXME: nearly identical code appears in fish.c */
6079 static void print_strings (char *const *argv)
6080 {
6081   int argc;
6082
6083   for (argc = 0; argv[argc] != NULL; ++argc)
6084     printf (\"\\t%%s\\n\", argv[argc]);
6085 }
6086
6087 /*
6088 static void print_table (char const *const *argv)
6089 {
6090   int i;
6091
6092   for (i = 0; argv[i] != NULL; i += 2)
6093     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6094 }
6095 */
6096
6097 ";
6098
6099   (* Generate a list of commands which are not tested anywhere. *)
6100   pr "static void no_test_warnings (void)\n";
6101   pr "{\n";
6102
6103   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6104   List.iter (
6105     fun (_, _, _, _, tests, _, _) ->
6106       let tests = filter_map (
6107         function
6108         | (_, (Always|If _|Unless _), test) -> Some test
6109         | (_, Disabled, _) -> None
6110       ) tests in
6111       let seq = List.concat (List.map seq_of_test tests) in
6112       let cmds_tested = List.map List.hd seq in
6113       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6114   ) all_functions;
6115
6116   List.iter (
6117     fun (name, _, _, _, _, _, _) ->
6118       if not (Hashtbl.mem hash name) then
6119         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6120   ) all_functions;
6121
6122   pr "}\n";
6123   pr "\n";
6124
6125   (* Generate the actual tests.  Note that we generate the tests
6126    * in reverse order, deliberately, so that (in general) the
6127    * newest tests run first.  This makes it quicker and easier to
6128    * debug them.
6129    *)
6130   let test_names =
6131     List.map (
6132       fun (name, _, _, flags, tests, _, _) ->
6133         mapi (generate_one_test name flags) tests
6134     ) (List.rev all_functions) in
6135   let test_names = List.concat test_names in
6136   let nr_tests = List.length test_names in
6137
6138   pr "\
6139 int main (int argc, char *argv[])
6140 {
6141   char c = 0;
6142   unsigned long int n_failed = 0;
6143   const char *filename;
6144   int fd;
6145   int nr_tests, test_num = 0;
6146
6147   setbuf (stdout, NULL);
6148
6149   no_test_warnings ();
6150
6151   g = guestfs_create ();
6152   if (g == NULL) {
6153     printf (\"guestfs_create FAILED\\n\");
6154     exit (EXIT_FAILURE);
6155   }
6156
6157   guestfs_set_error_handler (g, print_error, NULL);
6158
6159   guestfs_set_path (g, \"../appliance\");
6160
6161   filename = \"test1.img\";
6162   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6163   if (fd == -1) {
6164     perror (filename);
6165     exit (EXIT_FAILURE);
6166   }
6167   if (lseek (fd, %d, SEEK_SET) == -1) {
6168     perror (\"lseek\");
6169     close (fd);
6170     unlink (filename);
6171     exit (EXIT_FAILURE);
6172   }
6173   if (write (fd, &c, 1) == -1) {
6174     perror (\"write\");
6175     close (fd);
6176     unlink (filename);
6177     exit (EXIT_FAILURE);
6178   }
6179   if (close (fd) == -1) {
6180     perror (filename);
6181     unlink (filename);
6182     exit (EXIT_FAILURE);
6183   }
6184   if (guestfs_add_drive (g, filename) == -1) {
6185     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6186     exit (EXIT_FAILURE);
6187   }
6188
6189   filename = \"test2.img\";
6190   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6191   if (fd == -1) {
6192     perror (filename);
6193     exit (EXIT_FAILURE);
6194   }
6195   if (lseek (fd, %d, SEEK_SET) == -1) {
6196     perror (\"lseek\");
6197     close (fd);
6198     unlink (filename);
6199     exit (EXIT_FAILURE);
6200   }
6201   if (write (fd, &c, 1) == -1) {
6202     perror (\"write\");
6203     close (fd);
6204     unlink (filename);
6205     exit (EXIT_FAILURE);
6206   }
6207   if (close (fd) == -1) {
6208     perror (filename);
6209     unlink (filename);
6210     exit (EXIT_FAILURE);
6211   }
6212   if (guestfs_add_drive (g, filename) == -1) {
6213     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6214     exit (EXIT_FAILURE);
6215   }
6216
6217   filename = \"test3.img\";
6218   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6219   if (fd == -1) {
6220     perror (filename);
6221     exit (EXIT_FAILURE);
6222   }
6223   if (lseek (fd, %d, SEEK_SET) == -1) {
6224     perror (\"lseek\");
6225     close (fd);
6226     unlink (filename);
6227     exit (EXIT_FAILURE);
6228   }
6229   if (write (fd, &c, 1) == -1) {
6230     perror (\"write\");
6231     close (fd);
6232     unlink (filename);
6233     exit (EXIT_FAILURE);
6234   }
6235   if (close (fd) == -1) {
6236     perror (filename);
6237     unlink (filename);
6238     exit (EXIT_FAILURE);
6239   }
6240   if (guestfs_add_drive (g, filename) == -1) {
6241     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6242     exit (EXIT_FAILURE);
6243   }
6244
6245   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6246     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6247     exit (EXIT_FAILURE);
6248   }
6249
6250   if (guestfs_launch (g) == -1) {
6251     printf (\"guestfs_launch FAILED\\n\");
6252     exit (EXIT_FAILURE);
6253   }
6254
6255   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6256   alarm (600);
6257
6258   /* Cancel previous alarm. */
6259   alarm (0);
6260
6261   nr_tests = %d;
6262
6263 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6264
6265   iteri (
6266     fun i test_name ->
6267       pr "  test_num++;\n";
6268       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6269       pr "  if (%s () == -1) {\n" test_name;
6270       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6271       pr "    n_failed++;\n";
6272       pr "  }\n";
6273   ) test_names;
6274   pr "\n";
6275
6276   pr "  guestfs_close (g);\n";
6277   pr "  unlink (\"test1.img\");\n";
6278   pr "  unlink (\"test2.img\");\n";
6279   pr "  unlink (\"test3.img\");\n";
6280   pr "\n";
6281
6282   pr "  if (n_failed > 0) {\n";
6283   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6284   pr "    exit (EXIT_FAILURE);\n";
6285   pr "  }\n";
6286   pr "\n";
6287
6288   pr "  exit (EXIT_SUCCESS);\n";
6289   pr "}\n"
6290
6291 and generate_one_test name flags i (init, prereq, test) =
6292   let test_name = sprintf "test_%s_%d" name i in
6293
6294   pr "\
6295 static int %s_skip (void)
6296 {
6297   const char *str;
6298
6299   str = getenv (\"TEST_ONLY\");
6300   if (str)
6301     return strstr (str, \"%s\") == NULL;
6302   str = getenv (\"SKIP_%s\");
6303   if (str && STREQ (str, \"1\")) return 1;
6304   str = getenv (\"SKIP_TEST_%s\");
6305   if (str && STREQ (str, \"1\")) return 1;
6306   return 0;
6307 }
6308
6309 " test_name name (String.uppercase test_name) (String.uppercase name);
6310
6311   (match prereq with
6312    | Disabled | Always -> ()
6313    | If code | Unless code ->
6314        pr "static int %s_prereq (void)\n" test_name;
6315        pr "{\n";
6316        pr "  %s\n" code;
6317        pr "}\n";
6318        pr "\n";
6319   );
6320
6321   pr "\
6322 static int %s (void)
6323 {
6324   if (%s_skip ()) {
6325     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6326     return 0;
6327   }
6328
6329 " test_name test_name test_name;
6330
6331   (* Optional functions should only be tested if the relevant
6332    * support is available in the daemon.
6333    *)
6334   List.iter (
6335     function
6336     | Optional group ->
6337         pr "  {\n";
6338         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6339         pr "    int r;\n";
6340         pr "    suppress_error = 1;\n";
6341         pr "    r = guestfs_available (g, (char **) groups);\n";
6342         pr "    suppress_error = 0;\n";
6343         pr "    if (r == -1) {\n";
6344         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6345         pr "      return 0;\n";
6346         pr "    }\n";
6347         pr "  }\n";
6348     | _ -> ()
6349   ) flags;
6350
6351   (match prereq with
6352    | Disabled ->
6353        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6354    | If _ ->
6355        pr "  if (! %s_prereq ()) {\n" test_name;
6356        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6357        pr "    return 0;\n";
6358        pr "  }\n";
6359        pr "\n";
6360        generate_one_test_body name i test_name init test;
6361    | Unless _ ->
6362        pr "  if (%s_prereq ()) {\n" test_name;
6363        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6364        pr "    return 0;\n";
6365        pr "  }\n";
6366        pr "\n";
6367        generate_one_test_body name i test_name init test;
6368    | Always ->
6369        generate_one_test_body name i test_name init test
6370   );
6371
6372   pr "  return 0;\n";
6373   pr "}\n";
6374   pr "\n";
6375   test_name
6376
6377 and generate_one_test_body name i test_name init test =
6378   (match init with
6379    | InitNone (* XXX at some point, InitNone and InitEmpty became
6380                * folded together as the same thing.  Really we should
6381                * make InitNone do nothing at all, but the tests may
6382                * need to be checked to make sure this is OK.
6383                *)
6384    | InitEmpty ->
6385        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6386        List.iter (generate_test_command_call test_name)
6387          [["blockdev_setrw"; "/dev/sda"];
6388           ["umount_all"];
6389           ["lvm_remove_all"]]
6390    | InitPartition ->
6391        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6392        List.iter (generate_test_command_call test_name)
6393          [["blockdev_setrw"; "/dev/sda"];
6394           ["umount_all"];
6395           ["lvm_remove_all"];
6396           ["part_disk"; "/dev/sda"; "mbr"]]
6397    | InitBasicFS ->
6398        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6399        List.iter (generate_test_command_call test_name)
6400          [["blockdev_setrw"; "/dev/sda"];
6401           ["umount_all"];
6402           ["lvm_remove_all"];
6403           ["part_disk"; "/dev/sda"; "mbr"];
6404           ["mkfs"; "ext2"; "/dev/sda1"];
6405           ["mount"; "/dev/sda1"; "/"]]
6406    | InitBasicFSonLVM ->
6407        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6408          test_name;
6409        List.iter (generate_test_command_call test_name)
6410          [["blockdev_setrw"; "/dev/sda"];
6411           ["umount_all"];
6412           ["lvm_remove_all"];
6413           ["part_disk"; "/dev/sda"; "mbr"];
6414           ["pvcreate"; "/dev/sda1"];
6415           ["vgcreate"; "VG"; "/dev/sda1"];
6416           ["lvcreate"; "LV"; "VG"; "8"];
6417           ["mkfs"; "ext2"; "/dev/VG/LV"];
6418           ["mount"; "/dev/VG/LV"; "/"]]
6419    | InitISOFS ->
6420        pr "  /* InitISOFS for %s */\n" test_name;
6421        List.iter (generate_test_command_call test_name)
6422          [["blockdev_setrw"; "/dev/sda"];
6423           ["umount_all"];
6424           ["lvm_remove_all"];
6425           ["mount_ro"; "/dev/sdd"; "/"]]
6426   );
6427
6428   let get_seq_last = function
6429     | [] ->
6430         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6431           test_name
6432     | seq ->
6433         let seq = List.rev seq in
6434         List.rev (List.tl seq), List.hd seq
6435   in
6436
6437   match test with
6438   | TestRun seq ->
6439       pr "  /* TestRun for %s (%d) */\n" name i;
6440       List.iter (generate_test_command_call test_name) seq
6441   | TestOutput (seq, expected) ->
6442       pr "  /* TestOutput for %s (%d) */\n" name i;
6443       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6444       let seq, last = get_seq_last seq in
6445       let test () =
6446         pr "    if (STRNEQ (r, expected)) {\n";
6447         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6448         pr "      return -1;\n";
6449         pr "    }\n"
6450       in
6451       List.iter (generate_test_command_call test_name) seq;
6452       generate_test_command_call ~test test_name last
6453   | TestOutputList (seq, expected) ->
6454       pr "  /* TestOutputList for %s (%d) */\n" name i;
6455       let seq, last = get_seq_last seq in
6456       let test () =
6457         iteri (
6458           fun i str ->
6459             pr "    if (!r[%d]) {\n" i;
6460             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6461             pr "      print_strings (r);\n";
6462             pr "      return -1;\n";
6463             pr "    }\n";
6464             pr "    {\n";
6465             pr "      const char *expected = \"%s\";\n" (c_quote str);
6466             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6467             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6468             pr "        return -1;\n";
6469             pr "      }\n";
6470             pr "    }\n"
6471         ) expected;
6472         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6473         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6474           test_name;
6475         pr "      print_strings (r);\n";
6476         pr "      return -1;\n";
6477         pr "    }\n"
6478       in
6479       List.iter (generate_test_command_call test_name) seq;
6480       generate_test_command_call ~test test_name last
6481   | TestOutputListOfDevices (seq, expected) ->
6482       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6483       let seq, last = get_seq_last seq in
6484       let test () =
6485         iteri (
6486           fun i str ->
6487             pr "    if (!r[%d]) {\n" i;
6488             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6489             pr "      print_strings (r);\n";
6490             pr "      return -1;\n";
6491             pr "    }\n";
6492             pr "    {\n";
6493             pr "      const char *expected = \"%s\";\n" (c_quote str);
6494             pr "      r[%d][5] = 's';\n" i;
6495             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6496             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6497             pr "        return -1;\n";
6498             pr "      }\n";
6499             pr "    }\n"
6500         ) expected;
6501         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6502         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6503           test_name;
6504         pr "      print_strings (r);\n";
6505         pr "      return -1;\n";
6506         pr "    }\n"
6507       in
6508       List.iter (generate_test_command_call test_name) seq;
6509       generate_test_command_call ~test test_name last
6510   | TestOutputInt (seq, expected) ->
6511       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6512       let seq, last = get_seq_last seq in
6513       let test () =
6514         pr "    if (r != %d) {\n" expected;
6515         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6516           test_name expected;
6517         pr "               (int) r);\n";
6518         pr "      return -1;\n";
6519         pr "    }\n"
6520       in
6521       List.iter (generate_test_command_call test_name) seq;
6522       generate_test_command_call ~test test_name last
6523   | TestOutputIntOp (seq, op, expected) ->
6524       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6525       let seq, last = get_seq_last seq in
6526       let test () =
6527         pr "    if (! (r %s %d)) {\n" op expected;
6528         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6529           test_name op expected;
6530         pr "               (int) r);\n";
6531         pr "      return -1;\n";
6532         pr "    }\n"
6533       in
6534       List.iter (generate_test_command_call test_name) seq;
6535       generate_test_command_call ~test test_name last
6536   | TestOutputTrue seq ->
6537       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
6538       let seq, last = get_seq_last seq in
6539       let test () =
6540         pr "    if (!r) {\n";
6541         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
6542           test_name;
6543         pr "      return -1;\n";
6544         pr "    }\n"
6545       in
6546       List.iter (generate_test_command_call test_name) seq;
6547       generate_test_command_call ~test test_name last
6548   | TestOutputFalse seq ->
6549       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
6550       let seq, last = get_seq_last seq in
6551       let test () =
6552         pr "    if (r) {\n";
6553         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
6554           test_name;
6555         pr "      return -1;\n";
6556         pr "    }\n"
6557       in
6558       List.iter (generate_test_command_call test_name) seq;
6559       generate_test_command_call ~test test_name last
6560   | TestOutputLength (seq, expected) ->
6561       pr "  /* TestOutputLength for %s (%d) */\n" name i;
6562       let seq, last = get_seq_last seq in
6563       let test () =
6564         pr "    int j;\n";
6565         pr "    for (j = 0; j < %d; ++j)\n" expected;
6566         pr "      if (r[j] == NULL) {\n";
6567         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
6568           test_name;
6569         pr "        print_strings (r);\n";
6570         pr "        return -1;\n";
6571         pr "      }\n";
6572         pr "    if (r[j] != NULL) {\n";
6573         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
6574           test_name;
6575         pr "      print_strings (r);\n";
6576         pr "      return -1;\n";
6577         pr "    }\n"
6578       in
6579       List.iter (generate_test_command_call test_name) seq;
6580       generate_test_command_call ~test test_name last
6581   | TestOutputBuffer (seq, expected) ->
6582       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
6583       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6584       let seq, last = get_seq_last seq in
6585       let len = String.length expected in
6586       let test () =
6587         pr "    if (size != %d) {\n" len;
6588         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
6589         pr "      return -1;\n";
6590         pr "    }\n";
6591         pr "    if (STRNEQLEN (r, expected, size)) {\n";
6592         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6593         pr "      return -1;\n";
6594         pr "    }\n"
6595       in
6596       List.iter (generate_test_command_call test_name) seq;
6597       generate_test_command_call ~test test_name last
6598   | TestOutputStruct (seq, checks) ->
6599       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
6600       let seq, last = get_seq_last seq in
6601       let test () =
6602         List.iter (
6603           function
6604           | CompareWithInt (field, expected) ->
6605               pr "    if (r->%s != %d) {\n" field expected;
6606               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
6607                 test_name field expected;
6608               pr "               (int) r->%s);\n" field;
6609               pr "      return -1;\n";
6610               pr "    }\n"
6611           | CompareWithIntOp (field, op, expected) ->
6612               pr "    if (!(r->%s %s %d)) {\n" field op expected;
6613               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
6614                 test_name field op expected;
6615               pr "               (int) r->%s);\n" field;
6616               pr "      return -1;\n";
6617               pr "    }\n"
6618           | CompareWithString (field, expected) ->
6619               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
6620               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
6621                 test_name field expected;
6622               pr "               r->%s);\n" field;
6623               pr "      return -1;\n";
6624               pr "    }\n"
6625           | CompareFieldsIntEq (field1, field2) ->
6626               pr "    if (r->%s != r->%s) {\n" field1 field2;
6627               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
6628                 test_name field1 field2;
6629               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
6630               pr "      return -1;\n";
6631               pr "    }\n"
6632           | CompareFieldsStrEq (field1, field2) ->
6633               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
6634               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
6635                 test_name field1 field2;
6636               pr "               r->%s, r->%s);\n" field1 field2;
6637               pr "      return -1;\n";
6638               pr "    }\n"
6639         ) checks
6640       in
6641       List.iter (generate_test_command_call test_name) seq;
6642       generate_test_command_call ~test test_name last
6643   | TestLastFail seq ->
6644       pr "  /* TestLastFail for %s (%d) */\n" name i;
6645       let seq, last = get_seq_last seq in
6646       List.iter (generate_test_command_call test_name) seq;
6647       generate_test_command_call test_name ~expect_error:true last
6648
6649 (* Generate the code to run a command, leaving the result in 'r'.
6650  * If you expect to get an error then you should set expect_error:true.
6651  *)
6652 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
6653   match cmd with
6654   | [] -> assert false
6655   | name :: args ->
6656       (* Look up the command to find out what args/ret it has. *)
6657       let style =
6658         try
6659           let _, style, _, _, _, _, _ =
6660             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
6661           style
6662         with Not_found ->
6663           failwithf "%s: in test, command %s was not found" test_name name in
6664
6665       if List.length (snd style) <> List.length args then
6666         failwithf "%s: in test, wrong number of args given to %s"
6667           test_name name;
6668
6669       pr "  {\n";
6670
6671       List.iter (
6672         function
6673         | OptString n, "NULL" -> ()
6674         | Pathname n, arg
6675         | Device n, arg
6676         | Dev_or_Path n, arg
6677         | String n, arg
6678         | OptString n, arg ->
6679             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
6680         | Int _, _
6681         | Int64 _, _
6682         | Bool _, _
6683         | FileIn _, _ | FileOut _, _ -> ()
6684         | StringList n, "" | DeviceList n, "" ->
6685             pr "    const char *const %s[1] = { NULL };\n" n
6686         | StringList n, arg | DeviceList n, arg ->
6687             let strs = string_split " " arg in
6688             iteri (
6689               fun i str ->
6690                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
6691             ) strs;
6692             pr "    const char *const %s[] = {\n" n;
6693             iteri (
6694               fun i _ -> pr "      %s_%d,\n" n i
6695             ) strs;
6696             pr "      NULL\n";
6697             pr "    };\n";
6698       ) (List.combine (snd style) args);
6699
6700       let error_code =
6701         match fst style with
6702         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
6703         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
6704         | RConstString _ | RConstOptString _ ->
6705             pr "    const char *r;\n"; "NULL"
6706         | RString _ -> pr "    char *r;\n"; "NULL"
6707         | RStringList _ | RHashtable _ ->
6708             pr "    char **r;\n";
6709             pr "    int i;\n";
6710             "NULL"
6711         | RStruct (_, typ) ->
6712             pr "    struct guestfs_%s *r;\n" typ; "NULL"
6713         | RStructList (_, typ) ->
6714             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
6715         | RBufferOut _ ->
6716             pr "    char *r;\n";
6717             pr "    size_t size;\n";
6718             "NULL" in
6719
6720       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
6721       pr "    r = guestfs_%s (g" name;
6722
6723       (* Generate the parameters. *)
6724       List.iter (
6725         function
6726         | OptString _, "NULL" -> pr ", NULL"
6727         | Pathname n, _
6728         | Device n, _ | Dev_or_Path n, _
6729         | String n, _
6730         | OptString n, _ ->
6731             pr ", %s" n
6732         | FileIn _, arg | FileOut _, arg ->
6733             pr ", \"%s\"" (c_quote arg)
6734         | StringList n, _ | DeviceList n, _ ->
6735             pr ", (char **) %s" n
6736         | Int _, arg ->
6737             let i =
6738               try int_of_string arg
6739               with Failure "int_of_string" ->
6740                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
6741             pr ", %d" i
6742         | Int64 _, arg ->
6743             let i =
6744               try Int64.of_string arg
6745               with Failure "int_of_string" ->
6746                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
6747             pr ", %Ld" i
6748         | Bool _, arg ->
6749             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
6750       ) (List.combine (snd style) args);
6751
6752       (match fst style with
6753        | RBufferOut _ -> pr ", &size"
6754        | _ -> ()
6755       );
6756
6757       pr ");\n";
6758
6759       if not expect_error then
6760         pr "    if (r == %s)\n" error_code
6761       else
6762         pr "    if (r != %s)\n" error_code;
6763       pr "      return -1;\n";
6764
6765       (* Insert the test code. *)
6766       (match test with
6767        | None -> ()
6768        | Some f -> f ()
6769       );
6770
6771       (match fst style with
6772        | RErr | RInt _ | RInt64 _ | RBool _
6773        | RConstString _ | RConstOptString _ -> ()
6774        | RString _ | RBufferOut _ -> pr "    free (r);\n"
6775        | RStringList _ | RHashtable _ ->
6776            pr "    for (i = 0; r[i] != NULL; ++i)\n";
6777            pr "      free (r[i]);\n";
6778            pr "    free (r);\n"
6779        | RStruct (_, typ) ->
6780            pr "    guestfs_free_%s (r);\n" typ
6781        | RStructList (_, typ) ->
6782            pr "    guestfs_free_%s_list (r);\n" typ
6783       );
6784
6785       pr "  }\n"
6786
6787 and c_quote str =
6788   let str = replace_str str "\r" "\\r" in
6789   let str = replace_str str "\n" "\\n" in
6790   let str = replace_str str "\t" "\\t" in
6791   let str = replace_str str "\000" "\\0" in
6792   str
6793
6794 (* Generate a lot of different functions for guestfish. *)
6795 and generate_fish_cmds () =
6796   generate_header CStyle GPLv2plus;
6797
6798   let all_functions =
6799     List.filter (
6800       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6801     ) all_functions in
6802   let all_functions_sorted =
6803     List.filter (
6804       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6805     ) all_functions_sorted in
6806
6807   pr "#include <stdio.h>\n";
6808   pr "#include <stdlib.h>\n";
6809   pr "#include <string.h>\n";
6810   pr "#include <inttypes.h>\n";
6811   pr "\n";
6812   pr "#include <guestfs.h>\n";
6813   pr "#include \"c-ctype.h\"\n";
6814   pr "#include \"fish.h\"\n";
6815   pr "\n";
6816
6817   (* list_commands function, which implements guestfish -h *)
6818   pr "void list_commands (void)\n";
6819   pr "{\n";
6820   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
6821   pr "  list_builtin_commands ();\n";
6822   List.iter (
6823     fun (name, _, _, flags, _, shortdesc, _) ->
6824       let name = replace_char name '_' '-' in
6825       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
6826         name shortdesc
6827   ) all_functions_sorted;
6828   pr "  printf (\"    %%s\\n\",";
6829   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
6830   pr "}\n";
6831   pr "\n";
6832
6833   (* display_command function, which implements guestfish -h cmd *)
6834   pr "void display_command (const char *cmd)\n";
6835   pr "{\n";
6836   List.iter (
6837     fun (name, style, _, flags, _, shortdesc, longdesc) ->
6838       let name2 = replace_char name '_' '-' in
6839       let alias =
6840         try find_map (function FishAlias n -> Some n | _ -> None) flags
6841         with Not_found -> name in
6842       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
6843       let synopsis =
6844         match snd style with
6845         | [] -> name2
6846         | args ->
6847             sprintf "%s %s"
6848               name2 (String.concat " " (List.map name_of_argt args)) in
6849
6850       let warnings =
6851         if List.mem ProtocolLimitWarning flags then
6852           ("\n\n" ^ protocol_limit_warning)
6853         else "" in
6854
6855       (* For DangerWillRobinson commands, we should probably have
6856        * guestfish prompt before allowing you to use them (especially
6857        * in interactive mode). XXX
6858        *)
6859       let warnings =
6860         warnings ^
6861           if List.mem DangerWillRobinson flags then
6862             ("\n\n" ^ danger_will_robinson)
6863           else "" in
6864
6865       let warnings =
6866         warnings ^
6867           match deprecation_notice flags with
6868           | None -> ""
6869           | Some txt -> "\n\n" ^ txt in
6870
6871       let describe_alias =
6872         if name <> alias then
6873           sprintf "\n\nYou can use '%s' as an alias for this command." alias
6874         else "" in
6875
6876       pr "  if (";
6877       pr "STRCASEEQ (cmd, \"%s\")" name;
6878       if name <> name2 then
6879         pr " || STRCASEEQ (cmd, \"%s\")" name2;
6880       if name <> alias then
6881         pr " || STRCASEEQ (cmd, \"%s\")" alias;
6882       pr ")\n";
6883       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
6884         name2 shortdesc
6885         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
6886          "=head1 DESCRIPTION\n\n" ^
6887          longdesc ^ warnings ^ describe_alias);
6888       pr "  else\n"
6889   ) all_functions;
6890   pr "    display_builtin_command (cmd);\n";
6891   pr "}\n";
6892   pr "\n";
6893
6894   let emit_print_list_function typ =
6895     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
6896       typ typ typ;
6897     pr "{\n";
6898     pr "  unsigned int i;\n";
6899     pr "\n";
6900     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
6901     pr "    printf (\"[%%d] = {\\n\", i);\n";
6902     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
6903     pr "    printf (\"}\\n\");\n";
6904     pr "  }\n";
6905     pr "}\n";
6906     pr "\n";
6907   in
6908
6909   (* print_* functions *)
6910   List.iter (
6911     fun (typ, cols) ->
6912       let needs_i =
6913         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
6914
6915       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
6916       pr "{\n";
6917       if needs_i then (
6918         pr "  unsigned int i;\n";
6919         pr "\n"
6920       );
6921       List.iter (
6922         function
6923         | name, FString ->
6924             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
6925         | name, FUUID ->
6926             pr "  printf (\"%%s%s: \", indent);\n" name;
6927             pr "  for (i = 0; i < 32; ++i)\n";
6928             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
6929             pr "  printf (\"\\n\");\n"
6930         | name, FBuffer ->
6931             pr "  printf (\"%%s%s: \", indent);\n" name;
6932             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
6933             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
6934             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
6935             pr "    else\n";
6936             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
6937             pr "  printf (\"\\n\");\n"
6938         | name, (FUInt64|FBytes) ->
6939             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
6940               name typ name
6941         | name, FInt64 ->
6942             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
6943               name typ name
6944         | name, FUInt32 ->
6945             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
6946               name typ name
6947         | name, FInt32 ->
6948             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
6949               name typ name
6950         | name, FChar ->
6951             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
6952               name typ name
6953         | name, FOptPercent ->
6954             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
6955               typ name name typ name;
6956             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
6957       ) cols;
6958       pr "}\n";
6959       pr "\n";
6960   ) structs;
6961
6962   (* Emit a print_TYPE_list function definition only if that function is used. *)
6963   List.iter (
6964     function
6965     | typ, (RStructListOnly | RStructAndList) ->
6966         (* generate the function for typ *)
6967         emit_print_list_function typ
6968     | typ, _ -> () (* empty *)
6969   ) (rstructs_used_by all_functions);
6970
6971   (* Emit a print_TYPE function definition only if that function is used. *)
6972   List.iter (
6973     function
6974     | typ, (RStructOnly | RStructAndList) ->
6975         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
6976         pr "{\n";
6977         pr "  print_%s_indent (%s, \"\");\n" typ typ;
6978         pr "}\n";
6979         pr "\n";
6980     | typ, _ -> () (* empty *)
6981   ) (rstructs_used_by all_functions);
6982
6983   (* run_<action> actions *)
6984   List.iter (
6985     fun (name, style, _, flags, _, _, _) ->
6986       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
6987       pr "{\n";
6988       (match fst style with
6989        | RErr
6990        | RInt _
6991        | RBool _ -> pr "  int r;\n"
6992        | RInt64 _ -> pr "  int64_t r;\n"
6993        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
6994        | RString _ -> pr "  char *r;\n"
6995        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
6996        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
6997        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
6998        | RBufferOut _ ->
6999            pr "  char *r;\n";
7000            pr "  size_t size;\n";
7001       );
7002       List.iter (
7003         function
7004         | Device n
7005         | String n
7006         | OptString n
7007         | FileIn n
7008         | FileOut n -> pr "  const char *%s;\n" n
7009         | Pathname n
7010         | Dev_or_Path n -> pr "  char *%s;\n" n
7011         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7012         | Bool n -> pr "  int %s;\n" n
7013         | Int n -> pr "  int %s;\n" n
7014         | Int64 n -> pr "  int64_t %s;\n" n
7015       ) (snd style);
7016
7017       (* Check and convert parameters. *)
7018       let argc_expected = List.length (snd style) in
7019       pr "  if (argc != %d) {\n" argc_expected;
7020       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7021         argc_expected;
7022       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7023       pr "    return -1;\n";
7024       pr "  }\n";
7025       iteri (
7026         fun i ->
7027           function
7028           | Device name
7029           | String name ->
7030               pr "  %s = argv[%d];\n" name i
7031           | Pathname name
7032           | Dev_or_Path name ->
7033               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7034               pr "  if (%s == NULL) return -1;\n" name
7035           | OptString name ->
7036               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7037                 name i i
7038           | FileIn name ->
7039               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdin\";\n"
7040                 name i i
7041           | FileOut name ->
7042               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdout\";\n"
7043                 name i i
7044           | StringList name | DeviceList name ->
7045               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7046               pr "  if (%s == NULL) return -1;\n" name;
7047           | Bool name ->
7048               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7049           | Int name ->
7050               pr "  %s = atoi (argv[%d]);\n" name i
7051           | Int64 name ->
7052               pr "  %s = atoll (argv[%d]);\n" name i
7053       ) (snd style);
7054
7055       (* Call C API function. *)
7056       let fn =
7057         try find_map (function FishAction n -> Some n | _ -> None) flags
7058         with Not_found -> sprintf "guestfs_%s" name in
7059       pr "  r = %s " fn;
7060       generate_c_call_args ~handle:"g" style;
7061       pr ";\n";
7062
7063       List.iter (
7064         function
7065         | Device name | String name
7066         | OptString name | FileIn name | FileOut name | Bool name
7067         | Int name | Int64 name -> ()
7068         | Pathname name | Dev_or_Path name ->
7069             pr "  free (%s);\n" name
7070         | StringList name | DeviceList name ->
7071             pr "  free_strings (%s);\n" name
7072       ) (snd style);
7073
7074       (* Check return value for errors and display command results. *)
7075       (match fst style with
7076        | RErr -> pr "  return r;\n"
7077        | RInt _ ->
7078            pr "  if (r == -1) return -1;\n";
7079            pr "  printf (\"%%d\\n\", r);\n";
7080            pr "  return 0;\n"
7081        | RInt64 _ ->
7082            pr "  if (r == -1) return -1;\n";
7083            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7084            pr "  return 0;\n"
7085        | RBool _ ->
7086            pr "  if (r == -1) return -1;\n";
7087            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7088            pr "  return 0;\n"
7089        | RConstString _ ->
7090            pr "  if (r == NULL) return -1;\n";
7091            pr "  printf (\"%%s\\n\", r);\n";
7092            pr "  return 0;\n"
7093        | RConstOptString _ ->
7094            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7095            pr "  return 0;\n"
7096        | RString _ ->
7097            pr "  if (r == NULL) return -1;\n";
7098            pr "  printf (\"%%s\\n\", r);\n";
7099            pr "  free (r);\n";
7100            pr "  return 0;\n"
7101        | RStringList _ ->
7102            pr "  if (r == NULL) return -1;\n";
7103            pr "  print_strings (r);\n";
7104            pr "  free_strings (r);\n";
7105            pr "  return 0;\n"
7106        | RStruct (_, typ) ->
7107            pr "  if (r == NULL) return -1;\n";
7108            pr "  print_%s (r);\n" typ;
7109            pr "  guestfs_free_%s (r);\n" typ;
7110            pr "  return 0;\n"
7111        | RStructList (_, typ) ->
7112            pr "  if (r == NULL) return -1;\n";
7113            pr "  print_%s_list (r);\n" typ;
7114            pr "  guestfs_free_%s_list (r);\n" typ;
7115            pr "  return 0;\n"
7116        | RHashtable _ ->
7117            pr "  if (r == NULL) return -1;\n";
7118            pr "  print_table (r);\n";
7119            pr "  free_strings (r);\n";
7120            pr "  return 0;\n"
7121        | RBufferOut _ ->
7122            pr "  if (r == NULL) return -1;\n";
7123            pr "  fwrite (r, size, 1, stdout);\n";
7124            pr "  free (r);\n";
7125            pr "  return 0;\n"
7126       );
7127       pr "}\n";
7128       pr "\n"
7129   ) all_functions;
7130
7131   (* run_action function *)
7132   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7133   pr "{\n";
7134   List.iter (
7135     fun (name, _, _, flags, _, _, _) ->
7136       let name2 = replace_char name '_' '-' in
7137       let alias =
7138         try find_map (function FishAlias n -> Some n | _ -> None) flags
7139         with Not_found -> name in
7140       pr "  if (";
7141       pr "STRCASEEQ (cmd, \"%s\")" name;
7142       if name <> name2 then
7143         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7144       if name <> alias then
7145         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7146       pr ")\n";
7147       pr "    return run_%s (cmd, argc, argv);\n" name;
7148       pr "  else\n";
7149   ) all_functions;
7150   pr "    {\n";
7151   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7152   pr "      return -1;\n";
7153   pr "    }\n";
7154   pr "  return 0;\n";
7155   pr "}\n";
7156   pr "\n"
7157
7158 (* Readline completion for guestfish. *)
7159 and generate_fish_completion () =
7160   generate_header CStyle GPLv2plus;
7161
7162   let all_functions =
7163     List.filter (
7164       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7165     ) all_functions in
7166
7167   pr "\
7168 #include <config.h>
7169
7170 #include <stdio.h>
7171 #include <stdlib.h>
7172 #include <string.h>
7173
7174 #ifdef HAVE_LIBREADLINE
7175 #include <readline/readline.h>
7176 #endif
7177
7178 #include \"fish.h\"
7179
7180 #ifdef HAVE_LIBREADLINE
7181
7182 static const char *const commands[] = {
7183   BUILTIN_COMMANDS_FOR_COMPLETION,
7184 ";
7185
7186   (* Get the commands, including the aliases.  They don't need to be
7187    * sorted - the generator() function just does a dumb linear search.
7188    *)
7189   let commands =
7190     List.map (
7191       fun (name, _, _, flags, _, _, _) ->
7192         let name2 = replace_char name '_' '-' in
7193         let alias =
7194           try find_map (function FishAlias n -> Some n | _ -> None) flags
7195           with Not_found -> name in
7196
7197         if name <> alias then [name2; alias] else [name2]
7198     ) all_functions in
7199   let commands = List.flatten commands in
7200
7201   List.iter (pr "  \"%s\",\n") commands;
7202
7203   pr "  NULL
7204 };
7205
7206 static char *
7207 generator (const char *text, int state)
7208 {
7209   static int index, len;
7210   const char *name;
7211
7212   if (!state) {
7213     index = 0;
7214     len = strlen (text);
7215   }
7216
7217   rl_attempted_completion_over = 1;
7218
7219   while ((name = commands[index]) != NULL) {
7220     index++;
7221     if (STRCASEEQLEN (name, text, len))
7222       return strdup (name);
7223   }
7224
7225   return NULL;
7226 }
7227
7228 #endif /* HAVE_LIBREADLINE */
7229
7230 char **do_completion (const char *text, int start, int end)
7231 {
7232   char **matches = NULL;
7233
7234 #ifdef HAVE_LIBREADLINE
7235   rl_completion_append_character = ' ';
7236
7237   if (start == 0)
7238     matches = rl_completion_matches (text, generator);
7239   else if (complete_dest_paths)
7240     matches = rl_completion_matches (text, complete_dest_paths_generator);
7241 #endif
7242
7243   return matches;
7244 }
7245 ";
7246
7247 (* Generate the POD documentation for guestfish. *)
7248 and generate_fish_actions_pod () =
7249   let all_functions_sorted =
7250     List.filter (
7251       fun (_, _, _, flags, _, _, _) ->
7252         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7253     ) all_functions_sorted in
7254
7255   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7256
7257   List.iter (
7258     fun (name, style, _, flags, _, _, longdesc) ->
7259       let longdesc =
7260         Str.global_substitute rex (
7261           fun s ->
7262             let sub =
7263               try Str.matched_group 1 s
7264               with Not_found ->
7265                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7266             "C<" ^ replace_char sub '_' '-' ^ ">"
7267         ) longdesc in
7268       let name = replace_char name '_' '-' in
7269       let alias =
7270         try find_map (function FishAlias n -> Some n | _ -> None) flags
7271         with Not_found -> name in
7272
7273       pr "=head2 %s" name;
7274       if name <> alias then
7275         pr " | %s" alias;
7276       pr "\n";
7277       pr "\n";
7278       pr " %s" name;
7279       List.iter (
7280         function
7281         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7282         | OptString n -> pr " %s" n
7283         | StringList n | DeviceList n -> pr " '%s ...'" n
7284         | Bool _ -> pr " true|false"
7285         | Int n -> pr " %s" n
7286         | Int64 n -> pr " %s" n
7287         | FileIn n | FileOut n -> pr " (%s|-)" n
7288       ) (snd style);
7289       pr "\n";
7290       pr "\n";
7291       pr "%s\n\n" longdesc;
7292
7293       if List.exists (function FileIn _ | FileOut _ -> true
7294                       | _ -> false) (snd style) then
7295         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7296
7297       if List.mem ProtocolLimitWarning flags then
7298         pr "%s\n\n" protocol_limit_warning;
7299
7300       if List.mem DangerWillRobinson flags then
7301         pr "%s\n\n" danger_will_robinson;
7302
7303       match deprecation_notice flags with
7304       | None -> ()
7305       | Some txt -> pr "%s\n\n" txt
7306   ) all_functions_sorted
7307
7308 (* Generate a C function prototype. *)
7309 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7310     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7311     ?(prefix = "")
7312     ?handle name style =
7313   if extern then pr "extern ";
7314   if static then pr "static ";
7315   (match fst style with
7316    | RErr -> pr "int "
7317    | RInt _ -> pr "int "
7318    | RInt64 _ -> pr "int64_t "
7319    | RBool _ -> pr "int "
7320    | RConstString _ | RConstOptString _ -> pr "const char *"
7321    | RString _ | RBufferOut _ -> pr "char *"
7322    | RStringList _ | RHashtable _ -> pr "char **"
7323    | RStruct (_, typ) ->
7324        if not in_daemon then pr "struct guestfs_%s *" typ
7325        else pr "guestfs_int_%s *" typ
7326    | RStructList (_, typ) ->
7327        if not in_daemon then pr "struct guestfs_%s_list *" typ
7328        else pr "guestfs_int_%s_list *" typ
7329   );
7330   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7331   pr "%s%s (" prefix name;
7332   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7333     pr "void"
7334   else (
7335     let comma = ref false in
7336     (match handle with
7337      | None -> ()
7338      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7339     );
7340     let next () =
7341       if !comma then (
7342         if single_line then pr ", " else pr ",\n\t\t"
7343       );
7344       comma := true
7345     in
7346     List.iter (
7347       function
7348       | Pathname n
7349       | Device n | Dev_or_Path n
7350       | String n
7351       | OptString n ->
7352           next ();
7353           pr "const char *%s" n
7354       | StringList n | DeviceList n ->
7355           next ();
7356           pr "char *const *%s" n
7357       | Bool n -> next (); pr "int %s" n
7358       | Int n -> next (); pr "int %s" n
7359       | Int64 n -> next (); pr "int64_t %s" n
7360       | FileIn n
7361       | FileOut n ->
7362           if not in_daemon then (next (); pr "const char *%s" n)
7363     ) (snd style);
7364     if is_RBufferOut then (next (); pr "size_t *size_r");
7365   );
7366   pr ")";
7367   if semicolon then pr ";";
7368   if newline then pr "\n"
7369
7370 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7371 and generate_c_call_args ?handle ?(decl = false) style =
7372   pr "(";
7373   let comma = ref false in
7374   let next () =
7375     if !comma then pr ", ";
7376     comma := true
7377   in
7378   (match handle with
7379    | None -> ()
7380    | Some handle -> pr "%s" handle; comma := true
7381   );
7382   List.iter (
7383     fun arg ->
7384       next ();
7385       pr "%s" (name_of_argt arg)
7386   ) (snd style);
7387   (* For RBufferOut calls, add implicit &size parameter. *)
7388   if not decl then (
7389     match fst style with
7390     | RBufferOut _ ->
7391         next ();
7392         pr "&size"
7393     | _ -> ()
7394   );
7395   pr ")"
7396
7397 (* Generate the OCaml bindings interface. *)
7398 and generate_ocaml_mli () =
7399   generate_header OCamlStyle LGPLv2plus;
7400
7401   pr "\
7402 (** For API documentation you should refer to the C API
7403     in the guestfs(3) manual page.  The OCaml API uses almost
7404     exactly the same calls. *)
7405
7406 type t
7407 (** A [guestfs_h] handle. *)
7408
7409 exception Error of string
7410 (** This exception is raised when there is an error. *)
7411
7412 exception Handle_closed of string
7413 (** This exception is raised if you use a {!Guestfs.t} handle
7414     after calling {!close} on it.  The string is the name of
7415     the function. *)
7416
7417 val create : unit -> t
7418 (** Create a {!Guestfs.t} handle. *)
7419
7420 val close : t -> unit
7421 (** Close the {!Guestfs.t} handle and free up all resources used
7422     by it immediately.
7423
7424     Handles are closed by the garbage collector when they become
7425     unreferenced, but callers can call this in order to provide
7426     predictable cleanup. *)
7427
7428 ";
7429   generate_ocaml_structure_decls ();
7430
7431   (* The actions. *)
7432   List.iter (
7433     fun (name, style, _, _, _, shortdesc, _) ->
7434       generate_ocaml_prototype name style;
7435       pr "(** %s *)\n" shortdesc;
7436       pr "\n"
7437   ) all_functions_sorted
7438
7439 (* Generate the OCaml bindings implementation. *)
7440 and generate_ocaml_ml () =
7441   generate_header OCamlStyle LGPLv2plus;
7442
7443   pr "\
7444 type t
7445
7446 exception Error of string
7447 exception Handle_closed of string
7448
7449 external create : unit -> t = \"ocaml_guestfs_create\"
7450 external close : t -> unit = \"ocaml_guestfs_close\"
7451
7452 (* Give the exceptions names, so they can be raised from the C code. *)
7453 let () =
7454   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
7455   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
7456
7457 ";
7458
7459   generate_ocaml_structure_decls ();
7460
7461   (* The actions. *)
7462   List.iter (
7463     fun (name, style, _, _, _, shortdesc, _) ->
7464       generate_ocaml_prototype ~is_external:true name style;
7465   ) all_functions_sorted
7466
7467 (* Generate the OCaml bindings C implementation. *)
7468 and generate_ocaml_c () =
7469   generate_header CStyle LGPLv2plus;
7470
7471   pr "\
7472 #include <stdio.h>
7473 #include <stdlib.h>
7474 #include <string.h>
7475
7476 #include <caml/config.h>
7477 #include <caml/alloc.h>
7478 #include <caml/callback.h>
7479 #include <caml/fail.h>
7480 #include <caml/memory.h>
7481 #include <caml/mlvalues.h>
7482 #include <caml/signals.h>
7483
7484 #include <guestfs.h>
7485
7486 #include \"guestfs_c.h\"
7487
7488 /* Copy a hashtable of string pairs into an assoc-list.  We return
7489  * the list in reverse order, but hashtables aren't supposed to be
7490  * ordered anyway.
7491  */
7492 static CAMLprim value
7493 copy_table (char * const * argv)
7494 {
7495   CAMLparam0 ();
7496   CAMLlocal5 (rv, pairv, kv, vv, cons);
7497   int i;
7498
7499   rv = Val_int (0);
7500   for (i = 0; argv[i] != NULL; i += 2) {
7501     kv = caml_copy_string (argv[i]);
7502     vv = caml_copy_string (argv[i+1]);
7503     pairv = caml_alloc (2, 0);
7504     Store_field (pairv, 0, kv);
7505     Store_field (pairv, 1, vv);
7506     cons = caml_alloc (2, 0);
7507     Store_field (cons, 1, rv);
7508     rv = cons;
7509     Store_field (cons, 0, pairv);
7510   }
7511
7512   CAMLreturn (rv);
7513 }
7514
7515 ";
7516
7517   (* Struct copy functions. *)
7518
7519   let emit_ocaml_copy_list_function typ =
7520     pr "static CAMLprim value\n";
7521     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
7522     pr "{\n";
7523     pr "  CAMLparam0 ();\n";
7524     pr "  CAMLlocal2 (rv, v);\n";
7525     pr "  unsigned int i;\n";
7526     pr "\n";
7527     pr "  if (%ss->len == 0)\n" typ;
7528     pr "    CAMLreturn (Atom (0));\n";
7529     pr "  else {\n";
7530     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
7531     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
7532     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
7533     pr "      caml_modify (&Field (rv, i), v);\n";
7534     pr "    }\n";
7535     pr "    CAMLreturn (rv);\n";
7536     pr "  }\n";
7537     pr "}\n";
7538     pr "\n";
7539   in
7540
7541   List.iter (
7542     fun (typ, cols) ->
7543       let has_optpercent_col =
7544         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
7545
7546       pr "static CAMLprim value\n";
7547       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
7548       pr "{\n";
7549       pr "  CAMLparam0 ();\n";
7550       if has_optpercent_col then
7551         pr "  CAMLlocal3 (rv, v, v2);\n"
7552       else
7553         pr "  CAMLlocal2 (rv, v);\n";
7554       pr "\n";
7555       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
7556       iteri (
7557         fun i col ->
7558           (match col with
7559            | name, FString ->
7560                pr "  v = caml_copy_string (%s->%s);\n" typ name
7561            | name, FBuffer ->
7562                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
7563                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
7564                  typ name typ name
7565            | name, FUUID ->
7566                pr "  v = caml_alloc_string (32);\n";
7567                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
7568            | name, (FBytes|FInt64|FUInt64) ->
7569                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
7570            | name, (FInt32|FUInt32) ->
7571                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
7572            | name, FOptPercent ->
7573                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
7574                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
7575                pr "    v = caml_alloc (1, 0);\n";
7576                pr "    Store_field (v, 0, v2);\n";
7577                pr "  } else /* None */\n";
7578                pr "    v = Val_int (0);\n";
7579            | name, FChar ->
7580                pr "  v = Val_int (%s->%s);\n" typ name
7581           );
7582           pr "  Store_field (rv, %d, v);\n" i
7583       ) cols;
7584       pr "  CAMLreturn (rv);\n";
7585       pr "}\n";
7586       pr "\n";
7587   ) structs;
7588
7589   (* Emit a copy_TYPE_list function definition only if that function is used. *)
7590   List.iter (
7591     function
7592     | typ, (RStructListOnly | RStructAndList) ->
7593         (* generate the function for typ *)
7594         emit_ocaml_copy_list_function typ
7595     | typ, _ -> () (* empty *)
7596   ) (rstructs_used_by all_functions);
7597
7598   (* The wrappers. *)
7599   List.iter (
7600     fun (name, style, _, _, _, _, _) ->
7601       pr "/* Automatically generated wrapper for function\n";
7602       pr " * ";
7603       generate_ocaml_prototype name style;
7604       pr " */\n";
7605       pr "\n";
7606
7607       let params =
7608         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
7609
7610       let needs_extra_vs =
7611         match fst style with RConstOptString _ -> true | _ -> false in
7612
7613       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7614       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
7615       List.iter (pr ", value %s") (List.tl params); pr ");\n";
7616       pr "\n";
7617
7618       pr "CAMLprim value\n";
7619       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
7620       List.iter (pr ", value %s") (List.tl params);
7621       pr ")\n";
7622       pr "{\n";
7623
7624       (match params with
7625        | [p1; p2; p3; p4; p5] ->
7626            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
7627        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
7628            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
7629            pr "  CAMLxparam%d (%s);\n"
7630              (List.length rest) (String.concat ", " rest)
7631        | ps ->
7632            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
7633       );
7634       if not needs_extra_vs then
7635         pr "  CAMLlocal1 (rv);\n"
7636       else
7637         pr "  CAMLlocal3 (rv, v, v2);\n";
7638       pr "\n";
7639
7640       pr "  guestfs_h *g = Guestfs_val (gv);\n";
7641       pr "  if (g == NULL)\n";
7642       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
7643       pr "\n";
7644
7645       List.iter (
7646         function
7647         | Pathname n
7648         | Device n | Dev_or_Path n
7649         | String n
7650         | FileIn n
7651         | FileOut n ->
7652             pr "  const char *%s = String_val (%sv);\n" n n
7653         | OptString n ->
7654             pr "  const char *%s =\n" n;
7655             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
7656               n n
7657         | StringList n | DeviceList n ->
7658             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
7659         | Bool n ->
7660             pr "  int %s = Bool_val (%sv);\n" n n
7661         | Int n ->
7662             pr "  int %s = Int_val (%sv);\n" n n
7663         | Int64 n ->
7664             pr "  int64_t %s = Int64_val (%sv);\n" n n
7665       ) (snd style);
7666       let error_code =
7667         match fst style with
7668         | RErr -> pr "  int r;\n"; "-1"
7669         | RInt _ -> pr "  int r;\n"; "-1"
7670         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7671         | RBool _ -> pr "  int r;\n"; "-1"
7672         | RConstString _ | RConstOptString _ ->
7673             pr "  const char *r;\n"; "NULL"
7674         | RString _ -> pr "  char *r;\n"; "NULL"
7675         | RStringList _ ->
7676             pr "  int i;\n";
7677             pr "  char **r;\n";
7678             "NULL"
7679         | RStruct (_, typ) ->
7680             pr "  struct guestfs_%s *r;\n" typ; "NULL"
7681         | RStructList (_, typ) ->
7682             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7683         | RHashtable _ ->
7684             pr "  int i;\n";
7685             pr "  char **r;\n";
7686             "NULL"
7687         | RBufferOut _ ->
7688             pr "  char *r;\n";
7689             pr "  size_t size;\n";
7690             "NULL" in
7691       pr "\n";
7692
7693       pr "  caml_enter_blocking_section ();\n";
7694       pr "  r = guestfs_%s " name;
7695       generate_c_call_args ~handle:"g" style;
7696       pr ";\n";
7697       pr "  caml_leave_blocking_section ();\n";
7698
7699       List.iter (
7700         function
7701         | StringList n | DeviceList n ->
7702             pr "  ocaml_guestfs_free_strings (%s);\n" n;
7703         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
7704         | Bool _ | Int _ | Int64 _
7705         | FileIn _ | FileOut _ -> ()
7706       ) (snd style);
7707
7708       pr "  if (r == %s)\n" error_code;
7709       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
7710       pr "\n";
7711
7712       (match fst style with
7713        | RErr -> pr "  rv = Val_unit;\n"
7714        | RInt _ -> pr "  rv = Val_int (r);\n"
7715        | RInt64 _ ->
7716            pr "  rv = caml_copy_int64 (r);\n"
7717        | RBool _ -> pr "  rv = Val_bool (r);\n"
7718        | RConstString _ ->
7719            pr "  rv = caml_copy_string (r);\n"
7720        | RConstOptString _ ->
7721            pr "  if (r) { /* Some string */\n";
7722            pr "    v = caml_alloc (1, 0);\n";
7723            pr "    v2 = caml_copy_string (r);\n";
7724            pr "    Store_field (v, 0, v2);\n";
7725            pr "  } else /* None */\n";
7726            pr "    v = Val_int (0);\n";
7727        | RString _ ->
7728            pr "  rv = caml_copy_string (r);\n";
7729            pr "  free (r);\n"
7730        | RStringList _ ->
7731            pr "  rv = caml_copy_string_array ((const char **) r);\n";
7732            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7733            pr "  free (r);\n"
7734        | RStruct (_, typ) ->
7735            pr "  rv = copy_%s (r);\n" typ;
7736            pr "  guestfs_free_%s (r);\n" typ;
7737        | RStructList (_, typ) ->
7738            pr "  rv = copy_%s_list (r);\n" typ;
7739            pr "  guestfs_free_%s_list (r);\n" typ;
7740        | RHashtable _ ->
7741            pr "  rv = copy_table (r);\n";
7742            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7743            pr "  free (r);\n";
7744        | RBufferOut _ ->
7745            pr "  rv = caml_alloc_string (size);\n";
7746            pr "  memcpy (String_val (rv), r, size);\n";
7747       );
7748
7749       pr "  CAMLreturn (rv);\n";
7750       pr "}\n";
7751       pr "\n";
7752
7753       if List.length params > 5 then (
7754         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7755         pr "CAMLprim value ";
7756         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
7757         pr "CAMLprim value\n";
7758         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
7759         pr "{\n";
7760         pr "  return ocaml_guestfs_%s (argv[0]" name;
7761         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
7762         pr ");\n";
7763         pr "}\n";
7764         pr "\n"
7765       )
7766   ) all_functions_sorted
7767
7768 and generate_ocaml_structure_decls () =
7769   List.iter (
7770     fun (typ, cols) ->
7771       pr "type %s = {\n" typ;
7772       List.iter (
7773         function
7774         | name, FString -> pr "  %s : string;\n" name
7775         | name, FBuffer -> pr "  %s : string;\n" name
7776         | name, FUUID -> pr "  %s : string;\n" name
7777         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
7778         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
7779         | name, FChar -> pr "  %s : char;\n" name
7780         | name, FOptPercent -> pr "  %s : float option;\n" name
7781       ) cols;
7782       pr "}\n";
7783       pr "\n"
7784   ) structs
7785
7786 and generate_ocaml_prototype ?(is_external = false) name style =
7787   if is_external then pr "external " else pr "val ";
7788   pr "%s : t -> " name;
7789   List.iter (
7790     function
7791     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
7792     | OptString _ -> pr "string option -> "
7793     | StringList _ | DeviceList _ -> pr "string array -> "
7794     | Bool _ -> pr "bool -> "
7795     | Int _ -> pr "int -> "
7796     | Int64 _ -> pr "int64 -> "
7797   ) (snd style);
7798   (match fst style with
7799    | RErr -> pr "unit" (* all errors are turned into exceptions *)
7800    | RInt _ -> pr "int"
7801    | RInt64 _ -> pr "int64"
7802    | RBool _ -> pr "bool"
7803    | RConstString _ -> pr "string"
7804    | RConstOptString _ -> pr "string option"
7805    | RString _ | RBufferOut _ -> pr "string"
7806    | RStringList _ -> pr "string array"
7807    | RStruct (_, typ) -> pr "%s" typ
7808    | RStructList (_, typ) -> pr "%s array" typ
7809    | RHashtable _ -> pr "(string * string) list"
7810   );
7811   if is_external then (
7812     pr " = ";
7813     if List.length (snd style) + 1 > 5 then
7814       pr "\"ocaml_guestfs_%s_byte\" " name;
7815     pr "\"ocaml_guestfs_%s\"" name
7816   );
7817   pr "\n"
7818
7819 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
7820 and generate_perl_xs () =
7821   generate_header CStyle LGPLv2plus;
7822
7823   pr "\
7824 #include \"EXTERN.h\"
7825 #include \"perl.h\"
7826 #include \"XSUB.h\"
7827
7828 #include <guestfs.h>
7829
7830 #ifndef PRId64
7831 #define PRId64 \"lld\"
7832 #endif
7833
7834 static SV *
7835 my_newSVll(long long val) {
7836 #ifdef USE_64_BIT_ALL
7837   return newSViv(val);
7838 #else
7839   char buf[100];
7840   int len;
7841   len = snprintf(buf, 100, \"%%\" PRId64, val);
7842   return newSVpv(buf, len);
7843 #endif
7844 }
7845
7846 #ifndef PRIu64
7847 #define PRIu64 \"llu\"
7848 #endif
7849
7850 static SV *
7851 my_newSVull(unsigned long long val) {
7852 #ifdef USE_64_BIT_ALL
7853   return newSVuv(val);
7854 #else
7855   char buf[100];
7856   int len;
7857   len = snprintf(buf, 100, \"%%\" PRIu64, val);
7858   return newSVpv(buf, len);
7859 #endif
7860 }
7861
7862 /* http://www.perlmonks.org/?node_id=680842 */
7863 static char **
7864 XS_unpack_charPtrPtr (SV *arg) {
7865   char **ret;
7866   AV *av;
7867   I32 i;
7868
7869   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
7870     croak (\"array reference expected\");
7871
7872   av = (AV *)SvRV (arg);
7873   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
7874   if (!ret)
7875     croak (\"malloc failed\");
7876
7877   for (i = 0; i <= av_len (av); i++) {
7878     SV **elem = av_fetch (av, i, 0);
7879
7880     if (!elem || !*elem)
7881       croak (\"missing element in list\");
7882
7883     ret[i] = SvPV_nolen (*elem);
7884   }
7885
7886   ret[i] = NULL;
7887
7888   return ret;
7889 }
7890
7891 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
7892
7893 PROTOTYPES: ENABLE
7894
7895 guestfs_h *
7896 _create ()
7897    CODE:
7898       RETVAL = guestfs_create ();
7899       if (!RETVAL)
7900         croak (\"could not create guestfs handle\");
7901       guestfs_set_error_handler (RETVAL, NULL, NULL);
7902  OUTPUT:
7903       RETVAL
7904
7905 void
7906 DESTROY (g)
7907       guestfs_h *g;
7908  PPCODE:
7909       guestfs_close (g);
7910
7911 ";
7912
7913   List.iter (
7914     fun (name, style, _, _, _, _, _) ->
7915       (match fst style with
7916        | RErr -> pr "void\n"
7917        | RInt _ -> pr "SV *\n"
7918        | RInt64 _ -> pr "SV *\n"
7919        | RBool _ -> pr "SV *\n"
7920        | RConstString _ -> pr "SV *\n"
7921        | RConstOptString _ -> pr "SV *\n"
7922        | RString _ -> pr "SV *\n"
7923        | RBufferOut _ -> pr "SV *\n"
7924        | RStringList _
7925        | RStruct _ | RStructList _
7926        | RHashtable _ ->
7927            pr "void\n" (* all lists returned implictly on the stack *)
7928       );
7929       (* Call and arguments. *)
7930       pr "%s " name;
7931       generate_c_call_args ~handle:"g" ~decl:true style;
7932       pr "\n";
7933       pr "      guestfs_h *g;\n";
7934       iteri (
7935         fun i ->
7936           function
7937           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
7938               pr "      char *%s;\n" n
7939           | OptString n ->
7940               (* http://www.perlmonks.org/?node_id=554277
7941                * Note that the implicit handle argument means we have
7942                * to add 1 to the ST(x) operator.
7943                *)
7944               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
7945           | StringList n | DeviceList n -> pr "      char **%s;\n" n
7946           | Bool n -> pr "      int %s;\n" n
7947           | Int n -> pr "      int %s;\n" n
7948           | Int64 n -> pr "      int64_t %s;\n" n
7949       ) (snd style);
7950
7951       let do_cleanups () =
7952         List.iter (
7953           function
7954           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
7955           | Bool _ | Int _ | Int64 _
7956           | FileIn _ | FileOut _ -> ()
7957           | StringList n | DeviceList n -> pr "      free (%s);\n" n
7958         ) (snd style)
7959       in
7960
7961       (* Code. *)
7962       (match fst style with
7963        | RErr ->
7964            pr "PREINIT:\n";
7965            pr "      int r;\n";
7966            pr " PPCODE:\n";
7967            pr "      r = guestfs_%s " name;
7968            generate_c_call_args ~handle:"g" style;
7969            pr ";\n";
7970            do_cleanups ();
7971            pr "      if (r == -1)\n";
7972            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7973        | RInt n
7974        | RBool n ->
7975            pr "PREINIT:\n";
7976            pr "      int %s;\n" n;
7977            pr "   CODE:\n";
7978            pr "      %s = guestfs_%s " n name;
7979            generate_c_call_args ~handle:"g" style;
7980            pr ";\n";
7981            do_cleanups ();
7982            pr "      if (%s == -1)\n" n;
7983            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7984            pr "      RETVAL = newSViv (%s);\n" n;
7985            pr " OUTPUT:\n";
7986            pr "      RETVAL\n"
7987        | RInt64 n ->
7988            pr "PREINIT:\n";
7989            pr "      int64_t %s;\n" n;
7990            pr "   CODE:\n";
7991            pr "      %s = guestfs_%s " n name;
7992            generate_c_call_args ~handle:"g" style;
7993            pr ";\n";
7994            do_cleanups ();
7995            pr "      if (%s == -1)\n" n;
7996            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7997            pr "      RETVAL = my_newSVll (%s);\n" n;
7998            pr " OUTPUT:\n";
7999            pr "      RETVAL\n"
8000        | RConstString n ->
8001            pr "PREINIT:\n";
8002            pr "      const char *%s;\n" n;
8003            pr "   CODE:\n";
8004            pr "      %s = guestfs_%s " n name;
8005            generate_c_call_args ~handle:"g" style;
8006            pr ";\n";
8007            do_cleanups ();
8008            pr "      if (%s == NULL)\n" n;
8009            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8010            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8011            pr " OUTPUT:\n";
8012            pr "      RETVAL\n"
8013        | RConstOptString n ->
8014            pr "PREINIT:\n";
8015            pr "      const char *%s;\n" n;
8016            pr "   CODE:\n";
8017            pr "      %s = guestfs_%s " n name;
8018            generate_c_call_args ~handle:"g" style;
8019            pr ";\n";
8020            do_cleanups ();
8021            pr "      if (%s == NULL)\n" n;
8022            pr "        RETVAL = &PL_sv_undef;\n";
8023            pr "      else\n";
8024            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8025            pr " OUTPUT:\n";
8026            pr "      RETVAL\n"
8027        | RString n ->
8028            pr "PREINIT:\n";
8029            pr "      char *%s;\n" n;
8030            pr "   CODE:\n";
8031            pr "      %s = guestfs_%s " n name;
8032            generate_c_call_args ~handle:"g" style;
8033            pr ";\n";
8034            do_cleanups ();
8035            pr "      if (%s == NULL)\n" n;
8036            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8037            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8038            pr "      free (%s);\n" n;
8039            pr " OUTPUT:\n";
8040            pr "      RETVAL\n"
8041        | RStringList n | RHashtable n ->
8042            pr "PREINIT:\n";
8043            pr "      char **%s;\n" n;
8044            pr "      int i, n;\n";
8045            pr " PPCODE:\n";
8046            pr "      %s = guestfs_%s " n name;
8047            generate_c_call_args ~handle:"g" style;
8048            pr ";\n";
8049            do_cleanups ();
8050            pr "      if (%s == NULL)\n" n;
8051            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8052            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8053            pr "      EXTEND (SP, n);\n";
8054            pr "      for (i = 0; i < n; ++i) {\n";
8055            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8056            pr "        free (%s[i]);\n" n;
8057            pr "      }\n";
8058            pr "      free (%s);\n" n;
8059        | RStruct (n, typ) ->
8060            let cols = cols_of_struct typ in
8061            generate_perl_struct_code typ cols name style n do_cleanups
8062        | RStructList (n, typ) ->
8063            let cols = cols_of_struct typ in
8064            generate_perl_struct_list_code typ cols name style n do_cleanups
8065        | RBufferOut n ->
8066            pr "PREINIT:\n";
8067            pr "      char *%s;\n" n;
8068            pr "      size_t size;\n";
8069            pr "   CODE:\n";
8070            pr "      %s = guestfs_%s " n name;
8071            generate_c_call_args ~handle:"g" style;
8072            pr ";\n";
8073            do_cleanups ();
8074            pr "      if (%s == NULL)\n" n;
8075            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8076            pr "      RETVAL = newSVpv (%s, size);\n" n;
8077            pr "      free (%s);\n" n;
8078            pr " OUTPUT:\n";
8079            pr "      RETVAL\n"
8080       );
8081
8082       pr "\n"
8083   ) all_functions
8084
8085 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8086   pr "PREINIT:\n";
8087   pr "      struct guestfs_%s_list *%s;\n" typ n;
8088   pr "      int i;\n";
8089   pr "      HV *hv;\n";
8090   pr " PPCODE:\n";
8091   pr "      %s = guestfs_%s " n name;
8092   generate_c_call_args ~handle:"g" style;
8093   pr ";\n";
8094   do_cleanups ();
8095   pr "      if (%s == NULL)\n" n;
8096   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8097   pr "      EXTEND (SP, %s->len);\n" n;
8098   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8099   pr "        hv = newHV ();\n";
8100   List.iter (
8101     function
8102     | name, FString ->
8103         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8104           name (String.length name) n name
8105     | name, FUUID ->
8106         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8107           name (String.length name) n name
8108     | name, FBuffer ->
8109         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8110           name (String.length name) n name n name
8111     | name, (FBytes|FUInt64) ->
8112         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8113           name (String.length name) n name
8114     | name, FInt64 ->
8115         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8116           name (String.length name) n name
8117     | name, (FInt32|FUInt32) ->
8118         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8119           name (String.length name) n name
8120     | name, FChar ->
8121         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8122           name (String.length name) n name
8123     | name, FOptPercent ->
8124         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8125           name (String.length name) n name
8126   ) cols;
8127   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8128   pr "      }\n";
8129   pr "      guestfs_free_%s_list (%s);\n" typ n
8130
8131 and generate_perl_struct_code typ cols name style n do_cleanups =
8132   pr "PREINIT:\n";
8133   pr "      struct guestfs_%s *%s;\n" typ n;
8134   pr " PPCODE:\n";
8135   pr "      %s = guestfs_%s " n name;
8136   generate_c_call_args ~handle:"g" style;
8137   pr ";\n";
8138   do_cleanups ();
8139   pr "      if (%s == NULL)\n" n;
8140   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
8141   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8142   List.iter (
8143     fun ((name, _) as col) ->
8144       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8145
8146       match col with
8147       | name, FString ->
8148           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8149             n name
8150       | name, FBuffer ->
8151           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
8152             n name n name
8153       | name, FUUID ->
8154           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8155             n name
8156       | name, (FBytes|FUInt64) ->
8157           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8158             n name
8159       | name, FInt64 ->
8160           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8161             n name
8162       | name, (FInt32|FUInt32) ->
8163           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8164             n name
8165       | name, FChar ->
8166           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8167             n name
8168       | name, FOptPercent ->
8169           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8170             n name
8171   ) cols;
8172   pr "      free (%s);\n" n
8173
8174 (* Generate Sys/Guestfs.pm. *)
8175 and generate_perl_pm () =
8176   generate_header HashStyle LGPLv2plus;
8177
8178   pr "\
8179 =pod
8180
8181 =head1 NAME
8182
8183 Sys::Guestfs - Perl bindings for libguestfs
8184
8185 =head1 SYNOPSIS
8186
8187  use Sys::Guestfs;
8188
8189  my $h = Sys::Guestfs->new ();
8190  $h->add_drive ('guest.img');
8191  $h->launch ();
8192  $h->mount ('/dev/sda1', '/');
8193  $h->touch ('/hello');
8194  $h->sync ();
8195
8196 =head1 DESCRIPTION
8197
8198 The C<Sys::Guestfs> module provides a Perl XS binding to the
8199 libguestfs API for examining and modifying virtual machine
8200 disk images.
8201
8202 Amongst the things this is good for: making batch configuration
8203 changes to guests, getting disk used/free statistics (see also:
8204 virt-df), migrating between virtualization systems (see also:
8205 virt-p2v), performing partial backups, performing partial guest
8206 clones, cloning guests and changing registry/UUID/hostname info, and
8207 much else besides.
8208
8209 Libguestfs uses Linux kernel and qemu code, and can access any type of
8210 guest filesystem that Linux and qemu can, including but not limited
8211 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8212 schemes, qcow, qcow2, vmdk.
8213
8214 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8215 LVs, what filesystem is in each LV, etc.).  It can also run commands
8216 in the context of the guest.  Also you can access filesystems over FTP.
8217
8218 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8219 functions for using libguestfs from Perl, including integration
8220 with libvirt.
8221
8222 =head1 ERRORS
8223
8224 All errors turn into calls to C<croak> (see L<Carp(3)>).
8225
8226 =head1 METHODS
8227
8228 =over 4
8229
8230 =cut
8231
8232 package Sys::Guestfs;
8233
8234 use strict;
8235 use warnings;
8236
8237 require XSLoader;
8238 XSLoader::load ('Sys::Guestfs');
8239
8240 =item $h = Sys::Guestfs->new ();
8241
8242 Create a new guestfs handle.
8243
8244 =cut
8245
8246 sub new {
8247   my $proto = shift;
8248   my $class = ref ($proto) || $proto;
8249
8250   my $self = Sys::Guestfs::_create ();
8251   bless $self, $class;
8252   return $self;
8253 }
8254
8255 ";
8256
8257   (* Actions.  We only need to print documentation for these as
8258    * they are pulled in from the XS code automatically.
8259    *)
8260   List.iter (
8261     fun (name, style, _, flags, _, _, longdesc) ->
8262       if not (List.mem NotInDocs flags) then (
8263         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8264         pr "=item ";
8265         generate_perl_prototype name style;
8266         pr "\n\n";
8267         pr "%s\n\n" longdesc;
8268         if List.mem ProtocolLimitWarning flags then
8269           pr "%s\n\n" protocol_limit_warning;
8270         if List.mem DangerWillRobinson flags then
8271           pr "%s\n\n" danger_will_robinson;
8272         match deprecation_notice flags with
8273         | None -> ()
8274         | Some txt -> pr "%s\n\n" txt
8275       )
8276   ) all_functions_sorted;
8277
8278   (* End of file. *)
8279   pr "\
8280 =cut
8281
8282 1;
8283
8284 =back
8285
8286 =head1 COPYRIGHT
8287
8288 Copyright (C) %s Red Hat Inc.
8289
8290 =head1 LICENSE
8291
8292 Please see the file COPYING.LIB for the full license.
8293
8294 =head1 SEE ALSO
8295
8296 L<guestfs(3)>,
8297 L<guestfish(1)>,
8298 L<http://libguestfs.org>,
8299 L<Sys::Guestfs::Lib(3)>.
8300
8301 =cut
8302 " copyright_years
8303
8304 and generate_perl_prototype name style =
8305   (match fst style with
8306    | RErr -> ()
8307    | RBool n
8308    | RInt n
8309    | RInt64 n
8310    | RConstString n
8311    | RConstOptString n
8312    | RString n
8313    | RBufferOut n -> pr "$%s = " n
8314    | RStruct (n,_)
8315    | RHashtable n -> pr "%%%s = " n
8316    | RStringList n
8317    | RStructList (n,_) -> pr "@%s = " n
8318   );
8319   pr "$h->%s (" name;
8320   let comma = ref false in
8321   List.iter (
8322     fun arg ->
8323       if !comma then pr ", ";
8324       comma := true;
8325       match arg with
8326       | Pathname n | Device n | Dev_or_Path n | String n
8327       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8328           pr "$%s" n
8329       | StringList n | DeviceList n ->
8330           pr "\\@%s" n
8331   ) (snd style);
8332   pr ");"
8333
8334 (* Generate Python C module. *)
8335 and generate_python_c () =
8336   generate_header CStyle LGPLv2plus;
8337
8338   pr "\
8339 #include <Python.h>
8340
8341 #include <stdio.h>
8342 #include <stdlib.h>
8343 #include <assert.h>
8344
8345 #include \"guestfs.h\"
8346
8347 typedef struct {
8348   PyObject_HEAD
8349   guestfs_h *g;
8350 } Pyguestfs_Object;
8351
8352 static guestfs_h *
8353 get_handle (PyObject *obj)
8354 {
8355   assert (obj);
8356   assert (obj != Py_None);
8357   return ((Pyguestfs_Object *) obj)->g;
8358 }
8359
8360 static PyObject *
8361 put_handle (guestfs_h *g)
8362 {
8363   assert (g);
8364   return
8365     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8366 }
8367
8368 /* This list should be freed (but not the strings) after use. */
8369 static char **
8370 get_string_list (PyObject *obj)
8371 {
8372   int i, len;
8373   char **r;
8374
8375   assert (obj);
8376
8377   if (!PyList_Check (obj)) {
8378     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8379     return NULL;
8380   }
8381
8382   len = PyList_Size (obj);
8383   r = malloc (sizeof (char *) * (len+1));
8384   if (r == NULL) {
8385     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8386     return NULL;
8387   }
8388
8389   for (i = 0; i < len; ++i)
8390     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8391   r[len] = NULL;
8392
8393   return r;
8394 }
8395
8396 static PyObject *
8397 put_string_list (char * const * const argv)
8398 {
8399   PyObject *list;
8400   int argc, i;
8401
8402   for (argc = 0; argv[argc] != NULL; ++argc)
8403     ;
8404
8405   list = PyList_New (argc);
8406   for (i = 0; i < argc; ++i)
8407     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8408
8409   return list;
8410 }
8411
8412 static PyObject *
8413 put_table (char * const * const argv)
8414 {
8415   PyObject *list, *item;
8416   int argc, i;
8417
8418   for (argc = 0; argv[argc] != NULL; ++argc)
8419     ;
8420
8421   list = PyList_New (argc >> 1);
8422   for (i = 0; i < argc; i += 2) {
8423     item = PyTuple_New (2);
8424     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8425     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8426     PyList_SetItem (list, i >> 1, item);
8427   }
8428
8429   return list;
8430 }
8431
8432 static void
8433 free_strings (char **argv)
8434 {
8435   int argc;
8436
8437   for (argc = 0; argv[argc] != NULL; ++argc)
8438     free (argv[argc]);
8439   free (argv);
8440 }
8441
8442 static PyObject *
8443 py_guestfs_create (PyObject *self, PyObject *args)
8444 {
8445   guestfs_h *g;
8446
8447   g = guestfs_create ();
8448   if (g == NULL) {
8449     PyErr_SetString (PyExc_RuntimeError,
8450                      \"guestfs.create: failed to allocate handle\");
8451     return NULL;
8452   }
8453   guestfs_set_error_handler (g, NULL, NULL);
8454   return put_handle (g);
8455 }
8456
8457 static PyObject *
8458 py_guestfs_close (PyObject *self, PyObject *args)
8459 {
8460   PyObject *py_g;
8461   guestfs_h *g;
8462
8463   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
8464     return NULL;
8465   g = get_handle (py_g);
8466
8467   guestfs_close (g);
8468
8469   Py_INCREF (Py_None);
8470   return Py_None;
8471 }
8472
8473 ";
8474
8475   let emit_put_list_function typ =
8476     pr "static PyObject *\n";
8477     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
8478     pr "{\n";
8479     pr "  PyObject *list;\n";
8480     pr "  int i;\n";
8481     pr "\n";
8482     pr "  list = PyList_New (%ss->len);\n" typ;
8483     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
8484     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
8485     pr "  return list;\n";
8486     pr "};\n";
8487     pr "\n"
8488   in
8489
8490   (* Structures, turned into Python dictionaries. *)
8491   List.iter (
8492     fun (typ, cols) ->
8493       pr "static PyObject *\n";
8494       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
8495       pr "{\n";
8496       pr "  PyObject *dict;\n";
8497       pr "\n";
8498       pr "  dict = PyDict_New ();\n";
8499       List.iter (
8500         function
8501         | name, FString ->
8502             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8503             pr "                        PyString_FromString (%s->%s));\n"
8504               typ name
8505         | name, FBuffer ->
8506             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8507             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
8508               typ name typ name
8509         | name, FUUID ->
8510             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8511             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
8512               typ name
8513         | name, (FBytes|FUInt64) ->
8514             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8515             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
8516               typ name
8517         | name, FInt64 ->
8518             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8519             pr "                        PyLong_FromLongLong (%s->%s));\n"
8520               typ name
8521         | name, FUInt32 ->
8522             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8523             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
8524               typ name
8525         | name, FInt32 ->
8526             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8527             pr "                        PyLong_FromLong (%s->%s));\n"
8528               typ name
8529         | name, FOptPercent ->
8530             pr "  if (%s->%s >= 0)\n" typ name;
8531             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
8532             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
8533               typ name;
8534             pr "  else {\n";
8535             pr "    Py_INCREF (Py_None);\n";
8536             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
8537             pr "  }\n"
8538         | name, FChar ->
8539             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8540             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
8541       ) cols;
8542       pr "  return dict;\n";
8543       pr "};\n";
8544       pr "\n";
8545
8546   ) structs;
8547
8548   (* Emit a put_TYPE_list function definition only if that function is used. *)
8549   List.iter (
8550     function
8551     | typ, (RStructListOnly | RStructAndList) ->
8552         (* generate the function for typ *)
8553         emit_put_list_function typ
8554     | typ, _ -> () (* empty *)
8555   ) (rstructs_used_by all_functions);
8556
8557   (* Python wrapper functions. *)
8558   List.iter (
8559     fun (name, style, _, _, _, _, _) ->
8560       pr "static PyObject *\n";
8561       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
8562       pr "{\n";
8563
8564       pr "  PyObject *py_g;\n";
8565       pr "  guestfs_h *g;\n";
8566       pr "  PyObject *py_r;\n";
8567
8568       let error_code =
8569         match fst style with
8570         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
8571         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8572         | RConstString _ | RConstOptString _ ->
8573             pr "  const char *r;\n"; "NULL"
8574         | RString _ -> pr "  char *r;\n"; "NULL"
8575         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
8576         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
8577         | RStructList (_, typ) ->
8578             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8579         | RBufferOut _ ->
8580             pr "  char *r;\n";
8581             pr "  size_t size;\n";
8582             "NULL" in
8583
8584       List.iter (
8585         function
8586         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8587             pr "  const char *%s;\n" n
8588         | OptString n -> pr "  const char *%s;\n" n
8589         | StringList n | DeviceList n ->
8590             pr "  PyObject *py_%s;\n" n;
8591             pr "  char **%s;\n" n
8592         | Bool n -> pr "  int %s;\n" n
8593         | Int n -> pr "  int %s;\n" n
8594         | Int64 n -> pr "  long long %s;\n" n
8595       ) (snd style);
8596
8597       pr "\n";
8598
8599       (* Convert the parameters. *)
8600       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
8601       List.iter (
8602         function
8603         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
8604         | OptString _ -> pr "z"
8605         | StringList _ | DeviceList _ -> pr "O"
8606         | Bool _ -> pr "i" (* XXX Python has booleans? *)
8607         | Int _ -> pr "i"
8608         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
8609                              * emulate C's int/long/long long in Python?
8610                              *)
8611       ) (snd style);
8612       pr ":guestfs_%s\",\n" name;
8613       pr "                         &py_g";
8614       List.iter (
8615         function
8616         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
8617         | OptString n -> pr ", &%s" n
8618         | StringList n | DeviceList n -> pr ", &py_%s" n
8619         | Bool n -> pr ", &%s" n
8620         | Int n -> pr ", &%s" n
8621         | Int64 n -> pr ", &%s" n
8622       ) (snd style);
8623
8624       pr "))\n";
8625       pr "    return NULL;\n";
8626
8627       pr "  g = get_handle (py_g);\n";
8628       List.iter (
8629         function
8630         | Pathname _ | Device _ | Dev_or_Path _ | String _
8631         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8632         | StringList n | DeviceList n ->
8633             pr "  %s = get_string_list (py_%s);\n" n n;
8634             pr "  if (!%s) return NULL;\n" n
8635       ) (snd style);
8636
8637       pr "\n";
8638
8639       pr "  r = guestfs_%s " name;
8640       generate_c_call_args ~handle:"g" style;
8641       pr ";\n";
8642
8643       List.iter (
8644         function
8645         | Pathname _ | Device _ | Dev_or_Path _ | String _
8646         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8647         | StringList n | DeviceList n ->
8648             pr "  free (%s);\n" n
8649       ) (snd style);
8650
8651       pr "  if (r == %s) {\n" error_code;
8652       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
8653       pr "    return NULL;\n";
8654       pr "  }\n";
8655       pr "\n";
8656
8657       (match fst style with
8658        | RErr ->
8659            pr "  Py_INCREF (Py_None);\n";
8660            pr "  py_r = Py_None;\n"
8661        | RInt _
8662        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
8663        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
8664        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
8665        | RConstOptString _ ->
8666            pr "  if (r)\n";
8667            pr "    py_r = PyString_FromString (r);\n";
8668            pr "  else {\n";
8669            pr "    Py_INCREF (Py_None);\n";
8670            pr "    py_r = Py_None;\n";
8671            pr "  }\n"
8672        | RString _ ->
8673            pr "  py_r = PyString_FromString (r);\n";
8674            pr "  free (r);\n"
8675        | RStringList _ ->
8676            pr "  py_r = put_string_list (r);\n";
8677            pr "  free_strings (r);\n"
8678        | RStruct (_, typ) ->
8679            pr "  py_r = put_%s (r);\n" typ;
8680            pr "  guestfs_free_%s (r);\n" typ
8681        | RStructList (_, typ) ->
8682            pr "  py_r = put_%s_list (r);\n" typ;
8683            pr "  guestfs_free_%s_list (r);\n" typ
8684        | RHashtable n ->
8685            pr "  py_r = put_table (r);\n";
8686            pr "  free_strings (r);\n"
8687        | RBufferOut _ ->
8688            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
8689            pr "  free (r);\n"
8690       );
8691
8692       pr "  return py_r;\n";
8693       pr "}\n";
8694       pr "\n"
8695   ) all_functions;
8696
8697   (* Table of functions. *)
8698   pr "static PyMethodDef methods[] = {\n";
8699   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
8700   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
8701   List.iter (
8702     fun (name, _, _, _, _, _, _) ->
8703       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
8704         name name
8705   ) all_functions;
8706   pr "  { NULL, NULL, 0, NULL }\n";
8707   pr "};\n";
8708   pr "\n";
8709
8710   (* Init function. *)
8711   pr "\
8712 void
8713 initlibguestfsmod (void)
8714 {
8715   static int initialized = 0;
8716
8717   if (initialized) return;
8718   Py_InitModule ((char *) \"libguestfsmod\", methods);
8719   initialized = 1;
8720 }
8721 "
8722
8723 (* Generate Python module. *)
8724 and generate_python_py () =
8725   generate_header HashStyle LGPLv2plus;
8726
8727   pr "\
8728 u\"\"\"Python bindings for libguestfs
8729
8730 import guestfs
8731 g = guestfs.GuestFS ()
8732 g.add_drive (\"guest.img\")
8733 g.launch ()
8734 parts = g.list_partitions ()
8735
8736 The guestfs module provides a Python binding to the libguestfs API
8737 for examining and modifying virtual machine disk images.
8738
8739 Amongst the things this is good for: making batch configuration
8740 changes to guests, getting disk used/free statistics (see also:
8741 virt-df), migrating between virtualization systems (see also:
8742 virt-p2v), performing partial backups, performing partial guest
8743 clones, cloning guests and changing registry/UUID/hostname info, and
8744 much else besides.
8745
8746 Libguestfs uses Linux kernel and qemu code, and can access any type of
8747 guest filesystem that Linux and qemu can, including but not limited
8748 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8749 schemes, qcow, qcow2, vmdk.
8750
8751 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8752 LVs, what filesystem is in each LV, etc.).  It can also run commands
8753 in the context of the guest.  Also you can access filesystems over FTP.
8754
8755 Errors which happen while using the API are turned into Python
8756 RuntimeError exceptions.
8757
8758 To create a guestfs handle you usually have to perform the following
8759 sequence of calls:
8760
8761 # Create the handle, call add_drive at least once, and possibly
8762 # several times if the guest has multiple block devices:
8763 g = guestfs.GuestFS ()
8764 g.add_drive (\"guest.img\")
8765
8766 # Launch the qemu subprocess and wait for it to become ready:
8767 g.launch ()
8768
8769 # Now you can issue commands, for example:
8770 logvols = g.lvs ()
8771
8772 \"\"\"
8773
8774 import libguestfsmod
8775
8776 class GuestFS:
8777     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
8778
8779     def __init__ (self):
8780         \"\"\"Create a new libguestfs handle.\"\"\"
8781         self._o = libguestfsmod.create ()
8782
8783     def __del__ (self):
8784         libguestfsmod.close (self._o)
8785
8786 ";
8787
8788   List.iter (
8789     fun (name, style, _, flags, _, _, longdesc) ->
8790       pr "    def %s " name;
8791       generate_py_call_args ~handle:"self" (snd style);
8792       pr ":\n";
8793
8794       if not (List.mem NotInDocs flags) then (
8795         let doc = replace_str longdesc "C<guestfs_" "C<g." in
8796         let doc =
8797           match fst style with
8798           | RErr | RInt _ | RInt64 _ | RBool _
8799           | RConstOptString _ | RConstString _
8800           | RString _ | RBufferOut _ -> doc
8801           | RStringList _ ->
8802               doc ^ "\n\nThis function returns a list of strings."
8803           | RStruct (_, typ) ->
8804               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
8805           | RStructList (_, typ) ->
8806               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
8807           | RHashtable _ ->
8808               doc ^ "\n\nThis function returns a dictionary." in
8809         let doc =
8810           if List.mem ProtocolLimitWarning flags then
8811             doc ^ "\n\n" ^ protocol_limit_warning
8812           else doc in
8813         let doc =
8814           if List.mem DangerWillRobinson flags then
8815             doc ^ "\n\n" ^ danger_will_robinson
8816           else doc in
8817         let doc =
8818           match deprecation_notice flags with
8819           | None -> doc
8820           | Some txt -> doc ^ "\n\n" ^ txt in
8821         let doc = pod2text ~width:60 name doc in
8822         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
8823         let doc = String.concat "\n        " doc in
8824         pr "        u\"\"\"%s\"\"\"\n" doc;
8825       );
8826       pr "        return libguestfsmod.%s " name;
8827       generate_py_call_args ~handle:"self._o" (snd style);
8828       pr "\n";
8829       pr "\n";
8830   ) all_functions
8831
8832 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
8833 and generate_py_call_args ~handle args =
8834   pr "(%s" handle;
8835   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
8836   pr ")"
8837
8838 (* Useful if you need the longdesc POD text as plain text.  Returns a
8839  * list of lines.
8840  *
8841  * Because this is very slow (the slowest part of autogeneration),
8842  * we memoize the results.
8843  *)
8844 and pod2text ~width name longdesc =
8845   let key = width, name, longdesc in
8846   try Hashtbl.find pod2text_memo key
8847   with Not_found ->
8848     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
8849     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
8850     close_out chan;
8851     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
8852     let chan = open_process_in cmd in
8853     let lines = ref [] in
8854     let rec loop i =
8855       let line = input_line chan in
8856       if i = 1 then             (* discard the first line of output *)
8857         loop (i+1)
8858       else (
8859         let line = triml line in
8860         lines := line :: !lines;
8861         loop (i+1)
8862       ) in
8863     let lines = try loop 1 with End_of_file -> List.rev !lines in
8864     unlink filename;
8865     (match close_process_in chan with
8866      | WEXITED 0 -> ()
8867      | WEXITED i ->
8868          failwithf "pod2text: process exited with non-zero status (%d)" i
8869      | WSIGNALED i | WSTOPPED i ->
8870          failwithf "pod2text: process signalled or stopped by signal %d" i
8871     );
8872     Hashtbl.add pod2text_memo key lines;
8873     pod2text_memo_updated ();
8874     lines
8875
8876 (* Generate ruby bindings. *)
8877 and generate_ruby_c () =
8878   generate_header CStyle LGPLv2plus;
8879
8880   pr "\
8881 #include <stdio.h>
8882 #include <stdlib.h>
8883
8884 #include <ruby.h>
8885
8886 #include \"guestfs.h\"
8887
8888 #include \"extconf.h\"
8889
8890 /* For Ruby < 1.9 */
8891 #ifndef RARRAY_LEN
8892 #define RARRAY_LEN(r) (RARRAY((r))->len)
8893 #endif
8894
8895 static VALUE m_guestfs;                 /* guestfs module */
8896 static VALUE c_guestfs;                 /* guestfs_h handle */
8897 static VALUE e_Error;                   /* used for all errors */
8898
8899 static void ruby_guestfs_free (void *p)
8900 {
8901   if (!p) return;
8902   guestfs_close ((guestfs_h *) p);
8903 }
8904
8905 static VALUE ruby_guestfs_create (VALUE m)
8906 {
8907   guestfs_h *g;
8908
8909   g = guestfs_create ();
8910   if (!g)
8911     rb_raise (e_Error, \"failed to create guestfs handle\");
8912
8913   /* Don't print error messages to stderr by default. */
8914   guestfs_set_error_handler (g, NULL, NULL);
8915
8916   /* Wrap it, and make sure the close function is called when the
8917    * handle goes away.
8918    */
8919   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
8920 }
8921
8922 static VALUE ruby_guestfs_close (VALUE gv)
8923 {
8924   guestfs_h *g;
8925   Data_Get_Struct (gv, guestfs_h, g);
8926
8927   ruby_guestfs_free (g);
8928   DATA_PTR (gv) = NULL;
8929
8930   return Qnil;
8931 }
8932
8933 ";
8934
8935   List.iter (
8936     fun (name, style, _, _, _, _, _) ->
8937       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
8938       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
8939       pr ")\n";
8940       pr "{\n";
8941       pr "  guestfs_h *g;\n";
8942       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
8943       pr "  if (!g)\n";
8944       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
8945         name;
8946       pr "\n";
8947
8948       List.iter (
8949         function
8950         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8951             pr "  Check_Type (%sv, T_STRING);\n" n;
8952             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
8953             pr "  if (!%s)\n" n;
8954             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
8955             pr "              \"%s\", \"%s\");\n" n name
8956         | OptString n ->
8957             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
8958         | StringList n | DeviceList n ->
8959             pr "  char **%s;\n" n;
8960             pr "  Check_Type (%sv, T_ARRAY);\n" n;
8961             pr "  {\n";
8962             pr "    int i, len;\n";
8963             pr "    len = RARRAY_LEN (%sv);\n" n;
8964             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
8965               n;
8966             pr "    for (i = 0; i < len; ++i) {\n";
8967             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
8968             pr "      %s[i] = StringValueCStr (v);\n" n;
8969             pr "    }\n";
8970             pr "    %s[len] = NULL;\n" n;
8971             pr "  }\n";
8972         | Bool n ->
8973             pr "  int %s = RTEST (%sv);\n" n n
8974         | Int n ->
8975             pr "  int %s = NUM2INT (%sv);\n" n n
8976         | Int64 n ->
8977             pr "  long long %s = NUM2LL (%sv);\n" n n
8978       ) (snd style);
8979       pr "\n";
8980
8981       let error_code =
8982         match fst style with
8983         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
8984         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8985         | RConstString _ | RConstOptString _ ->
8986             pr "  const char *r;\n"; "NULL"
8987         | RString _ -> pr "  char *r;\n"; "NULL"
8988         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
8989         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
8990         | RStructList (_, typ) ->
8991             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8992         | RBufferOut _ ->
8993             pr "  char *r;\n";
8994             pr "  size_t size;\n";
8995             "NULL" in
8996       pr "\n";
8997
8998       pr "  r = guestfs_%s " name;
8999       generate_c_call_args ~handle:"g" style;
9000       pr ";\n";
9001
9002       List.iter (
9003         function
9004         | Pathname _ | Device _ | Dev_or_Path _ | String _
9005         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9006         | StringList n | DeviceList n ->
9007             pr "  free (%s);\n" n
9008       ) (snd style);
9009
9010       pr "  if (r == %s)\n" error_code;
9011       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9012       pr "\n";
9013
9014       (match fst style with
9015        | RErr ->
9016            pr "  return Qnil;\n"
9017        | RInt _ | RBool _ ->
9018            pr "  return INT2NUM (r);\n"
9019        | RInt64 _ ->
9020            pr "  return ULL2NUM (r);\n"
9021        | RConstString _ ->
9022            pr "  return rb_str_new2 (r);\n";
9023        | RConstOptString _ ->
9024            pr "  if (r)\n";
9025            pr "    return rb_str_new2 (r);\n";
9026            pr "  else\n";
9027            pr "    return Qnil;\n";
9028        | RString _ ->
9029            pr "  VALUE rv = rb_str_new2 (r);\n";
9030            pr "  free (r);\n";
9031            pr "  return rv;\n";
9032        | RStringList _ ->
9033            pr "  int i, len = 0;\n";
9034            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9035            pr "  VALUE rv = rb_ary_new2 (len);\n";
9036            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9037            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9038            pr "    free (r[i]);\n";
9039            pr "  }\n";
9040            pr "  free (r);\n";
9041            pr "  return rv;\n"
9042        | RStruct (_, typ) ->
9043            let cols = cols_of_struct typ in
9044            generate_ruby_struct_code typ cols
9045        | RStructList (_, typ) ->
9046            let cols = cols_of_struct typ in
9047            generate_ruby_struct_list_code typ cols
9048        | RHashtable _ ->
9049            pr "  VALUE rv = rb_hash_new ();\n";
9050            pr "  int i;\n";
9051            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9052            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9053            pr "    free (r[i]);\n";
9054            pr "    free (r[i+1]);\n";
9055            pr "  }\n";
9056            pr "  free (r);\n";
9057            pr "  return rv;\n"
9058        | RBufferOut _ ->
9059            pr "  VALUE rv = rb_str_new (r, size);\n";
9060            pr "  free (r);\n";
9061            pr "  return rv;\n";
9062       );
9063
9064       pr "}\n";
9065       pr "\n"
9066   ) all_functions;
9067
9068   pr "\
9069 /* Initialize the module. */
9070 void Init__guestfs ()
9071 {
9072   m_guestfs = rb_define_module (\"Guestfs\");
9073   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9074   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9075
9076   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9077   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9078
9079 ";
9080   (* Define the rest of the methods. *)
9081   List.iter (
9082     fun (name, style, _, _, _, _, _) ->
9083       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9084       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9085   ) all_functions;
9086
9087   pr "}\n"
9088
9089 (* Ruby code to return a struct. *)
9090 and generate_ruby_struct_code typ cols =
9091   pr "  VALUE rv = rb_hash_new ();\n";
9092   List.iter (
9093     function
9094     | name, FString ->
9095         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9096     | name, FBuffer ->
9097         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9098     | name, FUUID ->
9099         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9100     | name, (FBytes|FUInt64) ->
9101         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9102     | name, FInt64 ->
9103         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9104     | name, FUInt32 ->
9105         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9106     | name, FInt32 ->
9107         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9108     | name, FOptPercent ->
9109         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9110     | name, FChar -> (* XXX wrong? *)
9111         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9112   ) cols;
9113   pr "  guestfs_free_%s (r);\n" typ;
9114   pr "  return rv;\n"
9115
9116 (* Ruby code to return a struct list. *)
9117 and generate_ruby_struct_list_code typ cols =
9118   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9119   pr "  int i;\n";
9120   pr "  for (i = 0; i < r->len; ++i) {\n";
9121   pr "    VALUE hv = rb_hash_new ();\n";
9122   List.iter (
9123     function
9124     | name, FString ->
9125         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9126     | name, FBuffer ->
9127         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
9128     | name, FUUID ->
9129         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9130     | name, (FBytes|FUInt64) ->
9131         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9132     | name, FInt64 ->
9133         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9134     | name, FUInt32 ->
9135         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9136     | name, FInt32 ->
9137         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9138     | name, FOptPercent ->
9139         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9140     | name, FChar -> (* XXX wrong? *)
9141         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9142   ) cols;
9143   pr "    rb_ary_push (rv, hv);\n";
9144   pr "  }\n";
9145   pr "  guestfs_free_%s_list (r);\n" typ;
9146   pr "  return rv;\n"
9147
9148 (* Generate Java bindings GuestFS.java file. *)
9149 and generate_java_java () =
9150   generate_header CStyle LGPLv2plus;
9151
9152   pr "\
9153 package com.redhat.et.libguestfs;
9154
9155 import java.util.HashMap;
9156 import com.redhat.et.libguestfs.LibGuestFSException;
9157 import com.redhat.et.libguestfs.PV;
9158 import com.redhat.et.libguestfs.VG;
9159 import com.redhat.et.libguestfs.LV;
9160 import com.redhat.et.libguestfs.Stat;
9161 import com.redhat.et.libguestfs.StatVFS;
9162 import com.redhat.et.libguestfs.IntBool;
9163 import com.redhat.et.libguestfs.Dirent;
9164
9165 /**
9166  * The GuestFS object is a libguestfs handle.
9167  *
9168  * @author rjones
9169  */
9170 public class GuestFS {
9171   // Load the native code.
9172   static {
9173     System.loadLibrary (\"guestfs_jni\");
9174   }
9175
9176   /**
9177    * The native guestfs_h pointer.
9178    */
9179   long g;
9180
9181   /**
9182    * Create a libguestfs handle.
9183    *
9184    * @throws LibGuestFSException
9185    */
9186   public GuestFS () throws LibGuestFSException
9187   {
9188     g = _create ();
9189   }
9190   private native long _create () throws LibGuestFSException;
9191
9192   /**
9193    * Close a libguestfs handle.
9194    *
9195    * You can also leave handles to be collected by the garbage
9196    * collector, but this method ensures that the resources used
9197    * by the handle are freed up immediately.  If you call any
9198    * other methods after closing the handle, you will get an
9199    * exception.
9200    *
9201    * @throws LibGuestFSException
9202    */
9203   public void close () throws LibGuestFSException
9204   {
9205     if (g != 0)
9206       _close (g);
9207     g = 0;
9208   }
9209   private native void _close (long g) throws LibGuestFSException;
9210
9211   public void finalize () throws LibGuestFSException
9212   {
9213     close ();
9214   }
9215
9216 ";
9217
9218   List.iter (
9219     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9220       if not (List.mem NotInDocs flags); then (
9221         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9222         let doc =
9223           if List.mem ProtocolLimitWarning flags then
9224             doc ^ "\n\n" ^ protocol_limit_warning
9225           else doc in
9226         let doc =
9227           if List.mem DangerWillRobinson flags then
9228             doc ^ "\n\n" ^ danger_will_robinson
9229           else doc in
9230         let doc =
9231           match deprecation_notice flags with
9232           | None -> doc
9233           | Some txt -> doc ^ "\n\n" ^ txt in
9234         let doc = pod2text ~width:60 name doc in
9235         let doc = List.map (            (* RHBZ#501883 *)
9236           function
9237           | "" -> "<p>"
9238           | nonempty -> nonempty
9239         ) doc in
9240         let doc = String.concat "\n   * " doc in
9241
9242         pr "  /**\n";
9243         pr "   * %s\n" shortdesc;
9244         pr "   * <p>\n";
9245         pr "   * %s\n" doc;
9246         pr "   * @throws LibGuestFSException\n";
9247         pr "   */\n";
9248         pr "  ";
9249       );
9250       generate_java_prototype ~public:true ~semicolon:false name style;
9251       pr "\n";
9252       pr "  {\n";
9253       pr "    if (g == 0)\n";
9254       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9255         name;
9256       pr "    ";
9257       if fst style <> RErr then pr "return ";
9258       pr "_%s " name;
9259       generate_java_call_args ~handle:"g" (snd style);
9260       pr ";\n";
9261       pr "  }\n";
9262       pr "  ";
9263       generate_java_prototype ~privat:true ~native:true name style;
9264       pr "\n";
9265       pr "\n";
9266   ) all_functions;
9267
9268   pr "}\n"
9269
9270 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9271 and generate_java_call_args ~handle args =
9272   pr "(%s" handle;
9273   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9274   pr ")"
9275
9276 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9277     ?(semicolon=true) name style =
9278   if privat then pr "private ";
9279   if public then pr "public ";
9280   if native then pr "native ";
9281
9282   (* return type *)
9283   (match fst style with
9284    | RErr -> pr "void ";
9285    | RInt _ -> pr "int ";
9286    | RInt64 _ -> pr "long ";
9287    | RBool _ -> pr "boolean ";
9288    | RConstString _ | RConstOptString _ | RString _
9289    | RBufferOut _ -> pr "String ";
9290    | RStringList _ -> pr "String[] ";
9291    | RStruct (_, typ) ->
9292        let name = java_name_of_struct typ in
9293        pr "%s " name;
9294    | RStructList (_, typ) ->
9295        let name = java_name_of_struct typ in
9296        pr "%s[] " name;
9297    | RHashtable _ -> pr "HashMap<String,String> ";
9298   );
9299
9300   if native then pr "_%s " name else pr "%s " name;
9301   pr "(";
9302   let needs_comma = ref false in
9303   if native then (
9304     pr "long g";
9305     needs_comma := true
9306   );
9307
9308   (* args *)
9309   List.iter (
9310     fun arg ->
9311       if !needs_comma then pr ", ";
9312       needs_comma := true;
9313
9314       match arg with
9315       | Pathname n
9316       | Device n | Dev_or_Path n
9317       | String n
9318       | OptString n
9319       | FileIn n
9320       | FileOut n ->
9321           pr "String %s" n
9322       | StringList n | DeviceList n ->
9323           pr "String[] %s" n
9324       | Bool n ->
9325           pr "boolean %s" n
9326       | Int n ->
9327           pr "int %s" n
9328       | Int64 n ->
9329           pr "long %s" n
9330   ) (snd style);
9331
9332   pr ")\n";
9333   pr "    throws LibGuestFSException";
9334   if semicolon then pr ";"
9335
9336 and generate_java_struct jtyp cols () =
9337   generate_header CStyle LGPLv2plus;
9338
9339   pr "\
9340 package com.redhat.et.libguestfs;
9341
9342 /**
9343  * Libguestfs %s structure.
9344  *
9345  * @author rjones
9346  * @see GuestFS
9347  */
9348 public class %s {
9349 " jtyp jtyp;
9350
9351   List.iter (
9352     function
9353     | name, FString
9354     | name, FUUID
9355     | name, FBuffer -> pr "  public String %s;\n" name
9356     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9357     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9358     | name, FChar -> pr "  public char %s;\n" name
9359     | name, FOptPercent ->
9360         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9361         pr "  public float %s;\n" name
9362   ) cols;
9363
9364   pr "}\n"
9365
9366 and generate_java_c () =
9367   generate_header CStyle LGPLv2plus;
9368
9369   pr "\
9370 #include <stdio.h>
9371 #include <stdlib.h>
9372 #include <string.h>
9373
9374 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9375 #include \"guestfs.h\"
9376
9377 /* Note that this function returns.  The exception is not thrown
9378  * until after the wrapper function returns.
9379  */
9380 static void
9381 throw_exception (JNIEnv *env, const char *msg)
9382 {
9383   jclass cl;
9384   cl = (*env)->FindClass (env,
9385                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9386   (*env)->ThrowNew (env, cl, msg);
9387 }
9388
9389 JNIEXPORT jlong JNICALL
9390 Java_com_redhat_et_libguestfs_GuestFS__1create
9391   (JNIEnv *env, jobject obj)
9392 {
9393   guestfs_h *g;
9394
9395   g = guestfs_create ();
9396   if (g == NULL) {
9397     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9398     return 0;
9399   }
9400   guestfs_set_error_handler (g, NULL, NULL);
9401   return (jlong) (long) g;
9402 }
9403
9404 JNIEXPORT void JNICALL
9405 Java_com_redhat_et_libguestfs_GuestFS__1close
9406   (JNIEnv *env, jobject obj, jlong jg)
9407 {
9408   guestfs_h *g = (guestfs_h *) (long) jg;
9409   guestfs_close (g);
9410 }
9411
9412 ";
9413
9414   List.iter (
9415     fun (name, style, _, _, _, _, _) ->
9416       pr "JNIEXPORT ";
9417       (match fst style with
9418        | RErr -> pr "void ";
9419        | RInt _ -> pr "jint ";
9420        | RInt64 _ -> pr "jlong ";
9421        | RBool _ -> pr "jboolean ";
9422        | RConstString _ | RConstOptString _ | RString _
9423        | RBufferOut _ -> pr "jstring ";
9424        | RStruct _ | RHashtable _ ->
9425            pr "jobject ";
9426        | RStringList _ | RStructList _ ->
9427            pr "jobjectArray ";
9428       );
9429       pr "JNICALL\n";
9430       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9431       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9432       pr "\n";
9433       pr "  (JNIEnv *env, jobject obj, jlong jg";
9434       List.iter (
9435         function
9436         | Pathname n
9437         | Device n | Dev_or_Path n
9438         | String n
9439         | OptString n
9440         | FileIn n
9441         | FileOut n ->
9442             pr ", jstring j%s" n
9443         | StringList n | DeviceList n ->
9444             pr ", jobjectArray j%s" n
9445         | Bool n ->
9446             pr ", jboolean j%s" n
9447         | Int n ->
9448             pr ", jint j%s" n
9449         | Int64 n ->
9450             pr ", jlong j%s" n
9451       ) (snd style);
9452       pr ")\n";
9453       pr "{\n";
9454       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
9455       let error_code, no_ret =
9456         match fst style with
9457         | RErr -> pr "  int r;\n"; "-1", ""
9458         | RBool _
9459         | RInt _ -> pr "  int r;\n"; "-1", "0"
9460         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
9461         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9462         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9463         | RString _ ->
9464             pr "  jstring jr;\n";
9465             pr "  char *r;\n"; "NULL", "NULL"
9466         | RStringList _ ->
9467             pr "  jobjectArray jr;\n";
9468             pr "  int r_len;\n";
9469             pr "  jclass cl;\n";
9470             pr "  jstring jstr;\n";
9471             pr "  char **r;\n"; "NULL", "NULL"
9472         | RStruct (_, typ) ->
9473             pr "  jobject jr;\n";
9474             pr "  jclass cl;\n";
9475             pr "  jfieldID fl;\n";
9476             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
9477         | RStructList (_, typ) ->
9478             pr "  jobjectArray jr;\n";
9479             pr "  jclass cl;\n";
9480             pr "  jfieldID fl;\n";
9481             pr "  jobject jfl;\n";
9482             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
9483         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
9484         | RBufferOut _ ->
9485             pr "  jstring jr;\n";
9486             pr "  char *r;\n";
9487             pr "  size_t size;\n";
9488             "NULL", "NULL" in
9489       List.iter (
9490         function
9491         | Pathname n
9492         | Device n | Dev_or_Path n
9493         | String n
9494         | OptString n
9495         | FileIn n
9496         | FileOut n ->
9497             pr "  const char *%s;\n" n
9498         | StringList n | DeviceList n ->
9499             pr "  int %s_len;\n" n;
9500             pr "  const char **%s;\n" n
9501         | Bool n
9502         | Int n ->
9503             pr "  int %s;\n" n
9504         | Int64 n ->
9505             pr "  int64_t %s;\n" n
9506       ) (snd style);
9507
9508       let needs_i =
9509         (match fst style with
9510          | RStringList _ | RStructList _ -> true
9511          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
9512          | RConstOptString _
9513          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
9514           List.exists (function
9515                        | StringList _ -> true
9516                        | DeviceList _ -> true
9517                        | _ -> false) (snd style) in
9518       if needs_i then
9519         pr "  int i;\n";
9520
9521       pr "\n";
9522
9523       (* Get the parameters. *)
9524       List.iter (
9525         function
9526         | Pathname n
9527         | Device n | Dev_or_Path n
9528         | String n
9529         | FileIn n
9530         | FileOut n ->
9531             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
9532         | OptString n ->
9533             (* This is completely undocumented, but Java null becomes
9534              * a NULL parameter.
9535              *)
9536             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
9537         | StringList n | DeviceList n ->
9538             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
9539             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
9540             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9541             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9542               n;
9543             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
9544             pr "  }\n";
9545             pr "  %s[%s_len] = NULL;\n" n n;
9546         | Bool n
9547         | Int n
9548         | Int64 n ->
9549             pr "  %s = j%s;\n" n n
9550       ) (snd style);
9551
9552       (* Make the call. *)
9553       pr "  r = guestfs_%s " name;
9554       generate_c_call_args ~handle:"g" style;
9555       pr ";\n";
9556
9557       (* Release the parameters. *)
9558       List.iter (
9559         function
9560         | Pathname n
9561         | Device n | Dev_or_Path n
9562         | String n
9563         | FileIn n
9564         | FileOut n ->
9565             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9566         | OptString n ->
9567             pr "  if (j%s)\n" n;
9568             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9569         | StringList n | DeviceList n ->
9570             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9571             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9572               n;
9573             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
9574             pr "  }\n";
9575             pr "  free (%s);\n" n
9576         | Bool n
9577         | Int n
9578         | Int64 n -> ()
9579       ) (snd style);
9580
9581       (* Check for errors. *)
9582       pr "  if (r == %s) {\n" error_code;
9583       pr "    throw_exception (env, guestfs_last_error (g));\n";
9584       pr "    return %s;\n" no_ret;
9585       pr "  }\n";
9586
9587       (* Return value. *)
9588       (match fst style with
9589        | RErr -> ()
9590        | RInt _ -> pr "  return (jint) r;\n"
9591        | RBool _ -> pr "  return (jboolean) r;\n"
9592        | RInt64 _ -> pr "  return (jlong) r;\n"
9593        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
9594        | RConstOptString _ ->
9595            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
9596        | RString _ ->
9597            pr "  jr = (*env)->NewStringUTF (env, r);\n";
9598            pr "  free (r);\n";
9599            pr "  return jr;\n"
9600        | RStringList _ ->
9601            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
9602            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
9603            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
9604            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
9605            pr "  for (i = 0; i < r_len; ++i) {\n";
9606            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
9607            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
9608            pr "    free (r[i]);\n";
9609            pr "  }\n";
9610            pr "  free (r);\n";
9611            pr "  return jr;\n"
9612        | RStruct (_, typ) ->
9613            let jtyp = java_name_of_struct typ in
9614            let cols = cols_of_struct typ in
9615            generate_java_struct_return typ jtyp cols
9616        | RStructList (_, typ) ->
9617            let jtyp = java_name_of_struct typ in
9618            let cols = cols_of_struct typ in
9619            generate_java_struct_list_return typ jtyp cols
9620        | RHashtable _ ->
9621            (* XXX *)
9622            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
9623            pr "  return NULL;\n"
9624        | RBufferOut _ ->
9625            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
9626            pr "  free (r);\n";
9627            pr "  return jr;\n"
9628       );
9629
9630       pr "}\n";
9631       pr "\n"
9632   ) all_functions
9633
9634 and generate_java_struct_return typ jtyp cols =
9635   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9636   pr "  jr = (*env)->AllocObject (env, cl);\n";
9637   List.iter (
9638     function
9639     | name, FString ->
9640         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9641         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
9642     | name, FUUID ->
9643         pr "  {\n";
9644         pr "    char s[33];\n";
9645         pr "    memcpy (s, r->%s, 32);\n" name;
9646         pr "    s[32] = 0;\n";
9647         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9648         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9649         pr "  }\n";
9650     | name, FBuffer ->
9651         pr "  {\n";
9652         pr "    int len = r->%s_len;\n" name;
9653         pr "    char s[len+1];\n";
9654         pr "    memcpy (s, r->%s, len);\n" name;
9655         pr "    s[len] = 0;\n";
9656         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9657         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9658         pr "  }\n";
9659     | name, (FBytes|FUInt64|FInt64) ->
9660         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9661         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9662     | name, (FUInt32|FInt32) ->
9663         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9664         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9665     | name, FOptPercent ->
9666         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9667         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
9668     | name, FChar ->
9669         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9670         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9671   ) cols;
9672   pr "  free (r);\n";
9673   pr "  return jr;\n"
9674
9675 and generate_java_struct_list_return typ jtyp cols =
9676   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9677   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
9678   pr "  for (i = 0; i < r->len; ++i) {\n";
9679   pr "    jfl = (*env)->AllocObject (env, cl);\n";
9680   List.iter (
9681     function
9682     | name, FString ->
9683         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9684         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
9685     | name, FUUID ->
9686         pr "    {\n";
9687         pr "      char s[33];\n";
9688         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
9689         pr "      s[32] = 0;\n";
9690         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9691         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9692         pr "    }\n";
9693     | name, FBuffer ->
9694         pr "    {\n";
9695         pr "      int len = r->val[i].%s_len;\n" name;
9696         pr "      char s[len+1];\n";
9697         pr "      memcpy (s, r->val[i].%s, len);\n" name;
9698         pr "      s[len] = 0;\n";
9699         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9700         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9701         pr "    }\n";
9702     | name, (FBytes|FUInt64|FInt64) ->
9703         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9704         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9705     | name, (FUInt32|FInt32) ->
9706         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9707         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9708     | name, FOptPercent ->
9709         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9710         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
9711     | name, FChar ->
9712         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9713         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9714   ) cols;
9715   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
9716   pr "  }\n";
9717   pr "  guestfs_free_%s_list (r);\n" typ;
9718   pr "  return jr;\n"
9719
9720 and generate_java_makefile_inc () =
9721   generate_header HashStyle GPLv2plus;
9722
9723   pr "java_built_sources = \\\n";
9724   List.iter (
9725     fun (typ, jtyp) ->
9726         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
9727   ) java_structs;
9728   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
9729
9730 and generate_haskell_hs () =
9731   generate_header HaskellStyle LGPLv2plus;
9732
9733   (* XXX We only know how to generate partial FFI for Haskell
9734    * at the moment.  Please help out!
9735    *)
9736   let can_generate style =
9737     match style with
9738     | RErr, _
9739     | RInt _, _
9740     | RInt64 _, _ -> true
9741     | RBool _, _
9742     | RConstString _, _
9743     | RConstOptString _, _
9744     | RString _, _
9745     | RStringList _, _
9746     | RStruct _, _
9747     | RStructList _, _
9748     | RHashtable _, _
9749     | RBufferOut _, _ -> false in
9750
9751   pr "\
9752 {-# INCLUDE <guestfs.h> #-}
9753 {-# LANGUAGE ForeignFunctionInterface #-}
9754
9755 module Guestfs (
9756   create";
9757
9758   (* List out the names of the actions we want to export. *)
9759   List.iter (
9760     fun (name, style, _, _, _, _, _) ->
9761       if can_generate style then pr ",\n  %s" name
9762   ) all_functions;
9763
9764   pr "
9765   ) where
9766
9767 -- Unfortunately some symbols duplicate ones already present
9768 -- in Prelude.  We don't know which, so we hard-code a list
9769 -- here.
9770 import Prelude hiding (truncate)
9771
9772 import Foreign
9773 import Foreign.C
9774 import Foreign.C.Types
9775 import IO
9776 import Control.Exception
9777 import Data.Typeable
9778
9779 data GuestfsS = GuestfsS            -- represents the opaque C struct
9780 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
9781 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
9782
9783 -- XXX define properly later XXX
9784 data PV = PV
9785 data VG = VG
9786 data LV = LV
9787 data IntBool = IntBool
9788 data Stat = Stat
9789 data StatVFS = StatVFS
9790 data Hashtable = Hashtable
9791
9792 foreign import ccall unsafe \"guestfs_create\" c_create
9793   :: IO GuestfsP
9794 foreign import ccall unsafe \"&guestfs_close\" c_close
9795   :: FunPtr (GuestfsP -> IO ())
9796 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
9797   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
9798
9799 create :: IO GuestfsH
9800 create = do
9801   p <- c_create
9802   c_set_error_handler p nullPtr nullPtr
9803   h <- newForeignPtr c_close p
9804   return h
9805
9806 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
9807   :: GuestfsP -> IO CString
9808
9809 -- last_error :: GuestfsH -> IO (Maybe String)
9810 -- last_error h = do
9811 --   str <- withForeignPtr h (\\p -> c_last_error p)
9812 --   maybePeek peekCString str
9813
9814 last_error :: GuestfsH -> IO (String)
9815 last_error h = do
9816   str <- withForeignPtr h (\\p -> c_last_error p)
9817   if (str == nullPtr)
9818     then return \"no error\"
9819     else peekCString str
9820
9821 ";
9822
9823   (* Generate wrappers for each foreign function. *)
9824   List.iter (
9825     fun (name, style, _, _, _, _, _) ->
9826       if can_generate style then (
9827         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
9828         pr "  :: ";
9829         generate_haskell_prototype ~handle:"GuestfsP" style;
9830         pr "\n";
9831         pr "\n";
9832         pr "%s :: " name;
9833         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
9834         pr "\n";
9835         pr "%s %s = do\n" name
9836           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
9837         pr "  r <- ";
9838         (* Convert pointer arguments using with* functions. *)
9839         List.iter (
9840           function
9841           | FileIn n
9842           | FileOut n
9843           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
9844           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
9845           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
9846           | Bool _ | Int _ | Int64 _ -> ()
9847         ) (snd style);
9848         (* Convert integer arguments. *)
9849         let args =
9850           List.map (
9851             function
9852             | Bool n -> sprintf "(fromBool %s)" n
9853             | Int n -> sprintf "(fromIntegral %s)" n
9854             | Int64 n -> sprintf "(fromIntegral %s)" n
9855             | FileIn n | FileOut n
9856             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
9857           ) (snd style) in
9858         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
9859           (String.concat " " ("p" :: args));
9860         (match fst style with
9861          | RErr | RInt _ | RInt64 _ | RBool _ ->
9862              pr "  if (r == -1)\n";
9863              pr "    then do\n";
9864              pr "      err <- last_error h\n";
9865              pr "      fail err\n";
9866          | RConstString _ | RConstOptString _ | RString _
9867          | RStringList _ | RStruct _
9868          | RStructList _ | RHashtable _ | RBufferOut _ ->
9869              pr "  if (r == nullPtr)\n";
9870              pr "    then do\n";
9871              pr "      err <- last_error h\n";
9872              pr "      fail err\n";
9873         );
9874         (match fst style with
9875          | RErr ->
9876              pr "    else return ()\n"
9877          | RInt _ ->
9878              pr "    else return (fromIntegral r)\n"
9879          | RInt64 _ ->
9880              pr "    else return (fromIntegral r)\n"
9881          | RBool _ ->
9882              pr "    else return (toBool r)\n"
9883          | RConstString _
9884          | RConstOptString _
9885          | RString _
9886          | RStringList _
9887          | RStruct _
9888          | RStructList _
9889          | RHashtable _
9890          | RBufferOut _ ->
9891              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
9892         );
9893         pr "\n";
9894       )
9895   ) all_functions
9896
9897 and generate_haskell_prototype ~handle ?(hs = false) style =
9898   pr "%s -> " handle;
9899   let string = if hs then "String" else "CString" in
9900   let int = if hs then "Int" else "CInt" in
9901   let bool = if hs then "Bool" else "CInt" in
9902   let int64 = if hs then "Integer" else "Int64" in
9903   List.iter (
9904     fun arg ->
9905       (match arg with
9906        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
9907        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
9908        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
9909        | Bool _ -> pr "%s" bool
9910        | Int _ -> pr "%s" int
9911        | Int64 _ -> pr "%s" int
9912        | FileIn _ -> pr "%s" string
9913        | FileOut _ -> pr "%s" string
9914       );
9915       pr " -> ";
9916   ) (snd style);
9917   pr "IO (";
9918   (match fst style with
9919    | RErr -> if not hs then pr "CInt"
9920    | RInt _ -> pr "%s" int
9921    | RInt64 _ -> pr "%s" int64
9922    | RBool _ -> pr "%s" bool
9923    | RConstString _ -> pr "%s" string
9924    | RConstOptString _ -> pr "Maybe %s" string
9925    | RString _ -> pr "%s" string
9926    | RStringList _ -> pr "[%s]" string
9927    | RStruct (_, typ) ->
9928        let name = java_name_of_struct typ in
9929        pr "%s" name
9930    | RStructList (_, typ) ->
9931        let name = java_name_of_struct typ in
9932        pr "[%s]" name
9933    | RHashtable _ -> pr "Hashtable"
9934    | RBufferOut _ -> pr "%s" string
9935   );
9936   pr ")"
9937
9938 and generate_csharp () =
9939   generate_header CPlusPlusStyle LGPLv2plus;
9940
9941   (* XXX Make this configurable by the C# assembly users. *)
9942   let library = "libguestfs.so.0" in
9943
9944   pr "\
9945 // These C# bindings are highly experimental at present.
9946 //
9947 // Firstly they only work on Linux (ie. Mono).  In order to get them
9948 // to work on Windows (ie. .Net) you would need to port the library
9949 // itself to Windows first.
9950 //
9951 // The second issue is that some calls are known to be incorrect and
9952 // can cause Mono to segfault.  Particularly: calls which pass or
9953 // return string[], or return any structure value.  This is because
9954 // we haven't worked out the correct way to do this from C#.
9955 //
9956 // The third issue is that when compiling you get a lot of warnings.
9957 // We are not sure whether the warnings are important or not.
9958 //
9959 // Fourthly we do not routinely build or test these bindings as part
9960 // of the make && make check cycle, which means that regressions might
9961 // go unnoticed.
9962 //
9963 // Suggestions and patches are welcome.
9964
9965 // To compile:
9966 //
9967 // gmcs Libguestfs.cs
9968 // mono Libguestfs.exe
9969 //
9970 // (You'll probably want to add a Test class / static main function
9971 // otherwise this won't do anything useful).
9972
9973 using System;
9974 using System.IO;
9975 using System.Runtime.InteropServices;
9976 using System.Runtime.Serialization;
9977 using System.Collections;
9978
9979 namespace Guestfs
9980 {
9981   class Error : System.ApplicationException
9982   {
9983     public Error (string message) : base (message) {}
9984     protected Error (SerializationInfo info, StreamingContext context) {}
9985   }
9986
9987   class Guestfs
9988   {
9989     IntPtr _handle;
9990
9991     [DllImport (\"%s\")]
9992     static extern IntPtr guestfs_create ();
9993
9994     public Guestfs ()
9995     {
9996       _handle = guestfs_create ();
9997       if (_handle == IntPtr.Zero)
9998         throw new Error (\"could not create guestfs handle\");
9999     }
10000
10001     [DllImport (\"%s\")]
10002     static extern void guestfs_close (IntPtr h);
10003
10004     ~Guestfs ()
10005     {
10006       guestfs_close (_handle);
10007     }
10008
10009     [DllImport (\"%s\")]
10010     static extern string guestfs_last_error (IntPtr h);
10011
10012 " library library library;
10013
10014   (* Generate C# structure bindings.  We prefix struct names with
10015    * underscore because C# cannot have conflicting struct names and
10016    * method names (eg. "class stat" and "stat").
10017    *)
10018   List.iter (
10019     fun (typ, cols) ->
10020       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10021       pr "    public class _%s {\n" typ;
10022       List.iter (
10023         function
10024         | name, FChar -> pr "      char %s;\n" name
10025         | name, FString -> pr "      string %s;\n" name
10026         | name, FBuffer ->
10027             pr "      uint %s_len;\n" name;
10028             pr "      string %s;\n" name
10029         | name, FUUID ->
10030             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10031             pr "      string %s;\n" name
10032         | name, FUInt32 -> pr "      uint %s;\n" name
10033         | name, FInt32 -> pr "      int %s;\n" name
10034         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10035         | name, FInt64 -> pr "      long %s;\n" name
10036         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10037       ) cols;
10038       pr "    }\n";
10039       pr "\n"
10040   ) structs;
10041
10042   (* Generate C# function bindings. *)
10043   List.iter (
10044     fun (name, style, _, _, _, shortdesc, _) ->
10045       let rec csharp_return_type () =
10046         match fst style with
10047         | RErr -> "void"
10048         | RBool n -> "bool"
10049         | RInt n -> "int"
10050         | RInt64 n -> "long"
10051         | RConstString n
10052         | RConstOptString n
10053         | RString n
10054         | RBufferOut n -> "string"
10055         | RStruct (_,n) -> "_" ^ n
10056         | RHashtable n -> "Hashtable"
10057         | RStringList n -> "string[]"
10058         | RStructList (_,n) -> sprintf "_%s[]" n
10059
10060       and c_return_type () =
10061         match fst style with
10062         | RErr
10063         | RBool _
10064         | RInt _ -> "int"
10065         | RInt64 _ -> "long"
10066         | RConstString _
10067         | RConstOptString _
10068         | RString _
10069         | RBufferOut _ -> "string"
10070         | RStruct (_,n) -> "_" ^ n
10071         | RHashtable _
10072         | RStringList _ -> "string[]"
10073         | RStructList (_,n) -> sprintf "_%s[]" n
10074     
10075       and c_error_comparison () =
10076         match fst style with
10077         | RErr
10078         | RBool _
10079         | RInt _
10080         | RInt64 _ -> "== -1"
10081         | RConstString _
10082         | RConstOptString _
10083         | RString _
10084         | RBufferOut _
10085         | RStruct (_,_)
10086         | RHashtable _
10087         | RStringList _
10088         | RStructList (_,_) -> "== null"
10089     
10090       and generate_extern_prototype () =
10091         pr "    static extern %s guestfs_%s (IntPtr h"
10092           (c_return_type ()) name;
10093         List.iter (
10094           function
10095           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10096           | FileIn n | FileOut n ->
10097               pr ", [In] string %s" n
10098           | StringList n | DeviceList n ->
10099               pr ", [In] string[] %s" n
10100           | Bool n ->
10101               pr ", bool %s" n
10102           | Int n ->
10103               pr ", int %s" n
10104           | Int64 n ->
10105               pr ", long %s" n
10106         ) (snd style);
10107         pr ");\n"
10108
10109       and generate_public_prototype () =
10110         pr "    public %s %s (" (csharp_return_type ()) name;
10111         let comma = ref false in
10112         let next () =
10113           if !comma then pr ", ";
10114           comma := true
10115         in
10116         List.iter (
10117           function
10118           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10119           | FileIn n | FileOut n ->
10120               next (); pr "string %s" n
10121           | StringList n | DeviceList n ->
10122               next (); pr "string[] %s" n
10123           | Bool n ->
10124               next (); pr "bool %s" n
10125           | Int n ->
10126               next (); pr "int %s" n
10127           | Int64 n ->
10128               next (); pr "long %s" n
10129         ) (snd style);
10130         pr ")\n"
10131
10132       and generate_call () =
10133         pr "guestfs_%s (_handle" name;
10134         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10135         pr ");\n";
10136       in
10137
10138       pr "    [DllImport (\"%s\")]\n" library;
10139       generate_extern_prototype ();
10140       pr "\n";
10141       pr "    /// <summary>\n";
10142       pr "    /// %s\n" shortdesc;
10143       pr "    /// </summary>\n";
10144       generate_public_prototype ();
10145       pr "    {\n";
10146       pr "      %s r;\n" (c_return_type ());
10147       pr "      r = ";
10148       generate_call ();
10149       pr "      if (r %s)\n" (c_error_comparison ());
10150       pr "        throw new Error (\"%s: \" + guestfs_last_error (_handle));\n"
10151         name;
10152       (match fst style with
10153        | RErr -> ()
10154        | RBool _ ->
10155            pr "      return r != 0 ? true : false;\n"
10156        | RHashtable _ ->
10157            pr "      Hashtable rr = new Hashtable ();\n";
10158            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10159            pr "        rr.Add (r[i], r[i+1]);\n";
10160            pr "      return rr;\n"
10161        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10162        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10163        | RStructList _ ->
10164            pr "      return r;\n"
10165       );
10166       pr "    }\n";
10167       pr "\n";
10168   ) all_functions_sorted;
10169
10170   pr "  }
10171 }
10172 "
10173
10174 and generate_bindtests () =
10175   generate_header CStyle LGPLv2plus;
10176
10177   pr "\
10178 #include <stdio.h>
10179 #include <stdlib.h>
10180 #include <inttypes.h>
10181 #include <string.h>
10182
10183 #include \"guestfs.h\"
10184 #include \"guestfs-internal.h\"
10185 #include \"guestfs-internal-actions.h\"
10186 #include \"guestfs_protocol.h\"
10187
10188 #define error guestfs_error
10189 #define safe_calloc guestfs_safe_calloc
10190 #define safe_malloc guestfs_safe_malloc
10191
10192 static void
10193 print_strings (char *const *argv)
10194 {
10195   int argc;
10196
10197   printf (\"[\");
10198   for (argc = 0; argv[argc] != NULL; ++argc) {
10199     if (argc > 0) printf (\", \");
10200     printf (\"\\\"%%s\\\"\", argv[argc]);
10201   }
10202   printf (\"]\\n\");
10203 }
10204
10205 /* The test0 function prints its parameters to stdout. */
10206 ";
10207
10208   let test0, tests =
10209     match test_functions with
10210     | [] -> assert false
10211     | test0 :: tests -> test0, tests in
10212
10213   let () =
10214     let (name, style, _, _, _, _, _) = test0 in
10215     generate_prototype ~extern:false ~semicolon:false ~newline:true
10216       ~handle:"g" ~prefix:"guestfs__" name style;
10217     pr "{\n";
10218     List.iter (
10219       function
10220       | Pathname n
10221       | Device n | Dev_or_Path n
10222       | String n
10223       | FileIn n
10224       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10225       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10226       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10227       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10228       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10229       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10230     ) (snd style);
10231     pr "  /* Java changes stdout line buffering so we need this: */\n";
10232     pr "  fflush (stdout);\n";
10233     pr "  return 0;\n";
10234     pr "}\n";
10235     pr "\n" in
10236
10237   List.iter (
10238     fun (name, style, _, _, _, _, _) ->
10239       if String.sub name (String.length name - 3) 3 <> "err" then (
10240         pr "/* Test normal return. */\n";
10241         generate_prototype ~extern:false ~semicolon:false ~newline:true
10242           ~handle:"g" ~prefix:"guestfs__" name style;
10243         pr "{\n";
10244         (match fst style with
10245          | RErr ->
10246              pr "  return 0;\n"
10247          | RInt _ ->
10248              pr "  int r;\n";
10249              pr "  sscanf (val, \"%%d\", &r);\n";
10250              pr "  return r;\n"
10251          | RInt64 _ ->
10252              pr "  int64_t r;\n";
10253              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10254              pr "  return r;\n"
10255          | RBool _ ->
10256              pr "  return STREQ (val, \"true\");\n"
10257          | RConstString _
10258          | RConstOptString _ ->
10259              (* Can't return the input string here.  Return a static
10260               * string so we ensure we get a segfault if the caller
10261               * tries to free it.
10262               *)
10263              pr "  return \"static string\";\n"
10264          | RString _ ->
10265              pr "  return strdup (val);\n"
10266          | RStringList _ ->
10267              pr "  char **strs;\n";
10268              pr "  int n, i;\n";
10269              pr "  sscanf (val, \"%%d\", &n);\n";
10270              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10271              pr "  for (i = 0; i < n; ++i) {\n";
10272              pr "    strs[i] = safe_malloc (g, 16);\n";
10273              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10274              pr "  }\n";
10275              pr "  strs[n] = NULL;\n";
10276              pr "  return strs;\n"
10277          | RStruct (_, typ) ->
10278              pr "  struct guestfs_%s *r;\n" typ;
10279              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10280              pr "  return r;\n"
10281          | RStructList (_, typ) ->
10282              pr "  struct guestfs_%s_list *r;\n" typ;
10283              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10284              pr "  sscanf (val, \"%%d\", &r->len);\n";
10285              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10286              pr "  return r;\n"
10287          | RHashtable _ ->
10288              pr "  char **strs;\n";
10289              pr "  int n, i;\n";
10290              pr "  sscanf (val, \"%%d\", &n);\n";
10291              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10292              pr "  for (i = 0; i < n; ++i) {\n";
10293              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10294              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10295              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10296              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10297              pr "  }\n";
10298              pr "  strs[n*2] = NULL;\n";
10299              pr "  return strs;\n"
10300          | RBufferOut _ ->
10301              pr "  return strdup (val);\n"
10302         );
10303         pr "}\n";
10304         pr "\n"
10305       ) else (
10306         pr "/* Test error return. */\n";
10307         generate_prototype ~extern:false ~semicolon:false ~newline:true
10308           ~handle:"g" ~prefix:"guestfs__" name style;
10309         pr "{\n";
10310         pr "  error (g, \"error\");\n";
10311         (match fst style with
10312          | RErr | RInt _ | RInt64 _ | RBool _ ->
10313              pr "  return -1;\n"
10314          | RConstString _ | RConstOptString _
10315          | RString _ | RStringList _ | RStruct _
10316          | RStructList _
10317          | RHashtable _
10318          | RBufferOut _ ->
10319              pr "  return NULL;\n"
10320         );
10321         pr "}\n";
10322         pr "\n"
10323       )
10324   ) tests
10325
10326 and generate_ocaml_bindtests () =
10327   generate_header OCamlStyle GPLv2plus;
10328
10329   pr "\
10330 let () =
10331   let g = Guestfs.create () in
10332 ";
10333
10334   let mkargs args =
10335     String.concat " " (
10336       List.map (
10337         function
10338         | CallString s -> "\"" ^ s ^ "\""
10339         | CallOptString None -> "None"
10340         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10341         | CallStringList xs ->
10342             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10343         | CallInt i when i >= 0 -> string_of_int i
10344         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10345         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10346         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10347         | CallBool b -> string_of_bool b
10348       ) args
10349     )
10350   in
10351
10352   generate_lang_bindtests (
10353     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10354   );
10355
10356   pr "print_endline \"EOF\"\n"
10357
10358 and generate_perl_bindtests () =
10359   pr "#!/usr/bin/perl -w\n";
10360   generate_header HashStyle GPLv2plus;
10361
10362   pr "\
10363 use strict;
10364
10365 use Sys::Guestfs;
10366
10367 my $g = Sys::Guestfs->new ();
10368 ";
10369
10370   let mkargs args =
10371     String.concat ", " (
10372       List.map (
10373         function
10374         | CallString s -> "\"" ^ s ^ "\""
10375         | CallOptString None -> "undef"
10376         | CallOptString (Some s) -> sprintf "\"%s\"" s
10377         | CallStringList xs ->
10378             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10379         | CallInt i -> string_of_int i
10380         | CallInt64 i -> Int64.to_string i
10381         | CallBool b -> if b then "1" else "0"
10382       ) args
10383     )
10384   in
10385
10386   generate_lang_bindtests (
10387     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10388   );
10389
10390   pr "print \"EOF\\n\"\n"
10391
10392 and generate_python_bindtests () =
10393   generate_header HashStyle GPLv2plus;
10394
10395   pr "\
10396 import guestfs
10397
10398 g = guestfs.GuestFS ()
10399 ";
10400
10401   let mkargs args =
10402     String.concat ", " (
10403       List.map (
10404         function
10405         | CallString s -> "\"" ^ s ^ "\""
10406         | CallOptString None -> "None"
10407         | CallOptString (Some s) -> sprintf "\"%s\"" s
10408         | CallStringList xs ->
10409             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10410         | CallInt i -> string_of_int i
10411         | CallInt64 i -> Int64.to_string i
10412         | CallBool b -> if b then "1" else "0"
10413       ) args
10414     )
10415   in
10416
10417   generate_lang_bindtests (
10418     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10419   );
10420
10421   pr "print \"EOF\"\n"
10422
10423 and generate_ruby_bindtests () =
10424   generate_header HashStyle GPLv2plus;
10425
10426   pr "\
10427 require 'guestfs'
10428
10429 g = Guestfs::create()
10430 ";
10431
10432   let mkargs args =
10433     String.concat ", " (
10434       List.map (
10435         function
10436         | CallString s -> "\"" ^ s ^ "\""
10437         | CallOptString None -> "nil"
10438         | CallOptString (Some s) -> sprintf "\"%s\"" s
10439         | CallStringList xs ->
10440             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10441         | CallInt i -> string_of_int i
10442         | CallInt64 i -> Int64.to_string i
10443         | CallBool b -> string_of_bool b
10444       ) args
10445     )
10446   in
10447
10448   generate_lang_bindtests (
10449     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10450   );
10451
10452   pr "print \"EOF\\n\"\n"
10453
10454 and generate_java_bindtests () =
10455   generate_header CStyle GPLv2plus;
10456
10457   pr "\
10458 import com.redhat.et.libguestfs.*;
10459
10460 public class Bindtests {
10461     public static void main (String[] argv)
10462     {
10463         try {
10464             GuestFS g = new GuestFS ();
10465 ";
10466
10467   let mkargs args =
10468     String.concat ", " (
10469       List.map (
10470         function
10471         | CallString s -> "\"" ^ s ^ "\""
10472         | CallOptString None -> "null"
10473         | CallOptString (Some s) -> sprintf "\"%s\"" s
10474         | CallStringList xs ->
10475             "new String[]{" ^
10476               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
10477         | CallInt i -> string_of_int i
10478         | CallInt64 i -> Int64.to_string i
10479         | CallBool b -> string_of_bool b
10480       ) args
10481     )
10482   in
10483
10484   generate_lang_bindtests (
10485     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
10486   );
10487
10488   pr "
10489             System.out.println (\"EOF\");
10490         }
10491         catch (Exception exn) {
10492             System.err.println (exn);
10493             System.exit (1);
10494         }
10495     }
10496 }
10497 "
10498
10499 and generate_haskell_bindtests () =
10500   generate_header HaskellStyle GPLv2plus;
10501
10502   pr "\
10503 module Bindtests where
10504 import qualified Guestfs
10505
10506 main = do
10507   g <- Guestfs.create
10508 ";
10509
10510   let mkargs args =
10511     String.concat " " (
10512       List.map (
10513         function
10514         | CallString s -> "\"" ^ s ^ "\""
10515         | CallOptString None -> "Nothing"
10516         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
10517         | CallStringList xs ->
10518             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10519         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
10520         | CallInt i -> string_of_int i
10521         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
10522         | CallInt64 i -> Int64.to_string i
10523         | CallBool true -> "True"
10524         | CallBool false -> "False"
10525       ) args
10526     )
10527   in
10528
10529   generate_lang_bindtests (
10530     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
10531   );
10532
10533   pr "  putStrLn \"EOF\"\n"
10534
10535 (* Language-independent bindings tests - we do it this way to
10536  * ensure there is parity in testing bindings across all languages.
10537  *)
10538 and generate_lang_bindtests call =
10539   call "test0" [CallString "abc"; CallOptString (Some "def");
10540                 CallStringList []; CallBool false;
10541                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10542   call "test0" [CallString "abc"; CallOptString None;
10543                 CallStringList []; CallBool false;
10544                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10545   call "test0" [CallString ""; CallOptString (Some "def");
10546                 CallStringList []; CallBool false;
10547                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10548   call "test0" [CallString ""; CallOptString (Some "");
10549                 CallStringList []; CallBool false;
10550                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10551   call "test0" [CallString "abc"; CallOptString (Some "def");
10552                 CallStringList ["1"]; CallBool false;
10553                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10554   call "test0" [CallString "abc"; CallOptString (Some "def");
10555                 CallStringList ["1"; "2"]; CallBool false;
10556                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10557   call "test0" [CallString "abc"; CallOptString (Some "def");
10558                 CallStringList ["1"]; CallBool true;
10559                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10560   call "test0" [CallString "abc"; CallOptString (Some "def");
10561                 CallStringList ["1"]; CallBool false;
10562                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
10563   call "test0" [CallString "abc"; CallOptString (Some "def");
10564                 CallStringList ["1"]; CallBool false;
10565                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
10566   call "test0" [CallString "abc"; CallOptString (Some "def");
10567                 CallStringList ["1"]; CallBool false;
10568                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
10569   call "test0" [CallString "abc"; CallOptString (Some "def");
10570                 CallStringList ["1"]; CallBool false;
10571                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
10572   call "test0" [CallString "abc"; CallOptString (Some "def");
10573                 CallStringList ["1"]; CallBool false;
10574                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
10575   call "test0" [CallString "abc"; CallOptString (Some "def");
10576                 CallStringList ["1"]; CallBool false;
10577                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
10578
10579 (* XXX Add here tests of the return and error functions. *)
10580
10581 (* Code to generator bindings for virt-inspector.  Currently only
10582  * implemented for OCaml code (for virt-p2v 2.0).
10583  *)
10584 let rng_input = "inspector/virt-inspector.rng"
10585
10586 (* Read the input file and parse it into internal structures.  This is
10587  * by no means a complete RELAX NG parser, but is just enough to be
10588  * able to parse the specific input file.
10589  *)
10590 type rng =
10591   | Element of string * rng list        (* <element name=name/> *)
10592   | Attribute of string * rng list        (* <attribute name=name/> *)
10593   | Interleave of rng list                (* <interleave/> *)
10594   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
10595   | OneOrMore of rng                        (* <oneOrMore/> *)
10596   | Optional of rng                        (* <optional/> *)
10597   | Choice of string list                (* <choice><value/>*</choice> *)
10598   | Value of string                        (* <value>str</value> *)
10599   | Text                                (* <text/> *)
10600
10601 let rec string_of_rng = function
10602   | Element (name, xs) ->
10603       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10604   | Attribute (name, xs) ->
10605       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10606   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
10607   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
10608   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
10609   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
10610   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
10611   | Value value -> "Value \"" ^ value ^ "\""
10612   | Text -> "Text"
10613
10614 and string_of_rng_list xs =
10615   String.concat ", " (List.map string_of_rng xs)
10616
10617 let rec parse_rng ?defines context = function
10618   | [] -> []
10619   | Xml.Element ("element", ["name", name], children) :: rest ->
10620       Element (name, parse_rng ?defines context children)
10621       :: parse_rng ?defines context rest
10622   | Xml.Element ("attribute", ["name", name], children) :: rest ->
10623       Attribute (name, parse_rng ?defines context children)
10624       :: parse_rng ?defines context rest
10625   | Xml.Element ("interleave", [], children) :: rest ->
10626       Interleave (parse_rng ?defines context children)
10627       :: parse_rng ?defines context rest
10628   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
10629       let rng = parse_rng ?defines context [child] in
10630       (match rng with
10631        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
10632        | _ ->
10633            failwithf "%s: <zeroOrMore> contains more than one child element"
10634              context
10635       )
10636   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
10637       let rng = parse_rng ?defines context [child] in
10638       (match rng with
10639        | [child] -> OneOrMore child :: parse_rng ?defines context rest
10640        | _ ->
10641            failwithf "%s: <oneOrMore> contains more than one child element"
10642              context
10643       )
10644   | Xml.Element ("optional", [], [child]) :: rest ->
10645       let rng = parse_rng ?defines context [child] in
10646       (match rng with
10647        | [child] -> Optional child :: parse_rng ?defines context rest
10648        | _ ->
10649            failwithf "%s: <optional> contains more than one child element"
10650              context
10651       )
10652   | Xml.Element ("choice", [], children) :: rest ->
10653       let values = List.map (
10654         function Xml.Element ("value", [], [Xml.PCData value]) -> value
10655         | _ ->
10656             failwithf "%s: can't handle anything except <value> in <choice>"
10657               context
10658       ) children in
10659       Choice values
10660       :: parse_rng ?defines context rest
10661   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
10662       Value value :: parse_rng ?defines context rest
10663   | Xml.Element ("text", [], []) :: rest ->
10664       Text :: parse_rng ?defines context rest
10665   | Xml.Element ("ref", ["name", name], []) :: rest ->
10666       (* Look up the reference.  Because of limitations in this parser,
10667        * we can't handle arbitrarily nested <ref> yet.  You can only
10668        * use <ref> from inside <start>.
10669        *)
10670       (match defines with
10671        | None ->
10672            failwithf "%s: contains <ref>, but no refs are defined yet" context
10673        | Some map ->
10674            let rng = StringMap.find name map in
10675            rng @ parse_rng ?defines context rest
10676       )
10677   | x :: _ ->
10678       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
10679
10680 let grammar =
10681   let xml = Xml.parse_file rng_input in
10682   match xml with
10683   | Xml.Element ("grammar", _,
10684                  Xml.Element ("start", _, gram) :: defines) ->
10685       (* The <define/> elements are referenced in the <start> section,
10686        * so build a map of those first.
10687        *)
10688       let defines = List.fold_left (
10689         fun map ->
10690           function Xml.Element ("define", ["name", name], defn) ->
10691             StringMap.add name defn map
10692           | _ ->
10693               failwithf "%s: expected <define name=name/>" rng_input
10694       ) StringMap.empty defines in
10695       let defines = StringMap.mapi parse_rng defines in
10696
10697       (* Parse the <start> clause, passing the defines. *)
10698       parse_rng ~defines "<start>" gram
10699   | _ ->
10700       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
10701         rng_input
10702
10703 let name_of_field = function
10704   | Element (name, _) | Attribute (name, _)
10705   | ZeroOrMore (Element (name, _))
10706   | OneOrMore (Element (name, _))
10707   | Optional (Element (name, _)) -> name
10708   | Optional (Attribute (name, _)) -> name
10709   | Text -> (* an unnamed field in an element *)
10710       "data"
10711   | rng ->
10712       failwithf "name_of_field failed at: %s" (string_of_rng rng)
10713
10714 (* At the moment this function only generates OCaml types.  However we
10715  * should parameterize it later so it can generate types/structs in a
10716  * variety of languages.
10717  *)
10718 let generate_types xs =
10719   (* A simple type is one that can be printed out directly, eg.
10720    * "string option".  A complex type is one which has a name and has
10721    * to be defined via another toplevel definition, eg. a struct.
10722    *
10723    * generate_type generates code for either simple or complex types.
10724    * In the simple case, it returns the string ("string option").  In
10725    * the complex case, it returns the name ("mountpoint").  In the
10726    * complex case it has to print out the definition before returning,
10727    * so it should only be called when we are at the beginning of a
10728    * new line (BOL context).
10729    *)
10730   let rec generate_type = function
10731     | Text ->                                (* string *)
10732         "string", true
10733     | Choice values ->                        (* [`val1|`val2|...] *)
10734         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
10735     | ZeroOrMore rng ->                        (* <rng> list *)
10736         let t, is_simple = generate_type rng in
10737         t ^ " list (* 0 or more *)", is_simple
10738     | OneOrMore rng ->                        (* <rng> list *)
10739         let t, is_simple = generate_type rng in
10740         t ^ " list (* 1 or more *)", is_simple
10741                                         (* virt-inspector hack: bool *)
10742     | Optional (Attribute (name, [Value "1"])) ->
10743         "bool", true
10744     | Optional rng ->                        (* <rng> list *)
10745         let t, is_simple = generate_type rng in
10746         t ^ " option", is_simple
10747                                         (* type name = { fields ... } *)
10748     | Element (name, fields) when is_attrs_interleave fields ->
10749         generate_type_struct name (get_attrs_interleave fields)
10750     | Element (name, [field])                (* type name = field *)
10751     | Attribute (name, [field]) ->
10752         let t, is_simple = generate_type field in
10753         if is_simple then (t, true)
10754         else (
10755           pr "type %s = %s\n" name t;
10756           name, false
10757         )
10758     | Element (name, fields) ->              (* type name = { fields ... } *)
10759         generate_type_struct name fields
10760     | rng ->
10761         failwithf "generate_type failed at: %s" (string_of_rng rng)
10762
10763   and is_attrs_interleave = function
10764     | [Interleave _] -> true
10765     | Attribute _ :: fields -> is_attrs_interleave fields
10766     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
10767     | _ -> false
10768
10769   and get_attrs_interleave = function
10770     | [Interleave fields] -> fields
10771     | ((Attribute _) as field) :: fields
10772     | ((Optional (Attribute _)) as field) :: fields ->
10773         field :: get_attrs_interleave fields
10774     | _ -> assert false
10775
10776   and generate_types xs =
10777     List.iter (fun x -> ignore (generate_type x)) xs
10778
10779   and generate_type_struct name fields =
10780     (* Calculate the types of the fields first.  We have to do this
10781      * before printing anything so we are still in BOL context.
10782      *)
10783     let types = List.map fst (List.map generate_type fields) in
10784
10785     (* Special case of a struct containing just a string and another
10786      * field.  Turn it into an assoc list.
10787      *)
10788     match types with
10789     | ["string"; other] ->
10790         let fname1, fname2 =
10791           match fields with
10792           | [f1; f2] -> name_of_field f1, name_of_field f2
10793           | _ -> assert false in
10794         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
10795         name, false
10796
10797     | types ->
10798         pr "type %s = {\n" name;
10799         List.iter (
10800           fun (field, ftype) ->
10801             let fname = name_of_field field in
10802             pr "  %s_%s : %s;\n" name fname ftype
10803         ) (List.combine fields types);
10804         pr "}\n";
10805         (* Return the name of this type, and
10806          * false because it's not a simple type.
10807          *)
10808         name, false
10809   in
10810
10811   generate_types xs
10812
10813 let generate_parsers xs =
10814   (* As for generate_type above, generate_parser makes a parser for
10815    * some type, and returns the name of the parser it has generated.
10816    * Because it (may) need to print something, it should always be
10817    * called in BOL context.
10818    *)
10819   let rec generate_parser = function
10820     | Text ->                                (* string *)
10821         "string_child_or_empty"
10822     | Choice values ->                        (* [`val1|`val2|...] *)
10823         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
10824           (String.concat "|"
10825              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
10826     | ZeroOrMore rng ->                        (* <rng> list *)
10827         let pa = generate_parser rng in
10828         sprintf "(fun x -> List.map %s (Xml.children x))" pa
10829     | OneOrMore rng ->                        (* <rng> list *)
10830         let pa = generate_parser rng in
10831         sprintf "(fun x -> List.map %s (Xml.children x))" pa
10832                                         (* virt-inspector hack: bool *)
10833     | Optional (Attribute (name, [Value "1"])) ->
10834         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
10835     | Optional rng ->                        (* <rng> list *)
10836         let pa = generate_parser rng in
10837         sprintf "(function None -> None | Some x -> Some (%s x))" pa
10838                                         (* type name = { fields ... } *)
10839     | Element (name, fields) when is_attrs_interleave fields ->
10840         generate_parser_struct name (get_attrs_interleave fields)
10841     | Element (name, [field]) ->        (* type name = field *)
10842         let pa = generate_parser field in
10843         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
10844         pr "let %s =\n" parser_name;
10845         pr "  %s\n" pa;
10846         pr "let parse_%s = %s\n" name parser_name;
10847         parser_name
10848     | Attribute (name, [field]) ->
10849         let pa = generate_parser field in
10850         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
10851         pr "let %s =\n" parser_name;
10852         pr "  %s\n" pa;
10853         pr "let parse_%s = %s\n" name parser_name;
10854         parser_name
10855     | Element (name, fields) ->              (* type name = { fields ... } *)
10856         generate_parser_struct name ([], fields)
10857     | rng ->
10858         failwithf "generate_parser failed at: %s" (string_of_rng rng)
10859
10860   and is_attrs_interleave = function
10861     | [Interleave _] -> true
10862     | Attribute _ :: fields -> is_attrs_interleave fields
10863     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
10864     | _ -> false
10865
10866   and get_attrs_interleave = function
10867     | [Interleave fields] -> [], fields
10868     | ((Attribute _) as field) :: fields
10869     | ((Optional (Attribute _)) as field) :: fields ->
10870         let attrs, interleaves = get_attrs_interleave fields in
10871         (field :: attrs), interleaves
10872     | _ -> assert false
10873
10874   and generate_parsers xs =
10875     List.iter (fun x -> ignore (generate_parser x)) xs
10876
10877   and generate_parser_struct name (attrs, interleaves) =
10878     (* Generate parsers for the fields first.  We have to do this
10879      * before printing anything so we are still in BOL context.
10880      *)
10881     let fields = attrs @ interleaves in
10882     let pas = List.map generate_parser fields in
10883
10884     (* Generate an intermediate tuple from all the fields first.
10885      * If the type is just a string + another field, then we will
10886      * return this directly, otherwise it is turned into a record.
10887      *
10888      * RELAX NG note: This code treats <interleave> and plain lists of
10889      * fields the same.  In other words, it doesn't bother enforcing
10890      * any ordering of fields in the XML.
10891      *)
10892     pr "let parse_%s x =\n" name;
10893     pr "  let t = (\n    ";
10894     let comma = ref false in
10895     List.iter (
10896       fun x ->
10897         if !comma then pr ",\n    ";
10898         comma := true;
10899         match x with
10900         | Optional (Attribute (fname, [field])), pa ->
10901             pr "%s x" pa
10902         | Optional (Element (fname, [field])), pa ->
10903             pr "%s (optional_child %S x)" pa fname
10904         | Attribute (fname, [Text]), _ ->
10905             pr "attribute %S x" fname
10906         | (ZeroOrMore _ | OneOrMore _), pa ->
10907             pr "%s x" pa
10908         | Text, pa ->
10909             pr "%s x" pa
10910         | (field, pa) ->
10911             let fname = name_of_field field in
10912             pr "%s (child %S x)" pa fname
10913     ) (List.combine fields pas);
10914     pr "\n  ) in\n";
10915
10916     (match fields with
10917      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
10918          pr "  t\n"
10919
10920      | _ ->
10921          pr "  (Obj.magic t : %s)\n" name
10922 (*
10923          List.iter (
10924            function
10925            | (Optional (Attribute (fname, [field])), pa) ->
10926                pr "  %s_%s =\n" name fname;
10927                pr "    %s x;\n" pa
10928            | (Optional (Element (fname, [field])), pa) ->
10929                pr "  %s_%s =\n" name fname;
10930                pr "    (let x = optional_child %S x in\n" fname;
10931                pr "     %s x);\n" pa
10932            | (field, pa) ->
10933                let fname = name_of_field field in
10934                pr "  %s_%s =\n" name fname;
10935                pr "    (let x = child %S x in\n" fname;
10936                pr "     %s x);\n" pa
10937          ) (List.combine fields pas);
10938          pr "}\n"
10939 *)
10940     );
10941     sprintf "parse_%s" name
10942   in
10943
10944   generate_parsers xs
10945
10946 (* Generate ocaml/guestfs_inspector.mli. *)
10947 let generate_ocaml_inspector_mli () =
10948   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
10949
10950   pr "\
10951 (** This is an OCaml language binding to the external [virt-inspector]
10952     program.
10953
10954     For more information, please read the man page [virt-inspector(1)].
10955 *)
10956
10957 ";
10958
10959   generate_types grammar;
10960   pr "(** The nested information returned from the {!inspect} function. *)\n";
10961   pr "\n";
10962
10963   pr "\
10964 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
10965 (** To inspect a libvirt domain called [name], pass a singleton
10966     list: [inspect [name]].  When using libvirt only, you may
10967     optionally pass a libvirt URI using [inspect ~connect:uri ...].
10968
10969     To inspect a disk image or images, pass a list of the filenames
10970     of the disk images: [inspect filenames]
10971
10972     This function inspects the given guest or disk images and
10973     returns a list of operating system(s) found and a large amount
10974     of information about them.  In the vast majority of cases,
10975     a virtual machine only contains a single operating system.
10976
10977     If the optional [~xml] parameter is given, then this function
10978     skips running the external virt-inspector program and just
10979     parses the given XML directly (which is expected to be XML
10980     produced from a previous run of virt-inspector).  The list of
10981     names and connect URI are ignored in this case.
10982
10983     This function can throw a wide variety of exceptions, for example
10984     if the external virt-inspector program cannot be found, or if
10985     it doesn't generate valid XML.
10986 *)
10987 "
10988
10989 (* Generate ocaml/guestfs_inspector.ml. *)
10990 let generate_ocaml_inspector_ml () =
10991   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
10992
10993   pr "open Unix\n";
10994   pr "\n";
10995
10996   generate_types grammar;
10997   pr "\n";
10998
10999   pr "\
11000 (* Misc functions which are used by the parser code below. *)
11001 let first_child = function
11002   | Xml.Element (_, _, c::_) -> c
11003   | Xml.Element (name, _, []) ->
11004       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11005   | Xml.PCData str ->
11006       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11007
11008 let string_child_or_empty = function
11009   | Xml.Element (_, _, [Xml.PCData s]) -> s
11010   | Xml.Element (_, _, []) -> \"\"
11011   | Xml.Element (x, _, _) ->
11012       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11013                 x ^ \" instead\")
11014   | Xml.PCData str ->
11015       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11016
11017 let optional_child name xml =
11018   let children = Xml.children xml in
11019   try
11020     Some (List.find (function
11021                      | Xml.Element (n, _, _) when n = name -> true
11022                      | _ -> false) children)
11023   with
11024     Not_found -> None
11025
11026 let child name xml =
11027   match optional_child name xml with
11028   | Some c -> c
11029   | None ->
11030       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11031
11032 let attribute name xml =
11033   try Xml.attrib xml name
11034   with Xml.No_attribute _ ->
11035     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11036
11037 ";
11038
11039   generate_parsers grammar;
11040   pr "\n";
11041
11042   pr "\
11043 (* Run external virt-inspector, then use parser to parse the XML. *)
11044 let inspect ?connect ?xml names =
11045   let xml =
11046     match xml with
11047     | None ->
11048         if names = [] then invalid_arg \"inspect: no names given\";
11049         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11050           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11051           names in
11052         let cmd = List.map Filename.quote cmd in
11053         let cmd = String.concat \" \" cmd in
11054         let chan = open_process_in cmd in
11055         let xml = Xml.parse_in chan in
11056         (match close_process_in chan with
11057          | WEXITED 0 -> ()
11058          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11059          | WSIGNALED i | WSTOPPED i ->
11060              failwith (\"external virt-inspector command died or stopped on sig \" ^
11061                        string_of_int i)
11062         );
11063         xml
11064     | Some doc ->
11065         Xml.parse_string doc in
11066   parse_operatingsystems xml
11067 "
11068
11069 (* This is used to generate the src/MAX_PROC_NR file which
11070  * contains the maximum procedure number, a surrogate for the
11071  * ABI version number.  See src/Makefile.am for the details.
11072  *)
11073 and generate_max_proc_nr () =
11074   let proc_nrs = List.map (
11075     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11076   ) daemon_functions in
11077
11078   let max_proc_nr = List.fold_left max 0 proc_nrs in
11079
11080   pr "%d\n" max_proc_nr
11081
11082 let output_to filename k =
11083   let filename_new = filename ^ ".new" in
11084   chan := open_out filename_new;
11085   k ();
11086   close_out !chan;
11087   chan := Pervasives.stdout;
11088
11089   (* Is the new file different from the current file? *)
11090   if Sys.file_exists filename && files_equal filename filename_new then
11091     unlink filename_new                 (* same, so skip it *)
11092   else (
11093     (* different, overwrite old one *)
11094     (try chmod filename 0o644 with Unix_error _ -> ());
11095     rename filename_new filename;
11096     chmod filename 0o444;
11097     printf "written %s\n%!" filename;
11098   )
11099
11100 let perror msg = function
11101   | Unix_error (err, _, _) ->
11102       eprintf "%s: %s\n" msg (error_message err)
11103   | exn ->
11104       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11105
11106 (* Main program. *)
11107 let () =
11108   let lock_fd =
11109     try openfile "HACKING" [O_RDWR] 0
11110     with
11111     | Unix_error (ENOENT, _, _) ->
11112         eprintf "\
11113 You are probably running this from the wrong directory.
11114 Run it from the top source directory using the command
11115   src/generator.ml
11116 ";
11117         exit 1
11118     | exn ->
11119         perror "open: HACKING" exn;
11120         exit 1 in
11121
11122   (* Acquire a lock so parallel builds won't try to run the generator
11123    * twice at the same time.  Subsequent builds will wait for the first
11124    * one to finish.  Note the lock is released implicitly when the
11125    * program exits.
11126    *)
11127   (try lockf lock_fd F_LOCK 1
11128    with exn ->
11129      perror "lock: HACKING" exn;
11130      exit 1);
11131
11132   check_functions ();
11133
11134   output_to "src/guestfs_protocol.x" generate_xdr;
11135   output_to "src/guestfs-structs.h" generate_structs_h;
11136   output_to "src/guestfs-actions.h" generate_actions_h;
11137   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11138   output_to "src/guestfs-actions.c" generate_client_actions;
11139   output_to "src/guestfs-bindtests.c" generate_bindtests;
11140   output_to "src/guestfs-structs.pod" generate_structs_pod;
11141   output_to "src/guestfs-actions.pod" generate_actions_pod;
11142   output_to "src/guestfs-availability.pod" generate_availability_pod;
11143   output_to "daemon/actions.h" generate_daemon_actions_h;
11144   output_to "daemon/stubs.c" generate_daemon_actions;
11145   output_to "daemon/names.c" generate_daemon_names;
11146   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11147   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11148   output_to "capitests/tests.c" generate_tests;
11149   output_to "fish/cmds.c" generate_fish_cmds;
11150   output_to "fish/completion.c" generate_fish_completion;
11151   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11152   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11153   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11154   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11155   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11156   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11157   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11158   output_to "perl/Guestfs.xs" generate_perl_xs;
11159   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11160   output_to "perl/bindtests.pl" generate_perl_bindtests;
11161   output_to "python/guestfs-py.c" generate_python_c;
11162   output_to "python/guestfs.py" generate_python_py;
11163   output_to "python/bindtests.py" generate_python_bindtests;
11164   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11165   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11166   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11167
11168   List.iter (
11169     fun (typ, jtyp) ->
11170       let cols = cols_of_struct typ in
11171       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11172       output_to filename (generate_java_struct jtyp cols);
11173   ) java_structs;
11174
11175   output_to "java/Makefile.inc" generate_java_makefile_inc;
11176   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11177   output_to "java/Bindtests.java" generate_java_bindtests;
11178   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11179   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11180   output_to "csharp/Libguestfs.cs" generate_csharp;
11181   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11182
11183   (* Always generate this file last, and unconditionally.  It's used
11184    * by the Makefile to know when we must re-run the generator.
11185    *)
11186   let chan = open_out "src/stamp-generator" in
11187   fprintf chan "1\n";
11188   close_out chan;
11189
11190   printf "generated %d lines of code\n" !lines