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