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