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