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