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