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