Need to declare asprintf_nowarn as inline to avoid gcc complaining.
[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 all the
28  * output files.  Note that if you are using a separate build directory you
29  * must run generator.ml from the _source_ directory.
30  *
31  * IMPORTANT: This script should NOT print any warnings.  If it prints
32  * warnings, you should treat them as errors.
33  * [Need to add -warn-error to ocaml command line]
34  *)
35
36 #load "unix.cma";;
37 #load "str.cma";;
38
39 open Printf
40
41 type style = ret * args
42 and ret =
43     (* "RErr" as a return value means an int used as a simple error
44      * indication, ie. 0 or -1.
45      *)
46   | RErr
47
48     (* "RInt" as a return value means an int which is -1 for error
49      * or any value >= 0 on success.  Only use this for smallish
50      * positive ints (0 <= i < 2^30).
51      *)
52   | RInt of string
53
54     (* "RInt64" is the same as RInt, but is guaranteed to be able
55      * to return a full 64 bit value, _except_ that -1 means error
56      * (so -1 cannot be a valid, non-error return value).
57      *)
58   | RInt64 of string
59
60     (* "RBool" is a bool return value which can be true/false or
61      * -1 for error.
62      *)
63   | RBool of string
64
65     (* "RConstString" is a string that refers to a constant value.
66      * The return value must NOT be NULL (since NULL indicates
67      * an error).
68      *
69      * Try to avoid using this.  In particular you cannot use this
70      * for values returned from the daemon, because there is no
71      * thread-safe way to return them in the C API.
72      *)
73   | RConstString of string
74
75     (* "RConstOptString" is an even more broken version of
76      * "RConstString".  The returned string may be NULL and there
77      * is no way to return an error indication.  Avoid using this!
78      *)
79   | RConstOptString of string
80
81     (* "RString" is a returned string.  It must NOT be NULL, since
82      * a NULL return indicates an error.  The caller frees this.
83      *)
84   | RString of string
85
86     (* "RStringList" is a list of strings.  No string in the list
87      * can be NULL.  The caller frees the strings and the array.
88      *)
89   | RStringList of string
90
91     (* "RStruct" is a function which returns a single named structure
92      * or an error indication (in C, a struct, and in other languages
93      * with varying representations, but usually very efficient).  See
94      * after the function list below for the structures. 
95      *)
96   | RStruct of string * string          (* name of retval, name of struct *)
97
98     (* "RStructList" is a function which returns either a list/array
99      * of structures (could be zero-length), or an error indication.
100      *)
101   | RStructList of string * string      (* name of retval, name of struct *)
102
103     (* Key-value pairs of untyped strings.  Turns into a hashtable or
104      * dictionary in languages which support it.  DON'T use this as a
105      * general "bucket" for results.  Prefer a stronger typed return
106      * value if one is available, or write a custom struct.  Don't use
107      * this if the list could potentially be very long, since it is
108      * inefficient.  Keys should be unique.  NULLs are not permitted.
109      *)
110   | RHashtable of string
111
112     (* "RBufferOut" is handled almost exactly like RString, but
113      * it allows the string to contain arbitrary 8 bit data including
114      * ASCII NUL.  In the C API this causes an implicit extra parameter
115      * to be added of type <size_t *size_r>.  The extra parameter
116      * returns the actual size of the return buffer in bytes.
117      *
118      * Other programming languages support strings with arbitrary 8 bit
119      * data.
120      *
121      * At the RPC layer we have to use the opaque<> type instead of
122      * string<>.  Returned data is still limited to the max message
123      * size (ie. ~ 2 MB).
124      *)
125   | RBufferOut of string
126
127 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
128
129     (* Note in future we should allow a "variable args" parameter as
130      * the final parameter, to allow commands like
131      *   chmod mode file [file(s)...]
132      * This is not implemented yet, but many commands (such as chmod)
133      * are currently defined with the argument order keeping this future
134      * possibility in mind.
135      *)
136 and argt =
137   | String of string    (* const char *name, cannot be NULL *)
138   | OptString of string (* const char *name, may be NULL *)
139   | StringList of string(* list of strings (each string cannot be NULL) *)
140   | Bool of string      (* boolean *)
141   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
142     (* These are treated as filenames (simple string parameters) in
143      * the C API and bindings.  But in the RPC protocol, we transfer
144      * the actual file content up to or down from the daemon.
145      * FileIn: local machine -> daemon (in request)
146      * FileOut: daemon -> local machine (in reply)
147      * In guestfish (only), the special name "-" means read from
148      * stdin or write to stdout.
149      *)
150   | FileIn of string
151   | FileOut of string
152 (* Not implemented:
153     (* Opaque buffer which can contain arbitrary 8 bit data.
154      * In the C API, this is expressed as <char *, int> pair.
155      * Most other languages have a string type which can contain
156      * ASCII NUL.  We use whatever type is appropriate for each
157      * language.
158      * Buffers are limited by the total message size.  To transfer
159      * large blocks of data, use FileIn/FileOut parameters instead.
160      * To return an arbitrary buffer, use RBufferOut.
161      *)
162   | BufferIn of string
163 *)
164
165 type flags =
166   | ProtocolLimitWarning  (* display warning about protocol size limits *)
167   | DangerWillRobinson    (* flags particularly dangerous commands *)
168   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
169   | FishAction of string  (* call this function in guestfish *)
170   | NotInFish             (* do not export via guestfish *)
171   | NotInDocs             (* do not add this function to documentation *)
172
173 let protocol_limit_warning =
174   "Because of the message protocol, there is a transfer limit
175 of somewhere between 2MB and 4MB.  To transfer large files you should use
176 FTP."
177
178 let danger_will_robinson =
179   "B<This command is dangerous.  Without careful use you
180 can easily destroy all your data>."
181
182 (* You can supply zero or as many tests as you want per API call.
183  *
184  * Note that the test environment has 3 block devices, of size 500MB,
185  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
186  * a fourth squashfs block device with some known files on it (/dev/sdd).
187  *
188  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
189  * Number of cylinders was 63 for IDE emulated disks with precisely
190  * the same size.  How exactly this is calculated is a mystery.
191  *
192  * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
193  *
194  * To be able to run the tests in a reasonable amount of time,
195  * the virtual machine and block devices are reused between tests.
196  * So don't try testing kill_subprocess :-x
197  *
198  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
199  *
200  * Don't assume anything about the previous contents of the block
201  * devices.  Use 'Init*' to create some initial scenarios.
202  *
203  * You can add a prerequisite clause to any individual test.  This
204  * is a run-time check, which, if it fails, causes the test to be
205  * skipped.  Useful if testing a command which might not work on
206  * all variations of libguestfs builds.  A test that has prerequisite
207  * of 'Always' is run unconditionally.
208  *
209  * In addition, packagers can skip individual tests by setting the
210  * environment variables:     eg:
211  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
212  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
213  *)
214 type tests = (test_init * test_prereq * test) list
215 and test =
216     (* Run the command sequence and just expect nothing to fail. *)
217   | TestRun of seq
218     (* Run the command sequence and expect the output of the final
219      * command to be the string.
220      *)
221   | TestOutput of seq * string
222     (* Run the command sequence and expect the output of the final
223      * command to be the list of strings.
224      *)
225   | TestOutputList of seq * string list
226     (* Run the command sequence and expect the output of the final
227      * command to be the list of block devices (could be either
228      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
229      * character of each string).
230      *)
231   | TestOutputListOfDevices of seq * string list
232     (* Run the command sequence and expect the output of the final
233      * command to be the integer.
234      *)
235   | TestOutputInt of seq * int
236     (* Run the command sequence and expect the output of the final
237      * command to be <op> <int>, eg. ">=", "1".
238      *)
239   | TestOutputIntOp of seq * string * int
240     (* Run the command sequence and expect the output of the final
241      * command to be a true value (!= 0 or != NULL).
242      *)
243   | TestOutputTrue of seq
244     (* Run the command sequence and expect the output of the final
245      * command to be a false value (== 0 or == NULL, but not an error).
246      *)
247   | TestOutputFalse of seq
248     (* Run the command sequence and expect the output of the final
249      * command to be a list of the given length (but don't care about
250      * content).
251      *)
252   | TestOutputLength of seq * int
253     (* Run the command sequence and expect the output of the final
254      * command to be a structure.
255      *)
256   | TestOutputStruct of seq * test_field_compare list
257     (* Run the command sequence and expect the final command (only)
258      * to fail.
259      *)
260   | TestLastFail of seq
261
262 and test_field_compare =
263   | CompareWithInt of string * int
264   | CompareWithIntOp of string * string * int
265   | CompareWithString of string * string
266   | CompareFieldsIntEq of string * string
267   | CompareFieldsStrEq of string * string
268
269 (* Test prerequisites. *)
270 and test_prereq =
271     (* Test always runs. *)
272   | Always
273     (* Test is currently disabled - eg. it fails, or it tests some
274      * unimplemented feature.
275      *)
276   | Disabled
277     (* 'string' is some C code (a function body) that should return
278      * true or false.  The test will run if the code returns true.
279      *)
280   | If of string
281     (* As for 'If' but the test runs _unless_ the code returns true. *)
282   | Unless of string
283
284 (* Some initial scenarios for testing. *)
285 and test_init =
286     (* Do nothing, block devices could contain random stuff including
287      * LVM PVs, and some filesystems might be mounted.  This is usually
288      * a bad idea.
289      *)
290   | InitNone
291
292     (* Block devices are empty and no filesystems are mounted. *)
293   | InitEmpty
294
295     (* /dev/sda contains a single partition /dev/sda1, which is formatted
296      * as ext2, empty [except for lost+found] and mounted on /.
297      * /dev/sdb and /dev/sdc may have random content.
298      * No LVM.
299      *)
300   | InitBasicFS
301
302     (* /dev/sda:
303      *   /dev/sda1 (is a PV):
304      *     /dev/VG/LV (size 8MB):
305      *       formatted as ext2, empty [except for lost+found], mounted on /
306      * /dev/sdb and /dev/sdc may have random content.
307      *)
308   | InitBasicFSonLVM
309
310     (* /dev/sdd (the squashfs, see images/ directory in source)
311      * is mounted on /
312      *)
313   | InitSquashFS
314
315 (* Sequence of commands for testing. *)
316 and seq = cmd list
317 and cmd = string list
318
319 (* Note about long descriptions: When referring to another
320  * action, use the format C<guestfs_other> (ie. the full name of
321  * the C function).  This will be replaced as appropriate in other
322  * language bindings.
323  *
324  * Apart from that, long descriptions are just perldoc paragraphs.
325  *)
326
327 (* These test functions are used in the language binding tests. *)
328
329 let test_all_args = [
330   String "str";
331   OptString "optstr";
332   StringList "strlist";
333   Bool "b";
334   Int "integer";
335   FileIn "filein";
336   FileOut "fileout";
337 ]
338
339 let test_all_rets = [
340   (* except for RErr, which is tested thoroughly elsewhere *)
341   "test0rint",         RInt "valout";
342   "test0rint64",       RInt64 "valout";
343   "test0rbool",        RBool "valout";
344   "test0rconststring", RConstString "valout";
345   "test0rconstoptstring", RConstOptString "valout";
346   "test0rstring",      RString "valout";
347   "test0rstringlist",  RStringList "valout";
348   "test0rstruct",      RStruct ("valout", "lvm_pv");
349   "test0rstructlist",  RStructList ("valout", "lvm_pv");
350   "test0rhashtable",   RHashtable "valout";
351 ]
352
353 let test_functions = [
354   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
355    [],
356    "internal test function - do not use",
357    "\
358 This is an internal test function which is used to test whether
359 the automatically generated bindings can handle every possible
360 parameter type correctly.
361
362 It echos the contents of each parameter to stdout.
363
364 You probably don't want to call this function.");
365 ] @ List.flatten (
366   List.map (
367     fun (name, ret) ->
368       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
369         [],
370         "internal test function - do not use",
371         "\
372 This is an internal test function which is used to test whether
373 the automatically generated bindings can handle every possible
374 return type correctly.
375
376 It converts string C<val> to the return type.
377
378 You probably don't want to call this function.");
379        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
380         [],
381         "internal test function - do not use",
382         "\
383 This is an internal test function which is used to test whether
384 the automatically generated bindings can handle every possible
385 return type correctly.
386
387 This function always returns an error.
388
389 You probably don't want to call this function.")]
390   ) test_all_rets
391 )
392
393 (* non_daemon_functions are any functions which don't get processed
394  * in the daemon, eg. functions for setting and getting local
395  * configuration values.
396  *)
397
398 let non_daemon_functions = test_functions @ [
399   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
400    [],
401    "launch the qemu subprocess",
402    "\
403 Internally libguestfs is implemented by running a virtual machine
404 using L<qemu(1)>.
405
406 You should call this after configuring the handle
407 (eg. adding drives) but before performing any actions.");
408
409   ("wait_ready", (RErr, []), -1, [NotInFish],
410    [],
411    "wait until the qemu subprocess launches",
412    "\
413 Internally libguestfs is implemented by running a virtual machine
414 using L<qemu(1)>.
415
416 You should call this after C<guestfs_launch> to wait for the launch
417 to complete.");
418
419   ("kill_subprocess", (RErr, []), -1, [],
420    [],
421    "kill the qemu subprocess",
422    "\
423 This kills the qemu subprocess.  You should never need to call this.");
424
425   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
426    [],
427    "add an image to examine or modify",
428    "\
429 This function adds a virtual machine disk image C<filename> to the
430 guest.  The first time you call this function, the disk appears as IDE
431 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
432 so on.
433
434 You don't necessarily need to be root when using libguestfs.  However
435 you obviously do need sufficient permissions to access the filename
436 for whatever operations you want to perform (ie. read access if you
437 just want to read the image or write access if you want to modify the
438 image).
439
440 This is equivalent to the qemu parameter
441 C<-drive file=filename,cache=off,if=...>.
442
443 Note that this call checks for the existence of C<filename>.  This
444 stops you from specifying other types of drive which are supported
445 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
446 the general C<guestfs_config> call instead.");
447
448   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
449    [],
450    "add a CD-ROM disk image to examine",
451    "\
452 This function adds a virtual CD-ROM disk image to the guest.
453
454 This is equivalent to the qemu parameter C<-cdrom filename>.
455
456 Note that this call checks for the existence of C<filename>.  This
457 stops you from specifying other types of drive which are supported
458 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
459 the general C<guestfs_config> call instead.");
460
461   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
462    [],
463    "add a drive in snapshot mode (read-only)",
464    "\
465 This adds a drive in snapshot mode, making it effectively
466 read-only.
467
468 Note that writes to the device are allowed, and will be seen for
469 the duration of the guestfs handle, but they are written
470 to a temporary file which is discarded as soon as the guestfs
471 handle is closed.  We don't currently have any method to enable
472 changes to be committed, although qemu can support this.
473
474 This is equivalent to the qemu parameter
475 C<-drive file=filename,snapshot=on,if=...>.
476
477 Note that this call checks for the existence of C<filename>.  This
478 stops you from specifying other types of drive which are supported
479 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
480 the general C<guestfs_config> call instead.");
481
482   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
483    [],
484    "add qemu parameters",
485    "\
486 This can be used to add arbitrary qemu command line parameters
487 of the form C<-param value>.  Actually it's not quite arbitrary - we
488 prevent you from setting some parameters which would interfere with
489 parameters that we use.
490
491 The first character of C<param> string must be a C<-> (dash).
492
493 C<value> can be NULL.");
494
495   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
496    [],
497    "set the qemu binary",
498    "\
499 Set the qemu binary that we will use.
500
501 The default is chosen when the library was compiled by the
502 configure script.
503
504 You can also override this by setting the C<LIBGUESTFS_QEMU>
505 environment variable.
506
507 Setting C<qemu> to C<NULL> restores the default qemu binary.");
508
509   ("get_qemu", (RConstString "qemu", []), -1, [],
510    [InitNone, Always, TestRun (
511       [["get_qemu"]])],
512    "get the qemu binary",
513    "\
514 Return the current qemu binary.
515
516 This is always non-NULL.  If it wasn't set already, then this will
517 return the default qemu binary name.");
518
519   ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
520    [],
521    "set the search path",
522    "\
523 Set the path that libguestfs searches for kernel and initrd.img.
524
525 The default is C<$libdir/guestfs> unless overridden by setting
526 C<LIBGUESTFS_PATH> environment variable.
527
528 Setting C<path> to C<NULL> restores the default path.");
529
530   ("get_path", (RConstString "path", []), -1, [],
531    [InitNone, Always, TestRun (
532       [["get_path"]])],
533    "get the search path",
534    "\
535 Return the current search path.
536
537 This is always non-NULL.  If it wasn't set already, then this will
538 return the default path.");
539
540   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
541    [],
542    "add options to kernel command line",
543    "\
544 This function is used to add additional options to the
545 guest kernel command line.
546
547 The default is C<NULL> unless overridden by setting
548 C<LIBGUESTFS_APPEND> environment variable.
549
550 Setting C<append> to C<NULL> means I<no> additional options
551 are passed (libguestfs always adds a few of its own).");
552
553   ("get_append", (RConstOptString "append", []), -1, [],
554    (* This cannot be tested with the current framework.  The
555     * function can return NULL in normal operations, which the
556     * test framework interprets as an error.
557     *)
558    [],
559    "get the additional kernel options",
560    "\
561 Return the additional kernel options which are added to the
562 guest kernel command line.
563
564 If C<NULL> then no options are added.");
565
566   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
567    [],
568    "set autosync mode",
569    "\
570 If C<autosync> is true, this enables autosync.  Libguestfs will make a
571 best effort attempt to run C<guestfs_umount_all> followed by
572 C<guestfs_sync> when the handle is closed
573 (also if the program exits without closing handles).
574
575 This is disabled by default (except in guestfish where it is
576 enabled by default).");
577
578   ("get_autosync", (RBool "autosync", []), -1, [],
579    [InitNone, Always, TestRun (
580       [["get_autosync"]])],
581    "get autosync mode",
582    "\
583 Get the autosync flag.");
584
585   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
586    [],
587    "set verbose mode",
588    "\
589 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
590
591 Verbose messages are disabled unless the environment variable
592 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
593
594   ("get_verbose", (RBool "verbose", []), -1, [],
595    [],
596    "get verbose mode",
597    "\
598 This returns the verbose messages flag.");
599
600   ("is_ready", (RBool "ready", []), -1, [],
601    [InitNone, Always, TestOutputTrue (
602       [["is_ready"]])],
603    "is ready to accept commands",
604    "\
605 This returns true iff this handle is ready to accept commands
606 (in the C<READY> state).
607
608 For more information on states, see L<guestfs(3)>.");
609
610   ("is_config", (RBool "config", []), -1, [],
611    [InitNone, Always, TestOutputFalse (
612       [["is_config"]])],
613    "is in configuration state",
614    "\
615 This returns true iff this handle is being configured
616 (in the C<CONFIG> state).
617
618 For more information on states, see L<guestfs(3)>.");
619
620   ("is_launching", (RBool "launching", []), -1, [],
621    [InitNone, Always, TestOutputFalse (
622       [["is_launching"]])],
623    "is launching subprocess",
624    "\
625 This returns true iff this handle is launching the subprocess
626 (in the C<LAUNCHING> state).
627
628 For more information on states, see L<guestfs(3)>.");
629
630   ("is_busy", (RBool "busy", []), -1, [],
631    [InitNone, Always, TestOutputFalse (
632       [["is_busy"]])],
633    "is busy processing a command",
634    "\
635 This returns true iff this handle is busy processing a command
636 (in the C<BUSY> state).
637
638 For more information on states, see L<guestfs(3)>.");
639
640   ("get_state", (RInt "state", []), -1, [],
641    [],
642    "get the current state",
643    "\
644 This returns the current state as an opaque integer.  This is
645 only useful for printing debug and internal error messages.
646
647 For more information on states, see L<guestfs(3)>.");
648
649   ("set_busy", (RErr, []), -1, [NotInFish],
650    [],
651    "set state to busy",
652    "\
653 This sets the state to C<BUSY>.  This is only used when implementing
654 actions using the low-level API.
655
656 For more information on states, see L<guestfs(3)>.");
657
658   ("set_ready", (RErr, []), -1, [NotInFish],
659    [],
660    "set state to ready",
661    "\
662 This sets the state to C<READY>.  This is only used when implementing
663 actions using the low-level API.
664
665 For more information on states, see L<guestfs(3)>.");
666
667   ("end_busy", (RErr, []), -1, [NotInFish],
668    [],
669    "leave the busy state",
670    "\
671 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
672 state as is.  This is only used when implementing
673 actions using the low-level API.
674
675 For more information on states, see L<guestfs(3)>.");
676
677   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
678    [InitNone, Always, TestOutputInt (
679       [["set_memsize"; "500"];
680        ["get_memsize"]], 500)],
681    "set memory allocated to the qemu subprocess",
682    "\
683 This sets the memory size in megabytes allocated to the
684 qemu subprocess.  This only has any effect if called before
685 C<guestfs_launch>.
686
687 You can also change this by setting the environment
688 variable C<LIBGUESTFS_MEMSIZE> before the handle is
689 created.
690
691 For more information on the architecture of libguestfs,
692 see L<guestfs(3)>.");
693
694   ("get_memsize", (RInt "memsize", []), -1, [],
695    [InitNone, Always, TestOutputIntOp (
696       [["get_memsize"]], ">=", 256)],
697    "get memory allocated to the qemu subprocess",
698    "\
699 This gets the memory size in megabytes allocated to the
700 qemu subprocess.
701
702 If C<guestfs_set_memsize> was not called
703 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
704 then this returns the compiled-in default value for memsize.
705
706 For more information on the architecture of libguestfs,
707 see L<guestfs(3)>.");
708
709   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
710    [InitNone, Always, TestOutputIntOp (
711       [["get_pid"]], ">=", 1)],
712    "get PID of qemu subprocess",
713    "\
714 Return the process ID of the qemu subprocess.  If there is no
715 qemu subprocess, then this will return an error.
716
717 This is an internal call used for debugging and testing.");
718
719   ("version", (RStruct ("version", "version"), []), -1, [],
720    [InitNone, Always, TestOutputStruct (
721       [["version"]], [CompareWithInt ("major", 1)])],
722    "get the library version number",
723    "\
724 Return the libguestfs version number that the program is linked
725 against.
726
727 Note that because of dynamic linking this is not necessarily
728 the version of libguestfs that you compiled against.  You can
729 compile the program, and then at runtime dynamically link
730 against a completely different C<libguestfs.so> library.
731
732 This call was added in version C<1.0.58>.  In previous
733 versions of libguestfs there was no way to get the version
734 number.  From C code you can use ELF weak linking tricks to find out if
735 this symbol exists (if it doesn't, then it's an earlier version).
736
737 The call returns a structure with four elements.  The first
738 three (C<major>, C<minor> and C<release>) are numbers and
739 correspond to the usual version triplet.  The fourth element
740 (C<extra>) is a string and is normally empty, but may be
741 used for distro-specific information.
742
743 To construct the original version string:
744 C<$major.$minor.$release$extra>
745
746 I<Note:> Don't use this call to test for availability
747 of features.  Distro backports makes this unreliable.");
748
749 ]
750
751 (* daemon_functions are any functions which cause some action
752  * to take place in the daemon.
753  *)
754
755 let daemon_functions = [
756   ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
757    [InitEmpty, Always, TestOutput (
758       [["sfdiskM"; "/dev/sda"; ","];
759        ["mkfs"; "ext2"; "/dev/sda1"];
760        ["mount"; "/dev/sda1"; "/"];
761        ["write_file"; "/new"; "new file contents"; "0"];
762        ["cat"; "/new"]], "new file contents")],
763    "mount a guest disk at a position in the filesystem",
764    "\
765 Mount a guest disk at a position in the filesystem.  Block devices
766 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
767 the guest.  If those block devices contain partitions, they will have
768 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
769 names can be used.
770
771 The rules are the same as for L<mount(2)>:  A filesystem must
772 first be mounted on C</> before others can be mounted.  Other
773 filesystems can only be mounted on directories which already
774 exist.
775
776 The mounted filesystem is writable, if we have sufficient permissions
777 on the underlying device.
778
779 The filesystem options C<sync> and C<noatime> are set with this
780 call, in order to improve reliability.");
781
782   ("sync", (RErr, []), 2, [],
783    [ InitEmpty, Always, TestRun [["sync"]]],
784    "sync disks, writes are flushed through to the disk image",
785    "\
786 This syncs the disk, so that any writes are flushed through to the
787 underlying disk image.
788
789 You should always call this if you have modified a disk image, before
790 closing the handle.");
791
792   ("touch", (RErr, [String "path"]), 3, [],
793    [InitBasicFS, Always, TestOutputTrue (
794       [["touch"; "/new"];
795        ["exists"; "/new"]])],
796    "update file timestamps or create a new file",
797    "\
798 Touch acts like the L<touch(1)> command.  It can be used to
799 update the timestamps on a file, or, if the file does not exist,
800 to create a new zero-length file.");
801
802   ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
803    [InitBasicFS, Always, TestOutput (
804       [["write_file"; "/new"; "new file contents"; "0"];
805        ["cat"; "/new"]], "new file contents")],
806    "list the contents of a file",
807    "\
808 Return the contents of the file named C<path>.
809
810 Note that this function cannot correctly handle binary files
811 (specifically, files containing C<\\0> character which is treated
812 as end of string).  For those you need to use the C<guestfs_read_file>
813 or C<guestfs_download> functions which have a more complex interface.");
814
815   ("ll", (RString "listing", [String "directory"]), 5, [],
816    [], (* XXX Tricky to test because it depends on the exact format
817         * of the 'ls -l' command, which changes between F10 and F11.
818         *)
819    "list the files in a directory (long format)",
820    "\
821 List the files in C<directory> (relative to the root directory,
822 there is no cwd) in the format of 'ls -la'.
823
824 This command is mostly useful for interactive sessions.  It
825 is I<not> intended that you try to parse the output string.");
826
827   ("ls", (RStringList "listing", [String "directory"]), 6, [],
828    [InitBasicFS, Always, TestOutputList (
829       [["touch"; "/new"];
830        ["touch"; "/newer"];
831        ["touch"; "/newest"];
832        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
833    "list the files in a directory",
834    "\
835 List the files in C<directory> (relative to the root directory,
836 there is no cwd).  The '.' and '..' entries are not returned, but
837 hidden files are shown.
838
839 This command is mostly useful for interactive sessions.  Programs
840 should probably use C<guestfs_readdir> instead.");
841
842   ("list_devices", (RStringList "devices", []), 7, [],
843    [InitEmpty, Always, TestOutputListOfDevices (
844       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
845    "list the block devices",
846    "\
847 List all the block devices.
848
849 The full block device names are returned, eg. C</dev/sda>");
850
851   ("list_partitions", (RStringList "partitions", []), 8, [],
852    [InitBasicFS, Always, TestOutputListOfDevices (
853       [["list_partitions"]], ["/dev/sda1"]);
854     InitEmpty, Always, TestOutputListOfDevices (
855       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
856        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
857    "list the partitions",
858    "\
859 List all the partitions detected on all block devices.
860
861 The full partition device names are returned, eg. C</dev/sda1>
862
863 This does not return logical volumes.  For that you will need to
864 call C<guestfs_lvs>.");
865
866   ("pvs", (RStringList "physvols", []), 9, [],
867    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
868       [["pvs"]], ["/dev/sda1"]);
869     InitEmpty, Always, TestOutputListOfDevices (
870       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
871        ["pvcreate"; "/dev/sda1"];
872        ["pvcreate"; "/dev/sda2"];
873        ["pvcreate"; "/dev/sda3"];
874        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
875    "list the LVM physical volumes (PVs)",
876    "\
877 List all the physical volumes detected.  This is the equivalent
878 of the L<pvs(8)> command.
879
880 This returns a list of just the device names that contain
881 PVs (eg. C</dev/sda2>).
882
883 See also C<guestfs_pvs_full>.");
884
885   ("vgs", (RStringList "volgroups", []), 10, [],
886    [InitBasicFSonLVM, Always, TestOutputList (
887       [["vgs"]], ["VG"]);
888     InitEmpty, Always, TestOutputList (
889       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
890        ["pvcreate"; "/dev/sda1"];
891        ["pvcreate"; "/dev/sda2"];
892        ["pvcreate"; "/dev/sda3"];
893        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
894        ["vgcreate"; "VG2"; "/dev/sda3"];
895        ["vgs"]], ["VG1"; "VG2"])],
896    "list the LVM volume groups (VGs)",
897    "\
898 List all the volumes groups detected.  This is the equivalent
899 of the L<vgs(8)> command.
900
901 This returns a list of just the volume group names that were
902 detected (eg. C<VolGroup00>).
903
904 See also C<guestfs_vgs_full>.");
905
906   ("lvs", (RStringList "logvols", []), 11, [],
907    [InitBasicFSonLVM, Always, TestOutputList (
908       [["lvs"]], ["/dev/VG/LV"]);
909     InitEmpty, Always, TestOutputList (
910       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
911        ["pvcreate"; "/dev/sda1"];
912        ["pvcreate"; "/dev/sda2"];
913        ["pvcreate"; "/dev/sda3"];
914        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
915        ["vgcreate"; "VG2"; "/dev/sda3"];
916        ["lvcreate"; "LV1"; "VG1"; "50"];
917        ["lvcreate"; "LV2"; "VG1"; "50"];
918        ["lvcreate"; "LV3"; "VG2"; "50"];
919        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
920    "list the LVM logical volumes (LVs)",
921    "\
922 List all the logical volumes detected.  This is the equivalent
923 of the L<lvs(8)> command.
924
925 This returns a list of the logical volume device names
926 (eg. C</dev/VolGroup00/LogVol00>).
927
928 See also C<guestfs_lvs_full>.");
929
930   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [],
931    [], (* XXX how to test? *)
932    "list the LVM physical volumes (PVs)",
933    "\
934 List all the physical volumes detected.  This is the equivalent
935 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
936
937   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [],
938    [], (* XXX how to test? *)
939    "list the LVM volume groups (VGs)",
940    "\
941 List all the volumes groups detected.  This is the equivalent
942 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
943
944   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [],
945    [], (* XXX how to test? *)
946    "list the LVM logical volumes (LVs)",
947    "\
948 List all the logical volumes detected.  This is the equivalent
949 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
950
951   ("read_lines", (RStringList "lines", [String "path"]), 15, [],
952    [InitBasicFS, Always, TestOutputList (
953       [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
954        ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
955     InitBasicFS, Always, TestOutputList (
956       [["write_file"; "/new"; ""; "0"];
957        ["read_lines"; "/new"]], [])],
958    "read file as lines",
959    "\
960 Return the contents of the file named C<path>.
961
962 The file contents are returned as a list of lines.  Trailing
963 C<LF> and C<CRLF> character sequences are I<not> returned.
964
965 Note that this function cannot correctly handle binary files
966 (specifically, files containing C<\\0> character which is treated
967 as end of line).  For those you need to use the C<guestfs_read_file>
968 function which has a more complex interface.");
969
970   ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
971    [], (* XXX Augeas code needs tests. *)
972    "create a new Augeas handle",
973    "\
974 Create a new Augeas handle for editing configuration files.
975 If there was any previous Augeas handle associated with this
976 guestfs session, then it is closed.
977
978 You must call this before using any other C<guestfs_aug_*>
979 commands.
980
981 C<root> is the filesystem root.  C<root> must not be NULL,
982 use C</> instead.
983
984 The flags are the same as the flags defined in
985 E<lt>augeas.hE<gt>, the logical I<or> of the following
986 integers:
987
988 =over 4
989
990 =item C<AUG_SAVE_BACKUP> = 1
991
992 Keep the original file with a C<.augsave> extension.
993
994 =item C<AUG_SAVE_NEWFILE> = 2
995
996 Save changes into a file with extension C<.augnew>, and
997 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
998
999 =item C<AUG_TYPE_CHECK> = 4
1000
1001 Typecheck lenses (can be expensive).
1002
1003 =item C<AUG_NO_STDINC> = 8
1004
1005 Do not use standard load path for modules.
1006
1007 =item C<AUG_SAVE_NOOP> = 16
1008
1009 Make save a no-op, just record what would have been changed.
1010
1011 =item C<AUG_NO_LOAD> = 32
1012
1013 Do not load the tree in C<guestfs_aug_init>.
1014
1015 =back
1016
1017 To close the handle, you can call C<guestfs_aug_close>.
1018
1019 To find out more about Augeas, see L<http://augeas.net/>.");
1020
1021   ("aug_close", (RErr, []), 26, [],
1022    [], (* XXX Augeas code needs tests. *)
1023    "close the current Augeas handle",
1024    "\
1025 Close the current Augeas handle and free up any resources
1026 used by it.  After calling this, you have to call
1027 C<guestfs_aug_init> again before you can use any other
1028 Augeas functions.");
1029
1030   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
1031    [], (* XXX Augeas code needs tests. *)
1032    "define an Augeas variable",
1033    "\
1034 Defines an Augeas variable C<name> whose value is the result
1035 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1036 undefined.
1037
1038 On success this returns the number of nodes in C<expr>, or
1039 C<0> if C<expr> evaluates to something which is not a nodeset.");
1040
1041   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [],
1042    [], (* XXX Augeas code needs tests. *)
1043    "define an Augeas node",
1044    "\
1045 Defines a variable C<name> whose value is the result of
1046 evaluating C<expr>.
1047
1048 If C<expr> evaluates to an empty nodeset, a node is created,
1049 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1050 C<name> will be the nodeset containing that single node.
1051
1052 On success this returns a pair containing the
1053 number of nodes in the nodeset, and a boolean flag
1054 if a node was created.");
1055
1056   ("aug_get", (RString "val", [String "path"]), 19, [],
1057    [], (* XXX Augeas code needs tests. *)
1058    "look up the value of an Augeas path",
1059    "\
1060 Look up the value associated with C<path>.  If C<path>
1061 matches exactly one node, the C<value> is returned.");
1062
1063   ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
1064    [], (* XXX Augeas code needs tests. *)
1065    "set Augeas path to value",
1066    "\
1067 Set the value associated with C<path> to C<value>.");
1068
1069   ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
1070    [], (* XXX Augeas code needs tests. *)
1071    "insert a sibling Augeas node",
1072    "\
1073 Create a new sibling C<label> for C<path>, inserting it into
1074 the tree before or after C<path> (depending on the boolean
1075 flag C<before>).
1076
1077 C<path> must match exactly one existing node in the tree, and
1078 C<label> must be a label, ie. not contain C</>, C<*> or end
1079 with a bracketed index C<[N]>.");
1080
1081   ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
1082    [], (* XXX Augeas code needs tests. *)
1083    "remove an Augeas path",
1084    "\
1085 Remove C<path> and all of its children.
1086
1087 On success this returns the number of entries which were removed.");
1088
1089   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
1090    [], (* XXX Augeas code needs tests. *)
1091    "move Augeas node",
1092    "\
1093 Move the node C<src> to C<dest>.  C<src> must match exactly
1094 one node.  C<dest> is overwritten if it exists.");
1095
1096   ("aug_match", (RStringList "matches", [String "path"]), 24, [],
1097    [], (* XXX Augeas code needs tests. *)
1098    "return Augeas nodes which match path",
1099    "\
1100 Returns a list of paths which match the path expression C<path>.
1101 The returned paths are sufficiently qualified so that they match
1102 exactly one node in the current tree.");
1103
1104   ("aug_save", (RErr, []), 25, [],
1105    [], (* XXX Augeas code needs tests. *)
1106    "write all pending Augeas changes to disk",
1107    "\
1108 This writes all pending changes to disk.
1109
1110 The flags which were passed to C<guestfs_aug_init> affect exactly
1111 how files are saved.");
1112
1113   ("aug_load", (RErr, []), 27, [],
1114    [], (* XXX Augeas code needs tests. *)
1115    "load files into the tree",
1116    "\
1117 Load files into the tree.
1118
1119 See C<aug_load> in the Augeas documentation for the full gory
1120 details.");
1121
1122   ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
1123    [], (* XXX Augeas code needs tests. *)
1124    "list Augeas nodes under a path",
1125    "\
1126 This is just a shortcut for listing C<guestfs_aug_match>
1127 C<path/*> and sorting the resulting nodes into alphabetical order.");
1128
1129   ("rm", (RErr, [String "path"]), 29, [],
1130    [InitBasicFS, Always, TestRun
1131       [["touch"; "/new"];
1132        ["rm"; "/new"]];
1133     InitBasicFS, Always, TestLastFail
1134       [["rm"; "/new"]];
1135     InitBasicFS, Always, TestLastFail
1136       [["mkdir"; "/new"];
1137        ["rm"; "/new"]]],
1138    "remove a file",
1139    "\
1140 Remove the single file C<path>.");
1141
1142   ("rmdir", (RErr, [String "path"]), 30, [],
1143    [InitBasicFS, Always, TestRun
1144       [["mkdir"; "/new"];
1145        ["rmdir"; "/new"]];
1146     InitBasicFS, Always, TestLastFail
1147       [["rmdir"; "/new"]];
1148     InitBasicFS, Always, TestLastFail
1149       [["touch"; "/new"];
1150        ["rmdir"; "/new"]]],
1151    "remove a directory",
1152    "\
1153 Remove the single directory C<path>.");
1154
1155   ("rm_rf", (RErr, [String "path"]), 31, [],
1156    [InitBasicFS, Always, TestOutputFalse
1157       [["mkdir"; "/new"];
1158        ["mkdir"; "/new/foo"];
1159        ["touch"; "/new/foo/bar"];
1160        ["rm_rf"; "/new"];
1161        ["exists"; "/new"]]],
1162    "remove a file or directory recursively",
1163    "\
1164 Remove the file or directory C<path>, recursively removing the
1165 contents if its a directory.  This is like the C<rm -rf> shell
1166 command.");
1167
1168   ("mkdir", (RErr, [String "path"]), 32, [],
1169    [InitBasicFS, Always, TestOutputTrue
1170       [["mkdir"; "/new"];
1171        ["is_dir"; "/new"]];
1172     InitBasicFS, Always, TestLastFail
1173       [["mkdir"; "/new/foo/bar"]]],
1174    "create a directory",
1175    "\
1176 Create a directory named C<path>.");
1177
1178   ("mkdir_p", (RErr, [String "path"]), 33, [],
1179    [InitBasicFS, Always, TestOutputTrue
1180       [["mkdir_p"; "/new/foo/bar"];
1181        ["is_dir"; "/new/foo/bar"]];
1182     InitBasicFS, Always, TestOutputTrue
1183       [["mkdir_p"; "/new/foo/bar"];
1184        ["is_dir"; "/new/foo"]];
1185     InitBasicFS, Always, TestOutputTrue
1186       [["mkdir_p"; "/new/foo/bar"];
1187        ["is_dir"; "/new"]];
1188     (* Regression tests for RHBZ#503133: *)
1189     InitBasicFS, Always, TestRun
1190       [["mkdir"; "/new"];
1191        ["mkdir_p"; "/new"]];
1192     InitBasicFS, Always, TestLastFail
1193       [["touch"; "/new"];
1194        ["mkdir_p"; "/new"]]],
1195    "create a directory and parents",
1196    "\
1197 Create a directory named C<path>, creating any parent directories
1198 as necessary.  This is like the C<mkdir -p> shell command.");
1199
1200   ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1201    [], (* XXX Need stat command to test *)
1202    "change file mode",
1203    "\
1204 Change the mode (permissions) of C<path> to C<mode>.  Only
1205 numeric modes are supported.");
1206
1207   ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1208    [], (* XXX Need stat command to test *)
1209    "change file owner and group",
1210    "\
1211 Change the file owner to C<owner> and group to C<group>.
1212
1213 Only numeric uid and gid are supported.  If you want to use
1214 names, you will need to locate and parse the password file
1215 yourself (Augeas support makes this relatively easy).");
1216
1217   ("exists", (RBool "existsflag", [String "path"]), 36, [],
1218    [InitBasicFS, Always, TestOutputTrue (
1219       [["touch"; "/new"];
1220        ["exists"; "/new"]]);
1221     InitBasicFS, Always, TestOutputTrue (
1222       [["mkdir"; "/new"];
1223        ["exists"; "/new"]])],
1224    "test if file or directory exists",
1225    "\
1226 This returns C<true> if and only if there is a file, directory
1227 (or anything) with the given C<path> name.
1228
1229 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1230
1231   ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1232    [InitBasicFS, Always, TestOutputTrue (
1233       [["touch"; "/new"];
1234        ["is_file"; "/new"]]);
1235     InitBasicFS, Always, TestOutputFalse (
1236       [["mkdir"; "/new"];
1237        ["is_file"; "/new"]])],
1238    "test if file exists",
1239    "\
1240 This returns C<true> if and only if there is a file
1241 with the given C<path> name.  Note that it returns false for
1242 other objects like directories.
1243
1244 See also C<guestfs_stat>.");
1245
1246   ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1247    [InitBasicFS, Always, TestOutputFalse (
1248       [["touch"; "/new"];
1249        ["is_dir"; "/new"]]);
1250     InitBasicFS, Always, TestOutputTrue (
1251       [["mkdir"; "/new"];
1252        ["is_dir"; "/new"]])],
1253    "test if file exists",
1254    "\
1255 This returns C<true> if and only if there is a directory
1256 with the given C<path> name.  Note that it returns false for
1257 other objects like files.
1258
1259 See also C<guestfs_stat>.");
1260
1261   ("pvcreate", (RErr, [String "device"]), 39, [],
1262    [InitEmpty, Always, TestOutputListOfDevices (
1263       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1264        ["pvcreate"; "/dev/sda1"];
1265        ["pvcreate"; "/dev/sda2"];
1266        ["pvcreate"; "/dev/sda3"];
1267        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1268    "create an LVM physical volume",
1269    "\
1270 This creates an LVM physical volume on the named C<device>,
1271 where C<device> should usually be a partition name such
1272 as C</dev/sda1>.");
1273
1274   ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1275    [InitEmpty, Always, TestOutputList (
1276       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1277        ["pvcreate"; "/dev/sda1"];
1278        ["pvcreate"; "/dev/sda2"];
1279        ["pvcreate"; "/dev/sda3"];
1280        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1281        ["vgcreate"; "VG2"; "/dev/sda3"];
1282        ["vgs"]], ["VG1"; "VG2"])],
1283    "create an LVM volume group",
1284    "\
1285 This creates an LVM volume group called C<volgroup>
1286 from the non-empty list of physical volumes C<physvols>.");
1287
1288   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1289    [InitEmpty, Always, TestOutputList (
1290       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1291        ["pvcreate"; "/dev/sda1"];
1292        ["pvcreate"; "/dev/sda2"];
1293        ["pvcreate"; "/dev/sda3"];
1294        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1295        ["vgcreate"; "VG2"; "/dev/sda3"];
1296        ["lvcreate"; "LV1"; "VG1"; "50"];
1297        ["lvcreate"; "LV2"; "VG1"; "50"];
1298        ["lvcreate"; "LV3"; "VG2"; "50"];
1299        ["lvcreate"; "LV4"; "VG2"; "50"];
1300        ["lvcreate"; "LV5"; "VG2"; "50"];
1301        ["lvs"]],
1302       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1303        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1304    "create an LVM volume group",
1305    "\
1306 This creates an LVM volume group called C<logvol>
1307 on the volume group C<volgroup>, with C<size> megabytes.");
1308
1309   ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1310    [InitEmpty, Always, TestOutput (
1311       [["sfdiskM"; "/dev/sda"; ","];
1312        ["mkfs"; "ext2"; "/dev/sda1"];
1313        ["mount"; "/dev/sda1"; "/"];
1314        ["write_file"; "/new"; "new file contents"; "0"];
1315        ["cat"; "/new"]], "new file contents")],
1316    "make a filesystem",
1317    "\
1318 This creates a filesystem on C<device> (usually a partition
1319 or LVM logical volume).  The filesystem type is C<fstype>, for
1320 example C<ext3>.");
1321
1322   ("sfdisk", (RErr, [String "device";
1323                      Int "cyls"; Int "heads"; Int "sectors";
1324                      StringList "lines"]), 43, [DangerWillRobinson],
1325    [],
1326    "create partitions on a block device",
1327    "\
1328 This is a direct interface to the L<sfdisk(8)> program for creating
1329 partitions on block devices.
1330
1331 C<device> should be a block device, for example C</dev/sda>.
1332
1333 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1334 and sectors on the device, which are passed directly to sfdisk as
1335 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1336 of these, then the corresponding parameter is omitted.  Usually for
1337 'large' disks, you can just pass C<0> for these, but for small
1338 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1339 out the right geometry and you will need to tell it.
1340
1341 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1342 information refer to the L<sfdisk(8)> manpage.
1343
1344 To create a single partition occupying the whole disk, you would
1345 pass C<lines> as a single element list, when the single element being
1346 the string C<,> (comma).
1347
1348 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1349
1350   ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1351    [InitBasicFS, Always, TestOutput (
1352       [["write_file"; "/new"; "new file contents"; "0"];
1353        ["cat"; "/new"]], "new file contents");
1354     InitBasicFS, Always, TestOutput (
1355       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1356        ["cat"; "/new"]], "\nnew file contents\n");
1357     InitBasicFS, Always, TestOutput (
1358       [["write_file"; "/new"; "\n\n"; "0"];
1359        ["cat"; "/new"]], "\n\n");
1360     InitBasicFS, Always, TestOutput (
1361       [["write_file"; "/new"; ""; "0"];
1362        ["cat"; "/new"]], "");
1363     InitBasicFS, Always, TestOutput (
1364       [["write_file"; "/new"; "\n\n\n"; "0"];
1365        ["cat"; "/new"]], "\n\n\n");
1366     InitBasicFS, Always, TestOutput (
1367       [["write_file"; "/new"; "\n"; "0"];
1368        ["cat"; "/new"]], "\n")],
1369    "create a file",
1370    "\
1371 This call creates a file called C<path>.  The contents of the
1372 file is the string C<content> (which can contain any 8 bit data),
1373 with length C<size>.
1374
1375 As a special case, if C<size> is C<0>
1376 then the length is calculated using C<strlen> (so in this case
1377 the content cannot contain embedded ASCII NULs).
1378
1379 I<NB.> Owing to a bug, writing content containing ASCII NUL
1380 characters does I<not> work, even if the length is specified.
1381 We hope to resolve this bug in a future version.  In the meantime
1382 use C<guestfs_upload>.");
1383
1384   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1385    [InitEmpty, Always, TestOutputListOfDevices (
1386       [["sfdiskM"; "/dev/sda"; ","];
1387        ["mkfs"; "ext2"; "/dev/sda1"];
1388        ["mount"; "/dev/sda1"; "/"];
1389        ["mounts"]], ["/dev/sda1"]);
1390     InitEmpty, Always, TestOutputList (
1391       [["sfdiskM"; "/dev/sda"; ","];
1392        ["mkfs"; "ext2"; "/dev/sda1"];
1393        ["mount"; "/dev/sda1"; "/"];
1394        ["umount"; "/"];
1395        ["mounts"]], [])],
1396    "unmount a filesystem",
1397    "\
1398 This unmounts the given filesystem.  The filesystem may be
1399 specified either by its mountpoint (path) or the device which
1400 contains the filesystem.");
1401
1402   ("mounts", (RStringList "devices", []), 46, [],
1403    [InitBasicFS, Always, TestOutputListOfDevices (
1404       [["mounts"]], ["/dev/sda1"])],
1405    "show mounted filesystems",
1406    "\
1407 This returns the list of currently mounted filesystems.  It returns
1408 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1409
1410 Some internal mounts are not shown.
1411
1412 See also: C<guestfs_mountpoints>");
1413
1414   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1415    [InitBasicFS, Always, TestOutputList (
1416       [["umount_all"];
1417        ["mounts"]], []);
1418     (* check that umount_all can unmount nested mounts correctly: *)
1419     InitEmpty, Always, TestOutputList (
1420       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1421        ["mkfs"; "ext2"; "/dev/sda1"];
1422        ["mkfs"; "ext2"; "/dev/sda2"];
1423        ["mkfs"; "ext2"; "/dev/sda3"];
1424        ["mount"; "/dev/sda1"; "/"];
1425        ["mkdir"; "/mp1"];
1426        ["mount"; "/dev/sda2"; "/mp1"];
1427        ["mkdir"; "/mp1/mp2"];
1428        ["mount"; "/dev/sda3"; "/mp1/mp2"];
1429        ["mkdir"; "/mp1/mp2/mp3"];
1430        ["umount_all"];
1431        ["mounts"]], [])],
1432    "unmount all filesystems",
1433    "\
1434 This unmounts all mounted filesystems.
1435
1436 Some internal mounts are not unmounted by this call.");
1437
1438   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1439    [],
1440    "remove all LVM LVs, VGs and PVs",
1441    "\
1442 This command removes all LVM logical volumes, volume groups
1443 and physical volumes.");
1444
1445   ("file", (RString "description", [String "path"]), 49, [],
1446    [InitBasicFS, Always, TestOutput (
1447       [["touch"; "/new"];
1448        ["file"; "/new"]], "empty");
1449     InitBasicFS, Always, TestOutput (
1450       [["write_file"; "/new"; "some content\n"; "0"];
1451        ["file"; "/new"]], "ASCII text");
1452     InitBasicFS, Always, TestLastFail (
1453       [["file"; "/nofile"]])],
1454    "determine file type",
1455    "\
1456 This call uses the standard L<file(1)> command to determine
1457 the type or contents of the file.  This also works on devices,
1458 for example to find out whether a partition contains a filesystem.
1459
1460 The exact command which runs is C<file -bsL path>.  Note in
1461 particular that the filename is not prepended to the output
1462 (the C<-b> option).");
1463
1464   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1465    [InitBasicFS, Always, TestOutput (
1466       [["upload"; "test-command"; "/test-command"];
1467        ["chmod"; "0o755"; "/test-command"];
1468        ["command"; "/test-command 1"]], "Result1");
1469     InitBasicFS, Always, TestOutput (
1470       [["upload"; "test-command"; "/test-command"];
1471        ["chmod"; "0o755"; "/test-command"];
1472        ["command"; "/test-command 2"]], "Result2\n");
1473     InitBasicFS, Always, TestOutput (
1474       [["upload"; "test-command"; "/test-command"];
1475        ["chmod"; "0o755"; "/test-command"];
1476        ["command"; "/test-command 3"]], "\nResult3");
1477     InitBasicFS, Always, TestOutput (
1478       [["upload"; "test-command"; "/test-command"];
1479        ["chmod"; "0o755"; "/test-command"];
1480        ["command"; "/test-command 4"]], "\nResult4\n");
1481     InitBasicFS, Always, TestOutput (
1482       [["upload"; "test-command"; "/test-command"];
1483        ["chmod"; "0o755"; "/test-command"];
1484        ["command"; "/test-command 5"]], "\nResult5\n\n");
1485     InitBasicFS, Always, TestOutput (
1486       [["upload"; "test-command"; "/test-command"];
1487        ["chmod"; "0o755"; "/test-command"];
1488        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1489     InitBasicFS, Always, TestOutput (
1490       [["upload"; "test-command"; "/test-command"];
1491        ["chmod"; "0o755"; "/test-command"];
1492        ["command"; "/test-command 7"]], "");
1493     InitBasicFS, Always, TestOutput (
1494       [["upload"; "test-command"; "/test-command"];
1495        ["chmod"; "0o755"; "/test-command"];
1496        ["command"; "/test-command 8"]], "\n");
1497     InitBasicFS, Always, TestOutput (
1498       [["upload"; "test-command"; "/test-command"];
1499        ["chmod"; "0o755"; "/test-command"];
1500        ["command"; "/test-command 9"]], "\n\n");
1501     InitBasicFS, Always, TestOutput (
1502       [["upload"; "test-command"; "/test-command"];
1503        ["chmod"; "0o755"; "/test-command"];
1504        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1505     InitBasicFS, Always, TestOutput (
1506       [["upload"; "test-command"; "/test-command"];
1507        ["chmod"; "0o755"; "/test-command"];
1508        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1509     InitBasicFS, Always, TestLastFail (
1510       [["upload"; "test-command"; "/test-command"];
1511        ["chmod"; "0o755"; "/test-command"];
1512        ["command"; "/test-command"]])],
1513    "run a command from the guest filesystem",
1514    "\
1515 This call runs a command from the guest filesystem.  The
1516 filesystem must be mounted, and must contain a compatible
1517 operating system (ie. something Linux, with the same
1518 or compatible processor architecture).
1519
1520 The single parameter is an argv-style list of arguments.
1521 The first element is the name of the program to run.
1522 Subsequent elements are parameters.  The list must be
1523 non-empty (ie. must contain a program name).  Note that
1524 the command runs directly, and is I<not> invoked via
1525 the shell (see C<guestfs_sh>).
1526
1527 The return value is anything printed to I<stdout> by
1528 the command.
1529
1530 If the command returns a non-zero exit status, then
1531 this function returns an error message.  The error message
1532 string is the content of I<stderr> from the command.
1533
1534 The C<$PATH> environment variable will contain at least
1535 C</usr/bin> and C</bin>.  If you require a program from
1536 another location, you should provide the full path in the
1537 first parameter.
1538
1539 Shared libraries and data files required by the program
1540 must be available on filesystems which are mounted in the
1541 correct places.  It is the caller's responsibility to ensure
1542 all filesystems that are needed are mounted at the right
1543 locations.");
1544
1545   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1546    [InitBasicFS, Always, TestOutputList (
1547       [["upload"; "test-command"; "/test-command"];
1548        ["chmod"; "0o755"; "/test-command"];
1549        ["command_lines"; "/test-command 1"]], ["Result1"]);
1550     InitBasicFS, Always, TestOutputList (
1551       [["upload"; "test-command"; "/test-command"];
1552        ["chmod"; "0o755"; "/test-command"];
1553        ["command_lines"; "/test-command 2"]], ["Result2"]);
1554     InitBasicFS, Always, TestOutputList (
1555       [["upload"; "test-command"; "/test-command"];
1556        ["chmod"; "0o755"; "/test-command"];
1557        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1558     InitBasicFS, Always, TestOutputList (
1559       [["upload"; "test-command"; "/test-command"];
1560        ["chmod"; "0o755"; "/test-command"];
1561        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1562     InitBasicFS, Always, TestOutputList (
1563       [["upload"; "test-command"; "/test-command"];
1564        ["chmod"; "0o755"; "/test-command"];
1565        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1566     InitBasicFS, Always, TestOutputList (
1567       [["upload"; "test-command"; "/test-command"];
1568        ["chmod"; "0o755"; "/test-command"];
1569        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1570     InitBasicFS, Always, TestOutputList (
1571       [["upload"; "test-command"; "/test-command"];
1572        ["chmod"; "0o755"; "/test-command"];
1573        ["command_lines"; "/test-command 7"]], []);
1574     InitBasicFS, Always, TestOutputList (
1575       [["upload"; "test-command"; "/test-command"];
1576        ["chmod"; "0o755"; "/test-command"];
1577        ["command_lines"; "/test-command 8"]], [""]);
1578     InitBasicFS, Always, TestOutputList (
1579       [["upload"; "test-command"; "/test-command"];
1580        ["chmod"; "0o755"; "/test-command"];
1581        ["command_lines"; "/test-command 9"]], ["";""]);
1582     InitBasicFS, Always, TestOutputList (
1583       [["upload"; "test-command"; "/test-command"];
1584        ["chmod"; "0o755"; "/test-command"];
1585        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1586     InitBasicFS, Always, TestOutputList (
1587       [["upload"; "test-command"; "/test-command"];
1588        ["chmod"; "0o755"; "/test-command"];
1589        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1590    "run a command, returning lines",
1591    "\
1592 This is the same as C<guestfs_command>, but splits the
1593 result into a list of lines.
1594
1595 See also: C<guestfs_sh_lines>");
1596
1597   ("stat", (RStruct ("statbuf", "stat"), [String "path"]), 52, [],
1598    [InitBasicFS, Always, TestOutputStruct (
1599       [["touch"; "/new"];
1600        ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
1601    "get file information",
1602    "\
1603 Returns file information for the given C<path>.
1604
1605 This is the same as the C<stat(2)> system call.");
1606
1607   ("lstat", (RStruct ("statbuf", "stat"), [String "path"]), 53, [],
1608    [InitBasicFS, Always, TestOutputStruct (
1609       [["touch"; "/new"];
1610        ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
1611    "get file information for a symbolic link",
1612    "\
1613 Returns file information for the given C<path>.
1614
1615 This is the same as C<guestfs_stat> except that if C<path>
1616 is a symbolic link, then the link is stat-ed, not the file it
1617 refers to.
1618
1619 This is the same as the C<lstat(2)> system call.");
1620
1621   ("statvfs", (RStruct ("statbuf", "statvfs"), [String "path"]), 54, [],
1622    [InitBasicFS, Always, TestOutputStruct (
1623       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255);
1624                            CompareWithInt ("bsize", 1024)])],
1625    "get file system statistics",
1626    "\
1627 Returns file system statistics for any mounted file system.
1628 C<path> should be a file or directory in the mounted file system
1629 (typically it is the mount point itself, but it doesn't need to be).
1630
1631 This is the same as the C<statvfs(2)> system call.");
1632
1633   ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1634    [], (* XXX test *)
1635    "get ext2/ext3/ext4 superblock details",
1636    "\
1637 This returns the contents of the ext2, ext3 or ext4 filesystem
1638 superblock on C<device>.
1639
1640 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1641 manpage for more details.  The list of fields returned isn't
1642 clearly defined, and depends on both the version of C<tune2fs>
1643 that libguestfs was built against, and the filesystem itself.");
1644
1645   ("blockdev_setro", (RErr, [String "device"]), 56, [],
1646    [InitEmpty, Always, TestOutputTrue (
1647       [["blockdev_setro"; "/dev/sda"];
1648        ["blockdev_getro"; "/dev/sda"]])],
1649    "set block device to read-only",
1650    "\
1651 Sets the block device named C<device> to read-only.
1652
1653 This uses the L<blockdev(8)> command.");
1654
1655   ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1656    [InitEmpty, Always, TestOutputFalse (
1657       [["blockdev_setrw"; "/dev/sda"];
1658        ["blockdev_getro"; "/dev/sda"]])],
1659    "set block device to read-write",
1660    "\
1661 Sets the block device named C<device> to read-write.
1662
1663 This uses the L<blockdev(8)> command.");
1664
1665   ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1666    [InitEmpty, Always, TestOutputTrue (
1667       [["blockdev_setro"; "/dev/sda"];
1668        ["blockdev_getro"; "/dev/sda"]])],
1669    "is block device set to read-only",
1670    "\
1671 Returns a boolean indicating if the block device is read-only
1672 (true if read-only, false if not).
1673
1674 This uses the L<blockdev(8)> command.");
1675
1676   ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1677    [InitEmpty, Always, TestOutputInt (
1678       [["blockdev_getss"; "/dev/sda"]], 512)],
1679    "get sectorsize of block device",
1680    "\
1681 This returns the size of sectors on a block device.
1682 Usually 512, but can be larger for modern devices.
1683
1684 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1685 for that).
1686
1687 This uses the L<blockdev(8)> command.");
1688
1689   ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1690    [InitEmpty, Always, TestOutputInt (
1691       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1692    "get blocksize of block device",
1693    "\
1694 This returns the block size of a device.
1695
1696 (Note this is different from both I<size in blocks> and
1697 I<filesystem block size>).
1698
1699 This uses the L<blockdev(8)> command.");
1700
1701   ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1702    [], (* XXX test *)
1703    "set blocksize of block device",
1704    "\
1705 This sets the block size of a device.
1706
1707 (Note this is different from both I<size in blocks> and
1708 I<filesystem block size>).
1709
1710 This uses the L<blockdev(8)> command.");
1711
1712   ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1713    [InitEmpty, Always, TestOutputInt (
1714       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1715    "get total size of device in 512-byte sectors",
1716    "\
1717 This returns the size of the device in units of 512-byte sectors
1718 (even if the sectorsize isn't 512 bytes ... weird).
1719
1720 See also C<guestfs_blockdev_getss> for the real sector size of
1721 the device, and C<guestfs_blockdev_getsize64> for the more
1722 useful I<size in bytes>.
1723
1724 This uses the L<blockdev(8)> command.");
1725
1726   ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1727    [InitEmpty, Always, TestOutputInt (
1728       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1729    "get total size of device in bytes",
1730    "\
1731 This returns the size of the device in bytes.
1732
1733 See also C<guestfs_blockdev_getsz>.
1734
1735 This uses the L<blockdev(8)> command.");
1736
1737   ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1738    [InitEmpty, Always, TestRun
1739       [["blockdev_flushbufs"; "/dev/sda"]]],
1740    "flush device buffers",
1741    "\
1742 This tells the kernel to flush internal buffers associated
1743 with C<device>.
1744
1745 This uses the L<blockdev(8)> command.");
1746
1747   ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1748    [InitEmpty, Always, TestRun
1749       [["blockdev_rereadpt"; "/dev/sda"]]],
1750    "reread partition table",
1751    "\
1752 Reread the partition table on C<device>.
1753
1754 This uses the L<blockdev(8)> command.");
1755
1756   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1757    [InitBasicFS, Always, TestOutput (
1758       (* Pick a file from cwd which isn't likely to change. *)
1759       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1760        ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1761    "upload a file from the local machine",
1762    "\
1763 Upload local file C<filename> to C<remotefilename> on the
1764 filesystem.
1765
1766 C<filename> can also be a named pipe.
1767
1768 See also C<guestfs_download>.");
1769
1770   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1771    [InitBasicFS, Always, TestOutput (
1772       (* Pick a file from cwd which isn't likely to change. *)
1773       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1774        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1775        ["upload"; "testdownload.tmp"; "/upload"];
1776        ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1777    "download a file to the local machine",
1778    "\
1779 Download file C<remotefilename> and save it as C<filename>
1780 on the local machine.
1781
1782 C<filename> can also be a named pipe.
1783
1784 See also C<guestfs_upload>, C<guestfs_cat>.");
1785
1786   ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1787    [InitBasicFS, Always, TestOutput (
1788       [["write_file"; "/new"; "test\n"; "0"];
1789        ["checksum"; "crc"; "/new"]], "935282863");
1790     InitBasicFS, Always, TestLastFail (
1791       [["checksum"; "crc"; "/new"]]);
1792     InitBasicFS, Always, TestOutput (
1793       [["write_file"; "/new"; "test\n"; "0"];
1794        ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
1795     InitBasicFS, Always, TestOutput (
1796       [["write_file"; "/new"; "test\n"; "0"];
1797        ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
1798     InitBasicFS, Always, TestOutput (
1799       [["write_file"; "/new"; "test\n"; "0"];
1800        ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
1801     InitBasicFS, Always, TestOutput (
1802       [["write_file"; "/new"; "test\n"; "0"];
1803        ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
1804     InitBasicFS, Always, TestOutput (
1805       [["write_file"; "/new"; "test\n"; "0"];
1806        ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
1807     InitBasicFS, Always, TestOutput (
1808       [["write_file"; "/new"; "test\n"; "0"];
1809        ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
1810     InitSquashFS, Always, TestOutput (
1811       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
1812    "compute MD5, SHAx or CRC checksum of file",
1813    "\
1814 This call computes the MD5, SHAx or CRC checksum of the
1815 file named C<path>.
1816
1817 The type of checksum to compute is given by the C<csumtype>
1818 parameter which must have one of the following values:
1819
1820 =over 4
1821
1822 =item C<crc>
1823
1824 Compute the cyclic redundancy check (CRC) specified by POSIX
1825 for the C<cksum> command.
1826
1827 =item C<md5>
1828
1829 Compute the MD5 hash (using the C<md5sum> program).
1830
1831 =item C<sha1>
1832
1833 Compute the SHA1 hash (using the C<sha1sum> program).
1834
1835 =item C<sha224>
1836
1837 Compute the SHA224 hash (using the C<sha224sum> program).
1838
1839 =item C<sha256>
1840
1841 Compute the SHA256 hash (using the C<sha256sum> program).
1842
1843 =item C<sha384>
1844
1845 Compute the SHA384 hash (using the C<sha384sum> program).
1846
1847 =item C<sha512>
1848
1849 Compute the SHA512 hash (using the C<sha512sum> program).
1850
1851 =back
1852
1853 The checksum is returned as a printable string.");
1854
1855   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1856    [InitBasicFS, Always, TestOutput (
1857       [["tar_in"; "../images/helloworld.tar"; "/"];
1858        ["cat"; "/hello"]], "hello\n")],
1859    "unpack tarfile to directory",
1860    "\
1861 This command uploads and unpacks local file C<tarfile> (an
1862 I<uncompressed> tar file) into C<directory>.
1863
1864 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1865
1866   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1867    [],
1868    "pack directory into tarfile",
1869    "\
1870 This command packs the contents of C<directory> and downloads
1871 it to local file C<tarfile>.
1872
1873 To download a compressed tarball, use C<guestfs_tgz_out>.");
1874
1875   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1876    [InitBasicFS, Always, TestOutput (
1877       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1878        ["cat"; "/hello"]], "hello\n")],
1879    "unpack compressed tarball to directory",
1880    "\
1881 This command uploads and unpacks local file C<tarball> (a
1882 I<gzip compressed> tar file) into C<directory>.
1883
1884 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1885
1886   ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1887    [],
1888    "pack directory into compressed tarball",
1889    "\
1890 This command packs the contents of C<directory> and downloads
1891 it to local file C<tarball>.
1892
1893 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1894
1895   ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1896    [InitBasicFS, Always, TestLastFail (
1897       [["umount"; "/"];
1898        ["mount_ro"; "/dev/sda1"; "/"];
1899        ["touch"; "/new"]]);
1900     InitBasicFS, Always, TestOutput (
1901       [["write_file"; "/new"; "data"; "0"];
1902        ["umount"; "/"];
1903        ["mount_ro"; "/dev/sda1"; "/"];
1904        ["cat"; "/new"]], "data")],
1905    "mount a guest disk, read-only",
1906    "\
1907 This is the same as the C<guestfs_mount> command, but it
1908 mounts the filesystem with the read-only (I<-o ro>) flag.");
1909
1910   ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1911    [],
1912    "mount a guest disk with mount options",
1913    "\
1914 This is the same as the C<guestfs_mount> command, but it
1915 allows you to set the mount options as for the
1916 L<mount(8)> I<-o> flag.");
1917
1918   ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1919    [],
1920    "mount a guest disk with mount options and vfstype",
1921    "\
1922 This is the same as the C<guestfs_mount> command, but it
1923 allows you to set both the mount options and the vfstype
1924 as for the L<mount(8)> I<-o> and I<-t> flags.");
1925
1926   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1927    [],
1928    "debugging and internals",
1929    "\
1930 The C<guestfs_debug> command exposes some internals of
1931 C<guestfsd> (the guestfs daemon) that runs inside the
1932 qemu subprocess.
1933
1934 There is no comprehensive help for this command.  You have
1935 to look at the file C<daemon/debug.c> in the libguestfs source
1936 to find out what you can do.");
1937
1938   ("lvremove", (RErr, [String "device"]), 77, [],
1939    [InitEmpty, Always, TestOutputList (
1940       [["sfdiskM"; "/dev/sda"; ","];
1941        ["pvcreate"; "/dev/sda1"];
1942        ["vgcreate"; "VG"; "/dev/sda1"];
1943        ["lvcreate"; "LV1"; "VG"; "50"];
1944        ["lvcreate"; "LV2"; "VG"; "50"];
1945        ["lvremove"; "/dev/VG/LV1"];
1946        ["lvs"]], ["/dev/VG/LV2"]);
1947     InitEmpty, Always, TestOutputList (
1948       [["sfdiskM"; "/dev/sda"; ","];
1949        ["pvcreate"; "/dev/sda1"];
1950        ["vgcreate"; "VG"; "/dev/sda1"];
1951        ["lvcreate"; "LV1"; "VG"; "50"];
1952        ["lvcreate"; "LV2"; "VG"; "50"];
1953        ["lvremove"; "/dev/VG"];
1954        ["lvs"]], []);
1955     InitEmpty, Always, TestOutputList (
1956       [["sfdiskM"; "/dev/sda"; ","];
1957        ["pvcreate"; "/dev/sda1"];
1958        ["vgcreate"; "VG"; "/dev/sda1"];
1959        ["lvcreate"; "LV1"; "VG"; "50"];
1960        ["lvcreate"; "LV2"; "VG"; "50"];
1961        ["lvremove"; "/dev/VG"];
1962        ["vgs"]], ["VG"])],
1963    "remove an LVM logical volume",
1964    "\
1965 Remove an LVM logical volume C<device>, where C<device> is
1966 the path to the LV, such as C</dev/VG/LV>.
1967
1968 You can also remove all LVs in a volume group by specifying
1969 the VG name, C</dev/VG>.");
1970
1971   ("vgremove", (RErr, [String "vgname"]), 78, [],
1972    [InitEmpty, Always, TestOutputList (
1973       [["sfdiskM"; "/dev/sda"; ","];
1974        ["pvcreate"; "/dev/sda1"];
1975        ["vgcreate"; "VG"; "/dev/sda1"];
1976        ["lvcreate"; "LV1"; "VG"; "50"];
1977        ["lvcreate"; "LV2"; "VG"; "50"];
1978        ["vgremove"; "VG"];
1979        ["lvs"]], []);
1980     InitEmpty, Always, TestOutputList (
1981       [["sfdiskM"; "/dev/sda"; ","];
1982        ["pvcreate"; "/dev/sda1"];
1983        ["vgcreate"; "VG"; "/dev/sda1"];
1984        ["lvcreate"; "LV1"; "VG"; "50"];
1985        ["lvcreate"; "LV2"; "VG"; "50"];
1986        ["vgremove"; "VG"];
1987        ["vgs"]], [])],
1988    "remove an LVM volume group",
1989    "\
1990 Remove an LVM volume group C<vgname>, (for example C<VG>).
1991
1992 This also forcibly removes all logical volumes in the volume
1993 group (if any).");
1994
1995   ("pvremove", (RErr, [String "device"]), 79, [],
1996    [InitEmpty, Always, TestOutputListOfDevices (
1997       [["sfdiskM"; "/dev/sda"; ","];
1998        ["pvcreate"; "/dev/sda1"];
1999        ["vgcreate"; "VG"; "/dev/sda1"];
2000        ["lvcreate"; "LV1"; "VG"; "50"];
2001        ["lvcreate"; "LV2"; "VG"; "50"];
2002        ["vgremove"; "VG"];
2003        ["pvremove"; "/dev/sda1"];
2004        ["lvs"]], []);
2005     InitEmpty, Always, TestOutputListOfDevices (
2006       [["sfdiskM"; "/dev/sda"; ","];
2007        ["pvcreate"; "/dev/sda1"];
2008        ["vgcreate"; "VG"; "/dev/sda1"];
2009        ["lvcreate"; "LV1"; "VG"; "50"];
2010        ["lvcreate"; "LV2"; "VG"; "50"];
2011        ["vgremove"; "VG"];
2012        ["pvremove"; "/dev/sda1"];
2013        ["vgs"]], []);
2014     InitEmpty, Always, TestOutputListOfDevices (
2015       [["sfdiskM"; "/dev/sda"; ","];
2016        ["pvcreate"; "/dev/sda1"];
2017        ["vgcreate"; "VG"; "/dev/sda1"];
2018        ["lvcreate"; "LV1"; "VG"; "50"];
2019        ["lvcreate"; "LV2"; "VG"; "50"];
2020        ["vgremove"; "VG"];
2021        ["pvremove"; "/dev/sda1"];
2022        ["pvs"]], [])],
2023    "remove an LVM physical volume",
2024    "\
2025 This wipes a physical volume C<device> so that LVM will no longer
2026 recognise it.
2027
2028 The implementation uses the C<pvremove> command which refuses to
2029 wipe physical volumes that contain any volume groups, so you have
2030 to remove those first.");
2031
2032   ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
2033    [InitBasicFS, Always, TestOutput (
2034       [["set_e2label"; "/dev/sda1"; "testlabel"];
2035        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2036    "set the ext2/3/4 filesystem label",
2037    "\
2038 This sets the ext2/3/4 filesystem label of the filesystem on
2039 C<device> to C<label>.  Filesystem labels are limited to
2040 16 characters.
2041
2042 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2043 to return the existing label on a filesystem.");
2044
2045   ("get_e2label", (RString "label", [String "device"]), 81, [],
2046    [],
2047    "get the ext2/3/4 filesystem label",
2048    "\
2049 This returns the ext2/3/4 filesystem label of the filesystem on
2050 C<device>.");
2051
2052   ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
2053    [InitBasicFS, Always, TestOutput (
2054       [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
2055        ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
2056     InitBasicFS, Always, TestOutput (
2057       [["set_e2uuid"; "/dev/sda1"; "clear"];
2058        ["get_e2uuid"; "/dev/sda1"]], "");
2059     (* We can't predict what UUIDs will be, so just check the commands run. *)
2060     InitBasicFS, Always, TestRun (
2061       [["set_e2uuid"; "/dev/sda1"; "random"]]);
2062     InitBasicFS, Always, TestRun (
2063       [["set_e2uuid"; "/dev/sda1"; "time"]])],
2064    "set the ext2/3/4 filesystem UUID",
2065    "\
2066 This sets the ext2/3/4 filesystem UUID of the filesystem on
2067 C<device> to C<uuid>.  The format of the UUID and alternatives
2068 such as C<clear>, C<random> and C<time> are described in the
2069 L<tune2fs(8)> manpage.
2070
2071 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2072 to return the existing UUID of a filesystem.");
2073
2074   ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
2075    [],
2076    "get the ext2/3/4 filesystem UUID",
2077    "\
2078 This returns the ext2/3/4 filesystem UUID of the filesystem on
2079 C<device>.");
2080
2081   ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
2082    [InitBasicFS, Always, TestOutputInt (
2083       [["umount"; "/dev/sda1"];
2084        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2085     InitBasicFS, Always, TestOutputInt (
2086       [["umount"; "/dev/sda1"];
2087        ["zero"; "/dev/sda1"];
2088        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2089    "run the filesystem checker",
2090    "\
2091 This runs the filesystem checker (fsck) on C<device> which
2092 should have filesystem type C<fstype>.
2093
2094 The returned integer is the status.  See L<fsck(8)> for the
2095 list of status codes from C<fsck>.
2096
2097 Notes:
2098
2099 =over 4
2100
2101 =item *
2102
2103 Multiple status codes can be summed together.
2104
2105 =item *
2106
2107 A non-zero return code can mean \"success\", for example if
2108 errors have been corrected on the filesystem.
2109
2110 =item *
2111
2112 Checking or repairing NTFS volumes is not supported
2113 (by linux-ntfs).
2114
2115 =back
2116
2117 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2118
2119   ("zero", (RErr, [String "device"]), 85, [],
2120    [InitBasicFS, Always, TestOutput (
2121       [["umount"; "/dev/sda1"];
2122        ["zero"; "/dev/sda1"];
2123        ["file"; "/dev/sda1"]], "data")],
2124    "write zeroes to the device",
2125    "\
2126 This command writes zeroes over the first few blocks of C<device>.
2127
2128 How many blocks are zeroed isn't specified (but it's I<not> enough
2129 to securely wipe the device).  It should be sufficient to remove
2130 any partition tables, filesystem superblocks and so on.
2131
2132 See also: C<guestfs_scrub_device>.");
2133
2134   ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
2135    (* Test disabled because grub-install incompatible with virtio-blk driver.
2136     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2137     *)
2138    [InitBasicFS, Disabled, TestOutputTrue (
2139       [["grub_install"; "/"; "/dev/sda1"];
2140        ["is_dir"; "/boot"]])],
2141    "install GRUB",
2142    "\
2143 This command installs GRUB (the Grand Unified Bootloader) on
2144 C<device>, with the root directory being C<root>.");
2145
2146   ("cp", (RErr, [String "src"; String "dest"]), 87, [],
2147    [InitBasicFS, Always, TestOutput (
2148       [["write_file"; "/old"; "file content"; "0"];
2149        ["cp"; "/old"; "/new"];
2150        ["cat"; "/new"]], "file content");
2151     InitBasicFS, Always, TestOutputTrue (
2152       [["write_file"; "/old"; "file content"; "0"];
2153        ["cp"; "/old"; "/new"];
2154        ["is_file"; "/old"]]);
2155     InitBasicFS, Always, TestOutput (
2156       [["write_file"; "/old"; "file content"; "0"];
2157        ["mkdir"; "/dir"];
2158        ["cp"; "/old"; "/dir/new"];
2159        ["cat"; "/dir/new"]], "file content")],
2160    "copy a file",
2161    "\
2162 This copies a file from C<src> to C<dest> where C<dest> is
2163 either a destination filename or destination directory.");
2164
2165   ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2166    [InitBasicFS, Always, TestOutput (
2167       [["mkdir"; "/olddir"];
2168        ["mkdir"; "/newdir"];
2169        ["write_file"; "/olddir/file"; "file content"; "0"];
2170        ["cp_a"; "/olddir"; "/newdir"];
2171        ["cat"; "/newdir/olddir/file"]], "file content")],
2172    "copy a file or directory recursively",
2173    "\
2174 This copies a file or directory from C<src> to C<dest>
2175 recursively using the C<cp -a> command.");
2176
2177   ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2178    [InitBasicFS, Always, TestOutput (
2179       [["write_file"; "/old"; "file content"; "0"];
2180        ["mv"; "/old"; "/new"];
2181        ["cat"; "/new"]], "file content");
2182     InitBasicFS, Always, TestOutputFalse (
2183       [["write_file"; "/old"; "file content"; "0"];
2184        ["mv"; "/old"; "/new"];
2185        ["is_file"; "/old"]])],
2186    "move a file",
2187    "\
2188 This moves a file from C<src> to C<dest> where C<dest> is
2189 either a destination filename or destination directory.");
2190
2191   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2192    [InitEmpty, Always, TestRun (
2193       [["drop_caches"; "3"]])],
2194    "drop kernel page cache, dentries and inodes",
2195    "\
2196 This instructs the guest kernel to drop its page cache,
2197 and/or dentries and inode caches.  The parameter C<whattodrop>
2198 tells the kernel what precisely to drop, see
2199 L<http://linux-mm.org/Drop_Caches>
2200
2201 Setting C<whattodrop> to 3 should drop everything.
2202
2203 This automatically calls L<sync(2)> before the operation,
2204 so that the maximum guest memory is freed.");
2205
2206   ("dmesg", (RString "kmsgs", []), 91, [],
2207    [InitEmpty, Always, TestRun (
2208       [["dmesg"]])],
2209    "return kernel messages",
2210    "\
2211 This returns the kernel messages (C<dmesg> output) from
2212 the guest kernel.  This is sometimes useful for extended
2213 debugging of problems.
2214
2215 Another way to get the same information is to enable
2216 verbose messages with C<guestfs_set_verbose> or by setting
2217 the environment variable C<LIBGUESTFS_DEBUG=1> before
2218 running the program.");
2219
2220   ("ping_daemon", (RErr, []), 92, [],
2221    [InitEmpty, Always, TestRun (
2222       [["ping_daemon"]])],
2223    "ping the guest daemon",
2224    "\
2225 This is a test probe into the guestfs daemon running inside
2226 the qemu subprocess.  Calling this function checks that the
2227 daemon responds to the ping message, without affecting the daemon
2228 or attached block device(s) in any other way.");
2229
2230   ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2231    [InitBasicFS, Always, TestOutputTrue (
2232       [["write_file"; "/file1"; "contents of a file"; "0"];
2233        ["cp"; "/file1"; "/file2"];
2234        ["equal"; "/file1"; "/file2"]]);
2235     InitBasicFS, Always, TestOutputFalse (
2236       [["write_file"; "/file1"; "contents of a file"; "0"];
2237        ["write_file"; "/file2"; "contents of another file"; "0"];
2238        ["equal"; "/file1"; "/file2"]]);
2239     InitBasicFS, Always, TestLastFail (
2240       [["equal"; "/file1"; "/file2"]])],
2241    "test if two files have equal contents",
2242    "\
2243 This compares the two files C<file1> and C<file2> and returns
2244 true if their content is exactly equal, or false otherwise.
2245
2246 The external L<cmp(1)> program is used for the comparison.");
2247
2248   ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2249    [InitBasicFS, Always, TestOutputList (
2250       [["write_file"; "/new"; "hello\nworld\n"; "0"];
2251        ["strings"; "/new"]], ["hello"; "world"]);
2252     InitBasicFS, Always, TestOutputList (
2253       [["touch"; "/new"];
2254        ["strings"; "/new"]], [])],
2255    "print the printable strings in a file",
2256    "\
2257 This runs the L<strings(1)> command on a file and returns
2258 the list of printable strings found.");
2259
2260   ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2261    [InitBasicFS, Always, TestOutputList (
2262       [["write_file"; "/new"; "hello\nworld\n"; "0"];
2263        ["strings_e"; "b"; "/new"]], []);
2264     InitBasicFS, Disabled, TestOutputList (
2265       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2266        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2267    "print the printable strings in a file",
2268    "\
2269 This is like the C<guestfs_strings> command, but allows you to
2270 specify the encoding.
2271
2272 See the L<strings(1)> manpage for the full list of encodings.
2273
2274 Commonly useful encodings are C<l> (lower case L) which will
2275 show strings inside Windows/x86 files.
2276
2277 The returned strings are transcoded to UTF-8.");
2278
2279   ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2280    [InitBasicFS, Always, TestOutput (
2281       [["write_file"; "/new"; "hello\nworld\n"; "12"];
2282        ["hexdump"; "/new"]], "00000000  68 65 6c 6c 6f 0a 77 6f  72 6c 64 0a              |hello.world.|\n0000000c\n");
2283     (* Test for RHBZ#501888c2 regression which caused large hexdump
2284      * commands to segfault.
2285      *)
2286     InitSquashFS, Always, TestRun (
2287       [["hexdump"; "/100krandom"]])],
2288    "dump a file in hexadecimal",
2289    "\
2290 This runs C<hexdump -C> on the given C<path>.  The result is
2291 the human-readable, canonical hex dump of the file.");
2292
2293   ("zerofree", (RErr, [String "device"]), 97, [],
2294    [InitNone, Always, TestOutput (
2295       [["sfdiskM"; "/dev/sda"; ","];
2296        ["mkfs"; "ext3"; "/dev/sda1"];
2297        ["mount"; "/dev/sda1"; "/"];
2298        ["write_file"; "/new"; "test file"; "0"];
2299        ["umount"; "/dev/sda1"];
2300        ["zerofree"; "/dev/sda1"];
2301        ["mount"; "/dev/sda1"; "/"];
2302        ["cat"; "/new"]], "test file")],
2303    "zero unused inodes and disk blocks on ext2/3 filesystem",
2304    "\
2305 This runs the I<zerofree> program on C<device>.  This program
2306 claims to zero unused inodes and disk blocks on an ext2/3
2307 filesystem, thus making it possible to compress the filesystem
2308 more effectively.
2309
2310 You should B<not> run this program if the filesystem is
2311 mounted.
2312
2313 It is possible that using this program can damage the filesystem
2314 or data on the filesystem.");
2315
2316   ("pvresize", (RErr, [String "device"]), 98, [],
2317    [],
2318    "resize an LVM physical volume",
2319    "\
2320 This resizes (expands or shrinks) an existing LVM physical
2321 volume to match the new size of the underlying device.");
2322
2323   ("sfdisk_N", (RErr, [String "device"; Int "partnum";
2324                        Int "cyls"; Int "heads"; Int "sectors";
2325                        String "line"]), 99, [DangerWillRobinson],
2326    [],
2327    "modify a single partition on a block device",
2328    "\
2329 This runs L<sfdisk(8)> option to modify just the single
2330 partition C<n> (note: C<n> counts from 1).
2331
2332 For other parameters, see C<guestfs_sfdisk>.  You should usually
2333 pass C<0> for the cyls/heads/sectors parameters.");
2334
2335   ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2336    [],
2337    "display the partition table",
2338    "\
2339 This displays the partition table on C<device>, in the
2340 human-readable output of the L<sfdisk(8)> command.  It is
2341 not intended to be parsed.");
2342
2343   ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2344    [],
2345    "display the kernel geometry",
2346    "\
2347 This displays the kernel's idea of the geometry of C<device>.
2348
2349 The result is in human-readable format, and not designed to
2350 be parsed.");
2351
2352   ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2353    [],
2354    "display the disk geometry from the partition table",
2355    "\
2356 This displays the disk geometry of C<device> read from the
2357 partition table.  Especially in the case where the underlying
2358 block device has been resized, this can be different from the
2359 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2360
2361 The result is in human-readable format, and not designed to
2362 be parsed.");
2363
2364   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2365    [],
2366    "activate or deactivate all volume groups",
2367    "\
2368 This command activates or (if C<activate> is false) deactivates
2369 all logical volumes in all volume groups.
2370 If activated, then they are made known to the
2371 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2372 then those devices disappear.
2373
2374 This command is the same as running C<vgchange -a y|n>");
2375
2376   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2377    [],
2378    "activate or deactivate some volume groups",
2379    "\
2380 This command activates or (if C<activate> is false) deactivates
2381 all logical volumes in the listed volume groups C<volgroups>.
2382 If activated, then they are made known to the
2383 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2384 then those devices disappear.
2385
2386 This command is the same as running C<vgchange -a y|n volgroups...>
2387
2388 Note that if C<volgroups> is an empty list then B<all> volume groups
2389 are activated or deactivated.");
2390
2391   ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2392    [InitNone, Always, TestOutput (
2393       [["sfdiskM"; "/dev/sda"; ","];
2394        ["pvcreate"; "/dev/sda1"];
2395        ["vgcreate"; "VG"; "/dev/sda1"];
2396        ["lvcreate"; "LV"; "VG"; "10"];
2397        ["mkfs"; "ext2"; "/dev/VG/LV"];
2398        ["mount"; "/dev/VG/LV"; "/"];
2399        ["write_file"; "/new"; "test content"; "0"];
2400        ["umount"; "/"];
2401        ["lvresize"; "/dev/VG/LV"; "20"];
2402        ["e2fsck_f"; "/dev/VG/LV"];
2403        ["resize2fs"; "/dev/VG/LV"];
2404        ["mount"; "/dev/VG/LV"; "/"];
2405        ["cat"; "/new"]], "test content")],
2406    "resize an LVM logical volume",
2407    "\
2408 This resizes (expands or shrinks) an existing LVM logical
2409 volume to C<mbytes>.  When reducing, data in the reduced part
2410 is lost.");
2411
2412   ("resize2fs", (RErr, [String "device"]), 106, [],
2413    [], (* lvresize tests this *)
2414    "resize an ext2/ext3 filesystem",
2415    "\
2416 This resizes an ext2 or ext3 filesystem to match the size of
2417 the underlying device.
2418
2419 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2420 on the C<device> before calling this command.  For unknown reasons
2421 C<resize2fs> sometimes gives an error about this and sometimes not.
2422 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2423 calling this function.");
2424
2425   ("find", (RStringList "names", [String "directory"]), 107, [],
2426    [InitBasicFS, Always, TestOutputList (
2427       [["find"; "/"]], ["lost+found"]);
2428     InitBasicFS, Always, TestOutputList (
2429       [["touch"; "/a"];
2430        ["mkdir"; "/b"];
2431        ["touch"; "/b/c"];
2432        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2433     InitBasicFS, Always, TestOutputList (
2434       [["mkdir_p"; "/a/b/c"];
2435        ["touch"; "/a/b/c/d"];
2436        ["find"; "/a/b/"]], ["c"; "c/d"])],
2437    "find all files and directories",
2438    "\
2439 This command lists out all files and directories, recursively,
2440 starting at C<directory>.  It is essentially equivalent to
2441 running the shell command C<find directory -print> but some
2442 post-processing happens on the output, described below.
2443
2444 This returns a list of strings I<without any prefix>.  Thus
2445 if the directory structure was:
2446
2447  /tmp/a
2448  /tmp/b
2449  /tmp/c/d
2450
2451 then the returned list from C<guestfs_find> C</tmp> would be
2452 4 elements:
2453
2454  a
2455  b
2456  c
2457  c/d
2458
2459 If C<directory> is not a directory, then this command returns
2460 an error.
2461
2462 The returned list is sorted.");
2463
2464   ("e2fsck_f", (RErr, [String "device"]), 108, [],
2465    [], (* lvresize tests this *)
2466    "check an ext2/ext3 filesystem",
2467    "\
2468 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2469 filesystem checker on C<device>, noninteractively (C<-p>),
2470 even if the filesystem appears to be clean (C<-f>).
2471
2472 This command is only needed because of C<guestfs_resize2fs>
2473 (q.v.).  Normally you should use C<guestfs_fsck>.");
2474
2475   ("sleep", (RErr, [Int "secs"]), 109, [],
2476    [InitNone, Always, TestRun (
2477       [["sleep"; "1"]])],
2478    "sleep for some seconds",
2479    "\
2480 Sleep for C<secs> seconds.");
2481
2482   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [],
2483    [InitNone, Always, TestOutputInt (
2484       [["sfdiskM"; "/dev/sda"; ","];
2485        ["mkfs"; "ntfs"; "/dev/sda1"];
2486        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2487     InitNone, Always, TestOutputInt (
2488       [["sfdiskM"; "/dev/sda"; ","];
2489        ["mkfs"; "ext2"; "/dev/sda1"];
2490        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2491    "probe NTFS volume",
2492    "\
2493 This command runs the L<ntfs-3g.probe(8)> command which probes
2494 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2495 be mounted read-write, and some cannot be mounted at all).
2496
2497 C<rw> is a boolean flag.  Set it to true if you want to test
2498 if the volume can be mounted read-write.  Set it to false if
2499 you want to test if the volume can be mounted read-only.
2500
2501 The return value is an integer which C<0> if the operation
2502 would succeed, or some non-zero value documented in the
2503 L<ntfs-3g.probe(8)> manual page.");
2504
2505   ("sh", (RString "output", [String "command"]), 111, [],
2506    [], (* XXX needs tests *)
2507    "run a command via the shell",
2508    "\
2509 This call runs a command from the guest filesystem via the
2510 guest's C</bin/sh>.
2511
2512 This is like C<guestfs_command>, but passes the command to:
2513
2514  /bin/sh -c \"command\"
2515
2516 Depending on the guest's shell, this usually results in
2517 wildcards being expanded, shell expressions being interpolated
2518 and so on.
2519
2520 All the provisos about C<guestfs_command> apply to this call.");
2521
2522   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2523    [], (* XXX needs tests *)
2524    "run a command via the shell returning lines",
2525    "\
2526 This is the same as C<guestfs_sh>, but splits the result
2527 into a list of lines.
2528
2529 See also: C<guestfs_command_lines>");
2530
2531   ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [],
2532    [InitBasicFS, Always, TestOutputList (
2533       [["mkdir_p"; "/a/b/c"];
2534        ["touch"; "/a/b/c/d"];
2535        ["touch"; "/a/b/c/e"];
2536        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2537     InitBasicFS, Always, TestOutputList (
2538       [["mkdir_p"; "/a/b/c"];
2539        ["touch"; "/a/b/c/d"];
2540        ["touch"; "/a/b/c/e"];
2541        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2542     InitBasicFS, Always, TestOutputList (
2543       [["mkdir_p"; "/a/b/c"];
2544        ["touch"; "/a/b/c/d"];
2545        ["touch"; "/a/b/c/e"];
2546        ["glob_expand"; "/a/*/x/*"]], [])],
2547    "expand a wildcard path",
2548    "\
2549 This command searches for all the pathnames matching
2550 C<pattern> according to the wildcard expansion rules
2551 used by the shell.
2552
2553 If no paths match, then this returns an empty list
2554 (note: not an error).
2555
2556 It is just a wrapper around the C L<glob(3)> function
2557 with flags C<GLOB_MARK|GLOB_BRACE>.
2558 See that manual page for more details.");
2559
2560   ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson],
2561    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2562       [["scrub_device"; "/dev/sdc"]])],
2563    "scrub (securely wipe) a device",
2564    "\
2565 This command writes patterns over C<device> to make data retrieval
2566 more difficult.
2567
2568 It is an interface to the L<scrub(1)> program.  See that
2569 manual page for more details.");
2570
2571   ("scrub_file", (RErr, [String "file"]), 115, [],
2572    [InitBasicFS, Always, TestRun (
2573       [["write_file"; "/file"; "content"; "0"];
2574        ["scrub_file"; "/file"]])],
2575    "scrub (securely wipe) a file",
2576    "\
2577 This command writes patterns over a file to make data retrieval
2578 more difficult.
2579
2580 The file is I<removed> after scrubbing.
2581
2582 It is an interface to the L<scrub(1)> program.  See that
2583 manual page for more details.");
2584
2585   ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2586    [], (* XXX needs testing *)
2587    "scrub (securely wipe) free space",
2588    "\
2589 This command creates the directory C<dir> and then fills it
2590 with files until the filesystem is full, and scrubs the files
2591 as for C<guestfs_scrub_file>, and deletes them.
2592 The intention is to scrub any free space on the partition
2593 containing C<dir>.
2594
2595 It is an interface to the L<scrub(1)> program.  See that
2596 manual page for more details.");
2597
2598   ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2599    [InitBasicFS, Always, TestRun (
2600       [["mkdir"; "/tmp"];
2601        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2602    "create a temporary directory",
2603    "\
2604 This command creates a temporary directory.  The
2605 C<template> parameter should be a full pathname for the
2606 temporary directory name with the final six characters being
2607 \"XXXXXX\".
2608
2609 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2610 the second one being suitable for Windows filesystems.
2611
2612 The name of the temporary directory that was created
2613 is returned.
2614
2615 The temporary directory is created with mode 0700
2616 and is owned by root.
2617
2618 The caller is responsible for deleting the temporary
2619 directory and its contents after use.
2620
2621 See also: L<mkdtemp(3)>");
2622
2623   ("wc_l", (RInt "lines", [String "path"]), 118, [],
2624    [InitSquashFS, Always, TestOutputInt (
2625       [["wc_l"; "/10klines"]], 10000)],
2626    "count lines in a file",
2627    "\
2628 This command counts the lines in a file, using the
2629 C<wc -l> external command.");
2630
2631   ("wc_w", (RInt "words", [String "path"]), 119, [],
2632    [InitSquashFS, Always, TestOutputInt (
2633       [["wc_w"; "/10klines"]], 10000)],
2634    "count words in a file",
2635    "\
2636 This command counts the words in a file, using the
2637 C<wc -w> external command.");
2638
2639   ("wc_c", (RInt "chars", [String "path"]), 120, [],
2640    [InitSquashFS, Always, TestOutputInt (
2641       [["wc_c"; "/100kallspaces"]], 102400)],
2642    "count characters in a file",
2643    "\
2644 This command counts the characters in a file, using the
2645 C<wc -c> external command.");
2646
2647   ("head", (RStringList "lines", [String "path"]), 121, [ProtocolLimitWarning],
2648    [InitSquashFS, Always, TestOutputList (
2649       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2650    "return first 10 lines of a file",
2651    "\
2652 This command returns up to the first 10 lines of a file as
2653 a list of strings.");
2654
2655   ("head_n", (RStringList "lines", [Int "nrlines"; String "path"]), 122, [ProtocolLimitWarning],
2656    [InitSquashFS, Always, TestOutputList (
2657       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2658     InitSquashFS, Always, TestOutputList (
2659       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2660     InitSquashFS, Always, TestOutputList (
2661       [["head_n"; "0"; "/10klines"]], [])],
2662    "return first N lines of a file",
2663    "\
2664 If the parameter C<nrlines> is a positive number, this returns the first
2665 C<nrlines> lines of the file C<path>.
2666
2667 If the parameter C<nrlines> is a negative number, this returns lines
2668 from the file C<path>, excluding the last C<nrlines> lines.
2669
2670 If the parameter C<nrlines> is zero, this returns an empty list.");
2671
2672   ("tail", (RStringList "lines", [String "path"]), 123, [ProtocolLimitWarning],
2673    [InitSquashFS, Always, TestOutputList (
2674       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2675    "return last 10 lines of a file",
2676    "\
2677 This command returns up to the last 10 lines of a file as
2678 a list of strings.");
2679
2680   ("tail_n", (RStringList "lines", [Int "nrlines"; String "path"]), 124, [ProtocolLimitWarning],
2681    [InitSquashFS, Always, TestOutputList (
2682       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2683     InitSquashFS, Always, TestOutputList (
2684       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2685     InitSquashFS, Always, TestOutputList (
2686       [["tail_n"; "0"; "/10klines"]], [])],
2687    "return last N lines of a file",
2688    "\
2689 If the parameter C<nrlines> is a positive number, this returns the last
2690 C<nrlines> lines of the file C<path>.
2691
2692 If the parameter C<nrlines> is a negative number, this returns lines
2693 from the file C<path>, starting with the C<-nrlines>th line.
2694
2695 If the parameter C<nrlines> is zero, this returns an empty list.");
2696
2697   ("df", (RString "output", []), 125, [],
2698    [], (* XXX Tricky to test because it depends on the exact format
2699         * of the 'df' command and other imponderables.
2700         *)
2701    "report file system disk space usage",
2702    "\
2703 This command runs the C<df> command to report disk space used.
2704
2705 This command is mostly useful for interactive sessions.  It
2706 is I<not> intended that you try to parse the output string.
2707 Use C<statvfs> from programs.");
2708
2709   ("df_h", (RString "output", []), 126, [],
2710    [], (* XXX Tricky to test because it depends on the exact format
2711         * of the 'df' command and other imponderables.
2712         *)
2713    "report file system disk space usage (human readable)",
2714    "\
2715 This command runs the C<df -h> command to report disk space used
2716 in human-readable format.
2717
2718 This command is mostly useful for interactive sessions.  It
2719 is I<not> intended that you try to parse the output string.
2720 Use C<statvfs> from programs.");
2721
2722   ("du", (RInt64 "sizekb", [String "path"]), 127, [],
2723    [InitBasicFS, Always, TestOutputInt (
2724       [["mkdir"; "/p"];
2725        ["du"; "/p"]], 1 (* ie. 1 block, so depends on ext3 blocksize *))],
2726    "estimate file space usage",
2727    "\
2728 This command runs the C<du -s> command to estimate file space
2729 usage for C<path>.
2730
2731 C<path> can be a file or a directory.  If C<path> is a directory
2732 then the estimate includes the contents of the directory and all
2733 subdirectories (recursively).
2734
2735 The result is the estimated size in I<kilobytes>
2736 (ie. units of 1024 bytes).");
2737
2738   ("initrd_list", (RStringList "filenames", [String "path"]), 128, [],
2739    [InitSquashFS, Always, TestOutputList (
2740       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3"])],
2741    "list files in an initrd",
2742    "\
2743 This command lists out files contained in an initrd.
2744
2745 The files are listed without any initial C</> character.  The
2746 files are listed in the order they appear (not necessarily
2747 alphabetical).  Directory names are listed as separate items.
2748
2749 Old Linux kernels (2.4 and earlier) used a compressed ext2
2750 filesystem as initrd.  We I<only> support the newer initramfs
2751 format (compressed cpio files).");
2752
2753   ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
2754    [],
2755    "mount a file using the loop device",
2756    "\
2757 This command lets you mount C<file> (a filesystem image
2758 in a file) on a mount point.  It is entirely equivalent to
2759 the command C<mount -o loop file mountpoint>.");
2760
2761   ("mkswap", (RErr, [String "device"]), 130, [],
2762    [InitEmpty, Always, TestRun (
2763       [["sfdiskM"; "/dev/sda"; ","];
2764        ["mkswap"; "/dev/sda1"]])],
2765    "create a swap partition",
2766    "\
2767 Create a swap partition on C<device>.");
2768
2769   ("mkswap_L", (RErr, [String "label"; String "device"]), 131, [],
2770    [InitEmpty, Always, TestRun (
2771       [["sfdiskM"; "/dev/sda"; ","];
2772        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2773    "create a swap partition with a label",
2774    "\
2775 Create a swap partition on C<device> with label C<label>.");
2776
2777   ("mkswap_U", (RErr, [String "uuid"; String "device"]), 132, [],
2778    [InitEmpty, Always, TestRun (
2779       [["sfdiskM"; "/dev/sda"; ","];
2780        ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
2781    "create a swap partition with an explicit UUID",
2782    "\
2783 Create a swap partition on C<device> with UUID C<uuid>.");
2784
2785   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 133, [],
2786    [InitBasicFS, Always, TestOutputStruct (
2787       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2788        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2789        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2790     InitBasicFS, Always, TestOutputStruct (
2791       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2792        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2793    "make block, character or FIFO devices",
2794    "\
2795 This call creates block or character special devices, or
2796 named pipes (FIFOs).
2797
2798 The C<mode> parameter should be the mode, using the standard
2799 constants.  C<devmajor> and C<devminor> are the
2800 device major and minor numbers, only used when creating block
2801 and character special devices.");
2802
2803   ("mkfifo", (RErr, [Int "mode"; String "path"]), 134, [],
2804    [InitBasicFS, Always, TestOutputStruct (
2805       [["mkfifo"; "0o777"; "/node"];
2806        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2807    "make FIFO (named pipe)",
2808    "\
2809 This call creates a FIFO (named pipe) called C<path> with
2810 mode C<mode>.  It is just a convenient wrapper around
2811 C<guestfs_mknod>.");
2812
2813   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 135, [],
2814    [InitBasicFS, Always, TestOutputStruct (
2815       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2816        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2817    "make block device node",
2818    "\
2819 This call creates a block device node called C<path> with
2820 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2821 It is just a convenient wrapper around C<guestfs_mknod>.");
2822
2823   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 136, [],
2824    [InitBasicFS, Always, TestOutputStruct (
2825       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2826        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2827    "make char device node",
2828    "\
2829 This call creates a char device node called C<path> with
2830 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2831 It is just a convenient wrapper around C<guestfs_mknod>.");
2832
2833   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2834    [], (* XXX umask is one of those stateful things that we should
2835         * reset between each test.
2836         *)
2837    "set file mode creation mask (umask)",
2838    "\
2839 This function sets the mask used for creating new files and
2840 device nodes to C<mask & 0777>.
2841
2842 Typical umask values would be C<022> which creates new files
2843 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2844 C<002> which creates new files with permissions like
2845 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2846
2847 The default umask is C<022>.  This is important because it
2848 means that directories and device nodes will be created with
2849 C<0644> or C<0755> mode even if you specify C<0777>.
2850
2851 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2852
2853 This call returns the previous umask.");
2854
2855   ("readdir", (RStructList ("entries", "dirent"), [String "dir"]), 138, [],
2856    [],
2857    "read directories entries",
2858    "\
2859 This returns the list of directory entries in directory C<dir>.
2860
2861 All entries in the directory are returned, including C<.> and
2862 C<..>.  The entries are I<not> sorted, but returned in the same
2863 order as the underlying filesystem.
2864
2865 Also this call returns basic file type information about each
2866 file.  The C<ftyp> field will contain one of the following characters:
2867
2868 =over 4
2869
2870 =item 'b'
2871
2872 Block special
2873
2874 =item 'c'
2875
2876 Char special
2877
2878 =item 'd'
2879
2880 Directory
2881
2882 =item 'f'
2883
2884 FIFO (named pipe)
2885
2886 =item 'l'
2887
2888 Symbolic link
2889
2890 =item 'r'
2891
2892 Regular file
2893
2894 =item 's'
2895
2896 Socket
2897
2898 =item 'u'
2899
2900 Unknown file type
2901
2902 =item '?'
2903
2904 The L<readdir(3)> returned a C<d_type> field with an
2905 unexpected value
2906
2907 =back
2908
2909 This function is primarily intended for use by programs.  To
2910 get a simple list of names, use C<guestfs_ls>.  To get a printable
2911 directory for human consumption, use C<guestfs_ll>.");
2912
2913   ("sfdiskM", (RErr, [String "device"; StringList "lines"]), 139, [DangerWillRobinson],
2914    [],
2915    "create partitions on a block device",
2916    "\
2917 This is a simplified interface to the C<guestfs_sfdisk>
2918 command, where partition sizes are specified in megabytes
2919 only (rounded to the nearest cylinder) and you don't need
2920 to specify the cyls, heads and sectors parameters which
2921 were rarely if ever used anyway.
2922
2923 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
2924
2925   ("zfile", (RString "description", [String "method"; String "path"]), 140, [],
2926    [],
2927    "determine file type inside a compressed file",
2928    "\
2929 This command runs C<file> after first decompressing C<path>
2930 using C<method>.
2931
2932 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
2933
2934 See also: C<guestfs_file>");
2935
2936   ("getxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 141, [],
2937    [],
2938    "list extended attributes of a file or directory",
2939    "\
2940 This call lists the extended attributes of the file or directory
2941 C<path>.
2942
2943 At the system call level, this is a combination of the
2944 L<listxattr(2)> and L<getxattr(2)> calls.
2945
2946 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
2947
2948   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 142, [],
2949    [],
2950    "list extended attributes of a file or directory",
2951    "\
2952 This is the same as C<guestfs_getxattrs>, but if C<path>
2953 is a symbolic link, then it returns the extended attributes
2954 of the link itself.");
2955
2956   ("setxattr", (RErr, [String "xattr";
2957                        String "val"; Int "vallen"; (* will be BufferIn *)
2958                        String "path"]), 143, [],
2959    [],
2960    "set extended attribute of a file or directory",
2961    "\
2962 This call sets the extended attribute named C<xattr>
2963 of the file C<path> to the value C<val> (of length C<vallen>).
2964 The value is arbitrary 8 bit data.
2965
2966 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
2967
2968   ("lsetxattr", (RErr, [String "xattr";
2969                         String "val"; Int "vallen"; (* will be BufferIn *)
2970                         String "path"]), 144, [],
2971    [],
2972    "set extended attribute of a file or directory",
2973    "\
2974 This is the same as C<guestfs_setxattr>, but if C<path>
2975 is a symbolic link, then it sets an extended attribute
2976 of the link itself.");
2977
2978   ("removexattr", (RErr, [String "xattr"; String "path"]), 145, [],
2979    [],
2980    "remove extended attribute of a file or directory",
2981    "\
2982 This call removes the extended attribute named C<xattr>
2983 of the file C<path>.
2984
2985 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
2986
2987   ("lremovexattr", (RErr, [String "xattr"; String "path"]), 146, [],
2988    [],
2989    "remove extended attribute of a file or directory",
2990    "\
2991 This is the same as C<guestfs_removexattr>, but if C<path>
2992 is a symbolic link, then it removes an extended attribute
2993 of the link itself.");
2994
2995   ("mountpoints", (RHashtable "mps", []), 147, [],
2996    [],
2997    "show mountpoints",
2998    "\
2999 This call is similar to C<guestfs_mounts>.  That call returns
3000 a list of devices.  This one returns a hash table (map) of
3001 device name to directory where the device is mounted.");
3002
3003   ("mkmountpoint", (RErr, [String "path"]), 148, [],
3004    [],
3005    "create a mountpoint",
3006    "\
3007 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3008 specialized calls that can be used to create extra mountpoints
3009 before mounting the first filesystem.
3010
3011 These calls are I<only> necessary in some very limited circumstances,
3012 mainly the case where you want to mount a mix of unrelated and/or
3013 read-only filesystems together.
3014
3015 For example, live CDs often contain a \"Russian doll\" nest of
3016 filesystems, an ISO outer layer, with a squashfs image inside, with
3017 an ext2/3 image inside that.  You can unpack this as follows
3018 in guestfish:
3019
3020  add-ro Fedora-11-i686-Live.iso
3021  run
3022  mkmountpoint /cd
3023  mkmountpoint /squash
3024  mkmountpoint /ext3
3025  mount /dev/sda /cd
3026  mount-loop /cd/LiveOS/squashfs.img /squash
3027  mount-loop /squash/LiveOS/ext3fs.img /ext3
3028
3029 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3030
3031   ("rmmountpoint", (RErr, [String "path"]), 149, [],
3032    [],
3033    "remove a mountpoint",
3034    "\
3035 This calls removes a mountpoint that was previously created
3036 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3037 for full details.");
3038
3039   ("read_file", (RBufferOut "content", [String "path"]), 150, [ProtocolLimitWarning],
3040    [InitBasicFS, Always, TestOutput (
3041       [["write_file"; "/new"; "new file contents"; "0"];
3042        ["read_file"; "/new"]], "new file contents")],
3043    "read a file",
3044    "\
3045 This calls returns the contents of the file C<path> as a
3046 buffer.
3047
3048 Unlike C<guestfs_cat>, this function can correctly
3049 handle files that contain embedded ASCII NUL characters.
3050 However unlike C<guestfs_download>, this function is limited
3051 in the total size of file that can be handled.");
3052
3053 ]
3054
3055 let all_functions = non_daemon_functions @ daemon_functions
3056
3057 (* In some places we want the functions to be displayed sorted
3058  * alphabetically, so this is useful:
3059  *)
3060 let all_functions_sorted =
3061   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
3062                compare n1 n2) all_functions
3063
3064 (* Field types for structures. *)
3065 type field =
3066   | FChar                       (* C 'char' (really, a 7 bit byte). *)
3067   | FString                     (* nul-terminated ASCII string. *)
3068   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
3069   | FUInt32
3070   | FInt32
3071   | FUInt64
3072   | FInt64
3073   | FBytes                      (* Any int measure that counts bytes. *)
3074   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
3075   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
3076
3077 (* Because we generate extra parsing code for LVM command line tools,
3078  * we have to pull out the LVM columns separately here.
3079  *)
3080 let lvm_pv_cols = [
3081   "pv_name", FString;
3082   "pv_uuid", FUUID;
3083   "pv_fmt", FString;
3084   "pv_size", FBytes;
3085   "dev_size", FBytes;
3086   "pv_free", FBytes;
3087   "pv_used", FBytes;
3088   "pv_attr", FString (* XXX *);
3089   "pv_pe_count", FInt64;
3090   "pv_pe_alloc_count", FInt64;
3091   "pv_tags", FString;
3092   "pe_start", FBytes;
3093   "pv_mda_count", FInt64;
3094   "pv_mda_free", FBytes;
3095   (* Not in Fedora 10:
3096      "pv_mda_size", FBytes;
3097   *)
3098 ]
3099 let lvm_vg_cols = [
3100   "vg_name", FString;
3101   "vg_uuid", FUUID;
3102   "vg_fmt", FString;
3103   "vg_attr", FString (* XXX *);
3104   "vg_size", FBytes;
3105   "vg_free", FBytes;
3106   "vg_sysid", FString;
3107   "vg_extent_size", FBytes;
3108   "vg_extent_count", FInt64;
3109   "vg_free_count", FInt64;
3110   "max_lv", FInt64;
3111   "max_pv", FInt64;
3112   "pv_count", FInt64;
3113   "lv_count", FInt64;
3114   "snap_count", FInt64;
3115   "vg_seqno", FInt64;
3116   "vg_tags", FString;
3117   "vg_mda_count", FInt64;
3118   "vg_mda_free", FBytes;
3119   (* Not in Fedora 10:
3120      "vg_mda_size", FBytes;
3121   *)
3122 ]
3123 let lvm_lv_cols = [
3124   "lv_name", FString;
3125   "lv_uuid", FUUID;
3126   "lv_attr", FString (* XXX *);
3127   "lv_major", FInt64;
3128   "lv_minor", FInt64;
3129   "lv_kernel_major", FInt64;
3130   "lv_kernel_minor", FInt64;
3131   "lv_size", FBytes;
3132   "seg_count", FInt64;
3133   "origin", FString;
3134   "snap_percent", FOptPercent;
3135   "copy_percent", FOptPercent;
3136   "move_pv", FString;
3137   "lv_tags", FString;
3138   "mirror_log", FString;
3139   "modules", FString;
3140 ]
3141
3142 (* Names and fields in all structures (in RStruct and RStructList)
3143  * that we support.
3144  *)
3145 let structs = [
3146   (* The old RIntBool return type, only ever used for aug_defnode.  Do
3147    * not use this struct in any new code.
3148    *)
3149   "int_bool", [
3150     "i", FInt32;                (* for historical compatibility *)
3151     "b", FInt32;                (* for historical compatibility *)
3152   ];
3153
3154   (* LVM PVs, VGs, LVs. *)
3155   "lvm_pv", lvm_pv_cols;
3156   "lvm_vg", lvm_vg_cols;
3157   "lvm_lv", lvm_lv_cols;
3158
3159   (* Column names and types from stat structures.
3160    * NB. Can't use things like 'st_atime' because glibc header files
3161    * define some of these as macros.  Ugh.
3162    *)
3163   "stat", [
3164     "dev", FInt64;
3165     "ino", FInt64;
3166     "mode", FInt64;
3167     "nlink", FInt64;
3168     "uid", FInt64;
3169     "gid", FInt64;
3170     "rdev", FInt64;
3171     "size", FInt64;
3172     "blksize", FInt64;
3173     "blocks", FInt64;
3174     "atime", FInt64;
3175     "mtime", FInt64;
3176     "ctime", FInt64;
3177   ];
3178   "statvfs", [
3179     "bsize", FInt64;
3180     "frsize", FInt64;
3181     "blocks", FInt64;
3182     "bfree", FInt64;
3183     "bavail", FInt64;
3184     "files", FInt64;
3185     "ffree", FInt64;
3186     "favail", FInt64;
3187     "fsid", FInt64;
3188     "flag", FInt64;
3189     "namemax", FInt64;
3190   ];
3191
3192   (* Column names in dirent structure. *)
3193   "dirent", [
3194     "ino", FInt64;
3195     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
3196     "ftyp", FChar;
3197     "name", FString;
3198   ];
3199
3200   (* Version numbers. *)
3201   "version", [
3202     "major", FInt64;
3203     "minor", FInt64;
3204     "release", FInt64;
3205     "extra", FString;
3206   ];
3207
3208   (* Extended attribute. *)
3209   "xattr", [
3210     "attrname", FString;
3211     "attrval", FBuffer;
3212   ];
3213 ] (* end of structs *)
3214
3215 (* Ugh, Java has to be different ..
3216  * These names are also used by the Haskell bindings.
3217  *)
3218 let java_structs = [
3219   "int_bool", "IntBool";
3220   "lvm_pv", "PV";
3221   "lvm_vg", "VG";
3222   "lvm_lv", "LV";
3223   "stat", "Stat";
3224   "statvfs", "StatVFS";
3225   "dirent", "Dirent";
3226   "version", "Version";
3227   "xattr", "XAttr";
3228 ]
3229
3230 (* Used for testing language bindings. *)
3231 type callt =
3232   | CallString of string
3233   | CallOptString of string option
3234   | CallStringList of string list
3235   | CallInt of int
3236   | CallBool of bool
3237
3238 (* Used to memoize the result of pod2text. *)
3239 let pod2text_memo_filename = "src/.pod2text.data"
3240 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
3241   try
3242     let chan = open_in pod2text_memo_filename in
3243     let v = input_value chan in
3244     close_in chan;
3245     v
3246   with
3247     _ -> Hashtbl.create 13
3248
3249 (* Useful functions.
3250  * Note we don't want to use any external OCaml libraries which
3251  * makes this a bit harder than it should be.
3252  *)
3253 let failwithf fs = ksprintf failwith fs
3254
3255 let replace_char s c1 c2 =
3256   let s2 = String.copy s in
3257   let r = ref false in
3258   for i = 0 to String.length s2 - 1 do
3259     if String.unsafe_get s2 i = c1 then (
3260       String.unsafe_set s2 i c2;
3261       r := true
3262     )
3263   done;
3264   if not !r then s else s2
3265
3266 let isspace c =
3267   c = ' '
3268   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
3269
3270 let triml ?(test = isspace) str =
3271   let i = ref 0 in
3272   let n = ref (String.length str) in
3273   while !n > 0 && test str.[!i]; do
3274     decr n;
3275     incr i
3276   done;
3277   if !i = 0 then str
3278   else String.sub str !i !n
3279
3280 let trimr ?(test = isspace) str =
3281   let n = ref (String.length str) in
3282   while !n > 0 && test str.[!n-1]; do
3283     decr n
3284   done;
3285   if !n = String.length str then str
3286   else String.sub str 0 !n
3287
3288 let trim ?(test = isspace) str =
3289   trimr ~test (triml ~test str)
3290
3291 let rec find s sub =
3292   let len = String.length s in
3293   let sublen = String.length sub in
3294   let rec loop i =
3295     if i <= len-sublen then (
3296       let rec loop2 j =
3297         if j < sublen then (
3298           if s.[i+j] = sub.[j] then loop2 (j+1)
3299           else -1
3300         ) else
3301           i (* found *)
3302       in
3303       let r = loop2 0 in
3304       if r = -1 then loop (i+1) else r
3305     ) else
3306       -1 (* not found *)
3307   in
3308   loop 0
3309
3310 let rec replace_str s s1 s2 =
3311   let len = String.length s in
3312   let sublen = String.length s1 in
3313   let i = find s s1 in
3314   if i = -1 then s
3315   else (
3316     let s' = String.sub s 0 i in
3317     let s'' = String.sub s (i+sublen) (len-i-sublen) in
3318     s' ^ s2 ^ replace_str s'' s1 s2
3319   )
3320
3321 let rec string_split sep str =
3322   let len = String.length str in
3323   let seplen = String.length sep in
3324   let i = find str sep in
3325   if i = -1 then [str]
3326   else (
3327     let s' = String.sub str 0 i in
3328     let s'' = String.sub str (i+seplen) (len-i-seplen) in
3329     s' :: string_split sep s''
3330   )
3331
3332 let files_equal n1 n2 =
3333   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
3334   match Sys.command cmd with
3335   | 0 -> true
3336   | 1 -> false
3337   | i -> failwithf "%s: failed with error code %d" cmd i
3338
3339 let rec find_map f = function
3340   | [] -> raise Not_found
3341   | x :: xs ->
3342       match f x with
3343       | Some y -> y
3344       | None -> find_map f xs
3345
3346 let iteri f xs =
3347   let rec loop i = function
3348     | [] -> ()
3349     | x :: xs -> f i x; loop (i+1) xs
3350   in
3351   loop 0 xs
3352
3353 let mapi f xs =
3354   let rec loop i = function
3355     | [] -> []
3356     | x :: xs -> let r = f i x in r :: loop (i+1) xs
3357   in
3358   loop 0 xs
3359
3360 let name_of_argt = function
3361   | String n | OptString n | StringList n | Bool n | Int n
3362   | FileIn n | FileOut n -> n
3363
3364 let java_name_of_struct typ =
3365   try List.assoc typ java_structs
3366   with Not_found ->
3367     failwithf
3368       "java_name_of_struct: no java_structs entry corresponding to %s" typ
3369
3370 let cols_of_struct typ =
3371   try List.assoc typ structs
3372   with Not_found ->
3373     failwithf "cols_of_struct: unknown struct %s" typ
3374
3375 let seq_of_test = function
3376   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
3377   | TestOutputListOfDevices (s, _)
3378   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
3379   | TestOutputTrue s | TestOutputFalse s
3380   | TestOutputLength (s, _) | TestOutputStruct (s, _)
3381   | TestLastFail s -> s
3382
3383 (* Check function names etc. for consistency. *)
3384 let check_functions () =
3385   let contains_uppercase str =
3386     let len = String.length str in
3387     let rec loop i =
3388       if i >= len then false
3389       else (
3390         let c = str.[i] in
3391         if c >= 'A' && c <= 'Z' then true
3392         else loop (i+1)
3393       )
3394     in
3395     loop 0
3396   in
3397
3398   (* Check function names. *)
3399   List.iter (
3400     fun (name, _, _, _, _, _, _) ->
3401       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
3402         failwithf "function name %s does not need 'guestfs' prefix" name;
3403       if name = "" then
3404         failwithf "function name is empty";
3405       if name.[0] < 'a' || name.[0] > 'z' then
3406         failwithf "function name %s must start with lowercase a-z" name;
3407       if String.contains name '-' then
3408         failwithf "function name %s should not contain '-', use '_' instead."
3409           name
3410   ) all_functions;
3411
3412   (* Check function parameter/return names. *)
3413   List.iter (
3414     fun (name, style, _, _, _, _, _) ->
3415       let check_arg_ret_name n =
3416         if contains_uppercase n then
3417           failwithf "%s param/ret %s should not contain uppercase chars"
3418             name n;
3419         if String.contains n '-' || String.contains n '_' then
3420           failwithf "%s param/ret %s should not contain '-' or '_'"
3421             name n;
3422         if n = "value" then
3423           failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" name;
3424         if n = "int" || n = "char" || n = "short" || n = "long" then
3425           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
3426         if n = "i" || n = "n" then
3427           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
3428         if n = "argv" || n = "args" then
3429           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
3430       in
3431
3432       (match fst style with
3433        | RErr -> ()
3434        | RInt n | RInt64 n | RBool n
3435        | RConstString n | RConstOptString n | RString n
3436        | RStringList n | RStruct (n, _) | RStructList (n, _)
3437        | RHashtable n | RBufferOut n ->
3438            check_arg_ret_name n
3439       );
3440       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
3441   ) all_functions;
3442
3443   (* Check short descriptions. *)
3444   List.iter (
3445     fun (name, _, _, _, _, shortdesc, _) ->
3446       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
3447         failwithf "short description of %s should begin with lowercase." name;
3448       let c = shortdesc.[String.length shortdesc-1] in
3449       if c = '\n' || c = '.' then
3450         failwithf "short description of %s should not end with . or \\n." name
3451   ) all_functions;
3452
3453   (* Check long dscriptions. *)
3454   List.iter (
3455     fun (name, _, _, _, _, _, longdesc) ->
3456       if longdesc.[String.length longdesc-1] = '\n' then
3457         failwithf "long description of %s should not end with \\n." name
3458   ) all_functions;
3459
3460   (* Check proc_nrs. *)
3461   List.iter (
3462     fun (name, _, proc_nr, _, _, _, _) ->
3463       if proc_nr <= 0 then
3464         failwithf "daemon function %s should have proc_nr > 0" name
3465   ) daemon_functions;
3466
3467   List.iter (
3468     fun (name, _, proc_nr, _, _, _, _) ->
3469       if proc_nr <> -1 then
3470         failwithf "non-daemon function %s should have proc_nr -1" name
3471   ) non_daemon_functions;
3472
3473   let proc_nrs =
3474     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
3475       daemon_functions in
3476   let proc_nrs =
3477     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
3478   let rec loop = function
3479     | [] -> ()
3480     | [_] -> ()
3481     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
3482         loop rest
3483     | (name1,nr1) :: (name2,nr2) :: _ ->
3484         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
3485           name1 name2 nr1 nr2
3486   in
3487   loop proc_nrs;
3488
3489   (* Check tests. *)
3490   List.iter (
3491     function
3492       (* Ignore functions that have no tests.  We generate a
3493        * warning when the user does 'make check' instead.
3494        *)
3495     | name, _, _, _, [], _, _ -> ()
3496     | name, _, _, _, tests, _, _ ->
3497         let funcs =
3498           List.map (
3499             fun (_, _, test) ->
3500               match seq_of_test test with
3501               | [] ->
3502                   failwithf "%s has a test containing an empty sequence" name
3503               | cmds -> List.map List.hd cmds
3504           ) tests in
3505         let funcs = List.flatten funcs in
3506
3507         let tested = List.mem name funcs in
3508
3509         if not tested then
3510           failwithf "function %s has tests but does not test itself" name
3511   ) all_functions
3512
3513 (* 'pr' prints to the current output file. *)
3514 let chan = ref stdout
3515 let pr fs = ksprintf (output_string !chan) fs
3516
3517 (* Generate a header block in a number of standard styles. *)
3518 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
3519 type license = GPLv2 | LGPLv2
3520
3521 let generate_header comment license =
3522   let c = match comment with
3523     | CStyle ->     pr "/* "; " *"
3524     | HashStyle ->  pr "# ";  "#"
3525     | OCamlStyle -> pr "(* "; " *"
3526     | HaskellStyle -> pr "{- "; "  " in
3527   pr "libguestfs generated file\n";
3528   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
3529   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
3530   pr "%s\n" c;
3531   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
3532   pr "%s\n" c;
3533   (match license with
3534    | GPLv2 ->
3535        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
3536        pr "%s it under the terms of the GNU General Public License as published by\n" c;
3537        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
3538        pr "%s (at your option) any later version.\n" c;
3539        pr "%s\n" c;
3540        pr "%s This program is distributed in the hope that it will be useful,\n" c;
3541        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3542        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
3543        pr "%s GNU General Public License for more details.\n" c;
3544        pr "%s\n" c;
3545        pr "%s You should have received a copy of the GNU General Public License along\n" c;
3546        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
3547        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
3548
3549    | LGPLv2 ->
3550        pr "%s This library is free software; you can redistribute it and/or\n" c;
3551        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
3552        pr "%s License as published by the Free Software Foundation; either\n" c;
3553        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
3554        pr "%s\n" c;
3555        pr "%s This library is distributed in the hope that it will be useful,\n" c;
3556        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3557        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
3558        pr "%s Lesser General Public License for more details.\n" c;
3559        pr "%s\n" c;
3560        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
3561        pr "%s License along with this library; if not, write to the Free Software\n" c;
3562        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
3563   );
3564   (match comment with
3565    | CStyle -> pr " */\n"
3566    | HashStyle -> ()
3567    | OCamlStyle -> pr " *)\n"
3568    | HaskellStyle -> pr "-}\n"
3569   );
3570   pr "\n"
3571
3572 (* Start of main code generation functions below this line. *)
3573
3574 (* Generate the pod documentation for the C API. *)
3575 let rec generate_actions_pod () =
3576   List.iter (
3577     fun (shortname, style, _, flags, _, _, longdesc) ->
3578       if not (List.mem NotInDocs flags) then (
3579         let name = "guestfs_" ^ shortname in
3580         pr "=head2 %s\n\n" name;
3581         pr " ";
3582         generate_prototype ~extern:false ~handle:"handle" name style;
3583         pr "\n\n";
3584         pr "%s\n\n" longdesc;
3585         (match fst style with
3586          | RErr ->
3587              pr "This function returns 0 on success or -1 on error.\n\n"
3588          | RInt _ ->
3589              pr "On error this function returns -1.\n\n"
3590          | RInt64 _ ->
3591              pr "On error this function returns -1.\n\n"
3592          | RBool _ ->
3593              pr "This function returns a C truth value on success or -1 on error.\n\n"
3594          | RConstString _ ->
3595              pr "This function returns a string, or NULL on error.
3596 The string is owned by the guest handle and must I<not> be freed.\n\n"
3597          | RConstOptString _ ->
3598              pr "This function returns a string which may be NULL.
3599 There is way to return an error from this function.
3600 The string is owned by the guest handle and must I<not> be freed.\n\n"
3601          | RString _ ->
3602              pr "This function returns a string, or NULL on error.
3603 I<The caller must free the returned string after use>.\n\n"
3604          | RStringList _ ->
3605              pr "This function returns a NULL-terminated array of strings
3606 (like L<environ(3)>), or NULL if there was an error.
3607 I<The caller must free the strings and the array after use>.\n\n"
3608          | RStruct (_, typ) ->
3609              pr "This function returns a C<struct guestfs_%s *>,
3610 or NULL if there was an error.
3611 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
3612          | RStructList (_, typ) ->
3613              pr "This function returns a C<struct guestfs_%s_list *>
3614 (see E<lt>guestfs-structs.hE<gt>),
3615 or NULL if there was an error.
3616 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
3617          | RHashtable _ ->
3618              pr "This function returns a NULL-terminated array of
3619 strings, or NULL if there was an error.
3620 The array of strings will always have length C<2n+1>, where
3621 C<n> keys and values alternate, followed by the trailing NULL entry.
3622 I<The caller must free the strings and the array after use>.\n\n"
3623          | RBufferOut _ ->
3624              pr "This function returns a buffer, or NULL on error.
3625 The size of the returned buffer is written to C<*size_r>.
3626 I<The caller must free the returned buffer after use>.\n\n"
3627         );
3628         if List.mem ProtocolLimitWarning flags then
3629           pr "%s\n\n" protocol_limit_warning;
3630         if List.mem DangerWillRobinson flags then
3631           pr "%s\n\n" danger_will_robinson
3632       )
3633   ) all_functions_sorted
3634
3635 and generate_structs_pod () =
3636   (* Structs documentation. *)
3637   List.iter (
3638     fun (typ, cols) ->
3639       pr "=head2 guestfs_%s\n" typ;
3640       pr "\n";
3641       pr " struct guestfs_%s {\n" typ;
3642       List.iter (
3643         function
3644         | name, FChar -> pr "   char %s;\n" name
3645         | name, FUInt32 -> pr "   uint32_t %s;\n" name
3646         | name, FInt32 -> pr "   int32_t %s;\n" name
3647         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
3648         | name, FInt64 -> pr "   int64_t %s;\n" name
3649         | name, FString -> pr "   char *%s;\n" name
3650         | name, FBuffer ->
3651             pr "   /* The next two fields describe a byte array. */\n";
3652             pr "   uint32_t %s_len;\n" name;
3653             pr "   char *%s;\n" name
3654         | name, FUUID ->
3655             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
3656             pr "   char %s[32];\n" name
3657         | name, FOptPercent ->
3658             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
3659             pr "   float %s;\n" name
3660       ) cols;
3661       pr " };\n";
3662       pr " \n";
3663       pr " struct guestfs_%s_list {\n" typ;
3664       pr "   uint32_t len; /* Number of elements in list. */\n";
3665       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
3666       pr " };\n";
3667       pr " \n";
3668       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
3669       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
3670         typ typ;
3671       pr "\n"
3672   ) structs
3673
3674 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3675  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3676  *
3677  * We have to use an underscore instead of a dash because otherwise
3678  * rpcgen generates incorrect code.
3679  *
3680  * This header is NOT exported to clients, but see also generate_structs_h.
3681  *)
3682 and generate_xdr () =
3683   generate_header CStyle LGPLv2;
3684
3685   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3686   pr "typedef string str<>;\n";
3687   pr "\n";
3688
3689   (* Internal structures. *)
3690   List.iter (
3691     function
3692     | typ, cols ->
3693         pr "struct guestfs_int_%s {\n" typ;
3694         List.iter (function
3695                    | name, FChar -> pr "  char %s;\n" name
3696                    | name, FString -> pr "  string %s<>;\n" name
3697                    | name, FBuffer -> pr "  opaque %s<>;\n" name
3698                    | name, FUUID -> pr "  opaque %s[32];\n" name
3699                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
3700                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
3701                    | name, FOptPercent -> pr "  float %s;\n" name
3702                   ) cols;
3703         pr "};\n";
3704         pr "\n";
3705         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
3706         pr "\n";
3707   ) structs;
3708
3709   List.iter (
3710     fun (shortname, style, _, _, _, _, _) ->
3711       let name = "guestfs_" ^ shortname in
3712
3713       (match snd style with
3714        | [] -> ()
3715        | args ->
3716            pr "struct %s_args {\n" name;
3717            List.iter (
3718              function
3719              | String n -> pr "  string %s<>;\n" n
3720              | OptString n -> pr "  str *%s;\n" n
3721              | StringList n -> pr "  str %s<>;\n" n
3722              | Bool n -> pr "  bool %s;\n" n
3723              | Int n -> pr "  int %s;\n" n
3724              | FileIn _ | FileOut _ -> ()
3725            ) args;
3726            pr "};\n\n"
3727       );
3728       (match fst style with
3729        | RErr -> ()
3730        | RInt n ->
3731            pr "struct %s_ret {\n" name;
3732            pr "  int %s;\n" n;
3733            pr "};\n\n"
3734        | RInt64 n ->
3735            pr "struct %s_ret {\n" name;
3736            pr "  hyper %s;\n" n;
3737            pr "};\n\n"
3738        | RBool n ->
3739            pr "struct %s_ret {\n" name;
3740            pr "  bool %s;\n" n;
3741            pr "};\n\n"
3742        | RConstString _ | RConstOptString _ ->
3743            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
3744        | RString n ->
3745            pr "struct %s_ret {\n" name;
3746            pr "  string %s<>;\n" n;
3747            pr "};\n\n"
3748        | RStringList n ->
3749            pr "struct %s_ret {\n" name;
3750            pr "  str %s<>;\n" n;
3751            pr "};\n\n"
3752        | RStruct (n, typ) ->
3753            pr "struct %s_ret {\n" name;
3754            pr "  guestfs_int_%s %s;\n" typ n;
3755            pr "};\n\n"
3756        | RStructList (n, typ) ->
3757            pr "struct %s_ret {\n" name;
3758            pr "  guestfs_int_%s_list %s;\n" typ n;
3759            pr "};\n\n"
3760        | RHashtable n ->
3761            pr "struct %s_ret {\n" name;
3762            pr "  str %s<>;\n" n;
3763            pr "};\n\n"
3764        | RBufferOut n ->
3765            pr "struct %s_ret {\n" name;
3766            pr "  opaque %s<>;\n" n;
3767            pr "};\n\n"
3768       );
3769   ) daemon_functions;
3770
3771   (* Table of procedure numbers. *)
3772   pr "enum guestfs_procedure {\n";
3773   List.iter (
3774     fun (shortname, _, proc_nr, _, _, _, _) ->
3775       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3776   ) daemon_functions;
3777   pr "  GUESTFS_PROC_NR_PROCS\n";
3778   pr "};\n";
3779   pr "\n";
3780
3781   (* Having to choose a maximum message size is annoying for several
3782    * reasons (it limits what we can do in the API), but it (a) makes
3783    * the protocol a lot simpler, and (b) provides a bound on the size
3784    * of the daemon which operates in limited memory space.  For large
3785    * file transfers you should use FTP.
3786    *)
3787   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3788   pr "\n";
3789
3790   (* Message header, etc. *)
3791   pr "\
3792 /* The communication protocol is now documented in the guestfs(3)
3793  * manpage.
3794  */
3795
3796 const GUESTFS_PROGRAM = 0x2000F5F5;
3797 const GUESTFS_PROTOCOL_VERSION = 1;
3798
3799 /* These constants must be larger than any possible message length. */
3800 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3801 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3802
3803 enum guestfs_message_direction {
3804   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
3805   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
3806 };
3807
3808 enum guestfs_message_status {
3809   GUESTFS_STATUS_OK = 0,
3810   GUESTFS_STATUS_ERROR = 1
3811 };
3812
3813 const GUESTFS_ERROR_LEN = 256;
3814
3815 struct guestfs_message_error {
3816   string error_message<GUESTFS_ERROR_LEN>;
3817 };
3818
3819 struct guestfs_message_header {
3820   unsigned prog;                     /* GUESTFS_PROGRAM */
3821   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
3822   guestfs_procedure proc;            /* GUESTFS_PROC_x */
3823   guestfs_message_direction direction;
3824   unsigned serial;                   /* message serial number */
3825   guestfs_message_status status;
3826 };
3827
3828 const GUESTFS_MAX_CHUNK_SIZE = 8192;
3829
3830 struct guestfs_chunk {
3831   int cancel;                        /* if non-zero, transfer is cancelled */
3832   /* data size is 0 bytes if the transfer has finished successfully */
3833   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
3834 };
3835 "
3836
3837 (* Generate the guestfs-structs.h file. *)
3838 and generate_structs_h () =
3839   generate_header CStyle LGPLv2;
3840
3841   (* This is a public exported header file containing various
3842    * structures.  The structures are carefully written to have
3843    * exactly the same in-memory format as the XDR structures that
3844    * we use on the wire to the daemon.  The reason for creating
3845    * copies of these structures here is just so we don't have to
3846    * export the whole of guestfs_protocol.h (which includes much
3847    * unrelated and XDR-dependent stuff that we don't want to be
3848    * public, or required by clients).
3849    *
3850    * To reiterate, we will pass these structures to and from the
3851    * client with a simple assignment or memcpy, so the format
3852    * must be identical to what rpcgen / the RFC defines.
3853    *)
3854
3855   (* Public structures. *)
3856   List.iter (
3857     fun (typ, cols) ->
3858       pr "struct guestfs_%s {\n" typ;
3859       List.iter (
3860         function
3861         | name, FChar -> pr "  char %s;\n" name
3862         | name, FString -> pr "  char *%s;\n" name
3863         | name, FBuffer ->
3864             pr "  uint32_t %s_len;\n" name;
3865             pr "  char *%s;\n" name
3866         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
3867         | name, FUInt32 -> pr "  uint32_t %s;\n" name
3868         | name, FInt32 -> pr "  int32_t %s;\n" name
3869         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
3870         | name, FInt64 -> pr "  int64_t %s;\n" name
3871         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
3872       ) cols;
3873       pr "};\n";
3874       pr "\n";
3875       pr "struct guestfs_%s_list {\n" typ;
3876       pr "  uint32_t len;\n";
3877       pr "  struct guestfs_%s *val;\n" typ;
3878       pr "};\n";
3879       pr "\n";
3880       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
3881       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
3882       pr "\n"
3883   ) structs
3884
3885 (* Generate the guestfs-actions.h file. *)
3886 and generate_actions_h () =
3887   generate_header CStyle LGPLv2;
3888   List.iter (
3889     fun (shortname, style, _, _, _, _, _) ->
3890       let name = "guestfs_" ^ shortname in
3891       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
3892         name style
3893   ) all_functions
3894
3895 (* Generate the client-side dispatch stubs. *)
3896 and generate_client_actions () =
3897   generate_header CStyle LGPLv2;
3898
3899   pr "\
3900 #include <stdio.h>
3901 #include <stdlib.h>
3902
3903 #include \"guestfs.h\"
3904 #include \"guestfs_protocol.h\"
3905
3906 #define error guestfs_error
3907 #define perrorf guestfs_perrorf
3908 #define safe_malloc guestfs_safe_malloc
3909 #define safe_realloc guestfs_safe_realloc
3910 #define safe_strdup guestfs_safe_strdup
3911 #define safe_memdup guestfs_safe_memdup
3912
3913 /* Check the return message from a call for validity. */
3914 static int
3915 check_reply_header (guestfs_h *g,
3916                     const struct guestfs_message_header *hdr,
3917                     int proc_nr, int serial)
3918 {
3919   if (hdr->prog != GUESTFS_PROGRAM) {
3920     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
3921     return -1;
3922   }
3923   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
3924     error (g, \"wrong protocol version (%%d/%%d)\",
3925            hdr->vers, GUESTFS_PROTOCOL_VERSION);
3926     return -1;
3927   }
3928   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
3929     error (g, \"unexpected message direction (%%d/%%d)\",
3930            hdr->direction, GUESTFS_DIRECTION_REPLY);
3931     return -1;
3932   }
3933   if (hdr->proc != proc_nr) {
3934     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
3935     return -1;
3936   }
3937   if (hdr->serial != serial) {
3938     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
3939     return -1;
3940   }
3941
3942   return 0;
3943 }
3944
3945 /* Check we are in the right state to run a high-level action. */
3946 static int
3947 check_state (guestfs_h *g, const char *caller)
3948 {
3949   if (!guestfs_is_ready (g)) {
3950     if (guestfs_is_config (g))
3951       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
3952         caller);
3953     else if (guestfs_is_launching (g))
3954       error (g, \"%%s: call wait_ready() before using this function\",
3955         caller);
3956     else
3957       error (g, \"%%s called from the wrong state, %%d != READY\",
3958         caller, guestfs_get_state (g));
3959     return -1;
3960   }
3961   return 0;
3962 }
3963
3964 ";
3965
3966   (* Client-side stubs for each function. *)
3967   List.iter (
3968     fun (shortname, style, _, _, _, _, _) ->
3969       let name = "guestfs_" ^ shortname in
3970
3971       (* Generate the context struct which stores the high-level
3972        * state between callback functions.
3973        *)
3974       pr "struct %s_ctx {\n" shortname;
3975       pr "  /* This flag is set by the callbacks, so we know we've done\n";
3976       pr "   * the callbacks as expected, and in the right sequence.\n";
3977       pr "   * 0 = not called, 1 = reply_cb called.\n";
3978       pr "   */\n";
3979       pr "  int cb_sequence;\n";
3980       pr "  struct guestfs_message_header hdr;\n";
3981       pr "  struct guestfs_message_error err;\n";
3982       (match fst style with
3983        | RErr -> ()
3984        | RConstString _ | RConstOptString _ ->
3985            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
3986        | RInt _ | RInt64 _
3987        | RBool _ | RString _ | RStringList _
3988        | RStruct _ | RStructList _
3989        | RHashtable _ | RBufferOut _ ->
3990            pr "  struct %s_ret ret;\n" name
3991       );
3992       pr "};\n";
3993       pr "\n";
3994
3995       (* Generate the reply callback function. *)
3996       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
3997       pr "{\n";
3998       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
3999       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
4000       pr "\n";
4001       pr "  /* This should definitely not happen. */\n";
4002       pr "  if (ctx->cb_sequence != 0) {\n";
4003       pr "    ctx->cb_sequence = 9999;\n";
4004       pr "    error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
4005       pr "    return;\n";
4006       pr "  }\n";
4007       pr "\n";
4008       pr "  ml->main_loop_quit (ml, g);\n";
4009       pr "\n";
4010       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
4011       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
4012       pr "    return;\n";
4013       pr "  }\n";
4014       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
4015       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
4016       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
4017         name;
4018       pr "      return;\n";
4019       pr "    }\n";
4020       pr "    goto done;\n";
4021       pr "  }\n";
4022
4023       (match fst style with
4024        | RErr -> ()
4025        | RConstString _ | RConstOptString _ ->
4026            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4027        | RInt _ | RInt64 _
4028        | RBool _ | RString _ | RStringList _
4029        | RStruct _ | RStructList _
4030        | RHashtable _ | RBufferOut _ ->
4031            pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
4032            pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
4033            pr "    return;\n";
4034            pr "  }\n";
4035       );
4036
4037       pr " done:\n";
4038       pr "  ctx->cb_sequence = 1;\n";
4039       pr "}\n\n";
4040
4041       (* Generate the action stub. *)
4042       generate_prototype ~extern:false ~semicolon:false ~newline:true
4043         ~handle:"g" name style;
4044
4045       let error_code =
4046         match fst style with
4047         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
4048         | RConstString _ | RConstOptString _ ->
4049             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4050         | RString _ | RStringList _
4051         | RStruct _ | RStructList _
4052         | RHashtable _ | RBufferOut _ ->
4053             "NULL" in
4054
4055       pr "{\n";
4056
4057       (match snd style with
4058        | [] -> ()
4059        | _ -> pr "  struct %s_args args;\n" name
4060       );
4061
4062       pr "  struct %s_ctx ctx;\n" shortname;
4063       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
4064       pr "  int serial;\n";
4065       pr "\n";
4066       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
4067       pr "  guestfs_set_busy (g);\n";
4068       pr "\n";
4069       pr "  memset (&ctx, 0, sizeof ctx);\n";
4070       pr "\n";
4071
4072       (* Send the main header and arguments. *)
4073       (match snd style with
4074        | [] ->
4075            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
4076              (String.uppercase shortname)
4077        | args ->
4078            List.iter (
4079              function
4080              | String n ->
4081                  pr "  args.%s = (char *) %s;\n" n n
4082              | OptString n ->
4083                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
4084              | StringList n ->
4085                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
4086                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
4087              | Bool n ->
4088                  pr "  args.%s = %s;\n" n n
4089              | Int n ->
4090                  pr "  args.%s = %s;\n" n n
4091              | FileIn _ | FileOut _ -> ()
4092            ) args;
4093            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
4094              (String.uppercase shortname);
4095            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
4096              name;
4097       );
4098       pr "  if (serial == -1) {\n";
4099       pr "    guestfs_end_busy (g);\n";
4100       pr "    return %s;\n" error_code;
4101       pr "  }\n";
4102       pr "\n";
4103
4104       (* Send any additional files (FileIn) requested. *)
4105       let need_read_reply_label = ref false in
4106       List.iter (
4107         function
4108         | FileIn n ->
4109             pr "  {\n";
4110             pr "    int r;\n";
4111             pr "\n";
4112             pr "    r = guestfs__send_file_sync (g, %s);\n" n;
4113             pr "    if (r == -1) {\n";
4114             pr "      guestfs_end_busy (g);\n";
4115             pr "      return %s;\n" error_code;
4116             pr "    }\n";
4117             pr "    if (r == -2) /* daemon cancelled */\n";
4118             pr "      goto read_reply;\n";
4119             need_read_reply_label := true;
4120             pr "  }\n";
4121             pr "\n";
4122         | _ -> ()
4123       ) (snd style);
4124
4125       (* Wait for the reply from the remote end. *)
4126       if !need_read_reply_label then pr " read_reply:\n";
4127       pr "  guestfs__switch_to_receiving (g);\n";
4128       pr "  ctx.cb_sequence = 0;\n";
4129       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
4130       pr "  (void) ml->main_loop_run (ml, g);\n";
4131       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
4132       pr "  if (ctx.cb_sequence != 1) {\n";
4133       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
4134       pr "    guestfs_end_busy (g);\n";
4135       pr "    return %s;\n" error_code;
4136       pr "  }\n";
4137       pr "\n";
4138
4139       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
4140         (String.uppercase shortname);
4141       pr "    guestfs_end_busy (g);\n";
4142       pr "    return %s;\n" error_code;
4143       pr "  }\n";
4144       pr "\n";
4145
4146       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
4147       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
4148       pr "    free (ctx.err.error_message);\n";
4149       pr "    guestfs_end_busy (g);\n";
4150       pr "    return %s;\n" error_code;
4151       pr "  }\n";
4152       pr "\n";
4153
4154       (* Expecting to receive further files (FileOut)? *)
4155       List.iter (
4156         function
4157         | FileOut n ->
4158             pr "  if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
4159             pr "    guestfs_end_busy (g);\n";
4160             pr "    return %s;\n" error_code;
4161             pr "  }\n";
4162             pr "\n";
4163         | _ -> ()
4164       ) (snd style);
4165
4166       pr "  guestfs_end_busy (g);\n";
4167
4168       (match fst style with
4169        | RErr -> pr "  return 0;\n"
4170        | RInt n | RInt64 n | RBool n ->
4171            pr "  return ctx.ret.%s;\n" n
4172        | RConstString _ | RConstOptString _ ->
4173            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4174        | RString n ->
4175            pr "  return ctx.ret.%s; /* caller will free */\n" n
4176        | RStringList n | RHashtable n ->
4177            pr "  /* caller will free this, but we need to add a NULL entry */\n";
4178            pr "  ctx.ret.%s.%s_val =\n" n n;
4179            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
4180            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
4181              n n;
4182            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
4183            pr "  return ctx.ret.%s.%s_val;\n" n n
4184        | RStruct (n, _) ->
4185            pr "  /* caller will free this */\n";
4186            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4187        | RStructList (n, _) ->
4188            pr "  /* caller will free this */\n";
4189            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4190        | RBufferOut n ->
4191            pr "  *size_r = ctx.ret.%s.%s_len;\n" n n;
4192            pr "  return ctx.ret.%s.%s_val; /* caller will free */\n" n n
4193       );
4194
4195       pr "}\n\n"
4196   ) daemon_functions;
4197
4198   (* Functions to free structures. *)
4199   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
4200   pr " * structure format is identical to the XDR format.  See note in\n";
4201   pr " * generator.ml.\n";
4202   pr " */\n";
4203   pr "\n";
4204
4205   List.iter (
4206     fun (typ, _) ->
4207       pr "void\n";
4208       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
4209       pr "{\n";
4210       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
4211       pr "  free (x);\n";
4212       pr "}\n";
4213       pr "\n";
4214
4215       pr "void\n";
4216       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
4217       pr "{\n";
4218       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
4219       pr "  free (x);\n";
4220       pr "}\n";
4221       pr "\n";
4222
4223   ) structs;
4224
4225 (* Generate daemon/actions.h. *)
4226 and generate_daemon_actions_h () =
4227   generate_header CStyle GPLv2;
4228
4229   pr "#include \"../src/guestfs_protocol.h\"\n";
4230   pr "\n";
4231
4232   List.iter (
4233     fun (name, style, _, _, _, _, _) ->
4234       generate_prototype
4235         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
4236         name style;
4237   ) daemon_functions
4238
4239 (* Generate the server-side stubs. *)
4240 and generate_daemon_actions () =
4241   generate_header CStyle GPLv2;
4242
4243   pr "#include <config.h>\n";
4244   pr "\n";
4245   pr "#include <stdio.h>\n";
4246   pr "#include <stdlib.h>\n";
4247   pr "#include <string.h>\n";
4248   pr "#include <inttypes.h>\n";
4249   pr "#include <ctype.h>\n";
4250   pr "#include <rpc/types.h>\n";
4251   pr "#include <rpc/xdr.h>\n";
4252   pr "\n";
4253   pr "#include \"daemon.h\"\n";
4254   pr "#include \"../src/guestfs_protocol.h\"\n";
4255   pr "#include \"actions.h\"\n";
4256   pr "\n";
4257
4258   List.iter (
4259     fun (name, style, _, _, _, _, _) ->
4260       (* Generate server-side stubs. *)
4261       pr "static void %s_stub (XDR *xdr_in)\n" name;
4262       pr "{\n";
4263       let error_code =
4264         match fst style with
4265         | RErr | RInt _ -> pr "  int r;\n"; "-1"
4266         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4267         | RBool _ -> pr "  int r;\n"; "-1"
4268         | RConstString _ | RConstOptString _ ->
4269             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4270         | RString _ -> pr "  char *r;\n"; "NULL"
4271         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
4272         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
4273         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
4274         | RBufferOut _ ->
4275             pr "  size_t size;\n";
4276             pr "  char *r;\n";
4277             "NULL" in
4278
4279       (match snd style with
4280        | [] -> ()
4281        | args ->
4282            pr "  struct guestfs_%s_args args;\n" name;
4283            List.iter (
4284              function
4285                (* Note we allow the string to be writable, in order to
4286                 * allow device name translation.  This is safe because
4287                 * we can modify the string (passed from RPC).
4288                 *)
4289              | String n
4290              | OptString n -> pr "  char *%s;\n" n
4291              | StringList n -> pr "  char **%s;\n" n
4292              | Bool n -> pr "  int %s;\n" n
4293              | Int n -> pr "  int %s;\n" n
4294              | FileIn _ | FileOut _ -> ()
4295            ) args
4296       );
4297       pr "\n";
4298
4299       (match snd style with
4300        | [] -> ()
4301        | args ->
4302            pr "  memset (&args, 0, sizeof args);\n";
4303            pr "\n";
4304            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4305            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4306            pr "    return;\n";
4307            pr "  }\n";
4308            List.iter (
4309              function
4310              | String n -> pr "  %s = args.%s;\n" n n
4311              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
4312              | StringList n ->
4313                  pr "  %s = realloc (args.%s.%s_val,\n" n n n;
4314                  pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4315                  pr "  if (%s == NULL) {\n" n;
4316                  pr "    reply_with_perror (\"realloc\");\n";
4317                  pr "    goto done;\n";
4318                  pr "  }\n";
4319                  pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
4320                  pr "  args.%s.%s_val = %s;\n" n n n;
4321              | Bool n -> pr "  %s = args.%s;\n" n n
4322              | Int n -> pr "  %s = args.%s;\n" n n
4323              | FileIn _ | FileOut _ -> ()
4324            ) args;
4325            pr "\n"
4326       );
4327
4328       (* Don't want to call the impl with any FileIn or FileOut
4329        * parameters, since these go "outside" the RPC protocol.
4330        *)
4331       let args' =
4332         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
4333           (snd style) in
4334       pr "  r = do_%s " name;
4335       generate_c_call_args (fst style, args');
4336       pr ";\n";
4337
4338       pr "  if (r == %s)\n" error_code;
4339       pr "    /* do_%s has already called reply_with_error */\n" name;
4340       pr "    goto done;\n";
4341       pr "\n";
4342
4343       (* If there are any FileOut parameters, then the impl must
4344        * send its own reply.
4345        *)
4346       let no_reply =
4347         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
4348       if no_reply then
4349         pr "  /* do_%s has already sent a reply */\n" name
4350       else (
4351         match fst style with
4352         | RErr -> pr "  reply (NULL, NULL);\n"
4353         | RInt n | RInt64 n | RBool n ->
4354             pr "  struct guestfs_%s_ret ret;\n" name;
4355             pr "  ret.%s = r;\n" n;
4356             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4357               name
4358         | RConstString _ | RConstOptString _ ->
4359             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4360         | RString n ->
4361             pr "  struct guestfs_%s_ret ret;\n" name;
4362             pr "  ret.%s = r;\n" n;
4363             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4364               name;
4365             pr "  free (r);\n"
4366         | RStringList n | RHashtable n ->
4367             pr "  struct guestfs_%s_ret ret;\n" name;
4368             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
4369             pr "  ret.%s.%s_val = r;\n" n n;
4370             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4371               name;
4372             pr "  free_strings (r);\n"
4373         | RStruct (n, _) ->
4374             pr "  struct guestfs_%s_ret ret;\n" name;
4375             pr "  ret.%s = *r;\n" n;
4376             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4377               name;
4378             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4379               name
4380         | RStructList (n, _) ->
4381             pr "  struct guestfs_%s_ret ret;\n" name;
4382             pr "  ret.%s = *r;\n" n;
4383             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4384               name;
4385             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4386               name
4387         | RBufferOut n ->
4388             pr "  struct guestfs_%s_ret ret;\n" name;
4389             pr "  ret.%s.%s_val = r;\n" n n;
4390             pr "  ret.%s.%s_len = size;\n" n n;
4391             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4392               name;
4393             pr "  free (r);\n"
4394       );
4395
4396       (* Free the args. *)
4397       (match snd style with
4398        | [] ->
4399            pr "done: ;\n";
4400        | _ ->
4401            pr "done:\n";
4402            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4403              name
4404       );
4405
4406       pr "}\n\n";
4407   ) daemon_functions;
4408
4409   (* Dispatch function. *)
4410   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4411   pr "{\n";
4412   pr "  switch (proc_nr) {\n";
4413
4414   List.iter (
4415     fun (name, style, _, _, _, _, _) ->
4416       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
4417       pr "      %s_stub (xdr_in);\n" name;
4418       pr "      break;\n"
4419   ) daemon_functions;
4420
4421   pr "    default:\n";
4422   pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d, set LIBGUESTFS_PATH to point to the matching libguestfs appliance directory\", proc_nr);\n";
4423   pr "  }\n";
4424   pr "}\n";
4425   pr "\n";
4426
4427   (* LVM columns and tokenization functions. *)
4428   (* XXX This generates crap code.  We should rethink how we
4429    * do this parsing.
4430    *)
4431   List.iter (
4432     function
4433     | typ, cols ->
4434         pr "static const char *lvm_%s_cols = \"%s\";\n"
4435           typ (String.concat "," (List.map fst cols));
4436         pr "\n";
4437
4438         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
4439         pr "{\n";
4440         pr "  char *tok, *p, *next;\n";
4441         pr "  int i, j;\n";
4442         pr "\n";
4443         (*
4444           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4445           pr "\n";
4446         *)
4447         pr "  if (!str) {\n";
4448         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4449         pr "    return -1;\n";
4450         pr "  }\n";
4451         pr "  if (!*str || isspace (*str)) {\n";
4452         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4453         pr "    return -1;\n";
4454         pr "  }\n";
4455         pr "  tok = str;\n";
4456         List.iter (
4457           fun (name, coltype) ->
4458             pr "  if (!tok) {\n";
4459             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4460             pr "    return -1;\n";
4461             pr "  }\n";
4462             pr "  p = strchrnul (tok, ',');\n";
4463             pr "  if (*p) next = p+1; else next = NULL;\n";
4464             pr "  *p = '\\0';\n";
4465             (match coltype with
4466              | FString ->
4467                  pr "  r->%s = strdup (tok);\n" name;
4468                  pr "  if (r->%s == NULL) {\n" name;
4469                  pr "    perror (\"strdup\");\n";
4470                  pr "    return -1;\n";
4471                  pr "  }\n"
4472              | FUUID ->
4473                  pr "  for (i = j = 0; i < 32; ++j) {\n";
4474                  pr "    if (tok[j] == '\\0') {\n";
4475                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4476                  pr "      return -1;\n";
4477                  pr "    } else if (tok[j] != '-')\n";
4478                  pr "      r->%s[i++] = tok[j];\n" name;
4479                  pr "  }\n";
4480              | FBytes ->
4481                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4482                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4483                  pr "    return -1;\n";
4484                  pr "  }\n";
4485              | FInt64 ->
4486                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4487                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4488                  pr "    return -1;\n";
4489                  pr "  }\n";
4490              | FOptPercent ->
4491                  pr "  if (tok[0] == '\\0')\n";
4492                  pr "    r->%s = -1;\n" name;
4493                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4494                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4495                  pr "    return -1;\n";
4496                  pr "  }\n";
4497              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
4498                  assert false (* can never be an LVM column *)
4499             );
4500             pr "  tok = next;\n";
4501         ) cols;
4502
4503         pr "  if (tok != NULL) {\n";
4504         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4505         pr "    return -1;\n";
4506         pr "  }\n";
4507         pr "  return 0;\n";
4508         pr "}\n";
4509         pr "\n";
4510
4511         pr "guestfs_int_lvm_%s_list *\n" typ;
4512         pr "parse_command_line_%ss (void)\n" typ;
4513         pr "{\n";
4514         pr "  char *out, *err;\n";
4515         pr "  char *p, *pend;\n";
4516         pr "  int r, i;\n";
4517         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
4518         pr "  void *newp;\n";
4519         pr "\n";
4520         pr "  ret = malloc (sizeof *ret);\n";
4521         pr "  if (!ret) {\n";
4522         pr "    reply_with_perror (\"malloc\");\n";
4523         pr "    return NULL;\n";
4524         pr "  }\n";
4525         pr "\n";
4526         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
4527         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
4528         pr "\n";
4529         pr "  r = command (&out, &err,\n";
4530         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
4531         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4532         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4533         pr "  if (r == -1) {\n";
4534         pr "    reply_with_error (\"%%s\", err);\n";
4535         pr "    free (out);\n";
4536         pr "    free (err);\n";
4537         pr "    free (ret);\n";
4538         pr "    return NULL;\n";
4539         pr "  }\n";
4540         pr "\n";
4541         pr "  free (err);\n";
4542         pr "\n";
4543         pr "  /* Tokenize each line of the output. */\n";
4544         pr "  p = out;\n";
4545         pr "  i = 0;\n";
4546         pr "  while (p) {\n";
4547         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
4548         pr "    if (pend) {\n";
4549         pr "      *pend = '\\0';\n";
4550         pr "      pend++;\n";
4551         pr "    }\n";
4552         pr "\n";
4553         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
4554         pr "      p++;\n";
4555         pr "\n";
4556         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
4557         pr "      p = pend;\n";
4558         pr "      continue;\n";
4559         pr "    }\n";
4560         pr "\n";
4561         pr "    /* Allocate some space to store this next entry. */\n";
4562         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
4563         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
4564         pr "    if (newp == NULL) {\n";
4565         pr "      reply_with_perror (\"realloc\");\n";
4566         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
4567         pr "      free (ret);\n";
4568         pr "      free (out);\n";
4569         pr "      return NULL;\n";
4570         pr "    }\n";
4571         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
4572         pr "\n";
4573         pr "    /* Tokenize the next entry. */\n";
4574         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
4575         pr "    if (r == -1) {\n";
4576         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
4577         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
4578         pr "      free (ret);\n";
4579         pr "      free (out);\n";
4580         pr "      return NULL;\n";
4581         pr "    }\n";
4582         pr "\n";
4583         pr "    ++i;\n";
4584         pr "    p = pend;\n";
4585         pr "  }\n";
4586         pr "\n";
4587         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
4588         pr "\n";
4589         pr "  free (out);\n";
4590         pr "  return ret;\n";
4591         pr "}\n"
4592
4593   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
4594
4595 (* Generate a list of function names, for debugging in the daemon.. *)
4596 and generate_daemon_names () =
4597   generate_header CStyle GPLv2;
4598
4599   pr "#include <config.h>\n";
4600   pr "\n";
4601   pr "#include \"daemon.h\"\n";
4602   pr "\n";
4603
4604   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
4605   pr "const char *function_names[] = {\n";
4606   List.iter (
4607     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
4608   ) daemon_functions;
4609   pr "};\n";
4610
4611 (* Generate the tests. *)
4612 and generate_tests () =
4613   generate_header CStyle GPLv2;
4614
4615   pr "\
4616 #include <stdio.h>
4617 #include <stdlib.h>
4618 #include <string.h>
4619 #include <unistd.h>
4620 #include <sys/types.h>
4621 #include <fcntl.h>
4622
4623 #include \"guestfs.h\"
4624
4625 static guestfs_h *g;
4626 static int suppress_error = 0;
4627
4628 static void print_error (guestfs_h *g, void *data, const char *msg)
4629 {
4630   if (!suppress_error)
4631     fprintf (stderr, \"%%s\\n\", msg);
4632 }
4633
4634 static void print_strings (char * const * const argv)
4635 {
4636   int argc;
4637
4638   for (argc = 0; argv[argc] != NULL; ++argc)
4639     printf (\"\\t%%s\\n\", argv[argc]);
4640 }
4641
4642 /*
4643 static void print_table (char * const * const argv)
4644 {
4645   int i;
4646
4647   for (i = 0; argv[i] != NULL; i += 2)
4648     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
4649 }
4650 */
4651
4652 static void no_test_warnings (void)
4653 {
4654 ";
4655
4656   List.iter (
4657     function
4658     | name, _, _, _, [], _, _ ->
4659         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
4660     | name, _, _, _, tests, _, _ -> ()
4661   ) all_functions;
4662
4663   pr "}\n";
4664   pr "\n";
4665
4666   (* Generate the actual tests.  Note that we generate the tests
4667    * in reverse order, deliberately, so that (in general) the
4668    * newest tests run first.  This makes it quicker and easier to
4669    * debug them.
4670    *)
4671   let test_names =
4672     List.map (
4673       fun (name, _, _, _, tests, _, _) ->
4674         mapi (generate_one_test name) tests
4675     ) (List.rev all_functions) in
4676   let test_names = List.concat test_names in
4677   let nr_tests = List.length test_names in
4678
4679   pr "\
4680 int main (int argc, char *argv[])
4681 {
4682   char c = 0;
4683   int failed = 0;
4684   const char *filename;
4685   int fd;
4686   int nr_tests, test_num = 0;
4687
4688   setbuf (stdout, NULL);
4689
4690   no_test_warnings ();
4691
4692   g = guestfs_create ();
4693   if (g == NULL) {
4694     printf (\"guestfs_create FAILED\\n\");
4695     exit (1);
4696   }
4697
4698   guestfs_set_error_handler (g, print_error, NULL);
4699
4700   guestfs_set_path (g, \"../appliance\");
4701
4702   filename = \"test1.img\";
4703   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4704   if (fd == -1) {
4705     perror (filename);
4706     exit (1);
4707   }
4708   if (lseek (fd, %d, SEEK_SET) == -1) {
4709     perror (\"lseek\");
4710     close (fd);
4711     unlink (filename);
4712     exit (1);
4713   }
4714   if (write (fd, &c, 1) == -1) {
4715     perror (\"write\");
4716     close (fd);
4717     unlink (filename);
4718     exit (1);
4719   }
4720   if (close (fd) == -1) {
4721     perror (filename);
4722     unlink (filename);
4723     exit (1);
4724   }
4725   if (guestfs_add_drive (g, filename) == -1) {
4726     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4727     exit (1);
4728   }
4729
4730   filename = \"test2.img\";
4731   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4732   if (fd == -1) {
4733     perror (filename);
4734     exit (1);
4735   }
4736   if (lseek (fd, %d, SEEK_SET) == -1) {
4737     perror (\"lseek\");
4738     close (fd);
4739     unlink (filename);
4740     exit (1);
4741   }
4742   if (write (fd, &c, 1) == -1) {
4743     perror (\"write\");
4744     close (fd);
4745     unlink (filename);
4746     exit (1);
4747   }
4748   if (close (fd) == -1) {
4749     perror (filename);
4750     unlink (filename);
4751     exit (1);
4752   }
4753   if (guestfs_add_drive (g, filename) == -1) {
4754     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4755     exit (1);
4756   }
4757
4758   filename = \"test3.img\";
4759   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4760   if (fd == -1) {
4761     perror (filename);
4762     exit (1);
4763   }
4764   if (lseek (fd, %d, SEEK_SET) == -1) {
4765     perror (\"lseek\");
4766     close (fd);
4767     unlink (filename);
4768     exit (1);
4769   }
4770   if (write (fd, &c, 1) == -1) {
4771     perror (\"write\");
4772     close (fd);
4773     unlink (filename);
4774     exit (1);
4775   }
4776   if (close (fd) == -1) {
4777     perror (filename);
4778     unlink (filename);
4779     exit (1);
4780   }
4781   if (guestfs_add_drive (g, filename) == -1) {
4782     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4783     exit (1);
4784   }
4785
4786   if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4787     printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4788     exit (1);
4789   }
4790
4791   if (guestfs_launch (g) == -1) {
4792     printf (\"guestfs_launch FAILED\\n\");
4793     exit (1);
4794   }
4795
4796   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4797   alarm (600);
4798
4799   if (guestfs_wait_ready (g) == -1) {
4800     printf (\"guestfs_wait_ready FAILED\\n\");
4801     exit (1);
4802   }
4803
4804   /* Cancel previous alarm. */
4805   alarm (0);
4806
4807   nr_tests = %d;
4808
4809 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4810
4811   iteri (
4812     fun i test_name ->
4813       pr "  test_num++;\n";
4814       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4815       pr "  if (%s () == -1) {\n" test_name;
4816       pr "    printf (\"%s FAILED\\n\");\n" test_name;
4817       pr "    failed++;\n";
4818       pr "  }\n";
4819   ) test_names;
4820   pr "\n";
4821
4822   pr "  guestfs_close (g);\n";
4823   pr "  unlink (\"test1.img\");\n";
4824   pr "  unlink (\"test2.img\");\n";
4825   pr "  unlink (\"test3.img\");\n";
4826   pr "\n";
4827
4828   pr "  if (failed > 0) {\n";
4829   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
4830   pr "    exit (1);\n";
4831   pr "  }\n";
4832   pr "\n";
4833
4834   pr "  exit (0);\n";
4835   pr "}\n"
4836
4837 and generate_one_test name i (init, prereq, test) =
4838   let test_name = sprintf "test_%s_%d" name i in
4839
4840   pr "\
4841 static int %s_skip (void)
4842 {
4843   const char *str;
4844
4845   str = getenv (\"TEST_ONLY\");
4846   if (str)
4847     return strstr (str, \"%s\") == NULL;
4848   str = getenv (\"SKIP_%s\");
4849   if (str && strcmp (str, \"1\") == 0) return 1;
4850   str = getenv (\"SKIP_TEST_%s\");
4851   if (str && strcmp (str, \"1\") == 0) return 1;
4852   return 0;
4853 }
4854
4855 " test_name name (String.uppercase test_name) (String.uppercase name);
4856
4857   (match prereq with
4858    | Disabled | Always -> ()
4859    | If code | Unless code ->
4860        pr "static int %s_prereq (void)\n" test_name;
4861        pr "{\n";
4862        pr "  %s\n" code;
4863        pr "}\n";
4864        pr "\n";
4865   );
4866
4867   pr "\
4868 static int %s (void)
4869 {
4870   if (%s_skip ()) {
4871     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
4872     return 0;
4873   }
4874
4875 " test_name test_name test_name;
4876
4877   (match prereq with
4878    | Disabled ->
4879        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
4880    | If _ ->
4881        pr "  if (! %s_prereq ()) {\n" test_name;
4882        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4883        pr "    return 0;\n";
4884        pr "  }\n";
4885        pr "\n";
4886        generate_one_test_body name i test_name init test;
4887    | Unless _ ->
4888        pr "  if (%s_prereq ()) {\n" test_name;
4889        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
4890        pr "    return 0;\n";
4891        pr "  }\n";
4892        pr "\n";
4893        generate_one_test_body name i test_name init test;
4894    | Always ->
4895        generate_one_test_body name i test_name init test
4896   );
4897
4898   pr "  return 0;\n";
4899   pr "}\n";
4900   pr "\n";
4901   test_name
4902
4903 and generate_one_test_body name i test_name init test =
4904   (match init with
4905    | InitNone (* XXX at some point, InitNone and InitEmpty became
4906                * folded together as the same thing.  Really we should
4907                * make InitNone do nothing at all, but the tests may
4908                * need to be checked to make sure this is OK.
4909                *)
4910    | InitEmpty ->
4911        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
4912        List.iter (generate_test_command_call test_name)
4913          [["blockdev_setrw"; "/dev/sda"];
4914           ["umount_all"];
4915           ["lvm_remove_all"]]
4916    | InitBasicFS ->
4917        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
4918        List.iter (generate_test_command_call test_name)
4919          [["blockdev_setrw"; "/dev/sda"];
4920           ["umount_all"];
4921           ["lvm_remove_all"];
4922           ["sfdiskM"; "/dev/sda"; ","];
4923           ["mkfs"; "ext2"; "/dev/sda1"];
4924           ["mount"; "/dev/sda1"; "/"]]
4925    | InitBasicFSonLVM ->
4926        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
4927          test_name;
4928        List.iter (generate_test_command_call test_name)
4929          [["blockdev_setrw"; "/dev/sda"];
4930           ["umount_all"];
4931           ["lvm_remove_all"];
4932           ["sfdiskM"; "/dev/sda"; ","];
4933           ["pvcreate"; "/dev/sda1"];
4934           ["vgcreate"; "VG"; "/dev/sda1"];
4935           ["lvcreate"; "LV"; "VG"; "8"];
4936           ["mkfs"; "ext2"; "/dev/VG/LV"];
4937           ["mount"; "/dev/VG/LV"; "/"]]
4938    | InitSquashFS ->
4939        pr "  /* InitSquashFS for %s */\n" test_name;
4940        List.iter (generate_test_command_call test_name)
4941          [["blockdev_setrw"; "/dev/sda"];
4942           ["umount_all"];
4943           ["lvm_remove_all"];
4944           ["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"]]
4945   );
4946
4947   let get_seq_last = function
4948     | [] ->
4949         failwithf "%s: you cannot use [] (empty list) when expecting a command"
4950           test_name
4951     | seq ->
4952         let seq = List.rev seq in
4953         List.rev (List.tl seq), List.hd seq
4954   in
4955
4956   match test with
4957   | TestRun seq ->
4958       pr "  /* TestRun for %s (%d) */\n" name i;
4959       List.iter (generate_test_command_call test_name) seq
4960   | TestOutput (seq, expected) ->
4961       pr "  /* TestOutput for %s (%d) */\n" name i;
4962       pr "  const char *expected = \"%s\";\n" (c_quote expected);
4963       let seq, last = get_seq_last seq in
4964       let test () =
4965         pr "    if (strcmp (r, expected) != 0) {\n";
4966         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
4967         pr "      return -1;\n";
4968         pr "    }\n"
4969       in
4970       List.iter (generate_test_command_call test_name) seq;
4971       generate_test_command_call ~test test_name last
4972   | TestOutputList (seq, expected) ->
4973       pr "  /* TestOutputList for %s (%d) */\n" name i;
4974       let seq, last = get_seq_last seq in
4975       let test () =
4976         iteri (
4977           fun i str ->
4978             pr "    if (!r[%d]) {\n" i;
4979             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
4980             pr "      print_strings (r);\n";
4981             pr "      return -1;\n";
4982             pr "    }\n";
4983             pr "    {\n";
4984             pr "      const char *expected = \"%s\";\n" (c_quote str);
4985             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
4986             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
4987             pr "        return -1;\n";
4988             pr "      }\n";
4989             pr "    }\n"
4990         ) expected;
4991         pr "    if (r[%d] != NULL) {\n" (List.length expected);
4992         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
4993           test_name;
4994         pr "      print_strings (r);\n";
4995         pr "      return -1;\n";
4996         pr "    }\n"
4997       in
4998       List.iter (generate_test_command_call test_name) seq;
4999       generate_test_command_call ~test test_name last
5000   | TestOutputListOfDevices (seq, expected) ->
5001       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
5002       let seq, last = get_seq_last seq in
5003       let test () =
5004         iteri (
5005           fun i str ->
5006             pr "    if (!r[%d]) {\n" i;
5007             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5008             pr "      print_strings (r);\n";
5009             pr "      return -1;\n";
5010             pr "    }\n";
5011             pr "    {\n";
5012             pr "      const char *expected = \"%s\";\n" (c_quote str);
5013             pr "      r[%d][5] = 's';\n" i;
5014             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5015             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5016             pr "        return -1;\n";
5017             pr "      }\n";
5018             pr "    }\n"
5019         ) expected;
5020         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5021         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5022           test_name;
5023         pr "      print_strings (r);\n";
5024         pr "      return -1;\n";
5025         pr "    }\n"
5026       in
5027       List.iter (generate_test_command_call test_name) seq;
5028       generate_test_command_call ~test test_name last
5029   | TestOutputInt (seq, expected) ->
5030       pr "  /* TestOutputInt for %s (%d) */\n" name i;
5031       let seq, last = get_seq_last seq in
5032       let test () =
5033         pr "    if (r != %d) {\n" expected;
5034         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
5035           test_name expected;
5036         pr "               (int) r);\n";
5037         pr "      return -1;\n";
5038         pr "    }\n"
5039       in
5040       List.iter (generate_test_command_call test_name) seq;
5041       generate_test_command_call ~test test_name last
5042   | TestOutputIntOp (seq, op, expected) ->
5043       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
5044       let seq, last = get_seq_last seq in
5045       let test () =
5046         pr "    if (! (r %s %d)) {\n" op expected;
5047         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
5048           test_name op expected;
5049         pr "               (int) r);\n";
5050         pr "      return -1;\n";
5051         pr "    }\n"
5052       in
5053       List.iter (generate_test_command_call test_name) seq;
5054       generate_test_command_call ~test test_name last
5055   | TestOutputTrue seq ->
5056       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
5057       let seq, last = get_seq_last seq in
5058       let test () =
5059         pr "    if (!r) {\n";
5060         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
5061           test_name;
5062         pr "      return -1;\n";
5063         pr "    }\n"
5064       in
5065       List.iter (generate_test_command_call test_name) seq;
5066       generate_test_command_call ~test test_name last
5067   | TestOutputFalse seq ->
5068       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
5069       let seq, last = get_seq_last seq in
5070       let test () =
5071         pr "    if (r) {\n";
5072         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
5073           test_name;
5074         pr "      return -1;\n";
5075         pr "    }\n"
5076       in
5077       List.iter (generate_test_command_call test_name) seq;
5078       generate_test_command_call ~test test_name last
5079   | TestOutputLength (seq, expected) ->
5080       pr "  /* TestOutputLength for %s (%d) */\n" name i;
5081       let seq, last = get_seq_last seq in
5082       let test () =
5083         pr "    int j;\n";
5084         pr "    for (j = 0; j < %d; ++j)\n" expected;
5085         pr "      if (r[j] == NULL) {\n";
5086         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
5087           test_name;
5088         pr "        print_strings (r);\n";
5089         pr "        return -1;\n";
5090         pr "      }\n";
5091         pr "    if (r[j] != NULL) {\n";
5092         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
5093           test_name;
5094         pr "      print_strings (r);\n";
5095         pr "      return -1;\n";
5096         pr "    }\n"
5097       in
5098       List.iter (generate_test_command_call test_name) seq;
5099       generate_test_command_call ~test test_name last
5100   | TestOutputStruct (seq, checks) ->
5101       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
5102       let seq, last = get_seq_last seq in
5103       let test () =
5104         List.iter (
5105           function
5106           | CompareWithInt (field, expected) ->
5107               pr "    if (r->%s != %d) {\n" field expected;
5108               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
5109                 test_name field expected;
5110               pr "               (int) r->%s);\n" field;
5111               pr "      return -1;\n";
5112               pr "    }\n"
5113           | CompareWithIntOp (field, op, expected) ->
5114               pr "    if (!(r->%s %s %d)) {\n" field op expected;
5115               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
5116                 test_name field op expected;
5117               pr "               (int) r->%s);\n" field;
5118               pr "      return -1;\n";
5119               pr "    }\n"
5120           | CompareWithString (field, expected) ->
5121               pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
5122               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
5123                 test_name field expected;
5124               pr "               r->%s);\n" field;
5125               pr "      return -1;\n";
5126               pr "    }\n"
5127           | CompareFieldsIntEq (field1, field2) ->
5128               pr "    if (r->%s != r->%s) {\n" field1 field2;
5129               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
5130                 test_name field1 field2;
5131               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
5132               pr "      return -1;\n";
5133               pr "    }\n"
5134           | CompareFieldsStrEq (field1, field2) ->
5135               pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
5136               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
5137                 test_name field1 field2;
5138               pr "               r->%s, r->%s);\n" field1 field2;
5139               pr "      return -1;\n";
5140               pr "    }\n"
5141         ) checks
5142       in
5143       List.iter (generate_test_command_call test_name) seq;
5144       generate_test_command_call ~test test_name last
5145   | TestLastFail seq ->
5146       pr "  /* TestLastFail for %s (%d) */\n" name i;
5147       let seq, last = get_seq_last seq in
5148       List.iter (generate_test_command_call test_name) seq;
5149       generate_test_command_call test_name ~expect_error:true last
5150
5151 (* Generate the code to run a command, leaving the result in 'r'.
5152  * If you expect to get an error then you should set expect_error:true.
5153  *)
5154 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
5155   match cmd with
5156   | [] -> assert false
5157   | name :: args ->
5158       (* Look up the command to find out what args/ret it has. *)
5159       let style =
5160         try
5161           let _, style, _, _, _, _, _ =
5162             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
5163           style
5164         with Not_found ->
5165           failwithf "%s: in test, command %s was not found" test_name name in
5166
5167       if List.length (snd style) <> List.length args then
5168         failwithf "%s: in test, wrong number of args given to %s"
5169           test_name name;
5170
5171       pr "  {\n";
5172
5173       List.iter (
5174         function
5175         | OptString n, "NULL" -> ()
5176         | String n, arg
5177         | OptString n, arg ->
5178             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
5179         | Int _, _
5180         | Bool _, _
5181         | FileIn _, _ | FileOut _, _ -> ()
5182         | StringList n, arg ->
5183             let strs = string_split " " arg in
5184             iteri (
5185               fun i str ->
5186                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
5187             ) strs;
5188             pr "    const char *%s[] = {\n" n;
5189             iteri (
5190               fun i _ -> pr "      %s_%d,\n" n i
5191             ) strs;
5192             pr "      NULL\n";
5193             pr "    };\n";
5194       ) (List.combine (snd style) args);
5195
5196       let error_code =
5197         match fst style with
5198         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
5199         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
5200         | RConstString _ | RConstOptString _ ->
5201             pr "    const char *r;\n"; "NULL"
5202         | RString _ -> pr "    char *r;\n"; "NULL"
5203         | RStringList _ | RHashtable _ ->
5204             pr "    char **r;\n";
5205             pr "    int i;\n";
5206             "NULL"
5207         | RStruct (_, typ) ->
5208             pr "    struct guestfs_%s *r;\n" typ; "NULL"
5209         | RStructList (_, typ) ->
5210             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
5211         | RBufferOut _ ->
5212             pr "    char *r;\n";
5213             pr "    size_t size;\n";
5214             "NULL" in
5215
5216       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
5217       pr "    r = guestfs_%s (g" name;
5218
5219       (* Generate the parameters. *)
5220       List.iter (
5221         function
5222         | OptString _, "NULL" -> pr ", NULL"
5223         | String n, _
5224         | OptString n, _ ->
5225             pr ", %s" n
5226         | FileIn _, arg | FileOut _, arg ->
5227             pr ", \"%s\"" (c_quote arg)
5228         | StringList n, _ ->
5229             pr ", %s" n
5230         | Int _, arg ->
5231             let i =
5232               try int_of_string arg
5233               with Failure "int_of_string" ->
5234                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
5235             pr ", %d" i
5236         | Bool _, arg ->
5237             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
5238       ) (List.combine (snd style) args);
5239
5240       (match fst style with
5241        | RBufferOut _ -> pr ", &size"
5242        | _ -> ()
5243       );
5244
5245       pr ");\n";
5246
5247       if not expect_error then
5248         pr "    if (r == %s)\n" error_code
5249       else
5250         pr "    if (r != %s)\n" error_code;
5251       pr "      return -1;\n";
5252
5253       (* Insert the test code. *)
5254       (match test with
5255        | None -> ()
5256        | Some f -> f ()
5257       );
5258
5259       (match fst style with
5260        | RErr | RInt _ | RInt64 _ | RBool _
5261        | RConstString _ | RConstOptString _ -> ()
5262        | RString _ | RBufferOut _ -> pr "    free (r);\n"
5263        | RStringList _ | RHashtable _ ->
5264            pr "    for (i = 0; r[i] != NULL; ++i)\n";
5265            pr "      free (r[i]);\n";
5266            pr "    free (r);\n"
5267        | RStruct (_, typ) ->
5268            pr "    guestfs_free_%s (r);\n" typ
5269        | RStructList (_, typ) ->
5270            pr "    guestfs_free_%s_list (r);\n" typ
5271       );
5272
5273       pr "  }\n"
5274
5275 and c_quote str =
5276   let str = replace_str str "\r" "\\r" in
5277   let str = replace_str str "\n" "\\n" in
5278   let str = replace_str str "\t" "\\t" in
5279   let str = replace_str str "\000" "\\0" in
5280   str
5281
5282 (* Generate a lot of different functions for guestfish. *)
5283 and generate_fish_cmds () =
5284   generate_header CStyle GPLv2;
5285
5286   let all_functions =
5287     List.filter (
5288       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5289     ) all_functions in
5290   let all_functions_sorted =
5291     List.filter (
5292       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5293     ) all_functions_sorted in
5294
5295   pr "#include <stdio.h>\n";
5296   pr "#include <stdlib.h>\n";
5297   pr "#include <string.h>\n";
5298   pr "#include <inttypes.h>\n";
5299   pr "#include <ctype.h>\n";
5300   pr "\n";
5301   pr "#include <guestfs.h>\n";
5302   pr "#include \"fish.h\"\n";
5303   pr "\n";
5304
5305   (* list_commands function, which implements guestfish -h *)
5306   pr "void list_commands (void)\n";
5307   pr "{\n";
5308   pr "  printf (\"    %%-16s     %%s\\n\", \"Command\", \"Description\");\n";
5309   pr "  list_builtin_commands ();\n";
5310   List.iter (
5311     fun (name, _, _, flags, _, shortdesc, _) ->
5312       let name = replace_char name '_' '-' in
5313       pr "  printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
5314         name shortdesc
5315   ) all_functions_sorted;
5316   pr "  printf (\"    Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
5317   pr "}\n";
5318   pr "\n";
5319
5320   (* display_command function, which implements guestfish -h cmd *)
5321   pr "void display_command (const char *cmd)\n";
5322   pr "{\n";
5323   List.iter (
5324     fun (name, style, _, flags, _, shortdesc, longdesc) ->
5325       let name2 = replace_char name '_' '-' in
5326       let alias =
5327         try find_map (function FishAlias n -> Some n | _ -> None) flags
5328         with Not_found -> name in
5329       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
5330       let synopsis =
5331         match snd style with
5332         | [] -> name2
5333         | args ->
5334             sprintf "%s <%s>"
5335               name2 (String.concat "> <" (List.map name_of_argt args)) in
5336
5337       let warnings =
5338         if List.mem ProtocolLimitWarning flags then
5339           ("\n\n" ^ protocol_limit_warning)
5340         else "" in
5341
5342       (* For DangerWillRobinson commands, we should probably have
5343        * guestfish prompt before allowing you to use them (especially
5344        * in interactive mode). XXX
5345        *)
5346       let warnings =
5347         warnings ^
5348           if List.mem DangerWillRobinson flags then
5349             ("\n\n" ^ danger_will_robinson)
5350           else "" in
5351
5352       let describe_alias =
5353         if name <> alias then
5354           sprintf "\n\nYou can use '%s' as an alias for this command." alias
5355         else "" in
5356
5357       pr "  if (";
5358       pr "strcasecmp (cmd, \"%s\") == 0" name;
5359       if name <> name2 then
5360         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5361       if name <> alias then
5362         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5363       pr ")\n";
5364       pr "    pod2text (\"%s - %s\", %S);\n"
5365         name2 shortdesc
5366         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
5367       pr "  else\n"
5368   ) all_functions;
5369   pr "    display_builtin_command (cmd);\n";
5370   pr "}\n";
5371   pr "\n";
5372
5373   (* print_* functions *)
5374   List.iter (
5375     fun (typ, cols) ->
5376       let needs_i =
5377         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
5378
5379       pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
5380       pr "{\n";
5381       if needs_i then (
5382         pr "  int i;\n";
5383         pr "\n"
5384       );
5385       List.iter (
5386         function
5387         | name, FString ->
5388             pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
5389         | name, FUUID ->
5390             pr "  printf (\"%s: \");\n" name;
5391             pr "  for (i = 0; i < 32; ++i)\n";
5392             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
5393             pr "  printf (\"\\n\");\n"
5394         | name, FBuffer ->
5395             pr "  printf (\"%s: \");\n" name;
5396             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
5397             pr "    if (isprint (%s->%s[i]))\n" typ name;
5398             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
5399             pr "    else\n";
5400             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
5401             pr "  printf (\"\\n\");\n"
5402         | name, (FUInt64|FBytes) ->
5403             pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
5404         | name, FInt64 ->
5405             pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
5406         | name, FUInt32 ->
5407             pr "  printf (\"%s: %%\" PRIu32 \"\\n\", %s->%s);\n" name typ name
5408         | name, FInt32 ->
5409             pr "  printf (\"%s: %%\" PRIi32 \"\\n\", %s->%s);\n" name typ name
5410         | name, FChar ->
5411             pr "  printf (\"%s: %%c\\n\", %s->%s);\n" name typ name
5412         | name, FOptPercent ->
5413             pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
5414               typ name name typ name;
5415             pr "  else printf (\"%s: \\n\");\n" name
5416       ) cols;
5417       pr "}\n";
5418       pr "\n";
5419       pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
5420         typ typ typ;
5421       pr "{\n";
5422       pr "  int i;\n";
5423       pr "\n";
5424       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
5425       pr "    print_%s (&%ss->val[i]);\n" typ typ;
5426       pr "}\n";
5427       pr "\n";
5428   ) structs;
5429
5430   (* run_<action> actions *)
5431   List.iter (
5432     fun (name, style, _, flags, _, _, _) ->
5433       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
5434       pr "{\n";
5435       (match fst style with
5436        | RErr
5437        | RInt _
5438        | RBool _ -> pr "  int r;\n"
5439        | RInt64 _ -> pr "  int64_t r;\n"
5440        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
5441        | RString _ -> pr "  char *r;\n"
5442        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
5443        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
5444        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
5445        | RBufferOut _ ->
5446            pr "  char *r;\n";
5447            pr "  size_t size;\n";
5448       );
5449       List.iter (
5450         function
5451         | String n
5452         | OptString n
5453         | FileIn n
5454         | FileOut n -> pr "  const char *%s;\n" n
5455         | StringList n -> pr "  char **%s;\n" n
5456         | Bool n -> pr "  int %s;\n" n
5457         | Int n -> pr "  int %s;\n" n
5458       ) (snd style);
5459
5460       (* Check and convert parameters. *)
5461       let argc_expected = List.length (snd style) in
5462       pr "  if (argc != %d) {\n" argc_expected;
5463       pr "    fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
5464         argc_expected;
5465       pr "    fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
5466       pr "    return -1;\n";
5467       pr "  }\n";
5468       iteri (
5469         fun i ->
5470           function
5471           | String name -> pr "  %s = argv[%d];\n" name i
5472           | OptString name ->
5473               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5474                 name i i
5475           | FileIn name ->
5476               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5477                 name i i
5478           | FileOut name ->
5479               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5480                 name i i
5481           | StringList name ->
5482               pr "  %s = parse_string_list (argv[%d]);\n" name i
5483           | Bool name ->
5484               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5485           | Int name ->
5486               pr "  %s = atoi (argv[%d]);\n" name i
5487       ) (snd style);
5488
5489       (* Call C API function. *)
5490       let fn =
5491         try find_map (function FishAction n -> Some n | _ -> None) flags
5492         with Not_found -> sprintf "guestfs_%s" name in
5493       pr "  r = %s " fn;
5494       generate_c_call_args ~handle:"g" style;
5495       pr ";\n";
5496
5497       (* Check return value for errors and display command results. *)
5498       (match fst style with
5499        | RErr -> pr "  return r;\n"
5500        | RInt _ ->
5501            pr "  if (r == -1) return -1;\n";
5502            pr "  printf (\"%%d\\n\", r);\n";
5503            pr "  return 0;\n"
5504        | RInt64 _ ->
5505            pr "  if (r == -1) return -1;\n";
5506            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
5507            pr "  return 0;\n"
5508        | RBool _ ->
5509            pr "  if (r == -1) return -1;\n";
5510            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
5511            pr "  return 0;\n"
5512        | RConstString _ ->
5513            pr "  if (r == NULL) return -1;\n";
5514            pr "  printf (\"%%s\\n\", r);\n";
5515            pr "  return 0;\n"
5516        | RConstOptString _ ->
5517            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
5518            pr "  return 0;\n"
5519        | RString _ ->
5520            pr "  if (r == NULL) return -1;\n";
5521            pr "  printf (\"%%s\\n\", r);\n";
5522            pr "  free (r);\n";
5523            pr "  return 0;\n"
5524        | RStringList _ ->
5525            pr "  if (r == NULL) return -1;\n";
5526            pr "  print_strings (r);\n";
5527            pr "  free_strings (r);\n";
5528            pr "  return 0;\n"
5529        | RStruct (_, typ) ->
5530            pr "  if (r == NULL) return -1;\n";
5531            pr "  print_%s (r);\n" typ;
5532            pr "  guestfs_free_%s (r);\n" typ;
5533            pr "  return 0;\n"
5534        | RStructList (_, typ) ->
5535            pr "  if (r == NULL) return -1;\n";
5536            pr "  print_%s_list (r);\n" typ;
5537            pr "  guestfs_free_%s_list (r);\n" typ;
5538            pr "  return 0;\n"
5539        | RHashtable _ ->
5540            pr "  if (r == NULL) return -1;\n";
5541            pr "  print_table (r);\n";
5542            pr "  free_strings (r);\n";
5543            pr "  return 0;\n"
5544        | RBufferOut _ ->
5545            pr "  if (r == NULL) return -1;\n";
5546            pr "  fwrite (r, size, 1, stdout);\n";
5547            pr "  free (r);\n";
5548            pr "  return 0;\n"
5549       );
5550       pr "}\n";
5551       pr "\n"
5552   ) all_functions;
5553
5554   (* run_action function *)
5555   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
5556   pr "{\n";
5557   List.iter (
5558     fun (name, _, _, flags, _, _, _) ->
5559       let name2 = replace_char name '_' '-' in
5560       let alias =
5561         try find_map (function FishAlias n -> Some n | _ -> None) flags
5562         with Not_found -> name in
5563       pr "  if (";
5564       pr "strcasecmp (cmd, \"%s\") == 0" name;
5565       if name <> name2 then
5566         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5567       if name <> alias then
5568         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5569       pr ")\n";
5570       pr "    return run_%s (cmd, argc, argv);\n" name;
5571       pr "  else\n";
5572   ) all_functions;
5573   pr "    {\n";
5574   pr "      fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
5575   pr "      return -1;\n";
5576   pr "    }\n";
5577   pr "  return 0;\n";
5578   pr "}\n";
5579   pr "\n"
5580
5581 (* Readline completion for guestfish. *)
5582 and generate_fish_completion () =
5583   generate_header CStyle GPLv2;
5584
5585   let all_functions =
5586     List.filter (
5587       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5588     ) all_functions in
5589
5590   pr "\
5591 #include <config.h>
5592
5593 #include <stdio.h>
5594 #include <stdlib.h>
5595 #include <string.h>
5596
5597 #ifdef HAVE_LIBREADLINE
5598 #include <readline/readline.h>
5599 #endif
5600
5601 #include \"fish.h\"
5602
5603 #ifdef HAVE_LIBREADLINE
5604
5605 static const char *const commands[] = {
5606   BUILTIN_COMMANDS_FOR_COMPLETION,
5607 ";
5608
5609   (* Get the commands, including the aliases.  They don't need to be
5610    * sorted - the generator() function just does a dumb linear search.
5611    *)
5612   let commands =
5613     List.map (
5614       fun (name, _, _, flags, _, _, _) ->
5615         let name2 = replace_char name '_' '-' in
5616         let alias =
5617           try find_map (function FishAlias n -> Some n | _ -> None) flags
5618           with Not_found -> name in
5619
5620         if name <> alias then [name2; alias] else [name2]
5621     ) all_functions in
5622   let commands = List.flatten commands in
5623
5624   List.iter (pr "  \"%s\",\n") commands;
5625
5626   pr "  NULL
5627 };
5628
5629 static char *
5630 generator (const char *text, int state)
5631 {
5632   static int index, len;
5633   const char *name;
5634
5635   if (!state) {
5636     index = 0;
5637     len = strlen (text);
5638   }
5639
5640   rl_attempted_completion_over = 1;
5641
5642   while ((name = commands[index]) != NULL) {
5643     index++;
5644     if (strncasecmp (name, text, len) == 0)
5645       return strdup (name);
5646   }
5647
5648   return NULL;
5649 }
5650
5651 #endif /* HAVE_LIBREADLINE */
5652
5653 char **do_completion (const char *text, int start, int end)
5654 {
5655   char **matches = NULL;
5656
5657 #ifdef HAVE_LIBREADLINE
5658   rl_completion_append_character = ' ';
5659
5660   if (start == 0)
5661     matches = rl_completion_matches (text, generator);
5662   else if (complete_dest_paths)
5663     matches = rl_completion_matches (text, complete_dest_paths_generator);
5664 #endif
5665
5666   return matches;
5667 }
5668 ";
5669
5670 (* Generate the POD documentation for guestfish. *)
5671 and generate_fish_actions_pod () =
5672   let all_functions_sorted =
5673     List.filter (
5674       fun (_, _, _, flags, _, _, _) ->
5675         not (List.mem NotInFish flags || List.mem NotInDocs flags)
5676     ) all_functions_sorted in
5677
5678   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
5679
5680   List.iter (
5681     fun (name, style, _, flags, _, _, longdesc) ->
5682       let longdesc =
5683         Str.global_substitute rex (
5684           fun s ->
5685             let sub =
5686               try Str.matched_group 1 s
5687               with Not_found ->
5688                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
5689             "C<" ^ replace_char sub '_' '-' ^ ">"
5690         ) longdesc in
5691       let name = replace_char name '_' '-' in
5692       let alias =
5693         try find_map (function FishAlias n -> Some n | _ -> None) flags
5694         with Not_found -> name in
5695
5696       pr "=head2 %s" name;
5697       if name <> alias then
5698         pr " | %s" alias;
5699       pr "\n";
5700       pr "\n";
5701       pr " %s" name;
5702       List.iter (
5703         function
5704         | String n -> pr " %s" n
5705         | OptString n -> pr " %s" n
5706         | StringList n -> pr " '%s ...'" n
5707         | Bool _ -> pr " true|false"
5708         | Int n -> pr " %s" n
5709         | FileIn n | FileOut n -> pr " (%s|-)" n
5710       ) (snd style);
5711       pr "\n";
5712       pr "\n";
5713       pr "%s\n\n" longdesc;
5714
5715       if List.exists (function FileIn _ | FileOut _ -> true
5716                       | _ -> false) (snd style) then
5717         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5718
5719       if List.mem ProtocolLimitWarning flags then
5720         pr "%s\n\n" protocol_limit_warning;
5721
5722       if List.mem DangerWillRobinson flags then
5723         pr "%s\n\n" danger_will_robinson
5724   ) all_functions_sorted
5725
5726 (* Generate a C function prototype. *)
5727 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5728     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5729     ?(prefix = "")
5730     ?handle name style =
5731   if extern then pr "extern ";
5732   if static then pr "static ";
5733   (match fst style with
5734    | RErr -> pr "int "
5735    | RInt _ -> pr "int "
5736    | RInt64 _ -> pr "int64_t "
5737    | RBool _ -> pr "int "
5738    | RConstString _ | RConstOptString _ -> pr "const char *"
5739    | RString _ | RBufferOut _ -> pr "char *"
5740    | RStringList _ | RHashtable _ -> pr "char **"
5741    | RStruct (_, typ) ->
5742        if not in_daemon then pr "struct guestfs_%s *" typ
5743        else pr "guestfs_int_%s *" typ
5744    | RStructList (_, typ) ->
5745        if not in_daemon then pr "struct guestfs_%s_list *" typ
5746        else pr "guestfs_int_%s_list *" typ
5747   );
5748   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
5749   pr "%s%s (" prefix name;
5750   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
5751     pr "void"
5752   else (
5753     let comma = ref false in
5754     (match handle with
5755      | None -> ()
5756      | Some handle -> pr "guestfs_h *%s" handle; comma := true
5757     );
5758     let next () =
5759       if !comma then (
5760         if single_line then pr ", " else pr ",\n\t\t"
5761       );
5762       comma := true
5763     in
5764     List.iter (
5765       function
5766       | String n
5767       | OptString n ->
5768           next ();
5769           if not in_daemon then pr "const char *%s" n
5770           else pr "char *%s" n
5771       | StringList n ->
5772           next ();
5773           if not in_daemon then pr "char * const* const %s" n
5774           else pr "char **%s" n
5775       | Bool n -> next (); pr "int %s" n
5776       | Int n -> next (); pr "int %s" n
5777       | FileIn n
5778       | FileOut n ->
5779           if not in_daemon then (next (); pr "const char *%s" n)
5780     ) (snd style);
5781     if is_RBufferOut then (next (); pr "size_t *size_r");
5782   );
5783   pr ")";
5784   if semicolon then pr ";";
5785   if newline then pr "\n"
5786
5787 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5788 and generate_c_call_args ?handle ?(decl = false) style =
5789   pr "(";
5790   let comma = ref false in
5791   let next () =
5792     if !comma then pr ", ";
5793     comma := true
5794   in
5795   (match handle with
5796    | None -> ()
5797    | Some handle -> pr "%s" handle; comma := true
5798   );
5799   List.iter (
5800     fun arg ->
5801       next ();
5802       pr "%s" (name_of_argt arg)
5803   ) (snd style);
5804   (* For RBufferOut calls, add implicit &size parameter. *)
5805   if not decl then (
5806     match fst style with
5807     | RBufferOut _ ->
5808         next ();
5809         pr "&size"
5810     | _ -> ()
5811   );
5812   pr ")"
5813
5814 (* Generate the OCaml bindings interface. *)
5815 and generate_ocaml_mli () =
5816   generate_header OCamlStyle LGPLv2;
5817
5818   pr "\
5819 (** For API documentation you should refer to the C API
5820     in the guestfs(3) manual page.  The OCaml API uses almost
5821     exactly the same calls. *)
5822
5823 type t
5824 (** A [guestfs_h] handle. *)
5825
5826 exception Error of string
5827 (** This exception is raised when there is an error. *)
5828
5829 val create : unit -> t
5830
5831 val close : t -> unit
5832 (** Handles are closed by the garbage collector when they become
5833     unreferenced, but callers can also call this in order to
5834     provide predictable cleanup. *)
5835
5836 ";
5837   generate_ocaml_structure_decls ();
5838
5839   (* The actions. *)
5840   List.iter (
5841     fun (name, style, _, _, _, shortdesc, _) ->
5842       generate_ocaml_prototype name style;
5843       pr "(** %s *)\n" shortdesc;
5844       pr "\n"
5845   ) all_functions
5846
5847 (* Generate the OCaml bindings implementation. *)
5848 and generate_ocaml_ml () =
5849   generate_header OCamlStyle LGPLv2;
5850
5851   pr "\
5852 type t
5853 exception Error of string
5854 external create : unit -> t = \"ocaml_guestfs_create\"
5855 external close : t -> unit = \"ocaml_guestfs_close\"
5856
5857 let () =
5858   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
5859
5860 ";
5861
5862   generate_ocaml_structure_decls ();
5863
5864   (* The actions. *)
5865   List.iter (
5866     fun (name, style, _, _, _, shortdesc, _) ->
5867       generate_ocaml_prototype ~is_external:true name style;
5868   ) all_functions
5869
5870 (* Generate the OCaml bindings C implementation. *)
5871 and generate_ocaml_c () =
5872   generate_header CStyle LGPLv2;
5873
5874   pr "\
5875 #include <stdio.h>
5876 #include <stdlib.h>
5877 #include <string.h>
5878
5879 #include <caml/config.h>
5880 #include <caml/alloc.h>
5881 #include <caml/callback.h>
5882 #include <caml/fail.h>
5883 #include <caml/memory.h>
5884 #include <caml/mlvalues.h>
5885 #include <caml/signals.h>
5886
5887 #include <guestfs.h>
5888
5889 #include \"guestfs_c.h\"
5890
5891 /* Copy a hashtable of string pairs into an assoc-list.  We return
5892  * the list in reverse order, but hashtables aren't supposed to be
5893  * ordered anyway.
5894  */
5895 static CAMLprim value
5896 copy_table (char * const * argv)
5897 {
5898   CAMLparam0 ();
5899   CAMLlocal5 (rv, pairv, kv, vv, cons);
5900   int i;
5901
5902   rv = Val_int (0);
5903   for (i = 0; argv[i] != NULL; i += 2) {
5904     kv = caml_copy_string (argv[i]);
5905     vv = caml_copy_string (argv[i+1]);
5906     pairv = caml_alloc (2, 0);
5907     Store_field (pairv, 0, kv);
5908     Store_field (pairv, 1, vv);
5909     cons = caml_alloc (2, 0);
5910     Store_field (cons, 1, rv);
5911     rv = cons;
5912     Store_field (cons, 0, pairv);
5913   }
5914
5915   CAMLreturn (rv);
5916 }
5917
5918 ";
5919
5920   (* Struct copy functions. *)
5921   List.iter (
5922     fun (typ, cols) ->
5923       let has_optpercent_col =
5924         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
5925
5926       pr "static CAMLprim value\n";
5927       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
5928       pr "{\n";
5929       pr "  CAMLparam0 ();\n";
5930       if has_optpercent_col then
5931         pr "  CAMLlocal3 (rv, v, v2);\n"
5932       else
5933         pr "  CAMLlocal2 (rv, v);\n";
5934       pr "\n";
5935       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
5936       iteri (
5937         fun i col ->
5938           (match col with
5939            | name, FString ->
5940                pr "  v = caml_copy_string (%s->%s);\n" typ name
5941            | name, FBuffer ->
5942                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
5943                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
5944                  typ name typ name
5945            | name, FUUID ->
5946                pr "  v = caml_alloc_string (32);\n";
5947                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
5948            | name, (FBytes|FInt64|FUInt64) ->
5949                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
5950            | name, (FInt32|FUInt32) ->
5951                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
5952            | name, FOptPercent ->
5953                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
5954                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
5955                pr "    v = caml_alloc (1, 0);\n";
5956                pr "    Store_field (v, 0, v2);\n";
5957                pr "  } else /* None */\n";
5958                pr "    v = Val_int (0);\n";
5959            | name, FChar ->
5960                pr "  v = Val_int (%s->%s);\n" typ name
5961           );
5962           pr "  Store_field (rv, %d, v);\n" i
5963       ) cols;
5964       pr "  CAMLreturn (rv);\n";
5965       pr "}\n";
5966       pr "\n";
5967
5968       pr "static CAMLprim value\n";
5969       pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n"
5970         typ typ typ;
5971       pr "{\n";
5972       pr "  CAMLparam0 ();\n";
5973       pr "  CAMLlocal2 (rv, v);\n";
5974       pr "  int i;\n";
5975       pr "\n";
5976       pr "  if (%ss->len == 0)\n" typ;
5977       pr "    CAMLreturn (Atom (0));\n";
5978       pr "  else {\n";
5979       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
5980       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
5981       pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
5982       pr "      caml_modify (&Field (rv, i), v);\n";
5983       pr "    }\n";
5984       pr "    CAMLreturn (rv);\n";
5985       pr "  }\n";
5986       pr "}\n";
5987       pr "\n";
5988   ) structs;
5989
5990   (* The wrappers. *)
5991   List.iter (
5992     fun (name, style, _, _, _, _, _) ->
5993       let params =
5994         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
5995
5996       let needs_extra_vs =
5997         match fst style with RConstOptString _ -> true | _ -> false in
5998
5999       pr "CAMLprim value\n";
6000       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
6001       List.iter (pr ", value %s") (List.tl params);
6002       pr ")\n";
6003       pr "{\n";
6004
6005       (match params with
6006        | [p1; p2; p3; p4; p5] ->
6007            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
6008        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
6009            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
6010            pr "  CAMLxparam%d (%s);\n"
6011              (List.length rest) (String.concat ", " rest)
6012        | ps ->
6013            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
6014       );
6015       if not needs_extra_vs then
6016         pr "  CAMLlocal1 (rv);\n"
6017       else
6018         pr "  CAMLlocal3 (rv, v, v2);\n";
6019       pr "\n";
6020
6021       pr "  guestfs_h *g = Guestfs_val (gv);\n";
6022       pr "  if (g == NULL)\n";
6023       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
6024       pr "\n";
6025
6026       List.iter (
6027         function
6028         | String n
6029         | FileIn n
6030         | FileOut n ->
6031             pr "  const char *%s = String_val (%sv);\n" n n
6032         | OptString n ->
6033             pr "  const char *%s =\n" n;
6034             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
6035               n n
6036         | StringList n ->
6037             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
6038         | Bool n ->
6039             pr "  int %s = Bool_val (%sv);\n" n n
6040         | Int n ->
6041             pr "  int %s = Int_val (%sv);\n" n n
6042       ) (snd style);
6043       let error_code =
6044         match fst style with
6045         | RErr -> pr "  int r;\n"; "-1"
6046         | RInt _ -> pr "  int r;\n"; "-1"
6047         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6048         | RBool _ -> pr "  int r;\n"; "-1"
6049         | RConstString _ | RConstOptString _ ->
6050             pr "  const char *r;\n"; "NULL"
6051         | RString _ -> pr "  char *r;\n"; "NULL"
6052         | RStringList _ ->
6053             pr "  int i;\n";
6054             pr "  char **r;\n";
6055             "NULL"
6056         | RStruct (_, typ) ->
6057             pr "  struct guestfs_%s *r;\n" typ; "NULL"
6058         | RStructList (_, typ) ->
6059             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
6060         | RHashtable _ ->
6061             pr "  int i;\n";
6062             pr "  char **r;\n";
6063             "NULL"
6064         | RBufferOut _ ->
6065             pr "  char *r;\n";
6066             pr "  size_t size;\n";
6067             "NULL" in
6068       pr "\n";
6069
6070       pr "  caml_enter_blocking_section ();\n";
6071       pr "  r = guestfs_%s " name;
6072       generate_c_call_args ~handle:"g" style;
6073       pr ";\n";
6074       pr "  caml_leave_blocking_section ();\n";
6075
6076       List.iter (
6077         function
6078         | StringList n ->
6079             pr "  ocaml_guestfs_free_strings (%s);\n" n;
6080         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
6081       ) (snd style);
6082
6083       pr "  if (r == %s)\n" error_code;
6084       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
6085       pr "\n";
6086
6087       (match fst style with
6088        | RErr -> pr "  rv = Val_unit;\n"
6089        | RInt _ -> pr "  rv = Val_int (r);\n"
6090        | RInt64 _ ->
6091            pr "  rv = caml_copy_int64 (r);\n"
6092        | RBool _ -> pr "  rv = Val_bool (r);\n"
6093        | RConstString _ ->
6094            pr "  rv = caml_copy_string (r);\n"
6095        | RConstOptString _ ->
6096            pr "  if (r) { /* Some string */\n";
6097            pr "    v = caml_alloc (1, 0);\n";
6098            pr "    v2 = caml_copy_string (r);\n";
6099            pr "    Store_field (v, 0, v2);\n";
6100            pr "  } else /* None */\n";
6101            pr "    v = Val_int (0);\n";
6102        | RString _ ->
6103            pr "  rv = caml_copy_string (r);\n";
6104            pr "  free (r);\n"
6105        | RStringList _ ->
6106            pr "  rv = caml_copy_string_array ((const char **) r);\n";
6107            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6108            pr "  free (r);\n"
6109        | RStruct (_, typ) ->
6110            pr "  rv = copy_%s (r);\n" typ;
6111            pr "  guestfs_free_%s (r);\n" typ;
6112        | RStructList (_, typ) ->
6113            pr "  rv = copy_%s_list (r);\n" typ;
6114            pr "  guestfs_free_%s_list (r);\n" typ;
6115        | RHashtable _ ->
6116            pr "  rv = copy_table (r);\n";
6117            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6118            pr "  free (r);\n";
6119        | RBufferOut _ ->
6120            pr "  rv = caml_alloc_string (size);\n";
6121            pr "  memcpy (String_val (rv), r, size);\n";
6122       );
6123
6124       pr "  CAMLreturn (rv);\n";
6125       pr "}\n";
6126       pr "\n";
6127
6128       if List.length params > 5 then (
6129         pr "CAMLprim value\n";
6130         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
6131         pr "{\n";
6132         pr "  return ocaml_guestfs_%s (argv[0]" name;
6133         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
6134         pr ");\n";
6135         pr "}\n";
6136         pr "\n"
6137       )
6138   ) all_functions
6139
6140 and generate_ocaml_structure_decls () =
6141   List.iter (
6142     fun (typ, cols) ->
6143       pr "type %s = {\n" typ;
6144       List.iter (
6145         function
6146         | name, FString -> pr "  %s : string;\n" name
6147         | name, FBuffer -> pr "  %s : string;\n" name
6148         | name, FUUID -> pr "  %s : string;\n" name
6149         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
6150         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
6151         | name, FChar -> pr "  %s : char;\n" name
6152         | name, FOptPercent -> pr "  %s : float option;\n" name
6153       ) cols;
6154       pr "}\n";
6155       pr "\n"
6156   ) structs
6157
6158 and generate_ocaml_prototype ?(is_external = false) name style =
6159   if is_external then pr "external " else pr "val ";
6160   pr "%s : t -> " name;
6161   List.iter (
6162     function
6163     | String _ | FileIn _ | FileOut _ -> pr "string -> "
6164     | OptString _ -> pr "string option -> "
6165     | StringList _ -> pr "string array -> "
6166     | Bool _ -> pr "bool -> "
6167     | Int _ -> pr "int -> "
6168   ) (snd style);
6169   (match fst style with
6170    | RErr -> pr "unit" (* all errors are turned into exceptions *)
6171    | RInt _ -> pr "int"
6172    | RInt64 _ -> pr "int64"
6173    | RBool _ -> pr "bool"
6174    | RConstString _ -> pr "string"
6175    | RConstOptString _ -> pr "string option"
6176    | RString _ | RBufferOut _ -> pr "string"
6177    | RStringList _ -> pr "string array"
6178    | RStruct (_, typ) -> pr "%s" typ
6179    | RStructList (_, typ) -> pr "%s array" typ
6180    | RHashtable _ -> pr "(string * string) list"
6181   );
6182   if is_external then (
6183     pr " = ";
6184     if List.length (snd style) + 1 > 5 then
6185       pr "\"ocaml_guestfs_%s_byte\" " name;
6186     pr "\"ocaml_guestfs_%s\"" name
6187   );
6188   pr "\n"
6189
6190 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
6191 and generate_perl_xs () =
6192   generate_header CStyle LGPLv2;
6193
6194   pr "\
6195 #include \"EXTERN.h\"
6196 #include \"perl.h\"
6197 #include \"XSUB.h\"
6198
6199 #include <guestfs.h>
6200
6201 #ifndef PRId64
6202 #define PRId64 \"lld\"
6203 #endif
6204
6205 static SV *
6206 my_newSVll(long long val) {
6207 #ifdef USE_64_BIT_ALL
6208   return newSViv(val);
6209 #else
6210   char buf[100];
6211   int len;
6212   len = snprintf(buf, 100, \"%%\" PRId64, val);
6213   return newSVpv(buf, len);
6214 #endif
6215 }
6216
6217 #ifndef PRIu64
6218 #define PRIu64 \"llu\"
6219 #endif
6220
6221 static SV *
6222 my_newSVull(unsigned long long val) {
6223 #ifdef USE_64_BIT_ALL
6224   return newSVuv(val);
6225 #else
6226   char buf[100];
6227   int len;
6228   len = snprintf(buf, 100, \"%%\" PRIu64, val);
6229   return newSVpv(buf, len);
6230 #endif
6231 }
6232
6233 /* http://www.perlmonks.org/?node_id=680842 */
6234 static char **
6235 XS_unpack_charPtrPtr (SV *arg) {
6236   char **ret;
6237   AV *av;
6238   I32 i;
6239
6240   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
6241     croak (\"array reference expected\");
6242
6243   av = (AV *)SvRV (arg);
6244   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
6245   if (!ret)
6246     croak (\"malloc failed\");
6247
6248   for (i = 0; i <= av_len (av); i++) {
6249     SV **elem = av_fetch (av, i, 0);
6250
6251     if (!elem || !*elem)
6252       croak (\"missing element in list\");
6253
6254     ret[i] = SvPV_nolen (*elem);
6255   }
6256
6257   ret[i] = NULL;
6258
6259   return ret;
6260 }
6261
6262 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
6263
6264 PROTOTYPES: ENABLE
6265
6266 guestfs_h *
6267 _create ()
6268    CODE:
6269       RETVAL = guestfs_create ();
6270       if (!RETVAL)
6271         croak (\"could not create guestfs handle\");
6272       guestfs_set_error_handler (RETVAL, NULL, NULL);
6273  OUTPUT:
6274       RETVAL
6275
6276 void
6277 DESTROY (g)
6278       guestfs_h *g;
6279  PPCODE:
6280       guestfs_close (g);
6281
6282 ";
6283
6284   List.iter (
6285     fun (name, style, _, _, _, _, _) ->
6286       (match fst style with
6287        | RErr -> pr "void\n"
6288        | RInt _ -> pr "SV *\n"
6289        | RInt64 _ -> pr "SV *\n"
6290        | RBool _ -> pr "SV *\n"
6291        | RConstString _ -> pr "SV *\n"
6292        | RConstOptString _ -> pr "SV *\n"
6293        | RString _ -> pr "SV *\n"
6294        | RBufferOut _ -> pr "SV *\n"
6295        | RStringList _
6296        | RStruct _ | RStructList _
6297        | RHashtable _ ->
6298            pr "void\n" (* all lists returned implictly on the stack *)
6299       );
6300       (* Call and arguments. *)
6301       pr "%s " name;
6302       generate_c_call_args ~handle:"g" ~decl:true style;
6303       pr "\n";
6304       pr "      guestfs_h *g;\n";
6305       iteri (
6306         fun i ->
6307           function
6308           | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
6309           | OptString n ->
6310               (* http://www.perlmonks.org/?node_id=554277
6311                * Note that the implicit handle argument means we have
6312                * to add 1 to the ST(x) operator.
6313                *)
6314               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
6315           | StringList n -> pr "      char **%s;\n" n
6316           | Bool n -> pr "      int %s;\n" n
6317           | Int n -> pr "      int %s;\n" n
6318       ) (snd style);
6319
6320       let do_cleanups () =
6321         List.iter (
6322           function
6323           | String _ | OptString _ | Bool _ | Int _
6324           | FileIn _ | FileOut _ -> ()
6325           | StringList n -> pr "      free (%s);\n" n
6326         ) (snd style)
6327       in
6328
6329       (* Code. *)
6330       (match fst style with
6331        | RErr ->
6332            pr "PREINIT:\n";
6333            pr "      int r;\n";
6334            pr " PPCODE:\n";
6335            pr "      r = guestfs_%s " name;
6336            generate_c_call_args ~handle:"g" style;
6337            pr ";\n";
6338            do_cleanups ();
6339            pr "      if (r == -1)\n";
6340            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6341        | RInt n
6342        | RBool n ->
6343            pr "PREINIT:\n";
6344            pr "      int %s;\n" n;
6345            pr "   CODE:\n";
6346            pr "      %s = guestfs_%s " n name;
6347            generate_c_call_args ~handle:"g" style;
6348            pr ";\n";
6349            do_cleanups ();
6350            pr "      if (%s == -1)\n" n;
6351            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6352            pr "      RETVAL = newSViv (%s);\n" n;
6353            pr " OUTPUT:\n";
6354            pr "      RETVAL\n"
6355        | RInt64 n ->
6356            pr "PREINIT:\n";
6357            pr "      int64_t %s;\n" n;
6358            pr "   CODE:\n";
6359            pr "      %s = guestfs_%s " n name;
6360            generate_c_call_args ~handle:"g" style;
6361            pr ";\n";
6362            do_cleanups ();
6363            pr "      if (%s == -1)\n" n;
6364            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6365            pr "      RETVAL = my_newSVll (%s);\n" n;
6366            pr " OUTPUT:\n";
6367            pr "      RETVAL\n"
6368        | RConstString n ->
6369            pr "PREINIT:\n";
6370            pr "      const char *%s;\n" n;
6371            pr "   CODE:\n";
6372            pr "      %s = guestfs_%s " n name;
6373            generate_c_call_args ~handle:"g" style;
6374            pr ";\n";
6375            do_cleanups ();
6376            pr "      if (%s == NULL)\n" n;
6377            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6378            pr "      RETVAL = newSVpv (%s, 0);\n" n;
6379            pr " OUTPUT:\n";
6380            pr "      RETVAL\n"
6381        | RConstOptString n ->
6382            pr "PREINIT:\n";
6383            pr "      const char *%s;\n" n;
6384            pr "   CODE:\n";
6385            pr "      %s = guestfs_%s " n name;
6386            generate_c_call_args ~handle:"g" style;
6387            pr ";\n";
6388            do_cleanups ();
6389            pr "      if (%s == NULL)\n" n;
6390            pr "        RETVAL = &PL_sv_undef;\n";
6391            pr "      else\n";
6392            pr "        RETVAL = newSVpv (%s, 0);\n" n;
6393            pr " OUTPUT:\n";
6394            pr "      RETVAL\n"
6395        | RString n ->
6396            pr "PREINIT:\n";
6397            pr "      char *%s;\n" n;
6398            pr "   CODE:\n";
6399            pr "      %s = guestfs_%s " n name;
6400            generate_c_call_args ~handle:"g" style;
6401            pr ";\n";
6402            do_cleanups ();
6403            pr "      if (%s == NULL)\n" n;
6404            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6405            pr "      RETVAL = newSVpv (%s, 0);\n" n;
6406            pr "      free (%s);\n" n;
6407            pr " OUTPUT:\n";
6408            pr "      RETVAL\n"
6409        | RStringList n | RHashtable n ->
6410            pr "PREINIT:\n";
6411            pr "      char **%s;\n" n;
6412            pr "      int i, n;\n";
6413            pr " PPCODE:\n";
6414            pr "      %s = guestfs_%s " n name;
6415            generate_c_call_args ~handle:"g" style;
6416            pr ";\n";
6417            do_cleanups ();
6418            pr "      if (%s == NULL)\n" n;
6419            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6420            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6421            pr "      EXTEND (SP, n);\n";
6422            pr "      for (i = 0; i < n; ++i) {\n";
6423            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6424            pr "        free (%s[i]);\n" n;
6425            pr "      }\n";
6426            pr "      free (%s);\n" n;
6427        | RStruct (n, typ) ->
6428            let cols = cols_of_struct typ in
6429            generate_perl_struct_code typ cols name style n do_cleanups
6430        | RStructList (n, typ) ->
6431            let cols = cols_of_struct typ in
6432            generate_perl_struct_list_code typ cols name style n do_cleanups
6433        | RBufferOut n ->
6434            pr "PREINIT:\n";
6435            pr "      char *%s;\n" n;
6436            pr "      size_t size;\n";
6437            pr "   CODE:\n";
6438            pr "      %s = guestfs_%s " n name;
6439            generate_c_call_args ~handle:"g" style;
6440            pr ";\n";
6441            do_cleanups ();
6442            pr "      if (%s == NULL)\n" n;
6443            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6444            pr "      RETVAL = newSVpv (%s, size);\n" n;
6445            pr "      free (%s);\n" n;
6446            pr " OUTPUT:\n";
6447            pr "      RETVAL\n"
6448       );
6449
6450       pr "\n"
6451   ) all_functions
6452
6453 and generate_perl_struct_list_code typ cols name style n do_cleanups =
6454   pr "PREINIT:\n";
6455   pr "      struct guestfs_%s_list *%s;\n" typ n;
6456   pr "      int i;\n";
6457   pr "      HV *hv;\n";
6458   pr " PPCODE:\n";
6459   pr "      %s = guestfs_%s " n name;
6460   generate_c_call_args ~handle:"g" style;
6461   pr ";\n";
6462   do_cleanups ();
6463   pr "      if (%s == NULL)\n" n;
6464   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6465   pr "      EXTEND (SP, %s->len);\n" n;
6466   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
6467   pr "        hv = newHV ();\n";
6468   List.iter (
6469     function
6470     | name, FString ->
6471         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6472           name (String.length name) n name
6473     | name, FUUID ->
6474         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
6475           name (String.length name) n name
6476     | name, FBuffer ->
6477         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
6478           name (String.length name) n name n name
6479     | name, (FBytes|FUInt64) ->
6480         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6481           name (String.length name) n name
6482     | name, FInt64 ->
6483         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
6484           name (String.length name) n name
6485     | name, (FInt32|FUInt32) ->
6486         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6487           name (String.length name) n name
6488     | name, FChar ->
6489         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
6490           name (String.length name) n name
6491     | name, FOptPercent ->
6492         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6493           name (String.length name) n name
6494   ) cols;
6495   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
6496   pr "      }\n";
6497   pr "      guestfs_free_%s_list (%s);\n" typ n
6498
6499 and generate_perl_struct_code typ cols name style n do_cleanups =
6500   pr "PREINIT:\n";
6501   pr "      struct guestfs_%s *%s;\n" typ n;
6502   pr " PPCODE:\n";
6503   pr "      %s = guestfs_%s " n name;
6504   generate_c_call_args ~handle:"g" style;
6505   pr ";\n";
6506   do_cleanups ();
6507   pr "      if (%s == NULL)\n" n;
6508   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6509   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
6510   List.iter (
6511     fun ((name, _) as col) ->
6512       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
6513
6514       match col with
6515       | name, FString ->
6516           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
6517             n name
6518       | name, FBuffer ->
6519           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
6520             n name n name
6521       | name, FUUID ->
6522           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
6523             n name
6524       | name, (FBytes|FUInt64) ->
6525           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
6526             n name
6527       | name, FInt64 ->
6528           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
6529             n name
6530       | name, (FInt32|FUInt32) ->
6531           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
6532             n name
6533       | name, FChar ->
6534           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
6535             n name
6536       | name, FOptPercent ->
6537           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
6538             n name
6539   ) cols;
6540   pr "      free (%s);\n" n
6541
6542 (* Generate Sys/Guestfs.pm. *)
6543 and generate_perl_pm () =
6544   generate_header HashStyle LGPLv2;
6545
6546   pr "\
6547 =pod
6548
6549 =head1 NAME
6550
6551 Sys::Guestfs - Perl bindings for libguestfs
6552
6553 =head1 SYNOPSIS
6554
6555  use Sys::Guestfs;
6556
6557  my $h = Sys::Guestfs->new ();
6558  $h->add_drive ('guest.img');
6559  $h->launch ();
6560  $h->wait_ready ();
6561  $h->mount ('/dev/sda1', '/');
6562  $h->touch ('/hello');
6563  $h->sync ();
6564
6565 =head1 DESCRIPTION
6566
6567 The C<Sys::Guestfs> module provides a Perl XS binding to the
6568 libguestfs API for examining and modifying virtual machine
6569 disk images.
6570
6571 Amongst the things this is good for: making batch configuration
6572 changes to guests, getting disk used/free statistics (see also:
6573 virt-df), migrating between virtualization systems (see also:
6574 virt-p2v), performing partial backups, performing partial guest
6575 clones, cloning guests and changing registry/UUID/hostname info, and
6576 much else besides.
6577
6578 Libguestfs uses Linux kernel and qemu code, and can access any type of
6579 guest filesystem that Linux and qemu can, including but not limited
6580 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6581 schemes, qcow, qcow2, vmdk.
6582
6583 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6584 LVs, what filesystem is in each LV, etc.).  It can also run commands
6585 in the context of the guest.  Also you can access filesystems over FTP.
6586
6587 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
6588 functions for using libguestfs from Perl, including integration
6589 with libvirt.
6590
6591 =head1 ERRORS
6592
6593 All errors turn into calls to C<croak> (see L<Carp(3)>).
6594
6595 =head1 METHODS
6596
6597 =over 4
6598
6599 =cut
6600
6601 package Sys::Guestfs;
6602
6603 use strict;
6604 use warnings;
6605
6606 require XSLoader;
6607 XSLoader::load ('Sys::Guestfs');
6608
6609 =item $h = Sys::Guestfs->new ();
6610
6611 Create a new guestfs handle.
6612
6613 =cut
6614
6615 sub new {
6616   my $proto = shift;
6617   my $class = ref ($proto) || $proto;
6618
6619   my $self = Sys::Guestfs::_create ();
6620   bless $self, $class;
6621   return $self;
6622 }
6623
6624 ";
6625
6626   (* Actions.  We only need to print documentation for these as
6627    * they are pulled in from the XS code automatically.
6628    *)
6629   List.iter (
6630     fun (name, style, _, flags, _, _, longdesc) ->
6631       if not (List.mem NotInDocs flags) then (
6632         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
6633         pr "=item ";
6634         generate_perl_prototype name style;
6635         pr "\n\n";
6636         pr "%s\n\n" longdesc;
6637         if List.mem ProtocolLimitWarning flags then
6638           pr "%s\n\n" protocol_limit_warning;
6639         if List.mem DangerWillRobinson flags then
6640           pr "%s\n\n" danger_will_robinson
6641       )
6642   ) all_functions_sorted;
6643
6644   (* End of file. *)
6645   pr "\
6646 =cut
6647
6648 1;
6649
6650 =back
6651
6652 =head1 COPYRIGHT
6653
6654 Copyright (C) 2009 Red Hat Inc.
6655
6656 =head1 LICENSE
6657
6658 Please see the file COPYING.LIB for the full license.
6659
6660 =head1 SEE ALSO
6661
6662 L<guestfs(3)>,
6663 L<guestfish(1)>,
6664 L<http://libguestfs.org>,
6665 L<Sys::Guestfs::Lib(3)>.
6666
6667 =cut
6668 "
6669
6670 and generate_perl_prototype name style =
6671   (match fst style with
6672    | RErr -> ()
6673    | RBool n
6674    | RInt n
6675    | RInt64 n
6676    | RConstString n
6677    | RConstOptString n
6678    | RString n
6679    | RBufferOut n -> pr "$%s = " n
6680    | RStruct (n,_)
6681    | RHashtable n -> pr "%%%s = " n
6682    | RStringList n
6683    | RStructList (n,_) -> pr "@%s = " n
6684   );
6685   pr "$h->%s (" name;
6686   let comma = ref false in
6687   List.iter (
6688     fun arg ->
6689       if !comma then pr ", ";
6690       comma := true;
6691       match arg with
6692       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
6693           pr "$%s" n
6694       | StringList n ->
6695           pr "\\@%s" n
6696   ) (snd style);
6697   pr ");"
6698
6699 (* Generate Python C module. *)
6700 and generate_python_c () =
6701   generate_header CStyle LGPLv2;
6702
6703   pr "\
6704 #include <stdio.h>
6705 #include <stdlib.h>
6706 #include <assert.h>
6707
6708 #include <Python.h>
6709
6710 #include \"guestfs.h\"
6711
6712 typedef struct {
6713   PyObject_HEAD
6714   guestfs_h *g;
6715 } Pyguestfs_Object;
6716
6717 static guestfs_h *
6718 get_handle (PyObject *obj)
6719 {
6720   assert (obj);
6721   assert (obj != Py_None);
6722   return ((Pyguestfs_Object *) obj)->g;
6723 }
6724
6725 static PyObject *
6726 put_handle (guestfs_h *g)
6727 {
6728   assert (g);
6729   return
6730     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6731 }
6732
6733 /* This list should be freed (but not the strings) after use. */
6734 static const char **
6735 get_string_list (PyObject *obj)
6736 {
6737   int i, len;
6738   const char **r;
6739
6740   assert (obj);
6741
6742   if (!PyList_Check (obj)) {
6743     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6744     return NULL;
6745   }
6746
6747   len = PyList_Size (obj);
6748   r = malloc (sizeof (char *) * (len+1));
6749   if (r == NULL) {
6750     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6751     return NULL;
6752   }
6753
6754   for (i = 0; i < len; ++i)
6755     r[i] = PyString_AsString (PyList_GetItem (obj, i));
6756   r[len] = NULL;
6757
6758   return r;
6759 }
6760
6761 static PyObject *
6762 put_string_list (char * const * const argv)
6763 {
6764   PyObject *list;
6765   int argc, i;
6766
6767   for (argc = 0; argv[argc] != NULL; ++argc)
6768     ;
6769
6770   list = PyList_New (argc);
6771   for (i = 0; i < argc; ++i)
6772     PyList_SetItem (list, i, PyString_FromString (argv[i]));
6773
6774   return list;
6775 }
6776
6777 static PyObject *
6778 put_table (char * const * const argv)
6779 {
6780   PyObject *list, *item;
6781   int argc, i;
6782
6783   for (argc = 0; argv[argc] != NULL; ++argc)
6784     ;
6785
6786   list = PyList_New (argc >> 1);
6787   for (i = 0; i < argc; i += 2) {
6788     item = PyTuple_New (2);
6789     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
6790     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
6791     PyList_SetItem (list, i >> 1, item);
6792   }
6793
6794   return list;
6795 }
6796
6797 static void
6798 free_strings (char **argv)
6799 {
6800   int argc;
6801
6802   for (argc = 0; argv[argc] != NULL; ++argc)
6803     free (argv[argc]);
6804   free (argv);
6805 }
6806
6807 static PyObject *
6808 py_guestfs_create (PyObject *self, PyObject *args)
6809 {
6810   guestfs_h *g;
6811
6812   g = guestfs_create ();
6813   if (g == NULL) {
6814     PyErr_SetString (PyExc_RuntimeError,
6815                      \"guestfs.create: failed to allocate handle\");
6816     return NULL;
6817   }
6818   guestfs_set_error_handler (g, NULL, NULL);
6819   return put_handle (g);
6820 }
6821
6822 static PyObject *
6823 py_guestfs_close (PyObject *self, PyObject *args)
6824 {
6825   PyObject *py_g;
6826   guestfs_h *g;
6827
6828   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
6829     return NULL;
6830   g = get_handle (py_g);
6831
6832   guestfs_close (g);
6833
6834   Py_INCREF (Py_None);
6835   return Py_None;
6836 }
6837
6838 ";
6839
6840   (* Structures, turned into Python dictionaries. *)
6841   List.iter (
6842     fun (typ, cols) ->
6843       pr "static PyObject *\n";
6844       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
6845       pr "{\n";
6846       pr "  PyObject *dict;\n";
6847       pr "\n";
6848       pr "  dict = PyDict_New ();\n";
6849       List.iter (
6850         function
6851         | name, FString ->
6852             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6853             pr "                        PyString_FromString (%s->%s));\n"
6854               typ name
6855         | name, FBuffer ->
6856             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6857             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
6858               typ name typ name
6859         | name, FUUID ->
6860             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6861             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
6862               typ name
6863         | name, (FBytes|FUInt64) ->
6864             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6865             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
6866               typ name
6867         | name, FInt64 ->
6868             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6869             pr "                        PyLong_FromLongLong (%s->%s));\n"
6870               typ name
6871         | name, FUInt32 ->
6872             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6873             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
6874               typ name
6875         | name, FInt32 ->
6876             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6877             pr "                        PyLong_FromLong (%s->%s));\n"
6878               typ name
6879         | name, FOptPercent ->
6880             pr "  if (%s->%s >= 0)\n" typ name;
6881             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
6882             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
6883               typ name;
6884             pr "  else {\n";
6885             pr "    Py_INCREF (Py_None);\n";
6886             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
6887             pr "  }\n"
6888         | name, FChar ->
6889             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
6890             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
6891       ) cols;
6892       pr "  return dict;\n";
6893       pr "};\n";
6894       pr "\n";
6895
6896       pr "static PyObject *\n";
6897       pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
6898       pr "{\n";
6899       pr "  PyObject *list;\n";
6900       pr "  int i;\n";
6901       pr "\n";
6902       pr "  list = PyList_New (%ss->len);\n" typ;
6903       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
6904       pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
6905       pr "  return list;\n";
6906       pr "};\n";
6907       pr "\n"
6908   ) structs;
6909
6910   (* Python wrapper functions. *)
6911   List.iter (
6912     fun (name, style, _, _, _, _, _) ->
6913       pr "static PyObject *\n";
6914       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
6915       pr "{\n";
6916
6917       pr "  PyObject *py_g;\n";
6918       pr "  guestfs_h *g;\n";
6919       pr "  PyObject *py_r;\n";
6920
6921       let error_code =
6922         match fst style with
6923         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
6924         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6925         | RConstString _ | RConstOptString _ ->
6926             pr "  const char *r;\n"; "NULL"
6927         | RString _ -> pr "  char *r;\n"; "NULL"
6928         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6929         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
6930         | RStructList (_, typ) ->
6931             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
6932         | RBufferOut _ ->
6933             pr "  char *r;\n";
6934             pr "  size_t size;\n";
6935             "NULL" in
6936
6937       List.iter (
6938         function
6939         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
6940         | OptString n -> pr "  const char *%s;\n" n
6941         | StringList n ->
6942             pr "  PyObject *py_%s;\n" n;
6943             pr "  const char **%s;\n" n
6944         | Bool n -> pr "  int %s;\n" n
6945         | Int n -> pr "  int %s;\n" n
6946       ) (snd style);
6947
6948       pr "\n";
6949
6950       (* Convert the parameters. *)
6951       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
6952       List.iter (
6953         function
6954         | String _ | FileIn _ | FileOut _ -> pr "s"
6955         | OptString _ -> pr "z"
6956         | StringList _ -> pr "O"
6957         | Bool _ -> pr "i" (* XXX Python has booleans? *)
6958         | Int _ -> pr "i"
6959       ) (snd style);
6960       pr ":guestfs_%s\",\n" name;
6961       pr "                         &py_g";
6962       List.iter (
6963         function
6964         | String n | FileIn n | FileOut n -> pr ", &%s" n
6965         | OptString n -> pr ", &%s" n
6966         | StringList n -> pr ", &py_%s" n
6967         | Bool n -> pr ", &%s" n
6968         | Int n -> pr ", &%s" n
6969       ) (snd style);
6970
6971       pr "))\n";
6972       pr "    return NULL;\n";
6973
6974       pr "  g = get_handle (py_g);\n";
6975       List.iter (
6976         function
6977         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6978         | StringList n ->
6979             pr "  %s = get_string_list (py_%s);\n" n n;
6980             pr "  if (!%s) return NULL;\n" n
6981       ) (snd style);
6982
6983       pr "\n";
6984
6985       pr "  r = guestfs_%s " name;
6986       generate_c_call_args ~handle:"g" style;
6987       pr ";\n";
6988
6989       List.iter (
6990         function
6991         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
6992         | StringList n ->
6993             pr "  free (%s);\n" n
6994       ) (snd style);
6995
6996       pr "  if (r == %s) {\n" error_code;
6997       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
6998       pr "    return NULL;\n";
6999       pr "  }\n";
7000       pr "\n";
7001
7002       (match fst style with
7003        | RErr ->
7004            pr "  Py_INCREF (Py_None);\n";
7005            pr "  py_r = Py_None;\n"
7006        | RInt _
7007        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
7008        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
7009        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
7010        | RConstOptString _ ->
7011            pr "  if (r)\n";
7012            pr "    py_r = PyString_FromString (r);\n";
7013            pr "  else {\n";
7014            pr "    Py_INCREF (Py_None);\n";
7015            pr "    py_r = Py_None;\n";
7016            pr "  }\n"
7017        | RString _ ->
7018            pr "  py_r = PyString_FromString (r);\n";
7019            pr "  free (r);\n"
7020        | RStringList _ ->
7021            pr "  py_r = put_string_list (r);\n";
7022            pr "  free_strings (r);\n"
7023        | RStruct (_, typ) ->
7024            pr "  py_r = put_%s (r);\n" typ;
7025            pr "  guestfs_free_%s (r);\n" typ
7026        | RStructList (_, typ) ->
7027            pr "  py_r = put_%s_list (r);\n" typ;
7028            pr "  guestfs_free_%s_list (r);\n" typ
7029        | RHashtable n ->
7030            pr "  py_r = put_table (r);\n";
7031            pr "  free_strings (r);\n"
7032        | RBufferOut _ ->
7033            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
7034            pr "  free (r);\n"
7035       );
7036
7037       pr "  return py_r;\n";
7038       pr "}\n";
7039       pr "\n"
7040   ) all_functions;
7041
7042   (* Table of functions. *)
7043   pr "static PyMethodDef methods[] = {\n";
7044   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
7045   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
7046   List.iter (
7047     fun (name, _, _, _, _, _, _) ->
7048       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
7049         name name
7050   ) all_functions;
7051   pr "  { NULL, NULL, 0, NULL }\n";
7052   pr "};\n";
7053   pr "\n";
7054
7055   (* Init function. *)
7056   pr "\
7057 void
7058 initlibguestfsmod (void)
7059 {
7060   static int initialized = 0;
7061
7062   if (initialized) return;
7063   Py_InitModule ((char *) \"libguestfsmod\", methods);
7064   initialized = 1;
7065 }
7066 "
7067
7068 (* Generate Python module. *)
7069 and generate_python_py () =
7070   generate_header HashStyle LGPLv2;
7071
7072   pr "\
7073 u\"\"\"Python bindings for libguestfs
7074
7075 import guestfs
7076 g = guestfs.GuestFS ()
7077 g.add_drive (\"guest.img\")
7078 g.launch ()
7079 g.wait_ready ()
7080 parts = g.list_partitions ()
7081
7082 The guestfs module provides a Python binding to the libguestfs API
7083 for examining and modifying virtual machine disk images.
7084
7085 Amongst the things this is good for: making batch configuration
7086 changes to guests, getting disk used/free statistics (see also:
7087 virt-df), migrating between virtualization systems (see also:
7088 virt-p2v), performing partial backups, performing partial guest
7089 clones, cloning guests and changing registry/UUID/hostname info, and
7090 much else besides.
7091
7092 Libguestfs uses Linux kernel and qemu code, and can access any type of
7093 guest filesystem that Linux and qemu can, including but not limited
7094 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7095 schemes, qcow, qcow2, vmdk.
7096
7097 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7098 LVs, what filesystem is in each LV, etc.).  It can also run commands
7099 in the context of the guest.  Also you can access filesystems over FTP.
7100
7101 Errors which happen while using the API are turned into Python
7102 RuntimeError exceptions.
7103
7104 To create a guestfs handle you usually have to perform the following
7105 sequence of calls:
7106
7107 # Create the handle, call add_drive at least once, and possibly
7108 # several times if the guest has multiple block devices:
7109 g = guestfs.GuestFS ()
7110 g.add_drive (\"guest.img\")
7111
7112 # Launch the qemu subprocess and wait for it to become ready:
7113 g.launch ()
7114 g.wait_ready ()
7115
7116 # Now you can issue commands, for example:
7117 logvols = g.lvs ()
7118
7119 \"\"\"
7120
7121 import libguestfsmod
7122
7123 class GuestFS:
7124     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
7125
7126     def __init__ (self):
7127         \"\"\"Create a new libguestfs handle.\"\"\"
7128         self._o = libguestfsmod.create ()
7129
7130     def __del__ (self):
7131         libguestfsmod.close (self._o)
7132
7133 ";
7134
7135   List.iter (
7136     fun (name, style, _, flags, _, _, longdesc) ->
7137       pr "    def %s " name;
7138       generate_py_call_args ~handle:"self" (snd style);
7139       pr ":\n";
7140
7141       if not (List.mem NotInDocs flags) then (
7142         let doc = replace_str longdesc "C<guestfs_" "C<g." in
7143         let doc =
7144           match fst style with
7145           | RErr | RInt _ | RInt64 _ | RBool _
7146           | RConstOptString _ | RConstString _
7147           | RString _ | RBufferOut _ -> doc
7148           | RStringList _ ->
7149               doc ^ "\n\nThis function returns a list of strings."
7150           | RStruct (_, typ) ->
7151               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
7152           | RStructList (_, typ) ->
7153               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
7154           | RHashtable _ ->
7155               doc ^ "\n\nThis function returns a dictionary." in
7156         let doc =
7157           if List.mem ProtocolLimitWarning flags then
7158             doc ^ "\n\n" ^ protocol_limit_warning
7159           else doc in
7160         let doc =
7161           if List.mem DangerWillRobinson flags then
7162             doc ^ "\n\n" ^ danger_will_robinson
7163           else doc in
7164         let doc = pod2text ~width:60 name doc in
7165         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
7166         let doc = String.concat "\n        " doc in
7167         pr "        u\"\"\"%s\"\"\"\n" doc;
7168       );
7169       pr "        return libguestfsmod.%s " name;
7170       generate_py_call_args ~handle:"self._o" (snd style);
7171       pr "\n";
7172       pr "\n";
7173   ) all_functions
7174
7175 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
7176 and generate_py_call_args ~handle args =
7177   pr "(%s" handle;
7178   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
7179   pr ")"
7180
7181 (* Useful if you need the longdesc POD text as plain text.  Returns a
7182  * list of lines.
7183  *
7184  * Because this is very slow (the slowest part of autogeneration),
7185  * we memoize the results.
7186  *)
7187 and pod2text ~width name longdesc =
7188   let key = width, name, longdesc in
7189   try Hashtbl.find pod2text_memo key
7190   with Not_found ->
7191     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
7192     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
7193     close_out chan;
7194     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
7195     let chan = Unix.open_process_in cmd in
7196     let lines = ref [] in
7197     let rec loop i =
7198       let line = input_line chan in
7199       if i = 1 then             (* discard the first line of output *)
7200         loop (i+1)
7201       else (
7202         let line = triml line in
7203         lines := line :: !lines;
7204         loop (i+1)
7205       ) in
7206     let lines = try loop 1 with End_of_file -> List.rev !lines in
7207     Unix.unlink filename;
7208     (match Unix.close_process_in chan with
7209      | Unix.WEXITED 0 -> ()
7210      | Unix.WEXITED i ->
7211          failwithf "pod2text: process exited with non-zero status (%d)" i
7212      | Unix.WSIGNALED i | Unix.WSTOPPED i ->
7213          failwithf "pod2text: process signalled or stopped by signal %d" i
7214     );
7215     Hashtbl.add pod2text_memo key lines;
7216     let chan = open_out pod2text_memo_filename in
7217     output_value chan pod2text_memo;
7218     close_out chan;
7219     lines
7220
7221 (* Generate ruby bindings. *)
7222 and generate_ruby_c () =
7223   generate_header CStyle LGPLv2;
7224
7225   pr "\
7226 #include <stdio.h>
7227 #include <stdlib.h>
7228
7229 #include <ruby.h>
7230
7231 #include \"guestfs.h\"
7232
7233 #include \"extconf.h\"
7234
7235 /* For Ruby < 1.9 */
7236 #ifndef RARRAY_LEN
7237 #define RARRAY_LEN(r) (RARRAY((r))->len)
7238 #endif
7239
7240 static VALUE m_guestfs;                 /* guestfs module */
7241 static VALUE c_guestfs;                 /* guestfs_h handle */
7242 static VALUE e_Error;                   /* used for all errors */
7243
7244 static void ruby_guestfs_free (void *p)
7245 {
7246   if (!p) return;
7247   guestfs_close ((guestfs_h *) p);
7248 }
7249
7250 static VALUE ruby_guestfs_create (VALUE m)
7251 {
7252   guestfs_h *g;
7253
7254   g = guestfs_create ();
7255   if (!g)
7256     rb_raise (e_Error, \"failed to create guestfs handle\");
7257
7258   /* Don't print error messages to stderr by default. */
7259   guestfs_set_error_handler (g, NULL, NULL);
7260
7261   /* Wrap it, and make sure the close function is called when the
7262    * handle goes away.
7263    */
7264   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
7265 }
7266
7267 static VALUE ruby_guestfs_close (VALUE gv)
7268 {
7269   guestfs_h *g;
7270   Data_Get_Struct (gv, guestfs_h, g);
7271
7272   ruby_guestfs_free (g);
7273   DATA_PTR (gv) = NULL;
7274
7275   return Qnil;
7276 }
7277
7278 ";
7279
7280   List.iter (
7281     fun (name, style, _, _, _, _, _) ->
7282       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
7283       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
7284       pr ")\n";
7285       pr "{\n";
7286       pr "  guestfs_h *g;\n";
7287       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
7288       pr "  if (!g)\n";
7289       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
7290         name;
7291       pr "\n";
7292
7293       List.iter (
7294         function
7295         | String n | FileIn n | FileOut n ->
7296             pr "  Check_Type (%sv, T_STRING);\n" n;
7297             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
7298             pr "  if (!%s)\n" n;
7299             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
7300             pr "              \"%s\", \"%s\");\n" n name
7301         | OptString n ->
7302             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
7303         | StringList n ->
7304             pr "  char **%s;\n" n;
7305             pr "  Check_Type (%sv, T_ARRAY);\n" n;
7306             pr "  {\n";
7307             pr "    int i, len;\n";
7308             pr "    len = RARRAY_LEN (%sv);\n" n;
7309             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
7310               n;
7311             pr "    for (i = 0; i < len; ++i) {\n";
7312             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
7313             pr "      %s[i] = StringValueCStr (v);\n" n;
7314             pr "    }\n";
7315             pr "    %s[len] = NULL;\n" n;
7316             pr "  }\n";
7317         | Bool n ->
7318             pr "  int %s = RTEST (%sv);\n" n n
7319         | Int n ->
7320             pr "  int %s = NUM2INT (%sv);\n" n n
7321       ) (snd style);
7322       pr "\n";
7323
7324       let error_code =
7325         match fst style with
7326         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
7327         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7328         | RConstString _ | RConstOptString _ ->
7329             pr "  const char *r;\n"; "NULL"
7330         | RString _ -> pr "  char *r;\n"; "NULL"
7331         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
7332         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
7333         | RStructList (_, typ) ->
7334             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7335         | RBufferOut _ ->
7336             pr "  char *r;\n";
7337             pr "  size_t size;\n";
7338             "NULL" in
7339       pr "\n";
7340
7341       pr "  r = guestfs_%s " name;
7342       generate_c_call_args ~handle:"g" style;
7343       pr ";\n";
7344
7345       List.iter (
7346         function
7347         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7348         | StringList n ->
7349             pr "  free (%s);\n" n
7350       ) (snd style);
7351
7352       pr "  if (r == %s)\n" error_code;
7353       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
7354       pr "\n";
7355
7356       (match fst style with
7357        | RErr ->
7358            pr "  return Qnil;\n"
7359        | RInt _ | RBool _ ->
7360            pr "  return INT2NUM (r);\n"
7361        | RInt64 _ ->
7362            pr "  return ULL2NUM (r);\n"
7363        | RConstString _ ->
7364            pr "  return rb_str_new2 (r);\n";
7365        | RConstOptString _ ->
7366            pr "  if (r)\n";
7367            pr "    return rb_str_new2 (r);\n";
7368            pr "  else\n";
7369            pr "    return Qnil;\n";
7370        | RString _ ->
7371            pr "  VALUE rv = rb_str_new2 (r);\n";
7372            pr "  free (r);\n";
7373            pr "  return rv;\n";
7374        | RStringList _ ->
7375            pr "  int i, len = 0;\n";
7376            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
7377            pr "  VALUE rv = rb_ary_new2 (len);\n";
7378            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
7379            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
7380            pr "    free (r[i]);\n";
7381            pr "  }\n";
7382            pr "  free (r);\n";
7383            pr "  return rv;\n"
7384        | RStruct (_, typ) ->
7385            let cols = cols_of_struct typ in
7386            generate_ruby_struct_code typ cols
7387        | RStructList (_, typ) ->
7388            let cols = cols_of_struct typ in
7389            generate_ruby_struct_list_code typ cols
7390        | RHashtable _ ->
7391            pr "  VALUE rv = rb_hash_new ();\n";
7392            pr "  int i;\n";
7393            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
7394            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
7395            pr "    free (r[i]);\n";
7396            pr "    free (r[i+1]);\n";
7397            pr "  }\n";
7398            pr "  free (r);\n";
7399            pr "  return rv;\n"
7400        | RBufferOut _ ->
7401            pr "  VALUE rv = rb_str_new (r, size);\n";
7402            pr "  free (r);\n";
7403            pr "  return rv;\n";
7404       );
7405
7406       pr "}\n";
7407       pr "\n"
7408   ) all_functions;
7409
7410   pr "\
7411 /* Initialize the module. */
7412 void Init__guestfs ()
7413 {
7414   m_guestfs = rb_define_module (\"Guestfs\");
7415   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
7416   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
7417
7418   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
7419   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
7420
7421 ";
7422   (* Define the rest of the methods. *)
7423   List.iter (
7424     fun (name, style, _, _, _, _, _) ->
7425       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
7426       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
7427   ) all_functions;
7428
7429   pr "}\n"
7430
7431 (* Ruby code to return a struct. *)
7432 and generate_ruby_struct_code typ cols =
7433   pr "  VALUE rv = rb_hash_new ();\n";
7434   List.iter (
7435     function
7436     | name, FString ->
7437         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
7438     | name, FBuffer ->
7439         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
7440     | name, FUUID ->
7441         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
7442     | name, (FBytes|FUInt64) ->
7443         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7444     | name, FInt64 ->
7445         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
7446     | name, FUInt32 ->
7447         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
7448     | name, FInt32 ->
7449         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
7450     | name, FOptPercent ->
7451         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
7452     | name, FChar -> (* XXX wrong? *)
7453         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7454   ) cols;
7455   pr "  guestfs_free_%s (r);\n" typ;
7456   pr "  return rv;\n"
7457
7458 (* Ruby code to return a struct list. *)
7459 and generate_ruby_struct_list_code typ cols =
7460   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
7461   pr "  int i;\n";
7462   pr "  for (i = 0; i < r->len; ++i) {\n";
7463   pr "    VALUE hv = rb_hash_new ();\n";
7464   List.iter (
7465     function
7466     | name, FString ->
7467         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7468     | name, FBuffer ->
7469         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, r->val[i].%s_len));\n" name name name
7470     | name, FUUID ->
7471         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
7472     | name, (FBytes|FUInt64) ->
7473         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7474     | name, FInt64 ->
7475         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
7476     | name, FUInt32 ->
7477         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
7478     | name, FInt32 ->
7479         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
7480     | name, FOptPercent ->
7481         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
7482     | name, FChar -> (* XXX wrong? *)
7483         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7484   ) cols;
7485   pr "    rb_ary_push (rv, hv);\n";
7486   pr "  }\n";
7487   pr "  guestfs_free_%s_list (r);\n" typ;
7488   pr "  return rv;\n"
7489
7490 (* Generate Java bindings GuestFS.java file. *)
7491 and generate_java_java () =
7492   generate_header CStyle LGPLv2;
7493
7494   pr "\
7495 package com.redhat.et.libguestfs;
7496
7497 import java.util.HashMap;
7498 import com.redhat.et.libguestfs.LibGuestFSException;
7499 import com.redhat.et.libguestfs.PV;
7500 import com.redhat.et.libguestfs.VG;
7501 import com.redhat.et.libguestfs.LV;
7502 import com.redhat.et.libguestfs.Stat;
7503 import com.redhat.et.libguestfs.StatVFS;
7504 import com.redhat.et.libguestfs.IntBool;
7505 import com.redhat.et.libguestfs.Dirent;
7506
7507 /**
7508  * The GuestFS object is a libguestfs handle.
7509  *
7510  * @author rjones
7511  */
7512 public class GuestFS {
7513   // Load the native code.
7514   static {
7515     System.loadLibrary (\"guestfs_jni\");
7516   }
7517
7518   /**
7519    * The native guestfs_h pointer.
7520    */
7521   long g;
7522
7523   /**
7524    * Create a libguestfs handle.
7525    *
7526    * @throws LibGuestFSException
7527    */
7528   public GuestFS () throws LibGuestFSException
7529   {
7530     g = _create ();
7531   }
7532   private native long _create () throws LibGuestFSException;
7533
7534   /**
7535    * Close a libguestfs handle.
7536    *
7537    * You can also leave handles to be collected by the garbage
7538    * collector, but this method ensures that the resources used
7539    * by the handle are freed up immediately.  If you call any
7540    * other methods after closing the handle, you will get an
7541    * exception.
7542    *
7543    * @throws LibGuestFSException
7544    */
7545   public void close () throws LibGuestFSException
7546   {
7547     if (g != 0)
7548       _close (g);
7549     g = 0;
7550   }
7551   private native void _close (long g) throws LibGuestFSException;
7552
7553   public void finalize () throws LibGuestFSException
7554   {
7555     close ();
7556   }
7557
7558 ";
7559
7560   List.iter (
7561     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7562       if not (List.mem NotInDocs flags); then (
7563         let doc = replace_str longdesc "C<guestfs_" "C<g." in
7564         let doc =
7565           if List.mem ProtocolLimitWarning flags then
7566             doc ^ "\n\n" ^ protocol_limit_warning
7567           else doc in
7568         let doc =
7569           if List.mem DangerWillRobinson flags then
7570             doc ^ "\n\n" ^ danger_will_robinson
7571           else doc in
7572         let doc = pod2text ~width:60 name doc in
7573         let doc = List.map (            (* RHBZ#501883 *)
7574           function
7575           | "" -> "<p>"
7576           | nonempty -> nonempty
7577         ) doc in
7578         let doc = String.concat "\n   * " doc in
7579
7580         pr "  /**\n";
7581         pr "   * %s\n" shortdesc;
7582         pr "   * <p>\n";
7583         pr "   * %s\n" doc;
7584         pr "   * @throws LibGuestFSException\n";
7585         pr "   */\n";
7586         pr "  ";
7587       );
7588       generate_java_prototype ~public:true ~semicolon:false name style;
7589       pr "\n";
7590       pr "  {\n";
7591       pr "    if (g == 0)\n";
7592       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
7593         name;
7594       pr "    ";
7595       if fst style <> RErr then pr "return ";
7596       pr "_%s " name;
7597       generate_java_call_args ~handle:"g" (snd style);
7598       pr ";\n";
7599       pr "  }\n";
7600       pr "  ";
7601       generate_java_prototype ~privat:true ~native:true name style;
7602       pr "\n";
7603       pr "\n";
7604   ) all_functions;
7605
7606   pr "}\n"
7607
7608 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
7609 and generate_java_call_args ~handle args =
7610   pr "(%s" handle;
7611   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
7612   pr ")"
7613
7614 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
7615     ?(semicolon=true) name style =
7616   if privat then pr "private ";
7617   if public then pr "public ";
7618   if native then pr "native ";
7619
7620   (* return type *)
7621   (match fst style with
7622    | RErr -> pr "void ";
7623    | RInt _ -> pr "int ";
7624    | RInt64 _ -> pr "long ";
7625    | RBool _ -> pr "boolean ";
7626    | RConstString _ | RConstOptString _ | RString _
7627    | RBufferOut _ -> pr "String ";
7628    | RStringList _ -> pr "String[] ";
7629    | RStruct (_, typ) ->
7630        let name = java_name_of_struct typ in
7631        pr "%s " name;
7632    | RStructList (_, typ) ->
7633        let name = java_name_of_struct typ in
7634        pr "%s[] " name;
7635    | RHashtable _ -> pr "HashMap<String,String> ";
7636   );
7637
7638   if native then pr "_%s " name else pr "%s " name;
7639   pr "(";
7640   let needs_comma = ref false in
7641   if native then (
7642     pr "long g";
7643     needs_comma := true
7644   );
7645
7646   (* args *)
7647   List.iter (
7648     fun arg ->
7649       if !needs_comma then pr ", ";
7650       needs_comma := true;
7651
7652       match arg with
7653       | String n
7654       | OptString n
7655       | FileIn n
7656       | FileOut n ->
7657           pr "String %s" n
7658       | StringList n ->
7659           pr "String[] %s" n
7660       | Bool n ->
7661           pr "boolean %s" n
7662       | Int n ->
7663           pr "int %s" n
7664   ) (snd style);
7665
7666   pr ")\n";
7667   pr "    throws LibGuestFSException";
7668   if semicolon then pr ";"
7669
7670 and generate_java_struct jtyp cols =
7671   generate_header CStyle LGPLv2;
7672
7673   pr "\
7674 package com.redhat.et.libguestfs;
7675
7676 /**
7677  * Libguestfs %s structure.
7678  *
7679  * @author rjones
7680  * @see GuestFS
7681  */
7682 public class %s {
7683 " jtyp jtyp;
7684
7685   List.iter (
7686     function
7687     | name, FString
7688     | name, FUUID
7689     | name, FBuffer -> pr "  public String %s;\n" name
7690     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
7691     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
7692     | name, FChar -> pr "  public char %s;\n" name
7693     | name, FOptPercent ->
7694         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
7695         pr "  public float %s;\n" name
7696   ) cols;
7697
7698   pr "}\n"
7699
7700 and generate_java_c () =
7701   generate_header CStyle LGPLv2;
7702
7703   pr "\
7704 #include <stdio.h>
7705 #include <stdlib.h>
7706 #include <string.h>
7707
7708 #include \"com_redhat_et_libguestfs_GuestFS.h\"
7709 #include \"guestfs.h\"
7710
7711 /* Note that this function returns.  The exception is not thrown
7712  * until after the wrapper function returns.
7713  */
7714 static void
7715 throw_exception (JNIEnv *env, const char *msg)
7716 {
7717   jclass cl;
7718   cl = (*env)->FindClass (env,
7719                           \"com/redhat/et/libguestfs/LibGuestFSException\");
7720   (*env)->ThrowNew (env, cl, msg);
7721 }
7722
7723 JNIEXPORT jlong JNICALL
7724 Java_com_redhat_et_libguestfs_GuestFS__1create
7725   (JNIEnv *env, jobject obj)
7726 {
7727   guestfs_h *g;
7728
7729   g = guestfs_create ();
7730   if (g == NULL) {
7731     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
7732     return 0;
7733   }
7734   guestfs_set_error_handler (g, NULL, NULL);
7735   return (jlong) (long) g;
7736 }
7737
7738 JNIEXPORT void JNICALL
7739 Java_com_redhat_et_libguestfs_GuestFS__1close
7740   (JNIEnv *env, jobject obj, jlong jg)
7741 {
7742   guestfs_h *g = (guestfs_h *) (long) jg;
7743   guestfs_close (g);
7744 }
7745
7746 ";
7747
7748   List.iter (
7749     fun (name, style, _, _, _, _, _) ->
7750       pr "JNIEXPORT ";
7751       (match fst style with
7752        | RErr -> pr "void ";
7753        | RInt _ -> pr "jint ";
7754        | RInt64 _ -> pr "jlong ";
7755        | RBool _ -> pr "jboolean ";
7756        | RConstString _ | RConstOptString _ | RString _
7757        | RBufferOut _ -> pr "jstring ";
7758        | RStruct _ | RHashtable _ ->
7759            pr "jobject ";
7760        | RStringList _ | RStructList _ ->
7761            pr "jobjectArray ";
7762       );
7763       pr "JNICALL\n";
7764       pr "Java_com_redhat_et_libguestfs_GuestFS_";
7765       pr "%s" (replace_str ("_" ^ name) "_" "_1");
7766       pr "\n";
7767       pr "  (JNIEnv *env, jobject obj, jlong jg";
7768       List.iter (
7769         function
7770         | String n
7771         | OptString n
7772         | FileIn n
7773         | FileOut n ->
7774             pr ", jstring j%s" n
7775         | StringList n ->
7776             pr ", jobjectArray j%s" n
7777         | Bool n ->
7778             pr ", jboolean j%s" n
7779         | Int n ->
7780             pr ", jint j%s" n
7781       ) (snd style);
7782       pr ")\n";
7783       pr "{\n";
7784       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
7785       let error_code, no_ret =
7786         match fst style with
7787         | RErr -> pr "  int r;\n"; "-1", ""
7788         | RBool _
7789         | RInt _ -> pr "  int r;\n"; "-1", "0"
7790         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
7791         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
7792         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
7793         | RString _ ->
7794             pr "  jstring jr;\n";
7795             pr "  char *r;\n"; "NULL", "NULL"
7796         | RStringList _ ->
7797             pr "  jobjectArray jr;\n";
7798             pr "  int r_len;\n";
7799             pr "  jclass cl;\n";
7800             pr "  jstring jstr;\n";
7801             pr "  char **r;\n"; "NULL", "NULL"
7802         | RStruct (_, typ) ->
7803             pr "  jobject jr;\n";
7804             pr "  jclass cl;\n";
7805             pr "  jfieldID fl;\n";
7806             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
7807         | RStructList (_, typ) ->
7808             pr "  jobjectArray jr;\n";
7809             pr "  jclass cl;\n";
7810             pr "  jfieldID fl;\n";
7811             pr "  jobject jfl;\n";
7812             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
7813         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
7814         | RBufferOut _ ->
7815             pr "  jstring jr;\n";
7816             pr "  char *r;\n";
7817             pr "  size_t size;\n";
7818             "NULL", "NULL" in
7819       List.iter (
7820         function
7821         | String n
7822         | OptString n
7823         | FileIn n
7824         | FileOut n ->
7825             pr "  const char *%s;\n" n
7826         | StringList n ->
7827             pr "  int %s_len;\n" n;
7828             pr "  const char **%s;\n" n
7829         | Bool n
7830         | Int n ->
7831             pr "  int %s;\n" n
7832       ) (snd style);
7833
7834       let needs_i =
7835         (match fst style with
7836          | RStringList _ | RStructList _ -> true
7837          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
7838          | RConstOptString _
7839          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
7840           List.exists (function StringList _ -> true | _ -> false) (snd style) in
7841       if needs_i then
7842         pr "  int i;\n";
7843
7844       pr "\n";
7845
7846       (* Get the parameters. *)
7847       List.iter (
7848         function
7849         | String n
7850         | FileIn n
7851         | FileOut n ->
7852             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
7853         | OptString n ->
7854             (* This is completely undocumented, but Java null becomes
7855              * a NULL parameter.
7856              *)
7857             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
7858         | StringList n ->
7859             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
7860             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
7861             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
7862             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7863               n;
7864             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
7865             pr "  }\n";
7866             pr "  %s[%s_len] = NULL;\n" n n;
7867         | Bool n
7868         | Int n ->
7869             pr "  %s = j%s;\n" n n
7870       ) (snd style);
7871
7872       (* Make the call. *)
7873       pr "  r = guestfs_%s " name;
7874       generate_c_call_args ~handle:"g" style;
7875       pr ";\n";
7876
7877       (* Release the parameters. *)
7878       List.iter (
7879         function
7880         | String n
7881         | FileIn n
7882         | FileOut n ->
7883             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7884         | OptString n ->
7885             pr "  if (j%s)\n" n;
7886             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
7887         | StringList n ->
7888             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
7889             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
7890               n;
7891             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
7892             pr "  }\n";
7893             pr "  free (%s);\n" n
7894         | Bool n
7895         | Int n -> ()
7896       ) (snd style);
7897
7898       (* Check for errors. *)
7899       pr "  if (r == %s) {\n" error_code;
7900       pr "    throw_exception (env, guestfs_last_error (g));\n";
7901       pr "    return %s;\n" no_ret;
7902       pr "  }\n";
7903
7904       (* Return value. *)
7905       (match fst style with
7906        | RErr -> ()
7907        | RInt _ -> pr "  return (jint) r;\n"
7908        | RBool _ -> pr "  return (jboolean) r;\n"
7909        | RInt64 _ -> pr "  return (jlong) r;\n"
7910        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
7911        | RConstOptString _ ->
7912            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
7913        | RString _ ->
7914            pr "  jr = (*env)->NewStringUTF (env, r);\n";
7915            pr "  free (r);\n";
7916            pr "  return jr;\n"
7917        | RStringList _ ->
7918            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
7919            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
7920            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
7921            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
7922            pr "  for (i = 0; i < r_len; ++i) {\n";
7923            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
7924            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
7925            pr "    free (r[i]);\n";
7926            pr "  }\n";
7927            pr "  free (r);\n";
7928            pr "  return jr;\n"
7929        | RStruct (_, typ) ->
7930            let jtyp = java_name_of_struct typ in
7931            let cols = cols_of_struct typ in
7932            generate_java_struct_return typ jtyp cols
7933        | RStructList (_, typ) ->
7934            let jtyp = java_name_of_struct typ in
7935            let cols = cols_of_struct typ in
7936            generate_java_struct_list_return typ jtyp cols
7937        | RHashtable _ ->
7938            (* XXX *)
7939            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
7940            pr "  return NULL;\n"
7941        | RBufferOut _ ->
7942            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
7943            pr "  free (r);\n";
7944            pr "  return jr;\n"
7945       );
7946
7947       pr "}\n";
7948       pr "\n"
7949   ) all_functions
7950
7951 and generate_java_struct_return typ jtyp cols =
7952   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7953   pr "  jr = (*env)->AllocObject (env, cl);\n";
7954   List.iter (
7955     function
7956     | name, FString ->
7957         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7958         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
7959     | name, FUUID ->
7960         pr "  {\n";
7961         pr "    char s[33];\n";
7962         pr "    memcpy (s, r->%s, 32);\n" name;
7963         pr "    s[32] = 0;\n";
7964         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7965         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
7966         pr "  }\n";
7967     | name, FBuffer ->
7968         pr "  {\n";
7969         pr "    int len = r->%s_len;\n" name;
7970         pr "    char s[len+1];\n";
7971         pr "    memcpy (s, r->%s, len);\n" name;
7972         pr "    s[len] = 0;\n";
7973         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
7974         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
7975         pr "  }\n";
7976     | name, (FBytes|FUInt64|FInt64) ->
7977         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
7978         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7979     | name, (FUInt32|FInt32) ->
7980         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
7981         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7982     | name, FOptPercent ->
7983         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
7984         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
7985     | name, FChar ->
7986         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
7987         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
7988   ) cols;
7989   pr "  free (r);\n";
7990   pr "  return jr;\n"
7991
7992 and generate_java_struct_list_return typ jtyp cols =
7993   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
7994   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
7995   pr "  for (i = 0; i < r->len; ++i) {\n";
7996   pr "    jfl = (*env)->AllocObject (env, cl);\n";
7997   List.iter (
7998     function
7999     | name, FString ->
8000         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8001         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
8002     | name, FUUID ->
8003         pr "    {\n";
8004         pr "      char s[33];\n";
8005         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
8006         pr "      s[32] = 0;\n";
8007         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8008         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8009         pr "    }\n";
8010     | name, FBuffer ->
8011         pr "    {\n";
8012         pr "      int len = r->val[i].%s_len;\n" name;
8013         pr "      char s[len+1];\n";
8014         pr "      memcpy (s, r->val[i].%s, len);\n" name;
8015         pr "      s[len] = 0;\n";
8016         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8017         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8018         pr "    }\n";
8019     | name, (FBytes|FUInt64|FInt64) ->
8020         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8021         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8022     | name, (FUInt32|FInt32) ->
8023         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8024         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8025     | name, FOptPercent ->
8026         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8027         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
8028     | name, FChar ->
8029         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8030         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8031   ) cols;
8032   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
8033   pr "  }\n";
8034   pr "  guestfs_free_%s_list (r);\n" typ;
8035   pr "  return jr;\n"
8036
8037 and generate_haskell_hs () =
8038   generate_header HaskellStyle LGPLv2;
8039
8040   (* XXX We only know how to generate partial FFI for Haskell
8041    * at the moment.  Please help out!
8042    *)
8043   let can_generate style =
8044     match style with
8045     | RErr, _
8046     | RInt _, _
8047     | RInt64 _, _ -> true
8048     | RBool _, _
8049     | RConstString _, _
8050     | RConstOptString _, _
8051     | RString _, _
8052     | RStringList _, _
8053     | RStruct _, _
8054     | RStructList _, _
8055     | RHashtable _, _
8056     | RBufferOut _, _ -> false in
8057
8058   pr "\
8059 {-# INCLUDE <guestfs.h> #-}
8060 {-# LANGUAGE ForeignFunctionInterface #-}
8061
8062 module Guestfs (
8063   create";
8064
8065   (* List out the names of the actions we want to export. *)
8066   List.iter (
8067     fun (name, style, _, _, _, _, _) ->
8068       if can_generate style then pr ",\n  %s" name
8069   ) all_functions;
8070
8071   pr "
8072   ) where
8073 import Foreign
8074 import Foreign.C
8075 import Foreign.C.Types
8076 import IO
8077 import Control.Exception
8078 import Data.Typeable
8079
8080 data GuestfsS = GuestfsS            -- represents the opaque C struct
8081 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
8082 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
8083
8084 -- XXX define properly later XXX
8085 data PV = PV
8086 data VG = VG
8087 data LV = LV
8088 data IntBool = IntBool
8089 data Stat = Stat
8090 data StatVFS = StatVFS
8091 data Hashtable = Hashtable
8092
8093 foreign import ccall unsafe \"guestfs_create\" c_create
8094   :: IO GuestfsP
8095 foreign import ccall unsafe \"&guestfs_close\" c_close
8096   :: FunPtr (GuestfsP -> IO ())
8097 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
8098   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
8099
8100 create :: IO GuestfsH
8101 create = do
8102   p <- c_create
8103   c_set_error_handler p nullPtr nullPtr
8104   h <- newForeignPtr c_close p
8105   return h
8106
8107 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
8108   :: GuestfsP -> IO CString
8109
8110 -- last_error :: GuestfsH -> IO (Maybe String)
8111 -- last_error h = do
8112 --   str <- withForeignPtr h (\\p -> c_last_error p)
8113 --   maybePeek peekCString str
8114
8115 last_error :: GuestfsH -> IO (String)
8116 last_error h = do
8117   str <- withForeignPtr h (\\p -> c_last_error p)
8118   if (str == nullPtr)
8119     then return \"no error\"
8120     else peekCString str
8121
8122 ";
8123
8124   (* Generate wrappers for each foreign function. *)
8125   List.iter (
8126     fun (name, style, _, _, _, _, _) ->
8127       if can_generate style then (
8128         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
8129         pr "  :: ";
8130         generate_haskell_prototype ~handle:"GuestfsP" style;
8131         pr "\n";
8132         pr "\n";
8133         pr "%s :: " name;
8134         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
8135         pr "\n";
8136         pr "%s %s = do\n" name
8137           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
8138         pr "  r <- ";
8139         (* Convert pointer arguments using with* functions. *)
8140         List.iter (
8141           function
8142           | FileIn n
8143           | FileOut n
8144           | String n -> pr "withCString %s $ \\%s -> " n n
8145           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
8146           | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
8147           | Bool _ | Int _ -> ()
8148         ) (snd style);
8149         (* Convert integer arguments. *)
8150         let args =
8151           List.map (
8152             function
8153             | Bool n -> sprintf "(fromBool %s)" n
8154             | Int n -> sprintf "(fromIntegral %s)" n
8155             | FileIn n | FileOut n | String n | OptString n | StringList n -> n
8156           ) (snd style) in
8157         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
8158           (String.concat " " ("p" :: args));
8159         (match fst style with
8160          | RErr | RInt _ | RInt64 _ | RBool _ ->
8161              pr "  if (r == -1)\n";
8162              pr "    then do\n";
8163              pr "      err <- last_error h\n";
8164              pr "      fail err\n";
8165          | RConstString _ | RConstOptString _ | RString _
8166          | RStringList _ | RStruct _
8167          | RStructList _ | RHashtable _ | RBufferOut _ ->
8168              pr "  if (r == nullPtr)\n";
8169              pr "    then do\n";
8170              pr "      err <- last_error h\n";
8171              pr "      fail err\n";
8172         );
8173         (match fst style with
8174          | RErr ->
8175              pr "    else return ()\n"
8176          | RInt _ ->
8177              pr "    else return (fromIntegral r)\n"
8178          | RInt64 _ ->
8179              pr "    else return (fromIntegral r)\n"
8180          | RBool _ ->
8181              pr "    else return (toBool r)\n"
8182          | RConstString _
8183          | RConstOptString _
8184          | RString _
8185          | RStringList _
8186          | RStruct _
8187          | RStructList _
8188          | RHashtable _
8189          | RBufferOut _ ->
8190              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
8191         );
8192         pr "\n";
8193       )
8194   ) all_functions
8195
8196 and generate_haskell_prototype ~handle ?(hs = false) style =
8197   pr "%s -> " handle;
8198   let string = if hs then "String" else "CString" in
8199   let int = if hs then "Int" else "CInt" in
8200   let bool = if hs then "Bool" else "CInt" in
8201   let int64 = if hs then "Integer" else "Int64" in
8202   List.iter (
8203     fun arg ->
8204       (match arg with
8205        | String _ -> pr "%s" string
8206        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
8207        | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
8208        | Bool _ -> pr "%s" bool
8209        | Int _ -> pr "%s" int
8210        | FileIn _ -> pr "%s" string
8211        | FileOut _ -> pr "%s" string
8212       );
8213       pr " -> ";
8214   ) (snd style);
8215   pr "IO (";
8216   (match fst style with
8217    | RErr -> if not hs then pr "CInt"
8218    | RInt _ -> pr "%s" int
8219    | RInt64 _ -> pr "%s" int64
8220    | RBool _ -> pr "%s" bool
8221    | RConstString _ -> pr "%s" string
8222    | RConstOptString _ -> pr "Maybe %s" string
8223    | RString _ -> pr "%s" string
8224    | RStringList _ -> pr "[%s]" string
8225    | RStruct (_, typ) ->
8226        let name = java_name_of_struct typ in
8227        pr "%s" name
8228    | RStructList (_, typ) ->
8229        let name = java_name_of_struct typ in
8230        pr "[%s]" name
8231    | RHashtable _ -> pr "Hashtable"
8232    | RBufferOut _ -> pr "%s" string
8233   );
8234   pr ")"
8235
8236 and generate_bindtests () =
8237   generate_header CStyle LGPLv2;
8238
8239   pr "\
8240 #include <stdio.h>
8241 #include <stdlib.h>
8242 #include <inttypes.h>
8243 #include <string.h>
8244
8245 #include \"guestfs.h\"
8246 #include \"guestfs_protocol.h\"
8247
8248 #define error guestfs_error
8249 #define safe_calloc guestfs_safe_calloc
8250 #define safe_malloc guestfs_safe_malloc
8251
8252 static void
8253 print_strings (char * const* const argv)
8254 {
8255   int argc;
8256
8257   printf (\"[\");
8258   for (argc = 0; argv[argc] != NULL; ++argc) {
8259     if (argc > 0) printf (\", \");
8260     printf (\"\\\"%%s\\\"\", argv[argc]);
8261   }
8262   printf (\"]\\n\");
8263 }
8264
8265 /* The test0 function prints its parameters to stdout. */
8266 ";
8267
8268   let test0, tests =
8269     match test_functions with
8270     | [] -> assert false
8271     | test0 :: tests -> test0, tests in
8272
8273   let () =
8274     let (name, style, _, _, _, _, _) = test0 in
8275     generate_prototype ~extern:false ~semicolon:false ~newline:true
8276       ~handle:"g" ~prefix:"guestfs_" name style;
8277     pr "{\n";
8278     List.iter (
8279       function
8280       | String n
8281       | FileIn n
8282       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
8283       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
8284       | StringList n -> pr "  print_strings (%s);\n" n
8285       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
8286       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
8287     ) (snd style);
8288     pr "  /* Java changes stdout line buffering so we need this: */\n";
8289     pr "  fflush (stdout);\n";
8290     pr "  return 0;\n";
8291     pr "}\n";
8292     pr "\n" in
8293
8294   List.iter (
8295     fun (name, style, _, _, _, _, _) ->
8296       if String.sub name (String.length name - 3) 3 <> "err" then (
8297         pr "/* Test normal return. */\n";
8298         generate_prototype ~extern:false ~semicolon:false ~newline:true
8299           ~handle:"g" ~prefix:"guestfs_" name style;
8300         pr "{\n";
8301         (match fst style with
8302          | RErr ->
8303              pr "  return 0;\n"
8304          | RInt _ ->
8305              pr "  int r;\n";
8306              pr "  sscanf (val, \"%%d\", &r);\n";
8307              pr "  return r;\n"
8308          | RInt64 _ ->
8309              pr "  int64_t r;\n";
8310              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
8311              pr "  return r;\n"
8312          | RBool _ ->
8313              pr "  return strcmp (val, \"true\") == 0;\n"
8314          | RConstString _
8315          | RConstOptString _ ->
8316              (* Can't return the input string here.  Return a static
8317               * string so we ensure we get a segfault if the caller
8318               * tries to free it.
8319               *)
8320              pr "  return \"static string\";\n"
8321          | RString _ ->
8322              pr "  return strdup (val);\n"
8323          | RStringList _ ->
8324              pr "  char **strs;\n";
8325              pr "  int n, i;\n";
8326              pr "  sscanf (val, \"%%d\", &n);\n";
8327              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
8328              pr "  for (i = 0; i < n; ++i) {\n";
8329              pr "    strs[i] = safe_malloc (g, 16);\n";
8330              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
8331              pr "  }\n";
8332              pr "  strs[n] = NULL;\n";
8333              pr "  return strs;\n"
8334          | RStruct (_, typ) ->
8335              pr "  struct guestfs_%s *r;\n" typ;
8336              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
8337              pr "  return r;\n"
8338          | RStructList (_, typ) ->
8339              pr "  struct guestfs_%s_list *r;\n" typ;
8340              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
8341              pr "  sscanf (val, \"%%d\", &r->len);\n";
8342              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8343              pr "  return r;\n"
8344          | RHashtable _ ->
8345              pr "  char **strs;\n";
8346              pr "  int n, i;\n";
8347              pr "  sscanf (val, \"%%d\", &n);\n";
8348              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
8349              pr "  for (i = 0; i < n; ++i) {\n";
8350              pr "    strs[i*2] = safe_malloc (g, 16);\n";
8351              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
8352              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
8353              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
8354              pr "  }\n";
8355              pr "  strs[n*2] = NULL;\n";
8356              pr "  return strs;\n"
8357          | RBufferOut _ ->
8358              pr "  return strdup (val);\n"
8359         );
8360         pr "}\n";
8361         pr "\n"
8362       ) else (
8363         pr "/* Test error return. */\n";
8364         generate_prototype ~extern:false ~semicolon:false ~newline:true
8365           ~handle:"g" ~prefix:"guestfs_" name style;
8366         pr "{\n";
8367         pr "  error (g, \"error\");\n";
8368         (match fst style with
8369          | RErr | RInt _ | RInt64 _ | RBool _ ->
8370              pr "  return -1;\n"
8371          | RConstString _ | RConstOptString _
8372          | RString _ | RStringList _ | RStruct _
8373          | RStructList _
8374          | RHashtable _
8375          | RBufferOut _ ->
8376              pr "  return NULL;\n"
8377         );
8378         pr "}\n";
8379         pr "\n"
8380       )
8381   ) tests
8382
8383 and generate_ocaml_bindtests () =
8384   generate_header OCamlStyle GPLv2;
8385
8386   pr "\
8387 let () =
8388   let g = Guestfs.create () in
8389 ";
8390
8391   let mkargs args =
8392     String.concat " " (
8393       List.map (
8394         function
8395         | CallString s -> "\"" ^ s ^ "\""
8396         | CallOptString None -> "None"
8397         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
8398         | CallStringList xs ->
8399             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
8400         | CallInt i when i >= 0 -> string_of_int i
8401         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
8402         | CallBool b -> string_of_bool b
8403       ) args
8404     )
8405   in
8406
8407   generate_lang_bindtests (
8408     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
8409   );
8410
8411   pr "print_endline \"EOF\"\n"
8412
8413 and generate_perl_bindtests () =
8414   pr "#!/usr/bin/perl -w\n";
8415   generate_header HashStyle GPLv2;
8416
8417   pr "\
8418 use strict;
8419
8420 use Sys::Guestfs;
8421
8422 my $g = Sys::Guestfs->new ();
8423 ";
8424
8425   let mkargs args =
8426     String.concat ", " (
8427       List.map (
8428         function
8429         | CallString s -> "\"" ^ s ^ "\""
8430         | CallOptString None -> "undef"
8431         | CallOptString (Some s) -> sprintf "\"%s\"" s
8432         | CallStringList xs ->
8433             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8434         | CallInt i -> string_of_int i
8435         | CallBool b -> if b then "1" else "0"
8436       ) args
8437     )
8438   in
8439
8440   generate_lang_bindtests (
8441     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
8442   );
8443
8444   pr "print \"EOF\\n\"\n"
8445
8446 and generate_python_bindtests () =
8447   generate_header HashStyle GPLv2;
8448
8449   pr "\
8450 import guestfs
8451
8452 g = guestfs.GuestFS ()
8453 ";
8454
8455   let mkargs args =
8456     String.concat ", " (
8457       List.map (
8458         function
8459         | CallString s -> "\"" ^ s ^ "\""
8460         | CallOptString None -> "None"
8461         | CallOptString (Some s) -> sprintf "\"%s\"" s
8462         | CallStringList xs ->
8463             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8464         | CallInt i -> string_of_int i
8465         | CallBool b -> if b then "1" else "0"
8466       ) args
8467     )
8468   in
8469
8470   generate_lang_bindtests (
8471     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
8472   );
8473
8474   pr "print \"EOF\"\n"
8475
8476 and generate_ruby_bindtests () =
8477   generate_header HashStyle GPLv2;
8478
8479   pr "\
8480 require 'guestfs'
8481
8482 g = Guestfs::create()
8483 ";
8484
8485   let mkargs args =
8486     String.concat ", " (
8487       List.map (
8488         function
8489         | CallString s -> "\"" ^ s ^ "\""
8490         | CallOptString None -> "nil"
8491         | CallOptString (Some s) -> sprintf "\"%s\"" s
8492         | CallStringList xs ->
8493             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8494         | CallInt i -> string_of_int i
8495         | CallBool b -> string_of_bool b
8496       ) args
8497     )
8498   in
8499
8500   generate_lang_bindtests (
8501     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
8502   );
8503
8504   pr "print \"EOF\\n\"\n"
8505
8506 and generate_java_bindtests () =
8507   generate_header CStyle GPLv2;
8508
8509   pr "\
8510 import com.redhat.et.libguestfs.*;
8511
8512 public class Bindtests {
8513     public static void main (String[] argv)
8514     {
8515         try {
8516             GuestFS g = new GuestFS ();
8517 ";
8518
8519   let mkargs args =
8520     String.concat ", " (
8521       List.map (
8522         function
8523         | CallString s -> "\"" ^ s ^ "\""
8524         | CallOptString None -> "null"
8525         | CallOptString (Some s) -> sprintf "\"%s\"" s
8526         | CallStringList xs ->
8527             "new String[]{" ^
8528               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
8529         | CallInt i -> string_of_int i
8530         | CallBool b -> string_of_bool b
8531       ) args
8532     )
8533   in
8534
8535   generate_lang_bindtests (
8536     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
8537   );
8538
8539   pr "
8540             System.out.println (\"EOF\");
8541         }
8542         catch (Exception exn) {
8543             System.err.println (exn);
8544             System.exit (1);
8545         }
8546     }
8547 }
8548 "
8549
8550 and generate_haskell_bindtests () =
8551   generate_header HaskellStyle GPLv2;
8552
8553   pr "\
8554 module Bindtests where
8555 import qualified Guestfs
8556
8557 main = do
8558   g <- Guestfs.create
8559 ";
8560
8561   let mkargs args =
8562     String.concat " " (
8563       List.map (
8564         function
8565         | CallString s -> "\"" ^ s ^ "\""
8566         | CallOptString None -> "Nothing"
8567         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
8568         | CallStringList xs ->
8569             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8570         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
8571         | CallInt i -> string_of_int i
8572         | CallBool true -> "True"
8573         | CallBool false -> "False"
8574       ) args
8575     )
8576   in
8577
8578   generate_lang_bindtests (
8579     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
8580   );
8581
8582   pr "  putStrLn \"EOF\"\n"
8583
8584 (* Language-independent bindings tests - we do it this way to
8585  * ensure there is parity in testing bindings across all languages.
8586  *)
8587 and generate_lang_bindtests call =
8588   call "test0" [CallString "abc"; CallOptString (Some "def");
8589                 CallStringList []; CallBool false;
8590                 CallInt 0; CallString "123"; CallString "456"];
8591   call "test0" [CallString "abc"; CallOptString None;
8592                 CallStringList []; CallBool false;
8593                 CallInt 0; CallString "123"; CallString "456"];
8594   call "test0" [CallString ""; CallOptString (Some "def");
8595                 CallStringList []; CallBool false;
8596                 CallInt 0; CallString "123"; CallString "456"];
8597   call "test0" [CallString ""; CallOptString (Some "");
8598                 CallStringList []; CallBool false;
8599                 CallInt 0; CallString "123"; CallString "456"];
8600   call "test0" [CallString "abc"; CallOptString (Some "def");
8601                 CallStringList ["1"]; CallBool false;
8602                 CallInt 0; CallString "123"; CallString "456"];
8603   call "test0" [CallString "abc"; CallOptString (Some "def");
8604                 CallStringList ["1"; "2"]; CallBool false;
8605                 CallInt 0; CallString "123"; CallString "456"];
8606   call "test0" [CallString "abc"; CallOptString (Some "def");
8607                 CallStringList ["1"]; CallBool true;
8608                 CallInt 0; CallString "123"; CallString "456"];
8609   call "test0" [CallString "abc"; CallOptString (Some "def");
8610                 CallStringList ["1"]; CallBool false;
8611                 CallInt (-1); CallString "123"; CallString "456"];
8612   call "test0" [CallString "abc"; CallOptString (Some "def");
8613                 CallStringList ["1"]; CallBool false;
8614                 CallInt (-2); CallString "123"; CallString "456"];
8615   call "test0" [CallString "abc"; CallOptString (Some "def");
8616                 CallStringList ["1"]; CallBool false;
8617                 CallInt 1; CallString "123"; CallString "456"];
8618   call "test0" [CallString "abc"; CallOptString (Some "def");
8619                 CallStringList ["1"]; CallBool false;
8620                 CallInt 2; CallString "123"; CallString "456"];
8621   call "test0" [CallString "abc"; CallOptString (Some "def");
8622                 CallStringList ["1"]; CallBool false;
8623                 CallInt 4095; CallString "123"; CallString "456"];
8624   call "test0" [CallString "abc"; CallOptString (Some "def");
8625                 CallStringList ["1"]; CallBool false;
8626                 CallInt 0; CallString ""; CallString ""]
8627
8628 (* XXX Add here tests of the return and error functions. *)
8629
8630 (* This is used to generate the src/MAX_PROC_NR file which
8631  * contains the maximum procedure number, a surrogate for the
8632  * ABI version number.  See src/Makefile.am for the details.
8633  *)
8634 and generate_max_proc_nr () =
8635   let proc_nrs = List.map (
8636     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
8637   ) daemon_functions in
8638
8639   let max_proc_nr = List.fold_left max 0 proc_nrs in
8640
8641   pr "%d\n" max_proc_nr
8642
8643 let output_to filename =
8644   let filename_new = filename ^ ".new" in
8645   chan := open_out filename_new;
8646   let close () =
8647     close_out !chan;
8648     chan := stdout;
8649
8650     (* Is the new file different from the current file? *)
8651     if Sys.file_exists filename && files_equal filename filename_new then
8652       Unix.unlink filename_new          (* same, so skip it *)
8653     else (
8654       (* different, overwrite old one *)
8655       (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
8656       Unix.rename filename_new filename;
8657       Unix.chmod filename 0o444;
8658       printf "written %s\n%!" filename;
8659     )
8660   in
8661   close
8662
8663 (* Main program. *)
8664 let () =
8665   check_functions ();
8666
8667   if not (Sys.file_exists "HACKING") then (
8668     eprintf "\
8669 You are probably running this from the wrong directory.
8670 Run it from the top source directory using the command
8671   src/generator.ml
8672 ";
8673     exit 1
8674   );
8675
8676   let close = output_to "src/guestfs_protocol.x" in
8677   generate_xdr ();
8678   close ();
8679
8680   let close = output_to "src/guestfs-structs.h" in
8681   generate_structs_h ();
8682   close ();
8683
8684   let close = output_to "src/guestfs-actions.h" in
8685   generate_actions_h ();
8686   close ();
8687
8688   let close = output_to "src/guestfs-actions.c" in
8689   generate_client_actions ();
8690   close ();
8691
8692   let close = output_to "daemon/actions.h" in
8693   generate_daemon_actions_h ();
8694   close ();
8695
8696   let close = output_to "daemon/stubs.c" in
8697   generate_daemon_actions ();
8698   close ();
8699
8700   let close = output_to "daemon/names.c" in
8701   generate_daemon_names ();
8702   close ();
8703
8704   let close = output_to "capitests/tests.c" in
8705   generate_tests ();
8706   close ();
8707
8708   let close = output_to "src/guestfs-bindtests.c" in
8709   generate_bindtests ();
8710   close ();
8711
8712   let close = output_to "fish/cmds.c" in
8713   generate_fish_cmds ();
8714   close ();
8715
8716   let close = output_to "fish/completion.c" in
8717   generate_fish_completion ();
8718   close ();
8719
8720   let close = output_to "guestfs-structs.pod" in
8721   generate_structs_pod ();
8722   close ();
8723
8724   let close = output_to "guestfs-actions.pod" in
8725   generate_actions_pod ();
8726   close ();
8727
8728   let close = output_to "guestfish-actions.pod" in
8729   generate_fish_actions_pod ();
8730   close ();
8731
8732   let close = output_to "ocaml/guestfs.mli" in
8733   generate_ocaml_mli ();
8734   close ();
8735
8736   let close = output_to "ocaml/guestfs.ml" in
8737   generate_ocaml_ml ();
8738   close ();
8739
8740   let close = output_to "ocaml/guestfs_c_actions.c" in
8741   generate_ocaml_c ();
8742   close ();
8743
8744   let close = output_to "ocaml/bindtests.ml" in
8745   generate_ocaml_bindtests ();
8746   close ();
8747
8748   let close = output_to "perl/Guestfs.xs" in
8749   generate_perl_xs ();
8750   close ();
8751
8752   let close = output_to "perl/lib/Sys/Guestfs.pm" in
8753   generate_perl_pm ();
8754   close ();
8755
8756   let close = output_to "perl/bindtests.pl" in
8757   generate_perl_bindtests ();
8758   close ();
8759
8760   let close = output_to "python/guestfs-py.c" in
8761   generate_python_c ();
8762   close ();
8763
8764   let close = output_to "python/guestfs.py" in
8765   generate_python_py ();
8766   close ();
8767
8768   let close = output_to "python/bindtests.py" in
8769   generate_python_bindtests ();
8770   close ();
8771
8772   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
8773   generate_ruby_c ();
8774   close ();
8775
8776   let close = output_to "ruby/bindtests.rb" in
8777   generate_ruby_bindtests ();
8778   close ();
8779
8780   let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
8781   generate_java_java ();
8782   close ();
8783
8784   List.iter (
8785     fun (typ, jtyp) ->
8786       let cols = cols_of_struct typ in
8787       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
8788       let close = output_to filename in
8789       generate_java_struct jtyp cols;
8790       close ();
8791   ) java_structs;
8792
8793   let close = output_to "java/Makefile.inc" in
8794   pr "java_built_sources =";
8795   List.iter (
8796     fun (typ, jtyp) ->
8797         pr " com/redhat/et/libguestfs/%s.java" jtyp;
8798   ) java_structs;
8799   pr " com/redhat/et/libguestfs/GuestFS.java\n";
8800   close ();
8801
8802   let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
8803   generate_java_c ();
8804   close ();
8805
8806   let close = output_to "java/Bindtests.java" in
8807   generate_java_bindtests ();
8808   close ();
8809
8810   let close = output_to "haskell/Guestfs.hs" in
8811   generate_haskell_hs ();
8812   close ();
8813
8814   let close = output_to "haskell/Bindtests.hs" in
8815   generate_haskell_bindtests ();
8816   close ();
8817
8818   let close = output_to "src/MAX_PROC_NR" in
8819   generate_max_proc_nr ();
8820   close ();
8821
8822   (* Always generate this file last, and unconditionally.  It's used
8823    * by the Makefile to know when we must re-run the generator.
8824    *)
8825   let chan = open_out "src/stamp-generator" in
8826   fprintf chan "1\n";
8827   close_out chan