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