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