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