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