c32b0ed8e0c9da80c13190b03eba486eab7d37ae
[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
37 open Printf
38
39 type style = ret * args
40 and ret =
41     (* "RErr" as a return value means an int used as a simple error
42      * indication, ie. 0 or -1.
43      *)
44   | RErr
45     (* "RInt" as a return value means an int which is -1 for error
46      * or any value >= 0 on success.
47      *)
48   | RInt of string
49     (* "RBool" is a bool return value which can be true/false or
50      * -1 for error.
51      *)
52   | RBool of string
53     (* "RConstString" is a string that refers to a constant value.
54      * Try to avoid using this.  In particular you cannot use this
55      * for values returned from the daemon, because there is no
56      * thread-safe way to return them in the C API.
57      *)
58   | RConstString of string
59     (* "RString" and "RStringList" are caller-frees. *)
60   | RString of string
61   | RStringList of string
62     (* Some limited tuples are possible: *)
63   | RIntBool of string * string
64     (* LVM PVs, VGs and LVs. *)
65   | RPVList of string
66   | RVGList of string
67   | RLVList of string
68     (* Stat buffers. *)
69   | RStat of string
70   | RStatVFS of string
71 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
72
73     (* Note in future we should allow a "variable args" parameter as
74      * the final parameter, to allow commands like
75      *   chmod mode file [file(s)...]
76      * This is not implemented yet, but many commands (such as chmod)
77      * are currently defined with the argument order keeping this future
78      * possibility in mind.
79      *)
80 and argt =
81   | String of string    (* const char *name, cannot be NULL *)
82   | OptString of string (* const char *name, may be NULL *)
83   | StringList of string(* list of strings (each string cannot be NULL) *)
84   | Bool of string      (* boolean *)
85   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
86
87 type flags =
88   | ProtocolLimitWarning  (* display warning about protocol size limits *)
89   | DangerWillRobinson    (* flags particularly dangerous commands *)
90   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
91   | FishAction of string  (* call this function in guestfish *)
92   | NotInFish             (* do not export via guestfish *)
93
94 let protocol_limit_warning =
95   "Because of the message protocol, there is a transfer limit 
96 of somewhere between 2MB and 4MB.  To transfer large files you should use
97 FTP."
98
99 let danger_will_robinson =
100   "B<This command is dangerous.  Without careful use you
101 can easily destroy all your data>."
102
103 (* You can supply zero or as many tests as you want per API call.
104  *
105  * Note that the test environment has 3 block devices, of size 500MB,
106  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc).
107  * Note for partitioning purposes, the 500MB device has 63 cylinders.
108  *
109  * To be able to run the tests in a reasonable amount of time,
110  * the virtual machine and block devices are reused between tests.
111  * So don't try testing kill_subprocess :-x
112  *
113  * Between each test we umount-all and lvm-remove-all (except InitNone).
114  *
115  * Don't assume anything about the previous contents of the block
116  * devices.  Use 'Init*' to create some initial scenarios.
117  *)
118 type tests = (test_init * test) list
119 and test =
120     (* Run the command sequence and just expect nothing to fail. *)
121   | TestRun of seq
122     (* Run the command sequence and expect the output of the final
123      * command to be the string.
124      *)
125   | TestOutput of seq * string
126     (* Run the command sequence and expect the output of the final
127      * command to be the list of strings.
128      *)
129   | TestOutputList of seq * string list
130     (* Run the command sequence and expect the output of the final
131      * command to be the integer.
132      *)
133   | TestOutputInt of seq * int
134     (* Run the command sequence and expect the output of the final
135      * command to be a true value (!= 0 or != NULL).
136      *)
137   | TestOutputTrue of seq
138     (* Run the command sequence and expect the output of the final
139      * command to be a false value (== 0 or == NULL, but not an error).
140      *)
141   | TestOutputFalse of seq
142     (* Run the command sequence and expect the output of the final
143      * command to be a list of the given length (but don't care about
144      * content).
145      *)
146   | TestOutputLength of seq * int
147     (* Run the command sequence and expect the output of the final
148      * command to be a structure.
149      *)
150   | TestOutputStruct of seq * test_field_compare list
151     (* Run the command sequence and expect the final command (only)
152      * to fail.
153      *)
154   | TestLastFail of seq
155
156 and test_field_compare =
157   | CompareWithInt of string * int
158   | CompareWithString of string * string
159   | CompareFieldsIntEq of string * string
160   | CompareFieldsStrEq of string * string
161
162 (* Some initial scenarios for testing. *)
163 and test_init =
164     (* Do nothing, block devices could contain random stuff including
165      * LVM PVs, and some filesystems might be mounted.  This is usually
166      * a bad idea.
167      *)
168   | InitNone
169     (* Block devices are empty and no filesystems are mounted. *)
170   | InitEmpty
171     (* /dev/sda contains a single partition /dev/sda1, which is formatted
172      * as ext2, empty [except for lost+found] and mounted on /.
173      * /dev/sdb and /dev/sdc may have random content.
174      * No LVM.
175      *)
176   | InitBasicFS
177     (* /dev/sda:
178      *   /dev/sda1 (is a PV):
179      *     /dev/VG/LV (size 8MB):
180      *       formatted as ext2, empty [except for lost+found], mounted on /
181      * /dev/sdb and /dev/sdc may have random content.
182      *)
183   | InitBasicFSonLVM
184
185 (* Sequence of commands for testing. *)
186 and seq = cmd list
187 and cmd = string list
188
189 (* Note about long descriptions: When referring to another
190  * action, use the format C<guestfs_other> (ie. the full name of
191  * the C function).  This will be replaced as appropriate in other
192  * language bindings.
193  *
194  * Apart from that, long descriptions are just perldoc paragraphs.
195  *)
196
197 let non_daemon_functions = [
198   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
199    [],
200    "launch the qemu subprocess",
201    "\
202 Internally libguestfs is implemented by running a virtual machine
203 using L<qemu(1)>.
204
205 You should call this after configuring the handle
206 (eg. adding drives) but before performing any actions.");
207
208   ("wait_ready", (RErr, []), -1, [NotInFish],
209    [],
210    "wait until the qemu subprocess launches",
211    "\
212 Internally libguestfs is implemented by running a virtual machine
213 using L<qemu(1)>.
214
215 You should call this after C<guestfs_launch> to wait for the launch
216 to complete.");
217
218   ("kill_subprocess", (RErr, []), -1, [],
219    [],
220    "kill the qemu subprocess",
221    "\
222 This kills the qemu subprocess.  You should never need to call this.");
223
224   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
225    [],
226    "add an image to examine or modify",
227    "\
228 This function adds a virtual machine disk image C<filename> to the
229 guest.  The first time you call this function, the disk appears as IDE
230 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
231 so on.
232
233 You don't necessarily need to be root when using libguestfs.  However
234 you obviously do need sufficient permissions to access the filename
235 for whatever operations you want to perform (ie. read access if you
236 just want to read the image or write access if you want to modify the
237 image).
238
239 This is equivalent to the qemu parameter C<-drive file=filename>.");
240
241   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
242    [],
243    "add a CD-ROM disk image to examine",
244    "\
245 This function adds a virtual CD-ROM disk image to the guest.
246
247 This is equivalent to the qemu parameter C<-cdrom filename>.");
248
249   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
250    [],
251    "add qemu parameters",
252    "\
253 This can be used to add arbitrary qemu command line parameters
254 of the form C<-param value>.  Actually it's not quite arbitrary - we
255 prevent you from setting some parameters which would interfere with
256 parameters that we use.
257
258 The first character of C<param> string must be a C<-> (dash).
259
260 C<value> can be NULL.");
261
262   ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
263    [],
264    "set the search path",
265    "\
266 Set the path that libguestfs searches for kernel and initrd.img.
267
268 The default is C<$libdir/guestfs> unless overridden by setting
269 C<LIBGUESTFS_PATH> environment variable.
270
271 The string C<path> is stashed in the libguestfs handle, so the caller
272 must make sure it remains valid for the lifetime of the handle.
273
274 Setting C<path> to C<NULL> restores the default path.");
275
276   ("get_path", (RConstString "path", []), -1, [],
277    [],
278    "get the search path",
279    "\
280 Return the current search path.
281
282 This is always non-NULL.  If it wasn't set already, then this will
283 return the default path.");
284
285   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
286    [],
287    "set autosync mode",
288    "\
289 If C<autosync> is true, this enables autosync.  Libguestfs will make a
290 best effort attempt to run C<guestfs_sync> when the handle is closed
291 (also if the program exits without closing handles).");
292
293   ("get_autosync", (RBool "autosync", []), -1, [],
294    [],
295    "get autosync mode",
296    "\
297 Get the autosync flag.");
298
299   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
300    [],
301    "set verbose mode",
302    "\
303 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
304
305 Verbose messages are disabled unless the environment variable
306 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
307
308   ("get_verbose", (RBool "verbose", []), -1, [],
309    [],
310    "get verbose mode",
311    "\
312 This returns the verbose messages flag.")
313 ]
314
315 let daemon_functions = [
316   ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
317    [InitEmpty, TestOutput (
318       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
319        ["mkfs"; "ext2"; "/dev/sda1"];
320        ["mount"; "/dev/sda1"; "/"];
321        ["write_file"; "/new"; "new file contents"; "0"];
322        ["cat"; "/new"]], "new file contents")],
323    "mount a guest disk at a position in the filesystem",
324    "\
325 Mount a guest disk at a position in the filesystem.  Block devices
326 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
327 the guest.  If those block devices contain partitions, they will have
328 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
329 names can be used.
330
331 The rules are the same as for L<mount(2)>:  A filesystem must
332 first be mounted on C</> before others can be mounted.  Other
333 filesystems can only be mounted on directories which already
334 exist.
335
336 The mounted filesystem is writable, if we have sufficient permissions
337 on the underlying device.
338
339 The filesystem options C<sync> and C<noatime> are set with this
340 call, in order to improve reliability.");
341
342   ("sync", (RErr, []), 2, [],
343    [ InitEmpty, TestRun [["sync"]]],
344    "sync disks, writes are flushed through to the disk image",
345    "\
346 This syncs the disk, so that any writes are flushed through to the
347 underlying disk image.
348
349 You should always call this if you have modified a disk image, before
350 closing the handle.");
351
352   ("touch", (RErr, [String "path"]), 3, [],
353    [InitBasicFS, TestOutputTrue (
354       [["touch"; "/new"];
355        ["exists"; "/new"]])],
356    "update file timestamps or create a new file",
357    "\
358 Touch acts like the L<touch(1)> command.  It can be used to
359 update the timestamps on a file, or, if the file does not exist,
360 to create a new zero-length file.");
361
362   ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
363    [InitBasicFS, TestOutput (
364       [["write_file"; "/new"; "new file contents"; "0"];
365        ["cat"; "/new"]], "new file contents")],
366    "list the contents of a file",
367    "\
368 Return the contents of the file named C<path>.
369
370 Note that this function cannot correctly handle binary files
371 (specifically, files containing C<\\0> character which is treated
372 as end of string).  For those you need to use the C<guestfs_read_file>
373 function which has a more complex interface.");
374
375   ("ll", (RString "listing", [String "directory"]), 5, [],
376    [], (* XXX Tricky to test because it depends on the exact format
377         * of the 'ls -l' command, which changes between F10 and F11.
378         *)
379    "list the files in a directory (long format)",
380    "\
381 List the files in C<directory> (relative to the root directory,
382 there is no cwd) in the format of 'ls -la'.
383
384 This command is mostly useful for interactive sessions.  It
385 is I<not> intended that you try to parse the output string.");
386
387   ("ls", (RStringList "listing", [String "directory"]), 6, [],
388    [InitBasicFS, TestOutputList (
389       [["touch"; "/new"];
390        ["touch"; "/newer"];
391        ["touch"; "/newest"];
392        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
393    "list the files in a directory",
394    "\
395 List the files in C<directory> (relative to the root directory,
396 there is no cwd).  The '.' and '..' entries are not returned, but
397 hidden files are shown.
398
399 This command is mostly useful for interactive sessions.  Programs
400 should probably use C<guestfs_readdir> instead.");
401
402   ("list_devices", (RStringList "devices", []), 7, [],
403    [InitEmpty, TestOutputList (
404       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
405    "list the block devices",
406    "\
407 List all the block devices.
408
409 The full block device names are returned, eg. C</dev/sda>");
410
411   ("list_partitions", (RStringList "partitions", []), 8, [],
412    [InitBasicFS, TestOutputList (
413       [["list_partitions"]], ["/dev/sda1"]);
414     InitEmpty, TestOutputList (
415       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
416        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
417    "list the partitions",
418    "\
419 List all the partitions detected on all block devices.
420
421 The full partition device names are returned, eg. C</dev/sda1>
422
423 This does not return logical volumes.  For that you will need to
424 call C<guestfs_lvs>.");
425
426   ("pvs", (RStringList "physvols", []), 9, [],
427    [InitBasicFSonLVM, TestOutputList (
428       [["pvs"]], ["/dev/sda1"]);
429     InitEmpty, TestOutputList (
430       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
431        ["pvcreate"; "/dev/sda1"];
432        ["pvcreate"; "/dev/sda2"];
433        ["pvcreate"; "/dev/sda3"];
434        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
435    "list the LVM physical volumes (PVs)",
436    "\
437 List all the physical volumes detected.  This is the equivalent
438 of the L<pvs(8)> command.
439
440 This returns a list of just the device names that contain
441 PVs (eg. C</dev/sda2>).
442
443 See also C<guestfs_pvs_full>.");
444
445   ("vgs", (RStringList "volgroups", []), 10, [],
446    [InitBasicFSonLVM, TestOutputList (
447       [["vgs"]], ["VG"]);
448     InitEmpty, TestOutputList (
449       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
450        ["pvcreate"; "/dev/sda1"];
451        ["pvcreate"; "/dev/sda2"];
452        ["pvcreate"; "/dev/sda3"];
453        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
454        ["vgcreate"; "VG2"; "/dev/sda3"];
455        ["vgs"]], ["VG1"; "VG2"])],
456    "list the LVM volume groups (VGs)",
457    "\
458 List all the volumes groups detected.  This is the equivalent
459 of the L<vgs(8)> command.
460
461 This returns a list of just the volume group names that were
462 detected (eg. C<VolGroup00>).
463
464 See also C<guestfs_vgs_full>.");
465
466   ("lvs", (RStringList "logvols", []), 11, [],
467    [InitBasicFSonLVM, TestOutputList (
468       [["lvs"]], ["/dev/VG/LV"]);
469     InitEmpty, TestOutputList (
470       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
471        ["pvcreate"; "/dev/sda1"];
472        ["pvcreate"; "/dev/sda2"];
473        ["pvcreate"; "/dev/sda3"];
474        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
475        ["vgcreate"; "VG2"; "/dev/sda3"];
476        ["lvcreate"; "LV1"; "VG1"; "50"];
477        ["lvcreate"; "LV2"; "VG1"; "50"];
478        ["lvcreate"; "LV3"; "VG2"; "50"];
479        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
480    "list the LVM logical volumes (LVs)",
481    "\
482 List all the logical volumes detected.  This is the equivalent
483 of the L<lvs(8)> command.
484
485 This returns a list of the logical volume device names
486 (eg. C</dev/VolGroup00/LogVol00>).
487
488 See also C<guestfs_lvs_full>.");
489
490   ("pvs_full", (RPVList "physvols", []), 12, [],
491    [], (* XXX how to test? *)
492    "list the LVM physical volumes (PVs)",
493    "\
494 List all the physical volumes detected.  This is the equivalent
495 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
496
497   ("vgs_full", (RVGList "volgroups", []), 13, [],
498    [], (* XXX how to test? *)
499    "list the LVM volume groups (VGs)",
500    "\
501 List all the volumes groups detected.  This is the equivalent
502 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
503
504   ("lvs_full", (RLVList "logvols", []), 14, [],
505    [], (* XXX how to test? *)
506    "list the LVM logical volumes (LVs)",
507    "\
508 List all the logical volumes detected.  This is the equivalent
509 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
510
511   ("read_lines", (RStringList "lines", [String "path"]), 15, [],
512    [InitBasicFS, TestOutputList (
513       [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
514        ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
515     InitBasicFS, TestOutputList (
516       [["write_file"; "/new"; ""; "0"];
517        ["read_lines"; "/new"]], [])],
518    "read file as lines",
519    "\
520 Return the contents of the file named C<path>.
521
522 The file contents are returned as a list of lines.  Trailing
523 C<LF> and C<CRLF> character sequences are I<not> returned.
524
525 Note that this function cannot correctly handle binary files
526 (specifically, files containing C<\\0> character which is treated
527 as end of line).  For those you need to use the C<guestfs_read_file>
528 function which has a more complex interface.");
529
530   ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
531    [], (* XXX Augeas code needs tests. *)
532    "create a new Augeas handle",
533    "\
534 Create a new Augeas handle for editing configuration files.
535 If there was any previous Augeas handle associated with this
536 guestfs session, then it is closed.
537
538 You must call this before using any other C<guestfs_aug_*>
539 commands.
540
541 C<root> is the filesystem root.  C<root> must not be NULL,
542 use C</> instead.
543
544 The flags are the same as the flags defined in
545 E<lt>augeas.hE<gt>, the logical I<or> of the following
546 integers:
547
548 =over 4
549
550 =item C<AUG_SAVE_BACKUP> = 1
551
552 Keep the original file with a C<.augsave> extension.
553
554 =item C<AUG_SAVE_NEWFILE> = 2
555
556 Save changes into a file with extension C<.augnew>, and
557 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
558
559 =item C<AUG_TYPE_CHECK> = 4
560
561 Typecheck lenses (can be expensive).
562
563 =item C<AUG_NO_STDINC> = 8
564
565 Do not use standard load path for modules.
566
567 =item C<AUG_SAVE_NOOP> = 16
568
569 Make save a no-op, just record what would have been changed.
570
571 =item C<AUG_NO_LOAD> = 32
572
573 Do not load the tree in C<guestfs_aug_init>.
574
575 =back
576
577 To close the handle, you can call C<guestfs_aug_close>.
578
579 To find out more about Augeas, see L<http://augeas.net/>.");
580
581   ("aug_close", (RErr, []), 26, [],
582    [], (* XXX Augeas code needs tests. *)
583    "close the current Augeas handle",
584    "\
585 Close the current Augeas handle and free up any resources
586 used by it.  After calling this, you have to call
587 C<guestfs_aug_init> again before you can use any other
588 Augeas functions.");
589
590   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
591    [], (* XXX Augeas code needs tests. *)
592    "define an Augeas variable",
593    "\
594 Defines an Augeas variable C<name> whose value is the result
595 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
596 undefined.
597
598 On success this returns the number of nodes in C<expr>, or
599 C<0> if C<expr> evaluates to something which is not a nodeset.");
600
601   ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
602    [], (* XXX Augeas code needs tests. *)
603    "define an Augeas node",
604    "\
605 Defines a variable C<name> whose value is the result of
606 evaluating C<expr>.
607
608 If C<expr> evaluates to an empty nodeset, a node is created,
609 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
610 C<name> will be the nodeset containing that single node.
611
612 On success this returns a pair containing the
613 number of nodes in the nodeset, and a boolean flag
614 if a node was created.");
615
616   ("aug_get", (RString "val", [String "path"]), 19, [],
617    [], (* XXX Augeas code needs tests. *)
618    "look up the value of an Augeas path",
619    "\
620 Look up the value associated with C<path>.  If C<path>
621 matches exactly one node, the C<value> is returned.");
622
623   ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
624    [], (* XXX Augeas code needs tests. *)
625    "set Augeas path to value",
626    "\
627 Set the value associated with C<path> to C<value>.");
628
629   ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
630    [], (* XXX Augeas code needs tests. *)
631    "insert a sibling Augeas node",
632    "\
633 Create a new sibling C<label> for C<path>, inserting it into
634 the tree before or after C<path> (depending on the boolean
635 flag C<before>).
636
637 C<path> must match exactly one existing node in the tree, and
638 C<label> must be a label, ie. not contain C</>, C<*> or end
639 with a bracketed index C<[N]>.");
640
641   ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
642    [], (* XXX Augeas code needs tests. *)
643    "remove an Augeas path",
644    "\
645 Remove C<path> and all of its children.
646
647 On success this returns the number of entries which were removed.");
648
649   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
650    [], (* XXX Augeas code needs tests. *)
651    "move Augeas node",
652    "\
653 Move the node C<src> to C<dest>.  C<src> must match exactly
654 one node.  C<dest> is overwritten if it exists.");
655
656   ("aug_match", (RStringList "matches", [String "path"]), 24, [],
657    [], (* XXX Augeas code needs tests. *)
658    "return Augeas nodes which match path",
659    "\
660 Returns a list of paths which match the path expression C<path>.
661 The returned paths are sufficiently qualified so that they match
662 exactly one node in the current tree.");
663
664   ("aug_save", (RErr, []), 25, [],
665    [], (* XXX Augeas code needs tests. *)
666    "write all pending Augeas changes to disk",
667    "\
668 This writes all pending changes to disk.
669
670 The flags which were passed to C<guestfs_aug_init> affect exactly
671 how files are saved.");
672
673   ("aug_load", (RErr, []), 27, [],
674    [], (* XXX Augeas code needs tests. *)
675    "load files into the tree",
676    "\
677 Load files into the tree.
678
679 See C<aug_load> in the Augeas documentation for the full gory
680 details.");
681
682   ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
683    [], (* XXX Augeas code needs tests. *)
684    "list Augeas nodes under a path",
685    "\
686 This is just a shortcut for listing C<guestfs_aug_match>
687 C<path/*> and sorting the resulting nodes into alphabetical order.");
688
689   ("rm", (RErr, [String "path"]), 29, [],
690    [InitBasicFS, TestRun
691       [["touch"; "/new"];
692        ["rm"; "/new"]];
693     InitBasicFS, TestLastFail
694       [["rm"; "/new"]];
695     InitBasicFS, TestLastFail
696       [["mkdir"; "/new"];
697        ["rm"; "/new"]]],
698    "remove a file",
699    "\
700 Remove the single file C<path>.");
701
702   ("rmdir", (RErr, [String "path"]), 30, [],
703    [InitBasicFS, TestRun
704       [["mkdir"; "/new"];
705        ["rmdir"; "/new"]];
706     InitBasicFS, TestLastFail
707       [["rmdir"; "/new"]];
708     InitBasicFS, TestLastFail
709       [["touch"; "/new"];
710        ["rmdir"; "/new"]]],
711    "remove a directory",
712    "\
713 Remove the single directory C<path>.");
714
715   ("rm_rf", (RErr, [String "path"]), 31, [],
716    [InitBasicFS, TestOutputFalse
717       [["mkdir"; "/new"];
718        ["mkdir"; "/new/foo"];
719        ["touch"; "/new/foo/bar"];
720        ["rm_rf"; "/new"];
721        ["exists"; "/new"]]],
722    "remove a file or directory recursively",
723    "\
724 Remove the file or directory C<path>, recursively removing the
725 contents if its a directory.  This is like the C<rm -rf> shell
726 command.");
727
728   ("mkdir", (RErr, [String "path"]), 32, [],
729    [InitBasicFS, TestOutputTrue
730       [["mkdir"; "/new"];
731        ["is_dir"; "/new"]];
732     InitBasicFS, TestLastFail
733       [["mkdir"; "/new/foo/bar"]]],
734    "create a directory",
735    "\
736 Create a directory named C<path>.");
737
738   ("mkdir_p", (RErr, [String "path"]), 33, [],
739    [InitBasicFS, TestOutputTrue
740       [["mkdir_p"; "/new/foo/bar"];
741        ["is_dir"; "/new/foo/bar"]];
742     InitBasicFS, TestOutputTrue
743       [["mkdir_p"; "/new/foo/bar"];
744        ["is_dir"; "/new/foo"]];
745     InitBasicFS, TestOutputTrue
746       [["mkdir_p"; "/new/foo/bar"];
747        ["is_dir"; "/new"]]],
748    "create a directory and parents",
749    "\
750 Create a directory named C<path>, creating any parent directories
751 as necessary.  This is like the C<mkdir -p> shell command.");
752
753   ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
754    [], (* XXX Need stat command to test *)
755    "change file mode",
756    "\
757 Change the mode (permissions) of C<path> to C<mode>.  Only
758 numeric modes are supported.");
759
760   ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
761    [], (* XXX Need stat command to test *)
762    "change file owner and group",
763    "\
764 Change the file owner to C<owner> and group to C<group>.
765
766 Only numeric uid and gid are supported.  If you want to use
767 names, you will need to locate and parse the password file
768 yourself (Augeas support makes this relatively easy).");
769
770   ("exists", (RBool "existsflag", [String "path"]), 36, [],
771    [InitBasicFS, TestOutputTrue (
772       [["touch"; "/new"];
773        ["exists"; "/new"]]);
774     InitBasicFS, TestOutputTrue (
775       [["mkdir"; "/new"];
776        ["exists"; "/new"]])],
777    "test if file or directory exists",
778    "\
779 This returns C<true> if and only if there is a file, directory
780 (or anything) with the given C<path> name.
781
782 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
783
784   ("is_file", (RBool "fileflag", [String "path"]), 37, [],
785    [InitBasicFS, TestOutputTrue (
786       [["touch"; "/new"];
787        ["is_file"; "/new"]]);
788     InitBasicFS, TestOutputFalse (
789       [["mkdir"; "/new"];
790        ["is_file"; "/new"]])],
791    "test if file exists",
792    "\
793 This returns C<true> if and only if there is a file
794 with the given C<path> name.  Note that it returns false for
795 other objects like directories.
796
797 See also C<guestfs_stat>.");
798
799   ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
800    [InitBasicFS, TestOutputFalse (
801       [["touch"; "/new"];
802        ["is_dir"; "/new"]]);
803     InitBasicFS, TestOutputTrue (
804       [["mkdir"; "/new"];
805        ["is_dir"; "/new"]])],
806    "test if file exists",
807    "\
808 This returns C<true> if and only if there is a directory
809 with the given C<path> name.  Note that it returns false for
810 other objects like files.
811
812 See also C<guestfs_stat>.");
813
814   ("pvcreate", (RErr, [String "device"]), 39, [],
815    [InitEmpty, TestOutputList (
816       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
817        ["pvcreate"; "/dev/sda1"];
818        ["pvcreate"; "/dev/sda2"];
819        ["pvcreate"; "/dev/sda3"];
820        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
821    "create an LVM physical volume",
822    "\
823 This creates an LVM physical volume on the named C<device>,
824 where C<device> should usually be a partition name such
825 as C</dev/sda1>.");
826
827   ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
828    [InitEmpty, TestOutputList (
829       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
830        ["pvcreate"; "/dev/sda1"];
831        ["pvcreate"; "/dev/sda2"];
832        ["pvcreate"; "/dev/sda3"];
833        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
834        ["vgcreate"; "VG2"; "/dev/sda3"];
835        ["vgs"]], ["VG1"; "VG2"])],
836    "create an LVM volume group",
837    "\
838 This creates an LVM volume group called C<volgroup>
839 from the non-empty list of physical volumes C<physvols>.");
840
841   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
842    [InitEmpty, TestOutputList (
843       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
844        ["pvcreate"; "/dev/sda1"];
845        ["pvcreate"; "/dev/sda2"];
846        ["pvcreate"; "/dev/sda3"];
847        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
848        ["vgcreate"; "VG2"; "/dev/sda3"];
849        ["lvcreate"; "LV1"; "VG1"; "50"];
850        ["lvcreate"; "LV2"; "VG1"; "50"];
851        ["lvcreate"; "LV3"; "VG2"; "50"];
852        ["lvcreate"; "LV4"; "VG2"; "50"];
853        ["lvcreate"; "LV5"; "VG2"; "50"];
854        ["lvs"]],
855       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
856        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
857    "create an LVM volume group",
858    "\
859 This creates an LVM volume group called C<logvol>
860 on the volume group C<volgroup>, with C<size> megabytes.");
861
862   ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
863    [InitEmpty, TestOutput (
864       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
865        ["mkfs"; "ext2"; "/dev/sda1"];
866        ["mount"; "/dev/sda1"; "/"];
867        ["write_file"; "/new"; "new file contents"; "0"];
868        ["cat"; "/new"]], "new file contents")],
869    "make a filesystem",
870    "\
871 This creates a filesystem on C<device> (usually a partition
872 of LVM logical volume).  The filesystem type is C<fstype>, for
873 example C<ext3>.");
874
875   ("sfdisk", (RErr, [String "device";
876                      Int "cyls"; Int "heads"; Int "sectors";
877                      StringList "lines"]), 43, [DangerWillRobinson],
878    [],
879    "create partitions on a block device",
880    "\
881 This is a direct interface to the L<sfdisk(8)> program for creating
882 partitions on block devices.
883
884 C<device> should be a block device, for example C</dev/sda>.
885
886 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
887 and sectors on the device, which are passed directly to sfdisk as
888 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
889 of these, then the corresponding parameter is omitted.  Usually for
890 'large' disks, you can just pass C<0> for these, but for small
891 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
892 out the right geometry and you will need to tell it.
893
894 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
895 information refer to the L<sfdisk(8)> manpage.
896
897 To create a single partition occupying the whole disk, you would
898 pass C<lines> as a single element list, when the single element being
899 the string C<,> (comma).");
900
901   ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
902    [InitEmpty, TestOutput (
903       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
904        ["mkfs"; "ext2"; "/dev/sda1"];
905        ["mount"; "/dev/sda1"; "/"];
906        ["write_file"; "/new"; "new file contents"; "0"];
907        ["cat"; "/new"]], "new file contents")],
908    "create a file",
909    "\
910 This call creates a file called C<path>.  The contents of the
911 file is the string C<content> (which can contain any 8 bit data),
912 with length C<size>.
913
914 As a special case, if C<size> is C<0>
915 then the length is calculated using C<strlen> (so in this case
916 the content cannot contain embedded ASCII NULs).");
917
918   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
919    [InitEmpty, TestOutputList (
920       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
921        ["mkfs"; "ext2"; "/dev/sda1"];
922        ["mount"; "/dev/sda1"; "/"];
923        ["mounts"]], ["/dev/sda1"]);
924     InitEmpty, TestOutputList (
925       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
926        ["mkfs"; "ext2"; "/dev/sda1"];
927        ["mount"; "/dev/sda1"; "/"];
928        ["umount"; "/"];
929        ["mounts"]], [])],
930    "unmount a filesystem",
931    "\
932 This unmounts the given filesystem.  The filesystem may be
933 specified either by its mountpoint (path) or the device which
934 contains the filesystem.");
935
936   ("mounts", (RStringList "devices", []), 46, [],
937    [InitBasicFS, TestOutputList (
938       [["mounts"]], ["/dev/sda1"])],
939    "show mounted filesystems",
940    "\
941 This returns the list of currently mounted filesystems.  It returns
942 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
943
944 Some internal mounts are not shown.");
945
946   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
947    [InitBasicFS, TestOutputList (
948       [["umount_all"];
949        ["mounts"]], [])],
950    "unmount all filesystems",
951    "\
952 This unmounts all mounted filesystems.
953
954 Some internal mounts are not unmounted by this call.");
955
956   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
957    [],
958    "remove all LVM LVs, VGs and PVs",
959    "\
960 This command removes all LVM logical volumes, volume groups
961 and physical volumes.");
962
963   ("file", (RString "description", [String "path"]), 49, [],
964    [InitBasicFS, TestOutput (
965       [["touch"; "/new"];
966        ["file"; "/new"]], "empty");
967     InitBasicFS, TestOutput (
968       [["write_file"; "/new"; "some content\n"; "0"];
969        ["file"; "/new"]], "ASCII text");
970     InitBasicFS, TestLastFail (
971       [["file"; "/nofile"]])],
972    "determine file type",
973    "\
974 This call uses the standard L<file(1)> command to determine
975 the type or contents of the file.  This also works on devices,
976 for example to find out whether a partition contains a filesystem.
977
978 The exact command which runs is C<file -bsL path>.  Note in
979 particular that the filename is not prepended to the output
980 (the C<-b> option).");
981
982   ("command", (RString "output", [StringList "arguments"]), 50, [],
983    [], (* XXX how to test? *)
984    "run a command from the guest filesystem",
985    "\
986 This call runs a command from the guest filesystem.  The
987 filesystem must be mounted, and must contain a compatible
988 operating system (ie. something Linux, with the same
989 or compatible processor architecture).
990
991 The single parameter is an argv-style list of arguments.
992 The first element is the name of the program to run.
993 Subsequent elements are parameters.  The list must be
994 non-empty (ie. must contain a program name).
995
996 The C<$PATH> environment variable will contain at least
997 C</usr/bin> and C</bin>.  If you require a program from
998 another location, you should provide the full path in the
999 first parameter.
1000
1001 Shared libraries and data files required by the program
1002 must be available on filesystems which are mounted in the
1003 correct places.  It is the caller's responsibility to ensure
1004 all filesystems that are needed are mounted at the right
1005 locations.");
1006
1007   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [],
1008    [], (* XXX how to test? *)
1009    "run a command, returning lines",
1010    "\
1011 This is the same as C<guestfs_command>, but splits the
1012 result into a list of lines.");
1013
1014   ("stat", (RStat "statbuf", [String "path"]), 52, [],
1015    [InitBasicFS, TestOutputStruct (
1016       [["touch"; "/new"];
1017        ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1018    "get file information",
1019    "\
1020 Returns file information for the given C<path>.
1021
1022 This is the same as the C<stat(2)> system call.");
1023
1024   ("lstat", (RStat "statbuf", [String "path"]), 53, [],
1025    [InitBasicFS, TestOutputStruct (
1026       [["touch"; "/new"];
1027        ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1028    "get file information for a symbolic link",
1029    "\
1030 Returns file information for the given C<path>.
1031
1032 This is the same as C<guestfs_stat> except that if C<path>
1033 is a symbolic link, then the link is stat-ed, not the file it
1034 refers to.
1035
1036 This is the same as the C<lstat(2)> system call.");
1037
1038   ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
1039    [InitBasicFS, TestOutputStruct (
1040       [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
1041                            CompareWithInt ("blocks", 490020);
1042                            CompareWithInt ("bsize", 1024)])],
1043    "get file system statistics",
1044    "\
1045 Returns file system statistics for any mounted file system.
1046 C<path> should be a file or directory in the mounted file system
1047 (typically it is the mount point itself, but it doesn't need to be).
1048
1049 This is the same as the C<statvfs(2)> system call.");
1050
1051 ]
1052
1053 let all_functions = non_daemon_functions @ daemon_functions
1054
1055 (* In some places we want the functions to be displayed sorted
1056  * alphabetically, so this is useful:
1057  *)
1058 let all_functions_sorted =
1059   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
1060                compare n1 n2) all_functions
1061
1062 (* Column names and types from LVM PVs/VGs/LVs. *)
1063 let pv_cols = [
1064   "pv_name", `String;
1065   "pv_uuid", `UUID;
1066   "pv_fmt", `String;
1067   "pv_size", `Bytes;
1068   "dev_size", `Bytes;
1069   "pv_free", `Bytes;
1070   "pv_used", `Bytes;
1071   "pv_attr", `String (* XXX *);
1072   "pv_pe_count", `Int;
1073   "pv_pe_alloc_count", `Int;
1074   "pv_tags", `String;
1075   "pe_start", `Bytes;
1076   "pv_mda_count", `Int;
1077   "pv_mda_free", `Bytes;
1078 (* Not in Fedora 10:
1079   "pv_mda_size", `Bytes;
1080 *)
1081 ]
1082 let vg_cols = [
1083   "vg_name", `String;
1084   "vg_uuid", `UUID;
1085   "vg_fmt", `String;
1086   "vg_attr", `String (* XXX *);
1087   "vg_size", `Bytes;
1088   "vg_free", `Bytes;
1089   "vg_sysid", `String;
1090   "vg_extent_size", `Bytes;
1091   "vg_extent_count", `Int;
1092   "vg_free_count", `Int;
1093   "max_lv", `Int;
1094   "max_pv", `Int;
1095   "pv_count", `Int;
1096   "lv_count", `Int;
1097   "snap_count", `Int;
1098   "vg_seqno", `Int;
1099   "vg_tags", `String;
1100   "vg_mda_count", `Int;
1101   "vg_mda_free", `Bytes;
1102 (* Not in Fedora 10:
1103   "vg_mda_size", `Bytes;
1104 *)
1105 ]
1106 let lv_cols = [
1107   "lv_name", `String;
1108   "lv_uuid", `UUID;
1109   "lv_attr", `String (* XXX *);
1110   "lv_major", `Int;
1111   "lv_minor", `Int;
1112   "lv_kernel_major", `Int;
1113   "lv_kernel_minor", `Int;
1114   "lv_size", `Bytes;
1115   "seg_count", `Int;
1116   "origin", `String;
1117   "snap_percent", `OptPercent;
1118   "copy_percent", `OptPercent;
1119   "move_pv", `String;
1120   "lv_tags", `String;
1121   "mirror_log", `String;
1122   "modules", `String;
1123 ]
1124
1125 (* Column names and types from stat structures.
1126  * NB. Can't use things like 'st_atime' because glibc header files
1127  * define some of these as macros.  Ugh.
1128  *)
1129 let stat_cols = [
1130   "dev", `Int;
1131   "ino", `Int;
1132   "mode", `Int;
1133   "nlink", `Int;
1134   "uid", `Int;
1135   "gid", `Int;
1136   "rdev", `Int;
1137   "size", `Int;
1138   "blksize", `Int;
1139   "blocks", `Int;
1140   "atime", `Int;
1141   "mtime", `Int;
1142   "ctime", `Int;
1143 ]
1144 let statvfs_cols = [
1145   "bsize", `Int;
1146   "frsize", `Int;
1147   "blocks", `Int;
1148   "bfree", `Int;
1149   "bavail", `Int;
1150   "files", `Int;
1151   "ffree", `Int;
1152   "favail", `Int;
1153   "fsid", `Int;
1154   "flag", `Int;
1155   "namemax", `Int;
1156 ]
1157
1158 (* Useful functions.
1159  * Note we don't want to use any external OCaml libraries which
1160  * makes this a bit harder than it should be.
1161  *)
1162 let failwithf fs = ksprintf failwith fs
1163
1164 let replace_char s c1 c2 =
1165   let s2 = String.copy s in
1166   let r = ref false in
1167   for i = 0 to String.length s2 - 1 do
1168     if String.unsafe_get s2 i = c1 then (
1169       String.unsafe_set s2 i c2;
1170       r := true
1171     )
1172   done;
1173   if not !r then s else s2
1174
1175 let rec find s sub =
1176   let len = String.length s in
1177   let sublen = String.length sub in
1178   let rec loop i =
1179     if i <= len-sublen then (
1180       let rec loop2 j =
1181         if j < sublen then (
1182           if s.[i+j] = sub.[j] then loop2 (j+1)
1183           else -1
1184         ) else
1185           i (* found *)
1186       in
1187       let r = loop2 0 in
1188       if r = -1 then loop (i+1) else r
1189     ) else
1190       -1 (* not found *)
1191   in
1192   loop 0
1193
1194 let rec replace_str s s1 s2 =
1195   let len = String.length s in
1196   let sublen = String.length s1 in
1197   let i = find s s1 in
1198   if i = -1 then s
1199   else (
1200     let s' = String.sub s 0 i in
1201     let s'' = String.sub s (i+sublen) (len-i-sublen) in
1202     s' ^ s2 ^ replace_str s'' s1 s2
1203   )
1204
1205 let rec string_split sep str =
1206   let len = String.length str in
1207   let seplen = String.length sep in
1208   let i = find str sep in
1209   if i = -1 then [str]
1210   else (
1211     let s' = String.sub str 0 i in
1212     let s'' = String.sub str (i+seplen) (len-i-seplen) in
1213     s' :: string_split sep s''
1214   )
1215
1216 let rec find_map f = function
1217   | [] -> raise Not_found
1218   | x :: xs ->
1219       match f x with
1220       | Some y -> y
1221       | None -> find_map f xs
1222
1223 let iteri f xs =
1224   let rec loop i = function
1225     | [] -> ()
1226     | x :: xs -> f i x; loop (i+1) xs
1227   in
1228   loop 0 xs
1229
1230 let mapi f xs =
1231   let rec loop i = function
1232     | [] -> []
1233     | x :: xs -> let r = f i x in r :: loop (i+1) xs
1234   in
1235   loop 0 xs
1236
1237 let name_of_argt = function
1238   | String n | OptString n | StringList n | Bool n | Int n -> n
1239
1240 (* Check function names etc. for consistency. *)
1241 let check_functions () =
1242   let contains_uppercase str =
1243     let len = String.length str in
1244     let rec loop i =
1245       if i >= len then false
1246       else (
1247         let c = str.[i] in
1248         if c >= 'A' && c <= 'Z' then true
1249         else loop (i+1)
1250       )
1251     in
1252     loop 0
1253   in
1254
1255   (* Check function names. *)
1256   List.iter (
1257     fun (name, _, _, _, _, _, _) ->
1258       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
1259         failwithf "function name %s does not need 'guestfs' prefix" name;
1260       if contains_uppercase name then
1261         failwithf "function name %s should not contain uppercase chars" name;
1262       if String.contains name '-' then
1263         failwithf "function name %s should not contain '-', use '_' instead."
1264           name
1265   ) all_functions;
1266
1267   (* Check function parameter/return names. *)
1268   List.iter (
1269     fun (name, style, _, _, _, _, _) ->
1270       let check_arg_ret_name n =
1271         if contains_uppercase n then
1272           failwithf "%s param/ret %s should not contain uppercase chars"
1273             name n;
1274         if String.contains n '-' || String.contains n '_' then
1275           failwithf "%s param/ret %s should not contain '-' or '_'"
1276             name n;
1277         if n = "value" then
1278           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;
1279         if n = "argv" || n = "args" then
1280           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
1281       in
1282
1283       (match fst style with
1284        | RErr -> ()
1285        | RInt n | RBool n | RConstString n | RString n
1286        | RStringList n | RPVList n | RVGList n | RLVList n
1287        | RStat n | RStatVFS n ->
1288            check_arg_ret_name n
1289        | RIntBool (n,m) ->
1290            check_arg_ret_name n;
1291            check_arg_ret_name m
1292       );
1293       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
1294   ) all_functions;
1295
1296   (* Check short descriptions. *)
1297   List.iter (
1298     fun (name, _, _, _, _, shortdesc, _) ->
1299       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
1300         failwithf "short description of %s should begin with lowercase." name;
1301       let c = shortdesc.[String.length shortdesc-1] in
1302       if c = '\n' || c = '.' then
1303         failwithf "short description of %s should not end with . or \\n." name
1304   ) all_functions;
1305
1306   (* Check long dscriptions. *)
1307   List.iter (
1308     fun (name, _, _, _, _, _, longdesc) ->
1309       if longdesc.[String.length longdesc-1] = '\n' then
1310         failwithf "long description of %s should not end with \\n." name
1311   ) all_functions;
1312
1313   (* Check proc_nrs. *)
1314   List.iter (
1315     fun (name, _, proc_nr, _, _, _, _) ->
1316       if proc_nr <= 0 then
1317         failwithf "daemon function %s should have proc_nr > 0" name
1318   ) daemon_functions;
1319
1320   List.iter (
1321     fun (name, _, proc_nr, _, _, _, _) ->
1322       if proc_nr <> -1 then
1323         failwithf "non-daemon function %s should have proc_nr -1" name
1324   ) non_daemon_functions;
1325
1326   let proc_nrs =
1327     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
1328       daemon_functions in
1329   let proc_nrs =
1330     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
1331   let rec loop = function
1332     | [] -> ()
1333     | [_] -> ()
1334     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
1335         loop rest
1336     | (name1,nr1) :: (name2,nr2) :: _ ->
1337         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
1338           name1 name2 nr1 nr2
1339   in
1340   loop proc_nrs
1341
1342 (* 'pr' prints to the current output file. *)
1343 let chan = ref stdout
1344 let pr fs = ksprintf (output_string !chan) fs
1345
1346 (* Generate a header block in a number of standard styles. *)
1347 type comment_style = CStyle | HashStyle | OCamlStyle
1348 type license = GPLv2 | LGPLv2
1349
1350 let generate_header comment license =
1351   let c = match comment with
1352     | CStyle ->     pr "/* "; " *"
1353     | HashStyle ->  pr "# ";  "#"
1354     | OCamlStyle -> pr "(* "; " *" in
1355   pr "libguestfs generated file\n";
1356   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
1357   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
1358   pr "%s\n" c;
1359   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
1360   pr "%s\n" c;
1361   (match license with
1362    | GPLv2 ->
1363        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
1364        pr "%s it under the terms of the GNU General Public License as published by\n" c;
1365        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
1366        pr "%s (at your option) any later version.\n" c;
1367        pr "%s\n" c;
1368        pr "%s This program is distributed in the hope that it will be useful,\n" c;
1369        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1370        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
1371        pr "%s GNU General Public License for more details.\n" c;
1372        pr "%s\n" c;
1373        pr "%s You should have received a copy of the GNU General Public License along\n" c;
1374        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
1375        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
1376
1377    | LGPLv2 ->
1378        pr "%s This library is free software; you can redistribute it and/or\n" c;
1379        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
1380        pr "%s License as published by the Free Software Foundation; either\n" c;
1381        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
1382        pr "%s\n" c;
1383        pr "%s This library is distributed in the hope that it will be useful,\n" c;
1384        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
1385        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
1386        pr "%s Lesser General Public License for more details.\n" c;
1387        pr "%s\n" c;
1388        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
1389        pr "%s License along with this library; if not, write to the Free Software\n" c;
1390        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
1391   );
1392   (match comment with
1393    | CStyle -> pr " */\n"
1394    | HashStyle -> ()
1395    | OCamlStyle -> pr " *)\n"
1396   );
1397   pr "\n"
1398
1399 (* Start of main code generation functions below this line. *)
1400
1401 (* Generate the pod documentation for the C API. *)
1402 let rec generate_actions_pod () =
1403   List.iter (
1404     fun (shortname, style, _, flags, _, _, longdesc) ->
1405       let name = "guestfs_" ^ shortname in
1406       pr "=head2 %s\n\n" name;
1407       pr " ";
1408       generate_prototype ~extern:false ~handle:"handle" name style;
1409       pr "\n\n";
1410       pr "%s\n\n" longdesc;
1411       (match fst style with
1412        | RErr ->
1413            pr "This function returns 0 on success or -1 on error.\n\n"
1414        | RInt _ ->
1415            pr "On error this function returns -1.\n\n"
1416        | RBool _ ->
1417            pr "This function returns a C truth value on success or -1 on error.\n\n"
1418        | RConstString _ ->
1419            pr "This function returns a string, or NULL on error.
1420 The string is owned by the guest handle and must I<not> be freed.\n\n"
1421        | RString _ ->
1422            pr "This function returns a string, or NULL on error.
1423 I<The caller must free the returned string after use>.\n\n"
1424        | RStringList _ ->
1425            pr "This function returns a NULL-terminated array of strings
1426 (like L<environ(3)>), or NULL if there was an error.
1427 I<The caller must free the strings and the array after use>.\n\n"
1428        | RIntBool _ ->
1429            pr "This function returns a C<struct guestfs_int_bool *>,
1430 or NULL if there was an error.
1431 I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
1432        | RPVList _ ->
1433            pr "This function returns a C<struct guestfs_lvm_pv_list *>
1434 (see E<lt>guestfs-structs.hE<gt>),
1435 or NULL if there was an error.
1436 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
1437        | RVGList _ ->
1438            pr "This function returns a C<struct guestfs_lvm_vg_list *>
1439 (see E<lt>guestfs-structs.hE<gt>),
1440 or NULL if there was an error.
1441 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
1442        | RLVList _ ->
1443            pr "This function returns a C<struct guestfs_lvm_lv_list *>
1444 (see E<lt>guestfs-structs.hE<gt>),
1445 or NULL if there was an error.
1446 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
1447        | RStat _ ->
1448            pr "This function returns a C<struct guestfs_stat *>
1449 (see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
1450 or NULL if there was an error.
1451 I<The caller must call C<free> after use>.\n\n"
1452        | RStatVFS _ ->
1453            pr "This function returns a C<struct guestfs_statvfs *>
1454 (see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
1455 or NULL if there was an error.
1456 I<The caller must call C<free> after use>.\n\n"
1457       );
1458       if List.mem ProtocolLimitWarning flags then
1459         pr "%s\n\n" protocol_limit_warning;
1460       if List.mem DangerWillRobinson flags then
1461         pr "%s\n\n" danger_will_robinson;
1462   ) all_functions_sorted
1463
1464 and generate_structs_pod () =
1465   (* LVM structs documentation. *)
1466   List.iter (
1467     fun (typ, cols) ->
1468       pr "=head2 guestfs_lvm_%s\n" typ;
1469       pr "\n";
1470       pr " struct guestfs_lvm_%s {\n" typ;
1471       List.iter (
1472         function
1473         | name, `String -> pr "  char *%s;\n" name
1474         | name, `UUID ->
1475             pr "  /* The next field is NOT nul-terminated, be careful when printing it: */\n";
1476             pr "  char %s[32];\n" name
1477         | name, `Bytes -> pr "  uint64_t %s;\n" name
1478         | name, `Int -> pr "  int64_t %s;\n" name
1479         | name, `OptPercent ->
1480             pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
1481             pr "  float %s;\n" name
1482       ) cols;
1483       pr " \n";
1484       pr " struct guestfs_lvm_%s_list {\n" typ;
1485       pr "   uint32_t len; /* Number of elements in list. */\n";
1486       pr "   struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
1487       pr " };\n";
1488       pr " \n";
1489       pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
1490         typ typ;
1491       pr "\n"
1492   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
1493
1494 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
1495  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
1496  *
1497  * We have to use an underscore instead of a dash because otherwise
1498  * rpcgen generates incorrect code.
1499  *
1500  * This header is NOT exported to clients, but see also generate_structs_h.
1501  *)
1502 and generate_xdr () =
1503   generate_header CStyle LGPLv2;
1504
1505   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
1506   pr "typedef string str<>;\n";
1507   pr "\n";
1508
1509   (* LVM internal structures. *)
1510   List.iter (
1511     function
1512     | typ, cols ->
1513         pr "struct guestfs_lvm_int_%s {\n" typ;
1514         List.iter (function
1515                    | name, `String -> pr "  string %s<>;\n" name
1516                    | name, `UUID -> pr "  opaque %s[32];\n" name
1517                    | name, `Bytes -> pr "  hyper %s;\n" name
1518                    | name, `Int -> pr "  hyper %s;\n" name
1519                    | name, `OptPercent -> pr "  float %s;\n" name
1520                   ) cols;
1521         pr "};\n";
1522         pr "\n";
1523         pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
1524         pr "\n";
1525   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1526
1527   (* Stat internal structures. *)
1528   List.iter (
1529     function
1530     | typ, cols ->
1531         pr "struct guestfs_int_%s {\n" typ;
1532         List.iter (function
1533                    | name, `Int -> pr "  hyper %s;\n" name
1534                   ) cols;
1535         pr "};\n";
1536         pr "\n";
1537   ) ["stat", stat_cols; "statvfs", statvfs_cols];
1538
1539   List.iter (
1540     fun (shortname, style, _, _, _, _, _) ->
1541       let name = "guestfs_" ^ shortname in
1542
1543       (match snd style with
1544        | [] -> ()
1545        | args ->
1546            pr "struct %s_args {\n" name;
1547            List.iter (
1548              function
1549              | String n -> pr "  string %s<>;\n" n
1550              | OptString n -> pr "  str *%s;\n" n
1551              | StringList n -> pr "  str %s<>;\n" n
1552              | Bool n -> pr "  bool %s;\n" n
1553              | Int n -> pr "  int %s;\n" n
1554            ) args;
1555            pr "};\n\n"
1556       );
1557       (match fst style with
1558        | RErr -> ()
1559        | RInt n ->
1560            pr "struct %s_ret {\n" name;
1561            pr "  int %s;\n" n;
1562            pr "};\n\n"
1563        | RBool n ->
1564            pr "struct %s_ret {\n" name;
1565            pr "  bool %s;\n" n;
1566            pr "};\n\n"
1567        | RConstString _ ->
1568            failwithf "RConstString cannot be returned from a daemon function"
1569        | RString n ->
1570            pr "struct %s_ret {\n" name;
1571            pr "  string %s<>;\n" n;
1572            pr "};\n\n"
1573        | RStringList n ->
1574            pr "struct %s_ret {\n" name;
1575            pr "  str %s<>;\n" n;
1576            pr "};\n\n"
1577        | RIntBool (n,m) ->
1578            pr "struct %s_ret {\n" name;
1579            pr "  int %s;\n" n;
1580            pr "  bool %s;\n" m;
1581            pr "};\n\n"
1582        | RPVList n ->
1583            pr "struct %s_ret {\n" name;
1584            pr "  guestfs_lvm_int_pv_list %s;\n" n;
1585            pr "};\n\n"
1586        | RVGList n ->
1587            pr "struct %s_ret {\n" name;
1588            pr "  guestfs_lvm_int_vg_list %s;\n" n;
1589            pr "};\n\n"
1590        | RLVList n ->
1591            pr "struct %s_ret {\n" name;
1592            pr "  guestfs_lvm_int_lv_list %s;\n" n;
1593            pr "};\n\n"
1594        | RStat n ->
1595            pr "struct %s_ret {\n" name;
1596            pr "  guestfs_int_stat %s;\n" n;
1597            pr "};\n\n";
1598        | RStatVFS n ->
1599            pr "struct %s_ret {\n" name;
1600            pr "  guestfs_int_statvfs %s;\n" n;
1601            pr "};\n\n";
1602       );
1603   ) daemon_functions;
1604
1605   (* Table of procedure numbers. *)
1606   pr "enum guestfs_procedure {\n";
1607   List.iter (
1608     fun (shortname, _, proc_nr, _, _, _, _) ->
1609       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
1610   ) daemon_functions;
1611   pr "  GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
1612   pr "};\n";
1613   pr "\n";
1614
1615   (* Having to choose a maximum message size is annoying for several
1616    * reasons (it limits what we can do in the API), but it (a) makes
1617    * the protocol a lot simpler, and (b) provides a bound on the size
1618    * of the daemon which operates in limited memory space.  For large
1619    * file transfers you should use FTP.
1620    *)
1621   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
1622   pr "\n";
1623
1624   (* Message header, etc. *)
1625   pr "\
1626 const GUESTFS_PROGRAM = 0x2000F5F5;
1627 const GUESTFS_PROTOCOL_VERSION = 1;
1628
1629 enum guestfs_message_direction {
1630   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
1631   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
1632 };
1633
1634 enum guestfs_message_status {
1635   GUESTFS_STATUS_OK = 0,
1636   GUESTFS_STATUS_ERROR = 1
1637 };
1638
1639 const GUESTFS_ERROR_LEN = 256;
1640
1641 struct guestfs_message_error {
1642   string error<GUESTFS_ERROR_LEN>;   /* error message */
1643 };
1644
1645 struct guestfs_message_header {
1646   unsigned prog;                     /* GUESTFS_PROGRAM */
1647   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
1648   guestfs_procedure proc;            /* GUESTFS_PROC_x */
1649   guestfs_message_direction direction;
1650   unsigned serial;                   /* message serial number */
1651   guestfs_message_status status;
1652 };
1653 "
1654
1655 (* Generate the guestfs-structs.h file. *)
1656 and generate_structs_h () =
1657   generate_header CStyle LGPLv2;
1658
1659   (* This is a public exported header file containing various
1660    * structures.  The structures are carefully written to have
1661    * exactly the same in-memory format as the XDR structures that
1662    * we use on the wire to the daemon.  The reason for creating
1663    * copies of these structures here is just so we don't have to
1664    * export the whole of guestfs_protocol.h (which includes much
1665    * unrelated and XDR-dependent stuff that we don't want to be
1666    * public, or required by clients).
1667    *
1668    * To reiterate, we will pass these structures to and from the
1669    * client with a simple assignment or memcpy, so the format
1670    * must be identical to what rpcgen / the RFC defines.
1671    *)
1672
1673   (* guestfs_int_bool structure. *)
1674   pr "struct guestfs_int_bool {\n";
1675   pr "  int32_t i;\n";
1676   pr "  int32_t b;\n";
1677   pr "};\n";
1678   pr "\n";
1679
1680   (* LVM public structures. *)
1681   List.iter (
1682     function
1683     | typ, cols ->
1684         pr "struct guestfs_lvm_%s {\n" typ;
1685         List.iter (
1686           function
1687           | name, `String -> pr "  char *%s;\n" name
1688           | name, `UUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
1689           | name, `Bytes -> pr "  uint64_t %s;\n" name
1690           | name, `Int -> pr "  int64_t %s;\n" name
1691           | name, `OptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
1692         ) cols;
1693         pr "};\n";
1694         pr "\n";
1695         pr "struct guestfs_lvm_%s_list {\n" typ;
1696         pr "  uint32_t len;\n";
1697         pr "  struct guestfs_lvm_%s *val;\n" typ;
1698         pr "};\n";
1699         pr "\n"
1700   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
1701
1702   (* Stat structures. *)
1703   List.iter (
1704     function
1705     | typ, cols ->
1706         pr "struct guestfs_%s {\n" typ;
1707         List.iter (
1708           function
1709           | name, `Int -> pr "  int64_t %s;\n" name
1710         ) cols;
1711         pr "};\n";
1712         pr "\n"
1713   ) ["stat", stat_cols; "statvfs", statvfs_cols]
1714
1715 (* Generate the guestfs-actions.h file. *)
1716 and generate_actions_h () =
1717   generate_header CStyle LGPLv2;
1718   List.iter (
1719     fun (shortname, style, _, _, _, _, _) ->
1720       let name = "guestfs_" ^ shortname in
1721       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
1722         name style
1723   ) all_functions
1724
1725 (* Generate the client-side dispatch stubs. *)
1726 and generate_client_actions () =
1727   generate_header CStyle LGPLv2;
1728
1729   (* Client-side stubs for each function. *)
1730   List.iter (
1731     fun (shortname, style, _, _, _, _, _) ->
1732       let name = "guestfs_" ^ shortname in
1733
1734       (* Generate the return value struct. *)
1735       pr "struct %s_rv {\n" shortname;
1736       pr "  int cb_done;  /* flag to indicate callback was called */\n";
1737       pr "  struct guestfs_message_header hdr;\n";
1738       pr "  struct guestfs_message_error err;\n";
1739       (match fst style with
1740        | RErr -> ()
1741        | RConstString _ ->
1742            failwithf "RConstString cannot be returned from a daemon function"
1743        | RInt _
1744        | RBool _ | RString _ | RStringList _
1745        | RIntBool _
1746        | RPVList _ | RVGList _ | RLVList _
1747        | RStat _ | RStatVFS _ ->
1748            pr "  struct %s_ret ret;\n" name
1749       );
1750       pr "};\n\n";
1751
1752       (* Generate the callback function. *)
1753       pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
1754       pr "{\n";
1755       pr "  struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
1756       pr "\n";
1757       pr "  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
1758       pr "    error (g, \"%s: failed to parse reply header\");\n" name;
1759       pr "    return;\n";
1760       pr "  }\n";
1761       pr "  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
1762       pr "    if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
1763       pr "      error (g, \"%s: failed to parse reply error\");\n" name;
1764       pr "      return;\n";
1765       pr "    }\n";
1766       pr "    goto done;\n";
1767       pr "  }\n";
1768
1769       (match fst style with
1770        | RErr -> ()
1771        | RConstString _ ->
1772            failwithf "RConstString cannot be returned from a daemon function"
1773        | RInt _
1774        | RBool _ | RString _ | RStringList _
1775        | RIntBool _
1776        | RPVList _ | RVGList _ | RLVList _
1777        | RStat _ | RStatVFS _ ->
1778             pr "  if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
1779             pr "    error (g, \"%s: failed to parse reply\");\n" name;
1780             pr "    return;\n";
1781             pr "  }\n";
1782       );
1783
1784       pr " done:\n";
1785       pr "  rv->cb_done = 1;\n";
1786       pr "  main_loop.main_loop_quit (g);\n";
1787       pr "}\n\n";
1788
1789       (* Generate the action stub. *)
1790       generate_prototype ~extern:false ~semicolon:false ~newline:true
1791         ~handle:"g" name style;
1792
1793       let error_code =
1794         match fst style with
1795         | RErr | RInt _ | RBool _ -> "-1"
1796         | RConstString _ ->
1797             failwithf "RConstString cannot be returned from a daemon function"
1798         | RString _ | RStringList _ | RIntBool _
1799         | RPVList _ | RVGList _ | RLVList _
1800         | RStat _ | RStatVFS _ ->
1801             "NULL" in
1802
1803       pr "{\n";
1804
1805       (match snd style with
1806        | [] -> ()
1807        | _ -> pr "  struct %s_args args;\n" name
1808       );
1809
1810       pr "  struct %s_rv rv;\n" shortname;
1811       pr "  int serial;\n";
1812       pr "\n";
1813       pr "  if (g->state != READY) {\n";
1814       pr "    error (g, \"%s called from the wrong state, %%d != READY\",\n"
1815         name;
1816       pr "      g->state);\n";
1817       pr "    return %s;\n" error_code;
1818       pr "  }\n";
1819       pr "\n";
1820       pr "  memset (&rv, 0, sizeof rv);\n";
1821       pr "\n";
1822
1823       (match snd style with
1824        | [] ->
1825            pr "  serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
1826              (String.uppercase shortname)
1827        | args ->
1828            List.iter (
1829              function
1830              | String n ->
1831                  pr "  args.%s = (char *) %s;\n" n n
1832              | OptString n ->
1833                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
1834              | StringList n ->
1835                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
1836                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
1837              | Bool n ->
1838                  pr "  args.%s = %s;\n" n n
1839              | Int n ->
1840                  pr "  args.%s = %s;\n" n n
1841            ) args;
1842            pr "  serial = dispatch (g, GUESTFS_PROC_%s,\n"
1843              (String.uppercase shortname);
1844            pr "                     (xdrproc_t) xdr_%s_args, (char *) &args);\n"
1845              name;
1846       );
1847       pr "  if (serial == -1)\n";
1848       pr "    return %s;\n" error_code;
1849       pr "\n";
1850
1851       pr "  rv.cb_done = 0;\n";
1852       pr "  g->reply_cb_internal = %s_cb;\n" shortname;
1853       pr "  g->reply_cb_internal_data = &rv;\n";
1854       pr "  main_loop.main_loop_run (g);\n";
1855       pr "  g->reply_cb_internal = NULL;\n";
1856       pr "  g->reply_cb_internal_data = NULL;\n";
1857       pr "  if (!rv.cb_done) {\n";
1858       pr "    error (g, \"%s failed, see earlier error messages\");\n" name;
1859       pr "    return %s;\n" error_code;
1860       pr "  }\n";
1861       pr "\n";
1862
1863       pr "  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
1864         (String.uppercase shortname);
1865       pr "    return %s;\n" error_code;
1866       pr "\n";
1867
1868       pr "  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
1869       pr "    error (g, \"%%s\", rv.err.error);\n";
1870       pr "    return %s;\n" error_code;
1871       pr "  }\n";
1872       pr "\n";
1873
1874       (match fst style with
1875        | RErr -> pr "  return 0;\n"
1876        | RInt n
1877        | RBool n -> pr "  return rv.ret.%s;\n" n
1878        | RConstString _ ->
1879            failwithf "RConstString cannot be returned from a daemon function"
1880        | RString n ->
1881            pr "  return rv.ret.%s; /* caller will free */\n" n
1882        | RStringList n ->
1883            pr "  /* caller will free this, but we need to add a NULL entry */\n";
1884            pr "  rv.ret.%s.%s_val =" n n;
1885            pr "    safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
1886            pr "                  sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
1887              n n;
1888            pr "  rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
1889            pr "  return rv.ret.%s.%s_val;\n" n n
1890        | RIntBool _ ->
1891            pr "  /* caller with free this */\n";
1892            pr "  return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
1893        | RPVList n ->
1894            pr "  /* caller will free this */\n";
1895            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1896        | RVGList n ->
1897            pr "  /* caller will free this */\n";
1898            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1899        | RLVList n ->
1900            pr "  /* caller will free this */\n";
1901            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1902        | RStat n ->
1903            pr "  /* caller will free this */\n";
1904            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1905        | RStatVFS n ->
1906            pr "  /* caller will free this */\n";
1907            pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
1908       );
1909
1910       pr "}\n\n"
1911   ) daemon_functions
1912
1913 (* Generate daemon/actions.h. *)
1914 and generate_daemon_actions_h () =
1915   generate_header CStyle GPLv2;
1916
1917   pr "#include \"../src/guestfs_protocol.h\"\n";
1918   pr "\n";
1919
1920   List.iter (
1921     fun (name, style, _, _, _, _, _) ->
1922         generate_prototype
1923           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
1924           name style;
1925   ) daemon_functions
1926
1927 (* Generate the server-side stubs. *)
1928 and generate_daemon_actions () =
1929   generate_header CStyle GPLv2;
1930
1931   pr "#define _GNU_SOURCE // for strchrnul\n";
1932   pr "\n";
1933   pr "#include <stdio.h>\n";
1934   pr "#include <stdlib.h>\n";
1935   pr "#include <string.h>\n";
1936   pr "#include <inttypes.h>\n";
1937   pr "#include <ctype.h>\n";
1938   pr "#include <rpc/types.h>\n";
1939   pr "#include <rpc/xdr.h>\n";
1940   pr "\n";
1941   pr "#include \"daemon.h\"\n";
1942   pr "#include \"../src/guestfs_protocol.h\"\n";
1943   pr "#include \"actions.h\"\n";
1944   pr "\n";
1945
1946   List.iter (
1947     fun (name, style, _, _, _, _, _) ->
1948       (* Generate server-side stubs. *)
1949       pr "static void %s_stub (XDR *xdr_in)\n" name;
1950       pr "{\n";
1951       let error_code =
1952         match fst style with
1953         | RErr | RInt _ -> pr "  int r;\n"; "-1"
1954         | RBool _ -> pr "  int r;\n"; "-1"
1955         | RConstString _ ->
1956             failwithf "RConstString cannot be returned from a daemon function"
1957         | RString _ -> pr "  char *r;\n"; "NULL"
1958         | RStringList _ -> pr "  char **r;\n"; "NULL"
1959         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
1960         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
1961         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
1962         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL"
1963         | RStat _ -> pr "  guestfs_int_stat *r;\n"; "NULL"
1964         | RStatVFS _ -> pr "  guestfs_int_statvfs *r;\n"; "NULL" in
1965
1966       (match snd style with
1967        | [] -> ()
1968        | args ->
1969            pr "  struct guestfs_%s_args args;\n" name;
1970            List.iter (
1971              function
1972              | String n
1973              | OptString n -> pr "  const char *%s;\n" n
1974              | StringList n -> pr "  char **%s;\n" n
1975              | Bool n -> pr "  int %s;\n" n
1976              | Int n -> pr "  int %s;\n" n
1977            ) args
1978       );
1979       pr "\n";
1980
1981       (match snd style with
1982        | [] -> ()
1983        | args ->
1984            pr "  memset (&args, 0, sizeof args);\n";
1985            pr "\n";
1986            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
1987            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
1988            pr "    return;\n";
1989            pr "  }\n";
1990            List.iter (
1991              function
1992              | String n -> pr "  %s = args.%s;\n" n n
1993              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
1994              | StringList n ->
1995                  pr "  args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
1996                  pr "  args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
1997                  pr "  %s = args.%s.%s_val;\n" n n n
1998              | Bool n -> pr "  %s = args.%s;\n" n n
1999              | Int n -> pr "  %s = args.%s;\n" n n
2000            ) args;
2001            pr "\n"
2002       );
2003
2004       pr "  r = do_%s " name;
2005       generate_call_args style;
2006       pr ";\n";
2007
2008       pr "  if (r == %s)\n" error_code;
2009       pr "    /* do_%s has already called reply_with_error */\n" name;
2010       pr "    goto done;\n";
2011       pr "\n";
2012
2013       (match fst style with
2014        | RErr -> pr "  reply (NULL, NULL);\n"
2015        | RInt n ->
2016            pr "  struct guestfs_%s_ret ret;\n" name;
2017            pr "  ret.%s = r;\n" n;
2018            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
2019        | RBool n ->
2020            pr "  struct guestfs_%s_ret ret;\n" name;
2021            pr "  ret.%s = r;\n" n;
2022            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
2023        | RConstString _ ->
2024            failwithf "RConstString cannot be returned from a daemon function"
2025        | RString n ->
2026            pr "  struct guestfs_%s_ret ret;\n" name;
2027            pr "  ret.%s = r;\n" n;
2028            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2029            pr "  free (r);\n"
2030        | RStringList n ->
2031            pr "  struct guestfs_%s_ret ret;\n" name;
2032            pr "  ret.%s.%s_len = count_strings (r);\n" n n;
2033            pr "  ret.%s.%s_val = r;\n" n n;
2034            pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2035            pr "  free_strings (r);\n"
2036        | RIntBool _ ->
2037            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
2038            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2039        | RPVList n | RVGList n | RLVList n | RStat n | RStatVFS n ->
2040            pr "  struct guestfs_%s_ret ret;\n" name;
2041            pr "  ret.%s = *r;\n" n;
2042            pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
2043            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
2044       );
2045
2046       (* Free the args. *)
2047       (match snd style with
2048        | [] ->
2049            pr "done: ;\n";
2050        | _ ->
2051            pr "done:\n";
2052            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2053              name
2054       );
2055
2056       pr "}\n\n";
2057   ) daemon_functions;
2058
2059   (* Dispatch function. *)
2060   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2061   pr "{\n";
2062   pr "  switch (proc_nr) {\n";
2063
2064   List.iter (
2065     fun (name, style, _, _, _, _, _) ->
2066         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
2067         pr "      %s_stub (xdr_in);\n" name;
2068         pr "      break;\n"
2069   ) daemon_functions;
2070
2071   pr "    default:\n";
2072   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2073   pr "  }\n";
2074   pr "}\n";
2075   pr "\n";
2076
2077   (* LVM columns and tokenization functions. *)
2078   (* XXX This generates crap code.  We should rethink how we
2079    * do this parsing.
2080    *)
2081   List.iter (
2082     function
2083     | typ, cols ->
2084         pr "static const char *lvm_%s_cols = \"%s\";\n"
2085           typ (String.concat "," (List.map fst cols));
2086         pr "\n";
2087
2088         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2089         pr "{\n";
2090         pr "  char *tok, *p, *next;\n";
2091         pr "  int i, j;\n";
2092         pr "\n";
2093         (*
2094         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2095         pr "\n";
2096         *)
2097         pr "  if (!str) {\n";
2098         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2099         pr "    return -1;\n";
2100         pr "  }\n";
2101         pr "  if (!*str || isspace (*str)) {\n";
2102         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2103         pr "    return -1;\n";
2104         pr "  }\n";
2105         pr "  tok = str;\n";
2106         List.iter (
2107           fun (name, coltype) ->
2108             pr "  if (!tok) {\n";
2109             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2110             pr "    return -1;\n";
2111             pr "  }\n";
2112             pr "  p = strchrnul (tok, ',');\n";
2113             pr "  if (*p) next = p+1; else next = NULL;\n";
2114             pr "  *p = '\\0';\n";
2115             (match coltype with
2116              | `String ->
2117                  pr "  r->%s = strdup (tok);\n" name;
2118                  pr "  if (r->%s == NULL) {\n" name;
2119                  pr "    perror (\"strdup\");\n";
2120                  pr "    return -1;\n";
2121                  pr "  }\n"
2122              | `UUID ->
2123                  pr "  for (i = j = 0; i < 32; ++j) {\n";
2124                  pr "    if (tok[j] == '\\0') {\n";
2125                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2126                  pr "      return -1;\n";
2127                  pr "    } else if (tok[j] != '-')\n";
2128                  pr "      r->%s[i++] = tok[j];\n" name;
2129                  pr "  }\n";
2130              | `Bytes ->
2131                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2132                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2133                  pr "    return -1;\n";
2134                  pr "  }\n";
2135              | `Int ->
2136                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2137                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2138                  pr "    return -1;\n";
2139                  pr "  }\n";
2140              | `OptPercent ->
2141                  pr "  if (tok[0] == '\\0')\n";
2142                  pr "    r->%s = -1;\n" name;
2143                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2144                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2145                  pr "    return -1;\n";
2146                  pr "  }\n";
2147             );
2148             pr "  tok = next;\n";
2149         ) cols;
2150
2151         pr "  if (tok != NULL) {\n";
2152         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2153         pr "    return -1;\n";
2154         pr "  }\n";
2155         pr "  return 0;\n";
2156         pr "}\n";
2157         pr "\n";
2158
2159         pr "guestfs_lvm_int_%s_list *\n" typ;
2160         pr "parse_command_line_%ss (void)\n" typ;
2161         pr "{\n";
2162         pr "  char *out, *err;\n";
2163         pr "  char *p, *pend;\n";
2164         pr "  int r, i;\n";
2165         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
2166         pr "  void *newp;\n";
2167         pr "\n";
2168         pr "  ret = malloc (sizeof *ret);\n";
2169         pr "  if (!ret) {\n";
2170         pr "    reply_with_perror (\"malloc\");\n";
2171         pr "    return NULL;\n";
2172         pr "  }\n";
2173         pr "\n";
2174         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2175         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2176         pr "\n";
2177         pr "  r = command (&out, &err,\n";
2178         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
2179         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2180         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2181         pr "  if (r == -1) {\n";
2182         pr "    reply_with_error (\"%%s\", err);\n";
2183         pr "    free (out);\n";
2184         pr "    free (err);\n";
2185         pr "    return NULL;\n";
2186         pr "  }\n";
2187         pr "\n";
2188         pr "  free (err);\n";
2189         pr "\n";
2190         pr "  /* Tokenize each line of the output. */\n";
2191         pr "  p = out;\n";
2192         pr "  i = 0;\n";
2193         pr "  while (p) {\n";
2194         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
2195         pr "    if (pend) {\n";
2196         pr "      *pend = '\\0';\n";
2197         pr "      pend++;\n";
2198         pr "    }\n";
2199         pr "\n";
2200         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
2201         pr "      p++;\n";
2202         pr "\n";
2203         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
2204         pr "      p = pend;\n";
2205         pr "      continue;\n";
2206         pr "    }\n";
2207         pr "\n";
2208         pr "    /* Allocate some space to store this next entry. */\n";
2209         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2210         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2211         pr "    if (newp == NULL) {\n";
2212         pr "      reply_with_perror (\"realloc\");\n";
2213         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2214         pr "      free (ret);\n";
2215         pr "      free (out);\n";
2216         pr "      return NULL;\n";
2217         pr "    }\n";
2218         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2219         pr "\n";
2220         pr "    /* Tokenize the next entry. */\n";
2221         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2222         pr "    if (r == -1) {\n";
2223         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2224         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2225         pr "      free (ret);\n";
2226         pr "      free (out);\n";
2227         pr "      return NULL;\n";
2228         pr "    }\n";
2229         pr "\n";
2230         pr "    ++i;\n";
2231         pr "    p = pend;\n";
2232         pr "  }\n";
2233         pr "\n";
2234         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2235         pr "\n";
2236         pr "  free (out);\n";
2237         pr "  return ret;\n";
2238         pr "}\n"
2239
2240   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2241
2242 (* Generate the tests. *)
2243 and generate_tests () =
2244   generate_header CStyle GPLv2;
2245
2246   pr "\
2247 #include <stdio.h>
2248 #include <stdlib.h>
2249 #include <string.h>
2250 #include <unistd.h>
2251 #include <sys/types.h>
2252 #include <fcntl.h>
2253
2254 #include \"guestfs.h\"
2255
2256 static guestfs_h *g;
2257 static int suppress_error = 0;
2258
2259 static void print_error (guestfs_h *g, void *data, const char *msg)
2260 {
2261   if (!suppress_error)
2262     fprintf (stderr, \"%%s\\n\", msg);
2263 }
2264
2265 static void print_strings (char * const * const argv)
2266 {
2267   int argc;
2268
2269   for (argc = 0; argv[argc] != NULL; ++argc)
2270     printf (\"\\t%%s\\n\", argv[argc]);
2271 }
2272
2273 ";
2274
2275   let test_names =
2276     List.map (
2277       fun (name, _, _, _, tests, _, _) ->
2278         mapi (generate_one_test name) tests
2279     ) all_functions in
2280   let test_names = List.concat test_names in
2281   let nr_tests = List.length test_names in
2282
2283   pr "\
2284 int main (int argc, char *argv[])
2285 {
2286   char c = 0;
2287   int failed = 0;
2288   const char *srcdir;
2289   int fd;
2290   char buf[256];
2291   int nr_tests;
2292
2293   g = guestfs_create ();
2294   if (g == NULL) {
2295     printf (\"guestfs_create FAILED\\n\");
2296     exit (1);
2297   }
2298
2299   guestfs_set_error_handler (g, print_error, NULL);
2300
2301   srcdir = getenv (\"srcdir\");
2302   if (!srcdir) srcdir = \".\";
2303   guestfs_set_path (g, srcdir);
2304
2305   snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
2306   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2307   if (fd == -1) {
2308     perror (buf);
2309     exit (1);
2310   }
2311   if (lseek (fd, %d, SEEK_SET) == -1) {
2312     perror (\"lseek\");
2313     close (fd);
2314     unlink (buf);
2315     exit (1);
2316   }
2317   if (write (fd, &c, 1) == -1) {
2318     perror (\"write\");
2319     close (fd);
2320     unlink (buf);
2321     exit (1);
2322   }
2323   if (close (fd) == -1) {
2324     perror (buf);
2325     unlink (buf);
2326     exit (1);
2327   }
2328   if (guestfs_add_drive (g, buf) == -1) {
2329     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2330     exit (1);
2331   }
2332
2333   snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
2334   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2335   if (fd == -1) {
2336     perror (buf);
2337     exit (1);
2338   }
2339   if (lseek (fd, %d, SEEK_SET) == -1) {
2340     perror (\"lseek\");
2341     close (fd);
2342     unlink (buf);
2343     exit (1);
2344   }
2345   if (write (fd, &c, 1) == -1) {
2346     perror (\"write\");
2347     close (fd);
2348     unlink (buf);
2349     exit (1);
2350   }
2351   if (close (fd) == -1) {
2352     perror (buf);
2353     unlink (buf);
2354     exit (1);
2355   }
2356   if (guestfs_add_drive (g, buf) == -1) {
2357     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2358     exit (1);
2359   }
2360
2361   snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
2362   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2363   if (fd == -1) {
2364     perror (buf);
2365     exit (1);
2366   }
2367   if (lseek (fd, %d, SEEK_SET) == -1) {
2368     perror (\"lseek\");
2369     close (fd);
2370     unlink (buf);
2371     exit (1);
2372   }
2373   if (write (fd, &c, 1) == -1) {
2374     perror (\"write\");
2375     close (fd);
2376     unlink (buf);
2377     exit (1);
2378   }
2379   if (close (fd) == -1) {
2380     perror (buf);
2381     unlink (buf);
2382     exit (1);
2383   }
2384   if (guestfs_add_drive (g, buf) == -1) {
2385     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2386     exit (1);
2387   }
2388
2389   if (guestfs_launch (g) == -1) {
2390     printf (\"guestfs_launch FAILED\\n\");
2391     exit (1);
2392   }
2393   if (guestfs_wait_ready (g) == -1) {
2394     printf (\"guestfs_wait_ready FAILED\\n\");
2395     exit (1);
2396   }
2397
2398   nr_tests = %d;
2399 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
2400
2401   iteri (
2402     fun i test_name ->
2403       pr "  printf (\"%3d/%%3d %s\\n\", nr_tests);\n" (i+1) test_name;
2404       pr "  if (%s () == -1) {\n" test_name;
2405       pr "    printf (\"%s FAILED\\n\");\n" test_name;
2406       pr "    failed++;\n";
2407       pr "  }\n";
2408   ) test_names;
2409   pr "\n";
2410
2411   pr "  guestfs_close (g);\n";
2412   pr "  snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
2413   pr "  unlink (buf);\n";
2414   pr "  snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
2415   pr "  unlink (buf);\n";
2416   pr "  snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
2417   pr "  unlink (buf);\n";
2418   pr "\n";
2419
2420   pr "  if (failed > 0) {\n";
2421   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
2422   pr "    exit (1);\n";
2423   pr "  }\n";
2424   pr "\n";
2425
2426   pr "  exit (0);\n";
2427   pr "}\n"
2428
2429 and generate_one_test name i (init, test) =
2430   let test_name = sprintf "test_%s_%d" name i in
2431
2432   pr "static int %s (void)\n" test_name;
2433   pr "{\n";
2434
2435   (match init with
2436    | InitNone -> ()
2437    | InitEmpty ->
2438        pr "  /* InitEmpty for %s (%d) */\n" name i;
2439        List.iter (generate_test_command_call test_name)
2440          [["umount_all"];
2441           ["lvm_remove_all"]]
2442    | InitBasicFS ->
2443        pr "  /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
2444        List.iter (generate_test_command_call test_name)
2445          [["umount_all"];
2446           ["lvm_remove_all"];
2447           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2448           ["mkfs"; "ext2"; "/dev/sda1"];
2449           ["mount"; "/dev/sda1"; "/"]]
2450    | InitBasicFSonLVM ->
2451        pr "  /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
2452          name i;
2453        List.iter (generate_test_command_call test_name)
2454          [["umount_all"];
2455           ["lvm_remove_all"];
2456           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2457           ["pvcreate"; "/dev/sda1"];
2458           ["vgcreate"; "VG"; "/dev/sda1"];
2459           ["lvcreate"; "LV"; "VG"; "8"];
2460           ["mkfs"; "ext2"; "/dev/VG/LV"];
2461           ["mount"; "/dev/VG/LV"; "/"]]
2462   );
2463
2464   let get_seq_last = function
2465     | [] ->
2466         failwithf "%s: you cannot use [] (empty list) when expecting a command"
2467           test_name
2468     | seq ->
2469         let seq = List.rev seq in
2470         List.rev (List.tl seq), List.hd seq
2471   in
2472
2473   (match test with
2474    | TestRun seq ->
2475        pr "  /* TestRun for %s (%d) */\n" name i;
2476        List.iter (generate_test_command_call test_name) seq
2477    | TestOutput (seq, expected) ->
2478        pr "  /* TestOutput for %s (%d) */\n" name i;
2479        let seq, last = get_seq_last seq in
2480        let test () =
2481          pr "    if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
2482          pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
2483          pr "      return -1;\n";
2484          pr "    }\n"
2485        in
2486        List.iter (generate_test_command_call test_name) seq;
2487        generate_test_command_call ~test test_name last
2488    | TestOutputList (seq, expected) ->
2489        pr "  /* TestOutputList for %s (%d) */\n" name i;
2490        let seq, last = get_seq_last seq in
2491        let test () =
2492          iteri (
2493            fun i str ->
2494              pr "    if (!r[%d]) {\n" i;
2495              pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
2496              pr "      print_strings (r);\n";
2497              pr "      return -1;\n";
2498              pr "    }\n";
2499              pr "    if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
2500              pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
2501              pr "      return -1;\n";
2502              pr "    }\n"
2503          ) expected;
2504          pr "    if (r[%d] != NULL) {\n" (List.length expected);
2505          pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
2506            test_name;
2507          pr "      print_strings (r);\n";
2508          pr "      return -1;\n";
2509          pr "    }\n"
2510        in
2511        List.iter (generate_test_command_call test_name) seq;
2512        generate_test_command_call ~test test_name last
2513    | TestOutputInt (seq, expected) ->
2514        pr "  /* TestOutputInt for %s (%d) */\n" name i;
2515        let seq, last = get_seq_last seq in
2516        let test () =
2517          pr "    if (r != %d) {\n" expected;
2518          pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\", r);\n"
2519            test_name expected;
2520          pr "      return -1;\n";
2521          pr "    }\n"
2522        in
2523        List.iter (generate_test_command_call test_name) seq;
2524        generate_test_command_call ~test test_name last
2525    | TestOutputTrue seq ->
2526        pr "  /* TestOutputTrue for %s (%d) */\n" name i;
2527        let seq, last = get_seq_last seq in
2528        let test () =
2529          pr "    if (!r) {\n";
2530          pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
2531            test_name;
2532          pr "      return -1;\n";
2533          pr "    }\n"
2534        in
2535        List.iter (generate_test_command_call test_name) seq;
2536        generate_test_command_call ~test test_name last
2537    | TestOutputFalse seq ->
2538        pr "  /* TestOutputFalse for %s (%d) */\n" name i;
2539        let seq, last = get_seq_last seq in
2540        let test () =
2541          pr "    if (r) {\n";
2542          pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
2543            test_name;
2544          pr "      return -1;\n";
2545          pr "    }\n"
2546        in
2547        List.iter (generate_test_command_call test_name) seq;
2548        generate_test_command_call ~test test_name last
2549    | TestOutputLength (seq, expected) ->
2550        pr "  /* TestOutputLength for %s (%d) */\n" name i;
2551        let seq, last = get_seq_last seq in
2552        let test () =
2553          pr "    int j;\n";
2554          pr "    for (j = 0; j < %d; ++j)\n" expected;
2555          pr "      if (r[j] == NULL) {\n";
2556          pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
2557            test_name;
2558          pr "        print_strings (r);\n";
2559          pr "        return -1;\n";
2560          pr "      }\n";
2561          pr "    if (r[j] != NULL) {\n";
2562          pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
2563            test_name;
2564          pr "      print_strings (r);\n";
2565          pr "      return -1;\n";
2566          pr "    }\n"
2567        in
2568        List.iter (generate_test_command_call test_name) seq;
2569        generate_test_command_call ~test test_name last
2570    | TestOutputStruct (seq, checks) ->
2571        pr "  /* TestOutputStruct for %s (%d) */\n" name i;
2572        let seq, last = get_seq_last seq in
2573        let test () =
2574          List.iter (
2575            function
2576            | CompareWithInt (field, expected) ->
2577                pr "    if (r->%s != %d) {\n" field expected;
2578                pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
2579                  test_name field expected;
2580                pr "               (int) r->%s);\n" field;
2581                pr "      return -1;\n";
2582                pr "    }\n"
2583            | CompareWithString (field, expected) ->
2584                pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
2585                pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
2586                  test_name field expected;
2587                pr "               r->%s);\n" field;
2588                pr "      return -1;\n";
2589                pr "    }\n"
2590            | CompareFieldsIntEq (field1, field2) ->
2591                pr "    if (r->%s != r->%s) {\n" field1 field2;
2592                pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
2593                  test_name field1 field2;
2594                pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
2595                pr "      return -1;\n";
2596                pr "    }\n"
2597            | CompareFieldsStrEq (field1, field2) ->
2598                pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
2599                pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
2600                  test_name field1 field2;
2601                pr "               r->%s, r->%s);\n" field1 field2;
2602                pr "      return -1;\n";
2603                pr "    }\n"
2604          ) checks
2605        in
2606        List.iter (generate_test_command_call test_name) seq;
2607        generate_test_command_call ~test test_name last
2608    | TestLastFail seq ->
2609        pr "  /* TestLastFail for %s (%d) */\n" name i;
2610        let seq, last = get_seq_last seq in
2611        List.iter (generate_test_command_call test_name) seq;
2612        generate_test_command_call test_name ~expect_error:true last
2613   );
2614
2615   pr "  return 0;\n";
2616   pr "}\n";
2617   pr "\n";
2618   test_name
2619
2620 (* Generate the code to run a command, leaving the result in 'r'.
2621  * If you expect to get an error then you should set expect_error:true.
2622  *)
2623 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
2624   match cmd with
2625   | [] -> assert false
2626   | name :: args ->
2627       (* Look up the command to find out what args/ret it has. *)
2628       let style =
2629         try
2630           let _, style, _, _, _, _, _ =
2631             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
2632           style
2633         with Not_found ->
2634           failwithf "%s: in test, command %s was not found" test_name name in
2635
2636       if List.length (snd style) <> List.length args then
2637         failwithf "%s: in test, wrong number of args given to %s"
2638           test_name name;
2639
2640       pr "  {\n";
2641
2642       List.iter (
2643         function
2644         | String _, _
2645         | OptString _, _
2646         | Int _, _
2647         | Bool _, _ -> ()
2648         | StringList n, arg ->
2649             pr "    char *%s[] = {\n" n;
2650             let strs = string_split " " arg in
2651             List.iter (
2652               fun str -> pr "      \"%s\",\n" (c_quote str)
2653             ) strs;
2654             pr "      NULL\n";
2655             pr "    };\n";
2656       ) (List.combine (snd style) args);
2657
2658       let error_code =
2659         match fst style with
2660         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
2661         | RConstString _ -> pr "    const char *r;\n"; "NULL"
2662         | RString _ -> pr "    char *r;\n"; "NULL"
2663         | RStringList _ ->
2664             pr "    char **r;\n";
2665             pr "    int i;\n";
2666             "NULL"
2667         | RIntBool _ ->
2668             pr "    struct guestfs_int_bool *r;\n"; "NULL"
2669         | RPVList _ ->
2670             pr "    struct guestfs_lvm_pv_list *r;\n"; "NULL"
2671         | RVGList _ ->
2672             pr "    struct guestfs_lvm_vg_list *r;\n"; "NULL"
2673         | RLVList _ ->
2674             pr "    struct guestfs_lvm_lv_list *r;\n"; "NULL"
2675         | RStat _ ->
2676             pr "    struct guestfs_stat *r;\n"; "NULL"
2677         | RStatVFS _ ->
2678             pr "    struct guestfs_statvfs *r;\n"; "NULL" in
2679
2680       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
2681       pr "    r = guestfs_%s (g" name;
2682
2683       (* Generate the parameters. *)
2684       List.iter (
2685         function
2686         | String _, arg -> pr ", \"%s\"" (c_quote arg)
2687         | OptString _, arg ->
2688             if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
2689         | StringList n, _ ->
2690             pr ", %s" n
2691         | Int _, arg ->
2692             let i =
2693               try int_of_string arg
2694               with Failure "int_of_string" ->
2695                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
2696             pr ", %d" i
2697         | Bool _, arg ->
2698             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
2699       ) (List.combine (snd style) args);
2700
2701       pr ");\n";
2702       if not expect_error then
2703         pr "    if (r == %s)\n" error_code
2704       else
2705         pr "    if (r != %s)\n" error_code;
2706       pr "      return -1;\n";
2707
2708       (* Insert the test code. *)
2709       (match test with
2710        | None -> ()
2711        | Some f -> f ()
2712       );
2713
2714       (match fst style with
2715        | RErr | RInt _ | RBool _ | RConstString _ -> ()
2716        | RString _ -> pr "    free (r);\n"
2717        | RStringList _ ->
2718            pr "    for (i = 0; r[i] != NULL; ++i)\n";
2719            pr "      free (r[i]);\n";
2720            pr "    free (r);\n"
2721        | RIntBool _ ->
2722            pr "    guestfs_free_int_bool (r);\n"
2723        | RPVList _ ->
2724            pr "    guestfs_free_lvm_pv_list (r);\n"
2725        | RVGList _ ->
2726            pr "    guestfs_free_lvm_vg_list (r);\n"
2727        | RLVList _ ->
2728            pr "    guestfs_free_lvm_lv_list (r);\n"
2729        | RStat _ | RStatVFS _ ->
2730            pr "    free (r);\n"
2731       );
2732
2733       pr "  }\n"
2734
2735 and c_quote str =
2736   let str = replace_str str "\r" "\\r" in
2737   let str = replace_str str "\n" "\\n" in
2738   let str = replace_str str "\t" "\\t" in
2739   str
2740
2741 (* Generate a lot of different functions for guestfish. *)
2742 and generate_fish_cmds () =
2743   generate_header CStyle GPLv2;
2744
2745   let all_functions =
2746     List.filter (
2747       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
2748     ) all_functions in
2749   let all_functions_sorted =
2750     List.filter (
2751       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
2752     ) all_functions_sorted in
2753
2754   pr "#include <stdio.h>\n";
2755   pr "#include <stdlib.h>\n";
2756   pr "#include <string.h>\n";
2757   pr "#include <inttypes.h>\n";
2758   pr "\n";
2759   pr "#include <guestfs.h>\n";
2760   pr "#include \"fish.h\"\n";
2761   pr "\n";
2762
2763   (* list_commands function, which implements guestfish -h *)
2764   pr "void list_commands (void)\n";
2765   pr "{\n";
2766   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
2767   pr "  list_builtin_commands ();\n";
2768   List.iter (
2769     fun (name, _, _, flags, _, shortdesc, _) ->
2770       let name = replace_char name '_' '-' in
2771       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
2772         name shortdesc
2773   ) all_functions_sorted;
2774   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
2775   pr "}\n";
2776   pr "\n";
2777
2778   (* display_command function, which implements guestfish -h cmd *)
2779   pr "void display_command (const char *cmd)\n";
2780   pr "{\n";
2781   List.iter (
2782     fun (name, style, _, flags, _, shortdesc, longdesc) ->
2783       let name2 = replace_char name '_' '-' in
2784       let alias =
2785         try find_map (function FishAlias n -> Some n | _ -> None) flags
2786         with Not_found -> name in
2787       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
2788       let synopsis =
2789         match snd style with
2790         | [] -> name2
2791         | args ->
2792             sprintf "%s <%s>"
2793               name2 (String.concat "> <" (List.map name_of_argt args)) in
2794
2795       let warnings =
2796         if List.mem ProtocolLimitWarning flags then
2797           ("\n\n" ^ protocol_limit_warning)
2798         else "" in
2799
2800       (* For DangerWillRobinson commands, we should probably have
2801        * guestfish prompt before allowing you to use them (especially
2802        * in interactive mode). XXX
2803        *)
2804       let warnings =
2805         warnings ^
2806           if List.mem DangerWillRobinson flags then
2807             ("\n\n" ^ danger_will_robinson)
2808           else "" in
2809
2810       let describe_alias =
2811         if name <> alias then
2812           sprintf "\n\nYou can use '%s' as an alias for this command." alias
2813         else "" in
2814
2815       pr "  if (";
2816       pr "strcasecmp (cmd, \"%s\") == 0" name;
2817       if name <> name2 then
2818         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
2819       if name <> alias then
2820         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
2821       pr ")\n";
2822       pr "    pod2text (\"%s - %s\", %S);\n"
2823         name2 shortdesc
2824         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
2825       pr "  else\n"
2826   ) all_functions;
2827   pr "    display_builtin_command (cmd);\n";
2828   pr "}\n";
2829   pr "\n";
2830
2831   (* print_{pv,vg,lv}_list functions *)
2832   List.iter (
2833     function
2834     | typ, cols ->
2835         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
2836         pr "{\n";
2837         pr "  int i;\n";
2838         pr "\n";
2839         List.iter (
2840           function
2841           | name, `String ->
2842               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
2843           | name, `UUID ->
2844               pr "  printf (\"%s: \");\n" name;
2845               pr "  for (i = 0; i < 32; ++i)\n";
2846               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
2847               pr "  printf (\"\\n\");\n"
2848           | name, `Bytes ->
2849               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
2850           | name, `Int ->
2851               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
2852           | name, `OptPercent ->
2853               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
2854                 typ name name typ name;
2855               pr "  else printf (\"%s: \\n\");\n" name
2856         ) cols;
2857         pr "}\n";
2858         pr "\n";
2859         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
2860           typ typ typ;
2861         pr "{\n";
2862         pr "  int i;\n";
2863         pr "\n";
2864         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
2865         pr "    print_%s (&%ss->val[i]);\n" typ typ;
2866         pr "}\n";
2867         pr "\n";
2868   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
2869
2870   (* print_{stat,statvfs} functions *)
2871   List.iter (
2872     function
2873     | typ, cols ->
2874         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
2875         pr "{\n";
2876         List.iter (
2877           function
2878           | name, `Int ->
2879               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
2880         ) cols;
2881         pr "}\n";
2882         pr "\n";
2883   ) ["stat", stat_cols; "statvfs", statvfs_cols];
2884
2885   (* run_<action> actions *)
2886   List.iter (
2887     fun (name, style, _, flags, _, _, _) ->
2888       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
2889       pr "{\n";
2890       (match fst style with
2891        | RErr
2892        | RInt _
2893        | RBool _ -> pr "  int r;\n"
2894        | RConstString _ -> pr "  const char *r;\n"
2895        | RString _ -> pr "  char *r;\n"
2896        | RStringList _ -> pr "  char **r;\n"
2897        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
2898        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
2899        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
2900        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
2901        | RStat _ -> pr "  struct guestfs_stat *r;\n"
2902        | RStatVFS _ -> pr "  struct guestfs_statvfs *r;\n"
2903       );
2904       List.iter (
2905         function
2906         | String n
2907         | OptString n -> pr "  const char *%s;\n" n
2908         | StringList n -> pr "  char **%s;\n" n
2909         | Bool n -> pr "  int %s;\n" n
2910         | Int n -> pr "  int %s;\n" n
2911       ) (snd style);
2912
2913       (* Check and convert parameters. *)
2914       let argc_expected = List.length (snd style) in
2915       pr "  if (argc != %d) {\n" argc_expected;
2916       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
2917         argc_expected;
2918       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
2919       pr "    return -1;\n";
2920       pr "  }\n";
2921       iteri (
2922         fun i ->
2923           function
2924           | String name -> pr "  %s = argv[%d];\n" name i
2925           | OptString name ->
2926               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
2927                 name i i
2928           | StringList name ->
2929               pr "  %s = parse_string_list (argv[%d]);\n" name i
2930           | Bool name ->
2931               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
2932           | Int name ->
2933               pr "  %s = atoi (argv[%d]);\n" name i
2934       ) (snd style);
2935
2936       (* Call C API function. *)
2937       let fn =
2938         try find_map (function FishAction n -> Some n | _ -> None) flags
2939         with Not_found -> sprintf "guestfs_%s" name in
2940       pr "  r = %s " fn;
2941       generate_call_args ~handle:"g" style;
2942       pr ";\n";
2943
2944       (* Check return value for errors and display command results. *)
2945       (match fst style with
2946        | RErr -> pr "  return r;\n"
2947        | RInt _ ->
2948            pr "  if (r == -1) return -1;\n";
2949            pr "  if (r) printf (\"%%d\\n\", r);\n";
2950            pr "  return 0;\n"
2951        | RBool _ ->
2952            pr "  if (r == -1) return -1;\n";
2953            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
2954            pr "  return 0;\n"
2955        | RConstString _ ->
2956            pr "  if (r == NULL) return -1;\n";
2957            pr "  printf (\"%%s\\n\", r);\n";
2958            pr "  return 0;\n"
2959        | RString _ ->
2960            pr "  if (r == NULL) return -1;\n";
2961            pr "  printf (\"%%s\\n\", r);\n";
2962            pr "  free (r);\n";
2963            pr "  return 0;\n"
2964        | RStringList _ ->
2965            pr "  if (r == NULL) return -1;\n";
2966            pr "  print_strings (r);\n";
2967            pr "  free_strings (r);\n";
2968            pr "  return 0;\n"
2969        | RIntBool _ ->
2970            pr "  if (r == NULL) return -1;\n";
2971            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
2972            pr "    r->b ? \"true\" : \"false\");\n";
2973            pr "  guestfs_free_int_bool (r);\n";
2974            pr "  return 0;\n"
2975        | RPVList _ ->
2976            pr "  if (r == NULL) return -1;\n";
2977            pr "  print_pv_list (r);\n";
2978            pr "  guestfs_free_lvm_pv_list (r);\n";
2979            pr "  return 0;\n"
2980        | RVGList _ ->
2981            pr "  if (r == NULL) return -1;\n";
2982            pr "  print_vg_list (r);\n";
2983            pr "  guestfs_free_lvm_vg_list (r);\n";
2984            pr "  return 0;\n"
2985        | RLVList _ ->
2986            pr "  if (r == NULL) return -1;\n";
2987            pr "  print_lv_list (r);\n";
2988            pr "  guestfs_free_lvm_lv_list (r);\n";
2989            pr "  return 0;\n"
2990        | RStat _ ->
2991            pr "  if (r == NULL) return -1;\n";
2992            pr "  print_stat (r);\n";
2993            pr "  free (r);\n";
2994            pr "  return 0;\n"
2995        | RStatVFS _ ->
2996            pr "  if (r == NULL) return -1;\n";
2997            pr "  print_statvfs (r);\n";
2998            pr "  free (r);\n";
2999            pr "  return 0;\n"
3000       );
3001       pr "}\n";
3002       pr "\n"
3003   ) all_functions;
3004
3005   (* run_action function *)
3006   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3007   pr "{\n";
3008   List.iter (
3009     fun (name, _, _, flags, _, _, _) ->
3010       let name2 = replace_char name '_' '-' in
3011       let alias =
3012         try find_map (function FishAlias n -> Some n | _ -> None) flags
3013         with Not_found -> name in
3014       pr "  if (";
3015       pr "strcasecmp (cmd, \"%s\") == 0" name;
3016       if name <> name2 then
3017         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3018       if name <> alias then
3019         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3020       pr ")\n";
3021       pr "    return run_%s (cmd, argc, argv);\n" name;
3022       pr "  else\n";
3023   ) all_functions;
3024   pr "    {\n";
3025   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3026   pr "      return -1;\n";
3027   pr "    }\n";
3028   pr "  return 0;\n";
3029   pr "}\n";
3030   pr "\n"
3031
3032 (* Readline completion for guestfish. *)
3033 and generate_fish_completion () =
3034   generate_header CStyle GPLv2;
3035
3036   let all_functions =
3037     List.filter (
3038       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3039     ) all_functions in
3040
3041   pr "\
3042 #include <config.h>
3043
3044 #include <stdio.h>
3045 #include <stdlib.h>
3046 #include <string.h>
3047
3048 #ifdef HAVE_LIBREADLINE
3049 #include <readline/readline.h>
3050 #endif
3051
3052 #include \"fish.h\"
3053
3054 #ifdef HAVE_LIBREADLINE
3055
3056 static const char *commands[] = {
3057 ";
3058
3059   (* Get the commands and sort them, including the aliases. *)
3060   let commands =
3061     List.map (
3062       fun (name, _, _, flags, _, _, _) ->
3063         let name2 = replace_char name '_' '-' in
3064         let alias =
3065           try find_map (function FishAlias n -> Some n | _ -> None) flags
3066           with Not_found -> name in
3067
3068         if name <> alias then [name2; alias] else [name2]
3069     ) all_functions in
3070   let commands = List.flatten commands in
3071   let commands = List.sort compare commands in
3072
3073   List.iter (pr "  \"%s\",\n") commands;
3074
3075   pr "  NULL
3076 };
3077
3078 static char *
3079 generator (const char *text, int state)
3080 {
3081   static int index, len;
3082   const char *name;
3083
3084   if (!state) {
3085     index = 0;
3086     len = strlen (text);
3087   }
3088
3089   while ((name = commands[index]) != NULL) {
3090     index++;
3091     if (strncasecmp (name, text, len) == 0)
3092       return strdup (name);
3093   }
3094
3095   return NULL;
3096 }
3097
3098 #endif /* HAVE_LIBREADLINE */
3099
3100 char **do_completion (const char *text, int start, int end)
3101 {
3102   char **matches = NULL;
3103
3104 #ifdef HAVE_LIBREADLINE
3105   if (start == 0)
3106     matches = rl_completion_matches (text, generator);
3107 #endif
3108
3109   return matches;
3110 }
3111 ";
3112
3113 (* Generate the POD documentation for guestfish. *)
3114 and generate_fish_actions_pod () =
3115   let all_functions_sorted =
3116     List.filter (
3117       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3118     ) all_functions_sorted in
3119
3120   List.iter (
3121     fun (name, style, _, flags, _, _, longdesc) ->
3122       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3123       let name = replace_char name '_' '-' in
3124       let alias =
3125         try find_map (function FishAlias n -> Some n | _ -> None) flags
3126         with Not_found -> name in
3127
3128       pr "=head2 %s" name;
3129       if name <> alias then
3130         pr " | %s" alias;
3131       pr "\n";
3132       pr "\n";
3133       pr " %s" name;
3134       List.iter (
3135         function
3136         | String n -> pr " %s" n
3137         | OptString n -> pr " %s" n
3138         | StringList n -> pr " %s,..." n
3139         | Bool _ -> pr " true|false"
3140         | Int n -> pr " %s" n
3141       ) (snd style);
3142       pr "\n";
3143       pr "\n";
3144       pr "%s\n\n" longdesc;
3145
3146       if List.mem ProtocolLimitWarning flags then
3147         pr "%s\n\n" protocol_limit_warning;
3148
3149       if List.mem DangerWillRobinson flags then
3150         pr "%s\n\n" danger_will_robinson
3151   ) all_functions_sorted
3152
3153 (* Generate a C function prototype. *)
3154 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3155     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3156     ?(prefix = "")
3157     ?handle name style =
3158   if extern then pr "extern ";
3159   if static then pr "static ";
3160   (match fst style with
3161    | RErr -> pr "int "
3162    | RInt _ -> pr "int "
3163    | RBool _ -> pr "int "
3164    | RConstString _ -> pr "const char *"
3165    | RString _ -> pr "char *"
3166    | RStringList _ -> pr "char **"
3167    | RIntBool _ ->
3168        if not in_daemon then pr "struct guestfs_int_bool *"
3169        else pr "guestfs_%s_ret *" name
3170    | RPVList _ ->
3171        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3172        else pr "guestfs_lvm_int_pv_list *"
3173    | RVGList _ ->
3174        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3175        else pr "guestfs_lvm_int_vg_list *"
3176    | RLVList _ ->
3177        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3178        else pr "guestfs_lvm_int_lv_list *"
3179    | RStat _ ->
3180        if not in_daemon then pr "struct guestfs_stat *"
3181        else pr "guestfs_int_stat *"
3182    | RStatVFS _ ->
3183        if not in_daemon then pr "struct guestfs_statvfs *"
3184        else pr "guestfs_int_statvfs *"
3185   );
3186   pr "%s%s (" prefix name;
3187   if handle = None && List.length (snd style) = 0 then
3188     pr "void"
3189   else (
3190     let comma = ref false in
3191     (match handle with
3192      | None -> ()
3193      | Some handle -> pr "guestfs_h *%s" handle; comma := true
3194     );
3195     let next () =
3196       if !comma then (
3197         if single_line then pr ", " else pr ",\n\t\t"
3198       );
3199       comma := true
3200     in
3201     List.iter (
3202       function
3203       | String n -> next (); pr "const char *%s" n
3204       | OptString n -> next (); pr "const char *%s" n
3205       | StringList n -> next (); pr "char * const* const %s" n
3206       | Bool n -> next (); pr "int %s" n
3207       | Int n -> next (); pr "int %s" n
3208     ) (snd style);
3209   );
3210   pr ")";
3211   if semicolon then pr ";";
3212   if newline then pr "\n"
3213
3214 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3215 and generate_call_args ?handle style =
3216   pr "(";
3217   let comma = ref false in
3218   (match handle with
3219    | None -> ()
3220    | Some handle -> pr "%s" handle; comma := true
3221   );
3222   List.iter (
3223     fun arg ->
3224       if !comma then pr ", ";
3225       comma := true;
3226       match arg with
3227       | String n
3228       | OptString n
3229       | StringList n
3230       | Bool n
3231       | Int n -> pr "%s" n
3232   ) (snd style);
3233   pr ")"
3234
3235 (* Generate the OCaml bindings interface. *)
3236 and generate_ocaml_mli () =
3237   generate_header OCamlStyle LGPLv2;
3238
3239   pr "\
3240 (** For API documentation you should refer to the C API
3241     in the guestfs(3) manual page.  The OCaml API uses almost
3242     exactly the same calls. *)
3243
3244 type t
3245 (** A [guestfs_h] handle. *)
3246
3247 exception Error of string
3248 (** This exception is raised when there is an error. *)
3249
3250 val create : unit -> t
3251
3252 val close : t -> unit
3253 (** Handles are closed by the garbage collector when they become
3254     unreferenced, but callers can also call this in order to
3255     provide predictable cleanup. *)
3256
3257 ";
3258   generate_ocaml_lvm_structure_decls ();
3259
3260   generate_ocaml_stat_structure_decls ();
3261
3262   (* The actions. *)
3263   List.iter (
3264     fun (name, style, _, _, _, shortdesc, _) ->
3265       generate_ocaml_prototype name style;
3266       pr "(** %s *)\n" shortdesc;
3267       pr "\n"
3268   ) all_functions
3269
3270 (* Generate the OCaml bindings implementation. *)
3271 and generate_ocaml_ml () =
3272   generate_header OCamlStyle LGPLv2;
3273
3274   pr "\
3275 type t
3276 exception Error of string
3277 external create : unit -> t = \"ocaml_guestfs_create\"
3278 external close : t -> unit = \"ocaml_guestfs_close\"
3279
3280 let () =
3281   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3282
3283 ";
3284
3285   generate_ocaml_lvm_structure_decls ();
3286
3287   generate_ocaml_stat_structure_decls ();
3288
3289   (* The actions. *)
3290   List.iter (
3291     fun (name, style, _, _, _, shortdesc, _) ->
3292       generate_ocaml_prototype ~is_external:true name style;
3293   ) all_functions
3294
3295 (* Generate the OCaml bindings C implementation. *)
3296 and generate_ocaml_c () =
3297   generate_header CStyle LGPLv2;
3298
3299   pr "#include <stdio.h>\n";
3300   pr "#include <stdlib.h>\n";
3301   pr "#include <string.h>\n";
3302   pr "\n";
3303   pr "#include <caml/config.h>\n";
3304   pr "#include <caml/alloc.h>\n";
3305   pr "#include <caml/callback.h>\n";
3306   pr "#include <caml/fail.h>\n";
3307   pr "#include <caml/memory.h>\n";
3308   pr "#include <caml/mlvalues.h>\n";
3309   pr "#include <caml/signals.h>\n";
3310   pr "\n";
3311   pr "#include <guestfs.h>\n";
3312   pr "\n";
3313   pr "#include \"guestfs_c.h\"\n";
3314   pr "\n";
3315
3316   (* LVM struct copy functions. *)
3317   List.iter (
3318     fun (typ, cols) ->
3319       let has_optpercent_col =
3320         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
3321
3322       pr "static CAMLprim value\n";
3323       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
3324       pr "{\n";
3325       pr "  CAMLparam0 ();\n";
3326       if has_optpercent_col then
3327         pr "  CAMLlocal3 (rv, v, v2);\n"
3328       else
3329         pr "  CAMLlocal2 (rv, v);\n";
3330       pr "\n";
3331       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3332       iteri (
3333         fun i col ->
3334           (match col with
3335            | name, `String ->
3336                pr "  v = caml_copy_string (%s->%s);\n" typ name
3337            | name, `UUID ->
3338                pr "  v = caml_alloc_string (32);\n";
3339                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
3340            | name, `Bytes
3341            | name, `Int ->
3342                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3343            | name, `OptPercent ->
3344                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
3345                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
3346                pr "    v = caml_alloc (1, 0);\n";
3347                pr "    Store_field (v, 0, v2);\n";
3348                pr "  } else /* None */\n";
3349                pr "    v = Val_int (0);\n";
3350           );
3351           pr "  Store_field (rv, %d, v);\n" i
3352       ) cols;
3353       pr "  CAMLreturn (rv);\n";
3354       pr "}\n";
3355       pr "\n";
3356
3357       pr "static CAMLprim value\n";
3358       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
3359         typ typ typ;
3360       pr "{\n";
3361       pr "  CAMLparam0 ();\n";
3362       pr "  CAMLlocal2 (rv, v);\n";
3363       pr "  int i;\n";
3364       pr "\n";
3365       pr "  if (%ss->len == 0)\n" typ;
3366       pr "    CAMLreturn (Atom (0));\n";
3367       pr "  else {\n";
3368       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
3369       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
3370       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
3371       pr "      caml_modify (&Field (rv, i), v);\n";
3372       pr "    }\n";
3373       pr "    CAMLreturn (rv);\n";
3374       pr "  }\n";
3375       pr "}\n";
3376       pr "\n";
3377   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3378
3379   (* Stat copy functions. *)
3380   List.iter (
3381     fun (typ, cols) ->
3382       pr "static CAMLprim value\n";
3383       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
3384       pr "{\n";
3385       pr "  CAMLparam0 ();\n";
3386       pr "  CAMLlocal2 (rv, v);\n";
3387       pr "\n";
3388       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3389       iteri (
3390         fun i col ->
3391           (match col with
3392            | name, `Int ->
3393                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3394           );
3395           pr "  Store_field (rv, %d, v);\n" i
3396       ) cols;
3397       pr "  CAMLreturn (rv);\n";
3398       pr "}\n";
3399       pr "\n";
3400   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3401
3402   (* The wrappers. *)
3403   List.iter (
3404     fun (name, style, _, _, _, _, _) ->
3405       let params =
3406         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
3407
3408       pr "CAMLprim value\n";
3409       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
3410       List.iter (pr ", value %s") (List.tl params);
3411       pr ")\n";
3412       pr "{\n";
3413
3414       (match params with
3415        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
3416            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
3417            pr "  CAMLxparam%d (%s);\n"
3418              (List.length rest) (String.concat ", " rest)
3419        | ps ->
3420            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
3421       );
3422       pr "  CAMLlocal1 (rv);\n";
3423       pr "\n";
3424
3425       pr "  guestfs_h *g = Guestfs_val (gv);\n";
3426       pr "  if (g == NULL)\n";
3427       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
3428       pr "\n";
3429
3430       List.iter (
3431         function
3432         | String n ->
3433             pr "  const char *%s = String_val (%sv);\n" n n
3434         | OptString n ->
3435             pr "  const char *%s =\n" n;
3436             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
3437               n n
3438         | StringList n ->
3439             pr "  char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
3440         | Bool n ->
3441             pr "  int %s = Bool_val (%sv);\n" n n
3442         | Int n ->
3443             pr "  int %s = Int_val (%sv);\n" n n
3444       ) (snd style);
3445       let error_code =
3446         match fst style with
3447         | RErr -> pr "  int r;\n"; "-1"
3448         | RInt _ -> pr "  int r;\n"; "-1"
3449         | RBool _ -> pr "  int r;\n"; "-1"
3450         | RConstString _ -> pr "  const char *r;\n"; "NULL"
3451         | RString _ -> pr "  char *r;\n"; "NULL"
3452         | RStringList _ ->
3453             pr "  int i;\n";
3454             pr "  char **r;\n";
3455             "NULL"
3456         | RIntBool _ ->
3457             pr "  struct guestfs_int_bool *r;\n"; "NULL"
3458         | RPVList _ ->
3459             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
3460         | RVGList _ ->
3461             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
3462         | RLVList _ ->
3463             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
3464         | RStat _ ->
3465             pr "  struct guestfs_stat *r;\n"; "NULL"
3466         | RStatVFS _ ->
3467             pr "  struct guestfs_statvfs *r;\n"; "NULL" in
3468       pr "\n";
3469
3470       pr "  caml_enter_blocking_section ();\n";
3471       pr "  r = guestfs_%s " name;
3472       generate_call_args ~handle:"g" style;
3473       pr ";\n";
3474       pr "  caml_leave_blocking_section ();\n";
3475
3476       List.iter (
3477         function
3478         | StringList n ->
3479             pr "  ocaml_guestfs_free_strings (%s);\n" n;
3480         | String _ | OptString _ | Bool _ | Int _ -> ()
3481       ) (snd style);
3482
3483       pr "  if (r == %s)\n" error_code;
3484       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
3485       pr "\n";
3486
3487       (match fst style with
3488        | RErr -> pr "  rv = Val_unit;\n"
3489        | RInt _ -> pr "  rv = Val_int (r);\n"
3490        | RBool _ -> pr "  rv = Val_bool (r);\n"
3491        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
3492        | RString _ ->
3493            pr "  rv = caml_copy_string (r);\n";
3494            pr "  free (r);\n"
3495        | RStringList _ ->
3496            pr "  rv = caml_copy_string_array ((const char **) r);\n";
3497            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
3498            pr "  free (r);\n"
3499        | RIntBool _ ->
3500            pr "  rv = caml_alloc (2, 0);\n";
3501            pr "  Store_field (rv, 0, Val_int (r->i));\n";
3502            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
3503            pr "  guestfs_free_int_bool (r);\n";
3504        | RPVList _ ->
3505            pr "  rv = copy_lvm_pv_list (r);\n";
3506            pr "  guestfs_free_lvm_pv_list (r);\n";
3507        | RVGList _ ->
3508            pr "  rv = copy_lvm_vg_list (r);\n";
3509            pr "  guestfs_free_lvm_vg_list (r);\n";
3510        | RLVList _ ->
3511            pr "  rv = copy_lvm_lv_list (r);\n";
3512            pr "  guestfs_free_lvm_lv_list (r);\n";
3513        | RStat _ ->
3514            pr "  rv = copy_stat (r);\n";
3515            pr "  free (r);\n";
3516        | RStatVFS _ ->
3517            pr "  rv = copy_statvfs (r);\n";
3518            pr "  free (r);\n";
3519       );
3520
3521       pr "  CAMLreturn (rv);\n";
3522       pr "}\n";
3523       pr "\n";
3524
3525       if List.length params > 5 then (
3526         pr "CAMLprim value\n";
3527         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
3528         pr "{\n";
3529         pr "  return ocaml_guestfs_%s (argv[0]" name;
3530         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
3531         pr ");\n";
3532         pr "}\n";
3533         pr "\n"
3534       )
3535   ) all_functions
3536
3537 and generate_ocaml_lvm_structure_decls () =
3538   List.iter (
3539     fun (typ, cols) ->
3540       pr "type lvm_%s = {\n" typ;
3541       List.iter (
3542         function
3543         | name, `String -> pr "  %s : string;\n" name
3544         | name, `UUID -> pr "  %s : string;\n" name
3545         | name, `Bytes -> pr "  %s : int64;\n" name
3546         | name, `Int -> pr "  %s : int64;\n" name
3547         | name, `OptPercent -> pr "  %s : float option;\n" name
3548       ) cols;
3549       pr "}\n";
3550       pr "\n"
3551   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
3552
3553 and generate_ocaml_stat_structure_decls () =
3554   List.iter (
3555     fun (typ, cols) ->
3556       pr "type %s = {\n" typ;
3557       List.iter (
3558         function
3559         | name, `Int -> pr "  %s : int64;\n" name
3560       ) cols;
3561       pr "}\n";
3562       pr "\n"
3563   ) ["stat", stat_cols; "statvfs", statvfs_cols]
3564
3565 and generate_ocaml_prototype ?(is_external = false) name style =
3566   if is_external then pr "external " else pr "val ";
3567   pr "%s : t -> " name;
3568   List.iter (
3569     function
3570     | String _ -> pr "string -> "
3571     | OptString _ -> pr "string option -> "
3572     | StringList _ -> pr "string array -> "
3573     | Bool _ -> pr "bool -> "
3574     | Int _ -> pr "int -> "
3575   ) (snd style);
3576   (match fst style with
3577    | RErr -> pr "unit" (* all errors are turned into exceptions *)
3578    | RInt _ -> pr "int"
3579    | RBool _ -> pr "bool"
3580    | RConstString _ -> pr "string"
3581    | RString _ -> pr "string"
3582    | RStringList _ -> pr "string array"
3583    | RIntBool _ -> pr "int * bool"
3584    | RPVList _ -> pr "lvm_pv array"
3585    | RVGList _ -> pr "lvm_vg array"
3586    | RLVList _ -> pr "lvm_lv array"
3587    | RStat _ -> pr "stat"
3588    | RStatVFS _ -> pr "statvfs"
3589   );
3590   if is_external then (
3591     pr " = ";
3592     if List.length (snd style) + 1 > 5 then
3593       pr "\"ocaml_guestfs_%s_byte\" " name;
3594     pr "\"ocaml_guestfs_%s\"" name
3595   );
3596   pr "\n"
3597
3598 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
3599 and generate_perl_xs () =
3600   generate_header CStyle LGPLv2;
3601
3602   pr "\
3603 #include \"EXTERN.h\"
3604 #include \"perl.h\"
3605 #include \"XSUB.h\"
3606
3607 #include <guestfs.h>
3608
3609 #ifndef PRId64
3610 #define PRId64 \"lld\"
3611 #endif
3612
3613 static SV *
3614 my_newSVll(long long val) {
3615 #ifdef USE_64_BIT_ALL
3616   return newSViv(val);
3617 #else
3618   char buf[100];
3619   int len;
3620   len = snprintf(buf, 100, \"%%\" PRId64, val);
3621   return newSVpv(buf, len);
3622 #endif
3623 }
3624
3625 #ifndef PRIu64
3626 #define PRIu64 \"llu\"
3627 #endif
3628
3629 static SV *
3630 my_newSVull(unsigned long long val) {
3631 #ifdef USE_64_BIT_ALL
3632   return newSVuv(val);
3633 #else
3634   char buf[100];
3635   int len;
3636   len = snprintf(buf, 100, \"%%\" PRIu64, val);
3637   return newSVpv(buf, len);
3638 #endif
3639 }
3640
3641 /* http://www.perlmonks.org/?node_id=680842 */
3642 static char **
3643 XS_unpack_charPtrPtr (SV *arg) {
3644   char **ret;
3645   AV *av;
3646   I32 i;
3647
3648   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
3649     croak (\"array reference expected\");
3650   }
3651
3652   av = (AV *)SvRV (arg);
3653   ret = (char **)malloc (av_len (av) + 1 + 1);
3654
3655   for (i = 0; i <= av_len (av); i++) {
3656     SV **elem = av_fetch (av, i, 0);
3657
3658     if (!elem || !*elem)
3659       croak (\"missing element in list\");
3660
3661     ret[i] = SvPV_nolen (*elem);
3662   }
3663
3664   ret[i] = NULL;
3665
3666   return ret;
3667 }
3668
3669 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
3670
3671 guestfs_h *
3672 _create ()
3673    CODE:
3674       RETVAL = guestfs_create ();
3675       if (!RETVAL)
3676         croak (\"could not create guestfs handle\");
3677       guestfs_set_error_handler (RETVAL, NULL, NULL);
3678  OUTPUT:
3679       RETVAL
3680
3681 void
3682 DESTROY (g)
3683       guestfs_h *g;
3684  PPCODE:
3685       guestfs_close (g);
3686
3687 ";
3688
3689   List.iter (
3690     fun (name, style, _, _, _, _, _) ->
3691       (match fst style with
3692        | RErr -> pr "void\n"
3693        | RInt _ -> pr "SV *\n"
3694        | RBool _ -> pr "SV *\n"
3695        | RConstString _ -> pr "SV *\n"
3696        | RString _ -> pr "SV *\n"
3697        | RStringList _
3698        | RIntBool _
3699        | RPVList _ | RVGList _ | RLVList _
3700        | RStat _ | RStatVFS _ ->
3701            pr "void\n" (* all lists returned implictly on the stack *)
3702       );
3703       (* Call and arguments. *)
3704       pr "%s " name;
3705       generate_call_args ~handle:"g" style;
3706       pr "\n";
3707       pr "      guestfs_h *g;\n";
3708       List.iter (
3709         function
3710         | String n -> pr "      char *%s;\n" n
3711         | OptString n -> pr "      char *%s;\n" n
3712         | StringList n -> pr "      char **%s;\n" n
3713         | Bool n -> pr "      int %s;\n" n
3714         | Int n -> pr "      int %s;\n" n
3715       ) (snd style);
3716
3717       let do_cleanups () =
3718         List.iter (
3719           function
3720           | String _
3721           | OptString _
3722           | Bool _
3723           | Int _ -> ()
3724           | StringList n -> pr "      free (%s);\n" n
3725         ) (snd style)
3726       in
3727
3728       (* Code. *)
3729       (match fst style with
3730        | RErr ->
3731            pr "PREINIT:\n";
3732            pr "      int r;\n";
3733            pr " PPCODE:\n";
3734            pr "      r = guestfs_%s " name;
3735            generate_call_args ~handle:"g" style;
3736            pr ";\n";
3737            do_cleanups ();
3738            pr "      if (r == -1)\n";
3739            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3740        | RInt n
3741        | RBool n ->
3742            pr "PREINIT:\n";
3743            pr "      int %s;\n" n;
3744            pr "   CODE:\n";
3745            pr "      %s = guestfs_%s " n name;
3746            generate_call_args ~handle:"g" style;
3747            pr ";\n";
3748            do_cleanups ();
3749            pr "      if (%s == -1)\n" n;
3750            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3751            pr "      RETVAL = newSViv (%s);\n" n;
3752            pr " OUTPUT:\n";
3753            pr "      RETVAL\n"
3754        | RConstString n ->
3755            pr "PREINIT:\n";
3756            pr "      const char *%s;\n" n;
3757            pr "   CODE:\n";
3758            pr "      %s = guestfs_%s " n name;
3759            generate_call_args ~handle:"g" style;
3760            pr ";\n";
3761            do_cleanups ();
3762            pr "      if (%s == NULL)\n" n;
3763            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3764            pr "      RETVAL = newSVpv (%s, 0);\n" n;
3765            pr " OUTPUT:\n";
3766            pr "      RETVAL\n"
3767        | RString n ->
3768            pr "PREINIT:\n";
3769            pr "      char *%s;\n" n;
3770            pr "   CODE:\n";
3771            pr "      %s = guestfs_%s " n name;
3772            generate_call_args ~handle:"g" style;
3773            pr ";\n";
3774            do_cleanups ();
3775            pr "      if (%s == NULL)\n" n;
3776            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3777            pr "      RETVAL = newSVpv (%s, 0);\n" n;
3778            pr "      free (%s);\n" n;
3779            pr " OUTPUT:\n";
3780            pr "      RETVAL\n"
3781        | RStringList n ->
3782            pr "PREINIT:\n";
3783            pr "      char **%s;\n" n;
3784            pr "      int i, n;\n";
3785            pr " PPCODE:\n";
3786            pr "      %s = guestfs_%s " n name;
3787            generate_call_args ~handle:"g" style;
3788            pr ";\n";
3789            do_cleanups ();
3790            pr "      if (%s == NULL)\n" n;
3791            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3792            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
3793            pr "      EXTEND (SP, n);\n";
3794            pr "      for (i = 0; i < n; ++i) {\n";
3795            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
3796            pr "        free (%s[i]);\n" n;
3797            pr "      }\n";
3798            pr "      free (%s);\n" n;
3799        | RIntBool _ ->
3800            pr "PREINIT:\n";
3801            pr "      struct guestfs_int_bool *r;\n";
3802            pr " PPCODE:\n";
3803            pr "      r = guestfs_%s " name;
3804            generate_call_args ~handle:"g" style;
3805            pr ";\n";
3806            do_cleanups ();
3807            pr "      if (r == NULL)\n";
3808            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3809            pr "      EXTEND (SP, 2);\n";
3810            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
3811            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
3812            pr "      guestfs_free_int_bool (r);\n";
3813        | RPVList n ->
3814            generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
3815        | RVGList n ->
3816            generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
3817        | RLVList n ->
3818            generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
3819        | RStat n ->
3820            generate_perl_stat_code "stat" stat_cols name style n do_cleanups
3821        | RStatVFS n ->
3822            generate_perl_stat_code
3823              "statvfs" statvfs_cols name style n do_cleanups
3824       );
3825
3826       pr "\n"
3827   ) all_functions
3828
3829 and generate_perl_lvm_code typ cols name style n do_cleanups =
3830   pr "PREINIT:\n";
3831   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
3832   pr "      int i;\n";
3833   pr "      HV *hv;\n";
3834   pr " PPCODE:\n";
3835   pr "      %s = guestfs_%s " n name;
3836   generate_call_args ~handle:"g" style;
3837   pr ";\n";
3838   do_cleanups ();
3839   pr "      if (%s == NULL)\n" n;
3840   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3841   pr "      EXTEND (SP, %s->len);\n" n;
3842   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
3843   pr "        hv = newHV ();\n";
3844   List.iter (
3845     function
3846     | name, `String ->
3847         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
3848           name (String.length name) n name
3849     | name, `UUID ->
3850         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
3851           name (String.length name) n name
3852     | name, `Bytes ->
3853         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
3854           name (String.length name) n name
3855     | name, `Int ->
3856         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
3857           name (String.length name) n name
3858     | name, `OptPercent ->
3859         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
3860           name (String.length name) n name
3861   ) cols;
3862   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
3863   pr "      }\n";
3864   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
3865
3866 and generate_perl_stat_code typ cols name style n do_cleanups =
3867   pr "PREINIT:\n";
3868   pr "      struct guestfs_%s *%s;\n" typ n;
3869   pr " PPCODE:\n";
3870   pr "      %s = guestfs_%s " n name;
3871   generate_call_args ~handle:"g" style;
3872   pr ";\n";
3873   do_cleanups ();
3874   pr "      if (%s == NULL)\n" n;
3875   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
3876   pr "      EXTEND (SP, %d);\n" (List.length cols);
3877   List.iter (
3878     function
3879     | name, `Int ->
3880         pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
3881   ) cols;
3882   pr "      free (%s);\n" n
3883
3884 (* Generate Sys/Guestfs.pm. *)
3885 and generate_perl_pm () =
3886   generate_header HashStyle LGPLv2;
3887
3888   pr "\
3889 =pod
3890
3891 =head1 NAME
3892
3893 Sys::Guestfs - Perl bindings for libguestfs
3894
3895 =head1 SYNOPSIS
3896
3897  use Sys::Guestfs;
3898  
3899  my $h = Sys::Guestfs->new ();
3900  $h->add_drive ('guest.img');
3901  $h->launch ();
3902  $h->wait_ready ();
3903  $h->mount ('/dev/sda1', '/');
3904  $h->touch ('/hello');
3905  $h->sync ();
3906
3907 =head1 DESCRIPTION
3908
3909 The C<Sys::Guestfs> module provides a Perl XS binding to the
3910 libguestfs API for examining and modifying virtual machine
3911 disk images.
3912
3913 Amongst the things this is good for: making batch configuration
3914 changes to guests, getting disk used/free statistics (see also:
3915 virt-df), migrating between virtualization systems (see also:
3916 virt-p2v), performing partial backups, performing partial guest
3917 clones, cloning guests and changing registry/UUID/hostname info, and
3918 much else besides.
3919
3920 Libguestfs uses Linux kernel and qemu code, and can access any type of
3921 guest filesystem that Linux and qemu can, including but not limited
3922 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
3923 schemes, qcow, qcow2, vmdk.
3924
3925 Libguestfs provides ways to enumerate guest storage (eg. partitions,
3926 LVs, what filesystem is in each LV, etc.).  It can also run commands
3927 in the context of the guest.  Also you can access filesystems over FTP.
3928
3929 =head1 ERRORS
3930
3931 All errors turn into calls to C<croak> (see L<Carp(3)>).
3932
3933 =head1 METHODS
3934
3935 =over 4
3936
3937 =cut
3938
3939 package Sys::Guestfs;
3940
3941 use strict;
3942 use warnings;
3943
3944 require XSLoader;
3945 XSLoader::load ('Sys::Guestfs');
3946
3947 =item $h = Sys::Guestfs->new ();
3948
3949 Create a new guestfs handle.
3950
3951 =cut
3952
3953 sub new {
3954   my $proto = shift;
3955   my $class = ref ($proto) || $proto;
3956
3957   my $self = Sys::Guestfs::_create ();
3958   bless $self, $class;
3959   return $self;
3960 }
3961
3962 ";
3963
3964   (* Actions.  We only need to print documentation for these as
3965    * they are pulled in from the XS code automatically.
3966    *)
3967   List.iter (
3968     fun (name, style, _, flags, _, _, longdesc) ->
3969       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
3970       pr "=item ";
3971       generate_perl_prototype name style;
3972       pr "\n\n";
3973       pr "%s\n\n" longdesc;
3974       if List.mem ProtocolLimitWarning flags then
3975         pr "%s\n\n" protocol_limit_warning;
3976       if List.mem DangerWillRobinson flags then
3977         pr "%s\n\n" danger_will_robinson
3978   ) all_functions_sorted;
3979
3980   (* End of file. *)
3981   pr "\
3982 =cut
3983
3984 1;
3985
3986 =back
3987
3988 =head1 COPYRIGHT
3989
3990 Copyright (C) 2009 Red Hat Inc.
3991
3992 =head1 LICENSE
3993
3994 Please see the file COPYING.LIB for the full license.
3995
3996 =head1 SEE ALSO
3997
3998 L<guestfs(3)>, L<guestfish(1)>.
3999
4000 =cut
4001 "
4002
4003 and generate_perl_prototype name style =
4004   (match fst style with
4005    | RErr -> ()
4006    | RBool n
4007    | RInt n
4008    | RConstString n
4009    | RString n -> pr "$%s = " n
4010    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4011    | RStringList n
4012    | RPVList n
4013    | RVGList n
4014    | RLVList n -> pr "@%s = " n
4015    | RStat n
4016    | RStatVFS n -> pr "%%%s = " n
4017   );
4018   pr "$h->%s (" name;
4019   let comma = ref false in
4020   List.iter (
4021     fun arg ->
4022       if !comma then pr ", ";
4023       comma := true;
4024       match arg with
4025       | String n | OptString n | Bool n | Int n ->
4026           pr "$%s" n
4027       | StringList n ->
4028           pr "\\@%s" n
4029   ) (snd style);
4030   pr ");"
4031
4032 (* Generate Python C module. *)
4033 and generate_python_c () =
4034   generate_header CStyle LGPLv2;
4035
4036   pr "\
4037 #include <stdio.h>
4038 #include <stdlib.h>
4039 #include <assert.h>
4040
4041 #include <Python.h>
4042
4043 #include \"guestfs.h\"
4044
4045 typedef struct {
4046   PyObject_HEAD
4047   guestfs_h *g;
4048 } Pyguestfs_Object;
4049
4050 static guestfs_h *
4051 get_handle (PyObject *obj)
4052 {
4053   assert (obj);
4054   assert (obj != Py_None);
4055   return ((Pyguestfs_Object *) obj)->g;
4056 }
4057
4058 static PyObject *
4059 put_handle (guestfs_h *g)
4060 {
4061   assert (g);
4062   return
4063     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4064 }
4065
4066 /* This list should be freed (but not the strings) after use. */
4067 static const char **
4068 get_string_list (PyObject *obj)
4069 {
4070   int i, len;
4071   const char **r;
4072
4073   assert (obj);
4074
4075   if (!PyList_Check (obj)) {
4076     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4077     return NULL;
4078   }
4079
4080   len = PyList_Size (obj);
4081   r = malloc (sizeof (char *) * (len+1));
4082   if (r == NULL) {
4083     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4084     return NULL;
4085   }
4086
4087   for (i = 0; i < len; ++i)
4088     r[i] = PyString_AsString (PyList_GetItem (obj, i));
4089   r[len] = NULL;
4090
4091   return r;
4092 }
4093
4094 static PyObject *
4095 put_string_list (char * const * const argv)
4096 {
4097   PyObject *list;
4098   int argc, i;
4099
4100   for (argc = 0; argv[argc] != NULL; ++argc)
4101     ;
4102
4103   list = PyList_New (argc);
4104   for (i = 0; i < argc; ++i)
4105     PyList_SetItem (list, i, PyString_FromString (argv[i]));
4106
4107   return list;
4108 }
4109
4110 static void
4111 free_strings (char **argv)
4112 {
4113   int argc;
4114
4115   for (argc = 0; argv[argc] != NULL; ++argc)
4116     free (argv[argc]);
4117   free (argv);
4118 }
4119
4120 static PyObject *
4121 py_guestfs_create (PyObject *self, PyObject *args)
4122 {
4123   guestfs_h *g;
4124
4125   g = guestfs_create ();
4126   if (g == NULL) {
4127     PyErr_SetString (PyExc_RuntimeError,
4128                      \"guestfs.create: failed to allocate handle\");
4129     return NULL;
4130   }
4131   guestfs_set_error_handler (g, NULL, NULL);
4132   return put_handle (g);
4133 }
4134
4135 static PyObject *
4136 py_guestfs_close (PyObject *self, PyObject *args)
4137 {
4138   PyObject *py_g;
4139   guestfs_h *g;
4140
4141   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4142     return NULL;
4143   g = get_handle (py_g);
4144
4145   guestfs_close (g);
4146
4147   Py_INCREF (Py_None);
4148   return Py_None;
4149 }
4150
4151 ";
4152
4153   (* LVM structures, turned into Python dictionaries. *)
4154   List.iter (
4155     fun (typ, cols) ->
4156       pr "static PyObject *\n";
4157       pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4158       pr "{\n";
4159       pr "  PyObject *dict;\n";
4160       pr "\n";
4161       pr "  dict = PyDict_New ();\n";
4162       List.iter (
4163         function
4164         | name, `String ->
4165             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4166             pr "                        PyString_FromString (%s->%s));\n"
4167               typ name
4168         | name, `UUID ->
4169             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4170             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
4171               typ name
4172         | name, `Bytes ->
4173             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4174             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
4175               typ name
4176         | name, `Int ->
4177             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4178             pr "                        PyLong_FromLongLong (%s->%s));\n"
4179               typ name
4180         | name, `OptPercent ->
4181             pr "  if (%s->%s >= 0)\n" typ name;
4182             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
4183             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
4184               typ name;
4185             pr "  else {\n";
4186             pr "    Py_INCREF (Py_None);\n";
4187             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
4188             pr "  }\n"
4189       ) cols;
4190       pr "  return dict;\n";
4191       pr "};\n";
4192       pr "\n";
4193
4194       pr "static PyObject *\n";
4195       pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
4196       pr "{\n";
4197       pr "  PyObject *list;\n";
4198       pr "  int i;\n";
4199       pr "\n";
4200       pr "  list = PyList_New (%ss->len);\n" typ;
4201       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
4202       pr "    PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
4203       pr "  return list;\n";
4204       pr "};\n";
4205       pr "\n"
4206   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4207
4208   (* Stat structures, turned into Python dictionaries. *)
4209   List.iter (
4210     fun (typ, cols) ->
4211       pr "static PyObject *\n";
4212       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
4213       pr "{\n";
4214       pr "  PyObject *dict;\n";
4215       pr "\n";
4216       pr "  dict = PyDict_New ();\n";
4217       List.iter (
4218         function
4219         | name, `Int ->
4220             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4221             pr "                        PyLong_FromLongLong (%s->%s));\n"
4222               typ name
4223       ) cols;
4224       pr "  return dict;\n";
4225       pr "};\n";
4226       pr "\n";
4227   ) ["stat", stat_cols; "statvfs", statvfs_cols];
4228
4229   (* Python wrapper functions. *)
4230   List.iter (
4231     fun (name, style, _, _, _, _, _) ->
4232       pr "static PyObject *\n";
4233       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
4234       pr "{\n";
4235
4236       pr "  PyObject *py_g;\n";
4237       pr "  guestfs_h *g;\n";
4238       pr "  PyObject *py_r;\n";
4239
4240       let error_code =
4241         match fst style with
4242         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
4243         | RConstString _ -> pr "  const char *r;\n"; "NULL"
4244         | RString _ -> pr "  char *r;\n"; "NULL"
4245         | RStringList _ -> pr "  char **r;\n"; "NULL"
4246         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
4247         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
4248         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
4249         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
4250         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
4251         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
4252
4253       List.iter (
4254         function
4255         | String n -> pr "  const char *%s;\n" n
4256         | OptString n -> pr "  const char *%s;\n" n
4257         | StringList n ->
4258             pr "  PyObject *py_%s;\n" n;
4259             pr "  const char **%s;\n" n
4260         | Bool n -> pr "  int %s;\n" n
4261         | Int n -> pr "  int %s;\n" n
4262       ) (snd style);
4263
4264       pr "\n";
4265
4266       (* Convert the parameters. *)
4267       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
4268       List.iter (
4269         function
4270         | String _ -> pr "s"
4271         | OptString _ -> pr "z"
4272         | StringList _ -> pr "O"
4273         | Bool _ -> pr "i" (* XXX Python has booleans? *)
4274         | Int _ -> pr "i"
4275       ) (snd style);
4276       pr ":guestfs_%s\",\n" name;
4277       pr "                         &py_g";
4278       List.iter (
4279         function
4280         | String n -> pr ", &%s" n
4281         | OptString n -> pr ", &%s" n
4282         | StringList n -> pr ", &py_%s" n
4283         | Bool n -> pr ", &%s" n
4284         | Int n -> pr ", &%s" n
4285       ) (snd style);
4286
4287       pr "))\n";
4288       pr "    return NULL;\n";
4289
4290       pr "  g = get_handle (py_g);\n";
4291       List.iter (
4292         function
4293         | String _ | OptString _ | Bool _ | Int _ -> ()
4294         | StringList n ->
4295             pr "  %s = get_string_list (py_%s);\n" n n;
4296             pr "  if (!%s) return NULL;\n" n
4297       ) (snd style);
4298
4299       pr "\n";
4300
4301       pr "  r = guestfs_%s " name;
4302       generate_call_args ~handle:"g" style;
4303       pr ";\n";
4304
4305       List.iter (
4306         function
4307         | String _ | OptString _ | Bool _ | Int _ -> ()
4308         | StringList n ->
4309             pr "  free (%s);\n" n
4310       ) (snd style);
4311
4312       pr "  if (r == %s) {\n" error_code;
4313       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
4314       pr "    return NULL;\n";
4315       pr "  }\n";
4316       pr "\n";
4317
4318       (match fst style with
4319        | RErr ->
4320            pr "  Py_INCREF (Py_None);\n";
4321            pr "  py_r = Py_None;\n"
4322        | RInt _
4323        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
4324        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
4325        | RString _ ->
4326            pr "  py_r = PyString_FromString (r);\n";
4327            pr "  free (r);\n"
4328        | RStringList _ ->
4329            pr "  py_r = put_string_list (r);\n";
4330            pr "  free_strings (r);\n"
4331        | RIntBool _ ->
4332            pr "  py_r = PyTuple_New (2);\n";
4333            pr "  PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
4334            pr "  PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
4335            pr "  guestfs_free_int_bool (r);\n"
4336        | RPVList n ->
4337            pr "  py_r = put_lvm_pv_list (r);\n";
4338            pr "  guestfs_free_lvm_pv_list (r);\n"
4339        | RVGList n ->
4340            pr "  py_r = put_lvm_vg_list (r);\n";
4341            pr "  guestfs_free_lvm_vg_list (r);\n"
4342        | RLVList n ->
4343            pr "  py_r = put_lvm_lv_list (r);\n";
4344            pr "  guestfs_free_lvm_lv_list (r);\n"
4345        | RStat n ->
4346            pr "  py_r = put_stat (r);\n";
4347            pr "  free (r);\n"
4348        | RStatVFS n ->
4349            pr "  py_r = put_statvfs (r);\n";
4350            pr "  free (r);\n"
4351       );
4352
4353       pr "  return py_r;\n";
4354       pr "}\n";
4355       pr "\n"
4356   ) all_functions;
4357
4358   (* Table of functions. *)
4359   pr "static PyMethodDef methods[] = {\n";
4360   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
4361   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
4362   List.iter (
4363     fun (name, _, _, _, _, _, _) ->
4364       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
4365         name name
4366   ) all_functions;
4367   pr "  { NULL, NULL, 0, NULL }\n";
4368   pr "};\n";
4369   pr "\n";
4370
4371   (* Init function. *)
4372   pr "\
4373 void
4374 initlibguestfsmod (void)
4375 {
4376   static int initialized = 0;
4377
4378   if (initialized) return;
4379   Py_InitModule ((char *) \"libguestfsmod\", methods);
4380   initialized = 1;
4381 }
4382 "
4383
4384 (* Generate Python module. *)
4385 and generate_python_py () =
4386   generate_header HashStyle LGPLv2;
4387
4388   pr "import libguestfsmod\n";
4389   pr "\n";
4390   pr "class GuestFS:\n";
4391   pr "    def __init__ (self):\n";
4392   pr "        self._o = libguestfsmod.create ()\n";
4393   pr "\n";
4394   pr "    def __del__ (self):\n";
4395   pr "        libguestfsmod.close (self._o)\n";
4396   pr "\n";
4397
4398   List.iter (
4399     fun (name, style, _, _, _, _, _) ->
4400       pr "    def %s " name;
4401       generate_call_args ~handle:"self" style;
4402       pr ":\n";
4403       pr "        return libguestfsmod.%s " name;
4404       generate_call_args ~handle:"self._o" style;
4405       pr "\n";
4406       pr "\n";
4407   ) all_functions
4408
4409 let output_to filename =
4410   let filename_new = filename ^ ".new" in
4411   chan := open_out filename_new;
4412   let close () =
4413     close_out !chan;
4414     chan := stdout;
4415     Unix.rename filename_new filename;
4416     printf "written %s\n%!" filename;
4417   in
4418   close
4419
4420 (* Main program. *)
4421 let () =
4422   check_functions ();
4423
4424   if not (Sys.file_exists "configure.ac") then (
4425     eprintf "\
4426 You are probably running this from the wrong directory.
4427 Run it from the top source directory using the command
4428   src/generator.ml
4429 ";
4430     exit 1
4431   );
4432
4433   let close = output_to "src/guestfs_protocol.x" in
4434   generate_xdr ();
4435   close ();
4436
4437   let close = output_to "src/guestfs-structs.h" in
4438   generate_structs_h ();
4439   close ();
4440
4441   let close = output_to "src/guestfs-actions.h" in
4442   generate_actions_h ();
4443   close ();
4444
4445   let close = output_to "src/guestfs-actions.c" in
4446   generate_client_actions ();
4447   close ();
4448
4449   let close = output_to "daemon/actions.h" in
4450   generate_daemon_actions_h ();
4451   close ();
4452
4453   let close = output_to "daemon/stubs.c" in
4454   generate_daemon_actions ();
4455   close ();
4456
4457   let close = output_to "tests.c" in
4458   generate_tests ();
4459   close ();
4460
4461   let close = output_to "fish/cmds.c" in
4462   generate_fish_cmds ();
4463   close ();
4464
4465   let close = output_to "fish/completion.c" in
4466   generate_fish_completion ();
4467   close ();
4468
4469   let close = output_to "guestfs-structs.pod" in
4470   generate_structs_pod ();
4471   close ();
4472
4473   let close = output_to "guestfs-actions.pod" in
4474   generate_actions_pod ();
4475   close ();
4476
4477   let close = output_to "guestfish-actions.pod" in
4478   generate_fish_actions_pod ();
4479   close ();
4480
4481   let close = output_to "ocaml/guestfs.mli" in
4482   generate_ocaml_mli ();
4483   close ();
4484
4485   let close = output_to "ocaml/guestfs.ml" in
4486   generate_ocaml_ml ();
4487   close ();
4488
4489   let close = output_to "ocaml/guestfs_c_actions.c" in
4490   generate_ocaml_c ();
4491   close ();
4492
4493   let close = output_to "perl/Guestfs.xs" in
4494   generate_perl_xs ();
4495   close ();
4496
4497   let close = output_to "perl/lib/Sys/Guestfs.pm" in
4498   generate_perl_pm ();
4499   close ();
4500
4501   let close = output_to "python/guestfs-py.c" in
4502   generate_python_c ();
4503   close ();
4504
4505   let close = output_to "python/guestfs.py" in
4506   generate_python_py ();
4507   close ();