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