Begin to add the upload and download commands.
[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 send callback function. *)
2168       pr "static void %s_send_cb (guestfs_h *g, void *data)\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 "  ctx->cb_sequence = 1;\n";
2174       pr "  ml->main_loop_quit (ml, g);\n";
2175       pr "}\n";
2176       pr "\n";
2177
2178       (* Generate the reply callback function. *)
2179       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
2180       pr "{\n";
2181       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2182       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
2183       pr "\n";
2184       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
2185       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
2186       pr "    return;\n";
2187       pr "  }\n";
2188       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
2189       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
2190       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
2191         name;
2192       pr "      return;\n";
2193       pr "    }\n";
2194       pr "    goto done;\n";
2195       pr "  }\n";
2196
2197       (match fst style with
2198        | RErr -> ()
2199        | RConstString _ ->
2200            failwithf "RConstString cannot be returned from a daemon function"
2201        | RInt _ | RInt64 _
2202        | RBool _ | RString _ | RStringList _
2203        | RIntBool _
2204        | RPVList _ | RVGList _ | RLVList _
2205        | RStat _ | RStatVFS _
2206        | RHashtable _ ->
2207             pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
2208             pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
2209             pr "    return;\n";
2210             pr "  }\n";
2211       );
2212
2213       pr " done:\n";
2214       pr "  ctx->cb_sequence = 1001;\n";
2215       pr "  ml->main_loop_quit (ml, g);\n";
2216       pr "}\n\n";
2217
2218       (* Generate the action stub. *)
2219       generate_prototype ~extern:false ~semicolon:false ~newline:true
2220         ~handle:"g" name style;
2221
2222       let error_code =
2223         match fst style with
2224         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
2225         | RConstString _ ->
2226             failwithf "RConstString cannot be returned from a daemon function"
2227         | RString _ | RStringList _ | RIntBool _
2228         | RPVList _ | RVGList _ | RLVList _
2229         | RStat _ | RStatVFS _
2230         | RHashtable _ ->
2231             "NULL" in
2232
2233       pr "{\n";
2234
2235       (match snd style with
2236        | [] -> ()
2237        | _ -> pr "  struct %s_args args;\n" name
2238       );
2239
2240       pr "  struct %s_ctx ctx;\n" shortname;
2241       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
2242       pr "  int serial;\n";
2243       pr "\n";
2244       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
2245       pr "\n";
2246       pr "  memset (&ctx, 0, sizeof ctx);\n";
2247       pr "\n";
2248
2249       (* Dispatch the main header and arguments. *)
2250       (match snd style with
2251        | [] ->
2252            pr "  serial = guestfs__send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
2253              (String.uppercase shortname)
2254        | args ->
2255            List.iter (
2256              function
2257              | String n ->
2258                  pr "  args.%s = (char *) %s;\n" n n
2259              | OptString n ->
2260                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
2261              | StringList n ->
2262                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
2263                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
2264              | Bool n ->
2265                  pr "  args.%s = %s;\n" n n
2266              | Int n ->
2267                  pr "  args.%s = %s;\n" n n
2268              | FileIn _ | FileOut _ -> ()
2269            ) args;
2270            pr "  serial = guestfs__send (g, GUESTFS_PROC_%s,\n"
2271              (String.uppercase shortname);
2272            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
2273              name;
2274       );
2275       pr "  if (serial == -1)\n";
2276       pr "    return %s;\n" error_code;
2277       pr "\n";
2278
2279       (* Send the request. *)
2280       pr "  ctx.cb_sequence = 0;\n";
2281       pr "  guestfs_set_send_callback (g, %s_send_cb, &ctx);\n" shortname;
2282       pr "  (void) ml->main_loop_run (ml, g);\n";
2283       pr "  guestfs_set_send_callback (g, NULL, NULL);\n";
2284       pr "  if (ctx.cb_sequence != 1) {\n";
2285       pr "    error (g, \"%%s send failed, see earlier error messages\", \"%s\");\n" name;
2286       pr "    return %s;\n" error_code;
2287       pr "  }\n";
2288       pr "\n";
2289
2290       (* Send any additional files (FileIn) requested. *)
2291       List.iter (
2292         function
2293         | FileIn n ->
2294             pr "  if (guestfs__send_file_sync (ml, g, %s) == -1)\n" n;
2295             pr "    return %s;\n" error_code;
2296             pr "\n";
2297         | _ -> ()
2298       ) (snd style);
2299
2300       (* Wait for the reply from the remote end. *)
2301       pr "  guestfs__switch_to_receiving (g);\n";
2302       pr "  ctx.cb_sequence = 0;\n";
2303       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
2304       pr "  (void) ml->main_loop_run (ml, g);\n";
2305       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
2306       pr "  if (ctx.cb_sequence != 1001) {\n";
2307       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
2308       pr "    return %s;\n" error_code;
2309       pr "  }\n";
2310       pr "\n";
2311
2312       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
2313         (String.uppercase shortname);
2314       pr "    return %s;\n" error_code;
2315       pr "\n";
2316
2317       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
2318       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
2319       pr "    return %s;\n" error_code;
2320       pr "  }\n";
2321       pr "\n";
2322
2323       (* Expecting to receive further files (FileOut)? *)
2324       List.iter (
2325         function
2326         | FileOut n ->
2327             pr "  if (guestfs__receive_file_sync (ml, g, %s) == -1)\n" n;
2328             pr "    return %s;\n" error_code;
2329             pr "\n";
2330         | _ -> ()
2331       ) (snd style);
2332
2333       (match fst style with
2334        | RErr -> pr "  return 0;\n"
2335        | RInt n | RInt64 n | RBool n ->
2336            pr "  return ctx.ret.%s;\n" n
2337        | RConstString _ ->
2338            failwithf "RConstString cannot be returned from a daemon function"
2339        | RString n ->
2340            pr "  return ctx.ret.%s; /* caller will free */\n" n
2341        | RStringList n | RHashtable n ->
2342            pr "  /* caller will free this, but we need to add a NULL entry */\n";
2343            pr "  ctx.ret.%s.%s_val =\n" n n;
2344            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
2345            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
2346              n n;
2347            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
2348            pr "  return ctx.ret.%s.%s_val;\n" n n
2349        | RIntBool _ ->
2350            pr "  /* caller with free this */\n";
2351            pr "  return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
2352        | RPVList n | RVGList n | RLVList n
2353        | RStat n | RStatVFS n ->
2354            pr "  /* caller will free this */\n";
2355            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
2356       );
2357
2358       pr "}\n\n"
2359   ) daemon_functions
2360
2361 (* Generate daemon/actions.h. *)
2362 and generate_daemon_actions_h () =
2363   generate_header CStyle GPLv2;
2364
2365   pr "#include \"../src/guestfs_protocol.h\"\n";
2366   pr "\n";
2367
2368   List.iter (
2369     fun (name, style, _, _, _, _, _) ->
2370         generate_prototype
2371           ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
2372           name style;
2373   ) daemon_functions
2374
2375 (* Generate the server-side stubs. *)
2376 and generate_daemon_actions () =
2377   generate_header CStyle GPLv2;
2378
2379   pr "#define _GNU_SOURCE // for strchrnul\n";
2380   pr "\n";
2381   pr "#include <stdio.h>\n";
2382   pr "#include <stdlib.h>\n";
2383   pr "#include <string.h>\n";
2384   pr "#include <inttypes.h>\n";
2385   pr "#include <ctype.h>\n";
2386   pr "#include <rpc/types.h>\n";
2387   pr "#include <rpc/xdr.h>\n";
2388   pr "\n";
2389   pr "#include \"daemon.h\"\n";
2390   pr "#include \"../src/guestfs_protocol.h\"\n";
2391   pr "#include \"actions.h\"\n";
2392   pr "\n";
2393
2394   List.iter (
2395     fun (name, style, _, _, _, _, _) ->
2396       (* Generate server-side stubs. *)
2397       pr "static void %s_stub (XDR *xdr_in)\n" name;
2398       pr "{\n";
2399       let error_code =
2400         match fst style with
2401         | RErr | RInt _ -> pr "  int r;\n"; "-1"
2402         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
2403         | RBool _ -> pr "  int r;\n"; "-1"
2404         | RConstString _ ->
2405             failwithf "RConstString cannot be returned from a daemon function"
2406         | RString _ -> pr "  char *r;\n"; "NULL"
2407         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
2408         | RIntBool _ -> pr "  guestfs_%s_ret *r;\n" name; "NULL"
2409         | RPVList _ -> pr "  guestfs_lvm_int_pv_list *r;\n"; "NULL"
2410         | RVGList _ -> pr "  guestfs_lvm_int_vg_list *r;\n"; "NULL"
2411         | RLVList _ -> pr "  guestfs_lvm_int_lv_list *r;\n"; "NULL"
2412         | RStat _ -> pr "  guestfs_int_stat *r;\n"; "NULL"
2413         | RStatVFS _ -> pr "  guestfs_int_statvfs *r;\n"; "NULL" in
2414
2415       (match snd style with
2416        | [] -> ()
2417        | args ->
2418            pr "  struct guestfs_%s_args args;\n" name;
2419            List.iter (
2420              function
2421              | String n
2422              | OptString n -> pr "  const char *%s;\n" n
2423              | StringList n -> pr "  char **%s;\n" n
2424              | Bool n -> pr "  int %s;\n" n
2425              | Int n -> pr "  int %s;\n" n
2426              | FileIn _ | FileOut _ -> ()
2427            ) args
2428       );
2429       pr "\n";
2430
2431       (match snd style with
2432        | [] -> ()
2433        | args ->
2434            pr "  memset (&args, 0, sizeof args);\n";
2435            pr "\n";
2436            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
2437            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
2438            pr "    return;\n";
2439            pr "  }\n";
2440            List.iter (
2441              function
2442              | String n -> pr "  %s = args.%s;\n" n n
2443              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
2444              | StringList n ->
2445                  pr "  args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
2446                  pr "  args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
2447                  pr "  %s = args.%s.%s_val;\n" n n n
2448              | Bool n -> pr "  %s = args.%s;\n" n n
2449              | Int n -> pr "  %s = args.%s;\n" n n
2450              | FileIn _ | FileOut _ -> ()
2451            ) args;
2452            pr "\n"
2453       );
2454
2455       (* Don't want to call the impl with any FileIn or FileOut
2456        * parameters, since these go "outside" the RPC protocol.
2457        *)
2458       let argsnofile =
2459         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
2460           (snd style) in
2461       pr "  r = do_%s " name;
2462       generate_call_args argsnofile;
2463       pr ";\n";
2464
2465       pr "  if (r == %s)\n" error_code;
2466       pr "    /* do_%s has already called reply_with_error */\n" name;
2467       pr "    goto done;\n";
2468       pr "\n";
2469
2470       (* If there are any FileOut parameters, then the impl must
2471        * send its own reply.
2472        *)
2473       let no_reply =
2474         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
2475       if no_reply then
2476         pr "  /* do_%s has already sent a reply */\n" name
2477       else (
2478         match fst style with
2479         | RErr -> pr "  reply (NULL, NULL);\n"
2480         | RInt n | RInt64 n | RBool n ->
2481             pr "  struct guestfs_%s_ret ret;\n" name;
2482             pr "  ret.%s = r;\n" n;
2483             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2484               name
2485         | RConstString _ ->
2486             failwithf "RConstString cannot be returned from a daemon function"
2487         | RString n ->
2488             pr "  struct guestfs_%s_ret ret;\n" name;
2489             pr "  ret.%s = r;\n" n;
2490             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2491               name;
2492             pr "  free (r);\n"
2493         | RStringList n | RHashtable n ->
2494             pr "  struct guestfs_%s_ret ret;\n" name;
2495             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
2496             pr "  ret.%s.%s_val = r;\n" n n;
2497             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
2498               name;
2499             pr "  free_strings (r);\n"
2500         | RIntBool _ ->
2501             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
2502               name;
2503             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
2504         | RPVList n | RVGList n | RLVList n
2505         | RStat n | RStatVFS n ->
2506             pr "  struct guestfs_%s_ret ret;\n" name;
2507             pr "  ret.%s = *r;\n" n;
2508             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2509               name;
2510             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
2511               name
2512       );
2513
2514       (* Free the args. *)
2515       (match snd style with
2516        | [] ->
2517            pr "done: ;\n";
2518        | _ ->
2519            pr "done:\n";
2520            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
2521              name
2522       );
2523
2524       pr "}\n\n";
2525   ) daemon_functions;
2526
2527   (* Dispatch function. *)
2528   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
2529   pr "{\n";
2530   pr "  switch (proc_nr) {\n";
2531
2532   List.iter (
2533     fun (name, style, _, _, _, _, _) ->
2534         pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
2535         pr "      %s_stub (xdr_in);\n" name;
2536         pr "      break;\n"
2537   ) daemon_functions;
2538
2539   pr "    default:\n";
2540   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
2541   pr "  }\n";
2542   pr "}\n";
2543   pr "\n";
2544
2545   (* LVM columns and tokenization functions. *)
2546   (* XXX This generates crap code.  We should rethink how we
2547    * do this parsing.
2548    *)
2549   List.iter (
2550     function
2551     | typ, cols ->
2552         pr "static const char *lvm_%s_cols = \"%s\";\n"
2553           typ (String.concat "," (List.map fst cols));
2554         pr "\n";
2555
2556         pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
2557         pr "{\n";
2558         pr "  char *tok, *p, *next;\n";
2559         pr "  int i, j;\n";
2560         pr "\n";
2561         (*
2562         pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
2563         pr "\n";
2564         *)
2565         pr "  if (!str) {\n";
2566         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
2567         pr "    return -1;\n";
2568         pr "  }\n";
2569         pr "  if (!*str || isspace (*str)) {\n";
2570         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
2571         pr "    return -1;\n";
2572         pr "  }\n";
2573         pr "  tok = str;\n";
2574         List.iter (
2575           fun (name, coltype) ->
2576             pr "  if (!tok) {\n";
2577             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
2578             pr "    return -1;\n";
2579             pr "  }\n";
2580             pr "  p = strchrnul (tok, ',');\n";
2581             pr "  if (*p) next = p+1; else next = NULL;\n";
2582             pr "  *p = '\\0';\n";
2583             (match coltype with
2584              | `String ->
2585                  pr "  r->%s = strdup (tok);\n" name;
2586                  pr "  if (r->%s == NULL) {\n" name;
2587                  pr "    perror (\"strdup\");\n";
2588                  pr "    return -1;\n";
2589                  pr "  }\n"
2590              | `UUID ->
2591                  pr "  for (i = j = 0; i < 32; ++j) {\n";
2592                  pr "    if (tok[j] == '\\0') {\n";
2593                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
2594                  pr "      return -1;\n";
2595                  pr "    } else if (tok[j] != '-')\n";
2596                  pr "      r->%s[i++] = tok[j];\n" name;
2597                  pr "  }\n";
2598              | `Bytes ->
2599                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
2600                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2601                  pr "    return -1;\n";
2602                  pr "  }\n";
2603              | `Int ->
2604                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
2605                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2606                  pr "    return -1;\n";
2607                  pr "  }\n";
2608              | `OptPercent ->
2609                  pr "  if (tok[0] == '\\0')\n";
2610                  pr "    r->%s = -1;\n" name;
2611                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
2612                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
2613                  pr "    return -1;\n";
2614                  pr "  }\n";
2615             );
2616             pr "  tok = next;\n";
2617         ) cols;
2618
2619         pr "  if (tok != NULL) {\n";
2620         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
2621         pr "    return -1;\n";
2622         pr "  }\n";
2623         pr "  return 0;\n";
2624         pr "}\n";
2625         pr "\n";
2626
2627         pr "guestfs_lvm_int_%s_list *\n" typ;
2628         pr "parse_command_line_%ss (void)\n" typ;
2629         pr "{\n";
2630         pr "  char *out, *err;\n";
2631         pr "  char *p, *pend;\n";
2632         pr "  int r, i;\n";
2633         pr "  guestfs_lvm_int_%s_list *ret;\n" typ;
2634         pr "  void *newp;\n";
2635         pr "\n";
2636         pr "  ret = malloc (sizeof *ret);\n";
2637         pr "  if (!ret) {\n";
2638         pr "    reply_with_perror (\"malloc\");\n";
2639         pr "    return NULL;\n";
2640         pr "  }\n";
2641         pr "\n";
2642         pr "  ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
2643         pr "  ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
2644         pr "\n";
2645         pr "  r = command (&out, &err,\n";
2646         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
2647         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
2648         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
2649         pr "  if (r == -1) {\n";
2650         pr "    reply_with_error (\"%%s\", err);\n";
2651         pr "    free (out);\n";
2652         pr "    free (err);\n";
2653         pr "    free (ret);\n";
2654         pr "    return NULL;\n";
2655         pr "  }\n";
2656         pr "\n";
2657         pr "  free (err);\n";
2658         pr "\n";
2659         pr "  /* Tokenize each line of the output. */\n";
2660         pr "  p = out;\n";
2661         pr "  i = 0;\n";
2662         pr "  while (p) {\n";
2663         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
2664         pr "    if (pend) {\n";
2665         pr "      *pend = '\\0';\n";
2666         pr "      pend++;\n";
2667         pr "    }\n";
2668         pr "\n";
2669         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
2670         pr "      p++;\n";
2671         pr "\n";
2672         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
2673         pr "      p = pend;\n";
2674         pr "      continue;\n";
2675         pr "    }\n";
2676         pr "\n";
2677         pr "    /* Allocate some space to store this next entry. */\n";
2678         pr "    newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
2679         pr "                sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
2680         pr "    if (newp == NULL) {\n";
2681         pr "      reply_with_perror (\"realloc\");\n";
2682         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2683         pr "      free (ret);\n";
2684         pr "      free (out);\n";
2685         pr "      return NULL;\n";
2686         pr "    }\n";
2687         pr "    ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
2688         pr "\n";
2689         pr "    /* Tokenize the next entry. */\n";
2690         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
2691         pr "    if (r == -1) {\n";
2692         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
2693         pr "      free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
2694         pr "      free (ret);\n";
2695         pr "      free (out);\n";
2696         pr "      return NULL;\n";
2697         pr "    }\n";
2698         pr "\n";
2699         pr "    ++i;\n";
2700         pr "    p = pend;\n";
2701         pr "  }\n";
2702         pr "\n";
2703         pr "  ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
2704         pr "\n";
2705         pr "  free (out);\n";
2706         pr "  return ret;\n";
2707         pr "}\n"
2708
2709   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
2710
2711 (* Generate the tests. *)
2712 and generate_tests () =
2713   generate_header CStyle GPLv2;
2714
2715   pr "\
2716 #include <stdio.h>
2717 #include <stdlib.h>
2718 #include <string.h>
2719 #include <unistd.h>
2720 #include <sys/types.h>
2721 #include <fcntl.h>
2722
2723 #include \"guestfs.h\"
2724
2725 static guestfs_h *g;
2726 static int suppress_error = 0;
2727
2728 static void print_error (guestfs_h *g, void *data, const char *msg)
2729 {
2730   if (!suppress_error)
2731     fprintf (stderr, \"%%s\\n\", msg);
2732 }
2733
2734 static void print_strings (char * const * const argv)
2735 {
2736   int argc;
2737
2738   for (argc = 0; argv[argc] != NULL; ++argc)
2739     printf (\"\\t%%s\\n\", argv[argc]);
2740 }
2741
2742 /*
2743 static void print_table (char * const * const argv)
2744 {
2745   int i;
2746
2747   for (i = 0; argv[i] != NULL; i += 2)
2748     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
2749 }
2750 */
2751
2752 static void no_test_warnings (void)
2753 {
2754 ";
2755
2756   List.iter (
2757     function
2758     | name, _, _, _, [], _, _ ->
2759         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
2760     | name, _, _, _, tests, _, _ -> ()
2761   ) all_functions;
2762
2763   pr "}\n";
2764   pr "\n";
2765
2766   (* Generate the actual tests.  Note that we generate the tests
2767    * in reverse order, deliberately, so that (in general) the
2768    * newest tests run first.  This makes it quicker and easier to
2769    * debug them.
2770    *)
2771   let test_names =
2772     List.map (
2773       fun (name, _, _, _, tests, _, _) ->
2774         mapi (generate_one_test name) tests
2775     ) (List.rev all_functions) in
2776   let test_names = List.concat test_names in
2777   let nr_tests = List.length test_names in
2778
2779   pr "\
2780 int main (int argc, char *argv[])
2781 {
2782   char c = 0;
2783   int failed = 0;
2784   const char *srcdir;
2785   int fd;
2786   char buf[256];
2787   int nr_tests, test_num = 0;
2788
2789   no_test_warnings ();
2790
2791   g = guestfs_create ();
2792   if (g == NULL) {
2793     printf (\"guestfs_create FAILED\\n\");
2794     exit (1);
2795   }
2796
2797   guestfs_set_error_handler (g, print_error, NULL);
2798
2799   srcdir = getenv (\"srcdir\");
2800   if (!srcdir) srcdir = \".\";
2801   guestfs_set_path (g, srcdir);
2802
2803   snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
2804   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2805   if (fd == -1) {
2806     perror (buf);
2807     exit (1);
2808   }
2809   if (lseek (fd, %d, SEEK_SET) == -1) {
2810     perror (\"lseek\");
2811     close (fd);
2812     unlink (buf);
2813     exit (1);
2814   }
2815   if (write (fd, &c, 1) == -1) {
2816     perror (\"write\");
2817     close (fd);
2818     unlink (buf);
2819     exit (1);
2820   }
2821   if (close (fd) == -1) {
2822     perror (buf);
2823     unlink (buf);
2824     exit (1);
2825   }
2826   if (guestfs_add_drive (g, buf) == -1) {
2827     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2828     exit (1);
2829   }
2830
2831   snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
2832   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2833   if (fd == -1) {
2834     perror (buf);
2835     exit (1);
2836   }
2837   if (lseek (fd, %d, SEEK_SET) == -1) {
2838     perror (\"lseek\");
2839     close (fd);
2840     unlink (buf);
2841     exit (1);
2842   }
2843   if (write (fd, &c, 1) == -1) {
2844     perror (\"write\");
2845     close (fd);
2846     unlink (buf);
2847     exit (1);
2848   }
2849   if (close (fd) == -1) {
2850     perror (buf);
2851     unlink (buf);
2852     exit (1);
2853   }
2854   if (guestfs_add_drive (g, buf) == -1) {
2855     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2856     exit (1);
2857   }
2858
2859   snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
2860   fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
2861   if (fd == -1) {
2862     perror (buf);
2863     exit (1);
2864   }
2865   if (lseek (fd, %d, SEEK_SET) == -1) {
2866     perror (\"lseek\");
2867     close (fd);
2868     unlink (buf);
2869     exit (1);
2870   }
2871   if (write (fd, &c, 1) == -1) {
2872     perror (\"write\");
2873     close (fd);
2874     unlink (buf);
2875     exit (1);
2876   }
2877   if (close (fd) == -1) {
2878     perror (buf);
2879     unlink (buf);
2880     exit (1);
2881   }
2882   if (guestfs_add_drive (g, buf) == -1) {
2883     printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
2884     exit (1);
2885   }
2886
2887   if (guestfs_launch (g) == -1) {
2888     printf (\"guestfs_launch FAILED\\n\");
2889     exit (1);
2890   }
2891   if (guestfs_wait_ready (g) == -1) {
2892     printf (\"guestfs_wait_ready FAILED\\n\");
2893     exit (1);
2894   }
2895
2896   nr_tests = %d;
2897
2898 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
2899
2900   iteri (
2901     fun i test_name ->
2902       pr "  test_num++;\n";
2903       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
2904       pr "  if (%s () == -1) {\n" test_name;
2905       pr "    printf (\"%s FAILED\\n\");\n" test_name;
2906       pr "    failed++;\n";
2907       pr "  }\n";
2908   ) test_names;
2909   pr "\n";
2910
2911   pr "  guestfs_close (g);\n";
2912   pr "  snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
2913   pr "  unlink (buf);\n";
2914   pr "  snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
2915   pr "  unlink (buf);\n";
2916   pr "  snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
2917   pr "  unlink (buf);\n";
2918   pr "\n";
2919
2920   pr "  if (failed > 0) {\n";
2921   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
2922   pr "    exit (1);\n";
2923   pr "  }\n";
2924   pr "\n";
2925
2926   pr "  exit (0);\n";
2927   pr "}\n"
2928
2929 and generate_one_test name i (init, test) =
2930   let test_name = sprintf "test_%s_%d" name i in
2931
2932   pr "static int %s (void)\n" test_name;
2933   pr "{\n";
2934
2935   (match init with
2936    | InitNone -> ()
2937    | InitEmpty ->
2938        pr "  /* InitEmpty for %s (%d) */\n" name i;
2939        List.iter (generate_test_command_call test_name)
2940          [["umount_all"];
2941           ["lvm_remove_all"]]
2942    | InitBasicFS ->
2943        pr "  /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
2944        List.iter (generate_test_command_call test_name)
2945          [["umount_all"];
2946           ["lvm_remove_all"];
2947           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2948           ["mkfs"; "ext2"; "/dev/sda1"];
2949           ["mount"; "/dev/sda1"; "/"]]
2950    | InitBasicFSonLVM ->
2951        pr "  /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
2952          name i;
2953        List.iter (generate_test_command_call test_name)
2954          [["umount_all"];
2955           ["lvm_remove_all"];
2956           ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
2957           ["pvcreate"; "/dev/sda1"];
2958           ["vgcreate"; "VG"; "/dev/sda1"];
2959           ["lvcreate"; "LV"; "VG"; "8"];
2960           ["mkfs"; "ext2"; "/dev/VG/LV"];
2961           ["mount"; "/dev/VG/LV"; "/"]]
2962   );
2963
2964   let get_seq_last = function
2965     | [] ->
2966         failwithf "%s: you cannot use [] (empty list) when expecting a command"
2967           test_name
2968     | seq ->
2969         let seq = List.rev seq in
2970         List.rev (List.tl seq), List.hd seq
2971   in
2972
2973   (match test with
2974    | TestRun seq ->
2975        pr "  /* TestRun for %s (%d) */\n" name i;
2976        List.iter (generate_test_command_call test_name) seq
2977    | TestOutput (seq, expected) ->
2978        pr "  /* TestOutput for %s (%d) */\n" name i;
2979        let seq, last = get_seq_last seq in
2980        let test () =
2981          pr "    if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
2982          pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
2983          pr "      return -1;\n";
2984          pr "    }\n"
2985        in
2986        List.iter (generate_test_command_call test_name) seq;
2987        generate_test_command_call ~test test_name last
2988    | TestOutputList (seq, expected) ->
2989        pr "  /* TestOutputList for %s (%d) */\n" name i;
2990        let seq, last = get_seq_last seq in
2991        let test () =
2992          iteri (
2993            fun i str ->
2994              pr "    if (!r[%d]) {\n" i;
2995              pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
2996              pr "      print_strings (r);\n";
2997              pr "      return -1;\n";
2998              pr "    }\n";
2999              pr "    if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
3000              pr "      fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
3001              pr "      return -1;\n";
3002              pr "    }\n"
3003          ) expected;
3004          pr "    if (r[%d] != NULL) {\n" (List.length expected);
3005          pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
3006            test_name;
3007          pr "      print_strings (r);\n";
3008          pr "      return -1;\n";
3009          pr "    }\n"
3010        in
3011        List.iter (generate_test_command_call test_name) seq;
3012        generate_test_command_call ~test test_name last
3013    | TestOutputInt (seq, expected) ->
3014        pr "  /* TestOutputInt for %s (%d) */\n" name i;
3015        let seq, last = get_seq_last seq in
3016        let test () =
3017          pr "    if (r != %d) {\n" expected;
3018          pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
3019            test_name expected;
3020          pr "               (int) r);\n";
3021          pr "      return -1;\n";
3022          pr "    }\n"
3023        in
3024        List.iter (generate_test_command_call test_name) seq;
3025        generate_test_command_call ~test test_name last
3026    | TestOutputTrue seq ->
3027        pr "  /* TestOutputTrue for %s (%d) */\n" name i;
3028        let seq, last = get_seq_last seq in
3029        let test () =
3030          pr "    if (!r) {\n";
3031          pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
3032            test_name;
3033          pr "      return -1;\n";
3034          pr "    }\n"
3035        in
3036        List.iter (generate_test_command_call test_name) seq;
3037        generate_test_command_call ~test test_name last
3038    | TestOutputFalse seq ->
3039        pr "  /* TestOutputFalse for %s (%d) */\n" name i;
3040        let seq, last = get_seq_last seq in
3041        let test () =
3042          pr "    if (r) {\n";
3043          pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
3044            test_name;
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    | TestOutputLength (seq, expected) ->
3051        pr "  /* TestOutputLength for %s (%d) */\n" name i;
3052        let seq, last = get_seq_last seq in
3053        let test () =
3054          pr "    int j;\n";
3055          pr "    for (j = 0; j < %d; ++j)\n" expected;
3056          pr "      if (r[j] == NULL) {\n";
3057          pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
3058            test_name;
3059          pr "        print_strings (r);\n";
3060          pr "        return -1;\n";
3061          pr "      }\n";
3062          pr "    if (r[j] != NULL) {\n";
3063          pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
3064            test_name;
3065          pr "      print_strings (r);\n";
3066          pr "      return -1;\n";
3067          pr "    }\n"
3068        in
3069        List.iter (generate_test_command_call test_name) seq;
3070        generate_test_command_call ~test test_name last
3071    | TestOutputStruct (seq, checks) ->
3072        pr "  /* TestOutputStruct for %s (%d) */\n" name i;
3073        let seq, last = get_seq_last seq in
3074        let test () =
3075          List.iter (
3076            function
3077            | CompareWithInt (field, expected) ->
3078                pr "    if (r->%s != %d) {\n" field expected;
3079                pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
3080                  test_name field expected;
3081                pr "               (int) r->%s);\n" field;
3082                pr "      return -1;\n";
3083                pr "    }\n"
3084            | CompareWithString (field, expected) ->
3085                pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
3086                pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
3087                  test_name field expected;
3088                pr "               r->%s);\n" field;
3089                pr "      return -1;\n";
3090                pr "    }\n"
3091            | CompareFieldsIntEq (field1, field2) ->
3092                pr "    if (r->%s != r->%s) {\n" field1 field2;
3093                pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
3094                  test_name field1 field2;
3095                pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
3096                pr "      return -1;\n";
3097                pr "    }\n"
3098            | CompareFieldsStrEq (field1, field2) ->
3099                pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
3100                pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
3101                  test_name field1 field2;
3102                pr "               r->%s, r->%s);\n" field1 field2;
3103                pr "      return -1;\n";
3104                pr "    }\n"
3105          ) checks
3106        in
3107        List.iter (generate_test_command_call test_name) seq;
3108        generate_test_command_call ~test test_name last
3109    | TestLastFail seq ->
3110        pr "  /* TestLastFail for %s (%d) */\n" name i;
3111        let seq, last = get_seq_last seq in
3112        List.iter (generate_test_command_call test_name) seq;
3113        generate_test_command_call test_name ~expect_error:true last
3114   );
3115
3116   pr "  return 0;\n";
3117   pr "}\n";
3118   pr "\n";
3119   test_name
3120
3121 (* Generate the code to run a command, leaving the result in 'r'.
3122  * If you expect to get an error then you should set expect_error:true.
3123  *)
3124 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
3125   match cmd with
3126   | [] -> assert false
3127   | name :: args ->
3128       (* Look up the command to find out what args/ret it has. *)
3129       let style =
3130         try
3131           let _, style, _, _, _, _, _ =
3132             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
3133           style
3134         with Not_found ->
3135           failwithf "%s: in test, command %s was not found" test_name name in
3136
3137       if List.length (snd style) <> List.length args then
3138         failwithf "%s: in test, wrong number of args given to %s"
3139           test_name name;
3140
3141       pr "  {\n";
3142
3143       List.iter (
3144         function
3145         | String _, _
3146         | OptString _, _
3147         | Int _, _
3148         | Bool _, _ -> ()
3149         | FileIn _, _ | FileOut _, _ -> ()
3150         | StringList n, arg ->
3151             pr "    char *%s[] = {\n" n;
3152             let strs = string_split " " arg in
3153             List.iter (
3154               fun str -> pr "      \"%s\",\n" (c_quote str)
3155             ) strs;
3156             pr "      NULL\n";
3157             pr "    };\n";
3158       ) (List.combine (snd style) args);
3159
3160       let error_code =
3161         match fst style with
3162         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
3163         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
3164         | RConstString _ -> pr "    const char *r;\n"; "NULL"
3165         | RString _ -> pr "    char *r;\n"; "NULL"
3166         | RStringList _ | RHashtable _ ->
3167             pr "    char **r;\n";
3168             pr "    int i;\n";
3169             "NULL"
3170         | RIntBool _ ->
3171             pr "    struct guestfs_int_bool *r;\n"; "NULL"
3172         | RPVList _ ->
3173             pr "    struct guestfs_lvm_pv_list *r;\n"; "NULL"
3174         | RVGList _ ->
3175             pr "    struct guestfs_lvm_vg_list *r;\n"; "NULL"
3176         | RLVList _ ->
3177             pr "    struct guestfs_lvm_lv_list *r;\n"; "NULL"
3178         | RStat _ ->
3179             pr "    struct guestfs_stat *r;\n"; "NULL"
3180         | RStatVFS _ ->
3181             pr "    struct guestfs_statvfs *r;\n"; "NULL" in
3182
3183       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
3184       pr "    r = guestfs_%s (g" name;
3185
3186       (* Generate the parameters. *)
3187       List.iter (
3188         function
3189         | String _, arg
3190         | FileIn _, arg | FileOut _, arg ->
3191             pr ", \"%s\"" (c_quote arg)
3192         | OptString _, arg ->
3193             if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
3194         | StringList n, _ ->
3195             pr ", %s" n
3196         | Int _, arg ->
3197             let i =
3198               try int_of_string arg
3199               with Failure "int_of_string" ->
3200                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
3201             pr ", %d" i
3202         | Bool _, arg ->
3203             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
3204       ) (List.combine (snd style) args);
3205
3206       pr ");\n";
3207       if not expect_error then
3208         pr "    if (r == %s)\n" error_code
3209       else
3210         pr "    if (r != %s)\n" error_code;
3211       pr "      return -1;\n";
3212
3213       (* Insert the test code. *)
3214       (match test with
3215        | None -> ()
3216        | Some f -> f ()
3217       );
3218
3219       (match fst style with
3220        | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
3221        | RString _ -> pr "    free (r);\n"
3222        | RStringList _ | RHashtable _ ->
3223            pr "    for (i = 0; r[i] != NULL; ++i)\n";
3224            pr "      free (r[i]);\n";
3225            pr "    free (r);\n"
3226        | RIntBool _ ->
3227            pr "    guestfs_free_int_bool (r);\n"
3228        | RPVList _ ->
3229            pr "    guestfs_free_lvm_pv_list (r);\n"
3230        | RVGList _ ->
3231            pr "    guestfs_free_lvm_vg_list (r);\n"
3232        | RLVList _ ->
3233            pr "    guestfs_free_lvm_lv_list (r);\n"
3234        | RStat _ | RStatVFS _ ->
3235            pr "    free (r);\n"
3236       );
3237
3238       pr "  }\n"
3239
3240 and c_quote str =
3241   let str = replace_str str "\r" "\\r" in
3242   let str = replace_str str "\n" "\\n" in
3243   let str = replace_str str "\t" "\\t" in
3244   str
3245
3246 (* Generate a lot of different functions for guestfish. *)
3247 and generate_fish_cmds () =
3248   generate_header CStyle GPLv2;
3249
3250   let all_functions =
3251     List.filter (
3252       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3253     ) all_functions in
3254   let all_functions_sorted =
3255     List.filter (
3256       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3257     ) all_functions_sorted in
3258
3259   pr "#include <stdio.h>\n";
3260   pr "#include <stdlib.h>\n";
3261   pr "#include <string.h>\n";
3262   pr "#include <inttypes.h>\n";
3263   pr "\n";
3264   pr "#include <guestfs.h>\n";
3265   pr "#include \"fish.h\"\n";
3266   pr "\n";
3267
3268   (* list_commands function, which implements guestfish -h *)
3269   pr "void list_commands (void)\n";
3270   pr "{\n";
3271   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
3272   pr "  list_builtin_commands ();\n";
3273   List.iter (
3274     fun (name, _, _, flags, _, shortdesc, _) ->
3275       let name = replace_char name '_' '-' in
3276       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
3277         name shortdesc
3278   ) all_functions_sorted;
3279   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
3280   pr "}\n";
3281   pr "\n";
3282
3283   (* display_command function, which implements guestfish -h cmd *)
3284   pr "void display_command (const char *cmd)\n";
3285   pr "{\n";
3286   List.iter (
3287     fun (name, style, _, flags, _, shortdesc, longdesc) ->
3288       let name2 = replace_char name '_' '-' in
3289       let alias =
3290         try find_map (function FishAlias n -> Some n | _ -> None) flags
3291         with Not_found -> name in
3292       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3293       let synopsis =
3294         match snd style with
3295         | [] -> name2
3296         | args ->
3297             sprintf "%s <%s>"
3298               name2 (String.concat "> <" (List.map name_of_argt args)) in
3299
3300       let warnings =
3301         if List.mem ProtocolLimitWarning flags then
3302           ("\n\n" ^ protocol_limit_warning)
3303         else "" in
3304
3305       (* For DangerWillRobinson commands, we should probably have
3306        * guestfish prompt before allowing you to use them (especially
3307        * in interactive mode). XXX
3308        *)
3309       let warnings =
3310         warnings ^
3311           if List.mem DangerWillRobinson flags then
3312             ("\n\n" ^ danger_will_robinson)
3313           else "" in
3314
3315       let describe_alias =
3316         if name <> alias then
3317           sprintf "\n\nYou can use '%s' as an alias for this command." alias
3318         else "" in
3319
3320       pr "  if (";
3321       pr "strcasecmp (cmd, \"%s\") == 0" name;
3322       if name <> name2 then
3323         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3324       if name <> alias then
3325         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3326       pr ")\n";
3327       pr "    pod2text (\"%s - %s\", %S);\n"
3328         name2 shortdesc
3329         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
3330       pr "  else\n"
3331   ) all_functions;
3332   pr "    display_builtin_command (cmd);\n";
3333   pr "}\n";
3334   pr "\n";
3335
3336   (* print_{pv,vg,lv}_list functions *)
3337   List.iter (
3338     function
3339     | typ, cols ->
3340         pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
3341         pr "{\n";
3342         pr "  int i;\n";
3343         pr "\n";
3344         List.iter (
3345           function
3346           | name, `String ->
3347               pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
3348           | name, `UUID ->
3349               pr "  printf (\"%s: \");\n" name;
3350               pr "  for (i = 0; i < 32; ++i)\n";
3351               pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
3352               pr "  printf (\"\\n\");\n"
3353           | name, `Bytes ->
3354               pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
3355           | name, `Int ->
3356               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3357           | name, `OptPercent ->
3358               pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
3359                 typ name name typ name;
3360               pr "  else printf (\"%s: \\n\");\n" name
3361         ) cols;
3362         pr "}\n";
3363         pr "\n";
3364         pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
3365           typ typ typ;
3366         pr "{\n";
3367         pr "  int i;\n";
3368         pr "\n";
3369         pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
3370         pr "    print_%s (&%ss->val[i]);\n" typ typ;
3371         pr "}\n";
3372         pr "\n";
3373   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3374
3375   (* print_{stat,statvfs} functions *)
3376   List.iter (
3377     function
3378     | typ, cols ->
3379         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
3380         pr "{\n";
3381         List.iter (
3382           function
3383           | name, `Int ->
3384               pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
3385         ) cols;
3386         pr "}\n";
3387         pr "\n";
3388   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3389
3390   (* run_<action> actions *)
3391   List.iter (
3392     fun (name, style, _, flags, _, _, _) ->
3393       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
3394       pr "{\n";
3395       (match fst style with
3396        | RErr
3397        | RInt _
3398        | RBool _ -> pr "  int r;\n"
3399        | RInt64 _ -> pr "  int64_t r;\n"
3400        | RConstString _ -> pr "  const char *r;\n"
3401        | RString _ -> pr "  char *r;\n"
3402        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
3403        | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"
3404        | RPVList _ -> pr "  struct guestfs_lvm_pv_list *r;\n"
3405        | RVGList _ -> pr "  struct guestfs_lvm_vg_list *r;\n"
3406        | RLVList _ -> pr "  struct guestfs_lvm_lv_list *r;\n"
3407        | RStat _ -> pr "  struct guestfs_stat *r;\n"
3408        | RStatVFS _ -> pr "  struct guestfs_statvfs *r;\n"
3409       );
3410       List.iter (
3411         function
3412         | String n
3413         | OptString n
3414         | FileIn n
3415         | FileOut n -> pr "  const char *%s;\n" n
3416         | StringList n -> pr "  char **%s;\n" n
3417         | Bool n -> pr "  int %s;\n" n
3418         | Int n -> pr "  int %s;\n" n
3419       ) (snd style);
3420
3421       (* Check and convert parameters. *)
3422       let argc_expected = List.length (snd style) in
3423       pr "  if (argc != %d) {\n" argc_expected;
3424       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
3425         argc_expected;
3426       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
3427       pr "    return -1;\n";
3428       pr "  }\n";
3429       iteri (
3430         fun i ->
3431           function
3432           | String name -> pr "  %s = argv[%d];\n" name i
3433           | OptString name ->
3434               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
3435                 name i i
3436           | FileIn name ->
3437               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
3438                 name i i
3439           | FileOut name ->
3440               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
3441                 name i i
3442           | StringList name ->
3443               pr "  %s = parse_string_list (argv[%d]);\n" name i
3444           | Bool name ->
3445               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
3446           | Int name ->
3447               pr "  %s = atoi (argv[%d]);\n" name i
3448       ) (snd style);
3449
3450       (* Call C API function. *)
3451       let fn =
3452         try find_map (function FishAction n -> Some n | _ -> None) flags
3453         with Not_found -> sprintf "guestfs_%s" name in
3454       pr "  r = %s " fn;
3455       generate_call_args ~handle:"g" (snd style);
3456       pr ";\n";
3457
3458       (* Check return value for errors and display command results. *)
3459       (match fst style with
3460        | RErr -> pr "  return r;\n"
3461        | RInt _ ->
3462            pr "  if (r == -1) return -1;\n";
3463            pr "  printf (\"%%d\\n\", r);\n";
3464            pr "  return 0;\n"
3465        | RInt64 _ ->
3466            pr "  if (r == -1) return -1;\n";
3467            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
3468            pr "  return 0;\n"
3469        | RBool _ ->
3470            pr "  if (r == -1) return -1;\n";
3471            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
3472            pr "  return 0;\n"
3473        | RConstString _ ->
3474            pr "  if (r == NULL) return -1;\n";
3475            pr "  printf (\"%%s\\n\", r);\n";
3476            pr "  return 0;\n"
3477        | RString _ ->
3478            pr "  if (r == NULL) return -1;\n";
3479            pr "  printf (\"%%s\\n\", r);\n";
3480            pr "  free (r);\n";
3481            pr "  return 0;\n"
3482        | RStringList _ ->
3483            pr "  if (r == NULL) return -1;\n";
3484            pr "  print_strings (r);\n";
3485            pr "  free_strings (r);\n";
3486            pr "  return 0;\n"
3487        | RIntBool _ ->
3488            pr "  if (r == NULL) return -1;\n";
3489            pr "  printf (\"%%d, %%s\\n\", r->i,\n";
3490            pr "    r->b ? \"true\" : \"false\");\n";
3491            pr "  guestfs_free_int_bool (r);\n";
3492            pr "  return 0;\n"
3493        | RPVList _ ->
3494            pr "  if (r == NULL) return -1;\n";
3495            pr "  print_pv_list (r);\n";
3496            pr "  guestfs_free_lvm_pv_list (r);\n";
3497            pr "  return 0;\n"
3498        | RVGList _ ->
3499            pr "  if (r == NULL) return -1;\n";
3500            pr "  print_vg_list (r);\n";
3501            pr "  guestfs_free_lvm_vg_list (r);\n";
3502            pr "  return 0;\n"
3503        | RLVList _ ->
3504            pr "  if (r == NULL) return -1;\n";
3505            pr "  print_lv_list (r);\n";
3506            pr "  guestfs_free_lvm_lv_list (r);\n";
3507            pr "  return 0;\n"
3508        | RStat _ ->
3509            pr "  if (r == NULL) return -1;\n";
3510            pr "  print_stat (r);\n";
3511            pr "  free (r);\n";
3512            pr "  return 0;\n"
3513        | RStatVFS _ ->
3514            pr "  if (r == NULL) return -1;\n";
3515            pr "  print_statvfs (r);\n";
3516            pr "  free (r);\n";
3517            pr "  return 0;\n"
3518        | RHashtable _ ->
3519            pr "  if (r == NULL) return -1;\n";
3520            pr "  print_table (r);\n";
3521            pr "  free_strings (r);\n";
3522            pr "  return 0;\n"
3523       );
3524       pr "}\n";
3525       pr "\n"
3526   ) all_functions;
3527
3528   (* run_action function *)
3529   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
3530   pr "{\n";
3531   List.iter (
3532     fun (name, _, _, flags, _, _, _) ->
3533       let name2 = replace_char name '_' '-' in
3534       let alias =
3535         try find_map (function FishAlias n -> Some n | _ -> None) flags
3536         with Not_found -> name in
3537       pr "  if (";
3538       pr "strcasecmp (cmd, \"%s\") == 0" name;
3539       if name <> name2 then
3540         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
3541       if name <> alias then
3542         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
3543       pr ")\n";
3544       pr "    return run_%s (cmd, argc, argv);\n" name;
3545       pr "  else\n";
3546   ) all_functions;
3547   pr "    {\n";
3548   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
3549   pr "      return -1;\n";
3550   pr "    }\n";
3551   pr "  return 0;\n";
3552   pr "}\n";
3553   pr "\n"
3554
3555 (* Readline completion for guestfish. *)
3556 and generate_fish_completion () =
3557   generate_header CStyle GPLv2;
3558
3559   let all_functions =
3560     List.filter (
3561       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3562     ) all_functions in
3563
3564   pr "\
3565 #include <config.h>
3566
3567 #include <stdio.h>
3568 #include <stdlib.h>
3569 #include <string.h>
3570
3571 #ifdef HAVE_LIBREADLINE
3572 #include <readline/readline.h>
3573 #endif
3574
3575 #include \"fish.h\"
3576
3577 #ifdef HAVE_LIBREADLINE
3578
3579 static const char *commands[] = {
3580 ";
3581
3582   (* Get the commands and sort them, including the aliases. *)
3583   let commands =
3584     List.map (
3585       fun (name, _, _, flags, _, _, _) ->
3586         let name2 = replace_char name '_' '-' in
3587         let alias =
3588           try find_map (function FishAlias n -> Some n | _ -> None) flags
3589           with Not_found -> name in
3590
3591         if name <> alias then [name2; alias] else [name2]
3592     ) all_functions in
3593   let commands = List.flatten commands in
3594   let commands = List.sort compare commands in
3595
3596   List.iter (pr "  \"%s\",\n") commands;
3597
3598   pr "  NULL
3599 };
3600
3601 static char *
3602 generator (const char *text, int state)
3603 {
3604   static int index, len;
3605   const char *name;
3606
3607   if (!state) {
3608     index = 0;
3609     len = strlen (text);
3610   }
3611
3612   while ((name = commands[index]) != NULL) {
3613     index++;
3614     if (strncasecmp (name, text, len) == 0)
3615       return strdup (name);
3616   }
3617
3618   return NULL;
3619 }
3620
3621 #endif /* HAVE_LIBREADLINE */
3622
3623 char **do_completion (const char *text, int start, int end)
3624 {
3625   char **matches = NULL;
3626
3627 #ifdef HAVE_LIBREADLINE
3628   if (start == 0)
3629     matches = rl_completion_matches (text, generator);
3630 #endif
3631
3632   return matches;
3633 }
3634 ";
3635
3636 (* Generate the POD documentation for guestfish. *)
3637 and generate_fish_actions_pod () =
3638   let all_functions_sorted =
3639     List.filter (
3640       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
3641     ) all_functions_sorted in
3642
3643   List.iter (
3644     fun (name, style, _, flags, _, _, longdesc) ->
3645       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
3646       let name = replace_char name '_' '-' in
3647       let alias =
3648         try find_map (function FishAlias n -> Some n | _ -> None) flags
3649         with Not_found -> name in
3650
3651       pr "=head2 %s" name;
3652       if name <> alias then
3653         pr " | %s" alias;
3654       pr "\n";
3655       pr "\n";
3656       pr " %s" name;
3657       List.iter (
3658         function
3659         | String n -> pr " %s" n
3660         | OptString n -> pr " %s" n
3661         | StringList n -> pr " %s,..." n
3662         | Bool _ -> pr " true|false"
3663         | Int n -> pr " %s" n
3664         | FileIn n | FileOut n -> pr " (%s|-)" n
3665       ) (snd style);
3666       pr "\n";
3667       pr "\n";
3668       pr "%s\n\n" longdesc;
3669
3670       if List.exists (function FileIn _ | FileOut _ -> true
3671                       | _ -> false) (snd style) then
3672         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
3673
3674       if List.mem ProtocolLimitWarning flags then
3675         pr "%s\n\n" protocol_limit_warning;
3676
3677       if List.mem DangerWillRobinson flags then
3678         pr "%s\n\n" danger_will_robinson
3679   ) all_functions_sorted
3680
3681 (* Generate a C function prototype. *)
3682 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
3683     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
3684     ?(prefix = "")
3685     ?handle name style =
3686   if extern then pr "extern ";
3687   if static then pr "static ";
3688   (match fst style with
3689    | RErr -> pr "int "
3690    | RInt _ -> pr "int "
3691    | RInt64 _ -> pr "int64_t "
3692    | RBool _ -> pr "int "
3693    | RConstString _ -> pr "const char *"
3694    | RString _ -> pr "char *"
3695    | RStringList _ | RHashtable _ -> pr "char **"
3696    | RIntBool _ ->
3697        if not in_daemon then pr "struct guestfs_int_bool *"
3698        else pr "guestfs_%s_ret *" name
3699    | RPVList _ ->
3700        if not in_daemon then pr "struct guestfs_lvm_pv_list *"
3701        else pr "guestfs_lvm_int_pv_list *"
3702    | RVGList _ ->
3703        if not in_daemon then pr "struct guestfs_lvm_vg_list *"
3704        else pr "guestfs_lvm_int_vg_list *"
3705    | RLVList _ ->
3706        if not in_daemon then pr "struct guestfs_lvm_lv_list *"
3707        else pr "guestfs_lvm_int_lv_list *"
3708    | RStat _ ->
3709        if not in_daemon then pr "struct guestfs_stat *"
3710        else pr "guestfs_int_stat *"
3711    | RStatVFS _ ->
3712        if not in_daemon then pr "struct guestfs_statvfs *"
3713        else pr "guestfs_int_statvfs *"
3714   );
3715   pr "%s%s (" prefix name;
3716   if handle = None && List.length (snd style) = 0 then
3717     pr "void"
3718   else (
3719     let comma = ref false in
3720     (match handle with
3721      | None -> ()
3722      | Some handle -> pr "guestfs_h *%s" handle; comma := true
3723     );
3724     let next () =
3725       if !comma then (
3726         if single_line then pr ", " else pr ",\n\t\t"
3727       );
3728       comma := true
3729     in
3730     List.iter (
3731       function
3732       | String n
3733       | OptString n -> next (); pr "const char *%s" n
3734       | StringList n -> next (); pr "char * const* const %s" n
3735       | Bool n -> next (); pr "int %s" n
3736       | Int n -> next (); pr "int %s" n
3737       | FileIn n
3738       | FileOut n ->
3739           if not in_daemon then (next (); pr "const char *%s" n)
3740     ) (snd style);
3741   );
3742   pr ")";
3743   if semicolon then pr ";";
3744   if newline then pr "\n"
3745
3746 (* Generate C call arguments, eg "(handle, foo, bar)" *)
3747 and generate_call_args ?handle args =
3748   pr "(";
3749   let comma = ref false in
3750   (match handle with
3751    | None -> ()
3752    | Some handle -> pr "%s" handle; comma := true
3753   );
3754   List.iter (
3755     fun arg ->
3756       if !comma then pr ", ";
3757       comma := true;
3758       pr "%s" (name_of_argt arg)
3759   ) args;
3760   pr ")"
3761
3762 (* Generate the OCaml bindings interface. *)
3763 and generate_ocaml_mli () =
3764   generate_header OCamlStyle LGPLv2;
3765
3766   pr "\
3767 (** For API documentation you should refer to the C API
3768     in the guestfs(3) manual page.  The OCaml API uses almost
3769     exactly the same calls. *)
3770
3771 type t
3772 (** A [guestfs_h] handle. *)
3773
3774 exception Error of string
3775 (** This exception is raised when there is an error. *)
3776
3777 val create : unit -> t
3778
3779 val close : t -> unit
3780 (** Handles are closed by the garbage collector when they become
3781     unreferenced, but callers can also call this in order to
3782     provide predictable cleanup. *)
3783
3784 ";
3785   generate_ocaml_lvm_structure_decls ();
3786
3787   generate_ocaml_stat_structure_decls ();
3788
3789   (* The actions. *)
3790   List.iter (
3791     fun (name, style, _, _, _, shortdesc, _) ->
3792       generate_ocaml_prototype name style;
3793       pr "(** %s *)\n" shortdesc;
3794       pr "\n"
3795   ) all_functions
3796
3797 (* Generate the OCaml bindings implementation. *)
3798 and generate_ocaml_ml () =
3799   generate_header OCamlStyle LGPLv2;
3800
3801   pr "\
3802 type t
3803 exception Error of string
3804 external create : unit -> t = \"ocaml_guestfs_create\"
3805 external close : t -> unit = \"ocaml_guestfs_close\"
3806
3807 let () =
3808   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
3809
3810 ";
3811
3812   generate_ocaml_lvm_structure_decls ();
3813
3814   generate_ocaml_stat_structure_decls ();
3815
3816   (* The actions. *)
3817   List.iter (
3818     fun (name, style, _, _, _, shortdesc, _) ->
3819       generate_ocaml_prototype ~is_external:true name style;
3820   ) all_functions
3821
3822 (* Generate the OCaml bindings C implementation. *)
3823 and generate_ocaml_c () =
3824   generate_header CStyle LGPLv2;
3825
3826   pr "\
3827 #include <stdio.h>
3828 #include <stdlib.h>
3829 #include <string.h>
3830
3831 #include <caml/config.h>
3832 #include <caml/alloc.h>
3833 #include <caml/callback.h>
3834 #include <caml/fail.h>
3835 #include <caml/memory.h>
3836 #include <caml/mlvalues.h>
3837 #include <caml/signals.h>
3838
3839 #include <guestfs.h>
3840
3841 #include \"guestfs_c.h\"
3842
3843 /* Copy a hashtable of string pairs into an assoc-list.  We return
3844  * the list in reverse order, but hashtables aren't supposed to be
3845  * ordered anyway.
3846  */
3847 static CAMLprim value
3848 copy_table (char * const * argv)
3849 {
3850   CAMLparam0 ();
3851   CAMLlocal5 (rv, pairv, kv, vv, cons);
3852   int i;
3853
3854   rv = Val_int (0);
3855   for (i = 0; argv[i] != NULL; i += 2) {
3856     kv = caml_copy_string (argv[i]);
3857     vv = caml_copy_string (argv[i+1]);
3858     pairv = caml_alloc (2, 0);
3859     Store_field (pairv, 0, kv);
3860     Store_field (pairv, 1, vv);
3861     cons = caml_alloc (2, 0);
3862     Store_field (cons, 1, rv);
3863     rv = cons;
3864     Store_field (cons, 0, pairv);
3865   }
3866
3867   CAMLreturn (rv);
3868 }
3869
3870 ";
3871
3872   (* LVM struct copy functions. *)
3873   List.iter (
3874     fun (typ, cols) ->
3875       let has_optpercent_col =
3876         List.exists (function (_, `OptPercent) -> true | _ -> false) cols in
3877
3878       pr "static CAMLprim value\n";
3879       pr "copy_lvm_%s (const struct guestfs_lvm_%s *%s)\n" typ typ typ;
3880       pr "{\n";
3881       pr "  CAMLparam0 ();\n";
3882       if has_optpercent_col then
3883         pr "  CAMLlocal3 (rv, v, v2);\n"
3884       else
3885         pr "  CAMLlocal2 (rv, v);\n";
3886       pr "\n";
3887       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3888       iteri (
3889         fun i col ->
3890           (match col with
3891            | name, `String ->
3892                pr "  v = caml_copy_string (%s->%s);\n" typ name
3893            | name, `UUID ->
3894                pr "  v = caml_alloc_string (32);\n";
3895                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
3896            | name, `Bytes
3897            | name, `Int ->
3898                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3899            | name, `OptPercent ->
3900                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
3901                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
3902                pr "    v = caml_alloc (1, 0);\n";
3903                pr "    Store_field (v, 0, v2);\n";
3904                pr "  } else /* None */\n";
3905                pr "    v = Val_int (0);\n";
3906           );
3907           pr "  Store_field (rv, %d, v);\n" i
3908       ) cols;
3909       pr "  CAMLreturn (rv);\n";
3910       pr "}\n";
3911       pr "\n";
3912
3913       pr "static CAMLprim value\n";
3914       pr "copy_lvm_%s_list (const struct guestfs_lvm_%s_list *%ss)\n"
3915         typ typ typ;
3916       pr "{\n";
3917       pr "  CAMLparam0 ();\n";
3918       pr "  CAMLlocal2 (rv, v);\n";
3919       pr "  int i;\n";
3920       pr "\n";
3921       pr "  if (%ss->len == 0)\n" typ;
3922       pr "    CAMLreturn (Atom (0));\n";
3923       pr "  else {\n";
3924       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
3925       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
3926       pr "      v = copy_lvm_%s (&%ss->val[i]);\n" typ typ;
3927       pr "      caml_modify (&Field (rv, i), v);\n";
3928       pr "    }\n";
3929       pr "    CAMLreturn (rv);\n";
3930       pr "  }\n";
3931       pr "}\n";
3932       pr "\n";
3933   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
3934
3935   (* Stat copy functions. *)
3936   List.iter (
3937     fun (typ, cols) ->
3938       pr "static CAMLprim value\n";
3939       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
3940       pr "{\n";
3941       pr "  CAMLparam0 ();\n";
3942       pr "  CAMLlocal2 (rv, v);\n";
3943       pr "\n";
3944       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
3945       iteri (
3946         fun i col ->
3947           (match col with
3948            | name, `Int ->
3949                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
3950           );
3951           pr "  Store_field (rv, %d, v);\n" i
3952       ) cols;
3953       pr "  CAMLreturn (rv);\n";
3954       pr "}\n";
3955       pr "\n";
3956   ) ["stat", stat_cols; "statvfs", statvfs_cols];
3957
3958   (* The wrappers. *)
3959   List.iter (
3960     fun (name, style, _, _, _, _, _) ->
3961       let params =
3962         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
3963
3964       pr "CAMLprim value\n";
3965       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
3966       List.iter (pr ", value %s") (List.tl params);
3967       pr ")\n";
3968       pr "{\n";
3969
3970       (match params with
3971        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
3972            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
3973            pr "  CAMLxparam%d (%s);\n"
3974              (List.length rest) (String.concat ", " rest)
3975        | ps ->
3976            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
3977       );
3978       pr "  CAMLlocal1 (rv);\n";
3979       pr "\n";
3980
3981       pr "  guestfs_h *g = Guestfs_val (gv);\n";
3982       pr "  if (g == NULL)\n";
3983       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
3984       pr "\n";
3985
3986       List.iter (
3987         function
3988         | String n
3989         | FileIn n
3990         | FileOut n ->
3991             pr "  const char *%s = String_val (%sv);\n" n n
3992         | OptString n ->
3993             pr "  const char *%s =\n" n;
3994             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
3995               n n
3996         | StringList n ->
3997             pr "  char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
3998         | Bool n ->
3999             pr "  int %s = Bool_val (%sv);\n" n n
4000         | Int n ->
4001             pr "  int %s = Int_val (%sv);\n" n n
4002       ) (snd style);
4003       let error_code =
4004         match fst style with
4005         | RErr -> pr "  int r;\n"; "-1"
4006         | RInt _ -> pr "  int r;\n"; "-1"
4007         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4008         | RBool _ -> pr "  int r;\n"; "-1"
4009         | RConstString _ -> pr "  const char *r;\n"; "NULL"
4010         | RString _ -> pr "  char *r;\n"; "NULL"
4011         | RStringList _ ->
4012             pr "  int i;\n";
4013             pr "  char **r;\n";
4014             "NULL"
4015         | RIntBool _ ->
4016             pr "  struct guestfs_int_bool *r;\n"; "NULL"
4017         | RPVList _ ->
4018             pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
4019         | RVGList _ ->
4020             pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
4021         | RLVList _ ->
4022             pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
4023         | RStat _ ->
4024             pr "  struct guestfs_stat *r;\n"; "NULL"
4025         | RStatVFS _ ->
4026             pr "  struct guestfs_statvfs *r;\n"; "NULL"
4027         | RHashtable _ ->
4028             pr "  int i;\n";
4029             pr "  char **r;\n";
4030             "NULL" in
4031       pr "\n";
4032
4033       pr "  caml_enter_blocking_section ();\n";
4034       pr "  r = guestfs_%s " name;
4035       generate_call_args ~handle:"g" (snd style);
4036       pr ";\n";
4037       pr "  caml_leave_blocking_section ();\n";
4038
4039       List.iter (
4040         function
4041         | StringList n ->
4042             pr "  ocaml_guestfs_free_strings (%s);\n" n;
4043         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
4044       ) (snd style);
4045
4046       pr "  if (r == %s)\n" error_code;
4047       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
4048       pr "\n";
4049
4050       (match fst style with
4051        | RErr -> pr "  rv = Val_unit;\n"
4052        | RInt _ -> pr "  rv = Val_int (r);\n"
4053        | RInt64 _ ->
4054            pr "  rv = caml_copy_int64 (r);\n"
4055        | RBool _ -> pr "  rv = Val_bool (r);\n"
4056        | RConstString _ -> pr "  rv = caml_copy_string (r);\n"
4057        | RString _ ->
4058            pr "  rv = caml_copy_string (r);\n";
4059            pr "  free (r);\n"
4060        | RStringList _ ->
4061            pr "  rv = caml_copy_string_array ((const char **) r);\n";
4062            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4063            pr "  free (r);\n"
4064        | RIntBool _ ->
4065            pr "  rv = caml_alloc (2, 0);\n";
4066            pr "  Store_field (rv, 0, Val_int (r->i));\n";
4067            pr "  Store_field (rv, 1, Val_bool (r->b));\n";
4068            pr "  guestfs_free_int_bool (r);\n";
4069        | RPVList _ ->
4070            pr "  rv = copy_lvm_pv_list (r);\n";
4071            pr "  guestfs_free_lvm_pv_list (r);\n";
4072        | RVGList _ ->
4073            pr "  rv = copy_lvm_vg_list (r);\n";
4074            pr "  guestfs_free_lvm_vg_list (r);\n";
4075        | RLVList _ ->
4076            pr "  rv = copy_lvm_lv_list (r);\n";
4077            pr "  guestfs_free_lvm_lv_list (r);\n";
4078        | RStat _ ->
4079            pr "  rv = copy_stat (r);\n";
4080            pr "  free (r);\n";
4081        | RStatVFS _ ->
4082            pr "  rv = copy_statvfs (r);\n";
4083            pr "  free (r);\n";
4084        | RHashtable _ ->
4085            pr "  rv = copy_table (r);\n";
4086            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
4087            pr "  free (r);\n";
4088       );
4089
4090       pr "  CAMLreturn (rv);\n";
4091       pr "}\n";
4092       pr "\n";
4093
4094       if List.length params > 5 then (
4095         pr "CAMLprim value\n";
4096         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
4097         pr "{\n";
4098         pr "  return ocaml_guestfs_%s (argv[0]" name;
4099         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
4100         pr ");\n";
4101         pr "}\n";
4102         pr "\n"
4103       )
4104   ) all_functions
4105
4106 and generate_ocaml_lvm_structure_decls () =
4107   List.iter (
4108     fun (typ, cols) ->
4109       pr "type lvm_%s = {\n" typ;
4110       List.iter (
4111         function
4112         | name, `String -> pr "  %s : string;\n" name
4113         | name, `UUID -> pr "  %s : string;\n" name
4114         | name, `Bytes -> pr "  %s : int64;\n" name
4115         | name, `Int -> pr "  %s : int64;\n" name
4116         | name, `OptPercent -> pr "  %s : float option;\n" name
4117       ) cols;
4118       pr "}\n";
4119       pr "\n"
4120   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
4121
4122 and generate_ocaml_stat_structure_decls () =
4123   List.iter (
4124     fun (typ, cols) ->
4125       pr "type %s = {\n" typ;
4126       List.iter (
4127         function
4128         | name, `Int -> pr "  %s : int64;\n" name
4129       ) cols;
4130       pr "}\n";
4131       pr "\n"
4132   ) ["stat", stat_cols; "statvfs", statvfs_cols]
4133
4134 and generate_ocaml_prototype ?(is_external = false) name style =
4135   if is_external then pr "external " else pr "val ";
4136   pr "%s : t -> " name;
4137   List.iter (
4138     function
4139     | String _ | FileIn _ | FileOut _ -> pr "string -> "
4140     | OptString _ -> pr "string option -> "
4141     | StringList _ -> pr "string array -> "
4142     | Bool _ -> pr "bool -> "
4143     | Int _ -> pr "int -> "
4144   ) (snd style);
4145   (match fst style with
4146    | RErr -> pr "unit" (* all errors are turned into exceptions *)
4147    | RInt _ -> pr "int"
4148    | RInt64 _ -> pr "int64"
4149    | RBool _ -> pr "bool"
4150    | RConstString _ -> pr "string"
4151    | RString _ -> pr "string"
4152    | RStringList _ -> pr "string array"
4153    | RIntBool _ -> pr "int * bool"
4154    | RPVList _ -> pr "lvm_pv array"
4155    | RVGList _ -> pr "lvm_vg array"
4156    | RLVList _ -> pr "lvm_lv array"
4157    | RStat _ -> pr "stat"
4158    | RStatVFS _ -> pr "statvfs"
4159    | RHashtable _ -> pr "(string * string) list"
4160   );
4161   if is_external then (
4162     pr " = ";
4163     if List.length (snd style) + 1 > 5 then
4164       pr "\"ocaml_guestfs_%s_byte\" " name;
4165     pr "\"ocaml_guestfs_%s\"" name
4166   );
4167   pr "\n"
4168
4169 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
4170 and generate_perl_xs () =
4171   generate_header CStyle LGPLv2;
4172
4173   pr "\
4174 #include \"EXTERN.h\"
4175 #include \"perl.h\"
4176 #include \"XSUB.h\"
4177
4178 #include <guestfs.h>
4179
4180 #ifndef PRId64
4181 #define PRId64 \"lld\"
4182 #endif
4183
4184 static SV *
4185 my_newSVll(long long val) {
4186 #ifdef USE_64_BIT_ALL
4187   return newSViv(val);
4188 #else
4189   char buf[100];
4190   int len;
4191   len = snprintf(buf, 100, \"%%\" PRId64, val);
4192   return newSVpv(buf, len);
4193 #endif
4194 }
4195
4196 #ifndef PRIu64
4197 #define PRIu64 \"llu\"
4198 #endif
4199
4200 static SV *
4201 my_newSVull(unsigned long long val) {
4202 #ifdef USE_64_BIT_ALL
4203   return newSVuv(val);
4204 #else
4205   char buf[100];
4206   int len;
4207   len = snprintf(buf, 100, \"%%\" PRIu64, val);
4208   return newSVpv(buf, len);
4209 #endif
4210 }
4211
4212 /* http://www.perlmonks.org/?node_id=680842 */
4213 static char **
4214 XS_unpack_charPtrPtr (SV *arg) {
4215   char **ret;
4216   AV *av;
4217   I32 i;
4218
4219   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
4220     croak (\"array reference expected\");
4221   }
4222
4223   av = (AV *)SvRV (arg);
4224   ret = (char **)malloc (av_len (av) + 1 + 1);
4225
4226   for (i = 0; i <= av_len (av); i++) {
4227     SV **elem = av_fetch (av, i, 0);
4228
4229     if (!elem || !*elem)
4230       croak (\"missing element in list\");
4231
4232     ret[i] = SvPV_nolen (*elem);
4233   }
4234
4235   ret[i] = NULL;
4236
4237   return ret;
4238 }
4239
4240 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
4241
4242 guestfs_h *
4243 _create ()
4244    CODE:
4245       RETVAL = guestfs_create ();
4246       if (!RETVAL)
4247         croak (\"could not create guestfs handle\");
4248       guestfs_set_error_handler (RETVAL, NULL, NULL);
4249  OUTPUT:
4250       RETVAL
4251
4252 void
4253 DESTROY (g)
4254       guestfs_h *g;
4255  PPCODE:
4256       guestfs_close (g);
4257
4258 ";
4259
4260   List.iter (
4261     fun (name, style, _, _, _, _, _) ->
4262       (match fst style with
4263        | RErr -> pr "void\n"
4264        | RInt _ -> pr "SV *\n"
4265        | RInt64 _ -> pr "SV *\n"
4266        | RBool _ -> pr "SV *\n"
4267        | RConstString _ -> pr "SV *\n"
4268        | RString _ -> pr "SV *\n"
4269        | RStringList _
4270        | RIntBool _
4271        | RPVList _ | RVGList _ | RLVList _
4272        | RStat _ | RStatVFS _
4273        | RHashtable _ ->
4274            pr "void\n" (* all lists returned implictly on the stack *)
4275       );
4276       (* Call and arguments. *)
4277       pr "%s " name;
4278       generate_call_args ~handle:"g" (snd style);
4279       pr "\n";
4280       pr "      guestfs_h *g;\n";
4281       List.iter (
4282         function
4283         | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
4284         | OptString n -> pr "      char *%s;\n" n
4285         | StringList n -> pr "      char **%s;\n" n
4286         | Bool n -> pr "      int %s;\n" n
4287         | Int n -> pr "      int %s;\n" n
4288       ) (snd style);
4289
4290       let do_cleanups () =
4291         List.iter (
4292           function
4293           | String _ | OptString _ | Bool _ | Int _
4294           | FileIn _ | FileOut _ -> ()
4295           | StringList n -> pr "      free (%s);\n" n
4296         ) (snd style)
4297       in
4298
4299       (* Code. *)
4300       (match fst style with
4301        | RErr ->
4302            pr "PREINIT:\n";
4303            pr "      int r;\n";
4304            pr " PPCODE:\n";
4305            pr "      r = guestfs_%s " name;
4306            generate_call_args ~handle:"g" (snd style);
4307            pr ";\n";
4308            do_cleanups ();
4309            pr "      if (r == -1)\n";
4310            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4311        | RInt n
4312        | RBool n ->
4313            pr "PREINIT:\n";
4314            pr "      int %s;\n" n;
4315            pr "   CODE:\n";
4316            pr "      %s = guestfs_%s " n name;
4317            generate_call_args ~handle:"g" (snd style);
4318            pr ";\n";
4319            do_cleanups ();
4320            pr "      if (%s == -1)\n" n;
4321            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4322            pr "      RETVAL = newSViv (%s);\n" n;
4323            pr " OUTPUT:\n";
4324            pr "      RETVAL\n"
4325        | RInt64 n ->
4326            pr "PREINIT:\n";
4327            pr "      int64_t %s;\n" n;
4328            pr "   CODE:\n";
4329            pr "      %s = guestfs_%s " n name;
4330            generate_call_args ~handle:"g" (snd style);
4331            pr ";\n";
4332            do_cleanups ();
4333            pr "      if (%s == -1)\n" n;
4334            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4335            pr "      RETVAL = my_newSVll (%s);\n" n;
4336            pr " OUTPUT:\n";
4337            pr "      RETVAL\n"
4338        | RConstString n ->
4339            pr "PREINIT:\n";
4340            pr "      const char *%s;\n" n;
4341            pr "   CODE:\n";
4342            pr "      %s = guestfs_%s " n name;
4343            generate_call_args ~handle:"g" (snd style);
4344            pr ";\n";
4345            do_cleanups ();
4346            pr "      if (%s == NULL)\n" n;
4347            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4348            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4349            pr " OUTPUT:\n";
4350            pr "      RETVAL\n"
4351        | RString n ->
4352            pr "PREINIT:\n";
4353            pr "      char *%s;\n" n;
4354            pr "   CODE:\n";
4355            pr "      %s = guestfs_%s " n name;
4356            generate_call_args ~handle:"g" (snd style);
4357            pr ";\n";
4358            do_cleanups ();
4359            pr "      if (%s == NULL)\n" n;
4360            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4361            pr "      RETVAL = newSVpv (%s, 0);\n" n;
4362            pr "      free (%s);\n" n;
4363            pr " OUTPUT:\n";
4364            pr "      RETVAL\n"
4365        | RStringList n | RHashtable n ->
4366            pr "PREINIT:\n";
4367            pr "      char **%s;\n" n;
4368            pr "      int i, n;\n";
4369            pr " PPCODE:\n";
4370            pr "      %s = guestfs_%s " n name;
4371            generate_call_args ~handle:"g" (snd style);
4372            pr ";\n";
4373            do_cleanups ();
4374            pr "      if (%s == NULL)\n" n;
4375            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4376            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
4377            pr "      EXTEND (SP, n);\n";
4378            pr "      for (i = 0; i < n; ++i) {\n";
4379            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
4380            pr "        free (%s[i]);\n" n;
4381            pr "      }\n";
4382            pr "      free (%s);\n" n;
4383        | RIntBool _ ->
4384            pr "PREINIT:\n";
4385            pr "      struct guestfs_int_bool *r;\n";
4386            pr " PPCODE:\n";
4387            pr "      r = guestfs_%s " name;
4388            generate_call_args ~handle:"g" (snd style);
4389            pr ";\n";
4390            do_cleanups ();
4391            pr "      if (r == NULL)\n";
4392            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4393            pr "      EXTEND (SP, 2);\n";
4394            pr "      PUSHs (sv_2mortal (newSViv (r->i)));\n";
4395            pr "      PUSHs (sv_2mortal (newSViv (r->b)));\n";
4396            pr "      guestfs_free_int_bool (r);\n";
4397        | RPVList n ->
4398            generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
4399        | RVGList n ->
4400            generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
4401        | RLVList n ->
4402            generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
4403        | RStat n ->
4404            generate_perl_stat_code "stat" stat_cols name style n do_cleanups
4405        | RStatVFS n ->
4406            generate_perl_stat_code
4407              "statvfs" statvfs_cols name style n do_cleanups
4408       );
4409
4410       pr "\n"
4411   ) all_functions
4412
4413 and generate_perl_lvm_code typ cols name style n do_cleanups =
4414   pr "PREINIT:\n";
4415   pr "      struct guestfs_lvm_%s_list *%s;\n" typ n;
4416   pr "      int i;\n";
4417   pr "      HV *hv;\n";
4418   pr " PPCODE:\n";
4419   pr "      %s = guestfs_%s " n name;
4420   generate_call_args ~handle:"g" (snd style);
4421   pr ";\n";
4422   do_cleanups ();
4423   pr "      if (%s == NULL)\n" n;
4424   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4425   pr "      EXTEND (SP, %s->len);\n" n;
4426   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
4427   pr "        hv = newHV ();\n";
4428   List.iter (
4429     function
4430     | name, `String ->
4431         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
4432           name (String.length name) n name
4433     | name, `UUID ->
4434         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
4435           name (String.length name) n name
4436     | name, `Bytes ->
4437         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
4438           name (String.length name) n name
4439     | name, `Int ->
4440         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
4441           name (String.length name) n name
4442     | name, `OptPercent ->
4443         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
4444           name (String.length name) n name
4445   ) cols;
4446   pr "        PUSHs (sv_2mortal ((SV *) hv));\n";
4447   pr "      }\n";
4448   pr "      guestfs_free_lvm_%s_list (%s);\n" typ n
4449
4450 and generate_perl_stat_code typ cols name style n do_cleanups =
4451   pr "PREINIT:\n";
4452   pr "      struct guestfs_%s *%s;\n" typ n;
4453   pr " PPCODE:\n";
4454   pr "      %s = guestfs_%s " n name;
4455   generate_call_args ~handle:"g" (snd style);
4456   pr ";\n";
4457   do_cleanups ();
4458   pr "      if (%s == NULL)\n" n;
4459   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
4460   pr "      EXTEND (SP, %d);\n" (List.length cols);
4461   List.iter (
4462     function
4463     | name, `Int ->
4464         pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
4465   ) cols;
4466   pr "      free (%s);\n" n
4467
4468 (* Generate Sys/Guestfs.pm. *)
4469 and generate_perl_pm () =
4470   generate_header HashStyle LGPLv2;
4471
4472   pr "\
4473 =pod
4474
4475 =head1 NAME
4476
4477 Sys::Guestfs - Perl bindings for libguestfs
4478
4479 =head1 SYNOPSIS
4480
4481  use Sys::Guestfs;
4482  
4483  my $h = Sys::Guestfs->new ();
4484  $h->add_drive ('guest.img');
4485  $h->launch ();
4486  $h->wait_ready ();
4487  $h->mount ('/dev/sda1', '/');
4488  $h->touch ('/hello');
4489  $h->sync ();
4490
4491 =head1 DESCRIPTION
4492
4493 The C<Sys::Guestfs> module provides a Perl XS binding to the
4494 libguestfs API for examining and modifying virtual machine
4495 disk images.
4496
4497 Amongst the things this is good for: making batch configuration
4498 changes to guests, getting disk used/free statistics (see also:
4499 virt-df), migrating between virtualization systems (see also:
4500 virt-p2v), performing partial backups, performing partial guest
4501 clones, cloning guests and changing registry/UUID/hostname info, and
4502 much else besides.
4503
4504 Libguestfs uses Linux kernel and qemu code, and can access any type of
4505 guest filesystem that Linux and qemu can, including but not limited
4506 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
4507 schemes, qcow, qcow2, vmdk.
4508
4509 Libguestfs provides ways to enumerate guest storage (eg. partitions,
4510 LVs, what filesystem is in each LV, etc.).  It can also run commands
4511 in the context of the guest.  Also you can access filesystems over FTP.
4512
4513 =head1 ERRORS
4514
4515 All errors turn into calls to C<croak> (see L<Carp(3)>).
4516
4517 =head1 METHODS
4518
4519 =over 4
4520
4521 =cut
4522
4523 package Sys::Guestfs;
4524
4525 use strict;
4526 use warnings;
4527
4528 require XSLoader;
4529 XSLoader::load ('Sys::Guestfs');
4530
4531 =item $h = Sys::Guestfs->new ();
4532
4533 Create a new guestfs handle.
4534
4535 =cut
4536
4537 sub new {
4538   my $proto = shift;
4539   my $class = ref ($proto) || $proto;
4540
4541   my $self = Sys::Guestfs::_create ();
4542   bless $self, $class;
4543   return $self;
4544 }
4545
4546 ";
4547
4548   (* Actions.  We only need to print documentation for these as
4549    * they are pulled in from the XS code automatically.
4550    *)
4551   List.iter (
4552     fun (name, style, _, flags, _, _, longdesc) ->
4553       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
4554       pr "=item ";
4555       generate_perl_prototype name style;
4556       pr "\n\n";
4557       pr "%s\n\n" longdesc;
4558       if List.mem ProtocolLimitWarning flags then
4559         pr "%s\n\n" protocol_limit_warning;
4560       if List.mem DangerWillRobinson flags then
4561         pr "%s\n\n" danger_will_robinson
4562   ) all_functions_sorted;
4563
4564   (* End of file. *)
4565   pr "\
4566 =cut
4567
4568 1;
4569
4570 =back
4571
4572 =head1 COPYRIGHT
4573
4574 Copyright (C) 2009 Red Hat Inc.
4575
4576 =head1 LICENSE
4577
4578 Please see the file COPYING.LIB for the full license.
4579
4580 =head1 SEE ALSO
4581
4582 L<guestfs(3)>, L<guestfish(1)>.
4583
4584 =cut
4585 "
4586
4587 and generate_perl_prototype name style =
4588   (match fst style with
4589    | RErr -> ()
4590    | RBool n
4591    | RInt n
4592    | RInt64 n
4593    | RConstString n
4594    | RString n -> pr "$%s = " n
4595    | RIntBool (n, m) -> pr "($%s, $%s) = " n m
4596    | RStringList n
4597    | RPVList n
4598    | RVGList n
4599    | RLVList n -> pr "@%s = " n
4600    | RStat n
4601    | RStatVFS n
4602    | RHashtable n -> pr "%%%s = " n
4603   );
4604   pr "$h->%s (" name;
4605   let comma = ref false in
4606   List.iter (
4607     fun arg ->
4608       if !comma then pr ", ";
4609       comma := true;
4610       match arg with
4611       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
4612           pr "$%s" n
4613       | StringList n ->
4614           pr "\\@%s" n
4615   ) (snd style);
4616   pr ");"
4617
4618 (* Generate Python C module. *)
4619 and generate_python_c () =
4620   generate_header CStyle LGPLv2;
4621
4622   pr "\
4623 #include <stdio.h>
4624 #include <stdlib.h>
4625 #include <assert.h>
4626
4627 #include <Python.h>
4628
4629 #include \"guestfs.h\"
4630
4631 typedef struct {
4632   PyObject_HEAD
4633   guestfs_h *g;
4634 } Pyguestfs_Object;
4635
4636 static guestfs_h *
4637 get_handle (PyObject *obj)
4638 {
4639   assert (obj);
4640   assert (obj != Py_None);
4641   return ((Pyguestfs_Object *) obj)->g;
4642 }
4643
4644 static PyObject *
4645 put_handle (guestfs_h *g)
4646 {
4647   assert (g);
4648   return
4649     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
4650 }
4651
4652 /* This list should be freed (but not the strings) after use. */
4653 static const char **
4654 get_string_list (PyObject *obj)
4655 {
4656   int i, len;
4657   const char **r;
4658
4659   assert (obj);
4660
4661   if (!PyList_Check (obj)) {
4662     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
4663     return NULL;
4664   }
4665
4666   len = PyList_Size (obj);
4667   r = malloc (sizeof (char *) * (len+1));
4668   if (r == NULL) {
4669     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
4670     return NULL;
4671   }
4672
4673   for (i = 0; i < len; ++i)
4674     r[i] = PyString_AsString (PyList_GetItem (obj, i));
4675   r[len] = NULL;
4676
4677   return r;
4678 }
4679
4680 static PyObject *
4681 put_string_list (char * const * const argv)
4682 {
4683   PyObject *list;
4684   int argc, i;
4685
4686   for (argc = 0; argv[argc] != NULL; ++argc)
4687     ;
4688
4689   list = PyList_New (argc);
4690   for (i = 0; i < argc; ++i)
4691     PyList_SetItem (list, i, PyString_FromString (argv[i]));
4692
4693   return list;
4694 }
4695
4696 static PyObject *
4697 put_table (char * const * const argv)
4698 {
4699   PyObject *list, *item;
4700   int argc, i;
4701
4702   for (argc = 0; argv[argc] != NULL; ++argc)
4703     ;
4704
4705   list = PyList_New (argc >> 1);
4706   for (i = 0; i < argc; i += 2) {
4707     item = PyTuple_New (2);
4708     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
4709     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
4710     PyList_SetItem (list, i >> 1, item);
4711   }
4712
4713   return list;
4714 }
4715
4716 static void
4717 free_strings (char **argv)
4718 {
4719   int argc;
4720
4721   for (argc = 0; argv[argc] != NULL; ++argc)
4722     free (argv[argc]);
4723   free (argv);
4724 }
4725
4726 static PyObject *
4727 py_guestfs_create (PyObject *self, PyObject *args)
4728 {
4729   guestfs_h *g;
4730
4731   g = guestfs_create ();
4732   if (g == NULL) {
4733     PyErr_SetString (PyExc_RuntimeError,
4734                      \"guestfs.create: failed to allocate handle\");
4735     return NULL;
4736   }
4737   guestfs_set_error_handler (g, NULL, NULL);
4738   return put_handle (g);
4739 }
4740
4741 static PyObject *
4742 py_guestfs_close (PyObject *self, PyObject *args)
4743 {
4744   PyObject *py_g;
4745   guestfs_h *g;
4746
4747   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
4748     return NULL;
4749   g = get_handle (py_g);
4750
4751   guestfs_close (g);
4752
4753   Py_INCREF (Py_None);
4754   return Py_None;
4755 }
4756
4757 ";
4758
4759   (* LVM structures, turned into Python dictionaries. *)
4760   List.iter (
4761     fun (typ, cols) ->
4762       pr "static PyObject *\n";
4763       pr "put_lvm_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
4764       pr "{\n";
4765       pr "  PyObject *dict;\n";
4766       pr "\n";
4767       pr "  dict = PyDict_New ();\n";
4768       List.iter (
4769         function
4770         | name, `String ->
4771             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4772             pr "                        PyString_FromString (%s->%s));\n"
4773               typ name
4774         | name, `UUID ->
4775             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4776             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
4777               typ name
4778         | name, `Bytes ->
4779             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4780             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
4781               typ name
4782         | name, `Int ->
4783             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4784             pr "                        PyLong_FromLongLong (%s->%s));\n"
4785               typ name
4786         | name, `OptPercent ->
4787             pr "  if (%s->%s >= 0)\n" typ name;
4788             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
4789             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
4790               typ name;
4791             pr "  else {\n";
4792             pr "    Py_INCREF (Py_None);\n";
4793             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
4794             pr "  }\n"
4795       ) cols;
4796       pr "  return dict;\n";
4797       pr "};\n";
4798       pr "\n";
4799
4800       pr "static PyObject *\n";
4801       pr "put_lvm_%s_list (struct guestfs_lvm_%s_list *%ss)\n" typ typ typ;
4802       pr "{\n";
4803       pr "  PyObject *list;\n";
4804       pr "  int i;\n";
4805       pr "\n";
4806       pr "  list = PyList_New (%ss->len);\n" typ;
4807       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
4808       pr "    PyList_SetItem (list, i, put_lvm_%s (&%ss->val[i]));\n" typ typ;
4809       pr "  return list;\n";
4810       pr "};\n";
4811       pr "\n"
4812   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
4813
4814   (* Stat structures, turned into Python dictionaries. *)
4815   List.iter (
4816     fun (typ, cols) ->
4817       pr "static PyObject *\n";
4818       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
4819       pr "{\n";
4820       pr "  PyObject *dict;\n";
4821       pr "\n";
4822       pr "  dict = PyDict_New ();\n";
4823       List.iter (
4824         function
4825         | name, `Int ->
4826             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
4827             pr "                        PyLong_FromLongLong (%s->%s));\n"
4828               typ name
4829       ) cols;
4830       pr "  return dict;\n";
4831       pr "};\n";
4832       pr "\n";
4833   ) ["stat", stat_cols; "statvfs", statvfs_cols];
4834
4835   (* Python wrapper functions. *)
4836   List.iter (
4837     fun (name, style, _, _, _, _, _) ->
4838       pr "static PyObject *\n";
4839       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
4840       pr "{\n";
4841
4842       pr "  PyObject *py_g;\n";
4843       pr "  guestfs_h *g;\n";
4844       pr "  PyObject *py_r;\n";
4845
4846       let error_code =
4847         match fst style with
4848         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
4849         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4850         | RConstString _ -> pr "  const char *r;\n"; "NULL"
4851         | RString _ -> pr "  char *r;\n"; "NULL"
4852         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
4853         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
4854         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
4855         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
4856         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
4857         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
4858         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
4859
4860       List.iter (
4861         function
4862         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
4863         | OptString n -> pr "  const char *%s;\n" n
4864         | StringList n ->
4865             pr "  PyObject *py_%s;\n" n;
4866             pr "  const char **%s;\n" n
4867         | Bool n -> pr "  int %s;\n" n
4868         | Int n -> pr "  int %s;\n" n
4869       ) (snd style);
4870
4871       pr "\n";
4872
4873       (* Convert the parameters. *)
4874       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
4875       List.iter (
4876         function
4877         | String _ | FileIn _ | FileOut _ -> pr "s"
4878         | OptString _ -> pr "z"
4879         | StringList _ -> pr "O"
4880         | Bool _ -> pr "i" (* XXX Python has booleans? *)
4881         | Int _ -> pr "i"
4882       ) (snd style);
4883       pr ":guestfs_%s\",\n" name;
4884       pr "                         &py_g";
4885       List.iter (
4886         function
4887         | String n | FileIn n | FileOut n -> pr ", &%s" n
4888         | OptString n -> pr ", &%s" n
4889         | StringList n -> pr ", &py_%s" n
4890         | Bool n -> pr ", &%s" n
4891         | Int n -> pr ", &%s" n
4892       ) (snd style);
4893
4894       pr "))\n";
4895       pr "    return NULL;\n";
4896
4897       pr "  g = get_handle (py_g);\n";
4898       List.iter (
4899         function
4900         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
4901         | StringList n ->
4902             pr "  %s = get_string_list (py_%s);\n" n n;
4903             pr "  if (!%s) return NULL;\n" n
4904       ) (snd style);
4905
4906       pr "\n";
4907
4908       pr "  r = guestfs_%s " name;
4909       generate_call_args ~handle:"g" (snd style);
4910       pr ";\n";
4911
4912       List.iter (
4913         function
4914         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
4915         | StringList n ->
4916             pr "  free (%s);\n" n
4917       ) (snd style);
4918
4919       pr "  if (r == %s) {\n" error_code;
4920       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
4921       pr "    return NULL;\n";
4922       pr "  }\n";
4923       pr "\n";
4924
4925       (match fst style with
4926        | RErr ->
4927            pr "  Py_INCREF (Py_None);\n";
4928            pr "  py_r = Py_None;\n"
4929        | RInt _
4930        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
4931        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
4932        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
4933        | RString _ ->
4934            pr "  py_r = PyString_FromString (r);\n";
4935            pr "  free (r);\n"
4936        | RStringList _ ->
4937            pr "  py_r = put_string_list (r);\n";
4938            pr "  free_strings (r);\n"
4939        | RIntBool _ ->
4940            pr "  py_r = PyTuple_New (2);\n";
4941            pr "  PyTuple_SetItem (py_r, 0, PyInt_FromLong ((long) r->i));\n";
4942            pr "  PyTuple_SetItem (py_r, 1, PyInt_FromLong ((long) r->b));\n";
4943            pr "  guestfs_free_int_bool (r);\n"
4944        | RPVList n ->
4945            pr "  py_r = put_lvm_pv_list (r);\n";
4946            pr "  guestfs_free_lvm_pv_list (r);\n"
4947        | RVGList n ->
4948            pr "  py_r = put_lvm_vg_list (r);\n";
4949            pr "  guestfs_free_lvm_vg_list (r);\n"
4950        | RLVList n ->
4951            pr "  py_r = put_lvm_lv_list (r);\n";
4952            pr "  guestfs_free_lvm_lv_list (r);\n"
4953        | RStat n ->
4954            pr "  py_r = put_stat (r);\n";
4955            pr "  free (r);\n"
4956        | RStatVFS n ->
4957            pr "  py_r = put_statvfs (r);\n";
4958            pr "  free (r);\n"
4959        | RHashtable n ->
4960            pr "  py_r = put_table (r);\n";
4961            pr "  free_strings (r);\n"
4962       );
4963
4964       pr "  return py_r;\n";
4965       pr "}\n";
4966       pr "\n"
4967   ) all_functions;
4968
4969   (* Table of functions. *)
4970   pr "static PyMethodDef methods[] = {\n";
4971   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
4972   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
4973   List.iter (
4974     fun (name, _, _, _, _, _, _) ->
4975       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
4976         name name
4977   ) all_functions;
4978   pr "  { NULL, NULL, 0, NULL }\n";
4979   pr "};\n";
4980   pr "\n";
4981
4982   (* Init function. *)
4983   pr "\
4984 void
4985 initlibguestfsmod (void)
4986 {
4987   static int initialized = 0;
4988
4989   if (initialized) return;
4990   Py_InitModule ((char *) \"libguestfsmod\", methods);
4991   initialized = 1;
4992 }
4993 "
4994
4995 (* Generate Python module. *)
4996 and generate_python_py () =
4997   generate_header HashStyle LGPLv2;
4998
4999   pr "\
5000 u\"\"\"Python bindings for libguestfs
5001
5002 import guestfs
5003 g = guestfs.GuestFS ()
5004 g.add_drive (\"guest.img\")
5005 g.launch ()
5006 g.wait_ready ()
5007 parts = g.list_partitions ()
5008
5009 The guestfs module provides a Python binding to the libguestfs API
5010 for examining and modifying virtual machine disk images.
5011
5012 Amongst the things this is good for: making batch configuration
5013 changes to guests, getting disk used/free statistics (see also:
5014 virt-df), migrating between virtualization systems (see also:
5015 virt-p2v), performing partial backups, performing partial guest
5016 clones, cloning guests and changing registry/UUID/hostname info, and
5017 much else besides.
5018
5019 Libguestfs uses Linux kernel and qemu code, and can access any type of
5020 guest filesystem that Linux and qemu can, including but not limited
5021 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
5022 schemes, qcow, qcow2, vmdk.
5023
5024 Libguestfs provides ways to enumerate guest storage (eg. partitions,
5025 LVs, what filesystem is in each LV, etc.).  It can also run commands
5026 in the context of the guest.  Also you can access filesystems over FTP.
5027
5028 Errors which happen while using the API are turned into Python
5029 RuntimeError exceptions.
5030
5031 To create a guestfs handle you usually have to perform the following
5032 sequence of calls:
5033
5034 # Create the handle, call add_drive at least once, and possibly
5035 # several times if the guest has multiple block devices:
5036 g = guestfs.GuestFS ()
5037 g.add_drive (\"guest.img\")
5038
5039 # Launch the qemu subprocess and wait for it to become ready:
5040 g.launch ()
5041 g.wait_ready ()
5042
5043 # Now you can issue commands, for example:
5044 logvols = g.lvs ()
5045
5046 \"\"\"
5047
5048 import libguestfsmod
5049
5050 class GuestFS:
5051     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
5052
5053     def __init__ (self):
5054         \"\"\"Create a new libguestfs handle.\"\"\"
5055         self._o = libguestfsmod.create ()
5056
5057     def __del__ (self):
5058         libguestfsmod.close (self._o)
5059
5060 ";
5061
5062   List.iter (
5063     fun (name, style, _, flags, _, _, longdesc) ->
5064       let doc = replace_str longdesc "C<guestfs_" "C<g." in
5065       let doc =
5066         match fst style with
5067         | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _
5068         | RString _ -> doc
5069         | RStringList _ ->
5070             doc ^ "\n\nThis function returns a list of strings."
5071         | RIntBool _ ->
5072             doc ^ "\n\nThis function returns a tuple (int, bool).\n"
5073         | RPVList _ ->
5074             doc ^ "\n\nThis function returns a list of PVs.  Each PV is represented as a dictionary."
5075         | RVGList _ ->
5076             doc ^ "\n\nThis function returns a list of VGs.  Each VG is represented as a dictionary."
5077         | RLVList _ ->
5078             doc ^ "\n\nThis function returns a list of LVs.  Each LV is represented as a dictionary."
5079         | RStat _ ->
5080             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the stat structure."
5081        | RStatVFS _ ->
5082             doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
5083        | RHashtable _ ->
5084             doc ^ "\n\nThis function returns a dictionary." in
5085       let doc =
5086         if List.mem ProtocolLimitWarning flags then
5087           doc ^ "\n\n" ^ protocol_limit_warning
5088         else doc in
5089       let doc =
5090         if List.mem DangerWillRobinson flags then
5091           doc ^ "\n\n" ^ danger_will_robinson
5092         else doc in
5093       let doc = pod2text ~width:60 name doc in
5094       let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
5095       let doc = String.concat "\n        " doc in
5096
5097       pr "    def %s " name;
5098       generate_call_args ~handle:"self" (snd style);
5099       pr ":\n";
5100       pr "        u\"\"\"%s\"\"\"\n" doc;
5101       pr "        return libguestfsmod.%s " name;
5102       generate_call_args ~handle:"self._o" (snd style);
5103       pr "\n";
5104       pr "\n";
5105   ) all_functions
5106
5107 (* Useful if you need the longdesc POD text as plain text.  Returns a
5108  * list of lines.
5109  *)
5110 and pod2text ~width name longdesc =
5111   let filename, chan = Filename.open_temp_file "gen" ".tmp" in
5112   fprintf chan "=head1 %s\n\n%s\n" name longdesc;
5113   close_out chan;
5114   let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
5115   let chan = Unix.open_process_in cmd in
5116   let lines = ref [] in
5117   let rec loop i =
5118     let line = input_line chan in
5119     if i = 1 then               (* discard the first line of output *)
5120       loop (i+1)
5121     else (
5122       let line = triml line in
5123       lines := line :: !lines;
5124       loop (i+1)
5125     ) in
5126   let lines = try loop 1 with End_of_file -> List.rev !lines in
5127   Unix.unlink filename;
5128   match Unix.close_process_in chan with
5129   | Unix.WEXITED 0 -> lines
5130   | Unix.WEXITED i ->
5131       failwithf "pod2text: process exited with non-zero status (%d)" i
5132   | Unix.WSIGNALED i | Unix.WSTOPPED i ->
5133       failwithf "pod2text: process signalled or stopped by signal %d" i
5134
5135 (* Generate ruby bindings. *)
5136 and generate_ruby_c () =
5137   generate_header CStyle LGPLv2;
5138
5139   pr "\
5140 #include <stdio.h>
5141 #include <stdlib.h>
5142
5143 #include <ruby.h>
5144
5145 #include \"guestfs.h\"
5146
5147 #include \"extconf.h\"
5148
5149 static VALUE m_guestfs;                 /* guestfs module */
5150 static VALUE c_guestfs;                 /* guestfs_h handle */
5151 static VALUE e_Error;                   /* used for all errors */
5152
5153 static void ruby_guestfs_free (void *p)
5154 {
5155   if (!p) return;
5156   guestfs_close ((guestfs_h *) p);
5157 }
5158
5159 static VALUE ruby_guestfs_create (VALUE m)
5160 {
5161   guestfs_h *g;
5162
5163   g = guestfs_create ();
5164   if (!g)
5165     rb_raise (e_Error, \"failed to create guestfs handle\");
5166
5167   /* Don't print error messages to stderr by default. */
5168   guestfs_set_error_handler (g, NULL, NULL);
5169
5170   /* Wrap it, and make sure the close function is called when the
5171    * handle goes away.
5172    */
5173   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
5174 }
5175
5176 static VALUE ruby_guestfs_close (VALUE gv)
5177 {
5178   guestfs_h *g;
5179   Data_Get_Struct (gv, guestfs_h, g);
5180
5181   ruby_guestfs_free (g);
5182   DATA_PTR (gv) = NULL;
5183
5184   return Qnil;
5185 }
5186
5187 ";
5188
5189   List.iter (
5190     fun (name, style, _, _, _, _, _) ->
5191       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
5192       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
5193       pr ")\n";
5194       pr "{\n";
5195       pr "  guestfs_h *g;\n";
5196       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
5197       pr "  if (!g)\n";
5198       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
5199         name;
5200       pr "\n";
5201
5202       List.iter (
5203         function
5204         | String n | FileIn n | FileOut n ->
5205             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
5206             pr "  if (!%s)\n" n;
5207             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
5208             pr "              \"%s\", \"%s\");\n" n name
5209         | OptString n ->
5210             pr "  const char *%s = StringValueCStr (%sv);\n" n n
5211         | StringList n ->
5212             pr "  char **%s;" n;
5213             pr "  {\n";
5214             pr "    int i, len;\n";
5215             pr "    len = RARRAY_LEN (%sv);\n" n;
5216             pr "    %s = malloc (sizeof (char *) * (len+1));\n" n;
5217             pr "    for (i = 0; i < len; ++i) {\n";
5218             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
5219             pr "      %s[i] = StringValueCStr (v);\n" n;
5220             pr "    }\n";
5221             pr "  }\n";
5222         | Bool n
5223         | Int n ->
5224             pr "  int %s = NUM2INT (%sv);\n" n n
5225       ) (snd style);
5226       pr "\n";
5227
5228       let error_code =
5229         match fst style with
5230         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
5231         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5232         | RConstString _ -> pr "  const char *r;\n"; "NULL"
5233         | RString _ -> pr "  char *r;\n"; "NULL"
5234         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5235         | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
5236         | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
5237         | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
5238         | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
5239         | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
5240         | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
5241       pr "\n";
5242
5243       pr "  r = guestfs_%s " name;
5244       generate_call_args ~handle:"g" (snd style);
5245       pr ";\n";
5246
5247       List.iter (
5248         function
5249         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
5250         | StringList n ->
5251             pr "  free (%s);\n" n
5252       ) (snd style);
5253
5254       pr "  if (r == %s)\n" error_code;
5255       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
5256       pr "\n";
5257
5258       (match fst style with
5259        | RErr ->
5260            pr "  return Qnil;\n"
5261        | RInt _ | RBool _ ->
5262            pr "  return INT2NUM (r);\n"
5263        | RInt64 _ ->
5264            pr "  return ULL2NUM (r);\n"
5265        | RConstString _ ->
5266            pr "  return rb_str_new2 (r);\n";
5267        | RString _ ->
5268            pr "  VALUE rv = rb_str_new2 (r);\n";
5269            pr "  free (r);\n";
5270            pr "  return rv;\n";
5271        | RStringList _ ->
5272            pr "  int i, len = 0;\n";
5273            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
5274            pr "  VALUE rv = rb_ary_new2 (len);\n";
5275            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
5276            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
5277            pr "    free (r[i]);\n";
5278            pr "  }\n";
5279            pr "  free (r);\n";
5280            pr "  return rv;\n"
5281        | RIntBool _ ->
5282            pr "  VALUE rv = rb_ary_new2 (2);\n";
5283            pr "  rb_ary_push (rv, INT2NUM (r->i));\n";
5284            pr "  rb_ary_push (rv, INT2NUM (r->b));\n";
5285            pr "  guestfs_free_int_bool (r);\n";
5286            pr "  return rv;\n"
5287        | RPVList n ->
5288            generate_ruby_lvm_code "pv" pv_cols
5289        | RVGList n ->
5290            generate_ruby_lvm_code "vg" vg_cols
5291        | RLVList n ->
5292            generate_ruby_lvm_code "lv" lv_cols
5293        | RStat n ->
5294            pr "  VALUE rv = rb_hash_new ();\n";
5295            List.iter (
5296              function
5297              | name, `Int ->
5298                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5299            ) stat_cols;
5300            pr "  free (r);\n";
5301            pr "  return rv;\n"
5302        | RStatVFS n ->
5303            pr "  VALUE rv = rb_hash_new ();\n";
5304            List.iter (
5305              function
5306              | name, `Int ->
5307                  pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
5308            ) statvfs_cols;
5309            pr "  free (r);\n";
5310            pr "  return rv;\n"
5311        | RHashtable _ ->
5312            pr "  VALUE rv = rb_hash_new ();\n";
5313            pr "  int i;\n";
5314            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
5315            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
5316            pr "    free (r[i]);\n";
5317            pr "    free (r[i+1]);\n";
5318            pr "  }\n";
5319            pr "  free (r);\n";
5320            pr "  return rv;\n"
5321       );
5322
5323       pr "}\n";
5324       pr "\n"
5325   ) all_functions;
5326
5327   pr "\
5328 /* Initialize the module. */
5329 void Init__guestfs ()
5330 {
5331   m_guestfs = rb_define_module (\"Guestfs\");
5332   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
5333   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
5334
5335   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
5336   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
5337
5338 ";
5339   (* Define the rest of the methods. *)
5340   List.iter (
5341     fun (name, style, _, _, _, _, _) ->
5342       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
5343       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
5344   ) all_functions;
5345
5346   pr "}\n"
5347
5348 (* Ruby code to return an LVM struct list. *)
5349 and generate_ruby_lvm_code typ cols =
5350   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
5351   pr "  int i;\n";
5352   pr "  for (i = 0; i < r->len; ++i) {\n";
5353   pr "    VALUE hv = rb_hash_new ();\n";
5354   List.iter (
5355     function
5356     | name, `String ->
5357         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
5358     | name, `UUID ->
5359         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
5360     | name, `Bytes
5361     | name, `Int ->
5362         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
5363     | name, `OptPercent ->
5364         pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
5365   ) cols;
5366   pr "    rb_ary_push (rv, hv);\n";
5367   pr "  }\n";
5368   pr "  guestfs_free_lvm_%s_list (r);\n" typ;
5369   pr "  return rv;\n"
5370
5371 let output_to filename =
5372   let filename_new = filename ^ ".new" in
5373   chan := open_out filename_new;
5374   let close () =
5375     close_out !chan;
5376     chan := stdout;
5377     Unix.rename filename_new filename;
5378     printf "written %s\n%!" filename;
5379   in
5380   close
5381
5382 (* Main program. *)
5383 let () =
5384   check_functions ();
5385
5386   if not (Sys.file_exists "configure.ac") then (
5387     eprintf "\
5388 You are probably running this from the wrong directory.
5389 Run it from the top source directory using the command
5390   src/generator.ml
5391 ";
5392     exit 1
5393   );
5394
5395   let close = output_to "src/guestfs_protocol.x" in
5396   generate_xdr ();
5397   close ();
5398
5399   let close = output_to "src/guestfs-structs.h" in
5400   generate_structs_h ();
5401   close ();
5402
5403   let close = output_to "src/guestfs-actions.h" in
5404   generate_actions_h ();
5405   close ();
5406
5407   let close = output_to "src/guestfs-actions.c" in
5408   generate_client_actions ();
5409   close ();
5410
5411   let close = output_to "daemon/actions.h" in
5412   generate_daemon_actions_h ();
5413   close ();
5414
5415   let close = output_to "daemon/stubs.c" in
5416   generate_daemon_actions ();
5417   close ();
5418
5419   let close = output_to "tests.c" in
5420   generate_tests ();
5421   close ();
5422
5423   let close = output_to "fish/cmds.c" in
5424   generate_fish_cmds ();
5425   close ();
5426
5427   let close = output_to "fish/completion.c" in
5428   generate_fish_completion ();
5429   close ();
5430
5431   let close = output_to "guestfs-structs.pod" in
5432   generate_structs_pod ();
5433   close ();
5434
5435   let close = output_to "guestfs-actions.pod" in
5436   generate_actions_pod ();
5437   close ();
5438
5439   let close = output_to "guestfish-actions.pod" in
5440   generate_fish_actions_pod ();
5441   close ();
5442
5443   let close = output_to "ocaml/guestfs.mli" in
5444   generate_ocaml_mli ();
5445   close ();
5446
5447   let close = output_to "ocaml/guestfs.ml" in
5448   generate_ocaml_ml ();
5449   close ();
5450
5451   let close = output_to "ocaml/guestfs_c_actions.c" in
5452   generate_ocaml_c ();
5453   close ();
5454
5455   let close = output_to "perl/Guestfs.xs" in
5456   generate_perl_xs ();
5457   close ();
5458
5459   let close = output_to "perl/lib/Sys/Guestfs.pm" in
5460   generate_perl_pm ();
5461   close ();
5462
5463   let close = output_to "python/guestfs-py.c" in
5464   generate_python_c ();
5465   close ();
5466
5467   let close = output_to "python/guestfs.py" in
5468   generate_python_py ();
5469   close ();
5470
5471   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
5472   generate_ruby_c ();
5473   close ();