daemon: Fix strings to work on absolute symbolic links (RHBZ#579608).
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009-2010 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 of
25  * 'daemon_functions' below), and daemon/<somefile>.c to write the
26  * implementation.
27  *
28  * After editing this file, run it (./src/generator.ml) to regenerate
29  * all the output files.  'make' will rerun this automatically when
30  * necessary.  Note that if you are using a separate build directory
31  * you must run generator.ml from the _source_ directory.
32  *
33  * IMPORTANT: This script should NOT print any warnings.  If it prints
34  * warnings, you should treat them as errors.
35  *
36  * OCaml tips:
37  * (1) In emacs, install tuareg-mode to display and format OCaml code
38  * correctly.  'vim' comes with a good OCaml editing mode by default.
39  * (2) Read the resources at http://ocaml-tutorial.org/
40  *)
41
42 #load "unix.cma";;
43 #load "str.cma";;
44 #directory "+xml-light";;
45 #directory "+../pkg-lib/xml-light";; (* for GODI users *)
46 #load "xml-light.cma";;
47
48 open Unix
49 open Printf
50
51 type style = ret * args
52 and ret =
53     (* "RErr" as a return value means an int used as a simple error
54      * indication, ie. 0 or -1.
55      *)
56   | RErr
57
58     (* "RInt" as a return value means an int which is -1 for error
59      * or any value >= 0 on success.  Only use this for smallish
60      * positive ints (0 <= i < 2^30).
61      *)
62   | RInt of string
63
64     (* "RInt64" is the same as RInt, but is guaranteed to be able
65      * to return a full 64 bit value, _except_ that -1 means error
66      * (so -1 cannot be a valid, non-error return value).
67      *)
68   | RInt64 of string
69
70     (* "RBool" is a bool return value which can be true/false or
71      * -1 for error.
72      *)
73   | RBool of string
74
75     (* "RConstString" is a string that refers to a constant value.
76      * The return value must NOT be NULL (since NULL indicates
77      * an error).
78      *
79      * Try to avoid using this.  In particular you cannot use this
80      * for values returned from the daemon, because there is no
81      * thread-safe way to return them in the C API.
82      *)
83   | RConstString of string
84
85     (* "RConstOptString" is an even more broken version of
86      * "RConstString".  The returned string may be NULL and there
87      * is no way to return an error indication.  Avoid using this!
88      *)
89   | RConstOptString of string
90
91     (* "RString" is a returned string.  It must NOT be NULL, since
92      * a NULL return indicates an error.  The caller frees this.
93      *)
94   | RString of string
95
96     (* "RStringList" is a list of strings.  No string in the list
97      * can be NULL.  The caller frees the strings and the array.
98      *)
99   | RStringList of string
100
101     (* "RStruct" is a function which returns a single named structure
102      * or an error indication (in C, a struct, and in other languages
103      * with varying representations, but usually very efficient).  See
104      * after the function list below for the structures.
105      *)
106   | RStruct of string * string          (* name of retval, name of struct *)
107
108     (* "RStructList" is a function which returns either a list/array
109      * of structures (could be zero-length), or an error indication.
110      *)
111   | RStructList of string * string      (* name of retval, name of struct *)
112
113     (* Key-value pairs of untyped strings.  Turns into a hashtable or
114      * dictionary in languages which support it.  DON'T use this as a
115      * general "bucket" for results.  Prefer a stronger typed return
116      * value if one is available, or write a custom struct.  Don't use
117      * this if the list could potentially be very long, since it is
118      * inefficient.  Keys should be unique.  NULLs are not permitted.
119      *)
120   | RHashtable of string
121
122     (* "RBufferOut" is handled almost exactly like RString, but
123      * it allows the string to contain arbitrary 8 bit data including
124      * ASCII NUL.  In the C API this causes an implicit extra parameter
125      * to be added of type <size_t *size_r>.  The extra parameter
126      * returns the actual size of the return buffer in bytes.
127      *
128      * Other programming languages support strings with arbitrary 8 bit
129      * data.
130      *
131      * At the RPC layer we have to use the opaque<> type instead of
132      * string<>.  Returned data is still limited to the max message
133      * size (ie. ~ 2 MB).
134      *)
135   | RBufferOut of string
136
137 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
138
139     (* Note in future we should allow a "variable args" parameter as
140      * the final parameter, to allow commands like
141      *   chmod mode file [file(s)...]
142      * This is not implemented yet, but many commands (such as chmod)
143      * are currently defined with the argument order keeping this future
144      * possibility in mind.
145      *)
146 and argt =
147   | String of string    (* const char *name, cannot be NULL *)
148   | Device of string    (* /dev device name, cannot be NULL *)
149   | Pathname of string  (* file name, cannot be NULL *)
150   | Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
151   | OptString of string (* const char *name, may be NULL *)
152   | StringList of string(* list of strings (each string cannot be NULL) *)
153   | DeviceList of string(* list of Device names (each cannot be NULL) *)
154   | Bool of string      (* boolean *)
155   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
156   | Int64 of string     (* any 64 bit int *)
157     (* These are treated as filenames (simple string parameters) in
158      * the C API and bindings.  But in the RPC protocol, we transfer
159      * the actual file content up to or down from the daemon.
160      * FileIn: local machine -> daemon (in request)
161      * FileOut: daemon -> local machine (in reply)
162      * In guestfish (only), the special name "-" means read from
163      * stdin or write to stdout.
164      *)
165   | FileIn of string
166   | FileOut of string
167 (* Not implemented:
168     (* Opaque buffer which can contain arbitrary 8 bit data.
169      * In the C API, this is expressed as <char *, int> pair.
170      * Most other languages have a string type which can contain
171      * ASCII NUL.  We use whatever type is appropriate for each
172      * language.
173      * Buffers are limited by the total message size.  To transfer
174      * large blocks of data, use FileIn/FileOut parameters instead.
175      * To return an arbitrary buffer, use RBufferOut.
176      *)
177   | BufferIn of string
178 *)
179
180 type flags =
181   | ProtocolLimitWarning  (* display warning about protocol size limits *)
182   | DangerWillRobinson    (* flags particularly dangerous commands *)
183   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
184   | FishAction of string  (* call this function in guestfish *)
185   | FishOutput of fish_output_t (* how to display output in guestfish *)
186   | NotInFish             (* do not export via guestfish *)
187   | NotInDocs             (* do not add this function to documentation *)
188   | DeprecatedBy of string (* function is deprecated, use .. instead *)
189   | Optional of string    (* function is part of an optional group *)
190
191 and fish_output_t =
192   | FishOutputOctal       (* for int return, print in octal *)
193   | FishOutputHexadecimal (* for int return, print in hex *)
194
195 (* You can supply zero or as many tests as you want per API call.
196  *
197  * Note that the test environment has 3 block devices, of size 500MB,
198  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
199  * a fourth ISO block device with some known files on it (/dev/sdd).
200  *
201  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
202  * Number of cylinders was 63 for IDE emulated disks with precisely
203  * the same size.  How exactly this is calculated is a mystery.
204  *
205  * The ISO block device (/dev/sdd) comes from images/test.iso.
206  *
207  * To be able to run the tests in a reasonable amount of time,
208  * the virtual machine and block devices are reused between tests.
209  * So don't try testing kill_subprocess :-x
210  *
211  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
212  *
213  * Don't assume anything about the previous contents of the block
214  * devices.  Use 'Init*' to create some initial scenarios.
215  *
216  * You can add a prerequisite clause to any individual test.  This
217  * is a run-time check, which, if it fails, causes the test to be
218  * skipped.  Useful if testing a command which might not work on
219  * all variations of libguestfs builds.  A test that has prerequisite
220  * of 'Always' is run unconditionally.
221  *
222  * In addition, packagers can skip individual tests by setting the
223  * environment variables:     eg:
224  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
225  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
226  *)
227 type tests = (test_init * test_prereq * test) list
228 and test =
229     (* Run the command sequence and just expect nothing to fail. *)
230   | TestRun of seq
231
232     (* Run the command sequence and expect the output of the final
233      * command to be the string.
234      *)
235   | TestOutput of seq * string
236
237     (* Run the command sequence and expect the output of the final
238      * command to be the list of strings.
239      *)
240   | TestOutputList of seq * string list
241
242     (* Run the command sequence and expect the output of the final
243      * command to be the list of block devices (could be either
244      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
245      * character of each string).
246      *)
247   | TestOutputListOfDevices of seq * string list
248
249     (* Run the command sequence and expect the output of the final
250      * command to be the integer.
251      *)
252   | TestOutputInt of seq * int
253
254     (* Run the command sequence and expect the output of the final
255      * command to be <op> <int>, eg. ">=", "1".
256      *)
257   | TestOutputIntOp of seq * string * int
258
259     (* Run the command sequence and expect the output of the final
260      * command to be a true value (!= 0 or != NULL).
261      *)
262   | TestOutputTrue of seq
263
264     (* Run the command sequence and expect the output of the final
265      * command to be a false value (== 0 or == NULL, but not an error).
266      *)
267   | TestOutputFalse of seq
268
269     (* Run the command sequence and expect the output of the final
270      * command to be a list of the given length (but don't care about
271      * content).
272      *)
273   | TestOutputLength of seq * int
274
275     (* Run the command sequence and expect the output of the final
276      * command to be a buffer (RBufferOut), ie. string + size.
277      *)
278   | TestOutputBuffer of seq * string
279
280     (* Run the command sequence and expect the output of the final
281      * command to be a structure.
282      *)
283   | TestOutputStruct of seq * test_field_compare list
284
285     (* Run the command sequence and expect the final command (only)
286      * to fail.
287      *)
288   | TestLastFail of seq
289
290 and test_field_compare =
291   | CompareWithInt of string * int
292   | CompareWithIntOp of string * string * int
293   | CompareWithString of string * string
294   | CompareFieldsIntEq of string * string
295   | CompareFieldsStrEq of string * string
296
297 (* Test prerequisites. *)
298 and test_prereq =
299     (* Test always runs. *)
300   | Always
301
302     (* Test is currently disabled - eg. it fails, or it tests some
303      * unimplemented feature.
304      *)
305   | Disabled
306
307     (* 'string' is some C code (a function body) that should return
308      * true or false.  The test will run if the code returns true.
309      *)
310   | If of string
311
312     (* As for 'If' but the test runs _unless_ the code returns true. *)
313   | Unless of string
314
315 (* Some initial scenarios for testing. *)
316 and test_init =
317     (* Do nothing, block devices could contain random stuff including
318      * LVM PVs, and some filesystems might be mounted.  This is usually
319      * a bad idea.
320      *)
321   | InitNone
322
323     (* Block devices are empty and no filesystems are mounted. *)
324   | InitEmpty
325
326     (* /dev/sda contains a single partition /dev/sda1, with random
327      * content.  /dev/sdb and /dev/sdc may have random content.
328      * No LVM.
329      *)
330   | InitPartition
331
332     (* /dev/sda contains a single partition /dev/sda1, which is formatted
333      * as ext2, empty [except for lost+found] and mounted on /.
334      * /dev/sdb and /dev/sdc may have random content.
335      * No LVM.
336      *)
337   | InitBasicFS
338
339     (* /dev/sda:
340      *   /dev/sda1 (is a PV):
341      *     /dev/VG/LV (size 8MB):
342      *       formatted as ext2, empty [except for lost+found], mounted on /
343      * /dev/sdb and /dev/sdc may have random content.
344      *)
345   | InitBasicFSonLVM
346
347     (* /dev/sdd (the ISO, see images/ directory in source)
348      * is mounted on /
349      *)
350   | InitISOFS
351
352 (* Sequence of commands for testing. *)
353 and seq = cmd list
354 and cmd = string list
355
356 (* Note about long descriptions: When referring to another
357  * action, use the format C<guestfs_other> (ie. the full name of
358  * the C function).  This will be replaced as appropriate in other
359  * language bindings.
360  *
361  * Apart from that, long descriptions are just perldoc paragraphs.
362  *)
363
364 (* Generate a random UUID (used in tests). *)
365 let uuidgen () =
366   let chan = open_process_in "uuidgen" in
367   let uuid = input_line chan in
368   (match close_process_in chan with
369    | WEXITED 0 -> ()
370    | WEXITED _ ->
371        failwith "uuidgen: process exited with non-zero status"
372    | WSIGNALED _ | WSTOPPED _ ->
373        failwith "uuidgen: process signalled or stopped by signal"
374   );
375   uuid
376
377 (* These test functions are used in the language binding tests. *)
378
379 let test_all_args = [
380   String "str";
381   OptString "optstr";
382   StringList "strlist";
383   Bool "b";
384   Int "integer";
385   Int64 "integer64";
386   FileIn "filein";
387   FileOut "fileout";
388 ]
389
390 let test_all_rets = [
391   (* except for RErr, which is tested thoroughly elsewhere *)
392   "test0rint",         RInt "valout";
393   "test0rint64",       RInt64 "valout";
394   "test0rbool",        RBool "valout";
395   "test0rconststring", RConstString "valout";
396   "test0rconstoptstring", RConstOptString "valout";
397   "test0rstring",      RString "valout";
398   "test0rstringlist",  RStringList "valout";
399   "test0rstruct",      RStruct ("valout", "lvm_pv");
400   "test0rstructlist",  RStructList ("valout", "lvm_pv");
401   "test0rhashtable",   RHashtable "valout";
402 ]
403
404 let test_functions = [
405   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
406    [],
407    "internal test function - do not use",
408    "\
409 This is an internal test function which is used to test whether
410 the automatically generated bindings can handle every possible
411 parameter type correctly.
412
413 It echos the contents of each parameter to stdout.
414
415 You probably don't want to call this function.");
416 ] @ List.flatten (
417   List.map (
418     fun (name, ret) ->
419       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
420         [],
421         "internal test function - do not use",
422         "\
423 This is an internal test function which is used to test whether
424 the automatically generated bindings can handle every possible
425 return type correctly.
426
427 It converts string C<val> to the return type.
428
429 You probably don't want to call this function.");
430        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
431         [],
432         "internal test function - do not use",
433         "\
434 This is an internal test function which is used to test whether
435 the automatically generated bindings can handle every possible
436 return type correctly.
437
438 This function always returns an error.
439
440 You probably don't want to call this function.")]
441   ) test_all_rets
442 )
443
444 (* non_daemon_functions are any functions which don't get processed
445  * in the daemon, eg. functions for setting and getting local
446  * configuration values.
447  *)
448
449 let non_daemon_functions = test_functions @ [
450   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
451    [],
452    "launch the qemu subprocess",
453    "\
454 Internally libguestfs is implemented by running a virtual machine
455 using L<qemu(1)>.
456
457 You should call this after configuring the handle
458 (eg. adding drives) but before performing any actions.");
459
460   ("wait_ready", (RErr, []), -1, [NotInFish],
461    [],
462    "wait until the qemu subprocess launches (no op)",
463    "\
464 This function is a no op.
465
466 In versions of the API E<lt> 1.0.71 you had to call this function
467 just after calling C<guestfs_launch> to wait for the launch
468 to complete.  However this is no longer necessary because
469 C<guestfs_launch> now does the waiting.
470
471 If you see any calls to this function in code then you can just
472 remove them, unless you want to retain compatibility with older
473 versions of the API.");
474
475   ("kill_subprocess", (RErr, []), -1, [],
476    [],
477    "kill the qemu subprocess",
478    "\
479 This kills the qemu subprocess.  You should never need to call this.");
480
481   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
482    [],
483    "add an image to examine or modify",
484    "\
485 This function adds a virtual machine disk image C<filename> to the
486 guest.  The first time you call this function, the disk appears as IDE
487 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
488 so on.
489
490 You don't necessarily need to be root when using libguestfs.  However
491 you obviously do need sufficient permissions to access the filename
492 for whatever operations you want to perform (ie. read access if you
493 just want to read the image or write access if you want to modify the
494 image).
495
496 This is equivalent to the qemu parameter
497 C<-drive file=filename,cache=off,if=...>.
498
499 C<cache=off> is omitted in cases where it is not supported by
500 the underlying filesystem.
501
502 C<if=...> is set at compile time by the configuration option
503 C<./configure --with-drive-if=...>.  In the rare case where you
504 might need to change this at run time, use C<guestfs_add_drive_with_if>
505 or C<guestfs_add_drive_ro_with_if>.
506
507 Note that this call checks for the existence of C<filename>.  This
508 stops you from specifying other types of drive which are supported
509 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
510 the general C<guestfs_config> call instead.");
511
512   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
513    [],
514    "add a CD-ROM disk image to examine",
515    "\
516 This function adds a virtual CD-ROM disk image to the guest.
517
518 This is equivalent to the qemu parameter C<-cdrom filename>.
519
520 Notes:
521
522 =over 4
523
524 =item *
525
526 This call checks for the existence of C<filename>.  This
527 stops you from specifying other types of drive which are supported
528 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
529 the general C<guestfs_config> call instead.
530
531 =item *
532
533 If you just want to add an ISO file (often you use this as an
534 efficient way to transfer large files into the guest), then you
535 should probably use C<guestfs_add_drive_ro> instead.
536
537 =back");
538
539   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
540    [],
541    "add a drive in snapshot mode (read-only)",
542    "\
543 This adds a drive in snapshot mode, making it effectively
544 read-only.
545
546 Note that writes to the device are allowed, and will be seen for
547 the duration of the guestfs handle, but they are written
548 to a temporary file which is discarded as soon as the guestfs
549 handle is closed.  We don't currently have any method to enable
550 changes to be committed, although qemu can support this.
551
552 This is equivalent to the qemu parameter
553 C<-drive file=filename,snapshot=on,readonly=on,if=...>.
554
555 C<if=...> is set at compile time by the configuration option
556 C<./configure --with-drive-if=...>.  In the rare case where you
557 might need to change this at run time, use C<guestfs_add_drive_with_if>
558 or C<guestfs_add_drive_ro_with_if>.
559
560 C<readonly=on> is only added where qemu supports this option.
561
562 Note that this call checks for the existence of C<filename>.  This
563 stops you from specifying other types of drive which are supported
564 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
565 the general C<guestfs_config> call instead.");
566
567   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
568    [],
569    "add qemu parameters",
570    "\
571 This can be used to add arbitrary qemu command line parameters
572 of the form C<-param value>.  Actually it's not quite arbitrary - we
573 prevent you from setting some parameters which would interfere with
574 parameters that we use.
575
576 The first character of C<param> string must be a C<-> (dash).
577
578 C<value> can be NULL.");
579
580   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
581    [],
582    "set the qemu binary",
583    "\
584 Set the qemu binary that we will use.
585
586 The default is chosen when the library was compiled by the
587 configure script.
588
589 You can also override this by setting the C<LIBGUESTFS_QEMU>
590 environment variable.
591
592 Setting C<qemu> to C<NULL> restores the default qemu binary.
593
594 Note that you should call this function as early as possible
595 after creating the handle.  This is because some pre-launch
596 operations depend on testing qemu features (by running C<qemu -help>).
597 If the qemu binary changes, we don't retest features, and
598 so you might see inconsistent results.  Using the environment
599 variable C<LIBGUESTFS_QEMU> is safest of all since that picks
600 the qemu binary at the same time as the handle is created.");
601
602   ("get_qemu", (RConstString "qemu", []), -1, [],
603    [InitNone, Always, TestRun (
604       [["get_qemu"]])],
605    "get the qemu binary",
606    "\
607 Return the current qemu binary.
608
609 This is always non-NULL.  If it wasn't set already, then this will
610 return the default qemu binary name.");
611
612   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
613    [],
614    "set the search path",
615    "\
616 Set the path that libguestfs searches for kernel and initrd.img.
617
618 The default is C<$libdir/guestfs> unless overridden by setting
619 C<LIBGUESTFS_PATH> environment variable.
620
621 Setting C<path> to C<NULL> restores the default path.");
622
623   ("get_path", (RConstString "path", []), -1, [],
624    [InitNone, Always, TestRun (
625       [["get_path"]])],
626    "get the search path",
627    "\
628 Return the current search path.
629
630 This is always non-NULL.  If it wasn't set already, then this will
631 return the default path.");
632
633   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
634    [],
635    "add options to kernel command line",
636    "\
637 This function is used to add additional options to the
638 guest kernel command line.
639
640 The default is C<NULL> unless overridden by setting
641 C<LIBGUESTFS_APPEND> environment variable.
642
643 Setting C<append> to C<NULL> means I<no> additional options
644 are passed (libguestfs always adds a few of its own).");
645
646   ("get_append", (RConstOptString "append", []), -1, [],
647    (* This cannot be tested with the current framework.  The
648     * function can return NULL in normal operations, which the
649     * test framework interprets as an error.
650     *)
651    [],
652    "get the additional kernel options",
653    "\
654 Return the additional kernel options which are added to the
655 guest kernel command line.
656
657 If C<NULL> then no options are added.");
658
659   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
660    [],
661    "set autosync mode",
662    "\
663 If C<autosync> is true, this enables autosync.  Libguestfs will make a
664 best effort attempt to run C<guestfs_umount_all> followed by
665 C<guestfs_sync> when the handle is closed
666 (also if the program exits without closing handles).
667
668 This is disabled by default (except in guestfish where it is
669 enabled by default).");
670
671   ("get_autosync", (RBool "autosync", []), -1, [],
672    [InitNone, Always, TestRun (
673       [["get_autosync"]])],
674    "get autosync mode",
675    "\
676 Get the autosync flag.");
677
678   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
679    [],
680    "set verbose mode",
681    "\
682 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
683
684 Verbose messages are disabled unless the environment variable
685 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
686
687   ("get_verbose", (RBool "verbose", []), -1, [],
688    [],
689    "get verbose mode",
690    "\
691 This returns the verbose messages flag.");
692
693   ("is_ready", (RBool "ready", []), -1, [],
694    [InitNone, Always, TestOutputTrue (
695       [["is_ready"]])],
696    "is ready to accept commands",
697    "\
698 This returns true iff this handle is ready to accept commands
699 (in the C<READY> state).
700
701 For more information on states, see L<guestfs(3)>.");
702
703   ("is_config", (RBool "config", []), -1, [],
704    [InitNone, Always, TestOutputFalse (
705       [["is_config"]])],
706    "is in configuration state",
707    "\
708 This returns true iff this handle is being configured
709 (in the C<CONFIG> state).
710
711 For more information on states, see L<guestfs(3)>.");
712
713   ("is_launching", (RBool "launching", []), -1, [],
714    [InitNone, Always, TestOutputFalse (
715       [["is_launching"]])],
716    "is launching subprocess",
717    "\
718 This returns true iff this handle is launching the subprocess
719 (in the C<LAUNCHING> state).
720
721 For more information on states, see L<guestfs(3)>.");
722
723   ("is_busy", (RBool "busy", []), -1, [],
724    [InitNone, Always, TestOutputFalse (
725       [["is_busy"]])],
726    "is busy processing a command",
727    "\
728 This returns true iff this handle is busy processing a command
729 (in the C<BUSY> state).
730
731 For more information on states, see L<guestfs(3)>.");
732
733   ("get_state", (RInt "state", []), -1, [],
734    [],
735    "get the current state",
736    "\
737 This returns the current state as an opaque integer.  This is
738 only useful for printing debug and internal error messages.
739
740 For more information on states, see L<guestfs(3)>.");
741
742   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
743    [InitNone, Always, TestOutputInt (
744       [["set_memsize"; "500"];
745        ["get_memsize"]], 500)],
746    "set memory allocated to the qemu subprocess",
747    "\
748 This sets the memory size in megabytes allocated to the
749 qemu subprocess.  This only has any effect if called before
750 C<guestfs_launch>.
751
752 You can also change this by setting the environment
753 variable C<LIBGUESTFS_MEMSIZE> before the handle is
754 created.
755
756 For more information on the architecture of libguestfs,
757 see L<guestfs(3)>.");
758
759   ("get_memsize", (RInt "memsize", []), -1, [],
760    [InitNone, Always, TestOutputIntOp (
761       [["get_memsize"]], ">=", 256)],
762    "get memory allocated to the qemu subprocess",
763    "\
764 This gets the memory size in megabytes allocated to the
765 qemu subprocess.
766
767 If C<guestfs_set_memsize> was not called
768 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
769 then this returns the compiled-in default value for memsize.
770
771 For more information on the architecture of libguestfs,
772 see L<guestfs(3)>.");
773
774   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
775    [InitNone, Always, TestOutputIntOp (
776       [["get_pid"]], ">=", 1)],
777    "get PID of qemu subprocess",
778    "\
779 Return the process ID of the qemu subprocess.  If there is no
780 qemu subprocess, then this will return an error.
781
782 This is an internal call used for debugging and testing.");
783
784   ("version", (RStruct ("version", "version"), []), -1, [],
785    [InitNone, Always, TestOutputStruct (
786       [["version"]], [CompareWithInt ("major", 1)])],
787    "get the library version number",
788    "\
789 Return the libguestfs version number that the program is linked
790 against.
791
792 Note that because of dynamic linking this is not necessarily
793 the version of libguestfs that you compiled against.  You can
794 compile the program, and then at runtime dynamically link
795 against a completely different C<libguestfs.so> library.
796
797 This call was added in version C<1.0.58>.  In previous
798 versions of libguestfs there was no way to get the version
799 number.  From C code you can use ELF weak linking tricks to find out if
800 this symbol exists (if it doesn't, then it's an earlier version).
801
802 The call returns a structure with four elements.  The first
803 three (C<major>, C<minor> and C<release>) are numbers and
804 correspond to the usual version triplet.  The fourth element
805 (C<extra>) is a string and is normally empty, but may be
806 used for distro-specific information.
807
808 To construct the original version string:
809 C<$major.$minor.$release$extra>
810
811 I<Note:> Don't use this call to test for availability
812 of features.  Distro backports makes this unreliable.  Use
813 C<guestfs_available> instead.");
814
815   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
816    [InitNone, Always, TestOutputTrue (
817       [["set_selinux"; "true"];
818        ["get_selinux"]])],
819    "set SELinux enabled or disabled at appliance boot",
820    "\
821 This sets the selinux flag that is passed to the appliance
822 at boot time.  The default is C<selinux=0> (disabled).
823
824 Note that if SELinux is enabled, it is always in
825 Permissive mode (C<enforcing=0>).
826
827 For more information on the architecture of libguestfs,
828 see L<guestfs(3)>.");
829
830   ("get_selinux", (RBool "selinux", []), -1, [],
831    [],
832    "get SELinux enabled flag",
833    "\
834 This returns the current setting of the selinux flag which
835 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
836
837 For more information on the architecture of libguestfs,
838 see L<guestfs(3)>.");
839
840   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
841    [InitNone, Always, TestOutputFalse (
842       [["set_trace"; "false"];
843        ["get_trace"]])],
844    "enable or disable command traces",
845    "\
846 If the command trace flag is set to 1, then commands are
847 printed on stdout before they are executed in a format
848 which is very similar to the one used by guestfish.  In
849 other words, you can run a program with this enabled, and
850 you will get out a script which you can feed to guestfish
851 to perform the same set of actions.
852
853 If you want to trace C API calls into libguestfs (and
854 other libraries) then possibly a better way is to use
855 the external ltrace(1) command.
856
857 Command traces are disabled unless the environment variable
858 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
859
860   ("get_trace", (RBool "trace", []), -1, [],
861    [],
862    "get command trace enabled flag",
863    "\
864 Return the command trace flag.");
865
866   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
867    [InitNone, Always, TestOutputFalse (
868       [["set_direct"; "false"];
869        ["get_direct"]])],
870    "enable or disable direct appliance mode",
871    "\
872 If the direct appliance mode flag is enabled, then stdin and
873 stdout are passed directly through to the appliance once it
874 is launched.
875
876 One consequence of this is that log messages aren't caught
877 by the library and handled by C<guestfs_set_log_message_callback>,
878 but go straight to stdout.
879
880 You probably don't want to use this unless you know what you
881 are doing.
882
883 The default is disabled.");
884
885   ("get_direct", (RBool "direct", []), -1, [],
886    [],
887    "get direct appliance mode flag",
888    "\
889 Return the direct appliance mode flag.");
890
891   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
892    [InitNone, Always, TestOutputTrue (
893       [["set_recovery_proc"; "true"];
894        ["get_recovery_proc"]])],
895    "enable or disable the recovery process",
896    "\
897 If this is called with the parameter C<false> then
898 C<guestfs_launch> does not create a recovery process.  The
899 purpose of the recovery process is to stop runaway qemu
900 processes in the case where the main program aborts abruptly.
901
902 This only has any effect if called before C<guestfs_launch>,
903 and the default is true.
904
905 About the only time when you would want to disable this is
906 if the main process will fork itself into the background
907 (\"daemonize\" itself).  In this case the recovery process
908 thinks that the main program has disappeared and so kills
909 qemu, which is not very helpful.");
910
911   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
912    [],
913    "get recovery process enabled flag",
914    "\
915 Return the recovery process enabled flag.");
916
917   ("add_drive_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
918    [],
919    "add a drive specifying the QEMU block emulation to use",
920    "\
921 This is the same as C<guestfs_add_drive> but it allows you
922 to specify the QEMU interface emulation to use at run time.");
923
924   ("add_drive_ro_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
925    [],
926    "add a drive read-only specifying the QEMU block emulation to use",
927    "\
928 This is the same as C<guestfs_add_drive_ro> but it allows you
929 to specify the QEMU interface emulation to use at run time.");
930
931 ]
932
933 (* daemon_functions are any functions which cause some action
934  * to take place in the daemon.
935  *)
936
937 let daemon_functions = [
938   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
939    [InitEmpty, Always, TestOutput (
940       [["part_disk"; "/dev/sda"; "mbr"];
941        ["mkfs"; "ext2"; "/dev/sda1"];
942        ["mount"; "/dev/sda1"; "/"];
943        ["write_file"; "/new"; "new file contents"; "0"];
944        ["cat"; "/new"]], "new file contents")],
945    "mount a guest disk at a position in the filesystem",
946    "\
947 Mount a guest disk at a position in the filesystem.  Block devices
948 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
949 the guest.  If those block devices contain partitions, they will have
950 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
951 names can be used.
952
953 The rules are the same as for L<mount(2)>:  A filesystem must
954 first be mounted on C</> before others can be mounted.  Other
955 filesystems can only be mounted on directories which already
956 exist.
957
958 The mounted filesystem is writable, if we have sufficient permissions
959 on the underlying device.
960
961 B<Important note:>
962 When you use this call, the filesystem options C<sync> and C<noatime>
963 are set implicitly.  This was originally done because we thought it
964 would improve reliability, but it turns out that I<-o sync> has a
965 very large negative performance impact and negligible effect on
966 reliability.  Therefore we recommend that you avoid using
967 C<guestfs_mount> in any code that needs performance, and instead
968 use C<guestfs_mount_options> (use an empty string for the first
969 parameter if you don't want any options).");
970
971   ("sync", (RErr, []), 2, [],
972    [ InitEmpty, Always, TestRun [["sync"]]],
973    "sync disks, writes are flushed through to the disk image",
974    "\
975 This syncs the disk, so that any writes are flushed through to the
976 underlying disk image.
977
978 You should always call this if you have modified a disk image, before
979 closing the handle.");
980
981   ("touch", (RErr, [Pathname "path"]), 3, [],
982    [InitBasicFS, Always, TestOutputTrue (
983       [["touch"; "/new"];
984        ["exists"; "/new"]])],
985    "update file timestamps or create a new file",
986    "\
987 Touch acts like the L<touch(1)> command.  It can be used to
988 update the timestamps on a file, or, if the file does not exist,
989 to create a new zero-length file.");
990
991   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
992    [InitISOFS, Always, TestOutput (
993       [["cat"; "/known-2"]], "abcdef\n")],
994    "list the contents of a file",
995    "\
996 Return the contents of the file named C<path>.
997
998 Note that this function cannot correctly handle binary files
999 (specifically, files containing C<\\0> character which is treated
1000 as end of string).  For those you need to use the C<guestfs_read_file>
1001 or C<guestfs_download> functions which have a more complex interface.");
1002
1003   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
1004    [], (* XXX Tricky to test because it depends on the exact format
1005         * of the 'ls -l' command, which changes between F10 and F11.
1006         *)
1007    "list the files in a directory (long format)",
1008    "\
1009 List the files in C<directory> (relative to the root directory,
1010 there is no cwd) in the format of 'ls -la'.
1011
1012 This command is mostly useful for interactive sessions.  It
1013 is I<not> intended that you try to parse the output string.");
1014
1015   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
1016    [InitBasicFS, Always, TestOutputList (
1017       [["touch"; "/new"];
1018        ["touch"; "/newer"];
1019        ["touch"; "/newest"];
1020        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
1021    "list the files in a directory",
1022    "\
1023 List the files in C<directory> (relative to the root directory,
1024 there is no cwd).  The '.' and '..' entries are not returned, but
1025 hidden files are shown.
1026
1027 This command is mostly useful for interactive sessions.  Programs
1028 should probably use C<guestfs_readdir> instead.");
1029
1030   ("list_devices", (RStringList "devices", []), 7, [],
1031    [InitEmpty, Always, TestOutputListOfDevices (
1032       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
1033    "list the block devices",
1034    "\
1035 List all the block devices.
1036
1037 The full block device names are returned, eg. C</dev/sda>");
1038
1039   ("list_partitions", (RStringList "partitions", []), 8, [],
1040    [InitBasicFS, Always, TestOutputListOfDevices (
1041       [["list_partitions"]], ["/dev/sda1"]);
1042     InitEmpty, Always, TestOutputListOfDevices (
1043       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1044        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1045    "list the partitions",
1046    "\
1047 List all the partitions detected on all block devices.
1048
1049 The full partition device names are returned, eg. C</dev/sda1>
1050
1051 This does not return logical volumes.  For that you will need to
1052 call C<guestfs_lvs>.");
1053
1054   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
1055    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
1056       [["pvs"]], ["/dev/sda1"]);
1057     InitEmpty, Always, TestOutputListOfDevices (
1058       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1059        ["pvcreate"; "/dev/sda1"];
1060        ["pvcreate"; "/dev/sda2"];
1061        ["pvcreate"; "/dev/sda3"];
1062        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1063    "list the LVM physical volumes (PVs)",
1064    "\
1065 List all the physical volumes detected.  This is the equivalent
1066 of the L<pvs(8)> command.
1067
1068 This returns a list of just the device names that contain
1069 PVs (eg. C</dev/sda2>).
1070
1071 See also C<guestfs_pvs_full>.");
1072
1073   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1074    [InitBasicFSonLVM, Always, TestOutputList (
1075       [["vgs"]], ["VG"]);
1076     InitEmpty, Always, TestOutputList (
1077       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1078        ["pvcreate"; "/dev/sda1"];
1079        ["pvcreate"; "/dev/sda2"];
1080        ["pvcreate"; "/dev/sda3"];
1081        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1082        ["vgcreate"; "VG2"; "/dev/sda3"];
1083        ["vgs"]], ["VG1"; "VG2"])],
1084    "list the LVM volume groups (VGs)",
1085    "\
1086 List all the volumes groups detected.  This is the equivalent
1087 of the L<vgs(8)> command.
1088
1089 This returns a list of just the volume group names that were
1090 detected (eg. C<VolGroup00>).
1091
1092 See also C<guestfs_vgs_full>.");
1093
1094   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1095    [InitBasicFSonLVM, Always, TestOutputList (
1096       [["lvs"]], ["/dev/VG/LV"]);
1097     InitEmpty, Always, TestOutputList (
1098       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1099        ["pvcreate"; "/dev/sda1"];
1100        ["pvcreate"; "/dev/sda2"];
1101        ["pvcreate"; "/dev/sda3"];
1102        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1103        ["vgcreate"; "VG2"; "/dev/sda3"];
1104        ["lvcreate"; "LV1"; "VG1"; "50"];
1105        ["lvcreate"; "LV2"; "VG1"; "50"];
1106        ["lvcreate"; "LV3"; "VG2"; "50"];
1107        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1108    "list the LVM logical volumes (LVs)",
1109    "\
1110 List all the logical volumes detected.  This is the equivalent
1111 of the L<lvs(8)> command.
1112
1113 This returns a list of the logical volume device names
1114 (eg. C</dev/VolGroup00/LogVol00>).
1115
1116 See also C<guestfs_lvs_full>.");
1117
1118   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1119    [], (* XXX how to test? *)
1120    "list the LVM physical volumes (PVs)",
1121    "\
1122 List all the physical volumes detected.  This is the equivalent
1123 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1124
1125   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1126    [], (* XXX how to test? *)
1127    "list the LVM volume groups (VGs)",
1128    "\
1129 List all the volumes groups detected.  This is the equivalent
1130 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1131
1132   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1133    [], (* XXX how to test? *)
1134    "list the LVM logical volumes (LVs)",
1135    "\
1136 List all the logical volumes detected.  This is the equivalent
1137 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1138
1139   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1140    [InitISOFS, Always, TestOutputList (
1141       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1142     InitISOFS, Always, TestOutputList (
1143       [["read_lines"; "/empty"]], [])],
1144    "read file as lines",
1145    "\
1146 Return the contents of the file named C<path>.
1147
1148 The file contents are returned as a list of lines.  Trailing
1149 C<LF> and C<CRLF> character sequences are I<not> returned.
1150
1151 Note that this function cannot correctly handle binary files
1152 (specifically, files containing C<\\0> character which is treated
1153 as end of line).  For those you need to use the C<guestfs_read_file>
1154 function which has a more complex interface.");
1155
1156   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1157    [], (* XXX Augeas code needs tests. *)
1158    "create a new Augeas handle",
1159    "\
1160 Create a new Augeas handle for editing configuration files.
1161 If there was any previous Augeas handle associated with this
1162 guestfs session, then it is closed.
1163
1164 You must call this before using any other C<guestfs_aug_*>
1165 commands.
1166
1167 C<root> is the filesystem root.  C<root> must not be NULL,
1168 use C</> instead.
1169
1170 The flags are the same as the flags defined in
1171 E<lt>augeas.hE<gt>, the logical I<or> of the following
1172 integers:
1173
1174 =over 4
1175
1176 =item C<AUG_SAVE_BACKUP> = 1
1177
1178 Keep the original file with a C<.augsave> extension.
1179
1180 =item C<AUG_SAVE_NEWFILE> = 2
1181
1182 Save changes into a file with extension C<.augnew>, and
1183 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1184
1185 =item C<AUG_TYPE_CHECK> = 4
1186
1187 Typecheck lenses (can be expensive).
1188
1189 =item C<AUG_NO_STDINC> = 8
1190
1191 Do not use standard load path for modules.
1192
1193 =item C<AUG_SAVE_NOOP> = 16
1194
1195 Make save a no-op, just record what would have been changed.
1196
1197 =item C<AUG_NO_LOAD> = 32
1198
1199 Do not load the tree in C<guestfs_aug_init>.
1200
1201 =back
1202
1203 To close the handle, you can call C<guestfs_aug_close>.
1204
1205 To find out more about Augeas, see L<http://augeas.net/>.");
1206
1207   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1208    [], (* XXX Augeas code needs tests. *)
1209    "close the current Augeas handle",
1210    "\
1211 Close the current Augeas handle and free up any resources
1212 used by it.  After calling this, you have to call
1213 C<guestfs_aug_init> again before you can use any other
1214 Augeas functions.");
1215
1216   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1217    [], (* XXX Augeas code needs tests. *)
1218    "define an Augeas variable",
1219    "\
1220 Defines an Augeas variable C<name> whose value is the result
1221 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1222 undefined.
1223
1224 On success this returns the number of nodes in C<expr>, or
1225 C<0> if C<expr> evaluates to something which is not a nodeset.");
1226
1227   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1228    [], (* XXX Augeas code needs tests. *)
1229    "define an Augeas node",
1230    "\
1231 Defines a variable C<name> whose value is the result of
1232 evaluating C<expr>.
1233
1234 If C<expr> evaluates to an empty nodeset, a node is created,
1235 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1236 C<name> will be the nodeset containing that single node.
1237
1238 On success this returns a pair containing the
1239 number of nodes in the nodeset, and a boolean flag
1240 if a node was created.");
1241
1242   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1243    [], (* XXX Augeas code needs tests. *)
1244    "look up the value of an Augeas path",
1245    "\
1246 Look up the value associated with C<path>.  If C<path>
1247 matches exactly one node, the C<value> is returned.");
1248
1249   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1250    [], (* XXX Augeas code needs tests. *)
1251    "set Augeas path to value",
1252    "\
1253 Set the value associated with C<path> to C<val>.
1254
1255 In the Augeas API, it is possible to clear a node by setting
1256 the value to NULL.  Due to an oversight in the libguestfs API
1257 you cannot do that with this call.  Instead you must use the
1258 C<guestfs_aug_clear> call.");
1259
1260   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1261    [], (* XXX Augeas code needs tests. *)
1262    "insert a sibling Augeas node",
1263    "\
1264 Create a new sibling C<label> for C<path>, inserting it into
1265 the tree before or after C<path> (depending on the boolean
1266 flag C<before>).
1267
1268 C<path> must match exactly one existing node in the tree, and
1269 C<label> must be a label, ie. not contain C</>, C<*> or end
1270 with a bracketed index C<[N]>.");
1271
1272   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1273    [], (* XXX Augeas code needs tests. *)
1274    "remove an Augeas path",
1275    "\
1276 Remove C<path> and all of its children.
1277
1278 On success this returns the number of entries which were removed.");
1279
1280   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1281    [], (* XXX Augeas code needs tests. *)
1282    "move Augeas node",
1283    "\
1284 Move the node C<src> to C<dest>.  C<src> must match exactly
1285 one node.  C<dest> is overwritten if it exists.");
1286
1287   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1288    [], (* XXX Augeas code needs tests. *)
1289    "return Augeas nodes which match augpath",
1290    "\
1291 Returns a list of paths which match the path expression C<path>.
1292 The returned paths are sufficiently qualified so that they match
1293 exactly one node in the current tree.");
1294
1295   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1296    [], (* XXX Augeas code needs tests. *)
1297    "write all pending Augeas changes to disk",
1298    "\
1299 This writes all pending changes to disk.
1300
1301 The flags which were passed to C<guestfs_aug_init> affect exactly
1302 how files are saved.");
1303
1304   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1305    [], (* XXX Augeas code needs tests. *)
1306    "load files into the tree",
1307    "\
1308 Load files into the tree.
1309
1310 See C<aug_load> in the Augeas documentation for the full gory
1311 details.");
1312
1313   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1314    [], (* XXX Augeas code needs tests. *)
1315    "list Augeas nodes under augpath",
1316    "\
1317 This is just a shortcut for listing C<guestfs_aug_match>
1318 C<path/*> and sorting the resulting nodes into alphabetical order.");
1319
1320   ("rm", (RErr, [Pathname "path"]), 29, [],
1321    [InitBasicFS, Always, TestRun
1322       [["touch"; "/new"];
1323        ["rm"; "/new"]];
1324     InitBasicFS, Always, TestLastFail
1325       [["rm"; "/new"]];
1326     InitBasicFS, Always, TestLastFail
1327       [["mkdir"; "/new"];
1328        ["rm"; "/new"]]],
1329    "remove a file",
1330    "\
1331 Remove the single file C<path>.");
1332
1333   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1334    [InitBasicFS, Always, TestRun
1335       [["mkdir"; "/new"];
1336        ["rmdir"; "/new"]];
1337     InitBasicFS, Always, TestLastFail
1338       [["rmdir"; "/new"]];
1339     InitBasicFS, Always, TestLastFail
1340       [["touch"; "/new"];
1341        ["rmdir"; "/new"]]],
1342    "remove a directory",
1343    "\
1344 Remove the single directory C<path>.");
1345
1346   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1347    [InitBasicFS, Always, TestOutputFalse
1348       [["mkdir"; "/new"];
1349        ["mkdir"; "/new/foo"];
1350        ["touch"; "/new/foo/bar"];
1351        ["rm_rf"; "/new"];
1352        ["exists"; "/new"]]],
1353    "remove a file or directory recursively",
1354    "\
1355 Remove the file or directory C<path>, recursively removing the
1356 contents if its a directory.  This is like the C<rm -rf> shell
1357 command.");
1358
1359   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1360    [InitBasicFS, Always, TestOutputTrue
1361       [["mkdir"; "/new"];
1362        ["is_dir"; "/new"]];
1363     InitBasicFS, Always, TestLastFail
1364       [["mkdir"; "/new/foo/bar"]]],
1365    "create a directory",
1366    "\
1367 Create a directory named C<path>.");
1368
1369   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1370    [InitBasicFS, Always, TestOutputTrue
1371       [["mkdir_p"; "/new/foo/bar"];
1372        ["is_dir"; "/new/foo/bar"]];
1373     InitBasicFS, Always, TestOutputTrue
1374       [["mkdir_p"; "/new/foo/bar"];
1375        ["is_dir"; "/new/foo"]];
1376     InitBasicFS, Always, TestOutputTrue
1377       [["mkdir_p"; "/new/foo/bar"];
1378        ["is_dir"; "/new"]];
1379     (* Regression tests for RHBZ#503133: *)
1380     InitBasicFS, Always, TestRun
1381       [["mkdir"; "/new"];
1382        ["mkdir_p"; "/new"]];
1383     InitBasicFS, Always, TestLastFail
1384       [["touch"; "/new"];
1385        ["mkdir_p"; "/new"]]],
1386    "create a directory and parents",
1387    "\
1388 Create a directory named C<path>, creating any parent directories
1389 as necessary.  This is like the C<mkdir -p> shell command.");
1390
1391   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1392    [], (* XXX Need stat command to test *)
1393    "change file mode",
1394    "\
1395 Change the mode (permissions) of C<path> to C<mode>.  Only
1396 numeric modes are supported.
1397
1398 I<Note>: When using this command from guestfish, C<mode>
1399 by default would be decimal, unless you prefix it with
1400 C<0> to get octal, ie. use C<0700> not C<700>.
1401
1402 The mode actually set is affected by the umask.");
1403
1404   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1405    [], (* XXX Need stat command to test *)
1406    "change file owner and group",
1407    "\
1408 Change the file owner to C<owner> and group to C<group>.
1409
1410 Only numeric uid and gid are supported.  If you want to use
1411 names, you will need to locate and parse the password file
1412 yourself (Augeas support makes this relatively easy).");
1413
1414   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1415    [InitISOFS, Always, TestOutputTrue (
1416       [["exists"; "/empty"]]);
1417     InitISOFS, Always, TestOutputTrue (
1418       [["exists"; "/directory"]])],
1419    "test if file or directory exists",
1420    "\
1421 This returns C<true> if and only if there is a file, directory
1422 (or anything) with the given C<path> name.
1423
1424 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1425
1426   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1427    [InitISOFS, Always, TestOutputTrue (
1428       [["is_file"; "/known-1"]]);
1429     InitISOFS, Always, TestOutputFalse (
1430       [["is_file"; "/directory"]])],
1431    "test if file exists",
1432    "\
1433 This returns C<true> if and only if there is a file
1434 with the given C<path> name.  Note that it returns false for
1435 other objects like directories.
1436
1437 See also C<guestfs_stat>.");
1438
1439   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1440    [InitISOFS, Always, TestOutputFalse (
1441       [["is_dir"; "/known-3"]]);
1442     InitISOFS, Always, TestOutputTrue (
1443       [["is_dir"; "/directory"]])],
1444    "test if file exists",
1445    "\
1446 This returns C<true> if and only if there is a directory
1447 with the given C<path> name.  Note that it returns false for
1448 other objects like files.
1449
1450 See also C<guestfs_stat>.");
1451
1452   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1453    [InitEmpty, Always, TestOutputListOfDevices (
1454       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1455        ["pvcreate"; "/dev/sda1"];
1456        ["pvcreate"; "/dev/sda2"];
1457        ["pvcreate"; "/dev/sda3"];
1458        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1459    "create an LVM physical volume",
1460    "\
1461 This creates an LVM physical volume on the named C<device>,
1462 where C<device> should usually be a partition name such
1463 as C</dev/sda1>.");
1464
1465   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1466    [InitEmpty, Always, TestOutputList (
1467       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1468        ["pvcreate"; "/dev/sda1"];
1469        ["pvcreate"; "/dev/sda2"];
1470        ["pvcreate"; "/dev/sda3"];
1471        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1472        ["vgcreate"; "VG2"; "/dev/sda3"];
1473        ["vgs"]], ["VG1"; "VG2"])],
1474    "create an LVM volume group",
1475    "\
1476 This creates an LVM volume group called C<volgroup>
1477 from the non-empty list of physical volumes C<physvols>.");
1478
1479   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1480    [InitEmpty, Always, TestOutputList (
1481       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1482        ["pvcreate"; "/dev/sda1"];
1483        ["pvcreate"; "/dev/sda2"];
1484        ["pvcreate"; "/dev/sda3"];
1485        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1486        ["vgcreate"; "VG2"; "/dev/sda3"];
1487        ["lvcreate"; "LV1"; "VG1"; "50"];
1488        ["lvcreate"; "LV2"; "VG1"; "50"];
1489        ["lvcreate"; "LV3"; "VG2"; "50"];
1490        ["lvcreate"; "LV4"; "VG2"; "50"];
1491        ["lvcreate"; "LV5"; "VG2"; "50"];
1492        ["lvs"]],
1493       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1494        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1495    "create an LVM logical volume",
1496    "\
1497 This creates an LVM logical volume called C<logvol>
1498 on the volume group C<volgroup>, with C<size> megabytes.");
1499
1500   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1501    [InitEmpty, Always, TestOutput (
1502       [["part_disk"; "/dev/sda"; "mbr"];
1503        ["mkfs"; "ext2"; "/dev/sda1"];
1504        ["mount_options"; ""; "/dev/sda1"; "/"];
1505        ["write_file"; "/new"; "new file contents"; "0"];
1506        ["cat"; "/new"]], "new file contents")],
1507    "make a filesystem",
1508    "\
1509 This creates a filesystem on C<device> (usually a partition
1510 or LVM logical volume).  The filesystem type is C<fstype>, for
1511 example C<ext3>.");
1512
1513   ("sfdisk", (RErr, [Device "device";
1514                      Int "cyls"; Int "heads"; Int "sectors";
1515                      StringList "lines"]), 43, [DangerWillRobinson],
1516    [],
1517    "create partitions on a block device",
1518    "\
1519 This is a direct interface to the L<sfdisk(8)> program for creating
1520 partitions on block devices.
1521
1522 C<device> should be a block device, for example C</dev/sda>.
1523
1524 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1525 and sectors on the device, which are passed directly to sfdisk as
1526 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1527 of these, then the corresponding parameter is omitted.  Usually for
1528 'large' disks, you can just pass C<0> for these, but for small
1529 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1530 out the right geometry and you will need to tell it.
1531
1532 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1533 information refer to the L<sfdisk(8)> manpage.
1534
1535 To create a single partition occupying the whole disk, you would
1536 pass C<lines> as a single element list, when the single element being
1537 the string C<,> (comma).
1538
1539 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1540 C<guestfs_part_init>");
1541
1542   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1543    [InitBasicFS, Always, TestOutput (
1544       [["write_file"; "/new"; "new file contents"; "0"];
1545        ["cat"; "/new"]], "new file contents");
1546     InitBasicFS, Always, TestOutput (
1547       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1548        ["cat"; "/new"]], "\nnew file contents\n");
1549     InitBasicFS, Always, TestOutput (
1550       [["write_file"; "/new"; "\n\n"; "0"];
1551        ["cat"; "/new"]], "\n\n");
1552     InitBasicFS, Always, TestOutput (
1553       [["write_file"; "/new"; ""; "0"];
1554        ["cat"; "/new"]], "");
1555     InitBasicFS, Always, TestOutput (
1556       [["write_file"; "/new"; "\n\n\n"; "0"];
1557        ["cat"; "/new"]], "\n\n\n");
1558     InitBasicFS, Always, TestOutput (
1559       [["write_file"; "/new"; "\n"; "0"];
1560        ["cat"; "/new"]], "\n")],
1561    "create a file",
1562    "\
1563 This call creates a file called C<path>.  The contents of the
1564 file is the string C<content> (which can contain any 8 bit data),
1565 with length C<size>.
1566
1567 As a special case, if C<size> is C<0>
1568 then the length is calculated using C<strlen> (so in this case
1569 the content cannot contain embedded ASCII NULs).
1570
1571 I<NB.> Owing to a bug, writing content containing ASCII NUL
1572 characters does I<not> work, even if the length is specified.
1573 We hope to resolve this bug in a future version.  In the meantime
1574 use C<guestfs_upload>.");
1575
1576   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1577    [InitEmpty, Always, TestOutputListOfDevices (
1578       [["part_disk"; "/dev/sda"; "mbr"];
1579        ["mkfs"; "ext2"; "/dev/sda1"];
1580        ["mount_options"; ""; "/dev/sda1"; "/"];
1581        ["mounts"]], ["/dev/sda1"]);
1582     InitEmpty, Always, TestOutputList (
1583       [["part_disk"; "/dev/sda"; "mbr"];
1584        ["mkfs"; "ext2"; "/dev/sda1"];
1585        ["mount_options"; ""; "/dev/sda1"; "/"];
1586        ["umount"; "/"];
1587        ["mounts"]], [])],
1588    "unmount a filesystem",
1589    "\
1590 This unmounts the given filesystem.  The filesystem may be
1591 specified either by its mountpoint (path) or the device which
1592 contains the filesystem.");
1593
1594   ("mounts", (RStringList "devices", []), 46, [],
1595    [InitBasicFS, Always, TestOutputListOfDevices (
1596       [["mounts"]], ["/dev/sda1"])],
1597    "show mounted filesystems",
1598    "\
1599 This returns the list of currently mounted filesystems.  It returns
1600 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1601
1602 Some internal mounts are not shown.
1603
1604 See also: C<guestfs_mountpoints>");
1605
1606   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1607    [InitBasicFS, Always, TestOutputList (
1608       [["umount_all"];
1609        ["mounts"]], []);
1610     (* check that umount_all can unmount nested mounts correctly: *)
1611     InitEmpty, Always, TestOutputList (
1612       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1613        ["mkfs"; "ext2"; "/dev/sda1"];
1614        ["mkfs"; "ext2"; "/dev/sda2"];
1615        ["mkfs"; "ext2"; "/dev/sda3"];
1616        ["mount_options"; ""; "/dev/sda1"; "/"];
1617        ["mkdir"; "/mp1"];
1618        ["mount_options"; ""; "/dev/sda2"; "/mp1"];
1619        ["mkdir"; "/mp1/mp2"];
1620        ["mount_options"; ""; "/dev/sda3"; "/mp1/mp2"];
1621        ["mkdir"; "/mp1/mp2/mp3"];
1622        ["umount_all"];
1623        ["mounts"]], [])],
1624    "unmount all filesystems",
1625    "\
1626 This unmounts all mounted filesystems.
1627
1628 Some internal mounts are not unmounted by this call.");
1629
1630   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1631    [],
1632    "remove all LVM LVs, VGs and PVs",
1633    "\
1634 This command removes all LVM logical volumes, volume groups
1635 and physical volumes.");
1636
1637   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1638    [InitISOFS, Always, TestOutput (
1639       [["file"; "/empty"]], "empty");
1640     InitISOFS, Always, TestOutput (
1641       [["file"; "/known-1"]], "ASCII text");
1642     InitISOFS, Always, TestLastFail (
1643       [["file"; "/notexists"]])],
1644    "determine file type",
1645    "\
1646 This call uses the standard L<file(1)> command to determine
1647 the type or contents of the file.  This also works on devices,
1648 for example to find out whether a partition contains a filesystem.
1649
1650 This call will also transparently look inside various types
1651 of compressed file.
1652
1653 The exact command which runs is C<file -zbsL path>.  Note in
1654 particular that the filename is not prepended to the output
1655 (the C<-b> option).");
1656
1657   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1658    [InitBasicFS, Always, TestOutput (
1659       [["upload"; "test-command"; "/test-command"];
1660        ["chmod"; "0o755"; "/test-command"];
1661        ["command"; "/test-command 1"]], "Result1");
1662     InitBasicFS, Always, TestOutput (
1663       [["upload"; "test-command"; "/test-command"];
1664        ["chmod"; "0o755"; "/test-command"];
1665        ["command"; "/test-command 2"]], "Result2\n");
1666     InitBasicFS, Always, TestOutput (
1667       [["upload"; "test-command"; "/test-command"];
1668        ["chmod"; "0o755"; "/test-command"];
1669        ["command"; "/test-command 3"]], "\nResult3");
1670     InitBasicFS, Always, TestOutput (
1671       [["upload"; "test-command"; "/test-command"];
1672        ["chmod"; "0o755"; "/test-command"];
1673        ["command"; "/test-command 4"]], "\nResult4\n");
1674     InitBasicFS, Always, TestOutput (
1675       [["upload"; "test-command"; "/test-command"];
1676        ["chmod"; "0o755"; "/test-command"];
1677        ["command"; "/test-command 5"]], "\nResult5\n\n");
1678     InitBasicFS, Always, TestOutput (
1679       [["upload"; "test-command"; "/test-command"];
1680        ["chmod"; "0o755"; "/test-command"];
1681        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1682     InitBasicFS, Always, TestOutput (
1683       [["upload"; "test-command"; "/test-command"];
1684        ["chmod"; "0o755"; "/test-command"];
1685        ["command"; "/test-command 7"]], "");
1686     InitBasicFS, Always, TestOutput (
1687       [["upload"; "test-command"; "/test-command"];
1688        ["chmod"; "0o755"; "/test-command"];
1689        ["command"; "/test-command 8"]], "\n");
1690     InitBasicFS, Always, TestOutput (
1691       [["upload"; "test-command"; "/test-command"];
1692        ["chmod"; "0o755"; "/test-command"];
1693        ["command"; "/test-command 9"]], "\n\n");
1694     InitBasicFS, Always, TestOutput (
1695       [["upload"; "test-command"; "/test-command"];
1696        ["chmod"; "0o755"; "/test-command"];
1697        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1698     InitBasicFS, Always, TestOutput (
1699       [["upload"; "test-command"; "/test-command"];
1700        ["chmod"; "0o755"; "/test-command"];
1701        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1702     InitBasicFS, Always, TestLastFail (
1703       [["upload"; "test-command"; "/test-command"];
1704        ["chmod"; "0o755"; "/test-command"];
1705        ["command"; "/test-command"]])],
1706    "run a command from the guest filesystem",
1707    "\
1708 This call runs a command from the guest filesystem.  The
1709 filesystem must be mounted, and must contain a compatible
1710 operating system (ie. something Linux, with the same
1711 or compatible processor architecture).
1712
1713 The single parameter is an argv-style list of arguments.
1714 The first element is the name of the program to run.
1715 Subsequent elements are parameters.  The list must be
1716 non-empty (ie. must contain a program name).  Note that
1717 the command runs directly, and is I<not> invoked via
1718 the shell (see C<guestfs_sh>).
1719
1720 The return value is anything printed to I<stdout> by
1721 the command.
1722
1723 If the command returns a non-zero exit status, then
1724 this function returns an error message.  The error message
1725 string is the content of I<stderr> from the command.
1726
1727 The C<$PATH> environment variable will contain at least
1728 C</usr/bin> and C</bin>.  If you require a program from
1729 another location, you should provide the full path in the
1730 first parameter.
1731
1732 Shared libraries and data files required by the program
1733 must be available on filesystems which are mounted in the
1734 correct places.  It is the caller's responsibility to ensure
1735 all filesystems that are needed are mounted at the right
1736 locations.");
1737
1738   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1739    [InitBasicFS, Always, TestOutputList (
1740       [["upload"; "test-command"; "/test-command"];
1741        ["chmod"; "0o755"; "/test-command"];
1742        ["command_lines"; "/test-command 1"]], ["Result1"]);
1743     InitBasicFS, Always, TestOutputList (
1744       [["upload"; "test-command"; "/test-command"];
1745        ["chmod"; "0o755"; "/test-command"];
1746        ["command_lines"; "/test-command 2"]], ["Result2"]);
1747     InitBasicFS, Always, TestOutputList (
1748       [["upload"; "test-command"; "/test-command"];
1749        ["chmod"; "0o755"; "/test-command"];
1750        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1751     InitBasicFS, Always, TestOutputList (
1752       [["upload"; "test-command"; "/test-command"];
1753        ["chmod"; "0o755"; "/test-command"];
1754        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1755     InitBasicFS, Always, TestOutputList (
1756       [["upload"; "test-command"; "/test-command"];
1757        ["chmod"; "0o755"; "/test-command"];
1758        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1759     InitBasicFS, Always, TestOutputList (
1760       [["upload"; "test-command"; "/test-command"];
1761        ["chmod"; "0o755"; "/test-command"];
1762        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1763     InitBasicFS, Always, TestOutputList (
1764       [["upload"; "test-command"; "/test-command"];
1765        ["chmod"; "0o755"; "/test-command"];
1766        ["command_lines"; "/test-command 7"]], []);
1767     InitBasicFS, Always, TestOutputList (
1768       [["upload"; "test-command"; "/test-command"];
1769        ["chmod"; "0o755"; "/test-command"];
1770        ["command_lines"; "/test-command 8"]], [""]);
1771     InitBasicFS, Always, TestOutputList (
1772       [["upload"; "test-command"; "/test-command"];
1773        ["chmod"; "0o755"; "/test-command"];
1774        ["command_lines"; "/test-command 9"]], ["";""]);
1775     InitBasicFS, Always, TestOutputList (
1776       [["upload"; "test-command"; "/test-command"];
1777        ["chmod"; "0o755"; "/test-command"];
1778        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1779     InitBasicFS, Always, TestOutputList (
1780       [["upload"; "test-command"; "/test-command"];
1781        ["chmod"; "0o755"; "/test-command"];
1782        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1783    "run a command, returning lines",
1784    "\
1785 This is the same as C<guestfs_command>, but splits the
1786 result into a list of lines.
1787
1788 See also: C<guestfs_sh_lines>");
1789
1790   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1791    [InitISOFS, Always, TestOutputStruct (
1792       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1793    "get file information",
1794    "\
1795 Returns file information for the given C<path>.
1796
1797 This is the same as the C<stat(2)> system call.");
1798
1799   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1800    [InitISOFS, Always, TestOutputStruct (
1801       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1802    "get file information for a symbolic link",
1803    "\
1804 Returns file information for the given C<path>.
1805
1806 This is the same as C<guestfs_stat> except that if C<path>
1807 is a symbolic link, then the link is stat-ed, not the file it
1808 refers to.
1809
1810 This is the same as the C<lstat(2)> system call.");
1811
1812   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1813    [InitISOFS, Always, TestOutputStruct (
1814       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1815    "get file system statistics",
1816    "\
1817 Returns file system statistics for any mounted file system.
1818 C<path> should be a file or directory in the mounted file system
1819 (typically it is the mount point itself, but it doesn't need to be).
1820
1821 This is the same as the C<statvfs(2)> system call.");
1822
1823   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1824    [], (* XXX test *)
1825    "get ext2/ext3/ext4 superblock details",
1826    "\
1827 This returns the contents of the ext2, ext3 or ext4 filesystem
1828 superblock on C<device>.
1829
1830 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1831 manpage for more details.  The list of fields returned isn't
1832 clearly defined, and depends on both the version of C<tune2fs>
1833 that libguestfs was built against, and the filesystem itself.");
1834
1835   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1836    [InitEmpty, Always, TestOutputTrue (
1837       [["blockdev_setro"; "/dev/sda"];
1838        ["blockdev_getro"; "/dev/sda"]])],
1839    "set block device to read-only",
1840    "\
1841 Sets the block device named C<device> to read-only.
1842
1843 This uses the L<blockdev(8)> command.");
1844
1845   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1846    [InitEmpty, Always, TestOutputFalse (
1847       [["blockdev_setrw"; "/dev/sda"];
1848        ["blockdev_getro"; "/dev/sda"]])],
1849    "set block device to read-write",
1850    "\
1851 Sets the block device named C<device> to read-write.
1852
1853 This uses the L<blockdev(8)> command.");
1854
1855   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1856    [InitEmpty, Always, TestOutputTrue (
1857       [["blockdev_setro"; "/dev/sda"];
1858        ["blockdev_getro"; "/dev/sda"]])],
1859    "is block device set to read-only",
1860    "\
1861 Returns a boolean indicating if the block device is read-only
1862 (true if read-only, false if not).
1863
1864 This uses the L<blockdev(8)> command.");
1865
1866   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1867    [InitEmpty, Always, TestOutputInt (
1868       [["blockdev_getss"; "/dev/sda"]], 512)],
1869    "get sectorsize of block device",
1870    "\
1871 This returns the size of sectors on a block device.
1872 Usually 512, but can be larger for modern devices.
1873
1874 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1875 for that).
1876
1877 This uses the L<blockdev(8)> command.");
1878
1879   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1880    [InitEmpty, Always, TestOutputInt (
1881       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1882    "get blocksize of block device",
1883    "\
1884 This returns the block size of a device.
1885
1886 (Note this is different from both I<size in blocks> and
1887 I<filesystem block size>).
1888
1889 This uses the L<blockdev(8)> command.");
1890
1891   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1892    [], (* XXX test *)
1893    "set blocksize of block device",
1894    "\
1895 This sets the block size of a device.
1896
1897 (Note this is different from both I<size in blocks> and
1898 I<filesystem block size>).
1899
1900 This uses the L<blockdev(8)> command.");
1901
1902   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1903    [InitEmpty, Always, TestOutputInt (
1904       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1905    "get total size of device in 512-byte sectors",
1906    "\
1907 This returns the size of the device in units of 512-byte sectors
1908 (even if the sectorsize isn't 512 bytes ... weird).
1909
1910 See also C<guestfs_blockdev_getss> for the real sector size of
1911 the device, and C<guestfs_blockdev_getsize64> for the more
1912 useful I<size in bytes>.
1913
1914 This uses the L<blockdev(8)> command.");
1915
1916   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1917    [InitEmpty, Always, TestOutputInt (
1918       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1919    "get total size of device in bytes",
1920    "\
1921 This returns the size of the device in bytes.
1922
1923 See also C<guestfs_blockdev_getsz>.
1924
1925 This uses the L<blockdev(8)> command.");
1926
1927   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1928    [InitEmpty, Always, TestRun
1929       [["blockdev_flushbufs"; "/dev/sda"]]],
1930    "flush device buffers",
1931    "\
1932 This tells the kernel to flush internal buffers associated
1933 with C<device>.
1934
1935 This uses the L<blockdev(8)> command.");
1936
1937   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1938    [InitEmpty, Always, TestRun
1939       [["blockdev_rereadpt"; "/dev/sda"]]],
1940    "reread partition table",
1941    "\
1942 Reread the partition table on C<device>.
1943
1944 This uses the L<blockdev(8)> command.");
1945
1946   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1947    [InitBasicFS, Always, TestOutput (
1948       (* Pick a file from cwd which isn't likely to change. *)
1949       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1950        ["checksum"; "md5"; "/COPYING.LIB"]],
1951       Digest.to_hex (Digest.file "COPYING.LIB"))],
1952    "upload a file from the local machine",
1953    "\
1954 Upload local file C<filename> to C<remotefilename> on the
1955 filesystem.
1956
1957 C<filename> can also be a named pipe.
1958
1959 See also C<guestfs_download>.");
1960
1961   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1962    [InitBasicFS, Always, TestOutput (
1963       (* Pick a file from cwd which isn't likely to change. *)
1964       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1965        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1966        ["upload"; "testdownload.tmp"; "/upload"];
1967        ["checksum"; "md5"; "/upload"]],
1968       Digest.to_hex (Digest.file "COPYING.LIB"))],
1969    "download a file to the local machine",
1970    "\
1971 Download file C<remotefilename> and save it as C<filename>
1972 on the local machine.
1973
1974 C<filename> can also be a named pipe.
1975
1976 See also C<guestfs_upload>, C<guestfs_cat>.");
1977
1978   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1979    [InitISOFS, Always, TestOutput (
1980       [["checksum"; "crc"; "/known-3"]], "2891671662");
1981     InitISOFS, Always, TestLastFail (
1982       [["checksum"; "crc"; "/notexists"]]);
1983     InitISOFS, Always, TestOutput (
1984       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1985     InitISOFS, Always, TestOutput (
1986       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1987     InitISOFS, Always, TestOutput (
1988       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1989     InitISOFS, Always, TestOutput (
1990       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1991     InitISOFS, Always, TestOutput (
1992       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1993     InitISOFS, Always, TestOutput (
1994       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6");
1995     (* Test for RHBZ#579608, absolute symbolic links. *)
1996     InitISOFS, Always, TestOutput (
1997       [["checksum"; "sha512"; "/abssymlink"]], "5f57d0639bc95081c53afc63a449403883818edc64da48930ad6b1a4fb49be90404686877743fbcd7c99811f3def7df7bc22635c885c6a8cf79c806b43451c1a")],
1998    "compute MD5, SHAx or CRC checksum of file",
1999    "\
2000 This call computes the MD5, SHAx or CRC checksum of the
2001 file named C<path>.
2002
2003 The type of checksum to compute is given by the C<csumtype>
2004 parameter which must have one of the following values:
2005
2006 =over 4
2007
2008 =item C<crc>
2009
2010 Compute the cyclic redundancy check (CRC) specified by POSIX
2011 for the C<cksum> command.
2012
2013 =item C<md5>
2014
2015 Compute the MD5 hash (using the C<md5sum> program).
2016
2017 =item C<sha1>
2018
2019 Compute the SHA1 hash (using the C<sha1sum> program).
2020
2021 =item C<sha224>
2022
2023 Compute the SHA224 hash (using the C<sha224sum> program).
2024
2025 =item C<sha256>
2026
2027 Compute the SHA256 hash (using the C<sha256sum> program).
2028
2029 =item C<sha384>
2030
2031 Compute the SHA384 hash (using the C<sha384sum> program).
2032
2033 =item C<sha512>
2034
2035 Compute the SHA512 hash (using the C<sha512sum> program).
2036
2037 =back
2038
2039 The checksum is returned as a printable string.
2040
2041 To get the checksum for a device, use C<guestfs_checksum_device>.
2042
2043 To get the checksums for many files, use C<guestfs_checksums_out>.");
2044
2045   ("tar_in", (RErr, [FileIn "tarfile"; Pathname "directory"]), 69, [],
2046    [InitBasicFS, Always, TestOutput (
2047       [["tar_in"; "../images/helloworld.tar"; "/"];
2048        ["cat"; "/hello"]], "hello\n")],
2049    "unpack tarfile to directory",
2050    "\
2051 This command uploads and unpacks local file C<tarfile> (an
2052 I<uncompressed> tar file) into C<directory>.
2053
2054 To upload a compressed tarball, use C<guestfs_tgz_in>
2055 or C<guestfs_txz_in>.");
2056
2057   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
2058    [],
2059    "pack directory into tarfile",
2060    "\
2061 This command packs the contents of C<directory> and downloads
2062 it to local file C<tarfile>.
2063
2064 To download a compressed tarball, use C<guestfs_tgz_out>
2065 or C<guestfs_txz_out>.");
2066
2067   ("tgz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 71, [],
2068    [InitBasicFS, Always, TestOutput (
2069       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
2070        ["cat"; "/hello"]], "hello\n")],
2071    "unpack compressed tarball to directory",
2072    "\
2073 This command uploads and unpacks local file C<tarball> (a
2074 I<gzip compressed> tar file) into C<directory>.
2075
2076 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
2077
2078   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
2079    [],
2080    "pack directory into compressed tarball",
2081    "\
2082 This command packs the contents of C<directory> and downloads
2083 it to local file C<tarball>.
2084
2085 To download an uncompressed tarball, use C<guestfs_tar_out>.");
2086
2087   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
2088    [InitBasicFS, Always, TestLastFail (
2089       [["umount"; "/"];
2090        ["mount_ro"; "/dev/sda1"; "/"];
2091        ["touch"; "/new"]]);
2092     InitBasicFS, Always, TestOutput (
2093       [["write_file"; "/new"; "data"; "0"];
2094        ["umount"; "/"];
2095        ["mount_ro"; "/dev/sda1"; "/"];
2096        ["cat"; "/new"]], "data")],
2097    "mount a guest disk, read-only",
2098    "\
2099 This is the same as the C<guestfs_mount> command, but it
2100 mounts the filesystem with the read-only (I<-o ro>) flag.");
2101
2102   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
2103    [],
2104    "mount a guest disk with mount options",
2105    "\
2106 This is the same as the C<guestfs_mount> command, but it
2107 allows you to set the mount options as for the
2108 L<mount(8)> I<-o> flag.
2109
2110 If the C<options> parameter is an empty string, then
2111 no options are passed (all options default to whatever
2112 the filesystem uses).");
2113
2114   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2115    [],
2116    "mount a guest disk with mount options and vfstype",
2117    "\
2118 This is the same as the C<guestfs_mount> command, but it
2119 allows you to set both the mount options and the vfstype
2120 as for the L<mount(8)> I<-o> and I<-t> flags.");
2121
2122   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2123    [],
2124    "debugging and internals",
2125    "\
2126 The C<guestfs_debug> command exposes some internals of
2127 C<guestfsd> (the guestfs daemon) that runs inside the
2128 qemu subprocess.
2129
2130 There is no comprehensive help for this command.  You have
2131 to look at the file C<daemon/debug.c> in the libguestfs source
2132 to find out what you can do.");
2133
2134   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2135    [InitEmpty, Always, TestOutputList (
2136       [["part_disk"; "/dev/sda"; "mbr"];
2137        ["pvcreate"; "/dev/sda1"];
2138        ["vgcreate"; "VG"; "/dev/sda1"];
2139        ["lvcreate"; "LV1"; "VG"; "50"];
2140        ["lvcreate"; "LV2"; "VG"; "50"];
2141        ["lvremove"; "/dev/VG/LV1"];
2142        ["lvs"]], ["/dev/VG/LV2"]);
2143     InitEmpty, Always, TestOutputList (
2144       [["part_disk"; "/dev/sda"; "mbr"];
2145        ["pvcreate"; "/dev/sda1"];
2146        ["vgcreate"; "VG"; "/dev/sda1"];
2147        ["lvcreate"; "LV1"; "VG"; "50"];
2148        ["lvcreate"; "LV2"; "VG"; "50"];
2149        ["lvremove"; "/dev/VG"];
2150        ["lvs"]], []);
2151     InitEmpty, Always, TestOutputList (
2152       [["part_disk"; "/dev/sda"; "mbr"];
2153        ["pvcreate"; "/dev/sda1"];
2154        ["vgcreate"; "VG"; "/dev/sda1"];
2155        ["lvcreate"; "LV1"; "VG"; "50"];
2156        ["lvcreate"; "LV2"; "VG"; "50"];
2157        ["lvremove"; "/dev/VG"];
2158        ["vgs"]], ["VG"])],
2159    "remove an LVM logical volume",
2160    "\
2161 Remove an LVM logical volume C<device>, where C<device> is
2162 the path to the LV, such as C</dev/VG/LV>.
2163
2164 You can also remove all LVs in a volume group by specifying
2165 the VG name, C</dev/VG>.");
2166
2167   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2168    [InitEmpty, Always, TestOutputList (
2169       [["part_disk"; "/dev/sda"; "mbr"];
2170        ["pvcreate"; "/dev/sda1"];
2171        ["vgcreate"; "VG"; "/dev/sda1"];
2172        ["lvcreate"; "LV1"; "VG"; "50"];
2173        ["lvcreate"; "LV2"; "VG"; "50"];
2174        ["vgremove"; "VG"];
2175        ["lvs"]], []);
2176     InitEmpty, Always, TestOutputList (
2177       [["part_disk"; "/dev/sda"; "mbr"];
2178        ["pvcreate"; "/dev/sda1"];
2179        ["vgcreate"; "VG"; "/dev/sda1"];
2180        ["lvcreate"; "LV1"; "VG"; "50"];
2181        ["lvcreate"; "LV2"; "VG"; "50"];
2182        ["vgremove"; "VG"];
2183        ["vgs"]], [])],
2184    "remove an LVM volume group",
2185    "\
2186 Remove an LVM volume group C<vgname>, (for example C<VG>).
2187
2188 This also forcibly removes all logical volumes in the volume
2189 group (if any).");
2190
2191   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2192    [InitEmpty, Always, TestOutputListOfDevices (
2193       [["part_disk"; "/dev/sda"; "mbr"];
2194        ["pvcreate"; "/dev/sda1"];
2195        ["vgcreate"; "VG"; "/dev/sda1"];
2196        ["lvcreate"; "LV1"; "VG"; "50"];
2197        ["lvcreate"; "LV2"; "VG"; "50"];
2198        ["vgremove"; "VG"];
2199        ["pvremove"; "/dev/sda1"];
2200        ["lvs"]], []);
2201     InitEmpty, Always, TestOutputListOfDevices (
2202       [["part_disk"; "/dev/sda"; "mbr"];
2203        ["pvcreate"; "/dev/sda1"];
2204        ["vgcreate"; "VG"; "/dev/sda1"];
2205        ["lvcreate"; "LV1"; "VG"; "50"];
2206        ["lvcreate"; "LV2"; "VG"; "50"];
2207        ["vgremove"; "VG"];
2208        ["pvremove"; "/dev/sda1"];
2209        ["vgs"]], []);
2210     InitEmpty, Always, TestOutputListOfDevices (
2211       [["part_disk"; "/dev/sda"; "mbr"];
2212        ["pvcreate"; "/dev/sda1"];
2213        ["vgcreate"; "VG"; "/dev/sda1"];
2214        ["lvcreate"; "LV1"; "VG"; "50"];
2215        ["lvcreate"; "LV2"; "VG"; "50"];
2216        ["vgremove"; "VG"];
2217        ["pvremove"; "/dev/sda1"];
2218        ["pvs"]], [])],
2219    "remove an LVM physical volume",
2220    "\
2221 This wipes a physical volume C<device> so that LVM will no longer
2222 recognise it.
2223
2224 The implementation uses the C<pvremove> command which refuses to
2225 wipe physical volumes that contain any volume groups, so you have
2226 to remove those first.");
2227
2228   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2229    [InitBasicFS, Always, TestOutput (
2230       [["set_e2label"; "/dev/sda1"; "testlabel"];
2231        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2232    "set the ext2/3/4 filesystem label",
2233    "\
2234 This sets the ext2/3/4 filesystem label of the filesystem on
2235 C<device> to C<label>.  Filesystem labels are limited to
2236 16 characters.
2237
2238 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2239 to return the existing label on a filesystem.");
2240
2241   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2242    [],
2243    "get the ext2/3/4 filesystem label",
2244    "\
2245 This returns the ext2/3/4 filesystem label of the filesystem on
2246 C<device>.");
2247
2248   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2249    (let uuid = uuidgen () in
2250     [InitBasicFS, Always, TestOutput (
2251        [["set_e2uuid"; "/dev/sda1"; uuid];
2252         ["get_e2uuid"; "/dev/sda1"]], uuid);
2253      InitBasicFS, Always, TestOutput (
2254        [["set_e2uuid"; "/dev/sda1"; "clear"];
2255         ["get_e2uuid"; "/dev/sda1"]], "");
2256      (* We can't predict what UUIDs will be, so just check the commands run. *)
2257      InitBasicFS, Always, TestRun (
2258        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2259      InitBasicFS, Always, TestRun (
2260        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2261    "set the ext2/3/4 filesystem UUID",
2262    "\
2263 This sets the ext2/3/4 filesystem UUID of the filesystem on
2264 C<device> to C<uuid>.  The format of the UUID and alternatives
2265 such as C<clear>, C<random> and C<time> are described in the
2266 L<tune2fs(8)> manpage.
2267
2268 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2269 to return the existing UUID of a filesystem.");
2270
2271   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2272    [],
2273    "get the ext2/3/4 filesystem UUID",
2274    "\
2275 This returns the ext2/3/4 filesystem UUID of the filesystem on
2276 C<device>.");
2277
2278   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [FishOutput FishOutputHexadecimal],
2279    [InitBasicFS, Always, TestOutputInt (
2280       [["umount"; "/dev/sda1"];
2281        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2282     InitBasicFS, Always, TestOutputInt (
2283       [["umount"; "/dev/sda1"];
2284        ["zero"; "/dev/sda1"];
2285        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2286    "run the filesystem checker",
2287    "\
2288 This runs the filesystem checker (fsck) on C<device> which
2289 should have filesystem type C<fstype>.
2290
2291 The returned integer is the status.  See L<fsck(8)> for the
2292 list of status codes from C<fsck>.
2293
2294 Notes:
2295
2296 =over 4
2297
2298 =item *
2299
2300 Multiple status codes can be summed together.
2301
2302 =item *
2303
2304 A non-zero return code can mean \"success\", for example if
2305 errors have been corrected on the filesystem.
2306
2307 =item *
2308
2309 Checking or repairing NTFS volumes is not supported
2310 (by linux-ntfs).
2311
2312 =back
2313
2314 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2315
2316   ("zero", (RErr, [Device "device"]), 85, [],
2317    [InitBasicFS, Always, TestOutput (
2318       [["umount"; "/dev/sda1"];
2319        ["zero"; "/dev/sda1"];
2320        ["file"; "/dev/sda1"]], "data")],
2321    "write zeroes to the device",
2322    "\
2323 This command writes zeroes over the first few blocks of C<device>.
2324
2325 How many blocks are zeroed isn't specified (but it's I<not> enough
2326 to securely wipe the device).  It should be sufficient to remove
2327 any partition tables, filesystem superblocks and so on.
2328
2329 See also: C<guestfs_zero_device>, C<guestfs_scrub_device>.");
2330
2331   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2332    (* Test disabled because grub-install incompatible with virtio-blk driver.
2333     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2334     *)
2335    [InitBasicFS, Disabled, TestOutputTrue (
2336       [["grub_install"; "/"; "/dev/sda1"];
2337        ["is_dir"; "/boot"]])],
2338    "install GRUB",
2339    "\
2340 This command installs GRUB (the Grand Unified Bootloader) on
2341 C<device>, with the root directory being C<root>.");
2342
2343   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2344    [InitBasicFS, Always, TestOutput (
2345       [["write_file"; "/old"; "file content"; "0"];
2346        ["cp"; "/old"; "/new"];
2347        ["cat"; "/new"]], "file content");
2348     InitBasicFS, Always, TestOutputTrue (
2349       [["write_file"; "/old"; "file content"; "0"];
2350        ["cp"; "/old"; "/new"];
2351        ["is_file"; "/old"]]);
2352     InitBasicFS, Always, TestOutput (
2353       [["write_file"; "/old"; "file content"; "0"];
2354        ["mkdir"; "/dir"];
2355        ["cp"; "/old"; "/dir/new"];
2356        ["cat"; "/dir/new"]], "file content")],
2357    "copy a file",
2358    "\
2359 This copies a file from C<src> to C<dest> where C<dest> is
2360 either a destination filename or destination directory.");
2361
2362   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2363    [InitBasicFS, Always, TestOutput (
2364       [["mkdir"; "/olddir"];
2365        ["mkdir"; "/newdir"];
2366        ["write_file"; "/olddir/file"; "file content"; "0"];
2367        ["cp_a"; "/olddir"; "/newdir"];
2368        ["cat"; "/newdir/olddir/file"]], "file content")],
2369    "copy a file or directory recursively",
2370    "\
2371 This copies a file or directory from C<src> to C<dest>
2372 recursively using the C<cp -a> command.");
2373
2374   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2375    [InitBasicFS, Always, TestOutput (
2376       [["write_file"; "/old"; "file content"; "0"];
2377        ["mv"; "/old"; "/new"];
2378        ["cat"; "/new"]], "file content");
2379     InitBasicFS, Always, TestOutputFalse (
2380       [["write_file"; "/old"; "file content"; "0"];
2381        ["mv"; "/old"; "/new"];
2382        ["is_file"; "/old"]])],
2383    "move a file",
2384    "\
2385 This moves a file from C<src> to C<dest> where C<dest> is
2386 either a destination filename or destination directory.");
2387
2388   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2389    [InitEmpty, Always, TestRun (
2390       [["drop_caches"; "3"]])],
2391    "drop kernel page cache, dentries and inodes",
2392    "\
2393 This instructs the guest kernel to drop its page cache,
2394 and/or dentries and inode caches.  The parameter C<whattodrop>
2395 tells the kernel what precisely to drop, see
2396 L<http://linux-mm.org/Drop_Caches>
2397
2398 Setting C<whattodrop> to 3 should drop everything.
2399
2400 This automatically calls L<sync(2)> before the operation,
2401 so that the maximum guest memory is freed.");
2402
2403   ("dmesg", (RString "kmsgs", []), 91, [],
2404    [InitEmpty, Always, TestRun (
2405       [["dmesg"]])],
2406    "return kernel messages",
2407    "\
2408 This returns the kernel messages (C<dmesg> output) from
2409 the guest kernel.  This is sometimes useful for extended
2410 debugging of problems.
2411
2412 Another way to get the same information is to enable
2413 verbose messages with C<guestfs_set_verbose> or by setting
2414 the environment variable C<LIBGUESTFS_DEBUG=1> before
2415 running the program.");
2416
2417   ("ping_daemon", (RErr, []), 92, [],
2418    [InitEmpty, Always, TestRun (
2419       [["ping_daemon"]])],
2420    "ping the guest daemon",
2421    "\
2422 This is a test probe into the guestfs daemon running inside
2423 the qemu subprocess.  Calling this function checks that the
2424 daemon responds to the ping message, without affecting the daemon
2425 or attached block device(s) in any other way.");
2426
2427   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2428    [InitBasicFS, Always, TestOutputTrue (
2429       [["write_file"; "/file1"; "contents of a file"; "0"];
2430        ["cp"; "/file1"; "/file2"];
2431        ["equal"; "/file1"; "/file2"]]);
2432     InitBasicFS, Always, TestOutputFalse (
2433       [["write_file"; "/file1"; "contents of a file"; "0"];
2434        ["write_file"; "/file2"; "contents of another file"; "0"];
2435        ["equal"; "/file1"; "/file2"]]);
2436     InitBasicFS, Always, TestLastFail (
2437       [["equal"; "/file1"; "/file2"]])],
2438    "test if two files have equal contents",
2439    "\
2440 This compares the two files C<file1> and C<file2> and returns
2441 true if their content is exactly equal, or false otherwise.
2442
2443 The external L<cmp(1)> program is used for the comparison.");
2444
2445   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2446    [InitISOFS, Always, TestOutputList (
2447       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2448     InitISOFS, Always, TestOutputList (
2449       [["strings"; "/empty"]], []);
2450     (* Test for RHBZ#579608, absolute symbolic links. *)
2451     InitISOFS, Always, TestRun (
2452       [["strings"; "/abssymlink"]])],
2453    "print the printable strings in a file",
2454    "\
2455 This runs the L<strings(1)> command on a file and returns
2456 the list of printable strings found.");
2457
2458   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2459    [InitISOFS, Always, TestOutputList (
2460       [["strings_e"; "b"; "/known-5"]], []);
2461     InitBasicFS, Disabled, TestOutputList (
2462       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2463        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2464    "print the printable strings in a file",
2465    "\
2466 This is like the C<guestfs_strings> command, but allows you to
2467 specify the encoding.
2468
2469 See the L<strings(1)> manpage for the full list of encodings.
2470
2471 Commonly useful encodings are C<l> (lower case L) which will
2472 show strings inside Windows/x86 files.
2473
2474 The returned strings are transcoded to UTF-8.");
2475
2476   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2477    [InitISOFS, Always, TestOutput (
2478       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2479     (* Test for RHBZ#501888c2 regression which caused large hexdump
2480      * commands to segfault.
2481      *)
2482     InitISOFS, Always, TestRun (
2483       [["hexdump"; "/100krandom"]]);
2484     (* Test for RHBZ#579608, absolute symbolic links. *)
2485     InitISOFS, Always, TestRun (
2486       [["hexdump"; "/abssymlink"]])],
2487    "dump a file in hexadecimal",
2488    "\
2489 This runs C<hexdump -C> on the given C<path>.  The result is
2490 the human-readable, canonical hex dump of the file.");
2491
2492   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2493    [InitNone, Always, TestOutput (
2494       [["part_disk"; "/dev/sda"; "mbr"];
2495        ["mkfs"; "ext3"; "/dev/sda1"];
2496        ["mount_options"; ""; "/dev/sda1"; "/"];
2497        ["write_file"; "/new"; "test file"; "0"];
2498        ["umount"; "/dev/sda1"];
2499        ["zerofree"; "/dev/sda1"];
2500        ["mount_options"; ""; "/dev/sda1"; "/"];
2501        ["cat"; "/new"]], "test file")],
2502    "zero unused inodes and disk blocks on ext2/3 filesystem",
2503    "\
2504 This runs the I<zerofree> program on C<device>.  This program
2505 claims to zero unused inodes and disk blocks on an ext2/3
2506 filesystem, thus making it possible to compress the filesystem
2507 more effectively.
2508
2509 You should B<not> run this program if the filesystem is
2510 mounted.
2511
2512 It is possible that using this program can damage the filesystem
2513 or data on the filesystem.");
2514
2515   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2516    [],
2517    "resize an LVM physical volume",
2518    "\
2519 This resizes (expands or shrinks) an existing LVM physical
2520 volume to match the new size of the underlying device.");
2521
2522   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2523                        Int "cyls"; Int "heads"; Int "sectors";
2524                        String "line"]), 99, [DangerWillRobinson],
2525    [],
2526    "modify a single partition on a block device",
2527    "\
2528 This runs L<sfdisk(8)> option to modify just the single
2529 partition C<n> (note: C<n> counts from 1).
2530
2531 For other parameters, see C<guestfs_sfdisk>.  You should usually
2532 pass C<0> for the cyls/heads/sectors parameters.
2533
2534 See also: C<guestfs_part_add>");
2535
2536   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2537    [],
2538    "display the partition table",
2539    "\
2540 This displays the partition table on C<device>, in the
2541 human-readable output of the L<sfdisk(8)> command.  It is
2542 not intended to be parsed.
2543
2544 See also: C<guestfs_part_list>");
2545
2546   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2547    [],
2548    "display the kernel geometry",
2549    "\
2550 This displays the kernel's idea of the geometry of C<device>.
2551
2552 The result is in human-readable format, and not designed to
2553 be parsed.");
2554
2555   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2556    [],
2557    "display the disk geometry from the partition table",
2558    "\
2559 This displays the disk geometry of C<device> read from the
2560 partition table.  Especially in the case where the underlying
2561 block device has been resized, this can be different from the
2562 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2563
2564 The result is in human-readable format, and not designed to
2565 be parsed.");
2566
2567   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2568    [],
2569    "activate or deactivate all volume groups",
2570    "\
2571 This command activates or (if C<activate> is false) deactivates
2572 all logical volumes in all volume groups.
2573 If activated, then they are made known to the
2574 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2575 then those devices disappear.
2576
2577 This command is the same as running C<vgchange -a y|n>");
2578
2579   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2580    [],
2581    "activate or deactivate some volume groups",
2582    "\
2583 This command activates or (if C<activate> is false) deactivates
2584 all logical volumes in the listed volume groups C<volgroups>.
2585 If activated, then they are made known to the
2586 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2587 then those devices disappear.
2588
2589 This command is the same as running C<vgchange -a y|n volgroups...>
2590
2591 Note that if C<volgroups> is an empty list then B<all> volume groups
2592 are activated or deactivated.");
2593
2594   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2595    [InitNone, Always, TestOutput (
2596       [["part_disk"; "/dev/sda"; "mbr"];
2597        ["pvcreate"; "/dev/sda1"];
2598        ["vgcreate"; "VG"; "/dev/sda1"];
2599        ["lvcreate"; "LV"; "VG"; "10"];
2600        ["mkfs"; "ext2"; "/dev/VG/LV"];
2601        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2602        ["write_file"; "/new"; "test content"; "0"];
2603        ["umount"; "/"];
2604        ["lvresize"; "/dev/VG/LV"; "20"];
2605        ["e2fsck_f"; "/dev/VG/LV"];
2606        ["resize2fs"; "/dev/VG/LV"];
2607        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2608        ["cat"; "/new"]], "test content");
2609     InitNone, Always, TestRun (
2610       (* Make an LV smaller to test RHBZ#587484. *)
2611       [["part_disk"; "/dev/sda"; "mbr"];
2612        ["pvcreate"; "/dev/sda1"];
2613        ["vgcreate"; "VG"; "/dev/sda1"];
2614        ["lvcreate"; "LV"; "VG"; "20"];
2615        ["lvresize"; "/dev/VG/LV"; "10"]])],
2616    "resize an LVM logical volume",
2617    "\
2618 This resizes (expands or shrinks) an existing LVM logical
2619 volume to C<mbytes>.  When reducing, data in the reduced part
2620 is lost.");
2621
2622   ("resize2fs", (RErr, [Device "device"]), 106, [],
2623    [], (* lvresize tests this *)
2624    "resize an ext2/ext3 filesystem",
2625    "\
2626 This resizes an ext2 or ext3 filesystem to match the size of
2627 the underlying device.
2628
2629 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2630 on the C<device> before calling this command.  For unknown reasons
2631 C<resize2fs> sometimes gives an error about this and sometimes not.
2632 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2633 calling this function.");
2634
2635   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2636    [InitBasicFS, Always, TestOutputList (
2637       [["find"; "/"]], ["lost+found"]);
2638     InitBasicFS, Always, TestOutputList (
2639       [["touch"; "/a"];
2640        ["mkdir"; "/b"];
2641        ["touch"; "/b/c"];
2642        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2643     InitBasicFS, Always, TestOutputList (
2644       [["mkdir_p"; "/a/b/c"];
2645        ["touch"; "/a/b/c/d"];
2646        ["find"; "/a/b/"]], ["c"; "c/d"])],
2647    "find all files and directories",
2648    "\
2649 This command lists out all files and directories, recursively,
2650 starting at C<directory>.  It is essentially equivalent to
2651 running the shell command C<find directory -print> but some
2652 post-processing happens on the output, described below.
2653
2654 This returns a list of strings I<without any prefix>.  Thus
2655 if the directory structure was:
2656
2657  /tmp/a
2658  /tmp/b
2659  /tmp/c/d
2660
2661 then the returned list from C<guestfs_find> C</tmp> would be
2662 4 elements:
2663
2664  a
2665  b
2666  c
2667  c/d
2668
2669 If C<directory> is not a directory, then this command returns
2670 an error.
2671
2672 The returned list is sorted.
2673
2674 See also C<guestfs_find0>.");
2675
2676   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2677    [], (* lvresize tests this *)
2678    "check an ext2/ext3 filesystem",
2679    "\
2680 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2681 filesystem checker on C<device>, noninteractively (C<-p>),
2682 even if the filesystem appears to be clean (C<-f>).
2683
2684 This command is only needed because of C<guestfs_resize2fs>
2685 (q.v.).  Normally you should use C<guestfs_fsck>.");
2686
2687   ("sleep", (RErr, [Int "secs"]), 109, [],
2688    [InitNone, Always, TestRun (
2689       [["sleep"; "1"]])],
2690    "sleep for some seconds",
2691    "\
2692 Sleep for C<secs> seconds.");
2693
2694   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2695    [InitNone, Always, TestOutputInt (
2696       [["part_disk"; "/dev/sda"; "mbr"];
2697        ["mkfs"; "ntfs"; "/dev/sda1"];
2698        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2699     InitNone, Always, TestOutputInt (
2700       [["part_disk"; "/dev/sda"; "mbr"];
2701        ["mkfs"; "ext2"; "/dev/sda1"];
2702        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2703    "probe NTFS volume",
2704    "\
2705 This command runs the L<ntfs-3g.probe(8)> command which probes
2706 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2707 be mounted read-write, and some cannot be mounted at all).
2708
2709 C<rw> is a boolean flag.  Set it to true if you want to test
2710 if the volume can be mounted read-write.  Set it to false if
2711 you want to test if the volume can be mounted read-only.
2712
2713 The return value is an integer which C<0> if the operation
2714 would succeed, or some non-zero value documented in the
2715 L<ntfs-3g.probe(8)> manual page.");
2716
2717   ("sh", (RString "output", [String "command"]), 111, [],
2718    [], (* XXX needs tests *)
2719    "run a command via the shell",
2720    "\
2721 This call runs a command from the guest filesystem via the
2722 guest's C</bin/sh>.
2723
2724 This is like C<guestfs_command>, but passes the command to:
2725
2726  /bin/sh -c \"command\"
2727
2728 Depending on the guest's shell, this usually results in
2729 wildcards being expanded, shell expressions being interpolated
2730 and so on.
2731
2732 All the provisos about C<guestfs_command> apply to this call.");
2733
2734   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2735    [], (* XXX needs tests *)
2736    "run a command via the shell returning lines",
2737    "\
2738 This is the same as C<guestfs_sh>, but splits the result
2739 into a list of lines.
2740
2741 See also: C<guestfs_command_lines>");
2742
2743   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2744    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2745     * code in stubs.c, since all valid glob patterns must start with "/".
2746     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2747     *)
2748    [InitBasicFS, Always, TestOutputList (
2749       [["mkdir_p"; "/a/b/c"];
2750        ["touch"; "/a/b/c/d"];
2751        ["touch"; "/a/b/c/e"];
2752        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2753     InitBasicFS, Always, TestOutputList (
2754       [["mkdir_p"; "/a/b/c"];
2755        ["touch"; "/a/b/c/d"];
2756        ["touch"; "/a/b/c/e"];
2757        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2758     InitBasicFS, Always, TestOutputList (
2759       [["mkdir_p"; "/a/b/c"];
2760        ["touch"; "/a/b/c/d"];
2761        ["touch"; "/a/b/c/e"];
2762        ["glob_expand"; "/a/*/x/*"]], [])],
2763    "expand a wildcard path",
2764    "\
2765 This command searches for all the pathnames matching
2766 C<pattern> according to the wildcard expansion rules
2767 used by the shell.
2768
2769 If no paths match, then this returns an empty list
2770 (note: not an error).
2771
2772 It is just a wrapper around the C L<glob(3)> function
2773 with flags C<GLOB_MARK|GLOB_BRACE>.
2774 See that manual page for more details.");
2775
2776   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2777    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2778       [["scrub_device"; "/dev/sdc"]])],
2779    "scrub (securely wipe) a device",
2780    "\
2781 This command writes patterns over C<device> to make data retrieval
2782 more difficult.
2783
2784 It is an interface to the L<scrub(1)> program.  See that
2785 manual page for more details.");
2786
2787   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2788    [InitBasicFS, Always, TestRun (
2789       [["write_file"; "/file"; "content"; "0"];
2790        ["scrub_file"; "/file"]])],
2791    "scrub (securely wipe) a file",
2792    "\
2793 This command writes patterns over a file to make data retrieval
2794 more difficult.
2795
2796 The file is I<removed> after scrubbing.
2797
2798 It is an interface to the L<scrub(1)> program.  See that
2799 manual page for more details.");
2800
2801   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2802    [], (* XXX needs testing *)
2803    "scrub (securely wipe) free space",
2804    "\
2805 This command creates the directory C<dir> and then fills it
2806 with files until the filesystem is full, and scrubs the files
2807 as for C<guestfs_scrub_file>, and deletes them.
2808 The intention is to scrub any free space on the partition
2809 containing C<dir>.
2810
2811 It is an interface to the L<scrub(1)> program.  See that
2812 manual page for more details.");
2813
2814   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2815    [InitBasicFS, Always, TestRun (
2816       [["mkdir"; "/tmp"];
2817        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2818    "create a temporary directory",
2819    "\
2820 This command creates a temporary directory.  The
2821 C<template> parameter should be a full pathname for the
2822 temporary directory name with the final six characters being
2823 \"XXXXXX\".
2824
2825 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2826 the second one being suitable for Windows filesystems.
2827
2828 The name of the temporary directory that was created
2829 is returned.
2830
2831 The temporary directory is created with mode 0700
2832 and is owned by root.
2833
2834 The caller is responsible for deleting the temporary
2835 directory and its contents after use.
2836
2837 See also: L<mkdtemp(3)>");
2838
2839   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2840    [InitISOFS, Always, TestOutputInt (
2841       [["wc_l"; "/10klines"]], 10000)],
2842    "count lines in a file",
2843    "\
2844 This command counts the lines in a file, using the
2845 C<wc -l> external command.");
2846
2847   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2848    [InitISOFS, Always, TestOutputInt (
2849       [["wc_w"; "/10klines"]], 10000)],
2850    "count words in a file",
2851    "\
2852 This command counts the words in a file, using the
2853 C<wc -w> external command.");
2854
2855   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2856    [InitISOFS, Always, TestOutputInt (
2857       [["wc_c"; "/100kallspaces"]], 102400)],
2858    "count characters in a file",
2859    "\
2860 This command counts the characters in a file, using the
2861 C<wc -c> external command.");
2862
2863   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2864    [InitISOFS, Always, TestOutputList (
2865       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"]);
2866     (* Test for RHBZ#579608, absolute symbolic links. *)
2867     InitISOFS, Always, TestOutputList (
2868       [["head"; "/abssymlink"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2869    "return first 10 lines of a file",
2870    "\
2871 This command returns up to the first 10 lines of a file as
2872 a list of strings.");
2873
2874   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2875    [InitISOFS, Always, TestOutputList (
2876       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2877     InitISOFS, Always, TestOutputList (
2878       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2879     InitISOFS, Always, TestOutputList (
2880       [["head_n"; "0"; "/10klines"]], [])],
2881    "return first N lines of a file",
2882    "\
2883 If the parameter C<nrlines> is a positive number, this returns the first
2884 C<nrlines> lines of the file C<path>.
2885
2886 If the parameter C<nrlines> is a negative number, this returns lines
2887 from the file C<path>, excluding the last C<nrlines> lines.
2888
2889 If the parameter C<nrlines> is zero, this returns an empty list.");
2890
2891   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2892    [InitISOFS, Always, TestOutputList (
2893       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2894    "return last 10 lines of a file",
2895    "\
2896 This command returns up to the last 10 lines of a file as
2897 a list of strings.");
2898
2899   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2900    [InitISOFS, Always, TestOutputList (
2901       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2902     InitISOFS, Always, TestOutputList (
2903       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2904     InitISOFS, Always, TestOutputList (
2905       [["tail_n"; "0"; "/10klines"]], [])],
2906    "return last N lines of a file",
2907    "\
2908 If the parameter C<nrlines> is a positive number, this returns the last
2909 C<nrlines> lines of the file C<path>.
2910
2911 If the parameter C<nrlines> is a negative number, this returns lines
2912 from the file C<path>, starting with the C<-nrlines>th line.
2913
2914 If the parameter C<nrlines> is zero, this returns an empty list.");
2915
2916   ("df", (RString "output", []), 125, [],
2917    [], (* XXX Tricky to test because it depends on the exact format
2918         * of the 'df' command and other imponderables.
2919         *)
2920    "report file system disk space usage",
2921    "\
2922 This command runs the C<df> command to report disk space used.
2923
2924 This command is mostly useful for interactive sessions.  It
2925 is I<not> intended that you try to parse the output string.
2926 Use C<statvfs> from programs.");
2927
2928   ("df_h", (RString "output", []), 126, [],
2929    [], (* XXX Tricky to test because it depends on the exact format
2930         * of the 'df' command and other imponderables.
2931         *)
2932    "report file system disk space usage (human readable)",
2933    "\
2934 This command runs the C<df -h> command to report disk space used
2935 in human-readable format.
2936
2937 This command is mostly useful for interactive sessions.  It
2938 is I<not> intended that you try to parse the output string.
2939 Use C<statvfs> from programs.");
2940
2941   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2942    [InitISOFS, Always, TestOutputInt (
2943       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2944    "estimate file space usage",
2945    "\
2946 This command runs the C<du -s> command to estimate file space
2947 usage for C<path>.
2948
2949 C<path> can be a file or a directory.  If C<path> is a directory
2950 then the estimate includes the contents of the directory and all
2951 subdirectories (recursively).
2952
2953 The result is the estimated size in I<kilobytes>
2954 (ie. units of 1024 bytes).");
2955
2956   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2957    [InitISOFS, Always, TestOutputList (
2958       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2959    "list files in an initrd",
2960    "\
2961 This command lists out files contained in an initrd.
2962
2963 The files are listed without any initial C</> character.  The
2964 files are listed in the order they appear (not necessarily
2965 alphabetical).  Directory names are listed as separate items.
2966
2967 Old Linux kernels (2.4 and earlier) used a compressed ext2
2968 filesystem as initrd.  We I<only> support the newer initramfs
2969 format (compressed cpio files).");
2970
2971   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2972    [],
2973    "mount a file using the loop device",
2974    "\
2975 This command lets you mount C<file> (a filesystem image
2976 in a file) on a mount point.  It is entirely equivalent to
2977 the command C<mount -o loop file mountpoint>.");
2978
2979   ("mkswap", (RErr, [Device "device"]), 130, [],
2980    [InitEmpty, Always, TestRun (
2981       [["part_disk"; "/dev/sda"; "mbr"];
2982        ["mkswap"; "/dev/sda1"]])],
2983    "create a swap partition",
2984    "\
2985 Create a swap partition on C<device>.");
2986
2987   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2988    [InitEmpty, Always, TestRun (
2989       [["part_disk"; "/dev/sda"; "mbr"];
2990        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2991    "create a swap partition with a label",
2992    "\
2993 Create a swap partition on C<device> with label C<label>.
2994
2995 Note that you cannot attach a swap label to a block device
2996 (eg. C</dev/sda>), just to a partition.  This appears to be
2997 a limitation of the kernel or swap tools.");
2998
2999   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
3000    (let uuid = uuidgen () in
3001     [InitEmpty, Always, TestRun (
3002        [["part_disk"; "/dev/sda"; "mbr"];
3003         ["mkswap_U"; uuid; "/dev/sda1"]])]),
3004    "create a swap partition with an explicit UUID",
3005    "\
3006 Create a swap partition on C<device> with UUID C<uuid>.");
3007
3008   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
3009    [InitBasicFS, Always, TestOutputStruct (
3010       [["mknod"; "0o10777"; "0"; "0"; "/node"];
3011        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
3012        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
3013     InitBasicFS, Always, TestOutputStruct (
3014       [["mknod"; "0o60777"; "66"; "99"; "/node"];
3015        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3016    "make block, character or FIFO devices",
3017    "\
3018 This call creates block or character special devices, or
3019 named pipes (FIFOs).
3020
3021 The C<mode> parameter should be the mode, using the standard
3022 constants.  C<devmajor> and C<devminor> are the
3023 device major and minor numbers, only used when creating block
3024 and character special devices.
3025
3026 Note that, just like L<mknod(2)>, the mode must be bitwise
3027 OR'd with S_IFBLK, S_IFCHR, S_IFIFO or S_IFSOCK (otherwise this call
3028 just creates a regular file).  These constants are
3029 available in the standard Linux header files, or you can use
3030 C<guestfs_mknod_b>, C<guestfs_mknod_c> or C<guestfs_mkfifo>
3031 which are wrappers around this command which bitwise OR
3032 in the appropriate constant for you.
3033
3034 The mode actually set is affected by the umask.");
3035
3036   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
3037    [InitBasicFS, Always, TestOutputStruct (
3038       [["mkfifo"; "0o777"; "/node"];
3039        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
3040    "make FIFO (named pipe)",
3041    "\
3042 This call creates a FIFO (named pipe) called C<path> with
3043 mode C<mode>.  It is just a convenient wrapper around
3044 C<guestfs_mknod>.
3045
3046 The mode actually set is affected by the umask.");
3047
3048   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
3049    [InitBasicFS, Always, TestOutputStruct (
3050       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
3051        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3052    "make block device node",
3053    "\
3054 This call creates a block device node called C<path> with
3055 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3056 It is just a convenient wrapper around C<guestfs_mknod>.
3057
3058 The mode actually set is affected by the umask.");
3059
3060   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
3061    [InitBasicFS, Always, TestOutputStruct (
3062       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
3063        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
3064    "make char device node",
3065    "\
3066 This call creates a char device node called C<path> with
3067 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3068 It is just a convenient wrapper around C<guestfs_mknod>.
3069
3070 The mode actually set is affected by the umask.");
3071
3072   ("umask", (RInt "oldmask", [Int "mask"]), 137, [FishOutput FishOutputOctal],
3073    [InitEmpty, Always, TestOutputInt (
3074       [["umask"; "0o22"]], 0o22)],
3075    "set file mode creation mask (umask)",
3076    "\
3077 This function sets the mask used for creating new files and
3078 device nodes to C<mask & 0777>.
3079
3080 Typical umask values would be C<022> which creates new files
3081 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
3082 C<002> which creates new files with permissions like
3083 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
3084
3085 The default umask is C<022>.  This is important because it
3086 means that directories and device nodes will be created with
3087 C<0644> or C<0755> mode even if you specify C<0777>.
3088
3089 See also C<guestfs_get_umask>,
3090 L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
3091
3092 This call returns the previous umask.");
3093
3094   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
3095    [],
3096    "read directories entries",
3097    "\
3098 This returns the list of directory entries in directory C<dir>.
3099
3100 All entries in the directory are returned, including C<.> and
3101 C<..>.  The entries are I<not> sorted, but returned in the same
3102 order as the underlying filesystem.
3103
3104 Also this call returns basic file type information about each
3105 file.  The C<ftyp> field will contain one of the following characters:
3106
3107 =over 4
3108
3109 =item 'b'
3110
3111 Block special
3112
3113 =item 'c'
3114
3115 Char special
3116
3117 =item 'd'
3118
3119 Directory
3120
3121 =item 'f'
3122
3123 FIFO (named pipe)
3124
3125 =item 'l'
3126
3127 Symbolic link
3128
3129 =item 'r'
3130
3131 Regular file
3132
3133 =item 's'
3134
3135 Socket
3136
3137 =item 'u'
3138
3139 Unknown file type
3140
3141 =item '?'
3142
3143 The L<readdir(3)> returned a C<d_type> field with an
3144 unexpected value
3145
3146 =back
3147
3148 This function is primarily intended for use by programs.  To
3149 get a simple list of names, use C<guestfs_ls>.  To get a printable
3150 directory for human consumption, use C<guestfs_ll>.");
3151
3152   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3153    [],
3154    "create partitions on a block device",
3155    "\
3156 This is a simplified interface to the C<guestfs_sfdisk>
3157 command, where partition sizes are specified in megabytes
3158 only (rounded to the nearest cylinder) and you don't need
3159 to specify the cyls, heads and sectors parameters which
3160 were rarely if ever used anyway.
3161
3162 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3163 and C<guestfs_part_disk>");
3164
3165   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3166    [],
3167    "determine file type inside a compressed file",
3168    "\
3169 This command runs C<file> after first decompressing C<path>
3170 using C<method>.
3171
3172 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3173
3174 Since 1.0.63, use C<guestfs_file> instead which can now
3175 process compressed files.");
3176
3177   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3178    [],
3179    "list extended attributes of a file or directory",
3180    "\
3181 This call lists the extended attributes of the file or directory
3182 C<path>.
3183
3184 At the system call level, this is a combination of the
3185 L<listxattr(2)> and L<getxattr(2)> calls.
3186
3187 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3188
3189   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3190    [],
3191    "list extended attributes of a file or directory",
3192    "\
3193 This is the same as C<guestfs_getxattrs>, but if C<path>
3194 is a symbolic link, then it returns the extended attributes
3195 of the link itself.");
3196
3197   ("setxattr", (RErr, [String "xattr";
3198                        String "val"; Int "vallen"; (* will be BufferIn *)
3199                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3200    [],
3201    "set extended attribute of a file or directory",
3202    "\
3203 This call sets the extended attribute named C<xattr>
3204 of the file C<path> to the value C<val> (of length C<vallen>).
3205 The value is arbitrary 8 bit data.
3206
3207 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3208
3209   ("lsetxattr", (RErr, [String "xattr";
3210                         String "val"; Int "vallen"; (* will be BufferIn *)
3211                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3212    [],
3213    "set extended attribute of a file or directory",
3214    "\
3215 This is the same as C<guestfs_setxattr>, but if C<path>
3216 is a symbolic link, then it sets an extended attribute
3217 of the link itself.");
3218
3219   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3220    [],
3221    "remove extended attribute of a file or directory",
3222    "\
3223 This call removes the extended attribute named C<xattr>
3224 of the file C<path>.
3225
3226 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3227
3228   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3229    [],
3230    "remove extended attribute of a file or directory",
3231    "\
3232 This is the same as C<guestfs_removexattr>, but if C<path>
3233 is a symbolic link, then it removes an extended attribute
3234 of the link itself.");
3235
3236   ("mountpoints", (RHashtable "mps", []), 147, [],
3237    [],
3238    "show mountpoints",
3239    "\
3240 This call is similar to C<guestfs_mounts>.  That call returns
3241 a list of devices.  This one returns a hash table (map) of
3242 device name to directory where the device is mounted.");
3243
3244   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3245    (* This is a special case: while you would expect a parameter
3246     * of type "Pathname", that doesn't work, because it implies
3247     * NEED_ROOT in the generated calling code in stubs.c, and
3248     * this function cannot use NEED_ROOT.
3249     *)
3250    [],
3251    "create a mountpoint",
3252    "\
3253 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3254 specialized calls that can be used to create extra mountpoints
3255 before mounting the first filesystem.
3256
3257 These calls are I<only> necessary in some very limited circumstances,
3258 mainly the case where you want to mount a mix of unrelated and/or
3259 read-only filesystems together.
3260
3261 For example, live CDs often contain a \"Russian doll\" nest of
3262 filesystems, an ISO outer layer, with a squashfs image inside, with
3263 an ext2/3 image inside that.  You can unpack this as follows
3264 in guestfish:
3265
3266  add-ro Fedora-11-i686-Live.iso
3267  run
3268  mkmountpoint /cd
3269  mkmountpoint /squash
3270  mkmountpoint /ext3
3271  mount /dev/sda /cd
3272  mount-loop /cd/LiveOS/squashfs.img /squash
3273  mount-loop /squash/LiveOS/ext3fs.img /ext3
3274
3275 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3276
3277   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3278    [],
3279    "remove a mountpoint",
3280    "\
3281 This calls removes a mountpoint that was previously created
3282 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3283 for full details.");
3284
3285   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3286    [InitISOFS, Always, TestOutputBuffer (
3287       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3288    "read a file",
3289    "\
3290 This calls returns the contents of the file C<path> as a
3291 buffer.
3292
3293 Unlike C<guestfs_cat>, this function can correctly
3294 handle files that contain embedded ASCII NUL characters.
3295 However unlike C<guestfs_download>, this function is limited
3296 in the total size of file that can be handled.");
3297
3298   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3299    [InitISOFS, Always, TestOutputList (
3300       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3301     InitISOFS, Always, TestOutputList (
3302       [["grep"; "nomatch"; "/test-grep.txt"]], []);
3303     (* Test for RHBZ#579608, absolute symbolic links. *)
3304     InitISOFS, Always, TestOutputList (
3305       [["grep"; "nomatch"; "/abssymlink"]], [])],
3306    "return lines matching a pattern",
3307    "\
3308 This calls the external C<grep> program and returns the
3309 matching lines.");
3310
3311   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3312    [InitISOFS, Always, TestOutputList (
3313       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3314    "return lines matching a pattern",
3315    "\
3316 This calls the external C<egrep> program and returns the
3317 matching lines.");
3318
3319   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3320    [InitISOFS, Always, TestOutputList (
3321       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3322    "return lines matching a pattern",
3323    "\
3324 This calls the external C<fgrep> program and returns the
3325 matching lines.");
3326
3327   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3328    [InitISOFS, Always, TestOutputList (
3329       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3330    "return lines matching a pattern",
3331    "\
3332 This calls the external C<grep -i> program and returns the
3333 matching lines.");
3334
3335   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3336    [InitISOFS, Always, TestOutputList (
3337       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3338    "return lines matching a pattern",
3339    "\
3340 This calls the external C<egrep -i> program and returns the
3341 matching lines.");
3342
3343   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3344    [InitISOFS, Always, TestOutputList (
3345       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3346    "return lines matching a pattern",
3347    "\
3348 This calls the external C<fgrep -i> program and returns the
3349 matching lines.");
3350
3351   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3352    [InitISOFS, Always, TestOutputList (
3353       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3354    "return lines matching a pattern",
3355    "\
3356 This calls the external C<zgrep> program and returns the
3357 matching lines.");
3358
3359   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3360    [InitISOFS, Always, TestOutputList (
3361       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3362    "return lines matching a pattern",
3363    "\
3364 This calls the external C<zegrep> program and returns the
3365 matching lines.");
3366
3367   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3368    [InitISOFS, Always, TestOutputList (
3369       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3370    "return lines matching a pattern",
3371    "\
3372 This calls the external C<zfgrep> program and returns the
3373 matching lines.");
3374
3375   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3376    [InitISOFS, Always, TestOutputList (
3377       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3378    "return lines matching a pattern",
3379    "\
3380 This calls the external C<zgrep -i> program and returns the
3381 matching lines.");
3382
3383   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3384    [InitISOFS, Always, TestOutputList (
3385       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3386    "return lines matching a pattern",
3387    "\
3388 This calls the external C<zegrep -i> program and returns the
3389 matching lines.");
3390
3391   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3392    [InitISOFS, Always, TestOutputList (
3393       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3394    "return lines matching a pattern",
3395    "\
3396 This calls the external C<zfgrep -i> program and returns the
3397 matching lines.");
3398
3399   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3400    [InitISOFS, Always, TestOutput (
3401       [["realpath"; "/../directory"]], "/directory")],
3402    "canonicalized absolute pathname",
3403    "\
3404 Return the canonicalized absolute pathname of C<path>.  The
3405 returned path has no C<.>, C<..> or symbolic link path elements.");
3406
3407   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3408    [InitBasicFS, Always, TestOutputStruct (
3409       [["touch"; "/a"];
3410        ["ln"; "/a"; "/b"];
3411        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3412    "create a hard link",
3413    "\
3414 This command creates a hard link using the C<ln> command.");
3415
3416   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3417    [InitBasicFS, Always, TestOutputStruct (
3418       [["touch"; "/a"];
3419        ["touch"; "/b"];
3420        ["ln_f"; "/a"; "/b"];
3421        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3422    "create a hard link",
3423    "\
3424 This command creates a hard link using the C<ln -f> command.
3425 The C<-f> option removes the link (C<linkname>) if it exists already.");
3426
3427   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3428    [InitBasicFS, Always, TestOutputStruct (
3429       [["touch"; "/a"];
3430        ["ln_s"; "a"; "/b"];
3431        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3432    "create a symbolic link",
3433    "\
3434 This command creates a symbolic link using the C<ln -s> command.");
3435
3436   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3437    [InitBasicFS, Always, TestOutput (
3438       [["mkdir_p"; "/a/b"];
3439        ["touch"; "/a/b/c"];
3440        ["ln_sf"; "../d"; "/a/b/c"];
3441        ["readlink"; "/a/b/c"]], "../d")],
3442    "create a symbolic link",
3443    "\
3444 This command creates a symbolic link using the C<ln -sf> command,
3445 The C<-f> option removes the link (C<linkname>) if it exists already.");
3446
3447   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3448    [] (* XXX tested above *),
3449    "read the target of a symbolic link",
3450    "\
3451 This command reads the target of a symbolic link.");
3452
3453   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3454    [InitBasicFS, Always, TestOutputStruct (
3455       [["fallocate"; "/a"; "1000000"];
3456        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3457    "preallocate a file in the guest filesystem",
3458    "\
3459 This command preallocates a file (containing zero bytes) named
3460 C<path> of size C<len> bytes.  If the file exists already, it
3461 is overwritten.
3462
3463 Do not confuse this with the guestfish-specific
3464 C<alloc> command which allocates a file in the host and
3465 attaches it as a device.");
3466
3467   ("swapon_device", (RErr, [Device "device"]), 170, [],
3468    [InitPartition, Always, TestRun (
3469       [["mkswap"; "/dev/sda1"];
3470        ["swapon_device"; "/dev/sda1"];
3471        ["swapoff_device"; "/dev/sda1"]])],
3472    "enable swap on device",
3473    "\
3474 This command enables the libguestfs appliance to use the
3475 swap device or partition named C<device>.  The increased
3476 memory is made available for all commands, for example
3477 those run using C<guestfs_command> or C<guestfs_sh>.
3478
3479 Note that you should not swap to existing guest swap
3480 partitions unless you know what you are doing.  They may
3481 contain hibernation information, or other information that
3482 the guest doesn't want you to trash.  You also risk leaking
3483 information about the host to the guest this way.  Instead,
3484 attach a new host device to the guest and swap on that.");
3485
3486   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3487    [], (* XXX tested by swapon_device *)
3488    "disable swap on device",
3489    "\
3490 This command disables the libguestfs appliance swap
3491 device or partition named C<device>.
3492 See C<guestfs_swapon_device>.");
3493
3494   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3495    [InitBasicFS, Always, TestRun (
3496       [["fallocate"; "/swap"; "8388608"];
3497        ["mkswap_file"; "/swap"];
3498        ["swapon_file"; "/swap"];
3499        ["swapoff_file"; "/swap"]])],
3500    "enable swap on file",
3501    "\
3502 This command enables swap to a file.
3503 See C<guestfs_swapon_device> for other notes.");
3504
3505   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3506    [], (* XXX tested by swapon_file *)
3507    "disable swap on file",
3508    "\
3509 This command disables the libguestfs appliance swap on file.");
3510
3511   ("swapon_label", (RErr, [String "label"]), 174, [],
3512    [InitEmpty, Always, TestRun (
3513       [["part_disk"; "/dev/sdb"; "mbr"];
3514        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3515        ["swapon_label"; "swapit"];
3516        ["swapoff_label"; "swapit"];
3517        ["zero"; "/dev/sdb"];
3518        ["blockdev_rereadpt"; "/dev/sdb"]])],
3519    "enable swap on labeled swap partition",
3520    "\
3521 This command enables swap to a labeled swap partition.
3522 See C<guestfs_swapon_device> for other notes.");
3523
3524   ("swapoff_label", (RErr, [String "label"]), 175, [],
3525    [], (* XXX tested by swapon_label *)
3526    "disable swap on labeled swap partition",
3527    "\
3528 This command disables the libguestfs appliance swap on
3529 labeled swap partition.");
3530
3531   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3532    (let uuid = uuidgen () in
3533     [InitEmpty, Always, TestRun (
3534        [["mkswap_U"; uuid; "/dev/sdb"];
3535         ["swapon_uuid"; uuid];
3536         ["swapoff_uuid"; uuid]])]),
3537    "enable swap on swap partition by UUID",
3538    "\
3539 This command enables swap to a swap partition with the given UUID.
3540 See C<guestfs_swapon_device> for other notes.");
3541
3542   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3543    [], (* XXX tested by swapon_uuid *)
3544    "disable swap on swap partition by UUID",
3545    "\
3546 This command disables the libguestfs appliance swap partition
3547 with the given UUID.");
3548
3549   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3550    [InitBasicFS, Always, TestRun (
3551       [["fallocate"; "/swap"; "8388608"];
3552        ["mkswap_file"; "/swap"]])],
3553    "create a swap file",
3554    "\
3555 Create a swap file.
3556
3557 This command just writes a swap file signature to an existing
3558 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3559
3560   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3561    [InitISOFS, Always, TestRun (
3562       [["inotify_init"; "0"]])],
3563    "create an inotify handle",
3564    "\
3565 This command creates a new inotify handle.
3566 The inotify subsystem can be used to notify events which happen to
3567 objects in the guest filesystem.
3568
3569 C<maxevents> is the maximum number of events which will be
3570 queued up between calls to C<guestfs_inotify_read> or
3571 C<guestfs_inotify_files>.
3572 If this is passed as C<0>, then the kernel (or previously set)
3573 default is used.  For Linux 2.6.29 the default was 16384 events.
3574 Beyond this limit, the kernel throws away events, but records
3575 the fact that it threw them away by setting a flag
3576 C<IN_Q_OVERFLOW> in the returned structure list (see
3577 C<guestfs_inotify_read>).
3578
3579 Before any events are generated, you have to add some
3580 watches to the internal watch list.  See:
3581 C<guestfs_inotify_add_watch>,
3582 C<guestfs_inotify_rm_watch> and
3583 C<guestfs_inotify_watch_all>.
3584
3585 Queued up events should be read periodically by calling
3586 C<guestfs_inotify_read>
3587 (or C<guestfs_inotify_files> which is just a helpful
3588 wrapper around C<guestfs_inotify_read>).  If you don't
3589 read the events out often enough then you risk the internal
3590 queue overflowing.
3591
3592 The handle should be closed after use by calling
3593 C<guestfs_inotify_close>.  This also removes any
3594 watches automatically.
3595
3596 See also L<inotify(7)> for an overview of the inotify interface
3597 as exposed by the Linux kernel, which is roughly what we expose
3598 via libguestfs.  Note that there is one global inotify handle
3599 per libguestfs instance.");
3600
3601   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3602    [InitBasicFS, Always, TestOutputList (
3603       [["inotify_init"; "0"];
3604        ["inotify_add_watch"; "/"; "1073741823"];
3605        ["touch"; "/a"];
3606        ["touch"; "/b"];
3607        ["inotify_files"]], ["a"; "b"])],
3608    "add an inotify watch",
3609    "\
3610 Watch C<path> for the events listed in C<mask>.
3611
3612 Note that if C<path> is a directory then events within that
3613 directory are watched, but this does I<not> happen recursively
3614 (in subdirectories).
3615
3616 Note for non-C or non-Linux callers: the inotify events are
3617 defined by the Linux kernel ABI and are listed in
3618 C</usr/include/sys/inotify.h>.");
3619
3620   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3621    [],
3622    "remove an inotify watch",
3623    "\
3624 Remove a previously defined inotify watch.
3625 See C<guestfs_inotify_add_watch>.");
3626
3627   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3628    [],
3629    "return list of inotify events",
3630    "\
3631 Return the complete queue of events that have happened
3632 since the previous read call.
3633
3634 If no events have happened, this returns an empty list.
3635
3636 I<Note>: In order to make sure that all events have been
3637 read, you must call this function repeatedly until it
3638 returns an empty list.  The reason is that the call will
3639 read events up to the maximum appliance-to-host message
3640 size and leave remaining events in the queue.");
3641
3642   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3643    [],
3644    "return list of watched files that had events",
3645    "\
3646 This function is a helpful wrapper around C<guestfs_inotify_read>
3647 which just returns a list of pathnames of objects that were
3648 touched.  The returned pathnames are sorted and deduplicated.");
3649
3650   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3651    [],
3652    "close the inotify handle",
3653    "\
3654 This closes the inotify handle which was previously
3655 opened by inotify_init.  It removes all watches, throws
3656 away any pending events, and deallocates all resources.");
3657
3658   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3659    [],
3660    "set SELinux security context",
3661    "\
3662 This sets the SELinux security context of the daemon
3663 to the string C<context>.
3664
3665 See the documentation about SELINUX in L<guestfs(3)>.");
3666
3667   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3668    [],
3669    "get SELinux security context",
3670    "\
3671 This gets the SELinux security context of the daemon.
3672
3673 See the documentation about SELINUX in L<guestfs(3)>,
3674 and C<guestfs_setcon>");
3675
3676   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3677    [InitEmpty, Always, TestOutput (
3678       [["part_disk"; "/dev/sda"; "mbr"];
3679        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3680        ["mount_options"; ""; "/dev/sda1"; "/"];
3681        ["write_file"; "/new"; "new file contents"; "0"];
3682        ["cat"; "/new"]], "new file contents")],
3683    "make a filesystem with block size",
3684    "\
3685 This call is similar to C<guestfs_mkfs>, but it allows you to
3686 control the block size of the resulting filesystem.  Supported
3687 block sizes depend on the filesystem type, but typically they
3688 are C<1024>, C<2048> or C<4096> only.");
3689
3690   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3691    [InitEmpty, Always, TestOutput (
3692       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3693        ["mke2journal"; "4096"; "/dev/sda1"];
3694        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3695        ["mount_options"; ""; "/dev/sda2"; "/"];
3696        ["write_file"; "/new"; "new file contents"; "0"];
3697        ["cat"; "/new"]], "new file contents")],
3698    "make ext2/3/4 external journal",
3699    "\
3700 This creates an ext2 external journal on C<device>.  It is equivalent
3701 to the command:
3702
3703  mke2fs -O journal_dev -b blocksize device");
3704
3705   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3706    [InitEmpty, Always, TestOutput (
3707       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3708        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3709        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3710        ["mount_options"; ""; "/dev/sda2"; "/"];
3711        ["write_file"; "/new"; "new file contents"; "0"];
3712        ["cat"; "/new"]], "new file contents")],
3713    "make ext2/3/4 external journal with label",
3714    "\
3715 This creates an ext2 external journal on C<device> with label C<label>.");
3716
3717   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3718    (let uuid = uuidgen () in
3719     [InitEmpty, Always, TestOutput (
3720        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3721         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3722         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3723         ["mount_options"; ""; "/dev/sda2"; "/"];
3724         ["write_file"; "/new"; "new file contents"; "0"];
3725         ["cat"; "/new"]], "new file contents")]),
3726    "make ext2/3/4 external journal with UUID",
3727    "\
3728 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3729
3730   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3731    [],
3732    "make ext2/3/4 filesystem with external journal",
3733    "\
3734 This creates an ext2/3/4 filesystem on C<device> with
3735 an external journal on C<journal>.  It is equivalent
3736 to the command:
3737
3738  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3739
3740 See also C<guestfs_mke2journal>.");
3741
3742   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3743    [],
3744    "make ext2/3/4 filesystem with external journal",
3745    "\
3746 This creates an ext2/3/4 filesystem on C<device> with
3747 an external journal on the journal labeled C<label>.
3748
3749 See also C<guestfs_mke2journal_L>.");
3750
3751   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3752    [],
3753    "make ext2/3/4 filesystem with external journal",
3754    "\
3755 This creates an ext2/3/4 filesystem on C<device> with
3756 an external journal on the journal with UUID C<uuid>.
3757
3758 See also C<guestfs_mke2journal_U>.");
3759
3760   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3761    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3762    "load a kernel module",
3763    "\
3764 This loads a kernel module in the appliance.
3765
3766 The kernel module must have been whitelisted when libguestfs
3767 was built (see C<appliance/kmod.whitelist.in> in the source).");
3768
3769   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3770    [InitNone, Always, TestOutput (
3771       [["echo_daemon"; "This is a test"]], "This is a test"
3772     )],
3773    "echo arguments back to the client",
3774    "\
3775 This command concatenate the list of C<words> passed with single spaces between
3776 them and returns the resulting string.
3777
3778 You can use this command to test the connection through to the daemon.
3779
3780 See also C<guestfs_ping_daemon>.");
3781
3782   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3783    [], (* There is a regression test for this. *)
3784    "find all files and directories, returning NUL-separated list",
3785    "\
3786 This command lists out all files and directories, recursively,
3787 starting at C<directory>, placing the resulting list in the
3788 external file called C<files>.
3789
3790 This command works the same way as C<guestfs_find> with the
3791 following exceptions:
3792
3793 =over 4
3794
3795 =item *
3796
3797 The resulting list is written to an external file.
3798
3799 =item *
3800
3801 Items (filenames) in the result are separated
3802 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3803
3804 =item *
3805
3806 This command is not limited in the number of names that it
3807 can return.
3808
3809 =item *
3810
3811 The result list is not sorted.
3812
3813 =back");
3814
3815   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3816    [InitISOFS, Always, TestOutput (
3817       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3818     InitISOFS, Always, TestOutput (
3819       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3820     InitISOFS, Always, TestOutput (
3821       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3822     InitISOFS, Always, TestLastFail (
3823       [["case_sensitive_path"; "/Known-1/"]]);
3824     InitBasicFS, Always, TestOutput (
3825       [["mkdir"; "/a"];
3826        ["mkdir"; "/a/bbb"];
3827        ["touch"; "/a/bbb/c"];
3828        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3829     InitBasicFS, Always, TestOutput (
3830       [["mkdir"; "/a"];
3831        ["mkdir"; "/a/bbb"];
3832        ["touch"; "/a/bbb/c"];
3833        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3834     InitBasicFS, Always, TestLastFail (
3835       [["mkdir"; "/a"];
3836        ["mkdir"; "/a/bbb"];
3837        ["touch"; "/a/bbb/c"];
3838        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3839    "return true path on case-insensitive filesystem",
3840    "\
3841 This can be used to resolve case insensitive paths on
3842 a filesystem which is case sensitive.  The use case is
3843 to resolve paths which you have read from Windows configuration
3844 files or the Windows Registry, to the true path.
3845
3846 The command handles a peculiarity of the Linux ntfs-3g
3847 filesystem driver (and probably others), which is that although
3848 the underlying filesystem is case-insensitive, the driver
3849 exports the filesystem to Linux as case-sensitive.
3850
3851 One consequence of this is that special directories such
3852 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3853 (or other things) depending on the precise details of how
3854 they were created.  In Windows itself this would not be
3855 a problem.
3856
3857 Bug or feature?  You decide:
3858 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3859
3860 This function resolves the true case of each element in the
3861 path and returns the case-sensitive path.
3862
3863 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3864 might return C<\"/WINDOWS/system32\"> (the exact return value
3865 would depend on details of how the directories were originally
3866 created under Windows).
3867
3868 I<Note>:
3869 This function does not handle drive names, backslashes etc.
3870
3871 See also C<guestfs_realpath>.");
3872
3873   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3874    [InitBasicFS, Always, TestOutput (
3875       [["vfs_type"; "/dev/sda1"]], "ext2")],
3876    "get the Linux VFS type corresponding to a mounted device",
3877    "\
3878 This command gets the block device type corresponding to
3879 a mounted device called C<device>.
3880
3881 Usually the result is the name of the Linux VFS module that
3882 is used to mount this device (probably determined automatically
3883 if you used the C<guestfs_mount> call).");
3884
3885   ("truncate", (RErr, [Pathname "path"]), 199, [],
3886    [InitBasicFS, Always, TestOutputStruct (
3887       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3888        ["truncate"; "/test"];
3889        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3890    "truncate a file to zero size",
3891    "\
3892 This command truncates C<path> to a zero-length file.  The
3893 file must exist already.");
3894
3895   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3896    [InitBasicFS, Always, TestOutputStruct (
3897       [["touch"; "/test"];
3898        ["truncate_size"; "/test"; "1000"];
3899        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3900    "truncate a file to a particular size",
3901    "\
3902 This command truncates C<path> to size C<size> bytes.  The file
3903 must exist already.  If the file is smaller than C<size> then
3904 the file is extended to the required size with null bytes.");
3905
3906   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3907    [InitBasicFS, Always, TestOutputStruct (
3908       [["touch"; "/test"];
3909        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3910        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3911    "set timestamp of a file with nanosecond precision",
3912    "\
3913 This command sets the timestamps of a file with nanosecond
3914 precision.
3915
3916 C<atsecs, atnsecs> are the last access time (atime) in secs and
3917 nanoseconds from the epoch.
3918
3919 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3920 secs and nanoseconds from the epoch.
3921
3922 If the C<*nsecs> field contains the special value C<-1> then
3923 the corresponding timestamp is set to the current time.  (The
3924 C<*secs> field is ignored in this case).
3925
3926 If the C<*nsecs> field contains the special value C<-2> then
3927 the corresponding timestamp is left unchanged.  (The
3928 C<*secs> field is ignored in this case).");
3929
3930   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3931    [InitBasicFS, Always, TestOutputStruct (
3932       [["mkdir_mode"; "/test"; "0o111"];
3933        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3934    "create a directory with a particular mode",
3935    "\
3936 This command creates a directory, setting the initial permissions
3937 of the directory to C<mode>.
3938
3939 For common Linux filesystems, the actual mode which is set will
3940 be C<mode & ~umask & 01777>.  Non-native-Linux filesystems may
3941 interpret the mode in other ways.
3942
3943 See also C<guestfs_mkdir>, C<guestfs_umask>");
3944
3945   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3946    [], (* XXX *)
3947    "change file owner and group",
3948    "\
3949 Change the file owner to C<owner> and group to C<group>.
3950 This is like C<guestfs_chown> but if C<path> is a symlink then
3951 the link itself is changed, not the target.
3952
3953 Only numeric uid and gid are supported.  If you want to use
3954 names, you will need to locate and parse the password file
3955 yourself (Augeas support makes this relatively easy).");
3956
3957   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3958    [], (* XXX *)
3959    "lstat on multiple files",
3960    "\
3961 This call allows you to perform the C<guestfs_lstat> operation
3962 on multiple files, where all files are in the directory C<path>.
3963 C<names> is the list of files from this directory.
3964
3965 On return you get a list of stat structs, with a one-to-one
3966 correspondence to the C<names> list.  If any name did not exist
3967 or could not be lstat'd, then the C<ino> field of that structure
3968 is set to C<-1>.
3969
3970 This call is intended for programs that want to efficiently
3971 list a directory contents without making many round-trips.
3972 See also C<guestfs_lxattrlist> for a similarly efficient call
3973 for getting extended attributes.  Very long directory listings
3974 might cause the protocol message size to be exceeded, causing
3975 this call to fail.  The caller must split up such requests
3976 into smaller groups of names.");
3977
3978   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3979    [], (* XXX *)
3980    "lgetxattr on multiple files",
3981    "\
3982 This call allows you to get the extended attributes
3983 of multiple files, where all files are in the directory C<path>.
3984 C<names> is the list of files from this directory.
3985
3986 On return you get a flat list of xattr structs which must be
3987 interpreted sequentially.  The first xattr struct always has a zero-length
3988 C<attrname>.  C<attrval> in this struct is zero-length
3989 to indicate there was an error doing C<lgetxattr> for this
3990 file, I<or> is a C string which is a decimal number
3991 (the number of following attributes for this file, which could
3992 be C<\"0\">).  Then after the first xattr struct are the
3993 zero or more attributes for the first named file.
3994 This repeats for the second and subsequent files.
3995
3996 This call is intended for programs that want to efficiently
3997 list a directory contents without making many round-trips.
3998 See also C<guestfs_lstatlist> for a similarly efficient call
3999 for getting standard stats.  Very long directory listings
4000 might cause the protocol message size to be exceeded, causing
4001 this call to fail.  The caller must split up such requests
4002 into smaller groups of names.");
4003
4004   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
4005    [], (* XXX *)
4006    "readlink on multiple files",
4007    "\
4008 This call allows you to do a C<readlink> operation
4009 on multiple files, where all files are in the directory C<path>.
4010 C<names> is the list of files from this directory.
4011
4012 On return you get a list of strings, with a one-to-one
4013 correspondence to the C<names> list.  Each string is the
4014 value of the symbol link.
4015
4016 If the C<readlink(2)> operation fails on any name, then
4017 the corresponding result string is the empty string C<\"\">.
4018 However the whole operation is completed even if there
4019 were C<readlink(2)> errors, and so you can call this
4020 function with names where you don't know if they are
4021 symbolic links already (albeit slightly less efficient).
4022
4023 This call is intended for programs that want to efficiently
4024 list a directory contents without making many round-trips.
4025 Very long directory listings might cause the protocol
4026 message size to be exceeded, causing
4027 this call to fail.  The caller must split up such requests
4028 into smaller groups of names.");
4029
4030   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
4031    [InitISOFS, Always, TestOutputBuffer (
4032       [["pread"; "/known-4"; "1"; "3"]], "\n");
4033     InitISOFS, Always, TestOutputBuffer (
4034       [["pread"; "/empty"; "0"; "100"]], "")],
4035    "read part of a file",
4036    "\
4037 This command lets you read part of a file.  It reads C<count>
4038 bytes of the file, starting at C<offset>, from file C<path>.
4039
4040 This may read fewer bytes than requested.  For further details
4041 see the L<pread(2)> system call.");
4042
4043   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
4044    [InitEmpty, Always, TestRun (
4045       [["part_init"; "/dev/sda"; "gpt"]])],
4046    "create an empty partition table",
4047    "\
4048 This creates an empty partition table on C<device> of one of the
4049 partition types listed below.  Usually C<parttype> should be
4050 either C<msdos> or C<gpt> (for large disks).
4051
4052 Initially there are no partitions.  Following this, you should
4053 call C<guestfs_part_add> for each partition required.
4054
4055 Possible values for C<parttype> are:
4056
4057 =over 4
4058
4059 =item B<efi> | B<gpt>
4060
4061 Intel EFI / GPT partition table.
4062
4063 This is recommended for >= 2 TB partitions that will be accessed
4064 from Linux and Intel-based Mac OS X.  It also has limited backwards
4065 compatibility with the C<mbr> format.
4066
4067 =item B<mbr> | B<msdos>
4068
4069 The standard PC \"Master Boot Record\" (MBR) format used
4070 by MS-DOS and Windows.  This partition type will B<only> work
4071 for device sizes up to 2 TB.  For large disks we recommend
4072 using C<gpt>.
4073
4074 =back
4075
4076 Other partition table types that may work but are not
4077 supported include:
4078
4079 =over 4
4080
4081 =item B<aix>
4082
4083 AIX disk labels.
4084
4085 =item B<amiga> | B<rdb>
4086
4087 Amiga \"Rigid Disk Block\" format.
4088
4089 =item B<bsd>
4090
4091 BSD disk labels.
4092
4093 =item B<dasd>
4094
4095 DASD, used on IBM mainframes.
4096
4097 =item B<dvh>
4098
4099 MIPS/SGI volumes.
4100
4101 =item B<mac>
4102
4103 Old Mac partition format.  Modern Macs use C<gpt>.
4104
4105 =item B<pc98>
4106
4107 NEC PC-98 format, common in Japan apparently.
4108
4109 =item B<sun>
4110
4111 Sun disk labels.
4112
4113 =back");
4114
4115   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
4116    [InitEmpty, Always, TestRun (
4117       [["part_init"; "/dev/sda"; "mbr"];
4118        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
4119     InitEmpty, Always, TestRun (
4120       [["part_init"; "/dev/sda"; "gpt"];
4121        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
4122        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
4123     InitEmpty, Always, TestRun (
4124       [["part_init"; "/dev/sda"; "mbr"];
4125        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
4126        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4127        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4128        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4129    "add a partition to the device",
4130    "\
4131 This command adds a partition to C<device>.  If there is no partition
4132 table on the device, call C<guestfs_part_init> first.
4133
4134 The C<prlogex> parameter is the type of partition.  Normally you
4135 should pass C<p> or C<primary> here, but MBR partition tables also
4136 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4137 types.
4138
4139 C<startsect> and C<endsect> are the start and end of the partition
4140 in I<sectors>.  C<endsect> may be negative, which means it counts
4141 backwards from the end of the disk (C<-1> is the last sector).
4142
4143 Creating a partition which covers the whole disk is not so easy.
4144 Use C<guestfs_part_disk> to do that.");
4145
4146   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4147    [InitEmpty, Always, TestRun (
4148       [["part_disk"; "/dev/sda"; "mbr"]]);
4149     InitEmpty, Always, TestRun (
4150       [["part_disk"; "/dev/sda"; "gpt"]])],
4151    "partition whole disk with a single primary partition",
4152    "\
4153 This command is simply a combination of C<guestfs_part_init>
4154 followed by C<guestfs_part_add> to create a single primary partition
4155 covering the whole disk.
4156
4157 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4158 but other possible values are described in C<guestfs_part_init>.");
4159
4160   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4161    [InitEmpty, Always, TestRun (
4162       [["part_disk"; "/dev/sda"; "mbr"];
4163        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4164    "make a partition bootable",
4165    "\
4166 This sets the bootable flag on partition numbered C<partnum> on
4167 device C<device>.  Note that partitions are numbered from 1.
4168
4169 The bootable flag is used by some operating systems (notably
4170 Windows) to determine which partition to boot from.  It is by
4171 no means universally recognized.");
4172
4173   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4174    [InitEmpty, Always, TestRun (
4175       [["part_disk"; "/dev/sda"; "gpt"];
4176        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4177    "set partition name",
4178    "\
4179 This sets the partition name on partition numbered C<partnum> on
4180 device C<device>.  Note that partitions are numbered from 1.
4181
4182 The partition name can only be set on certain types of partition
4183 table.  This works on C<gpt> but not on C<mbr> partitions.");
4184
4185   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4186    [], (* XXX Add a regression test for this. *)
4187    "list partitions on a device",
4188    "\
4189 This command parses the partition table on C<device> and
4190 returns the list of partitions found.
4191
4192 The fields in the returned structure are:
4193
4194 =over 4
4195
4196 =item B<part_num>
4197
4198 Partition number, counting from 1.
4199
4200 =item B<part_start>
4201
4202 Start of the partition I<in bytes>.  To get sectors you have to
4203 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4204
4205 =item B<part_end>
4206
4207 End of the partition in bytes.
4208
4209 =item B<part_size>
4210
4211 Size of the partition in bytes.
4212
4213 =back");
4214
4215   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4216    [InitEmpty, Always, TestOutput (
4217       [["part_disk"; "/dev/sda"; "gpt"];
4218        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4219    "get the partition table type",
4220    "\
4221 This command examines the partition table on C<device> and
4222 returns the partition table type (format) being used.
4223
4224 Common return values include: C<msdos> (a DOS/Windows style MBR
4225 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4226 values are possible, although unusual.  See C<guestfs_part_init>
4227 for a full list.");
4228
4229   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4230    [InitBasicFS, Always, TestOutputBuffer (
4231       [["fill"; "0x63"; "10"; "/test"];
4232        ["read_file"; "/test"]], "cccccccccc")],
4233    "fill a file with octets",
4234    "\
4235 This command creates a new file called C<path>.  The initial
4236 content of the file is C<len> octets of C<c>, where C<c>
4237 must be a number in the range C<[0..255]>.
4238
4239 To fill a file with zero bytes (sparsely), it is
4240 much more efficient to use C<guestfs_truncate_size>.");
4241
4242   ("available", (RErr, [StringList "groups"]), 216, [],
4243    [InitNone, Always, TestRun [["available"; ""]]],
4244    "test availability of some parts of the API",
4245    "\
4246 This command is used to check the availability of some
4247 groups of functionality in the appliance, which not all builds of
4248 the libguestfs appliance will be able to provide.
4249
4250 The libguestfs groups, and the functions that those
4251 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4252
4253 The argument C<groups> is a list of group names, eg:
4254 C<[\"inotify\", \"augeas\"]> would check for the availability of
4255 the Linux inotify functions and Augeas (configuration file
4256 editing) functions.
4257
4258 The command returns no error if I<all> requested groups are available.
4259
4260 It fails with an error if one or more of the requested
4261 groups is unavailable in the appliance.
4262
4263 If an unknown group name is included in the
4264 list of groups then an error is always returned.
4265
4266 I<Notes:>
4267
4268 =over 4
4269
4270 =item *
4271
4272 You must call C<guestfs_launch> before calling this function.
4273
4274 The reason is because we don't know what groups are
4275 supported by the appliance/daemon until it is running and can
4276 be queried.
4277
4278 =item *
4279
4280 If a group of functions is available, this does not necessarily
4281 mean that they will work.  You still have to check for errors
4282 when calling individual API functions even if they are
4283 available.
4284
4285 =item *
4286
4287 It is usually the job of distro packagers to build
4288 complete functionality into the libguestfs appliance.
4289 Upstream libguestfs, if built from source with all
4290 requirements satisfied, will support everything.
4291
4292 =item *
4293
4294 This call was added in version C<1.0.80>.  In previous
4295 versions of libguestfs all you could do would be to speculatively
4296 execute a command to find out if the daemon implemented it.
4297 See also C<guestfs_version>.
4298
4299 =back");
4300
4301   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4302    [InitBasicFS, Always, TestOutputBuffer (
4303       [["write_file"; "/src"; "hello, world"; "0"];
4304        ["dd"; "/src"; "/dest"];
4305        ["read_file"; "/dest"]], "hello, world")],
4306    "copy from source to destination using dd",
4307    "\
4308 This command copies from one source device or file C<src>
4309 to another destination device or file C<dest>.  Normally you
4310 would use this to copy to or from a device or partition, for
4311 example to duplicate a filesystem.
4312
4313 If the destination is a device, it must be as large or larger
4314 than the source file or device, otherwise the copy will fail.
4315 This command cannot do partial copies (see C<guestfs_copy_size>).");
4316
4317   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4318    [InitBasicFS, Always, TestOutputInt (
4319       [["write_file"; "/file"; "hello, world"; "0"];
4320        ["filesize"; "/file"]], 12)],
4321    "return the size of the file in bytes",
4322    "\
4323 This command returns the size of C<file> in bytes.
4324
4325 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4326 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4327 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4328
4329   ("lvrename", (RErr, [String "logvol"; String "newlogvol"]), 219, [],
4330    [InitBasicFSonLVM, Always, TestOutputList (
4331       [["lvrename"; "/dev/VG/LV"; "/dev/VG/LV2"];
4332        ["lvs"]], ["/dev/VG/LV2"])],
4333    "rename an LVM logical volume",
4334    "\
4335 Rename a logical volume C<logvol> with the new name C<newlogvol>.");
4336
4337   ("vgrename", (RErr, [String "volgroup"; String "newvolgroup"]), 220, [],
4338    [InitBasicFSonLVM, Always, TestOutputList (
4339       [["umount"; "/"];
4340        ["vg_activate"; "false"; "VG"];
4341        ["vgrename"; "VG"; "VG2"];
4342        ["vg_activate"; "true"; "VG2"];
4343        ["mount_options"; ""; "/dev/VG2/LV"; "/"];
4344        ["vgs"]], ["VG2"])],
4345    "rename an LVM volume group",
4346    "\
4347 Rename a volume group C<volgroup> with the new name C<newvolgroup>.");
4348
4349   ("initrd_cat", (RBufferOut "content", [Pathname "initrdpath"; String "filename"]), 221, [ProtocolLimitWarning],
4350    [InitISOFS, Always, TestOutputBuffer (
4351       [["initrd_cat"; "/initrd"; "known-4"]], "abc\ndef\nghi")],
4352    "list the contents of a single file in an initrd",
4353    "\
4354 This command unpacks the file C<filename> from the initrd file
4355 called C<initrdpath>.  The filename must be given I<without> the
4356 initial C</> character.
4357
4358 For example, in guestfish you could use the following command
4359 to examine the boot script (usually called C</init>)
4360 contained in a Linux initrd or initramfs image:
4361
4362  initrd-cat /boot/initrd-<version>.img init
4363
4364 See also C<guestfs_initrd_list>.");
4365
4366   ("pvuuid", (RString "uuid", [Device "device"]), 222, [],
4367    [],
4368    "get the UUID of a physical volume",
4369    "\
4370 This command returns the UUID of the LVM PV C<device>.");
4371
4372   ("vguuid", (RString "uuid", [String "vgname"]), 223, [],
4373    [],
4374    "get the UUID of a volume group",
4375    "\
4376 This command returns the UUID of the LVM VG named C<vgname>.");
4377
4378   ("lvuuid", (RString "uuid", [Device "device"]), 224, [],
4379    [],
4380    "get the UUID of a logical volume",
4381    "\
4382 This command returns the UUID of the LVM LV C<device>.");
4383
4384   ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [],
4385    [],
4386    "get the PV UUIDs containing the volume group",
4387    "\
4388 Given a VG called C<vgname>, this returns the UUIDs of all
4389 the physical volumes that this volume group resides on.
4390
4391 You can use this along with C<guestfs_pvs> and C<guestfs_pvuuid>
4392 calls to associate physical volumes and volume groups.
4393
4394 See also C<guestfs_vglvuuids>.");
4395
4396   ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [],
4397    [],
4398    "get the LV UUIDs of all LVs in the volume group",
4399    "\
4400 Given a VG called C<vgname>, this returns the UUIDs of all
4401 the logical volumes created in this volume group.
4402
4403 You can use this along with C<guestfs_lvs> and C<guestfs_lvuuid>
4404 calls to associate logical volumes and volume groups.
4405
4406 See also C<guestfs_vgpvuuids>.");
4407
4408   ("copy_size", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"; Int64 "size"]), 227, [],
4409    [InitBasicFS, Always, TestOutputBuffer (
4410       [["write_file"; "/src"; "hello, world"; "0"];
4411        ["copy_size"; "/src"; "/dest"; "5"];
4412        ["read_file"; "/dest"]], "hello")],
4413    "copy size bytes from source to destination using dd",
4414    "\
4415 This command copies exactly C<size> bytes from one source device
4416 or file C<src> to another destination device or file C<dest>.
4417
4418 Note this will fail if the source is too short or if the destination
4419 is not large enough.");
4420
4421   ("zero_device", (RErr, [Device "device"]), 228, [DangerWillRobinson],
4422    [InitBasicFSonLVM, Always, TestRun (
4423       [["zero_device"; "/dev/VG/LV"]])],
4424    "write zeroes to an entire device",
4425    "\
4426 This command writes zeroes over the entire C<device>.  Compare
4427 with C<guestfs_zero> which just zeroes the first few blocks of
4428 a device.");
4429
4430   ("txz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 229, [],
4431    [InitBasicFS, Always, TestOutput (
4432       [["txz_in"; "../images/helloworld.tar.xz"; "/"];
4433        ["cat"; "/hello"]], "hello\n")],
4434    "unpack compressed tarball to directory",
4435    "\
4436 This command uploads and unpacks local file C<tarball> (an
4437 I<xz compressed> tar file) into C<directory>.");
4438
4439   ("txz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 230, [],
4440    [],
4441    "pack directory into compressed tarball",
4442    "\
4443 This command packs the contents of C<directory> and downloads
4444 it to local file C<tarball> (as an xz compressed tar archive).");
4445
4446   ("ntfsresize", (RErr, [Device "device"]), 231, [Optional "ntfsprogs"],
4447    [],
4448    "resize an NTFS filesystem",
4449    "\
4450 This command resizes an NTFS filesystem, expanding or
4451 shrinking it to the size of the underlying device.
4452 See also L<ntfsresize(8)>.");
4453
4454   ("vgscan", (RErr, []), 232, [],
4455    [InitEmpty, Always, TestRun (
4456       [["vgscan"]])],
4457    "rescan for LVM physical volumes, volume groups and logical volumes",
4458    "\
4459 This rescans all block devices and rebuilds the list of LVM
4460 physical volumes, volume groups and logical volumes.");
4461
4462   ("part_del", (RErr, [Device "device"; Int "partnum"]), 233, [],
4463    [InitEmpty, Always, TestRun (
4464       [["part_init"; "/dev/sda"; "mbr"];
4465        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4466        ["part_del"; "/dev/sda"; "1"]])],
4467    "delete a partition",
4468    "\
4469 This command deletes the partition numbered C<partnum> on C<device>.
4470
4471 Note that in the case of MBR partitioning, deleting an
4472 extended partition also deletes any logical partitions
4473 it contains.");
4474
4475   ("part_get_bootable", (RBool "bootable", [Device "device"; Int "partnum"]), 234, [],
4476    [InitEmpty, Always, TestOutputTrue (
4477       [["part_init"; "/dev/sda"; "mbr"];
4478        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4479        ["part_set_bootable"; "/dev/sda"; "1"; "true"];
4480        ["part_get_bootable"; "/dev/sda"; "1"]])],
4481    "return true if a partition is bootable",
4482    "\
4483 This command returns true if the partition C<partnum> on
4484 C<device> has the bootable flag set.
4485
4486 See also C<guestfs_part_set_bootable>.");
4487
4488   ("part_get_mbr_id", (RInt "idbyte", [Device "device"; Int "partnum"]), 235, [FishOutput FishOutputHexadecimal],
4489    [InitEmpty, Always, TestOutputInt (
4490       [["part_init"; "/dev/sda"; "mbr"];
4491        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4492        ["part_set_mbr_id"; "/dev/sda"; "1"; "0x7f"];
4493        ["part_get_mbr_id"; "/dev/sda"; "1"]], 0x7f)],
4494    "get the MBR type byte (ID byte) from a partition",
4495    "\
4496 Returns the MBR type byte (also known as the ID byte) from
4497 the numbered partition C<partnum>.
4498
4499 Note that only MBR (old DOS-style) partitions have type bytes.
4500 You will get undefined results for other partition table
4501 types (see C<guestfs_part_get_parttype>).");
4502
4503   ("part_set_mbr_id", (RErr, [Device "device"; Int "partnum"; Int "idbyte"]), 236, [],
4504    [], (* tested by part_get_mbr_id *)
4505    "set the MBR type byte (ID byte) of a partition",
4506    "\
4507 Sets the MBR type byte (also known as the ID byte) of
4508 the numbered partition C<partnum> to C<idbyte>.  Note
4509 that the type bytes quoted in most documentation are
4510 in fact hexadecimal numbers, but usually documented
4511 without any leading \"0x\" which might be confusing.
4512
4513 Note that only MBR (old DOS-style) partitions have type bytes.
4514 You will get undefined results for other partition table
4515 types (see C<guestfs_part_get_parttype>).");
4516
4517   ("checksum_device", (RString "checksum", [String "csumtype"; Device "device"]), 237, [],
4518    [InitISOFS, Always, TestOutput (
4519       [["checksum_device"; "md5"; "/dev/sdd"]],
4520       (Digest.to_hex (Digest.file "images/test.iso")))],
4521    "compute MD5, SHAx or CRC checksum of the contents of a device",
4522    "\
4523 This call computes the MD5, SHAx or CRC checksum of the
4524 contents of the device named C<device>.  For the types of
4525 checksums supported see the C<guestfs_checksum> command.");
4526
4527   ("lvresize_free", (RErr, [Device "lv"; Int "percent"]), 238, [Optional "lvm2"],
4528    [InitNone, Always, TestRun (
4529       [["part_disk"; "/dev/sda"; "mbr"];
4530        ["pvcreate"; "/dev/sda1"];
4531        ["vgcreate"; "VG"; "/dev/sda1"];
4532        ["lvcreate"; "LV"; "VG"; "10"];
4533        ["lvresize_free"; "/dev/VG/LV"; "100"]])],
4534    "expand an LV to fill free space",
4535    "\
4536 This expands an existing logical volume C<lv> so that it fills
4537 C<pc>% of the remaining free space in the volume group.  Commonly
4538 you would call this with pc = 100 which expands the logical volume
4539 as much as possible, using all remaining free space in the volume
4540 group.");
4541
4542   ("aug_clear", (RErr, [String "augpath"]), 239, [Optional "augeas"],
4543    [], (* XXX Augeas code needs tests. *)
4544    "clear Augeas path",
4545    "\
4546 Set the value associated with C<path> to C<NULL>.  This
4547 is the same as the L<augtool(1)> C<clear> command.");
4548
4549   ("get_umask", (RInt "mask", []), 240, [FishOutput FishOutputOctal],
4550    [InitEmpty, Always, TestOutputInt (
4551       [["get_umask"]], 0o22)],
4552    "get the current umask",
4553    "\
4554 Return the current umask.  By default the umask is C<022>
4555 unless it has been set by calling C<guestfs_umask>.");
4556
4557   ("debug_upload", (RErr, [FileIn "filename"; String "tmpname"; Int "mode"]), 241, [],
4558    [],
4559    "upload a file to the appliance (internal use only)",
4560    "\
4561 The C<guestfs_debug_upload> command uploads a file to
4562 the libguestfs appliance.
4563
4564 There is no comprehensive help for this command.  You have
4565 to look at the file C<daemon/debug.c> in the libguestfs source
4566 to find out what it is for.");
4567
4568   ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [],
4569    [InitBasicFS, Always, TestOutput (
4570       [["base64_in"; "../images/hello.b64"; "/hello"];
4571        ["cat"; "/hello"]], "hello\n")],
4572    "upload base64-encoded data to file",
4573    "\
4574 This command uploads base64-encoded data from C<base64file>
4575 to C<filename>.");
4576
4577   ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [],
4578    [],
4579    "download file and encode as base64",
4580    "\
4581 This command downloads the contents of C<filename>, writing
4582 it out to local file C<base64file> encoded as base64.");
4583
4584   ("checksums_out", (RErr, [String "csumtype"; Pathname "directory"; FileOut "sumsfile"]), 244, [],
4585    [],
4586    "compute MD5, SHAx or CRC checksum of files in a directory",
4587    "\
4588 This command computes the checksums of all regular files in
4589 C<directory> and then emits a list of those checksums to
4590 the local output file C<sumsfile>.
4591
4592 This can be used for verifying the integrity of a virtual
4593 machine.  However to be properly secure you should pay
4594 attention to the output of the checksum command (it uses
4595 the ones from GNU coreutils).  In particular when the
4596 filename is not printable, coreutils uses a special
4597 backslash syntax.  For more information, see the GNU
4598 coreutils info file.");
4599
4600 ]
4601
4602 let all_functions = non_daemon_functions @ daemon_functions
4603
4604 (* In some places we want the functions to be displayed sorted
4605  * alphabetically, so this is useful:
4606  *)
4607 let all_functions_sorted =
4608   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4609                compare n1 n2) all_functions
4610
4611 (* Field types for structures. *)
4612 type field =
4613   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4614   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4615   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4616   | FUInt32
4617   | FInt32
4618   | FUInt64
4619   | FInt64
4620   | FBytes                      (* Any int measure that counts bytes. *)
4621   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4622   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4623
4624 (* Because we generate extra parsing code for LVM command line tools,
4625  * we have to pull out the LVM columns separately here.
4626  *)
4627 let lvm_pv_cols = [
4628   "pv_name", FString;
4629   "pv_uuid", FUUID;
4630   "pv_fmt", FString;
4631   "pv_size", FBytes;
4632   "dev_size", FBytes;
4633   "pv_free", FBytes;
4634   "pv_used", FBytes;
4635   "pv_attr", FString (* XXX *);
4636   "pv_pe_count", FInt64;
4637   "pv_pe_alloc_count", FInt64;
4638   "pv_tags", FString;
4639   "pe_start", FBytes;
4640   "pv_mda_count", FInt64;
4641   "pv_mda_free", FBytes;
4642   (* Not in Fedora 10:
4643      "pv_mda_size", FBytes;
4644   *)
4645 ]
4646 let lvm_vg_cols = [
4647   "vg_name", FString;
4648   "vg_uuid", FUUID;
4649   "vg_fmt", FString;
4650   "vg_attr", FString (* XXX *);
4651   "vg_size", FBytes;
4652   "vg_free", FBytes;
4653   "vg_sysid", FString;
4654   "vg_extent_size", FBytes;
4655   "vg_extent_count", FInt64;
4656   "vg_free_count", FInt64;
4657   "max_lv", FInt64;
4658   "max_pv", FInt64;
4659   "pv_count", FInt64;
4660   "lv_count", FInt64;
4661   "snap_count", FInt64;
4662   "vg_seqno", FInt64;
4663   "vg_tags", FString;
4664   "vg_mda_count", FInt64;
4665   "vg_mda_free", FBytes;
4666   (* Not in Fedora 10:
4667      "vg_mda_size", FBytes;
4668   *)
4669 ]
4670 let lvm_lv_cols = [
4671   "lv_name", FString;
4672   "lv_uuid", FUUID;
4673   "lv_attr", FString (* XXX *);
4674   "lv_major", FInt64;
4675   "lv_minor", FInt64;
4676   "lv_kernel_major", FInt64;
4677   "lv_kernel_minor", FInt64;
4678   "lv_size", FBytes;
4679   "seg_count", FInt64;
4680   "origin", FString;
4681   "snap_percent", FOptPercent;
4682   "copy_percent", FOptPercent;
4683   "move_pv", FString;
4684   "lv_tags", FString;
4685   "mirror_log", FString;
4686   "modules", FString;
4687 ]
4688
4689 (* Names and fields in all structures (in RStruct and RStructList)
4690  * that we support.
4691  *)
4692 let structs = [
4693   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4694    * not use this struct in any new code.
4695    *)
4696   "int_bool", [
4697     "i", FInt32;                (* for historical compatibility *)
4698     "b", FInt32;                (* for historical compatibility *)
4699   ];
4700
4701   (* LVM PVs, VGs, LVs. *)
4702   "lvm_pv", lvm_pv_cols;
4703   "lvm_vg", lvm_vg_cols;
4704   "lvm_lv", lvm_lv_cols;
4705
4706   (* Column names and types from stat structures.
4707    * NB. Can't use things like 'st_atime' because glibc header files
4708    * define some of these as macros.  Ugh.
4709    *)
4710   "stat", [
4711     "dev", FInt64;
4712     "ino", FInt64;
4713     "mode", FInt64;
4714     "nlink", FInt64;
4715     "uid", FInt64;
4716     "gid", FInt64;
4717     "rdev", FInt64;
4718     "size", FInt64;
4719     "blksize", FInt64;
4720     "blocks", FInt64;
4721     "atime", FInt64;
4722     "mtime", FInt64;
4723     "ctime", FInt64;
4724   ];
4725   "statvfs", [
4726     "bsize", FInt64;
4727     "frsize", FInt64;
4728     "blocks", FInt64;
4729     "bfree", FInt64;
4730     "bavail", FInt64;
4731     "files", FInt64;
4732     "ffree", FInt64;
4733     "favail", FInt64;
4734     "fsid", FInt64;
4735     "flag", FInt64;
4736     "namemax", FInt64;
4737   ];
4738
4739   (* Column names in dirent structure. *)
4740   "dirent", [
4741     "ino", FInt64;
4742     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4743     "ftyp", FChar;
4744     "name", FString;
4745   ];
4746
4747   (* Version numbers. *)
4748   "version", [
4749     "major", FInt64;
4750     "minor", FInt64;
4751     "release", FInt64;
4752     "extra", FString;
4753   ];
4754
4755   (* Extended attribute. *)
4756   "xattr", [
4757     "attrname", FString;
4758     "attrval", FBuffer;
4759   ];
4760
4761   (* Inotify events. *)
4762   "inotify_event", [
4763     "in_wd", FInt64;
4764     "in_mask", FUInt32;
4765     "in_cookie", FUInt32;
4766     "in_name", FString;
4767   ];
4768
4769   (* Partition table entry. *)
4770   "partition", [
4771     "part_num", FInt32;
4772     "part_start", FBytes;
4773     "part_end", FBytes;
4774     "part_size", FBytes;
4775   ];
4776 ] (* end of structs *)
4777
4778 (* Ugh, Java has to be different ..
4779  * These names are also used by the Haskell bindings.
4780  *)
4781 let java_structs = [
4782   "int_bool", "IntBool";
4783   "lvm_pv", "PV";
4784   "lvm_vg", "VG";
4785   "lvm_lv", "LV";
4786   "stat", "Stat";
4787   "statvfs", "StatVFS";
4788   "dirent", "Dirent";
4789   "version", "Version";
4790   "xattr", "XAttr";
4791   "inotify_event", "INotifyEvent";
4792   "partition", "Partition";
4793 ]
4794
4795 (* What structs are actually returned. *)
4796 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4797
4798 (* Returns a list of RStruct/RStructList structs that are returned
4799  * by any function.  Each element of returned list is a pair:
4800  *
4801  * (structname, RStructOnly)
4802  *    == there exists function which returns RStruct (_, structname)
4803  * (structname, RStructListOnly)
4804  *    == there exists function which returns RStructList (_, structname)
4805  * (structname, RStructAndList)
4806  *    == there are functions returning both RStruct (_, structname)
4807  *                                      and RStructList (_, structname)
4808  *)
4809 let rstructs_used_by functions =
4810   (* ||| is a "logical OR" for rstructs_used_t *)
4811   let (|||) a b =
4812     match a, b with
4813     | RStructAndList, _
4814     | _, RStructAndList -> RStructAndList
4815     | RStructOnly, RStructListOnly
4816     | RStructListOnly, RStructOnly -> RStructAndList
4817     | RStructOnly, RStructOnly -> RStructOnly
4818     | RStructListOnly, RStructListOnly -> RStructListOnly
4819   in
4820
4821   let h = Hashtbl.create 13 in
4822
4823   (* if elem->oldv exists, update entry using ||| operator,
4824    * else just add elem->newv to the hash
4825    *)
4826   let update elem newv =
4827     try  let oldv = Hashtbl.find h elem in
4828          Hashtbl.replace h elem (newv ||| oldv)
4829     with Not_found -> Hashtbl.add h elem newv
4830   in
4831
4832   List.iter (
4833     fun (_, style, _, _, _, _, _) ->
4834       match fst style with
4835       | RStruct (_, structname) -> update structname RStructOnly
4836       | RStructList (_, structname) -> update structname RStructListOnly
4837       | _ -> ()
4838   ) functions;
4839
4840   (* return key->values as a list of (key,value) *)
4841   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4842
4843 (* Used for testing language bindings. *)
4844 type callt =
4845   | CallString of string
4846   | CallOptString of string option
4847   | CallStringList of string list
4848   | CallInt of int
4849   | CallInt64 of int64
4850   | CallBool of bool
4851
4852 (* Used to memoize the result of pod2text. *)
4853 let pod2text_memo_filename = "src/.pod2text.data"
4854 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4855   try
4856     let chan = open_in pod2text_memo_filename in
4857     let v = input_value chan in
4858     close_in chan;
4859     v
4860   with
4861     _ -> Hashtbl.create 13
4862 let pod2text_memo_updated () =
4863   let chan = open_out pod2text_memo_filename in
4864   output_value chan pod2text_memo;
4865   close_out chan
4866
4867 (* Useful functions.
4868  * Note we don't want to use any external OCaml libraries which
4869  * makes this a bit harder than it should be.
4870  *)
4871 module StringMap = Map.Make (String)
4872
4873 let failwithf fs = ksprintf failwith fs
4874
4875 let unique = let i = ref 0 in fun () -> incr i; !i
4876
4877 let replace_char s c1 c2 =
4878   let s2 = String.copy s in
4879   let r = ref false in
4880   for i = 0 to String.length s2 - 1 do
4881     if String.unsafe_get s2 i = c1 then (
4882       String.unsafe_set s2 i c2;
4883       r := true
4884     )
4885   done;
4886   if not !r then s else s2
4887
4888 let isspace c =
4889   c = ' '
4890   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4891
4892 let triml ?(test = isspace) str =
4893   let i = ref 0 in
4894   let n = ref (String.length str) in
4895   while !n > 0 && test str.[!i]; do
4896     decr n;
4897     incr i
4898   done;
4899   if !i = 0 then str
4900   else String.sub str !i !n
4901
4902 let trimr ?(test = isspace) str =
4903   let n = ref (String.length str) in
4904   while !n > 0 && test str.[!n-1]; do
4905     decr n
4906   done;
4907   if !n = String.length str then str
4908   else String.sub str 0 !n
4909
4910 let trim ?(test = isspace) str =
4911   trimr ~test (triml ~test str)
4912
4913 let rec find s sub =
4914   let len = String.length s in
4915   let sublen = String.length sub in
4916   let rec loop i =
4917     if i <= len-sublen then (
4918       let rec loop2 j =
4919         if j < sublen then (
4920           if s.[i+j] = sub.[j] then loop2 (j+1)
4921           else -1
4922         ) else
4923           i (* found *)
4924       in
4925       let r = loop2 0 in
4926       if r = -1 then loop (i+1) else r
4927     ) else
4928       -1 (* not found *)
4929   in
4930   loop 0
4931
4932 let rec replace_str s s1 s2 =
4933   let len = String.length s in
4934   let sublen = String.length s1 in
4935   let i = find s s1 in
4936   if i = -1 then s
4937   else (
4938     let s' = String.sub s 0 i in
4939     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4940     s' ^ s2 ^ replace_str s'' s1 s2
4941   )
4942
4943 let rec string_split sep str =
4944   let len = String.length str in
4945   let seplen = String.length sep in
4946   let i = find str sep in
4947   if i = -1 then [str]
4948   else (
4949     let s' = String.sub str 0 i in
4950     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4951     s' :: string_split sep s''
4952   )
4953
4954 let files_equal n1 n2 =
4955   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4956   match Sys.command cmd with
4957   | 0 -> true
4958   | 1 -> false
4959   | i -> failwithf "%s: failed with error code %d" cmd i
4960
4961 let rec filter_map f = function
4962   | [] -> []
4963   | x :: xs ->
4964       match f x with
4965       | Some y -> y :: filter_map f xs
4966       | None -> filter_map f xs
4967
4968 let rec find_map f = function
4969   | [] -> raise Not_found
4970   | x :: xs ->
4971       match f x with
4972       | Some y -> y
4973       | None -> find_map f xs
4974
4975 let iteri f xs =
4976   let rec loop i = function
4977     | [] -> ()
4978     | x :: xs -> f i x; loop (i+1) xs
4979   in
4980   loop 0 xs
4981
4982 let mapi f xs =
4983   let rec loop i = function
4984     | [] -> []
4985     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4986   in
4987   loop 0 xs
4988
4989 let count_chars c str =
4990   let count = ref 0 in
4991   for i = 0 to String.length str - 1 do
4992     if c = String.unsafe_get str i then incr count
4993   done;
4994   !count
4995
4996 let name_of_argt = function
4997   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4998   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4999   | FileIn n | FileOut n -> n
5000
5001 let java_name_of_struct typ =
5002   try List.assoc typ java_structs
5003   with Not_found ->
5004     failwithf
5005       "java_name_of_struct: no java_structs entry corresponding to %s" typ
5006
5007 let cols_of_struct typ =
5008   try List.assoc typ structs
5009   with Not_found ->
5010     failwithf "cols_of_struct: unknown struct %s" typ
5011
5012 let seq_of_test = function
5013   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
5014   | TestOutputListOfDevices (s, _)
5015   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
5016   | TestOutputTrue s | TestOutputFalse s
5017   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
5018   | TestOutputStruct (s, _)
5019   | TestLastFail s -> s
5020
5021 (* Handling for function flags. *)
5022 let protocol_limit_warning =
5023   "Because of the message protocol, there is a transfer limit
5024 of somewhere between 2MB and 4MB.  See L<guestfs(3)/PROTOCOL LIMITS>."
5025
5026 let danger_will_robinson =
5027   "B<This command is dangerous.  Without careful use you
5028 can easily destroy all your data>."
5029
5030 let deprecation_notice flags =
5031   try
5032     let alt =
5033       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
5034     let txt =
5035       sprintf "This function is deprecated.
5036 In new code, use the C<%s> call instead.
5037
5038 Deprecated functions will not be removed from the API, but the
5039 fact that they are deprecated indicates that there are problems
5040 with correct use of these functions." alt in
5041     Some txt
5042   with
5043     Not_found -> None
5044
5045 (* Create list of optional groups. *)
5046 let optgroups =
5047   let h = Hashtbl.create 13 in
5048   List.iter (
5049     fun (name, _, _, flags, _, _, _) ->
5050       List.iter (
5051         function
5052         | Optional group ->
5053             let names = try Hashtbl.find h group with Not_found -> [] in
5054             Hashtbl.replace h group (name :: names)
5055         | _ -> ()
5056       ) flags
5057   ) daemon_functions;
5058   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
5059   let groups =
5060     List.map (
5061       fun group -> group, List.sort compare (Hashtbl.find h group)
5062     ) groups in
5063   List.sort (fun x y -> compare (fst x) (fst y)) groups
5064
5065 (* Check function names etc. for consistency. *)
5066 let check_functions () =
5067   let contains_uppercase str =
5068     let len = String.length str in
5069     let rec loop i =
5070       if i >= len then false
5071       else (
5072         let c = str.[i] in
5073         if c >= 'A' && c <= 'Z' then true
5074         else loop (i+1)
5075       )
5076     in
5077     loop 0
5078   in
5079
5080   (* Check function names. *)
5081   List.iter (
5082     fun (name, _, _, _, _, _, _) ->
5083       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
5084         failwithf "function name %s does not need 'guestfs' prefix" name;
5085       if name = "" then
5086         failwithf "function name is empty";
5087       if name.[0] < 'a' || name.[0] > 'z' then
5088         failwithf "function name %s must start with lowercase a-z" name;
5089       if String.contains name '-' then
5090         failwithf "function name %s should not contain '-', use '_' instead."
5091           name
5092   ) all_functions;
5093
5094   (* Check function parameter/return names. *)
5095   List.iter (
5096     fun (name, style, _, _, _, _, _) ->
5097       let check_arg_ret_name n =
5098         if contains_uppercase n then
5099           failwithf "%s param/ret %s should not contain uppercase chars"
5100             name n;
5101         if String.contains n '-' || String.contains n '_' then
5102           failwithf "%s param/ret %s should not contain '-' or '_'"
5103             name n;
5104         if n = "value" then
5105           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;
5106         if n = "int" || n = "char" || n = "short" || n = "long" then
5107           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
5108         if n = "i" || n = "n" then
5109           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
5110         if n = "argv" || n = "args" then
5111           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
5112
5113         (* List Haskell, OCaml and C keywords here.
5114          * http://www.haskell.org/haskellwiki/Keywords
5115          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
5116          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
5117          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
5118          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
5119          * Omitting _-containing words, since they're handled above.
5120          * Omitting the OCaml reserved word, "val", is ok,
5121          * and saves us from renaming several parameters.
5122          *)
5123         let reserved = [
5124           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
5125           "char"; "class"; "const"; "constraint"; "continue"; "data";
5126           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
5127           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
5128           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
5129           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
5130           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
5131           "interface";
5132           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
5133           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
5134           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
5135           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
5136           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
5137           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
5138           "volatile"; "when"; "where"; "while";
5139           ] in
5140         if List.mem n reserved then
5141           failwithf "%s has param/ret using reserved word %s" name n;
5142       in
5143
5144       (match fst style with
5145        | RErr -> ()
5146        | RInt n | RInt64 n | RBool n
5147        | RConstString n | RConstOptString n | RString n
5148        | RStringList n | RStruct (n, _) | RStructList (n, _)
5149        | RHashtable n | RBufferOut n ->
5150            check_arg_ret_name n
5151       );
5152       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
5153   ) all_functions;
5154
5155   (* Check short descriptions. *)
5156   List.iter (
5157     fun (name, _, _, _, _, shortdesc, _) ->
5158       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
5159         failwithf "short description of %s should begin with lowercase." name;
5160       let c = shortdesc.[String.length shortdesc-1] in
5161       if c = '\n' || c = '.' then
5162         failwithf "short description of %s should not end with . or \\n." name
5163   ) all_functions;
5164
5165   (* Check long descriptions. *)
5166   List.iter (
5167     fun (name, _, _, _, _, _, longdesc) ->
5168       if longdesc.[String.length longdesc-1] = '\n' then
5169         failwithf "long description of %s should not end with \\n." name
5170   ) all_functions;
5171
5172   (* Check proc_nrs. *)
5173   List.iter (
5174     fun (name, _, proc_nr, _, _, _, _) ->
5175       if proc_nr <= 0 then
5176         failwithf "daemon function %s should have proc_nr > 0" name
5177   ) daemon_functions;
5178
5179   List.iter (
5180     fun (name, _, proc_nr, _, _, _, _) ->
5181       if proc_nr <> -1 then
5182         failwithf "non-daemon function %s should have proc_nr -1" name
5183   ) non_daemon_functions;
5184
5185   let proc_nrs =
5186     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
5187       daemon_functions in
5188   let proc_nrs =
5189     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
5190   let rec loop = function
5191     | [] -> ()
5192     | [_] -> ()
5193     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
5194         loop rest
5195     | (name1,nr1) :: (name2,nr2) :: _ ->
5196         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
5197           name1 name2 nr1 nr2
5198   in
5199   loop proc_nrs;
5200
5201   (* Check tests. *)
5202   List.iter (
5203     function
5204       (* Ignore functions that have no tests.  We generate a
5205        * warning when the user does 'make check' instead.
5206        *)
5207     | name, _, _, _, [], _, _ -> ()
5208     | name, _, _, _, tests, _, _ ->
5209         let funcs =
5210           List.map (
5211             fun (_, _, test) ->
5212               match seq_of_test test with
5213               | [] ->
5214                   failwithf "%s has a test containing an empty sequence" name
5215               | cmds -> List.map List.hd cmds
5216           ) tests in
5217         let funcs = List.flatten funcs in
5218
5219         let tested = List.mem name funcs in
5220
5221         if not tested then
5222           failwithf "function %s has tests but does not test itself" name
5223   ) all_functions
5224
5225 (* 'pr' prints to the current output file. *)
5226 let chan = ref Pervasives.stdout
5227 let lines = ref 0
5228 let pr fs =
5229   ksprintf
5230     (fun str ->
5231        let i = count_chars '\n' str in
5232        lines := !lines + i;
5233        output_string !chan str
5234     ) fs
5235
5236 let copyright_years =
5237   let this_year = 1900 + (localtime (time ())).tm_year in
5238   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
5239
5240 (* Generate a header block in a number of standard styles. *)
5241 type comment_style =
5242     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
5243 type license = GPLv2plus | LGPLv2plus
5244
5245 let generate_header ?(extra_inputs = []) comment license =
5246   let inputs = "src/generator.ml" :: extra_inputs in
5247   let c = match comment with
5248     | CStyle ->         pr "/* "; " *"
5249     | CPlusPlusStyle -> pr "// "; "//"
5250     | HashStyle ->      pr "# ";  "#"
5251     | OCamlStyle ->     pr "(* "; " *"
5252     | HaskellStyle ->   pr "{- "; "  " in
5253   pr "libguestfs generated file\n";
5254   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
5255   List.iter (pr "%s   %s\n" c) inputs;
5256   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
5257   pr "%s\n" c;
5258   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
5259   pr "%s\n" c;
5260   (match license with
5261    | GPLv2plus ->
5262        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
5263        pr "%s it under the terms of the GNU General Public License as published by\n" c;
5264        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
5265        pr "%s (at your option) any later version.\n" c;
5266        pr "%s\n" c;
5267        pr "%s This program is distributed in the hope that it will be useful,\n" c;
5268        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5269        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
5270        pr "%s GNU General Public License for more details.\n" c;
5271        pr "%s\n" c;
5272        pr "%s You should have received a copy of the GNU General Public License along\n" c;
5273        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
5274        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
5275
5276    | LGPLv2plus ->
5277        pr "%s This library is free software; you can redistribute it and/or\n" c;
5278        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
5279        pr "%s License as published by the Free Software Foundation; either\n" c;
5280        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
5281        pr "%s\n" c;
5282        pr "%s This library is distributed in the hope that it will be useful,\n" c;
5283        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5284        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
5285        pr "%s Lesser General Public License for more details.\n" c;
5286        pr "%s\n" c;
5287        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
5288        pr "%s License along with this library; if not, write to the Free Software\n" c;
5289        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
5290   );
5291   (match comment with
5292    | CStyle -> pr " */\n"
5293    | CPlusPlusStyle
5294    | HashStyle -> ()
5295    | OCamlStyle -> pr " *)\n"
5296    | HaskellStyle -> pr "-}\n"
5297   );
5298   pr "\n"
5299
5300 (* Start of main code generation functions below this line. *)
5301
5302 (* Generate the pod documentation for the C API. *)
5303 let rec generate_actions_pod () =
5304   List.iter (
5305     fun (shortname, style, _, flags, _, _, longdesc) ->
5306       if not (List.mem NotInDocs flags) then (
5307         let name = "guestfs_" ^ shortname in
5308         pr "=head2 %s\n\n" name;
5309         pr " ";
5310         generate_prototype ~extern:false ~handle:"g" name style;
5311         pr "\n\n";
5312         pr "%s\n\n" longdesc;
5313         (match fst style with
5314          | RErr ->
5315              pr "This function returns 0 on success or -1 on error.\n\n"
5316          | RInt _ ->
5317              pr "On error this function returns -1.\n\n"
5318          | RInt64 _ ->
5319              pr "On error this function returns -1.\n\n"
5320          | RBool _ ->
5321              pr "This function returns a C truth value on success or -1 on error.\n\n"
5322          | RConstString _ ->
5323              pr "This function returns a string, or NULL on error.
5324 The string is owned by the guest handle and must I<not> be freed.\n\n"
5325          | RConstOptString _ ->
5326              pr "This function returns a string which may be NULL.
5327 There is way to return an error from this function.
5328 The string is owned by the guest handle and must I<not> be freed.\n\n"
5329          | RString _ ->
5330              pr "This function returns a string, or NULL on error.
5331 I<The caller must free the returned string after use>.\n\n"
5332          | RStringList _ ->
5333              pr "This function returns a NULL-terminated array of strings
5334 (like L<environ(3)>), or NULL if there was an error.
5335 I<The caller must free the strings and the array after use>.\n\n"
5336          | RStruct (_, typ) ->
5337              pr "This function returns a C<struct guestfs_%s *>,
5338 or NULL if there was an error.
5339 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
5340          | RStructList (_, typ) ->
5341              pr "This function returns a C<struct guestfs_%s_list *>
5342 (see E<lt>guestfs-structs.hE<gt>),
5343 or NULL if there was an error.
5344 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
5345          | RHashtable _ ->
5346              pr "This function returns a NULL-terminated array of
5347 strings, or NULL if there was an error.
5348 The array of strings will always have length C<2n+1>, where
5349 C<n> keys and values alternate, followed by the trailing NULL entry.
5350 I<The caller must free the strings and the array after use>.\n\n"
5351          | RBufferOut _ ->
5352              pr "This function returns a buffer, or NULL on error.
5353 The size of the returned buffer is written to C<*size_r>.
5354 I<The caller must free the returned buffer after use>.\n\n"
5355         );
5356         if List.mem ProtocolLimitWarning flags then
5357           pr "%s\n\n" protocol_limit_warning;
5358         if List.mem DangerWillRobinson flags then
5359           pr "%s\n\n" danger_will_robinson;
5360         match deprecation_notice flags with
5361         | None -> ()
5362         | Some txt -> pr "%s\n\n" txt
5363       )
5364   ) all_functions_sorted
5365
5366 and generate_structs_pod () =
5367   (* Structs documentation. *)
5368   List.iter (
5369     fun (typ, cols) ->
5370       pr "=head2 guestfs_%s\n" typ;
5371       pr "\n";
5372       pr " struct guestfs_%s {\n" typ;
5373       List.iter (
5374         function
5375         | name, FChar -> pr "   char %s;\n" name
5376         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5377         | name, FInt32 -> pr "   int32_t %s;\n" name
5378         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5379         | name, FInt64 -> pr "   int64_t %s;\n" name
5380         | name, FString -> pr "   char *%s;\n" name
5381         | name, FBuffer ->
5382             pr "   /* The next two fields describe a byte array. */\n";
5383             pr "   uint32_t %s_len;\n" name;
5384             pr "   char *%s;\n" name
5385         | name, FUUID ->
5386             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5387             pr "   char %s[32];\n" name
5388         | name, FOptPercent ->
5389             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5390             pr "   float %s;\n" name
5391       ) cols;
5392       pr " };\n";
5393       pr " \n";
5394       pr " struct guestfs_%s_list {\n" typ;
5395       pr "   uint32_t len; /* Number of elements in list. */\n";
5396       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5397       pr " };\n";
5398       pr " \n";
5399       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5400       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5401         typ typ;
5402       pr "\n"
5403   ) structs
5404
5405 and generate_availability_pod () =
5406   (* Availability documentation. *)
5407   pr "=over 4\n";
5408   pr "\n";
5409   List.iter (
5410     fun (group, functions) ->
5411       pr "=item B<%s>\n" group;
5412       pr "\n";
5413       pr "The following functions:\n";
5414       List.iter (pr "L</guestfs_%s>\n") functions;
5415       pr "\n"
5416   ) optgroups;
5417   pr "=back\n";
5418   pr "\n"
5419
5420 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5421  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5422  *
5423  * We have to use an underscore instead of a dash because otherwise
5424  * rpcgen generates incorrect code.
5425  *
5426  * This header is NOT exported to clients, but see also generate_structs_h.
5427  *)
5428 and generate_xdr () =
5429   generate_header CStyle LGPLv2plus;
5430
5431   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5432   pr "typedef string str<>;\n";
5433   pr "\n";
5434
5435   (* Internal structures. *)
5436   List.iter (
5437     function
5438     | typ, cols ->
5439         pr "struct guestfs_int_%s {\n" typ;
5440         List.iter (function
5441                    | name, FChar -> pr "  char %s;\n" name
5442                    | name, FString -> pr "  string %s<>;\n" name
5443                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5444                    | name, FUUID -> pr "  opaque %s[32];\n" name
5445                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5446                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5447                    | name, FOptPercent -> pr "  float %s;\n" name
5448                   ) cols;
5449         pr "};\n";
5450         pr "\n";
5451         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5452         pr "\n";
5453   ) structs;
5454
5455   List.iter (
5456     fun (shortname, style, _, _, _, _, _) ->
5457       let name = "guestfs_" ^ shortname in
5458
5459       (match snd style with
5460        | [] -> ()
5461        | args ->
5462            pr "struct %s_args {\n" name;
5463            List.iter (
5464              function
5465              | Pathname n | Device n | Dev_or_Path n | String n ->
5466                  pr "  string %s<>;\n" n
5467              | OptString n -> pr "  str *%s;\n" n
5468              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5469              | Bool n -> pr "  bool %s;\n" n
5470              | Int n -> pr "  int %s;\n" n
5471              | Int64 n -> pr "  hyper %s;\n" n
5472              | FileIn _ | FileOut _ -> ()
5473            ) args;
5474            pr "};\n\n"
5475       );
5476       (match fst style with
5477        | RErr -> ()
5478        | RInt n ->
5479            pr "struct %s_ret {\n" name;
5480            pr "  int %s;\n" n;
5481            pr "};\n\n"
5482        | RInt64 n ->
5483            pr "struct %s_ret {\n" name;
5484            pr "  hyper %s;\n" n;
5485            pr "};\n\n"
5486        | RBool n ->
5487            pr "struct %s_ret {\n" name;
5488            pr "  bool %s;\n" n;
5489            pr "};\n\n"
5490        | RConstString _ | RConstOptString _ ->
5491            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5492        | RString n ->
5493            pr "struct %s_ret {\n" name;
5494            pr "  string %s<>;\n" n;
5495            pr "};\n\n"
5496        | RStringList n ->
5497            pr "struct %s_ret {\n" name;
5498            pr "  str %s<>;\n" n;
5499            pr "};\n\n"
5500        | RStruct (n, typ) ->
5501            pr "struct %s_ret {\n" name;
5502            pr "  guestfs_int_%s %s;\n" typ n;
5503            pr "};\n\n"
5504        | RStructList (n, typ) ->
5505            pr "struct %s_ret {\n" name;
5506            pr "  guestfs_int_%s_list %s;\n" typ n;
5507            pr "};\n\n"
5508        | RHashtable n ->
5509            pr "struct %s_ret {\n" name;
5510            pr "  str %s<>;\n" n;
5511            pr "};\n\n"
5512        | RBufferOut n ->
5513            pr "struct %s_ret {\n" name;
5514            pr "  opaque %s<>;\n" n;
5515            pr "};\n\n"
5516       );
5517   ) daemon_functions;
5518
5519   (* Table of procedure numbers. *)
5520   pr "enum guestfs_procedure {\n";
5521   List.iter (
5522     fun (shortname, _, proc_nr, _, _, _, _) ->
5523       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5524   ) daemon_functions;
5525   pr "  GUESTFS_PROC_NR_PROCS\n";
5526   pr "};\n";
5527   pr "\n";
5528
5529   (* Having to choose a maximum message size is annoying for several
5530    * reasons (it limits what we can do in the API), but it (a) makes
5531    * the protocol a lot simpler, and (b) provides a bound on the size
5532    * of the daemon which operates in limited memory space.
5533    *)
5534   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5535   pr "\n";
5536
5537   (* Message header, etc. *)
5538   pr "\
5539 /* The communication protocol is now documented in the guestfs(3)
5540  * manpage.
5541  */
5542
5543 const GUESTFS_PROGRAM = 0x2000F5F5;
5544 const GUESTFS_PROTOCOL_VERSION = 1;
5545
5546 /* These constants must be larger than any possible message length. */
5547 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5548 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5549
5550 enum guestfs_message_direction {
5551   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5552   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5553 };
5554
5555 enum guestfs_message_status {
5556   GUESTFS_STATUS_OK = 0,
5557   GUESTFS_STATUS_ERROR = 1
5558 };
5559
5560 const GUESTFS_ERROR_LEN = 256;
5561
5562 struct guestfs_message_error {
5563   string error_message<GUESTFS_ERROR_LEN>;
5564 };
5565
5566 struct guestfs_message_header {
5567   unsigned prog;                     /* GUESTFS_PROGRAM */
5568   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5569   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5570   guestfs_message_direction direction;
5571   unsigned serial;                   /* message serial number */
5572   guestfs_message_status status;
5573 };
5574
5575 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5576
5577 struct guestfs_chunk {
5578   int cancel;                        /* if non-zero, transfer is cancelled */
5579   /* data size is 0 bytes if the transfer has finished successfully */
5580   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5581 };
5582 "
5583
5584 (* Generate the guestfs-structs.h file. *)
5585 and generate_structs_h () =
5586   generate_header CStyle LGPLv2plus;
5587
5588   (* This is a public exported header file containing various
5589    * structures.  The structures are carefully written to have
5590    * exactly the same in-memory format as the XDR structures that
5591    * we use on the wire to the daemon.  The reason for creating
5592    * copies of these structures here is just so we don't have to
5593    * export the whole of guestfs_protocol.h (which includes much
5594    * unrelated and XDR-dependent stuff that we don't want to be
5595    * public, or required by clients).
5596    *
5597    * To reiterate, we will pass these structures to and from the
5598    * client with a simple assignment or memcpy, so the format
5599    * must be identical to what rpcgen / the RFC defines.
5600    *)
5601
5602   (* Public structures. *)
5603   List.iter (
5604     fun (typ, cols) ->
5605       pr "struct guestfs_%s {\n" typ;
5606       List.iter (
5607         function
5608         | name, FChar -> pr "  char %s;\n" name
5609         | name, FString -> pr "  char *%s;\n" name
5610         | name, FBuffer ->
5611             pr "  uint32_t %s_len;\n" name;
5612             pr "  char *%s;\n" name
5613         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5614         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5615         | name, FInt32 -> pr "  int32_t %s;\n" name
5616         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5617         | name, FInt64 -> pr "  int64_t %s;\n" name
5618         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5619       ) cols;
5620       pr "};\n";
5621       pr "\n";
5622       pr "struct guestfs_%s_list {\n" typ;
5623       pr "  uint32_t len;\n";
5624       pr "  struct guestfs_%s *val;\n" typ;
5625       pr "};\n";
5626       pr "\n";
5627       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5628       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5629       pr "\n"
5630   ) structs
5631
5632 (* Generate the guestfs-actions.h file. *)
5633 and generate_actions_h () =
5634   generate_header CStyle LGPLv2plus;
5635   List.iter (
5636     fun (shortname, style, _, _, _, _, _) ->
5637       let name = "guestfs_" ^ shortname in
5638       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5639         name style
5640   ) all_functions
5641
5642 (* Generate the guestfs-internal-actions.h file. *)
5643 and generate_internal_actions_h () =
5644   generate_header CStyle LGPLv2plus;
5645   List.iter (
5646     fun (shortname, style, _, _, _, _, _) ->
5647       let name = "guestfs__" ^ shortname in
5648       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5649         name style
5650   ) non_daemon_functions
5651
5652 (* Generate the client-side dispatch stubs. *)
5653 and generate_client_actions () =
5654   generate_header CStyle LGPLv2plus;
5655
5656   pr "\
5657 #include <stdio.h>
5658 #include <stdlib.h>
5659 #include <stdint.h>
5660 #include <string.h>
5661 #include <inttypes.h>
5662
5663 #include \"guestfs.h\"
5664 #include \"guestfs-internal.h\"
5665 #include \"guestfs-internal-actions.h\"
5666 #include \"guestfs_protocol.h\"
5667
5668 #define error guestfs_error
5669 //#define perrorf guestfs_perrorf
5670 #define safe_malloc guestfs_safe_malloc
5671 #define safe_realloc guestfs_safe_realloc
5672 //#define safe_strdup guestfs_safe_strdup
5673 #define safe_memdup guestfs_safe_memdup
5674
5675 /* Check the return message from a call for validity. */
5676 static int
5677 check_reply_header (guestfs_h *g,
5678                     const struct guestfs_message_header *hdr,
5679                     unsigned int proc_nr, unsigned int serial)
5680 {
5681   if (hdr->prog != GUESTFS_PROGRAM) {
5682     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5683     return -1;
5684   }
5685   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5686     error (g, \"wrong protocol version (%%d/%%d)\",
5687            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5688     return -1;
5689   }
5690   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5691     error (g, \"unexpected message direction (%%d/%%d)\",
5692            hdr->direction, GUESTFS_DIRECTION_REPLY);
5693     return -1;
5694   }
5695   if (hdr->proc != proc_nr) {
5696     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5697     return -1;
5698   }
5699   if (hdr->serial != serial) {
5700     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5701     return -1;
5702   }
5703
5704   return 0;
5705 }
5706
5707 /* Check we are in the right state to run a high-level action. */
5708 static int
5709 check_state (guestfs_h *g, const char *caller)
5710 {
5711   if (!guestfs__is_ready (g)) {
5712     if (guestfs__is_config (g) || guestfs__is_launching (g))
5713       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5714         caller);
5715     else
5716       error (g, \"%%s called from the wrong state, %%d != READY\",
5717         caller, guestfs__get_state (g));
5718     return -1;
5719   }
5720   return 0;
5721 }
5722
5723 ";
5724
5725   (* Generate code to generate guestfish call traces. *)
5726   let trace_call shortname style =
5727     pr "  if (guestfs__get_trace (g)) {\n";
5728
5729     let needs_i =
5730       List.exists (function
5731                    | StringList _ | DeviceList _ -> true
5732                    | _ -> false) (snd style) in
5733     if needs_i then (
5734       pr "    int i;\n";
5735       pr "\n"
5736     );
5737
5738     pr "    printf (\"%s\");\n" shortname;
5739     List.iter (
5740       function
5741       | String n                        (* strings *)
5742       | Device n
5743       | Pathname n
5744       | Dev_or_Path n
5745       | FileIn n
5746       | FileOut n ->
5747           (* guestfish doesn't support string escaping, so neither do we *)
5748           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5749       | OptString n ->                  (* string option *)
5750           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5751           pr "    else printf (\" null\");\n"
5752       | StringList n
5753       | DeviceList n ->                 (* string list *)
5754           pr "    putchar (' ');\n";
5755           pr "    putchar ('\"');\n";
5756           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5757           pr "      if (i > 0) putchar (' ');\n";
5758           pr "      fputs (%s[i], stdout);\n" n;
5759           pr "    }\n";
5760           pr "    putchar ('\"');\n";
5761       | Bool n ->                       (* boolean *)
5762           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5763       | Int n ->                        (* int *)
5764           pr "    printf (\" %%d\", %s);\n" n
5765       | Int64 n ->
5766           pr "    printf (\" %%\" PRIi64, %s);\n" n
5767     ) (snd style);
5768     pr "    putchar ('\\n');\n";
5769     pr "  }\n";
5770     pr "\n";
5771   in
5772
5773   (* For non-daemon functions, generate a wrapper around each function. *)
5774   List.iter (
5775     fun (shortname, style, _, _, _, _, _) ->
5776       let name = "guestfs_" ^ shortname in
5777
5778       generate_prototype ~extern:false ~semicolon:false ~newline:true
5779         ~handle:"g" name style;
5780       pr "{\n";
5781       trace_call shortname style;
5782       pr "  return guestfs__%s " shortname;
5783       generate_c_call_args ~handle:"g" style;
5784       pr ";\n";
5785       pr "}\n";
5786       pr "\n"
5787   ) non_daemon_functions;
5788
5789   (* Client-side stubs for each function. *)
5790   List.iter (
5791     fun (shortname, style, _, _, _, _, _) ->
5792       let name = "guestfs_" ^ shortname in
5793
5794       (* Generate the action stub. *)
5795       generate_prototype ~extern:false ~semicolon:false ~newline:true
5796         ~handle:"g" name style;
5797
5798       let error_code =
5799         match fst style with
5800         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5801         | RConstString _ | RConstOptString _ ->
5802             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5803         | RString _ | RStringList _
5804         | RStruct _ | RStructList _
5805         | RHashtable _ | RBufferOut _ ->
5806             "NULL" in
5807
5808       pr "{\n";
5809
5810       (match snd style with
5811        | [] -> ()
5812        | _ -> pr "  struct %s_args args;\n" name
5813       );
5814
5815       pr "  guestfs_message_header hdr;\n";
5816       pr "  guestfs_message_error err;\n";
5817       let has_ret =
5818         match fst style with
5819         | RErr -> false
5820         | RConstString _ | RConstOptString _ ->
5821             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5822         | RInt _ | RInt64 _
5823         | RBool _ | RString _ | RStringList _
5824         | RStruct _ | RStructList _
5825         | RHashtable _ | RBufferOut _ ->
5826             pr "  struct %s_ret ret;\n" name;
5827             true in
5828
5829       pr "  int serial;\n";
5830       pr "  int r;\n";
5831       pr "\n";
5832       trace_call shortname style;
5833       pr "  if (check_state (g, \"%s\") == -1) return %s;\n"
5834         shortname error_code;
5835       pr "  guestfs___set_busy (g);\n";
5836       pr "\n";
5837
5838       (* Send the main header and arguments. *)
5839       (match snd style with
5840        | [] ->
5841            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5842              (String.uppercase shortname)
5843        | args ->
5844            List.iter (
5845              function
5846              | Pathname n | Device n | Dev_or_Path n | String n ->
5847                  pr "  args.%s = (char *) %s;\n" n n
5848              | OptString n ->
5849                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5850              | StringList n | DeviceList n ->
5851                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5852                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5853              | Bool n ->
5854                  pr "  args.%s = %s;\n" n n
5855              | Int n ->
5856                  pr "  args.%s = %s;\n" n n
5857              | Int64 n ->
5858                  pr "  args.%s = %s;\n" n n
5859              | FileIn _ | FileOut _ -> ()
5860            ) args;
5861            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5862              (String.uppercase shortname);
5863            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5864              name;
5865       );
5866       pr "  if (serial == -1) {\n";
5867       pr "    guestfs___end_busy (g);\n";
5868       pr "    return %s;\n" error_code;
5869       pr "  }\n";
5870       pr "\n";
5871
5872       (* Send any additional files (FileIn) requested. *)
5873       let need_read_reply_label = ref false in
5874       List.iter (
5875         function
5876         | FileIn n ->
5877             pr "  r = guestfs___send_file (g, %s);\n" n;
5878             pr "  if (r == -1) {\n";
5879             pr "    guestfs___end_busy (g);\n";
5880             pr "    return %s;\n" error_code;
5881             pr "  }\n";
5882             pr "  if (r == -2) /* daemon cancelled */\n";
5883             pr "    goto read_reply;\n";
5884             need_read_reply_label := true;
5885             pr "\n";
5886         | _ -> ()
5887       ) (snd style);
5888
5889       (* Wait for the reply from the remote end. *)
5890       if !need_read_reply_label then pr " read_reply:\n";
5891       pr "  memset (&hdr, 0, sizeof hdr);\n";
5892       pr "  memset (&err, 0, sizeof err);\n";
5893       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5894       pr "\n";
5895       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5896       if not has_ret then
5897         pr "NULL, NULL"
5898       else
5899         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5900       pr ");\n";
5901
5902       pr "  if (r == -1) {\n";
5903       pr "    guestfs___end_busy (g);\n";
5904       pr "    return %s;\n" error_code;
5905       pr "  }\n";
5906       pr "\n";
5907
5908       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5909         (String.uppercase shortname);
5910       pr "    guestfs___end_busy (g);\n";
5911       pr "    return %s;\n" error_code;
5912       pr "  }\n";
5913       pr "\n";
5914
5915       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5916       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5917       pr "    free (err.error_message);\n";
5918       pr "    guestfs___end_busy (g);\n";
5919       pr "    return %s;\n" error_code;
5920       pr "  }\n";
5921       pr "\n";
5922
5923       (* Expecting to receive further files (FileOut)? *)
5924       List.iter (
5925         function
5926         | FileOut n ->
5927             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5928             pr "    guestfs___end_busy (g);\n";
5929             pr "    return %s;\n" error_code;
5930             pr "  }\n";
5931             pr "\n";
5932         | _ -> ()
5933       ) (snd style);
5934
5935       pr "  guestfs___end_busy (g);\n";
5936
5937       (match fst style with
5938        | RErr -> pr "  return 0;\n"
5939        | RInt n | RInt64 n | RBool n ->
5940            pr "  return ret.%s;\n" n
5941        | RConstString _ | RConstOptString _ ->
5942            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5943        | RString n ->
5944            pr "  return ret.%s; /* caller will free */\n" n
5945        | RStringList n | RHashtable n ->
5946            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5947            pr "  ret.%s.%s_val =\n" n n;
5948            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5949            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5950              n n;
5951            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5952            pr "  return ret.%s.%s_val;\n" n n
5953        | RStruct (n, _) ->
5954            pr "  /* caller will free this */\n";
5955            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5956        | RStructList (n, _) ->
5957            pr "  /* caller will free this */\n";
5958            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5959        | RBufferOut n ->
5960            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5961            pr "   * _val might be NULL here.  To make the API saner for\n";
5962            pr "   * callers, we turn this case into a unique pointer (using\n";
5963            pr "   * malloc(1)).\n";
5964            pr "   */\n";
5965            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5966            pr "    *size_r = ret.%s.%s_len;\n" n n;
5967            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5968            pr "  } else {\n";
5969            pr "    free (ret.%s.%s_val);\n" n n;
5970            pr "    char *p = safe_malloc (g, 1);\n";
5971            pr "    *size_r = ret.%s.%s_len;\n" n n;
5972            pr "    return p;\n";
5973            pr "  }\n";
5974       );
5975
5976       pr "}\n\n"
5977   ) daemon_functions;
5978
5979   (* Functions to free structures. *)
5980   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5981   pr " * structure format is identical to the XDR format.  See note in\n";
5982   pr " * generator.ml.\n";
5983   pr " */\n";
5984   pr "\n";
5985
5986   List.iter (
5987     fun (typ, _) ->
5988       pr "void\n";
5989       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5990       pr "{\n";
5991       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5992       pr "  free (x);\n";
5993       pr "}\n";
5994       pr "\n";
5995
5996       pr "void\n";
5997       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5998       pr "{\n";
5999       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
6000       pr "  free (x);\n";
6001       pr "}\n";
6002       pr "\n";
6003
6004   ) structs;
6005
6006 (* Generate daemon/actions.h. *)
6007 and generate_daemon_actions_h () =
6008   generate_header CStyle GPLv2plus;
6009
6010   pr "#include \"../src/guestfs_protocol.h\"\n";
6011   pr "\n";
6012
6013   List.iter (
6014     fun (name, style, _, _, _, _, _) ->
6015       generate_prototype
6016         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
6017         name style;
6018   ) daemon_functions
6019
6020 (* Generate the linker script which controls the visibility of
6021  * symbols in the public ABI and ensures no other symbols get
6022  * exported accidentally.
6023  *)
6024 and generate_linker_script () =
6025   generate_header HashStyle GPLv2plus;
6026
6027   let globals = [
6028     "guestfs_create";
6029     "guestfs_close";
6030     "guestfs_get_error_handler";
6031     "guestfs_get_out_of_memory_handler";
6032     "guestfs_last_error";
6033     "guestfs_set_error_handler";
6034     "guestfs_set_launch_done_callback";
6035     "guestfs_set_log_message_callback";
6036     "guestfs_set_out_of_memory_handler";
6037     "guestfs_set_subprocess_quit_callback";
6038
6039     (* Unofficial parts of the API: the bindings code use these
6040      * functions, so it is useful to export them.
6041      *)
6042     "guestfs_safe_calloc";
6043     "guestfs_safe_malloc";
6044   ] in
6045   let functions =
6046     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
6047       all_functions in
6048   let structs =
6049     List.concat (
6050       List.map (fun (typ, _) ->
6051                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
6052         structs
6053     ) in
6054   let globals = List.sort compare (globals @ functions @ structs) in
6055
6056   pr "{\n";
6057   pr "    global:\n";
6058   List.iter (pr "        %s;\n") globals;
6059   pr "\n";
6060
6061   pr "    local:\n";
6062   pr "        *;\n";
6063   pr "};\n"
6064
6065 (* Generate the server-side stubs. *)
6066 and generate_daemon_actions () =
6067   generate_header CStyle GPLv2plus;
6068
6069   pr "#include <config.h>\n";
6070   pr "\n";
6071   pr "#include <stdio.h>\n";
6072   pr "#include <stdlib.h>\n";
6073   pr "#include <string.h>\n";
6074   pr "#include <inttypes.h>\n";
6075   pr "#include <rpc/types.h>\n";
6076   pr "#include <rpc/xdr.h>\n";
6077   pr "\n";
6078   pr "#include \"daemon.h\"\n";
6079   pr "#include \"c-ctype.h\"\n";
6080   pr "#include \"../src/guestfs_protocol.h\"\n";
6081   pr "#include \"actions.h\"\n";
6082   pr "\n";
6083
6084   List.iter (
6085     fun (name, style, _, _, _, _, _) ->
6086       (* Generate server-side stubs. *)
6087       pr "static void %s_stub (XDR *xdr_in)\n" name;
6088       pr "{\n";
6089       let error_code =
6090         match fst style with
6091         | RErr | RInt _ -> pr "  int r;\n"; "-1"
6092         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6093         | RBool _ -> pr "  int r;\n"; "-1"
6094         | RConstString _ | RConstOptString _ ->
6095             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6096         | RString _ -> pr "  char *r;\n"; "NULL"
6097         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6098         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
6099         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
6100         | RBufferOut _ ->
6101             pr "  size_t size = 1;\n";
6102             pr "  char *r;\n";
6103             "NULL" in
6104
6105       (match snd style with
6106        | [] -> ()
6107        | args ->
6108            pr "  struct guestfs_%s_args args;\n" name;
6109            List.iter (
6110              function
6111              | Device n | Dev_or_Path n
6112              | Pathname n
6113              | String n -> ()
6114              | OptString n -> pr "  char *%s;\n" n
6115              | StringList n | DeviceList n -> pr "  char **%s;\n" n
6116              | Bool n -> pr "  int %s;\n" n
6117              | Int n -> pr "  int %s;\n" n
6118              | Int64 n -> pr "  int64_t %s;\n" n
6119              | FileIn _ | FileOut _ -> ()
6120            ) args
6121       );
6122       pr "\n";
6123
6124       let is_filein =
6125         List.exists (function FileIn _ -> true | _ -> false) (snd style) in
6126
6127       (match snd style with
6128        | [] -> ()
6129        | args ->
6130            pr "  memset (&args, 0, sizeof args);\n";
6131            pr "\n";
6132            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
6133            if is_filein then
6134              pr "    cancel_receive ();\n";
6135            pr "    reply_with_error (\"daemon failed to decode procedure arguments\");\n";
6136            pr "    goto done;\n";
6137            pr "  }\n";
6138            let pr_args n =
6139              pr "  char *%s = args.%s;\n" n n
6140            in
6141            let pr_list_handling_code n =
6142              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
6143              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
6144              pr "  if (%s == NULL) {\n" n;
6145              if is_filein then
6146                pr "    cancel_receive ();\n";
6147              pr "    reply_with_perror (\"realloc\");\n";
6148              pr "    goto done;\n";
6149              pr "  }\n";
6150              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
6151              pr "  args.%s.%s_val = %s;\n" n n n;
6152            in
6153            List.iter (
6154              function
6155              | Pathname n ->
6156                  pr_args n;
6157                  pr "  ABS_PATH (%s, %s, goto done);\n"
6158                    n (if is_filein then "cancel_receive ()" else "");
6159              | Device n ->
6160                  pr_args n;
6161                  pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
6162                    n (if is_filein then "cancel_receive ()" else "");
6163              | Dev_or_Path n ->
6164                  pr_args n;
6165                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
6166                    n (if is_filein then "cancel_receive ()" else "");
6167              | String n -> pr_args n
6168              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
6169              | StringList n ->
6170                  pr_list_handling_code n;
6171              | DeviceList n ->
6172                  pr_list_handling_code n;
6173                  pr "  /* Ensure that each is a device,\n";
6174                  pr "   * and perform device name translation. */\n";
6175                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
6176                  pr "    RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n"
6177                    (if is_filein then "cancel_receive ()" else "");
6178                  pr "  }\n";
6179              | Bool n -> pr "  %s = args.%s;\n" n n
6180              | Int n -> pr "  %s = args.%s;\n" n n
6181              | Int64 n -> pr "  %s = args.%s;\n" n n
6182              | FileIn _ | FileOut _ -> ()
6183            ) args;
6184            pr "\n"
6185       );
6186
6187
6188       (* this is used at least for do_equal *)
6189       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
6190         (* Emit NEED_ROOT just once, even when there are two or
6191            more Pathname args *)
6192         pr "  NEED_ROOT (%s, goto done);\n"
6193           (if is_filein then "cancel_receive ()" else "");
6194       );
6195
6196       (* Don't want to call the impl with any FileIn or FileOut
6197        * parameters, since these go "outside" the RPC protocol.
6198        *)
6199       let args' =
6200         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
6201           (snd style) in
6202       pr "  r = do_%s " name;
6203       generate_c_call_args (fst style, args');
6204       pr ";\n";
6205
6206       (match fst style with
6207        | RErr | RInt _ | RInt64 _ | RBool _
6208        | RConstString _ | RConstOptString _
6209        | RString _ | RStringList _ | RHashtable _
6210        | RStruct (_, _) | RStructList (_, _) ->
6211            pr "  if (r == %s)\n" error_code;
6212            pr "    /* do_%s has already called reply_with_error */\n" name;
6213            pr "    goto done;\n";
6214            pr "\n"
6215        | RBufferOut _ ->
6216            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
6217            pr "   * an ordinary zero-length buffer), so be careful ...\n";
6218            pr "   */\n";
6219            pr "  if (size == 1 && r == %s)\n" error_code;
6220            pr "    /* do_%s has already called reply_with_error */\n" name;
6221            pr "    goto done;\n";
6222            pr "\n"
6223       );
6224
6225       (* If there are any FileOut parameters, then the impl must
6226        * send its own reply.
6227        *)
6228       let no_reply =
6229         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
6230       if no_reply then
6231         pr "  /* do_%s has already sent a reply */\n" name
6232       else (
6233         match fst style with
6234         | RErr -> pr "  reply (NULL, NULL);\n"
6235         | RInt n | RInt64 n | RBool n ->
6236             pr "  struct guestfs_%s_ret ret;\n" name;
6237             pr "  ret.%s = r;\n" n;
6238             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6239               name
6240         | RConstString _ | RConstOptString _ ->
6241             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6242         | RString n ->
6243             pr "  struct guestfs_%s_ret ret;\n" name;
6244             pr "  ret.%s = r;\n" n;
6245             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6246               name;
6247             pr "  free (r);\n"
6248         | RStringList n | RHashtable n ->
6249             pr "  struct guestfs_%s_ret ret;\n" name;
6250             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
6251             pr "  ret.%s.%s_val = r;\n" n n;
6252             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6253               name;
6254             pr "  free_strings (r);\n"
6255         | RStruct (n, _) ->
6256             pr "  struct guestfs_%s_ret ret;\n" name;
6257             pr "  ret.%s = *r;\n" n;
6258             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6259               name;
6260             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6261               name
6262         | RStructList (n, _) ->
6263             pr "  struct guestfs_%s_ret ret;\n" name;
6264             pr "  ret.%s = *r;\n" n;
6265             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6266               name;
6267             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6268               name
6269         | RBufferOut n ->
6270             pr "  struct guestfs_%s_ret ret;\n" name;
6271             pr "  ret.%s.%s_val = r;\n" n n;
6272             pr "  ret.%s.%s_len = size;\n" n n;
6273             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6274               name;
6275             pr "  free (r);\n"
6276       );
6277
6278       (* Free the args. *)
6279       pr "done:\n";
6280       (match snd style with
6281        | [] -> ()
6282        | _ ->
6283            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
6284              name
6285       );
6286       pr "  return;\n";
6287       pr "}\n\n";
6288   ) daemon_functions;
6289
6290   (* Dispatch function. *)
6291   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
6292   pr "{\n";
6293   pr "  switch (proc_nr) {\n";
6294
6295   List.iter (
6296     fun (name, style, _, _, _, _, _) ->
6297       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
6298       pr "      %s_stub (xdr_in);\n" name;
6299       pr "      break;\n"
6300   ) daemon_functions;
6301
6302   pr "    default:\n";
6303   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";
6304   pr "  }\n";
6305   pr "}\n";
6306   pr "\n";
6307
6308   (* LVM columns and tokenization functions. *)
6309   (* XXX This generates crap code.  We should rethink how we
6310    * do this parsing.
6311    *)
6312   List.iter (
6313     function
6314     | typ, cols ->
6315         pr "static const char *lvm_%s_cols = \"%s\";\n"
6316           typ (String.concat "," (List.map fst cols));
6317         pr "\n";
6318
6319         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
6320         pr "{\n";
6321         pr "  char *tok, *p, *next;\n";
6322         pr "  int i, j;\n";
6323         pr "\n";
6324         (*
6325           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
6326           pr "\n";
6327         *)
6328         pr "  if (!str) {\n";
6329         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
6330         pr "    return -1;\n";
6331         pr "  }\n";
6332         pr "  if (!*str || c_isspace (*str)) {\n";
6333         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
6334         pr "    return -1;\n";
6335         pr "  }\n";
6336         pr "  tok = str;\n";
6337         List.iter (
6338           fun (name, coltype) ->
6339             pr "  if (!tok) {\n";
6340             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
6341             pr "    return -1;\n";
6342             pr "  }\n";
6343             pr "  p = strchrnul (tok, ',');\n";
6344             pr "  if (*p) next = p+1; else next = NULL;\n";
6345             pr "  *p = '\\0';\n";
6346             (match coltype with
6347              | FString ->
6348                  pr "  r->%s = strdup (tok);\n" name;
6349                  pr "  if (r->%s == NULL) {\n" name;
6350                  pr "    perror (\"strdup\");\n";
6351                  pr "    return -1;\n";
6352                  pr "  }\n"
6353              | FUUID ->
6354                  pr "  for (i = j = 0; i < 32; ++j) {\n";
6355                  pr "    if (tok[j] == '\\0') {\n";
6356                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
6357                  pr "      return -1;\n";
6358                  pr "    } else if (tok[j] != '-')\n";
6359                  pr "      r->%s[i++] = tok[j];\n" name;
6360                  pr "  }\n";
6361              | FBytes ->
6362                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
6363                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6364                  pr "    return -1;\n";
6365                  pr "  }\n";
6366              | FInt64 ->
6367                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
6368                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6369                  pr "    return -1;\n";
6370                  pr "  }\n";
6371              | FOptPercent ->
6372                  pr "  if (tok[0] == '\\0')\n";
6373                  pr "    r->%s = -1;\n" name;
6374                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
6375                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6376                  pr "    return -1;\n";
6377                  pr "  }\n";
6378              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
6379                  assert false (* can never be an LVM column *)
6380             );
6381             pr "  tok = next;\n";
6382         ) cols;
6383
6384         pr "  if (tok != NULL) {\n";
6385         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6386         pr "    return -1;\n";
6387         pr "  }\n";
6388         pr "  return 0;\n";
6389         pr "}\n";
6390         pr "\n";
6391
6392         pr "guestfs_int_lvm_%s_list *\n" typ;
6393         pr "parse_command_line_%ss (void)\n" typ;
6394         pr "{\n";
6395         pr "  char *out, *err;\n";
6396         pr "  char *p, *pend;\n";
6397         pr "  int r, i;\n";
6398         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6399         pr "  void *newp;\n";
6400         pr "\n";
6401         pr "  ret = malloc (sizeof *ret);\n";
6402         pr "  if (!ret) {\n";
6403         pr "    reply_with_perror (\"malloc\");\n";
6404         pr "    return NULL;\n";
6405         pr "  }\n";
6406         pr "\n";
6407         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6408         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6409         pr "\n";
6410         pr "  r = command (&out, &err,\n";
6411         pr "           \"lvm\", \"%ss\",\n" typ;
6412         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6413         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6414         pr "  if (r == -1) {\n";
6415         pr "    reply_with_error (\"%%s\", err);\n";
6416         pr "    free (out);\n";
6417         pr "    free (err);\n";
6418         pr "    free (ret);\n";
6419         pr "    return NULL;\n";
6420         pr "  }\n";
6421         pr "\n";
6422         pr "  free (err);\n";
6423         pr "\n";
6424         pr "  /* Tokenize each line of the output. */\n";
6425         pr "  p = out;\n";
6426         pr "  i = 0;\n";
6427         pr "  while (p) {\n";
6428         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6429         pr "    if (pend) {\n";
6430         pr "      *pend = '\\0';\n";
6431         pr "      pend++;\n";
6432         pr "    }\n";
6433         pr "\n";
6434         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6435         pr "      p++;\n";
6436         pr "\n";
6437         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6438         pr "      p = pend;\n";
6439         pr "      continue;\n";
6440         pr "    }\n";
6441         pr "\n";
6442         pr "    /* Allocate some space to store this next entry. */\n";
6443         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6444         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6445         pr "    if (newp == NULL) {\n";
6446         pr "      reply_with_perror (\"realloc\");\n";
6447         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6448         pr "      free (ret);\n";
6449         pr "      free (out);\n";
6450         pr "      return NULL;\n";
6451         pr "    }\n";
6452         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6453         pr "\n";
6454         pr "    /* Tokenize the next entry. */\n";
6455         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6456         pr "    if (r == -1) {\n";
6457         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6458         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6459         pr "      free (ret);\n";
6460         pr "      free (out);\n";
6461         pr "      return NULL;\n";
6462         pr "    }\n";
6463         pr "\n";
6464         pr "    ++i;\n";
6465         pr "    p = pend;\n";
6466         pr "  }\n";
6467         pr "\n";
6468         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6469         pr "\n";
6470         pr "  free (out);\n";
6471         pr "  return ret;\n";
6472         pr "}\n"
6473
6474   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6475
6476 (* Generate a list of function names, for debugging in the daemon.. *)
6477 and generate_daemon_names () =
6478   generate_header CStyle GPLv2plus;
6479
6480   pr "#include <config.h>\n";
6481   pr "\n";
6482   pr "#include \"daemon.h\"\n";
6483   pr "\n";
6484
6485   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6486   pr "const char *function_names[] = {\n";
6487   List.iter (
6488     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6489   ) daemon_functions;
6490   pr "};\n";
6491
6492 (* Generate the optional groups for the daemon to implement
6493  * guestfs_available.
6494  *)
6495 and generate_daemon_optgroups_c () =
6496   generate_header CStyle GPLv2plus;
6497
6498   pr "#include <config.h>\n";
6499   pr "\n";
6500   pr "#include \"daemon.h\"\n";
6501   pr "#include \"optgroups.h\"\n";
6502   pr "\n";
6503
6504   pr "struct optgroup optgroups[] = {\n";
6505   List.iter (
6506     fun (group, _) ->
6507       pr "  { \"%s\", optgroup_%s_available },\n" group group
6508   ) optgroups;
6509   pr "  { NULL, NULL }\n";
6510   pr "};\n"
6511
6512 and generate_daemon_optgroups_h () =
6513   generate_header CStyle GPLv2plus;
6514
6515   List.iter (
6516     fun (group, _) ->
6517       pr "extern int optgroup_%s_available (void);\n" group
6518   ) optgroups
6519
6520 (* Generate the tests. *)
6521 and generate_tests () =
6522   generate_header CStyle GPLv2plus;
6523
6524   pr "\
6525 #include <stdio.h>
6526 #include <stdlib.h>
6527 #include <string.h>
6528 #include <unistd.h>
6529 #include <sys/types.h>
6530 #include <fcntl.h>
6531
6532 #include \"guestfs.h\"
6533 #include \"guestfs-internal.h\"
6534
6535 static guestfs_h *g;
6536 static int suppress_error = 0;
6537
6538 static void print_error (guestfs_h *g, void *data, const char *msg)
6539 {
6540   if (!suppress_error)
6541     fprintf (stderr, \"%%s\\n\", msg);
6542 }
6543
6544 /* FIXME: nearly identical code appears in fish.c */
6545 static void print_strings (char *const *argv)
6546 {
6547   int argc;
6548
6549   for (argc = 0; argv[argc] != NULL; ++argc)
6550     printf (\"\\t%%s\\n\", argv[argc]);
6551 }
6552
6553 /*
6554 static void print_table (char const *const *argv)
6555 {
6556   int i;
6557
6558   for (i = 0; argv[i] != NULL; i += 2)
6559     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6560 }
6561 */
6562
6563 ";
6564
6565   (* Generate a list of commands which are not tested anywhere. *)
6566   pr "static void no_test_warnings (void)\n";
6567   pr "{\n";
6568
6569   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6570   List.iter (
6571     fun (_, _, _, _, tests, _, _) ->
6572       let tests = filter_map (
6573         function
6574         | (_, (Always|If _|Unless _), test) -> Some test
6575         | (_, Disabled, _) -> None
6576       ) tests in
6577       let seq = List.concat (List.map seq_of_test tests) in
6578       let cmds_tested = List.map List.hd seq in
6579       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6580   ) all_functions;
6581
6582   List.iter (
6583     fun (name, _, _, _, _, _, _) ->
6584       if not (Hashtbl.mem hash name) then
6585         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6586   ) all_functions;
6587
6588   pr "}\n";
6589   pr "\n";
6590
6591   (* Generate the actual tests.  Note that we generate the tests
6592    * in reverse order, deliberately, so that (in general) the
6593    * newest tests run first.  This makes it quicker and easier to
6594    * debug them.
6595    *)
6596   let test_names =
6597     List.map (
6598       fun (name, _, _, flags, tests, _, _) ->
6599         mapi (generate_one_test name flags) tests
6600     ) (List.rev all_functions) in
6601   let test_names = List.concat test_names in
6602   let nr_tests = List.length test_names in
6603
6604   pr "\
6605 int main (int argc, char *argv[])
6606 {
6607   char c = 0;
6608   unsigned long int n_failed = 0;
6609   const char *filename;
6610   int fd;
6611   int nr_tests, test_num = 0;
6612
6613   setbuf (stdout, NULL);
6614
6615   no_test_warnings ();
6616
6617   g = guestfs_create ();
6618   if (g == NULL) {
6619     printf (\"guestfs_create FAILED\\n\");
6620     exit (EXIT_FAILURE);
6621   }
6622
6623   guestfs_set_error_handler (g, print_error, NULL);
6624
6625   guestfs_set_path (g, \"../appliance\");
6626
6627   filename = \"test1.img\";
6628   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6629   if (fd == -1) {
6630     perror (filename);
6631     exit (EXIT_FAILURE);
6632   }
6633   if (lseek (fd, %d, SEEK_SET) == -1) {
6634     perror (\"lseek\");
6635     close (fd);
6636     unlink (filename);
6637     exit (EXIT_FAILURE);
6638   }
6639   if (write (fd, &c, 1) == -1) {
6640     perror (\"write\");
6641     close (fd);
6642     unlink (filename);
6643     exit (EXIT_FAILURE);
6644   }
6645   if (close (fd) == -1) {
6646     perror (filename);
6647     unlink (filename);
6648     exit (EXIT_FAILURE);
6649   }
6650   if (guestfs_add_drive (g, filename) == -1) {
6651     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6652     exit (EXIT_FAILURE);
6653   }
6654
6655   filename = \"test2.img\";
6656   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6657   if (fd == -1) {
6658     perror (filename);
6659     exit (EXIT_FAILURE);
6660   }
6661   if (lseek (fd, %d, SEEK_SET) == -1) {
6662     perror (\"lseek\");
6663     close (fd);
6664     unlink (filename);
6665     exit (EXIT_FAILURE);
6666   }
6667   if (write (fd, &c, 1) == -1) {
6668     perror (\"write\");
6669     close (fd);
6670     unlink (filename);
6671     exit (EXIT_FAILURE);
6672   }
6673   if (close (fd) == -1) {
6674     perror (filename);
6675     unlink (filename);
6676     exit (EXIT_FAILURE);
6677   }
6678   if (guestfs_add_drive (g, filename) == -1) {
6679     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6680     exit (EXIT_FAILURE);
6681   }
6682
6683   filename = \"test3.img\";
6684   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6685   if (fd == -1) {
6686     perror (filename);
6687     exit (EXIT_FAILURE);
6688   }
6689   if (lseek (fd, %d, SEEK_SET) == -1) {
6690     perror (\"lseek\");
6691     close (fd);
6692     unlink (filename);
6693     exit (EXIT_FAILURE);
6694   }
6695   if (write (fd, &c, 1) == -1) {
6696     perror (\"write\");
6697     close (fd);
6698     unlink (filename);
6699     exit (EXIT_FAILURE);
6700   }
6701   if (close (fd) == -1) {
6702     perror (filename);
6703     unlink (filename);
6704     exit (EXIT_FAILURE);
6705   }
6706   if (guestfs_add_drive (g, filename) == -1) {
6707     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6708     exit (EXIT_FAILURE);
6709   }
6710
6711   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6712     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6713     exit (EXIT_FAILURE);
6714   }
6715
6716   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6717   alarm (600);
6718
6719   if (guestfs_launch (g) == -1) {
6720     printf (\"guestfs_launch FAILED\\n\");
6721     exit (EXIT_FAILURE);
6722   }
6723
6724   /* Cancel previous alarm. */
6725   alarm (0);
6726
6727   nr_tests = %d;
6728
6729 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6730
6731   iteri (
6732     fun i test_name ->
6733       pr "  test_num++;\n";
6734       pr "  if (guestfs_get_verbose (g))\n";
6735       pr "    printf (\"-------------------------------------------------------------------------------\\n\");\n";
6736       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6737       pr "  if (%s () == -1) {\n" test_name;
6738       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6739       pr "    n_failed++;\n";
6740       pr "  }\n";
6741   ) test_names;
6742   pr "\n";
6743
6744   pr "  guestfs_close (g);\n";
6745   pr "  unlink (\"test1.img\");\n";
6746   pr "  unlink (\"test2.img\");\n";
6747   pr "  unlink (\"test3.img\");\n";
6748   pr "\n";
6749
6750   pr "  if (n_failed > 0) {\n";
6751   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6752   pr "    exit (EXIT_FAILURE);\n";
6753   pr "  }\n";
6754   pr "\n";
6755
6756   pr "  exit (EXIT_SUCCESS);\n";
6757   pr "}\n"
6758
6759 and generate_one_test name flags i (init, prereq, test) =
6760   let test_name = sprintf "test_%s_%d" name i in
6761
6762   pr "\
6763 static int %s_skip (void)
6764 {
6765   const char *str;
6766
6767   str = getenv (\"TEST_ONLY\");
6768   if (str)
6769     return strstr (str, \"%s\") == NULL;
6770   str = getenv (\"SKIP_%s\");
6771   if (str && STREQ (str, \"1\")) return 1;
6772   str = getenv (\"SKIP_TEST_%s\");
6773   if (str && STREQ (str, \"1\")) return 1;
6774   return 0;
6775 }
6776
6777 " test_name name (String.uppercase test_name) (String.uppercase name);
6778
6779   (match prereq with
6780    | Disabled | Always -> ()
6781    | If code | Unless code ->
6782        pr "static int %s_prereq (void)\n" test_name;
6783        pr "{\n";
6784        pr "  %s\n" code;
6785        pr "}\n";
6786        pr "\n";
6787   );
6788
6789   pr "\
6790 static int %s (void)
6791 {
6792   if (%s_skip ()) {
6793     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6794     return 0;
6795   }
6796
6797 " test_name test_name test_name;
6798
6799   (* Optional functions should only be tested if the relevant
6800    * support is available in the daemon.
6801    *)
6802   List.iter (
6803     function
6804     | Optional group ->
6805         pr "  {\n";
6806         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6807         pr "    int r;\n";
6808         pr "    suppress_error = 1;\n";
6809         pr "    r = guestfs_available (g, (char **) groups);\n";
6810         pr "    suppress_error = 0;\n";
6811         pr "    if (r == -1) {\n";
6812         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6813         pr "      return 0;\n";
6814         pr "    }\n";
6815         pr "  }\n";
6816     | _ -> ()
6817   ) flags;
6818
6819   (match prereq with
6820    | Disabled ->
6821        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6822    | If _ ->
6823        pr "  if (! %s_prereq ()) {\n" test_name;
6824        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6825        pr "    return 0;\n";
6826        pr "  }\n";
6827        pr "\n";
6828        generate_one_test_body name i test_name init test;
6829    | Unless _ ->
6830        pr "  if (%s_prereq ()) {\n" test_name;
6831        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6832        pr "    return 0;\n";
6833        pr "  }\n";
6834        pr "\n";
6835        generate_one_test_body name i test_name init test;
6836    | Always ->
6837        generate_one_test_body name i test_name init test
6838   );
6839
6840   pr "  return 0;\n";
6841   pr "}\n";
6842   pr "\n";
6843   test_name
6844
6845 and generate_one_test_body name i test_name init test =
6846   (match init with
6847    | InitNone (* XXX at some point, InitNone and InitEmpty became
6848                * folded together as the same thing.  Really we should
6849                * make InitNone do nothing at all, but the tests may
6850                * need to be checked to make sure this is OK.
6851                *)
6852    | InitEmpty ->
6853        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6854        List.iter (generate_test_command_call test_name)
6855          [["blockdev_setrw"; "/dev/sda"];
6856           ["umount_all"];
6857           ["lvm_remove_all"]]
6858    | InitPartition ->
6859        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6860        List.iter (generate_test_command_call test_name)
6861          [["blockdev_setrw"; "/dev/sda"];
6862           ["umount_all"];
6863           ["lvm_remove_all"];
6864           ["part_disk"; "/dev/sda"; "mbr"]]
6865    | InitBasicFS ->
6866        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6867        List.iter (generate_test_command_call test_name)
6868          [["blockdev_setrw"; "/dev/sda"];
6869           ["umount_all"];
6870           ["lvm_remove_all"];
6871           ["part_disk"; "/dev/sda"; "mbr"];
6872           ["mkfs"; "ext2"; "/dev/sda1"];
6873           ["mount_options"; ""; "/dev/sda1"; "/"]]
6874    | InitBasicFSonLVM ->
6875        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6876          test_name;
6877        List.iter (generate_test_command_call test_name)
6878          [["blockdev_setrw"; "/dev/sda"];
6879           ["umount_all"];
6880           ["lvm_remove_all"];
6881           ["part_disk"; "/dev/sda"; "mbr"];
6882           ["pvcreate"; "/dev/sda1"];
6883           ["vgcreate"; "VG"; "/dev/sda1"];
6884           ["lvcreate"; "LV"; "VG"; "8"];
6885           ["mkfs"; "ext2"; "/dev/VG/LV"];
6886           ["mount_options"; ""; "/dev/VG/LV"; "/"]]
6887    | InitISOFS ->
6888        pr "  /* InitISOFS for %s */\n" test_name;
6889        List.iter (generate_test_command_call test_name)
6890          [["blockdev_setrw"; "/dev/sda"];
6891           ["umount_all"];
6892           ["lvm_remove_all"];
6893           ["mount_ro"; "/dev/sdd"; "/"]]
6894   );
6895
6896   let get_seq_last = function
6897     | [] ->
6898         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6899           test_name
6900     | seq ->
6901         let seq = List.rev seq in
6902         List.rev (List.tl seq), List.hd seq
6903   in
6904
6905   match test with
6906   | TestRun seq ->
6907       pr "  /* TestRun for %s (%d) */\n" name i;
6908       List.iter (generate_test_command_call test_name) seq
6909   | TestOutput (seq, expected) ->
6910       pr "  /* TestOutput for %s (%d) */\n" name i;
6911       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6912       let seq, last = get_seq_last seq in
6913       let test () =
6914         pr "    if (STRNEQ (r, expected)) {\n";
6915         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6916         pr "      return -1;\n";
6917         pr "    }\n"
6918       in
6919       List.iter (generate_test_command_call test_name) seq;
6920       generate_test_command_call ~test test_name last
6921   | TestOutputList (seq, expected) ->
6922       pr "  /* TestOutputList for %s (%d) */\n" name i;
6923       let seq, last = get_seq_last seq in
6924       let test () =
6925         iteri (
6926           fun i str ->
6927             pr "    if (!r[%d]) {\n" i;
6928             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6929             pr "      print_strings (r);\n";
6930             pr "      return -1;\n";
6931             pr "    }\n";
6932             pr "    {\n";
6933             pr "      const char *expected = \"%s\";\n" (c_quote str);
6934             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6935             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6936             pr "        return -1;\n";
6937             pr "      }\n";
6938             pr "    }\n"
6939         ) expected;
6940         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6941         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6942           test_name;
6943         pr "      print_strings (r);\n";
6944         pr "      return -1;\n";
6945         pr "    }\n"
6946       in
6947       List.iter (generate_test_command_call test_name) seq;
6948       generate_test_command_call ~test test_name last
6949   | TestOutputListOfDevices (seq, expected) ->
6950       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6951       let seq, last = get_seq_last seq in
6952       let test () =
6953         iteri (
6954           fun i str ->
6955             pr "    if (!r[%d]) {\n" i;
6956             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6957             pr "      print_strings (r);\n";
6958             pr "      return -1;\n";
6959             pr "    }\n";
6960             pr "    {\n";
6961             pr "      const char *expected = \"%s\";\n" (c_quote str);
6962             pr "      r[%d][5] = 's';\n" i;
6963             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6964             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6965             pr "        return -1;\n";
6966             pr "      }\n";
6967             pr "    }\n"
6968         ) expected;
6969         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6970         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6971           test_name;
6972         pr "      print_strings (r);\n";
6973         pr "      return -1;\n";
6974         pr "    }\n"
6975       in
6976       List.iter (generate_test_command_call test_name) seq;
6977       generate_test_command_call ~test test_name last
6978   | TestOutputInt (seq, expected) ->
6979       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6980       let seq, last = get_seq_last seq in
6981       let test () =
6982         pr "    if (r != %d) {\n" expected;
6983         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6984           test_name expected;
6985         pr "               (int) r);\n";
6986         pr "      return -1;\n";
6987         pr "    }\n"
6988       in
6989       List.iter (generate_test_command_call test_name) seq;
6990       generate_test_command_call ~test test_name last
6991   | TestOutputIntOp (seq, op, expected) ->
6992       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6993       let seq, last = get_seq_last seq in
6994       let test () =
6995         pr "    if (! (r %s %d)) {\n" op expected;
6996         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6997           test_name op expected;
6998         pr "               (int) r);\n";
6999         pr "      return -1;\n";
7000         pr "    }\n"
7001       in
7002       List.iter (generate_test_command_call test_name) seq;
7003       generate_test_command_call ~test test_name last
7004   | TestOutputTrue seq ->
7005       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
7006       let seq, last = get_seq_last seq in
7007       let test () =
7008         pr "    if (!r) {\n";
7009         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
7010           test_name;
7011         pr "      return -1;\n";
7012         pr "    }\n"
7013       in
7014       List.iter (generate_test_command_call test_name) seq;
7015       generate_test_command_call ~test test_name last
7016   | TestOutputFalse seq ->
7017       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
7018       let seq, last = get_seq_last seq in
7019       let test () =
7020         pr "    if (r) {\n";
7021         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
7022           test_name;
7023         pr "      return -1;\n";
7024         pr "    }\n"
7025       in
7026       List.iter (generate_test_command_call test_name) seq;
7027       generate_test_command_call ~test test_name last
7028   | TestOutputLength (seq, expected) ->
7029       pr "  /* TestOutputLength for %s (%d) */\n" name i;
7030       let seq, last = get_seq_last seq in
7031       let test () =
7032         pr "    int j;\n";
7033         pr "    for (j = 0; j < %d; ++j)\n" expected;
7034         pr "      if (r[j] == NULL) {\n";
7035         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
7036           test_name;
7037         pr "        print_strings (r);\n";
7038         pr "        return -1;\n";
7039         pr "      }\n";
7040         pr "    if (r[j] != NULL) {\n";
7041         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
7042           test_name;
7043         pr "      print_strings (r);\n";
7044         pr "      return -1;\n";
7045         pr "    }\n"
7046       in
7047       List.iter (generate_test_command_call test_name) seq;
7048       generate_test_command_call ~test test_name last
7049   | TestOutputBuffer (seq, expected) ->
7050       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
7051       pr "  const char *expected = \"%s\";\n" (c_quote expected);
7052       let seq, last = get_seq_last seq in
7053       let len = String.length expected in
7054       let test () =
7055         pr "    if (size != %d) {\n" len;
7056         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
7057         pr "      return -1;\n";
7058         pr "    }\n";
7059         pr "    if (STRNEQLEN (r, expected, size)) {\n";
7060         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
7061         pr "      return -1;\n";
7062         pr "    }\n"
7063       in
7064       List.iter (generate_test_command_call test_name) seq;
7065       generate_test_command_call ~test test_name last
7066   | TestOutputStruct (seq, checks) ->
7067       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
7068       let seq, last = get_seq_last seq in
7069       let test () =
7070         List.iter (
7071           function
7072           | CompareWithInt (field, expected) ->
7073               pr "    if (r->%s != %d) {\n" field expected;
7074               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
7075                 test_name field expected;
7076               pr "               (int) r->%s);\n" field;
7077               pr "      return -1;\n";
7078               pr "    }\n"
7079           | CompareWithIntOp (field, op, expected) ->
7080               pr "    if (!(r->%s %s %d)) {\n" field op expected;
7081               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
7082                 test_name field op expected;
7083               pr "               (int) r->%s);\n" field;
7084               pr "      return -1;\n";
7085               pr "    }\n"
7086           | CompareWithString (field, expected) ->
7087               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
7088               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
7089                 test_name field expected;
7090               pr "               r->%s);\n" field;
7091               pr "      return -1;\n";
7092               pr "    }\n"
7093           | CompareFieldsIntEq (field1, field2) ->
7094               pr "    if (r->%s != r->%s) {\n" field1 field2;
7095               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
7096                 test_name field1 field2;
7097               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
7098               pr "      return -1;\n";
7099               pr "    }\n"
7100           | CompareFieldsStrEq (field1, field2) ->
7101               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
7102               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
7103                 test_name field1 field2;
7104               pr "               r->%s, r->%s);\n" field1 field2;
7105               pr "      return -1;\n";
7106               pr "    }\n"
7107         ) checks
7108       in
7109       List.iter (generate_test_command_call test_name) seq;
7110       generate_test_command_call ~test test_name last
7111   | TestLastFail seq ->
7112       pr "  /* TestLastFail for %s (%d) */\n" name i;
7113       let seq, last = get_seq_last seq in
7114       List.iter (generate_test_command_call test_name) seq;
7115       generate_test_command_call test_name ~expect_error:true last
7116
7117 (* Generate the code to run a command, leaving the result in 'r'.
7118  * If you expect to get an error then you should set expect_error:true.
7119  *)
7120 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
7121   match cmd with
7122   | [] -> assert false
7123   | name :: args ->
7124       (* Look up the command to find out what args/ret it has. *)
7125       let style =
7126         try
7127           let _, style, _, _, _, _, _ =
7128             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
7129           style
7130         with Not_found ->
7131           failwithf "%s: in test, command %s was not found" test_name name in
7132
7133       if List.length (snd style) <> List.length args then
7134         failwithf "%s: in test, wrong number of args given to %s"
7135           test_name name;
7136
7137       pr "  {\n";
7138
7139       List.iter (
7140         function
7141         | OptString n, "NULL" -> ()
7142         | Pathname n, arg
7143         | Device n, arg
7144         | Dev_or_Path n, arg
7145         | String n, arg
7146         | OptString n, arg ->
7147             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
7148         | Int _, _
7149         | Int64 _, _
7150         | Bool _, _
7151         | FileIn _, _ | FileOut _, _ -> ()
7152         | StringList n, "" | DeviceList n, "" ->
7153             pr "    const char *const %s[1] = { NULL };\n" n
7154         | StringList n, arg | DeviceList n, arg ->
7155             let strs = string_split " " arg in
7156             iteri (
7157               fun i str ->
7158                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
7159             ) strs;
7160             pr "    const char *const %s[] = {\n" n;
7161             iteri (
7162               fun i _ -> pr "      %s_%d,\n" n i
7163             ) strs;
7164             pr "      NULL\n";
7165             pr "    };\n";
7166       ) (List.combine (snd style) args);
7167
7168       let error_code =
7169         match fst style with
7170         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
7171         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
7172         | RConstString _ | RConstOptString _ ->
7173             pr "    const char *r;\n"; "NULL"
7174         | RString _ -> pr "    char *r;\n"; "NULL"
7175         | RStringList _ | RHashtable _ ->
7176             pr "    char **r;\n";
7177             pr "    int i;\n";
7178             "NULL"
7179         | RStruct (_, typ) ->
7180             pr "    struct guestfs_%s *r;\n" typ; "NULL"
7181         | RStructList (_, typ) ->
7182             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
7183         | RBufferOut _ ->
7184             pr "    char *r;\n";
7185             pr "    size_t size;\n";
7186             "NULL" in
7187
7188       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
7189       pr "    r = guestfs_%s (g" name;
7190
7191       (* Generate the parameters. *)
7192       List.iter (
7193         function
7194         | OptString _, "NULL" -> pr ", NULL"
7195         | Pathname n, _
7196         | Device n, _ | Dev_or_Path n, _
7197         | String n, _
7198         | OptString n, _ ->
7199             pr ", %s" n
7200         | FileIn _, arg | FileOut _, arg ->
7201             pr ", \"%s\"" (c_quote arg)
7202         | StringList n, _ | DeviceList n, _ ->
7203             pr ", (char **) %s" n
7204         | Int _, arg ->
7205             let i =
7206               try int_of_string arg
7207               with Failure "int_of_string" ->
7208                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
7209             pr ", %d" i
7210         | Int64 _, arg ->
7211             let i =
7212               try Int64.of_string arg
7213               with Failure "int_of_string" ->
7214                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
7215             pr ", %Ld" i
7216         | Bool _, arg ->
7217             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
7218       ) (List.combine (snd style) args);
7219
7220       (match fst style with
7221        | RBufferOut _ -> pr ", &size"
7222        | _ -> ()
7223       );
7224
7225       pr ");\n";
7226
7227       if not expect_error then
7228         pr "    if (r == %s)\n" error_code
7229       else
7230         pr "    if (r != %s)\n" error_code;
7231       pr "      return -1;\n";
7232
7233       (* Insert the test code. *)
7234       (match test with
7235        | None -> ()
7236        | Some f -> f ()
7237       );
7238
7239       (match fst style with
7240        | RErr | RInt _ | RInt64 _ | RBool _
7241        | RConstString _ | RConstOptString _ -> ()
7242        | RString _ | RBufferOut _ -> pr "    free (r);\n"
7243        | RStringList _ | RHashtable _ ->
7244            pr "    for (i = 0; r[i] != NULL; ++i)\n";
7245            pr "      free (r[i]);\n";
7246            pr "    free (r);\n"
7247        | RStruct (_, typ) ->
7248            pr "    guestfs_free_%s (r);\n" typ
7249        | RStructList (_, typ) ->
7250            pr "    guestfs_free_%s_list (r);\n" typ
7251       );
7252
7253       pr "  }\n"
7254
7255 and c_quote str =
7256   let str = replace_str str "\r" "\\r" in
7257   let str = replace_str str "\n" "\\n" in
7258   let str = replace_str str "\t" "\\t" in
7259   let str = replace_str str "\000" "\\0" in
7260   str
7261
7262 (* Generate a lot of different functions for guestfish. *)
7263 and generate_fish_cmds () =
7264   generate_header CStyle GPLv2plus;
7265
7266   let all_functions =
7267     List.filter (
7268       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7269     ) all_functions in
7270   let all_functions_sorted =
7271     List.filter (
7272       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7273     ) all_functions_sorted in
7274
7275   pr "#include <config.h>\n";
7276   pr "\n";
7277   pr "#include <stdio.h>\n";
7278   pr "#include <stdlib.h>\n";
7279   pr "#include <string.h>\n";
7280   pr "#include <inttypes.h>\n";
7281   pr "\n";
7282   pr "#include <guestfs.h>\n";
7283   pr "#include \"c-ctype.h\"\n";
7284   pr "#include \"full-write.h\"\n";
7285   pr "#include \"xstrtol.h\"\n";
7286   pr "#include \"fish.h\"\n";
7287   pr "\n";
7288
7289   (* list_commands function, which implements guestfish -h *)
7290   pr "void list_commands (void)\n";
7291   pr "{\n";
7292   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
7293   pr "  list_builtin_commands ();\n";
7294   List.iter (
7295     fun (name, _, _, flags, _, shortdesc, _) ->
7296       let name = replace_char name '_' '-' in
7297       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
7298         name shortdesc
7299   ) all_functions_sorted;
7300   pr "  printf (\"    %%s\\n\",";
7301   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
7302   pr "}\n";
7303   pr "\n";
7304
7305   (* display_command function, which implements guestfish -h cmd *)
7306   pr "void display_command (const char *cmd)\n";
7307   pr "{\n";
7308   List.iter (
7309     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7310       let name2 = replace_char name '_' '-' in
7311       let alias =
7312         try find_map (function FishAlias n -> Some n | _ -> None) flags
7313         with Not_found -> name in
7314       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
7315       let synopsis =
7316         match snd style with
7317         | [] -> name2
7318         | args ->
7319             sprintf "%s %s"
7320               name2 (String.concat " " (List.map name_of_argt args)) in
7321
7322       let warnings =
7323         if List.mem ProtocolLimitWarning flags then
7324           ("\n\n" ^ protocol_limit_warning)
7325         else "" in
7326
7327       (* For DangerWillRobinson commands, we should probably have
7328        * guestfish prompt before allowing you to use them (especially
7329        * in interactive mode). XXX
7330        *)
7331       let warnings =
7332         warnings ^
7333           if List.mem DangerWillRobinson flags then
7334             ("\n\n" ^ danger_will_robinson)
7335           else "" in
7336
7337       let warnings =
7338         warnings ^
7339           match deprecation_notice flags with
7340           | None -> ""
7341           | Some txt -> "\n\n" ^ txt in
7342
7343       let describe_alias =
7344         if name <> alias then
7345           sprintf "\n\nYou can use '%s' as an alias for this command." alias
7346         else "" in
7347
7348       pr "  if (";
7349       pr "STRCASEEQ (cmd, \"%s\")" name;
7350       if name <> name2 then
7351         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7352       if name <> alias then
7353         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7354       pr ")\n";
7355       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
7356         name2 shortdesc
7357         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
7358          "=head1 DESCRIPTION\n\n" ^
7359          longdesc ^ warnings ^ describe_alias);
7360       pr "  else\n"
7361   ) all_functions;
7362   pr "    display_builtin_command (cmd);\n";
7363   pr "}\n";
7364   pr "\n";
7365
7366   let emit_print_list_function typ =
7367     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
7368       typ typ typ;
7369     pr "{\n";
7370     pr "  unsigned int i;\n";
7371     pr "\n";
7372     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
7373     pr "    printf (\"[%%d] = {\\n\", i);\n";
7374     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
7375     pr "    printf (\"}\\n\");\n";
7376     pr "  }\n";
7377     pr "}\n";
7378     pr "\n";
7379   in
7380
7381   (* print_* functions *)
7382   List.iter (
7383     fun (typ, cols) ->
7384       let needs_i =
7385         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
7386
7387       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7388       pr "{\n";
7389       if needs_i then (
7390         pr "  unsigned int i;\n";
7391         pr "\n"
7392       );
7393       List.iter (
7394         function
7395         | name, FString ->
7396             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7397         | name, FUUID ->
7398             pr "  printf (\"%%s%s: \", indent);\n" name;
7399             pr "  for (i = 0; i < 32; ++i)\n";
7400             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7401             pr "  printf (\"\\n\");\n"
7402         | name, FBuffer ->
7403             pr "  printf (\"%%s%s: \", indent);\n" name;
7404             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7405             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7406             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7407             pr "    else\n";
7408             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7409             pr "  printf (\"\\n\");\n"
7410         | name, (FUInt64|FBytes) ->
7411             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7412               name typ name
7413         | name, FInt64 ->
7414             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7415               name typ name
7416         | name, FUInt32 ->
7417             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7418               name typ name
7419         | name, FInt32 ->
7420             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7421               name typ name
7422         | name, FChar ->
7423             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7424               name typ name
7425         | name, FOptPercent ->
7426             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7427               typ name name typ name;
7428             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7429       ) cols;
7430       pr "}\n";
7431       pr "\n";
7432   ) structs;
7433
7434   (* Emit a print_TYPE_list function definition only if that function is used. *)
7435   List.iter (
7436     function
7437     | typ, (RStructListOnly | RStructAndList) ->
7438         (* generate the function for typ *)
7439         emit_print_list_function typ
7440     | typ, _ -> () (* empty *)
7441   ) (rstructs_used_by all_functions);
7442
7443   (* Emit a print_TYPE function definition only if that function is used. *)
7444   List.iter (
7445     function
7446     | typ, (RStructOnly | RStructAndList) ->
7447         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7448         pr "{\n";
7449         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7450         pr "}\n";
7451         pr "\n";
7452     | typ, _ -> () (* empty *)
7453   ) (rstructs_used_by all_functions);
7454
7455   (* run_<action> actions *)
7456   List.iter (
7457     fun (name, style, _, flags, _, _, _) ->
7458       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7459       pr "{\n";
7460       (match fst style with
7461        | RErr
7462        | RInt _
7463        | RBool _ -> pr "  int r;\n"
7464        | RInt64 _ -> pr "  int64_t r;\n"
7465        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7466        | RString _ -> pr "  char *r;\n"
7467        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7468        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7469        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7470        | RBufferOut _ ->
7471            pr "  char *r;\n";
7472            pr "  size_t size;\n";
7473       );
7474       List.iter (
7475         function
7476         | Device n
7477         | String n
7478         | OptString n -> pr "  const char *%s;\n" n
7479         | Pathname n
7480         | Dev_or_Path n
7481         | FileIn n
7482         | FileOut n -> pr "  char *%s;\n" n
7483         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7484         | Bool n -> pr "  int %s;\n" n
7485         | Int n -> pr "  int %s;\n" n
7486         | Int64 n -> pr "  int64_t %s;\n" n
7487       ) (snd style);
7488
7489       (* Check and convert parameters. *)
7490       let argc_expected = List.length (snd style) in
7491       pr "  if (argc != %d) {\n" argc_expected;
7492       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7493         argc_expected;
7494       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7495       pr "    return -1;\n";
7496       pr "  }\n";
7497
7498       let parse_integer fn fntyp rtyp range name i =
7499         pr "  {\n";
7500         pr "    strtol_error xerr;\n";
7501         pr "    %s r;\n" fntyp;
7502         pr "\n";
7503         pr "    xerr = %s (argv[%d], NULL, 0, &r, \"\");\n" fn i;
7504         pr "    if (xerr != LONGINT_OK) {\n";
7505         pr "      fprintf (stderr,\n";
7506         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7507         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7508         pr "      return -1;\n";
7509         pr "    }\n";
7510         (match range with
7511          | None -> ()
7512          | Some (min, max, comment) ->
7513              pr "    /* %s */\n" comment;
7514              pr "    if (r < %s || r > %s) {\n" min max;
7515              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7516                name;
7517              pr "      return -1;\n";
7518              pr "    }\n";
7519              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7520         );
7521         pr "    %s = r;\n" name;
7522         pr "  }\n";
7523       in
7524
7525       iteri (
7526         fun i ->
7527           function
7528           | Device name
7529           | String name ->
7530               pr "  %s = argv[%d];\n" name i
7531           | Pathname name
7532           | Dev_or_Path name ->
7533               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7534               pr "  if (%s == NULL) return -1;\n" name
7535           | OptString name ->
7536               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7537                 name i i
7538           | FileIn name ->
7539               pr "  %s = file_in (argv[%d]);\n" name i;
7540               pr "  if (%s == NULL) return -1;\n" name
7541           | FileOut name ->
7542               pr "  %s = file_out (argv[%d]);\n" name i;
7543               pr "  if (%s == NULL) return -1;\n" name
7544           | StringList name | DeviceList name ->
7545               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7546               pr "  if (%s == NULL) return -1;\n" name;
7547           | Bool name ->
7548               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7549           | Int name ->
7550               let range =
7551                 let min = "(-(2LL<<30))"
7552                 and max = "((2LL<<30)-1)"
7553                 and comment =
7554                   "The Int type in the generator is a signed 31 bit int." in
7555                 Some (min, max, comment) in
7556               parse_integer "xstrtoll" "long long" "int" range name i
7557           | Int64 name ->
7558               parse_integer "xstrtoll" "long long" "int64_t" None name i
7559       ) (snd style);
7560
7561       (* Call C API function. *)
7562       let fn =
7563         try find_map (function FishAction n -> Some n | _ -> None) flags
7564         with Not_found -> sprintf "guestfs_%s" name in
7565       pr "  r = %s " fn;
7566       generate_c_call_args ~handle:"g" style;
7567       pr ";\n";
7568
7569       List.iter (
7570         function
7571         | Device name | String name
7572         | OptString name | Bool name
7573         | Int name | Int64 name -> ()
7574         | Pathname name | Dev_or_Path name | FileOut name ->
7575             pr "  free (%s);\n" name
7576         | FileIn name ->
7577             pr "  free_file_in (%s);\n" name
7578         | StringList name | DeviceList name ->
7579             pr "  free_strings (%s);\n" name
7580       ) (snd style);
7581
7582       (* Any output flags? *)
7583       let fish_output =
7584         let flags = filter_map (
7585           function FishOutput flag -> Some flag | _ -> None
7586         ) flags in
7587         match flags with
7588         | [] -> None
7589         | [f] -> Some f
7590         | _ ->
7591             failwithf "%s: more than one FishOutput flag is not allowed" name in
7592
7593       (* Check return value for errors and display command results. *)
7594       (match fst style with
7595        | RErr -> pr "  return r;\n"
7596        | RInt _ ->
7597            pr "  if (r == -1) return -1;\n";
7598            (match fish_output with
7599             | None ->
7600                 pr "  printf (\"%%d\\n\", r);\n";
7601             | Some FishOutputOctal ->
7602                 pr "  printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n";
7603             | Some FishOutputHexadecimal ->
7604                 pr "  printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7605            pr "  return 0;\n"
7606        | RInt64 _ ->
7607            pr "  if (r == -1) return -1;\n";
7608            (match fish_output with
7609             | None ->
7610                 pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7611             | Some FishOutputOctal ->
7612                 pr "  printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n";
7613             | Some FishOutputHexadecimal ->
7614                 pr "  printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7615            pr "  return 0;\n"
7616        | RBool _ ->
7617            pr "  if (r == -1) return -1;\n";
7618            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7619            pr "  return 0;\n"
7620        | RConstString _ ->
7621            pr "  if (r == NULL) return -1;\n";
7622            pr "  printf (\"%%s\\n\", r);\n";
7623            pr "  return 0;\n"
7624        | RConstOptString _ ->
7625            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7626            pr "  return 0;\n"
7627        | RString _ ->
7628            pr "  if (r == NULL) return -1;\n";
7629            pr "  printf (\"%%s\\n\", r);\n";
7630            pr "  free (r);\n";
7631            pr "  return 0;\n"
7632        | RStringList _ ->
7633            pr "  if (r == NULL) return -1;\n";
7634            pr "  print_strings (r);\n";
7635            pr "  free_strings (r);\n";
7636            pr "  return 0;\n"
7637        | RStruct (_, typ) ->
7638            pr "  if (r == NULL) return -1;\n";
7639            pr "  print_%s (r);\n" typ;
7640            pr "  guestfs_free_%s (r);\n" typ;
7641            pr "  return 0;\n"
7642        | RStructList (_, typ) ->
7643            pr "  if (r == NULL) return -1;\n";
7644            pr "  print_%s_list (r);\n" typ;
7645            pr "  guestfs_free_%s_list (r);\n" typ;
7646            pr "  return 0;\n"
7647        | RHashtable _ ->
7648            pr "  if (r == NULL) return -1;\n";
7649            pr "  print_table (r);\n";
7650            pr "  free_strings (r);\n";
7651            pr "  return 0;\n"
7652        | RBufferOut _ ->
7653            pr "  if (r == NULL) return -1;\n";
7654            pr "  if (full_write (1, r, size) != size) {\n";
7655            pr "    perror (\"write\");\n";
7656            pr "    free (r);\n";
7657            pr "    return -1;\n";
7658            pr "  }\n";
7659            pr "  free (r);\n";
7660            pr "  return 0;\n"
7661       );
7662       pr "}\n";
7663       pr "\n"
7664   ) all_functions;
7665
7666   (* run_action function *)
7667   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7668   pr "{\n";
7669   List.iter (
7670     fun (name, _, _, flags, _, _, _) ->
7671       let name2 = replace_char name '_' '-' in
7672       let alias =
7673         try find_map (function FishAlias n -> Some n | _ -> None) flags
7674         with Not_found -> name in
7675       pr "  if (";
7676       pr "STRCASEEQ (cmd, \"%s\")" name;
7677       if name <> name2 then
7678         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7679       if name <> alias then
7680         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7681       pr ")\n";
7682       pr "    return run_%s (cmd, argc, argv);\n" name;
7683       pr "  else\n";
7684   ) all_functions;
7685   pr "    {\n";
7686   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7687   pr "      if (command_num == 1)\n";
7688   pr "        extended_help_message ();\n";
7689   pr "      return -1;\n";
7690   pr "    }\n";
7691   pr "  return 0;\n";
7692   pr "}\n";
7693   pr "\n"
7694
7695 (* Readline completion for guestfish. *)
7696 and generate_fish_completion () =
7697   generate_header CStyle GPLv2plus;
7698
7699   let all_functions =
7700     List.filter (
7701       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7702     ) all_functions in
7703
7704   pr "\
7705 #include <config.h>
7706
7707 #include <stdio.h>
7708 #include <stdlib.h>
7709 #include <string.h>
7710
7711 #ifdef HAVE_LIBREADLINE
7712 #include <readline/readline.h>
7713 #endif
7714
7715 #include \"fish.h\"
7716
7717 #ifdef HAVE_LIBREADLINE
7718
7719 static const char *const commands[] = {
7720   BUILTIN_COMMANDS_FOR_COMPLETION,
7721 ";
7722
7723   (* Get the commands, including the aliases.  They don't need to be
7724    * sorted - the generator() function just does a dumb linear search.
7725    *)
7726   let commands =
7727     List.map (
7728       fun (name, _, _, flags, _, _, _) ->
7729         let name2 = replace_char name '_' '-' in
7730         let alias =
7731           try find_map (function FishAlias n -> Some n | _ -> None) flags
7732           with Not_found -> name in
7733
7734         if name <> alias then [name2; alias] else [name2]
7735     ) all_functions in
7736   let commands = List.flatten commands in
7737
7738   List.iter (pr "  \"%s\",\n") commands;
7739
7740   pr "  NULL
7741 };
7742
7743 static char *
7744 generator (const char *text, int state)
7745 {
7746   static int index, len;
7747   const char *name;
7748
7749   if (!state) {
7750     index = 0;
7751     len = strlen (text);
7752   }
7753
7754   rl_attempted_completion_over = 1;
7755
7756   while ((name = commands[index]) != NULL) {
7757     index++;
7758     if (STRCASEEQLEN (name, text, len))
7759       return strdup (name);
7760   }
7761
7762   return NULL;
7763 }
7764
7765 #endif /* HAVE_LIBREADLINE */
7766
7767 #ifdef HAVE_RL_COMPLETION_MATCHES
7768 #define RL_COMPLETION_MATCHES rl_completion_matches
7769 #else
7770 #ifdef HAVE_COMPLETION_MATCHES
7771 #define RL_COMPLETION_MATCHES completion_matches
7772 #endif
7773 #endif /* else just fail if we don't have either symbol */
7774
7775 char **
7776 do_completion (const char *text, int start, int end)
7777 {
7778   char **matches = NULL;
7779
7780 #ifdef HAVE_LIBREADLINE
7781   rl_completion_append_character = ' ';
7782
7783   if (start == 0)
7784     matches = RL_COMPLETION_MATCHES (text, generator);
7785   else if (complete_dest_paths)
7786     matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
7787 #endif
7788
7789   return matches;
7790 }
7791 ";
7792
7793 (* Generate the POD documentation for guestfish. *)
7794 and generate_fish_actions_pod () =
7795   let all_functions_sorted =
7796     List.filter (
7797       fun (_, _, _, flags, _, _, _) ->
7798         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7799     ) all_functions_sorted in
7800
7801   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7802
7803   List.iter (
7804     fun (name, style, _, flags, _, _, longdesc) ->
7805       let longdesc =
7806         Str.global_substitute rex (
7807           fun s ->
7808             let sub =
7809               try Str.matched_group 1 s
7810               with Not_found ->
7811                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7812             "C<" ^ replace_char sub '_' '-' ^ ">"
7813         ) longdesc in
7814       let name = replace_char name '_' '-' in
7815       let alias =
7816         try find_map (function FishAlias n -> Some n | _ -> None) flags
7817         with Not_found -> name in
7818
7819       pr "=head2 %s" name;
7820       if name <> alias then
7821         pr " | %s" alias;
7822       pr "\n";
7823       pr "\n";
7824       pr " %s" name;
7825       List.iter (
7826         function
7827         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7828         | OptString n -> pr " %s" n
7829         | StringList n | DeviceList n -> pr " '%s ...'" n
7830         | Bool _ -> pr " true|false"
7831         | Int n -> pr " %s" n
7832         | Int64 n -> pr " %s" n
7833         | FileIn n | FileOut n -> pr " (%s|-)" n
7834       ) (snd style);
7835       pr "\n";
7836       pr "\n";
7837       pr "%s\n\n" longdesc;
7838
7839       if List.exists (function FileIn _ | FileOut _ -> true
7840                       | _ -> false) (snd style) then
7841         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7842
7843       if List.mem ProtocolLimitWarning flags then
7844         pr "%s\n\n" protocol_limit_warning;
7845
7846       if List.mem DangerWillRobinson flags then
7847         pr "%s\n\n" danger_will_robinson;
7848
7849       match deprecation_notice flags with
7850       | None -> ()
7851       | Some txt -> pr "%s\n\n" txt
7852   ) all_functions_sorted
7853
7854 (* Generate a C function prototype. *)
7855 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7856     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7857     ?(prefix = "")
7858     ?handle name style =
7859   if extern then pr "extern ";
7860   if static then pr "static ";
7861   (match fst style with
7862    | RErr -> pr "int "
7863    | RInt _ -> pr "int "
7864    | RInt64 _ -> pr "int64_t "
7865    | RBool _ -> pr "int "
7866    | RConstString _ | RConstOptString _ -> pr "const char *"
7867    | RString _ | RBufferOut _ -> pr "char *"
7868    | RStringList _ | RHashtable _ -> pr "char **"
7869    | RStruct (_, typ) ->
7870        if not in_daemon then pr "struct guestfs_%s *" typ
7871        else pr "guestfs_int_%s *" typ
7872    | RStructList (_, typ) ->
7873        if not in_daemon then pr "struct guestfs_%s_list *" typ
7874        else pr "guestfs_int_%s_list *" typ
7875   );
7876   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7877   pr "%s%s (" prefix name;
7878   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7879     pr "void"
7880   else (
7881     let comma = ref false in
7882     (match handle with
7883      | None -> ()
7884      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7885     );
7886     let next () =
7887       if !comma then (
7888         if single_line then pr ", " else pr ",\n\t\t"
7889       );
7890       comma := true
7891     in
7892     List.iter (
7893       function
7894       | Pathname n
7895       | Device n | Dev_or_Path n
7896       | String n
7897       | OptString n ->
7898           next ();
7899           pr "const char *%s" n
7900       | StringList n | DeviceList n ->
7901           next ();
7902           pr "char *const *%s" n
7903       | Bool n -> next (); pr "int %s" n
7904       | Int n -> next (); pr "int %s" n
7905       | Int64 n -> next (); pr "int64_t %s" n
7906       | FileIn n
7907       | FileOut n ->
7908           if not in_daemon then (next (); pr "const char *%s" n)
7909     ) (snd style);
7910     if is_RBufferOut then (next (); pr "size_t *size_r");
7911   );
7912   pr ")";
7913   if semicolon then pr ";";
7914   if newline then pr "\n"
7915
7916 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7917 and generate_c_call_args ?handle ?(decl = false) style =
7918   pr "(";
7919   let comma = ref false in
7920   let next () =
7921     if !comma then pr ", ";
7922     comma := true
7923   in
7924   (match handle with
7925    | None -> ()
7926    | Some handle -> pr "%s" handle; comma := true
7927   );
7928   List.iter (
7929     fun arg ->
7930       next ();
7931       pr "%s" (name_of_argt arg)
7932   ) (snd style);
7933   (* For RBufferOut calls, add implicit &size parameter. *)
7934   if not decl then (
7935     match fst style with
7936     | RBufferOut _ ->
7937         next ();
7938         pr "&size"
7939     | _ -> ()
7940   );
7941   pr ")"
7942
7943 (* Generate the OCaml bindings interface. *)
7944 and generate_ocaml_mli () =
7945   generate_header OCamlStyle LGPLv2plus;
7946
7947   pr "\
7948 (** For API documentation you should refer to the C API
7949     in the guestfs(3) manual page.  The OCaml API uses almost
7950     exactly the same calls. *)
7951
7952 type t
7953 (** A [guestfs_h] handle. *)
7954
7955 exception Error of string
7956 (** This exception is raised when there is an error. *)
7957
7958 exception Handle_closed of string
7959 (** This exception is raised if you use a {!Guestfs.t} handle
7960     after calling {!close} on it.  The string is the name of
7961     the function. *)
7962
7963 val create : unit -> t
7964 (** Create a {!Guestfs.t} handle. *)
7965
7966 val close : t -> unit
7967 (** Close the {!Guestfs.t} handle and free up all resources used
7968     by it immediately.
7969
7970     Handles are closed by the garbage collector when they become
7971     unreferenced, but callers can call this in order to provide
7972     predictable cleanup. *)
7973
7974 ";
7975   generate_ocaml_structure_decls ();
7976
7977   (* The actions. *)
7978   List.iter (
7979     fun (name, style, _, _, _, shortdesc, _) ->
7980       generate_ocaml_prototype name style;
7981       pr "(** %s *)\n" shortdesc;
7982       pr "\n"
7983   ) all_functions_sorted
7984
7985 (* Generate the OCaml bindings implementation. *)
7986 and generate_ocaml_ml () =
7987   generate_header OCamlStyle LGPLv2plus;
7988
7989   pr "\
7990 type t
7991
7992 exception Error of string
7993 exception Handle_closed of string
7994
7995 external create : unit -> t = \"ocaml_guestfs_create\"
7996 external close : t -> unit = \"ocaml_guestfs_close\"
7997
7998 (* Give the exceptions names, so they can be raised from the C code. *)
7999 let () =
8000   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
8001   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
8002
8003 ";
8004
8005   generate_ocaml_structure_decls ();
8006
8007   (* The actions. *)
8008   List.iter (
8009     fun (name, style, _, _, _, shortdesc, _) ->
8010       generate_ocaml_prototype ~is_external:true name style;
8011   ) all_functions_sorted
8012
8013 (* Generate the OCaml bindings C implementation. *)
8014 and generate_ocaml_c () =
8015   generate_header CStyle LGPLv2plus;
8016
8017   pr "\
8018 #include <stdio.h>
8019 #include <stdlib.h>
8020 #include <string.h>
8021
8022 #include <caml/config.h>
8023 #include <caml/alloc.h>
8024 #include <caml/callback.h>
8025 #include <caml/fail.h>
8026 #include <caml/memory.h>
8027 #include <caml/mlvalues.h>
8028 #include <caml/signals.h>
8029
8030 #include <guestfs.h>
8031
8032 #include \"guestfs_c.h\"
8033
8034 /* Copy a hashtable of string pairs into an assoc-list.  We return
8035  * the list in reverse order, but hashtables aren't supposed to be
8036  * ordered anyway.
8037  */
8038 static CAMLprim value
8039 copy_table (char * const * argv)
8040 {
8041   CAMLparam0 ();
8042   CAMLlocal5 (rv, pairv, kv, vv, cons);
8043   int i;
8044
8045   rv = Val_int (0);
8046   for (i = 0; argv[i] != NULL; i += 2) {
8047     kv = caml_copy_string (argv[i]);
8048     vv = caml_copy_string (argv[i+1]);
8049     pairv = caml_alloc (2, 0);
8050     Store_field (pairv, 0, kv);
8051     Store_field (pairv, 1, vv);
8052     cons = caml_alloc (2, 0);
8053     Store_field (cons, 1, rv);
8054     rv = cons;
8055     Store_field (cons, 0, pairv);
8056   }
8057
8058   CAMLreturn (rv);
8059 }
8060
8061 ";
8062
8063   (* Struct copy functions. *)
8064
8065   let emit_ocaml_copy_list_function typ =
8066     pr "static CAMLprim value\n";
8067     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
8068     pr "{\n";
8069     pr "  CAMLparam0 ();\n";
8070     pr "  CAMLlocal2 (rv, v);\n";
8071     pr "  unsigned int i;\n";
8072     pr "\n";
8073     pr "  if (%ss->len == 0)\n" typ;
8074     pr "    CAMLreturn (Atom (0));\n";
8075     pr "  else {\n";
8076     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
8077     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
8078     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
8079     pr "      caml_modify (&Field (rv, i), v);\n";
8080     pr "    }\n";
8081     pr "    CAMLreturn (rv);\n";
8082     pr "  }\n";
8083     pr "}\n";
8084     pr "\n";
8085   in
8086
8087   List.iter (
8088     fun (typ, cols) ->
8089       let has_optpercent_col =
8090         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
8091
8092       pr "static CAMLprim value\n";
8093       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
8094       pr "{\n";
8095       pr "  CAMLparam0 ();\n";
8096       if has_optpercent_col then
8097         pr "  CAMLlocal3 (rv, v, v2);\n"
8098       else
8099         pr "  CAMLlocal2 (rv, v);\n";
8100       pr "\n";
8101       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
8102       iteri (
8103         fun i col ->
8104           (match col with
8105            | name, FString ->
8106                pr "  v = caml_copy_string (%s->%s);\n" typ name
8107            | name, FBuffer ->
8108                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
8109                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
8110                  typ name typ name
8111            | name, FUUID ->
8112                pr "  v = caml_alloc_string (32);\n";
8113                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
8114            | name, (FBytes|FInt64|FUInt64) ->
8115                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
8116            | name, (FInt32|FUInt32) ->
8117                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
8118            | name, FOptPercent ->
8119                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
8120                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
8121                pr "    v = caml_alloc (1, 0);\n";
8122                pr "    Store_field (v, 0, v2);\n";
8123                pr "  } else /* None */\n";
8124                pr "    v = Val_int (0);\n";
8125            | name, FChar ->
8126                pr "  v = Val_int (%s->%s);\n" typ name
8127           );
8128           pr "  Store_field (rv, %d, v);\n" i
8129       ) cols;
8130       pr "  CAMLreturn (rv);\n";
8131       pr "}\n";
8132       pr "\n";
8133   ) structs;
8134
8135   (* Emit a copy_TYPE_list function definition only if that function is used. *)
8136   List.iter (
8137     function
8138     | typ, (RStructListOnly | RStructAndList) ->
8139         (* generate the function for typ *)
8140         emit_ocaml_copy_list_function typ
8141     | typ, _ -> () (* empty *)
8142   ) (rstructs_used_by all_functions);
8143
8144   (* The wrappers. *)
8145   List.iter (
8146     fun (name, style, _, _, _, _, _) ->
8147       pr "/* Automatically generated wrapper for function\n";
8148       pr " * ";
8149       generate_ocaml_prototype name style;
8150       pr " */\n";
8151       pr "\n";
8152
8153       let params =
8154         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
8155
8156       let needs_extra_vs =
8157         match fst style with RConstOptString _ -> true | _ -> false in
8158
8159       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8160       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
8161       List.iter (pr ", value %s") (List.tl params); pr ");\n";
8162       pr "\n";
8163
8164       pr "CAMLprim value\n";
8165       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
8166       List.iter (pr ", value %s") (List.tl params);
8167       pr ")\n";
8168       pr "{\n";
8169
8170       (match params with
8171        | [p1; p2; p3; p4; p5] ->
8172            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
8173        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
8174            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
8175            pr "  CAMLxparam%d (%s);\n"
8176              (List.length rest) (String.concat ", " rest)
8177        | ps ->
8178            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
8179       );
8180       if not needs_extra_vs then
8181         pr "  CAMLlocal1 (rv);\n"
8182       else
8183         pr "  CAMLlocal3 (rv, v, v2);\n";
8184       pr "\n";
8185
8186       pr "  guestfs_h *g = Guestfs_val (gv);\n";
8187       pr "  if (g == NULL)\n";
8188       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
8189       pr "\n";
8190
8191       List.iter (
8192         function
8193         | Pathname n
8194         | Device n | Dev_or_Path n
8195         | String n
8196         | FileIn n
8197         | FileOut n ->
8198             pr "  const char *%s = String_val (%sv);\n" n n
8199         | OptString n ->
8200             pr "  const char *%s =\n" n;
8201             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
8202               n n
8203         | StringList n | DeviceList n ->
8204             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
8205         | Bool n ->
8206             pr "  int %s = Bool_val (%sv);\n" n n
8207         | Int n ->
8208             pr "  int %s = Int_val (%sv);\n" n n
8209         | Int64 n ->
8210             pr "  int64_t %s = Int64_val (%sv);\n" n n
8211       ) (snd style);
8212       let error_code =
8213         match fst style with
8214         | RErr -> pr "  int r;\n"; "-1"
8215         | RInt _ -> pr "  int r;\n"; "-1"
8216         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8217         | RBool _ -> pr "  int r;\n"; "-1"
8218         | RConstString _ | RConstOptString _ ->
8219             pr "  const char *r;\n"; "NULL"
8220         | RString _ -> pr "  char *r;\n"; "NULL"
8221         | RStringList _ ->
8222             pr "  int i;\n";
8223             pr "  char **r;\n";
8224             "NULL"
8225         | RStruct (_, typ) ->
8226             pr "  struct guestfs_%s *r;\n" typ; "NULL"
8227         | RStructList (_, typ) ->
8228             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8229         | RHashtable _ ->
8230             pr "  int i;\n";
8231             pr "  char **r;\n";
8232             "NULL"
8233         | RBufferOut _ ->
8234             pr "  char *r;\n";
8235             pr "  size_t size;\n";
8236             "NULL" in
8237       pr "\n";
8238
8239       pr "  caml_enter_blocking_section ();\n";
8240       pr "  r = guestfs_%s " name;
8241       generate_c_call_args ~handle:"g" style;
8242       pr ";\n";
8243       pr "  caml_leave_blocking_section ();\n";
8244
8245       List.iter (
8246         function
8247         | StringList n | DeviceList n ->
8248             pr "  ocaml_guestfs_free_strings (%s);\n" n;
8249         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8250         | Bool _ | Int _ | Int64 _
8251         | FileIn _ | FileOut _ -> ()
8252       ) (snd style);
8253
8254       pr "  if (r == %s)\n" error_code;
8255       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
8256       pr "\n";
8257
8258       (match fst style with
8259        | RErr -> pr "  rv = Val_unit;\n"
8260        | RInt _ -> pr "  rv = Val_int (r);\n"
8261        | RInt64 _ ->
8262            pr "  rv = caml_copy_int64 (r);\n"
8263        | RBool _ -> pr "  rv = Val_bool (r);\n"
8264        | RConstString _ ->
8265            pr "  rv = caml_copy_string (r);\n"
8266        | RConstOptString _ ->
8267            pr "  if (r) { /* Some string */\n";
8268            pr "    v = caml_alloc (1, 0);\n";
8269            pr "    v2 = caml_copy_string (r);\n";
8270            pr "    Store_field (v, 0, v2);\n";
8271            pr "  } else /* None */\n";
8272            pr "    v = Val_int (0);\n";
8273        | RString _ ->
8274            pr "  rv = caml_copy_string (r);\n";
8275            pr "  free (r);\n"
8276        | RStringList _ ->
8277            pr "  rv = caml_copy_string_array ((const char **) r);\n";
8278            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8279            pr "  free (r);\n"
8280        | RStruct (_, typ) ->
8281            pr "  rv = copy_%s (r);\n" typ;
8282            pr "  guestfs_free_%s (r);\n" typ;
8283        | RStructList (_, typ) ->
8284            pr "  rv = copy_%s_list (r);\n" typ;
8285            pr "  guestfs_free_%s_list (r);\n" typ;
8286        | RHashtable _ ->
8287            pr "  rv = copy_table (r);\n";
8288            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8289            pr "  free (r);\n";
8290        | RBufferOut _ ->
8291            pr "  rv = caml_alloc_string (size);\n";
8292            pr "  memcpy (String_val (rv), r, size);\n";
8293       );
8294
8295       pr "  CAMLreturn (rv);\n";
8296       pr "}\n";
8297       pr "\n";
8298
8299       if List.length params > 5 then (
8300         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8301         pr "CAMLprim value ";
8302         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
8303         pr "CAMLprim value\n";
8304         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
8305         pr "{\n";
8306         pr "  return ocaml_guestfs_%s (argv[0]" name;
8307         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
8308         pr ");\n";
8309         pr "}\n";
8310         pr "\n"
8311       )
8312   ) all_functions_sorted
8313
8314 and generate_ocaml_structure_decls () =
8315   List.iter (
8316     fun (typ, cols) ->
8317       pr "type %s = {\n" typ;
8318       List.iter (
8319         function
8320         | name, FString -> pr "  %s : string;\n" name
8321         | name, FBuffer -> pr "  %s : string;\n" name
8322         | name, FUUID -> pr "  %s : string;\n" name
8323         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
8324         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
8325         | name, FChar -> pr "  %s : char;\n" name
8326         | name, FOptPercent -> pr "  %s : float option;\n" name
8327       ) cols;
8328       pr "}\n";
8329       pr "\n"
8330   ) structs
8331
8332 and generate_ocaml_prototype ?(is_external = false) name style =
8333   if is_external then pr "external " else pr "val ";
8334   pr "%s : t -> " name;
8335   List.iter (
8336     function
8337     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
8338     | OptString _ -> pr "string option -> "
8339     | StringList _ | DeviceList _ -> pr "string array -> "
8340     | Bool _ -> pr "bool -> "
8341     | Int _ -> pr "int -> "
8342     | Int64 _ -> pr "int64 -> "
8343   ) (snd style);
8344   (match fst style with
8345    | RErr -> pr "unit" (* all errors are turned into exceptions *)
8346    | RInt _ -> pr "int"
8347    | RInt64 _ -> pr "int64"
8348    | RBool _ -> pr "bool"
8349    | RConstString _ -> pr "string"
8350    | RConstOptString _ -> pr "string option"
8351    | RString _ | RBufferOut _ -> pr "string"
8352    | RStringList _ -> pr "string array"
8353    | RStruct (_, typ) -> pr "%s" typ
8354    | RStructList (_, typ) -> pr "%s array" typ
8355    | RHashtable _ -> pr "(string * string) list"
8356   );
8357   if is_external then (
8358     pr " = ";
8359     if List.length (snd style) + 1 > 5 then
8360       pr "\"ocaml_guestfs_%s_byte\" " name;
8361     pr "\"ocaml_guestfs_%s\"" name
8362   );
8363   pr "\n"
8364
8365 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
8366 and generate_perl_xs () =
8367   generate_header CStyle LGPLv2plus;
8368
8369   pr "\
8370 #include \"EXTERN.h\"
8371 #include \"perl.h\"
8372 #include \"XSUB.h\"
8373
8374 #include <guestfs.h>
8375
8376 #ifndef PRId64
8377 #define PRId64 \"lld\"
8378 #endif
8379
8380 static SV *
8381 my_newSVll(long long val) {
8382 #ifdef USE_64_BIT_ALL
8383   return newSViv(val);
8384 #else
8385   char buf[100];
8386   int len;
8387   len = snprintf(buf, 100, \"%%\" PRId64, val);
8388   return newSVpv(buf, len);
8389 #endif
8390 }
8391
8392 #ifndef PRIu64
8393 #define PRIu64 \"llu\"
8394 #endif
8395
8396 static SV *
8397 my_newSVull(unsigned long long val) {
8398 #ifdef USE_64_BIT_ALL
8399   return newSVuv(val);
8400 #else
8401   char buf[100];
8402   int len;
8403   len = snprintf(buf, 100, \"%%\" PRIu64, val);
8404   return newSVpv(buf, len);
8405 #endif
8406 }
8407
8408 /* http://www.perlmonks.org/?node_id=680842 */
8409 static char **
8410 XS_unpack_charPtrPtr (SV *arg) {
8411   char **ret;
8412   AV *av;
8413   I32 i;
8414
8415   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
8416     croak (\"array reference expected\");
8417
8418   av = (AV *)SvRV (arg);
8419   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
8420   if (!ret)
8421     croak (\"malloc failed\");
8422
8423   for (i = 0; i <= av_len (av); i++) {
8424     SV **elem = av_fetch (av, i, 0);
8425
8426     if (!elem || !*elem)
8427       croak (\"missing element in list\");
8428
8429     ret[i] = SvPV_nolen (*elem);
8430   }
8431
8432   ret[i] = NULL;
8433
8434   return ret;
8435 }
8436
8437 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8438
8439 PROTOTYPES: ENABLE
8440
8441 guestfs_h *
8442 _create ()
8443    CODE:
8444       RETVAL = guestfs_create ();
8445       if (!RETVAL)
8446         croak (\"could not create guestfs handle\");
8447       guestfs_set_error_handler (RETVAL, NULL, NULL);
8448  OUTPUT:
8449       RETVAL
8450
8451 void
8452 DESTROY (g)
8453       guestfs_h *g;
8454  PPCODE:
8455       guestfs_close (g);
8456
8457 ";
8458
8459   List.iter (
8460     fun (name, style, _, _, _, _, _) ->
8461       (match fst style with
8462        | RErr -> pr "void\n"
8463        | RInt _ -> pr "SV *\n"
8464        | RInt64 _ -> pr "SV *\n"
8465        | RBool _ -> pr "SV *\n"
8466        | RConstString _ -> pr "SV *\n"
8467        | RConstOptString _ -> pr "SV *\n"
8468        | RString _ -> pr "SV *\n"
8469        | RBufferOut _ -> pr "SV *\n"
8470        | RStringList _
8471        | RStruct _ | RStructList _
8472        | RHashtable _ ->
8473            pr "void\n" (* all lists returned implictly on the stack *)
8474       );
8475       (* Call and arguments. *)
8476       pr "%s " name;
8477       generate_c_call_args ~handle:"g" ~decl:true style;
8478       pr "\n";
8479       pr "      guestfs_h *g;\n";
8480       iteri (
8481         fun i ->
8482           function
8483           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8484               pr "      char *%s;\n" n
8485           | OptString n ->
8486               (* http://www.perlmonks.org/?node_id=554277
8487                * Note that the implicit handle argument means we have
8488                * to add 1 to the ST(x) operator.
8489                *)
8490               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8491           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8492           | Bool n -> pr "      int %s;\n" n
8493           | Int n -> pr "      int %s;\n" n
8494           | Int64 n -> pr "      int64_t %s;\n" n
8495       ) (snd style);
8496
8497       let do_cleanups () =
8498         List.iter (
8499           function
8500           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8501           | Bool _ | Int _ | Int64 _
8502           | FileIn _ | FileOut _ -> ()
8503           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8504         ) (snd style)
8505       in
8506
8507       (* Code. *)
8508       (match fst style with
8509        | RErr ->
8510            pr "PREINIT:\n";
8511            pr "      int r;\n";
8512            pr " PPCODE:\n";
8513            pr "      r = guestfs_%s " name;
8514            generate_c_call_args ~handle:"g" style;
8515            pr ";\n";
8516            do_cleanups ();
8517            pr "      if (r == -1)\n";
8518            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8519        | RInt n
8520        | RBool n ->
8521            pr "PREINIT:\n";
8522            pr "      int %s;\n" n;
8523            pr "   CODE:\n";
8524            pr "      %s = guestfs_%s " n name;
8525            generate_c_call_args ~handle:"g" style;
8526            pr ";\n";
8527            do_cleanups ();
8528            pr "      if (%s == -1)\n" n;
8529            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8530            pr "      RETVAL = newSViv (%s);\n" n;
8531            pr " OUTPUT:\n";
8532            pr "      RETVAL\n"
8533        | RInt64 n ->
8534            pr "PREINIT:\n";
8535            pr "      int64_t %s;\n" n;
8536            pr "   CODE:\n";
8537            pr "      %s = guestfs_%s " n name;
8538            generate_c_call_args ~handle:"g" style;
8539            pr ";\n";
8540            do_cleanups ();
8541            pr "      if (%s == -1)\n" n;
8542            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8543            pr "      RETVAL = my_newSVll (%s);\n" n;
8544            pr " OUTPUT:\n";
8545            pr "      RETVAL\n"
8546        | RConstString n ->
8547            pr "PREINIT:\n";
8548            pr "      const char *%s;\n" n;
8549            pr "   CODE:\n";
8550            pr "      %s = guestfs_%s " n name;
8551            generate_c_call_args ~handle:"g" style;
8552            pr ";\n";
8553            do_cleanups ();
8554            pr "      if (%s == NULL)\n" n;
8555            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8556            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8557            pr " OUTPUT:\n";
8558            pr "      RETVAL\n"
8559        | RConstOptString n ->
8560            pr "PREINIT:\n";
8561            pr "      const char *%s;\n" n;
8562            pr "   CODE:\n";
8563            pr "      %s = guestfs_%s " n name;
8564            generate_c_call_args ~handle:"g" style;
8565            pr ";\n";
8566            do_cleanups ();
8567            pr "      if (%s == NULL)\n" n;
8568            pr "        RETVAL = &PL_sv_undef;\n";
8569            pr "      else\n";
8570            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8571            pr " OUTPUT:\n";
8572            pr "      RETVAL\n"
8573        | RString n ->
8574            pr "PREINIT:\n";
8575            pr "      char *%s;\n" n;
8576            pr "   CODE:\n";
8577            pr "      %s = guestfs_%s " n name;
8578            generate_c_call_args ~handle:"g" style;
8579            pr ";\n";
8580            do_cleanups ();
8581            pr "      if (%s == NULL)\n" n;
8582            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8583            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8584            pr "      free (%s);\n" n;
8585            pr " OUTPUT:\n";
8586            pr "      RETVAL\n"
8587        | RStringList n | RHashtable n ->
8588            pr "PREINIT:\n";
8589            pr "      char **%s;\n" n;
8590            pr "      int i, n;\n";
8591            pr " PPCODE:\n";
8592            pr "      %s = guestfs_%s " n name;
8593            generate_c_call_args ~handle:"g" style;
8594            pr ";\n";
8595            do_cleanups ();
8596            pr "      if (%s == NULL)\n" n;
8597            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8598            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8599            pr "      EXTEND (SP, n);\n";
8600            pr "      for (i = 0; i < n; ++i) {\n";
8601            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8602            pr "        free (%s[i]);\n" n;
8603            pr "      }\n";
8604            pr "      free (%s);\n" n;
8605        | RStruct (n, typ) ->
8606            let cols = cols_of_struct typ in
8607            generate_perl_struct_code typ cols name style n do_cleanups
8608        | RStructList (n, typ) ->
8609            let cols = cols_of_struct typ in
8610            generate_perl_struct_list_code typ cols name style n do_cleanups
8611        | RBufferOut n ->
8612            pr "PREINIT:\n";
8613            pr "      char *%s;\n" n;
8614            pr "      size_t size;\n";
8615            pr "   CODE:\n";
8616            pr "      %s = guestfs_%s " n name;
8617            generate_c_call_args ~handle:"g" style;
8618            pr ";\n";
8619            do_cleanups ();
8620            pr "      if (%s == NULL)\n" n;
8621            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8622            pr "      RETVAL = newSVpvn (%s, size);\n" n;
8623            pr "      free (%s);\n" n;
8624            pr " OUTPUT:\n";
8625            pr "      RETVAL\n"
8626       );
8627
8628       pr "\n"
8629   ) all_functions
8630
8631 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8632   pr "PREINIT:\n";
8633   pr "      struct guestfs_%s_list *%s;\n" typ n;
8634   pr "      int i;\n";
8635   pr "      HV *hv;\n";
8636   pr " PPCODE:\n";
8637   pr "      %s = guestfs_%s " n name;
8638   generate_c_call_args ~handle:"g" style;
8639   pr ";\n";
8640   do_cleanups ();
8641   pr "      if (%s == NULL)\n" n;
8642   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8643   pr "      EXTEND (SP, %s->len);\n" n;
8644   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8645   pr "        hv = newHV ();\n";
8646   List.iter (
8647     function
8648     | name, FString ->
8649         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8650           name (String.length name) n name
8651     | name, FUUID ->
8652         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8653           name (String.length name) n name
8654     | name, FBuffer ->
8655         pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8656           name (String.length name) n name n name
8657     | name, (FBytes|FUInt64) ->
8658         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8659           name (String.length name) n name
8660     | name, FInt64 ->
8661         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8662           name (String.length name) n name
8663     | name, (FInt32|FUInt32) ->
8664         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8665           name (String.length name) n name
8666     | name, FChar ->
8667         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8668           name (String.length name) n name
8669     | name, FOptPercent ->
8670         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8671           name (String.length name) n name
8672   ) cols;
8673   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8674   pr "      }\n";
8675   pr "      guestfs_free_%s_list (%s);\n" typ n
8676
8677 and generate_perl_struct_code typ cols name style n do_cleanups =
8678   pr "PREINIT:\n";
8679   pr "      struct guestfs_%s *%s;\n" typ n;
8680   pr " PPCODE:\n";
8681   pr "      %s = guestfs_%s " n name;
8682   generate_c_call_args ~handle:"g" style;
8683   pr ";\n";
8684   do_cleanups ();
8685   pr "      if (%s == NULL)\n" n;
8686   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8687   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8688   List.iter (
8689     fun ((name, _) as col) ->
8690       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8691
8692       match col with
8693       | name, FString ->
8694           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8695             n name
8696       | name, FBuffer ->
8697           pr "      PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
8698             n name n name
8699       | name, FUUID ->
8700           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8701             n name
8702       | name, (FBytes|FUInt64) ->
8703           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8704             n name
8705       | name, FInt64 ->
8706           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8707             n name
8708       | name, (FInt32|FUInt32) ->
8709           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8710             n name
8711       | name, FChar ->
8712           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8713             n name
8714       | name, FOptPercent ->
8715           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8716             n name
8717   ) cols;
8718   pr "      free (%s);\n" n
8719
8720 (* Generate Sys/Guestfs.pm. *)
8721 and generate_perl_pm () =
8722   generate_header HashStyle LGPLv2plus;
8723
8724   pr "\
8725 =pod
8726
8727 =head1 NAME
8728
8729 Sys::Guestfs - Perl bindings for libguestfs
8730
8731 =head1 SYNOPSIS
8732
8733  use Sys::Guestfs;
8734
8735  my $h = Sys::Guestfs->new ();
8736  $h->add_drive ('guest.img');
8737  $h->launch ();
8738  $h->mount ('/dev/sda1', '/');
8739  $h->touch ('/hello');
8740  $h->sync ();
8741
8742 =head1 DESCRIPTION
8743
8744 The C<Sys::Guestfs> module provides a Perl XS binding to the
8745 libguestfs API for examining and modifying virtual machine
8746 disk images.
8747
8748 Amongst the things this is good for: making batch configuration
8749 changes to guests, getting disk used/free statistics (see also:
8750 virt-df), migrating between virtualization systems (see also:
8751 virt-p2v), performing partial backups, performing partial guest
8752 clones, cloning guests and changing registry/UUID/hostname info, and
8753 much else besides.
8754
8755 Libguestfs uses Linux kernel and qemu code, and can access any type of
8756 guest filesystem that Linux and qemu can, including but not limited
8757 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8758 schemes, qcow, qcow2, vmdk.
8759
8760 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8761 LVs, what filesystem is in each LV, etc.).  It can also run commands
8762 in the context of the guest.  Also you can access filesystems over
8763 FUSE.
8764
8765 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8766 functions for using libguestfs from Perl, including integration
8767 with libvirt.
8768
8769 =head1 ERRORS
8770
8771 All errors turn into calls to C<croak> (see L<Carp(3)>).
8772
8773 =head1 METHODS
8774
8775 =over 4
8776
8777 =cut
8778
8779 package Sys::Guestfs;
8780
8781 use strict;
8782 use warnings;
8783
8784 require XSLoader;
8785 XSLoader::load ('Sys::Guestfs');
8786
8787 =item $h = Sys::Guestfs->new ();
8788
8789 Create a new guestfs handle.
8790
8791 =cut
8792
8793 sub new {
8794   my $proto = shift;
8795   my $class = ref ($proto) || $proto;
8796
8797   my $self = Sys::Guestfs::_create ();
8798   bless $self, $class;
8799   return $self;
8800 }
8801
8802 ";
8803
8804   (* Actions.  We only need to print documentation for these as
8805    * they are pulled in from the XS code automatically.
8806    *)
8807   List.iter (
8808     fun (name, style, _, flags, _, _, longdesc) ->
8809       if not (List.mem NotInDocs flags) then (
8810         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8811         pr "=item ";
8812         generate_perl_prototype name style;
8813         pr "\n\n";
8814         pr "%s\n\n" longdesc;
8815         if List.mem ProtocolLimitWarning flags then
8816           pr "%s\n\n" protocol_limit_warning;
8817         if List.mem DangerWillRobinson flags then
8818           pr "%s\n\n" danger_will_robinson;
8819         match deprecation_notice flags with
8820         | None -> ()
8821         | Some txt -> pr "%s\n\n" txt
8822       )
8823   ) all_functions_sorted;
8824
8825   (* End of file. *)
8826   pr "\
8827 =cut
8828
8829 1;
8830
8831 =back
8832
8833 =head1 COPYRIGHT
8834
8835 Copyright (C) %s Red Hat Inc.
8836
8837 =head1 LICENSE
8838
8839 Please see the file COPYING.LIB for the full license.
8840
8841 =head1 SEE ALSO
8842
8843 L<guestfs(3)>,
8844 L<guestfish(1)>,
8845 L<http://libguestfs.org>,
8846 L<Sys::Guestfs::Lib(3)>.
8847
8848 =cut
8849 " copyright_years
8850
8851 and generate_perl_prototype name style =
8852   (match fst style with
8853    | RErr -> ()
8854    | RBool n
8855    | RInt n
8856    | RInt64 n
8857    | RConstString n
8858    | RConstOptString n
8859    | RString n
8860    | RBufferOut n -> pr "$%s = " n
8861    | RStruct (n,_)
8862    | RHashtable n -> pr "%%%s = " n
8863    | RStringList n
8864    | RStructList (n,_) -> pr "@%s = " n
8865   );
8866   pr "$h->%s (" name;
8867   let comma = ref false in
8868   List.iter (
8869     fun arg ->
8870       if !comma then pr ", ";
8871       comma := true;
8872       match arg with
8873       | Pathname n | Device n | Dev_or_Path n | String n
8874       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8875           pr "$%s" n
8876       | StringList n | DeviceList n ->
8877           pr "\\@%s" n
8878   ) (snd style);
8879   pr ");"
8880
8881 (* Generate Python C module. *)
8882 and generate_python_c () =
8883   generate_header CStyle LGPLv2plus;
8884
8885   pr "\
8886 #include <Python.h>
8887
8888 #include <stdio.h>
8889 #include <stdlib.h>
8890 #include <assert.h>
8891
8892 #include \"guestfs.h\"
8893
8894 typedef struct {
8895   PyObject_HEAD
8896   guestfs_h *g;
8897 } Pyguestfs_Object;
8898
8899 static guestfs_h *
8900 get_handle (PyObject *obj)
8901 {
8902   assert (obj);
8903   assert (obj != Py_None);
8904   return ((Pyguestfs_Object *) obj)->g;
8905 }
8906
8907 static PyObject *
8908 put_handle (guestfs_h *g)
8909 {
8910   assert (g);
8911   return
8912     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8913 }
8914
8915 /* This list should be freed (but not the strings) after use. */
8916 static char **
8917 get_string_list (PyObject *obj)
8918 {
8919   int i, len;
8920   char **r;
8921
8922   assert (obj);
8923
8924   if (!PyList_Check (obj)) {
8925     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8926     return NULL;
8927   }
8928
8929   len = PyList_Size (obj);
8930   r = malloc (sizeof (char *) * (len+1));
8931   if (r == NULL) {
8932     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8933     return NULL;
8934   }
8935
8936   for (i = 0; i < len; ++i)
8937     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8938   r[len] = NULL;
8939
8940   return r;
8941 }
8942
8943 static PyObject *
8944 put_string_list (char * const * const argv)
8945 {
8946   PyObject *list;
8947   int argc, i;
8948
8949   for (argc = 0; argv[argc] != NULL; ++argc)
8950     ;
8951
8952   list = PyList_New (argc);
8953   for (i = 0; i < argc; ++i)
8954     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8955
8956   return list;
8957 }
8958
8959 static PyObject *
8960 put_table (char * const * const argv)
8961 {
8962   PyObject *list, *item;
8963   int argc, i;
8964
8965   for (argc = 0; argv[argc] != NULL; ++argc)
8966     ;
8967
8968   list = PyList_New (argc >> 1);
8969   for (i = 0; i < argc; i += 2) {
8970     item = PyTuple_New (2);
8971     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8972     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8973     PyList_SetItem (list, i >> 1, item);
8974   }
8975
8976   return list;
8977 }
8978
8979 static void
8980 free_strings (char **argv)
8981 {
8982   int argc;
8983
8984   for (argc = 0; argv[argc] != NULL; ++argc)
8985     free (argv[argc]);
8986   free (argv);
8987 }
8988
8989 static PyObject *
8990 py_guestfs_create (PyObject *self, PyObject *args)
8991 {
8992   guestfs_h *g;
8993
8994   g = guestfs_create ();
8995   if (g == NULL) {
8996     PyErr_SetString (PyExc_RuntimeError,
8997                      \"guestfs.create: failed to allocate handle\");
8998     return NULL;
8999   }
9000   guestfs_set_error_handler (g, NULL, NULL);
9001   return put_handle (g);
9002 }
9003
9004 static PyObject *
9005 py_guestfs_close (PyObject *self, PyObject *args)
9006 {
9007   PyObject *py_g;
9008   guestfs_h *g;
9009
9010   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
9011     return NULL;
9012   g = get_handle (py_g);
9013
9014   guestfs_close (g);
9015
9016   Py_INCREF (Py_None);
9017   return Py_None;
9018 }
9019
9020 ";
9021
9022   let emit_put_list_function typ =
9023     pr "static PyObject *\n";
9024     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
9025     pr "{\n";
9026     pr "  PyObject *list;\n";
9027     pr "  int i;\n";
9028     pr "\n";
9029     pr "  list = PyList_New (%ss->len);\n" typ;
9030     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
9031     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
9032     pr "  return list;\n";
9033     pr "};\n";
9034     pr "\n"
9035   in
9036
9037   (* Structures, turned into Python dictionaries. *)
9038   List.iter (
9039     fun (typ, cols) ->
9040       pr "static PyObject *\n";
9041       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
9042       pr "{\n";
9043       pr "  PyObject *dict;\n";
9044       pr "\n";
9045       pr "  dict = PyDict_New ();\n";
9046       List.iter (
9047         function
9048         | name, FString ->
9049             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9050             pr "                        PyString_FromString (%s->%s));\n"
9051               typ name
9052         | name, FBuffer ->
9053             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9054             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
9055               typ name typ name
9056         | name, FUUID ->
9057             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9058             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
9059               typ name
9060         | name, (FBytes|FUInt64) ->
9061             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9062             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
9063               typ name
9064         | name, FInt64 ->
9065             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9066             pr "                        PyLong_FromLongLong (%s->%s));\n"
9067               typ name
9068         | name, FUInt32 ->
9069             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9070             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
9071               typ name
9072         | name, FInt32 ->
9073             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9074             pr "                        PyLong_FromLong (%s->%s));\n"
9075               typ name
9076         | name, FOptPercent ->
9077             pr "  if (%s->%s >= 0)\n" typ name;
9078             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
9079             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
9080               typ name;
9081             pr "  else {\n";
9082             pr "    Py_INCREF (Py_None);\n";
9083             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
9084             pr "  }\n"
9085         | name, FChar ->
9086             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9087             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
9088       ) cols;
9089       pr "  return dict;\n";
9090       pr "};\n";
9091       pr "\n";
9092
9093   ) structs;
9094
9095   (* Emit a put_TYPE_list function definition only if that function is used. *)
9096   List.iter (
9097     function
9098     | typ, (RStructListOnly | RStructAndList) ->
9099         (* generate the function for typ *)
9100         emit_put_list_function typ
9101     | typ, _ -> () (* empty *)
9102   ) (rstructs_used_by all_functions);
9103
9104   (* Python wrapper functions. *)
9105   List.iter (
9106     fun (name, style, _, _, _, _, _) ->
9107       pr "static PyObject *\n";
9108       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
9109       pr "{\n";
9110
9111       pr "  PyObject *py_g;\n";
9112       pr "  guestfs_h *g;\n";
9113       pr "  PyObject *py_r;\n";
9114
9115       let error_code =
9116         match fst style with
9117         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9118         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9119         | RConstString _ | RConstOptString _ ->
9120             pr "  const char *r;\n"; "NULL"
9121         | RString _ -> pr "  char *r;\n"; "NULL"
9122         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9123         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9124         | RStructList (_, typ) ->
9125             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9126         | RBufferOut _ ->
9127             pr "  char *r;\n";
9128             pr "  size_t size;\n";
9129             "NULL" in
9130
9131       List.iter (
9132         function
9133         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9134             pr "  const char *%s;\n" n
9135         | OptString n -> pr "  const char *%s;\n" n
9136         | StringList n | DeviceList n ->
9137             pr "  PyObject *py_%s;\n" n;
9138             pr "  char **%s;\n" n
9139         | Bool n -> pr "  int %s;\n" n
9140         | Int n -> pr "  int %s;\n" n
9141         | Int64 n -> pr "  long long %s;\n" n
9142       ) (snd style);
9143
9144       pr "\n";
9145
9146       (* Convert the parameters. *)
9147       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
9148       List.iter (
9149         function
9150         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
9151         | OptString _ -> pr "z"
9152         | StringList _ | DeviceList _ -> pr "O"
9153         | Bool _ -> pr "i" (* XXX Python has booleans? *)
9154         | Int _ -> pr "i"
9155         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
9156                              * emulate C's int/long/long long in Python?
9157                              *)
9158       ) (snd style);
9159       pr ":guestfs_%s\",\n" name;
9160       pr "                         &py_g";
9161       List.iter (
9162         function
9163         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
9164         | OptString n -> pr ", &%s" n
9165         | StringList n | DeviceList n -> pr ", &py_%s" n
9166         | Bool n -> pr ", &%s" n
9167         | Int n -> pr ", &%s" n
9168         | Int64 n -> pr ", &%s" n
9169       ) (snd style);
9170
9171       pr "))\n";
9172       pr "    return NULL;\n";
9173
9174       pr "  g = get_handle (py_g);\n";
9175       List.iter (
9176         function
9177         | Pathname _ | Device _ | Dev_or_Path _ | String _
9178         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9179         | StringList n | DeviceList n ->
9180             pr "  %s = get_string_list (py_%s);\n" n n;
9181             pr "  if (!%s) return NULL;\n" n
9182       ) (snd style);
9183
9184       pr "\n";
9185
9186       pr "  r = guestfs_%s " name;
9187       generate_c_call_args ~handle:"g" style;
9188       pr ";\n";
9189
9190       List.iter (
9191         function
9192         | Pathname _ | Device _ | Dev_or_Path _ | String _
9193         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9194         | StringList n | DeviceList n ->
9195             pr "  free (%s);\n" n
9196       ) (snd style);
9197
9198       pr "  if (r == %s) {\n" error_code;
9199       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
9200       pr "    return NULL;\n";
9201       pr "  }\n";
9202       pr "\n";
9203
9204       (match fst style with
9205        | RErr ->
9206            pr "  Py_INCREF (Py_None);\n";
9207            pr "  py_r = Py_None;\n"
9208        | RInt _
9209        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
9210        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
9211        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
9212        | RConstOptString _ ->
9213            pr "  if (r)\n";
9214            pr "    py_r = PyString_FromString (r);\n";
9215            pr "  else {\n";
9216            pr "    Py_INCREF (Py_None);\n";
9217            pr "    py_r = Py_None;\n";
9218            pr "  }\n"
9219        | RString _ ->
9220            pr "  py_r = PyString_FromString (r);\n";
9221            pr "  free (r);\n"
9222        | RStringList _ ->
9223            pr "  py_r = put_string_list (r);\n";
9224            pr "  free_strings (r);\n"
9225        | RStruct (_, typ) ->
9226            pr "  py_r = put_%s (r);\n" typ;
9227            pr "  guestfs_free_%s (r);\n" typ
9228        | RStructList (_, typ) ->
9229            pr "  py_r = put_%s_list (r);\n" typ;
9230            pr "  guestfs_free_%s_list (r);\n" typ
9231        | RHashtable n ->
9232            pr "  py_r = put_table (r);\n";
9233            pr "  free_strings (r);\n"
9234        | RBufferOut _ ->
9235            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
9236            pr "  free (r);\n"
9237       );
9238
9239       pr "  return py_r;\n";
9240       pr "}\n";
9241       pr "\n"
9242   ) all_functions;
9243
9244   (* Table of functions. *)
9245   pr "static PyMethodDef methods[] = {\n";
9246   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
9247   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
9248   List.iter (
9249     fun (name, _, _, _, _, _, _) ->
9250       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
9251         name name
9252   ) all_functions;
9253   pr "  { NULL, NULL, 0, NULL }\n";
9254   pr "};\n";
9255   pr "\n";
9256
9257   (* Init function. *)
9258   pr "\
9259 void
9260 initlibguestfsmod (void)
9261 {
9262   static int initialized = 0;
9263
9264   if (initialized) return;
9265   Py_InitModule ((char *) \"libguestfsmod\", methods);
9266   initialized = 1;
9267 }
9268 "
9269
9270 (* Generate Python module. *)
9271 and generate_python_py () =
9272   generate_header HashStyle LGPLv2plus;
9273
9274   pr "\
9275 u\"\"\"Python bindings for libguestfs
9276
9277 import guestfs
9278 g = guestfs.GuestFS ()
9279 g.add_drive (\"guest.img\")
9280 g.launch ()
9281 parts = g.list_partitions ()
9282
9283 The guestfs module provides a Python binding to the libguestfs API
9284 for examining and modifying virtual machine disk images.
9285
9286 Amongst the things this is good for: making batch configuration
9287 changes to guests, getting disk used/free statistics (see also:
9288 virt-df), migrating between virtualization systems (see also:
9289 virt-p2v), performing partial backups, performing partial guest
9290 clones, cloning guests and changing registry/UUID/hostname info, and
9291 much else besides.
9292
9293 Libguestfs uses Linux kernel and qemu code, and can access any type of
9294 guest filesystem that Linux and qemu can, including but not limited
9295 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
9296 schemes, qcow, qcow2, vmdk.
9297
9298 Libguestfs provides ways to enumerate guest storage (eg. partitions,
9299 LVs, what filesystem is in each LV, etc.).  It can also run commands
9300 in the context of the guest.  Also you can access filesystems over
9301 FUSE.
9302
9303 Errors which happen while using the API are turned into Python
9304 RuntimeError exceptions.
9305
9306 To create a guestfs handle you usually have to perform the following
9307 sequence of calls:
9308
9309 # Create the handle, call add_drive at least once, and possibly
9310 # several times if the guest has multiple block devices:
9311 g = guestfs.GuestFS ()
9312 g.add_drive (\"guest.img\")
9313
9314 # Launch the qemu subprocess and wait for it to become ready:
9315 g.launch ()
9316
9317 # Now you can issue commands, for example:
9318 logvols = g.lvs ()
9319
9320 \"\"\"
9321
9322 import libguestfsmod
9323
9324 class GuestFS:
9325     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
9326
9327     def __init__ (self):
9328         \"\"\"Create a new libguestfs handle.\"\"\"
9329         self._o = libguestfsmod.create ()
9330
9331     def __del__ (self):
9332         libguestfsmod.close (self._o)
9333
9334 ";
9335
9336   List.iter (
9337     fun (name, style, _, flags, _, _, longdesc) ->
9338       pr "    def %s " name;
9339       generate_py_call_args ~handle:"self" (snd style);
9340       pr ":\n";
9341
9342       if not (List.mem NotInDocs flags) then (
9343         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9344         let doc =
9345           match fst style with
9346           | RErr | RInt _ | RInt64 _ | RBool _
9347           | RConstOptString _ | RConstString _
9348           | RString _ | RBufferOut _ -> doc
9349           | RStringList _ ->
9350               doc ^ "\n\nThis function returns a list of strings."
9351           | RStruct (_, typ) ->
9352               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
9353           | RStructList (_, typ) ->
9354               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
9355           | RHashtable _ ->
9356               doc ^ "\n\nThis function returns a dictionary." in
9357         let doc =
9358           if List.mem ProtocolLimitWarning flags then
9359             doc ^ "\n\n" ^ protocol_limit_warning
9360           else doc in
9361         let doc =
9362           if List.mem DangerWillRobinson flags then
9363             doc ^ "\n\n" ^ danger_will_robinson
9364           else doc in
9365         let doc =
9366           match deprecation_notice flags with
9367           | None -> doc
9368           | Some txt -> doc ^ "\n\n" ^ txt in
9369         let doc = pod2text ~width:60 name doc in
9370         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
9371         let doc = String.concat "\n        " doc in
9372         pr "        u\"\"\"%s\"\"\"\n" doc;
9373       );
9374       pr "        return libguestfsmod.%s " name;
9375       generate_py_call_args ~handle:"self._o" (snd style);
9376       pr "\n";
9377       pr "\n";
9378   ) all_functions
9379
9380 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
9381 and generate_py_call_args ~handle args =
9382   pr "(%s" handle;
9383   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9384   pr ")"
9385
9386 (* Useful if you need the longdesc POD text as plain text.  Returns a
9387  * list of lines.
9388  *
9389  * Because this is very slow (the slowest part of autogeneration),
9390  * we memoize the results.
9391  *)
9392 and pod2text ~width name longdesc =
9393   let key = width, name, longdesc in
9394   try Hashtbl.find pod2text_memo key
9395   with Not_found ->
9396     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
9397     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
9398     close_out chan;
9399     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
9400     let chan = open_process_in cmd in
9401     let lines = ref [] in
9402     let rec loop i =
9403       let line = input_line chan in
9404       if i = 1 then             (* discard the first line of output *)
9405         loop (i+1)
9406       else (
9407         let line = triml line in
9408         lines := line :: !lines;
9409         loop (i+1)
9410       ) in
9411     let lines = try loop 1 with End_of_file -> List.rev !lines in
9412     unlink filename;
9413     (match close_process_in chan with
9414      | WEXITED 0 -> ()
9415      | WEXITED i ->
9416          failwithf "pod2text: process exited with non-zero status (%d)" i
9417      | WSIGNALED i | WSTOPPED i ->
9418          failwithf "pod2text: process signalled or stopped by signal %d" i
9419     );
9420     Hashtbl.add pod2text_memo key lines;
9421     pod2text_memo_updated ();
9422     lines
9423
9424 (* Generate ruby bindings. *)
9425 and generate_ruby_c () =
9426   generate_header CStyle LGPLv2plus;
9427
9428   pr "\
9429 #include <stdio.h>
9430 #include <stdlib.h>
9431
9432 #include <ruby.h>
9433
9434 #include \"guestfs.h\"
9435
9436 #include \"extconf.h\"
9437
9438 /* For Ruby < 1.9 */
9439 #ifndef RARRAY_LEN
9440 #define RARRAY_LEN(r) (RARRAY((r))->len)
9441 #endif
9442
9443 static VALUE m_guestfs;                 /* guestfs module */
9444 static VALUE c_guestfs;                 /* guestfs_h handle */
9445 static VALUE e_Error;                   /* used for all errors */
9446
9447 static void ruby_guestfs_free (void *p)
9448 {
9449   if (!p) return;
9450   guestfs_close ((guestfs_h *) p);
9451 }
9452
9453 static VALUE ruby_guestfs_create (VALUE m)
9454 {
9455   guestfs_h *g;
9456
9457   g = guestfs_create ();
9458   if (!g)
9459     rb_raise (e_Error, \"failed to create guestfs handle\");
9460
9461   /* Don't print error messages to stderr by default. */
9462   guestfs_set_error_handler (g, NULL, NULL);
9463
9464   /* Wrap it, and make sure the close function is called when the
9465    * handle goes away.
9466    */
9467   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9468 }
9469
9470 static VALUE ruby_guestfs_close (VALUE gv)
9471 {
9472   guestfs_h *g;
9473   Data_Get_Struct (gv, guestfs_h, g);
9474
9475   ruby_guestfs_free (g);
9476   DATA_PTR (gv) = NULL;
9477
9478   return Qnil;
9479 }
9480
9481 ";
9482
9483   List.iter (
9484     fun (name, style, _, _, _, _, _) ->
9485       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9486       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9487       pr ")\n";
9488       pr "{\n";
9489       pr "  guestfs_h *g;\n";
9490       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9491       pr "  if (!g)\n";
9492       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9493         name;
9494       pr "\n";
9495
9496       List.iter (
9497         function
9498         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9499             pr "  Check_Type (%sv, T_STRING);\n" n;
9500             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9501             pr "  if (!%s)\n" n;
9502             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9503             pr "              \"%s\", \"%s\");\n" n name
9504         | OptString n ->
9505             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9506         | StringList n | DeviceList n ->
9507             pr "  char **%s;\n" n;
9508             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9509             pr "  {\n";
9510             pr "    int i, len;\n";
9511             pr "    len = RARRAY_LEN (%sv);\n" n;
9512             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9513               n;
9514             pr "    for (i = 0; i < len; ++i) {\n";
9515             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9516             pr "      %s[i] = StringValueCStr (v);\n" n;
9517             pr "    }\n";
9518             pr "    %s[len] = NULL;\n" n;
9519             pr "  }\n";
9520         | Bool n ->
9521             pr "  int %s = RTEST (%sv);\n" n n
9522         | Int n ->
9523             pr "  int %s = NUM2INT (%sv);\n" n n
9524         | Int64 n ->
9525             pr "  long long %s = NUM2LL (%sv);\n" n n
9526       ) (snd style);
9527       pr "\n";
9528
9529       let error_code =
9530         match fst style with
9531         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9532         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9533         | RConstString _ | RConstOptString _ ->
9534             pr "  const char *r;\n"; "NULL"
9535         | RString _ -> pr "  char *r;\n"; "NULL"
9536         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9537         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9538         | RStructList (_, typ) ->
9539             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9540         | RBufferOut _ ->
9541             pr "  char *r;\n";
9542             pr "  size_t size;\n";
9543             "NULL" in
9544       pr "\n";
9545
9546       pr "  r = guestfs_%s " name;
9547       generate_c_call_args ~handle:"g" style;
9548       pr ";\n";
9549
9550       List.iter (
9551         function
9552         | Pathname _ | Device _ | Dev_or_Path _ | String _
9553         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9554         | StringList n | DeviceList n ->
9555             pr "  free (%s);\n" n
9556       ) (snd style);
9557
9558       pr "  if (r == %s)\n" error_code;
9559       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9560       pr "\n";
9561
9562       (match fst style with
9563        | RErr ->
9564            pr "  return Qnil;\n"
9565        | RInt _ | RBool _ ->
9566            pr "  return INT2NUM (r);\n"
9567        | RInt64 _ ->
9568            pr "  return ULL2NUM (r);\n"
9569        | RConstString _ ->
9570            pr "  return rb_str_new2 (r);\n";
9571        | RConstOptString _ ->
9572            pr "  if (r)\n";
9573            pr "    return rb_str_new2 (r);\n";
9574            pr "  else\n";
9575            pr "    return Qnil;\n";
9576        | RString _ ->
9577            pr "  VALUE rv = rb_str_new2 (r);\n";
9578            pr "  free (r);\n";
9579            pr "  return rv;\n";
9580        | RStringList _ ->
9581            pr "  int i, len = 0;\n";
9582            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9583            pr "  VALUE rv = rb_ary_new2 (len);\n";
9584            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9585            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9586            pr "    free (r[i]);\n";
9587            pr "  }\n";
9588            pr "  free (r);\n";
9589            pr "  return rv;\n"
9590        | RStruct (_, typ) ->
9591            let cols = cols_of_struct typ in
9592            generate_ruby_struct_code typ cols
9593        | RStructList (_, typ) ->
9594            let cols = cols_of_struct typ in
9595            generate_ruby_struct_list_code typ cols
9596        | RHashtable _ ->
9597            pr "  VALUE rv = rb_hash_new ();\n";
9598            pr "  int i;\n";
9599            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9600            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9601            pr "    free (r[i]);\n";
9602            pr "    free (r[i+1]);\n";
9603            pr "  }\n";
9604            pr "  free (r);\n";
9605            pr "  return rv;\n"
9606        | RBufferOut _ ->
9607            pr "  VALUE rv = rb_str_new (r, size);\n";
9608            pr "  free (r);\n";
9609            pr "  return rv;\n";
9610       );
9611
9612       pr "}\n";
9613       pr "\n"
9614   ) all_functions;
9615
9616   pr "\
9617 /* Initialize the module. */
9618 void Init__guestfs ()
9619 {
9620   m_guestfs = rb_define_module (\"Guestfs\");
9621   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9622   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9623
9624   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9625   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9626
9627 ";
9628   (* Define the rest of the methods. *)
9629   List.iter (
9630     fun (name, style, _, _, _, _, _) ->
9631       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9632       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9633   ) all_functions;
9634
9635   pr "}\n"
9636
9637 (* Ruby code to return a struct. *)
9638 and generate_ruby_struct_code typ cols =
9639   pr "  VALUE rv = rb_hash_new ();\n";
9640   List.iter (
9641     function
9642     | name, FString ->
9643         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9644     | name, FBuffer ->
9645         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9646     | name, FUUID ->
9647         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9648     | name, (FBytes|FUInt64) ->
9649         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9650     | name, FInt64 ->
9651         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9652     | name, FUInt32 ->
9653         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9654     | name, FInt32 ->
9655         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9656     | name, FOptPercent ->
9657         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9658     | name, FChar -> (* XXX wrong? *)
9659         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9660   ) cols;
9661   pr "  guestfs_free_%s (r);\n" typ;
9662   pr "  return rv;\n"
9663
9664 (* Ruby code to return a struct list. *)
9665 and generate_ruby_struct_list_code typ cols =
9666   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9667   pr "  int i;\n";
9668   pr "  for (i = 0; i < r->len; ++i) {\n";
9669   pr "    VALUE hv = rb_hash_new ();\n";
9670   List.iter (
9671     function
9672     | name, FString ->
9673         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9674     | name, FBuffer ->
9675         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
9676     | name, FUUID ->
9677         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9678     | name, (FBytes|FUInt64) ->
9679         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9680     | name, FInt64 ->
9681         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9682     | name, FUInt32 ->
9683         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9684     | name, FInt32 ->
9685         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9686     | name, FOptPercent ->
9687         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9688     | name, FChar -> (* XXX wrong? *)
9689         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9690   ) cols;
9691   pr "    rb_ary_push (rv, hv);\n";
9692   pr "  }\n";
9693   pr "  guestfs_free_%s_list (r);\n" typ;
9694   pr "  return rv;\n"
9695
9696 (* Generate Java bindings GuestFS.java file. *)
9697 and generate_java_java () =
9698   generate_header CStyle LGPLv2plus;
9699
9700   pr "\
9701 package com.redhat.et.libguestfs;
9702
9703 import java.util.HashMap;
9704 import com.redhat.et.libguestfs.LibGuestFSException;
9705 import com.redhat.et.libguestfs.PV;
9706 import com.redhat.et.libguestfs.VG;
9707 import com.redhat.et.libguestfs.LV;
9708 import com.redhat.et.libguestfs.Stat;
9709 import com.redhat.et.libguestfs.StatVFS;
9710 import com.redhat.et.libguestfs.IntBool;
9711 import com.redhat.et.libguestfs.Dirent;
9712
9713 /**
9714  * The GuestFS object is a libguestfs handle.
9715  *
9716  * @author rjones
9717  */
9718 public class GuestFS {
9719   // Load the native code.
9720   static {
9721     System.loadLibrary (\"guestfs_jni\");
9722   }
9723
9724   /**
9725    * The native guestfs_h pointer.
9726    */
9727   long g;
9728
9729   /**
9730    * Create a libguestfs handle.
9731    *
9732    * @throws LibGuestFSException
9733    */
9734   public GuestFS () throws LibGuestFSException
9735   {
9736     g = _create ();
9737   }
9738   private native long _create () throws LibGuestFSException;
9739
9740   /**
9741    * Close a libguestfs handle.
9742    *
9743    * You can also leave handles to be collected by the garbage
9744    * collector, but this method ensures that the resources used
9745    * by the handle are freed up immediately.  If you call any
9746    * other methods after closing the handle, you will get an
9747    * exception.
9748    *
9749    * @throws LibGuestFSException
9750    */
9751   public void close () throws LibGuestFSException
9752   {
9753     if (g != 0)
9754       _close (g);
9755     g = 0;
9756   }
9757   private native void _close (long g) throws LibGuestFSException;
9758
9759   public void finalize () throws LibGuestFSException
9760   {
9761     close ();
9762   }
9763
9764 ";
9765
9766   List.iter (
9767     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9768       if not (List.mem NotInDocs flags); then (
9769         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9770         let doc =
9771           if List.mem ProtocolLimitWarning flags then
9772             doc ^ "\n\n" ^ protocol_limit_warning
9773           else doc in
9774         let doc =
9775           if List.mem DangerWillRobinson flags then
9776             doc ^ "\n\n" ^ danger_will_robinson
9777           else doc in
9778         let doc =
9779           match deprecation_notice flags with
9780           | None -> doc
9781           | Some txt -> doc ^ "\n\n" ^ txt in
9782         let doc = pod2text ~width:60 name doc in
9783         let doc = List.map (            (* RHBZ#501883 *)
9784           function
9785           | "" -> "<p>"
9786           | nonempty -> nonempty
9787         ) doc in
9788         let doc = String.concat "\n   * " doc in
9789
9790         pr "  /**\n";
9791         pr "   * %s\n" shortdesc;
9792         pr "   * <p>\n";
9793         pr "   * %s\n" doc;
9794         pr "   * @throws LibGuestFSException\n";
9795         pr "   */\n";
9796         pr "  ";
9797       );
9798       generate_java_prototype ~public:true ~semicolon:false name style;
9799       pr "\n";
9800       pr "  {\n";
9801       pr "    if (g == 0)\n";
9802       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9803         name;
9804       pr "    ";
9805       if fst style <> RErr then pr "return ";
9806       pr "_%s " name;
9807       generate_java_call_args ~handle:"g" (snd style);
9808       pr ";\n";
9809       pr "  }\n";
9810       pr "  ";
9811       generate_java_prototype ~privat:true ~native:true name style;
9812       pr "\n";
9813       pr "\n";
9814   ) all_functions;
9815
9816   pr "}\n"
9817
9818 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9819 and generate_java_call_args ~handle args =
9820   pr "(%s" handle;
9821   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9822   pr ")"
9823
9824 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9825     ?(semicolon=true) name style =
9826   if privat then pr "private ";
9827   if public then pr "public ";
9828   if native then pr "native ";
9829
9830   (* return type *)
9831   (match fst style with
9832    | RErr -> pr "void ";
9833    | RInt _ -> pr "int ";
9834    | RInt64 _ -> pr "long ";
9835    | RBool _ -> pr "boolean ";
9836    | RConstString _ | RConstOptString _ | RString _
9837    | RBufferOut _ -> pr "String ";
9838    | RStringList _ -> pr "String[] ";
9839    | RStruct (_, typ) ->
9840        let name = java_name_of_struct typ in
9841        pr "%s " name;
9842    | RStructList (_, typ) ->
9843        let name = java_name_of_struct typ in
9844        pr "%s[] " name;
9845    | RHashtable _ -> pr "HashMap<String,String> ";
9846   );
9847
9848   if native then pr "_%s " name else pr "%s " name;
9849   pr "(";
9850   let needs_comma = ref false in
9851   if native then (
9852     pr "long g";
9853     needs_comma := true
9854   );
9855
9856   (* args *)
9857   List.iter (
9858     fun arg ->
9859       if !needs_comma then pr ", ";
9860       needs_comma := true;
9861
9862       match arg with
9863       | Pathname n
9864       | Device n | Dev_or_Path n
9865       | String n
9866       | OptString n
9867       | FileIn n
9868       | FileOut n ->
9869           pr "String %s" n
9870       | StringList n | DeviceList n ->
9871           pr "String[] %s" n
9872       | Bool n ->
9873           pr "boolean %s" n
9874       | Int n ->
9875           pr "int %s" n
9876       | Int64 n ->
9877           pr "long %s" n
9878   ) (snd style);
9879
9880   pr ")\n";
9881   pr "    throws LibGuestFSException";
9882   if semicolon then pr ";"
9883
9884 and generate_java_struct jtyp cols () =
9885   generate_header CStyle LGPLv2plus;
9886
9887   pr "\
9888 package com.redhat.et.libguestfs;
9889
9890 /**
9891  * Libguestfs %s structure.
9892  *
9893  * @author rjones
9894  * @see GuestFS
9895  */
9896 public class %s {
9897 " jtyp jtyp;
9898
9899   List.iter (
9900     function
9901     | name, FString
9902     | name, FUUID
9903     | name, FBuffer -> pr "  public String %s;\n" name
9904     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9905     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9906     | name, FChar -> pr "  public char %s;\n" name
9907     | name, FOptPercent ->
9908         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9909         pr "  public float %s;\n" name
9910   ) cols;
9911
9912   pr "}\n"
9913
9914 and generate_java_c () =
9915   generate_header CStyle LGPLv2plus;
9916
9917   pr "\
9918 #include <stdio.h>
9919 #include <stdlib.h>
9920 #include <string.h>
9921
9922 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9923 #include \"guestfs.h\"
9924
9925 /* Note that this function returns.  The exception is not thrown
9926  * until after the wrapper function returns.
9927  */
9928 static void
9929 throw_exception (JNIEnv *env, const char *msg)
9930 {
9931   jclass cl;
9932   cl = (*env)->FindClass (env,
9933                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9934   (*env)->ThrowNew (env, cl, msg);
9935 }
9936
9937 JNIEXPORT jlong JNICALL
9938 Java_com_redhat_et_libguestfs_GuestFS__1create
9939   (JNIEnv *env, jobject obj)
9940 {
9941   guestfs_h *g;
9942
9943   g = guestfs_create ();
9944   if (g == NULL) {
9945     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9946     return 0;
9947   }
9948   guestfs_set_error_handler (g, NULL, NULL);
9949   return (jlong) (long) g;
9950 }
9951
9952 JNIEXPORT void JNICALL
9953 Java_com_redhat_et_libguestfs_GuestFS__1close
9954   (JNIEnv *env, jobject obj, jlong jg)
9955 {
9956   guestfs_h *g = (guestfs_h *) (long) jg;
9957   guestfs_close (g);
9958 }
9959
9960 ";
9961
9962   List.iter (
9963     fun (name, style, _, _, _, _, _) ->
9964       pr "JNIEXPORT ";
9965       (match fst style with
9966        | RErr -> pr "void ";
9967        | RInt _ -> pr "jint ";
9968        | RInt64 _ -> pr "jlong ";
9969        | RBool _ -> pr "jboolean ";
9970        | RConstString _ | RConstOptString _ | RString _
9971        | RBufferOut _ -> pr "jstring ";
9972        | RStruct _ | RHashtable _ ->
9973            pr "jobject ";
9974        | RStringList _ | RStructList _ ->
9975            pr "jobjectArray ";
9976       );
9977       pr "JNICALL\n";
9978       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9979       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9980       pr "\n";
9981       pr "  (JNIEnv *env, jobject obj, jlong jg";
9982       List.iter (
9983         function
9984         | Pathname n
9985         | Device n | Dev_or_Path n
9986         | String n
9987         | OptString n
9988         | FileIn n
9989         | FileOut n ->
9990             pr ", jstring j%s" n
9991         | StringList n | DeviceList n ->
9992             pr ", jobjectArray j%s" n
9993         | Bool n ->
9994             pr ", jboolean j%s" n
9995         | Int n ->
9996             pr ", jint j%s" n
9997         | Int64 n ->
9998             pr ", jlong j%s" n
9999       ) (snd style);
10000       pr ")\n";
10001       pr "{\n";
10002       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
10003       let error_code, no_ret =
10004         match fst style with
10005         | RErr -> pr "  int r;\n"; "-1", ""
10006         | RBool _
10007         | RInt _ -> pr "  int r;\n"; "-1", "0"
10008         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
10009         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10010         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10011         | RString _ ->
10012             pr "  jstring jr;\n";
10013             pr "  char *r;\n"; "NULL", "NULL"
10014         | RStringList _ ->
10015             pr "  jobjectArray jr;\n";
10016             pr "  int r_len;\n";
10017             pr "  jclass cl;\n";
10018             pr "  jstring jstr;\n";
10019             pr "  char **r;\n"; "NULL", "NULL"
10020         | RStruct (_, typ) ->
10021             pr "  jobject jr;\n";
10022             pr "  jclass cl;\n";
10023             pr "  jfieldID fl;\n";
10024             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
10025         | RStructList (_, typ) ->
10026             pr "  jobjectArray jr;\n";
10027             pr "  jclass cl;\n";
10028             pr "  jfieldID fl;\n";
10029             pr "  jobject jfl;\n";
10030             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
10031         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
10032         | RBufferOut _ ->
10033             pr "  jstring jr;\n";
10034             pr "  char *r;\n";
10035             pr "  size_t size;\n";
10036             "NULL", "NULL" in
10037       List.iter (
10038         function
10039         | Pathname n
10040         | Device n | Dev_or_Path n
10041         | String n
10042         | OptString n
10043         | FileIn n
10044         | FileOut n ->
10045             pr "  const char *%s;\n" n
10046         | StringList n | DeviceList n ->
10047             pr "  int %s_len;\n" n;
10048             pr "  const char **%s;\n" n
10049         | Bool n
10050         | Int n ->
10051             pr "  int %s;\n" n
10052         | Int64 n ->
10053             pr "  int64_t %s;\n" n
10054       ) (snd style);
10055
10056       let needs_i =
10057         (match fst style with
10058          | RStringList _ | RStructList _ -> true
10059          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
10060          | RConstOptString _
10061          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
10062           List.exists (function
10063                        | StringList _ -> true
10064                        | DeviceList _ -> true
10065                        | _ -> false) (snd style) in
10066       if needs_i then
10067         pr "  int i;\n";
10068
10069       pr "\n";
10070
10071       (* Get the parameters. *)
10072       List.iter (
10073         function
10074         | Pathname n
10075         | Device n | Dev_or_Path n
10076         | String n
10077         | FileIn n
10078         | FileOut n ->
10079             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
10080         | OptString n ->
10081             (* This is completely undocumented, but Java null becomes
10082              * a NULL parameter.
10083              *)
10084             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
10085         | StringList n | DeviceList n ->
10086             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
10087             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
10088             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10089             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10090               n;
10091             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
10092             pr "  }\n";
10093             pr "  %s[%s_len] = NULL;\n" n n;
10094         | Bool n
10095         | Int n
10096         | Int64 n ->
10097             pr "  %s = j%s;\n" n n
10098       ) (snd style);
10099
10100       (* Make the call. *)
10101       pr "  r = guestfs_%s " name;
10102       generate_c_call_args ~handle:"g" style;
10103       pr ";\n";
10104
10105       (* Release the parameters. *)
10106       List.iter (
10107         function
10108         | Pathname n
10109         | Device n | Dev_or_Path n
10110         | String n
10111         | FileIn n
10112         | FileOut n ->
10113             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10114         | OptString n ->
10115             pr "  if (j%s)\n" n;
10116             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10117         | StringList n | DeviceList n ->
10118             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10119             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10120               n;
10121             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
10122             pr "  }\n";
10123             pr "  free (%s);\n" n
10124         | Bool n
10125         | Int n
10126         | Int64 n -> ()
10127       ) (snd style);
10128
10129       (* Check for errors. *)
10130       pr "  if (r == %s) {\n" error_code;
10131       pr "    throw_exception (env, guestfs_last_error (g));\n";
10132       pr "    return %s;\n" no_ret;
10133       pr "  }\n";
10134
10135       (* Return value. *)
10136       (match fst style with
10137        | RErr -> ()
10138        | RInt _ -> pr "  return (jint) r;\n"
10139        | RBool _ -> pr "  return (jboolean) r;\n"
10140        | RInt64 _ -> pr "  return (jlong) r;\n"
10141        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
10142        | RConstOptString _ ->
10143            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
10144        | RString _ ->
10145            pr "  jr = (*env)->NewStringUTF (env, r);\n";
10146            pr "  free (r);\n";
10147            pr "  return jr;\n"
10148        | RStringList _ ->
10149            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
10150            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
10151            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
10152            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
10153            pr "  for (i = 0; i < r_len; ++i) {\n";
10154            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
10155            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
10156            pr "    free (r[i]);\n";
10157            pr "  }\n";
10158            pr "  free (r);\n";
10159            pr "  return jr;\n"
10160        | RStruct (_, typ) ->
10161            let jtyp = java_name_of_struct typ in
10162            let cols = cols_of_struct typ in
10163            generate_java_struct_return typ jtyp cols
10164        | RStructList (_, typ) ->
10165            let jtyp = java_name_of_struct typ in
10166            let cols = cols_of_struct typ in
10167            generate_java_struct_list_return typ jtyp cols
10168        | RHashtable _ ->
10169            (* XXX *)
10170            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
10171            pr "  return NULL;\n"
10172        | RBufferOut _ ->
10173            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
10174            pr "  free (r);\n";
10175            pr "  return jr;\n"
10176       );
10177
10178       pr "}\n";
10179       pr "\n"
10180   ) all_functions
10181
10182 and generate_java_struct_return typ jtyp cols =
10183   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10184   pr "  jr = (*env)->AllocObject (env, cl);\n";
10185   List.iter (
10186     function
10187     | name, FString ->
10188         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10189         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
10190     | name, FUUID ->
10191         pr "  {\n";
10192         pr "    char s[33];\n";
10193         pr "    memcpy (s, r->%s, 32);\n" name;
10194         pr "    s[32] = 0;\n";
10195         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10196         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10197         pr "  }\n";
10198     | name, FBuffer ->
10199         pr "  {\n";
10200         pr "    int len = r->%s_len;\n" name;
10201         pr "    char s[len+1];\n";
10202         pr "    memcpy (s, r->%s, len);\n" name;
10203         pr "    s[len] = 0;\n";
10204         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10205         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10206         pr "  }\n";
10207     | name, (FBytes|FUInt64|FInt64) ->
10208         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10209         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10210     | name, (FUInt32|FInt32) ->
10211         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10212         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10213     | name, FOptPercent ->
10214         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10215         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
10216     | name, FChar ->
10217         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10218         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10219   ) cols;
10220   pr "  free (r);\n";
10221   pr "  return jr;\n"
10222
10223 and generate_java_struct_list_return typ jtyp cols =
10224   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10225   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
10226   pr "  for (i = 0; i < r->len; ++i) {\n";
10227   pr "    jfl = (*env)->AllocObject (env, cl);\n";
10228   List.iter (
10229     function
10230     | name, FString ->
10231         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10232         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
10233     | name, FUUID ->
10234         pr "    {\n";
10235         pr "      char s[33];\n";
10236         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
10237         pr "      s[32] = 0;\n";
10238         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10239         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10240         pr "    }\n";
10241     | name, FBuffer ->
10242         pr "    {\n";
10243         pr "      int len = r->val[i].%s_len;\n" name;
10244         pr "      char s[len+1];\n";
10245         pr "      memcpy (s, r->val[i].%s, len);\n" name;
10246         pr "      s[len] = 0;\n";
10247         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10248         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10249         pr "    }\n";
10250     | name, (FBytes|FUInt64|FInt64) ->
10251         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10252         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10253     | name, (FUInt32|FInt32) ->
10254         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10255         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10256     | name, FOptPercent ->
10257         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10258         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
10259     | name, FChar ->
10260         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10261         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10262   ) cols;
10263   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
10264   pr "  }\n";
10265   pr "  guestfs_free_%s_list (r);\n" typ;
10266   pr "  return jr;\n"
10267
10268 and generate_java_makefile_inc () =
10269   generate_header HashStyle GPLv2plus;
10270
10271   pr "java_built_sources = \\\n";
10272   List.iter (
10273     fun (typ, jtyp) ->
10274         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
10275   ) java_structs;
10276   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
10277
10278 and generate_haskell_hs () =
10279   generate_header HaskellStyle LGPLv2plus;
10280
10281   (* XXX We only know how to generate partial FFI for Haskell
10282    * at the moment.  Please help out!
10283    *)
10284   let can_generate style =
10285     match style with
10286     | RErr, _
10287     | RInt _, _
10288     | RInt64 _, _ -> true
10289     | RBool _, _
10290     | RConstString _, _
10291     | RConstOptString _, _
10292     | RString _, _
10293     | RStringList _, _
10294     | RStruct _, _
10295     | RStructList _, _
10296     | RHashtable _, _
10297     | RBufferOut _, _ -> false in
10298
10299   pr "\
10300 {-# INCLUDE <guestfs.h> #-}
10301 {-# LANGUAGE ForeignFunctionInterface #-}
10302
10303 module Guestfs (
10304   create";
10305
10306   (* List out the names of the actions we want to export. *)
10307   List.iter (
10308     fun (name, style, _, _, _, _, _) ->
10309       if can_generate style then pr ",\n  %s" name
10310   ) all_functions;
10311
10312   pr "
10313   ) where
10314
10315 -- Unfortunately some symbols duplicate ones already present
10316 -- in Prelude.  We don't know which, so we hard-code a list
10317 -- here.
10318 import Prelude hiding (truncate)
10319
10320 import Foreign
10321 import Foreign.C
10322 import Foreign.C.Types
10323 import IO
10324 import Control.Exception
10325 import Data.Typeable
10326
10327 data GuestfsS = GuestfsS            -- represents the opaque C struct
10328 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
10329 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
10330
10331 -- XXX define properly later XXX
10332 data PV = PV
10333 data VG = VG
10334 data LV = LV
10335 data IntBool = IntBool
10336 data Stat = Stat
10337 data StatVFS = StatVFS
10338 data Hashtable = Hashtable
10339
10340 foreign import ccall unsafe \"guestfs_create\" c_create
10341   :: IO GuestfsP
10342 foreign import ccall unsafe \"&guestfs_close\" c_close
10343   :: FunPtr (GuestfsP -> IO ())
10344 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
10345   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
10346
10347 create :: IO GuestfsH
10348 create = do
10349   p <- c_create
10350   c_set_error_handler p nullPtr nullPtr
10351   h <- newForeignPtr c_close p
10352   return h
10353
10354 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
10355   :: GuestfsP -> IO CString
10356
10357 -- last_error :: GuestfsH -> IO (Maybe String)
10358 -- last_error h = do
10359 --   str <- withForeignPtr h (\\p -> c_last_error p)
10360 --   maybePeek peekCString str
10361
10362 last_error :: GuestfsH -> IO (String)
10363 last_error h = do
10364   str <- withForeignPtr h (\\p -> c_last_error p)
10365   if (str == nullPtr)
10366     then return \"no error\"
10367     else peekCString str
10368
10369 ";
10370
10371   (* Generate wrappers for each foreign function. *)
10372   List.iter (
10373     fun (name, style, _, _, _, _, _) ->
10374       if can_generate style then (
10375         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
10376         pr "  :: ";
10377         generate_haskell_prototype ~handle:"GuestfsP" style;
10378         pr "\n";
10379         pr "\n";
10380         pr "%s :: " name;
10381         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
10382         pr "\n";
10383         pr "%s %s = do\n" name
10384           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
10385         pr "  r <- ";
10386         (* Convert pointer arguments using with* functions. *)
10387         List.iter (
10388           function
10389           | FileIn n
10390           | FileOut n
10391           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
10392           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
10393           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
10394           | Bool _ | Int _ | Int64 _ -> ()
10395         ) (snd style);
10396         (* Convert integer arguments. *)
10397         let args =
10398           List.map (
10399             function
10400             | Bool n -> sprintf "(fromBool %s)" n
10401             | Int n -> sprintf "(fromIntegral %s)" n
10402             | Int64 n -> sprintf "(fromIntegral %s)" n
10403             | FileIn n | FileOut n
10404             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
10405           ) (snd style) in
10406         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
10407           (String.concat " " ("p" :: args));
10408         (match fst style with
10409          | RErr | RInt _ | RInt64 _ | RBool _ ->
10410              pr "  if (r == -1)\n";
10411              pr "    then do\n";
10412              pr "      err <- last_error h\n";
10413              pr "      fail err\n";
10414          | RConstString _ | RConstOptString _ | RString _
10415          | RStringList _ | RStruct _
10416          | RStructList _ | RHashtable _ | RBufferOut _ ->
10417              pr "  if (r == nullPtr)\n";
10418              pr "    then do\n";
10419              pr "      err <- last_error h\n";
10420              pr "      fail err\n";
10421         );
10422         (match fst style with
10423          | RErr ->
10424              pr "    else return ()\n"
10425          | RInt _ ->
10426              pr "    else return (fromIntegral r)\n"
10427          | RInt64 _ ->
10428              pr "    else return (fromIntegral r)\n"
10429          | RBool _ ->
10430              pr "    else return (toBool r)\n"
10431          | RConstString _
10432          | RConstOptString _
10433          | RString _
10434          | RStringList _
10435          | RStruct _
10436          | RStructList _
10437          | RHashtable _
10438          | RBufferOut _ ->
10439              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10440         );
10441         pr "\n";
10442       )
10443   ) all_functions
10444
10445 and generate_haskell_prototype ~handle ?(hs = false) style =
10446   pr "%s -> " handle;
10447   let string = if hs then "String" else "CString" in
10448   let int = if hs then "Int" else "CInt" in
10449   let bool = if hs then "Bool" else "CInt" in
10450   let int64 = if hs then "Integer" else "Int64" in
10451   List.iter (
10452     fun arg ->
10453       (match arg with
10454        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10455        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10456        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10457        | Bool _ -> pr "%s" bool
10458        | Int _ -> pr "%s" int
10459        | Int64 _ -> pr "%s" int
10460        | FileIn _ -> pr "%s" string
10461        | FileOut _ -> pr "%s" string
10462       );
10463       pr " -> ";
10464   ) (snd style);
10465   pr "IO (";
10466   (match fst style with
10467    | RErr -> if not hs then pr "CInt"
10468    | RInt _ -> pr "%s" int
10469    | RInt64 _ -> pr "%s" int64
10470    | RBool _ -> pr "%s" bool
10471    | RConstString _ -> pr "%s" string
10472    | RConstOptString _ -> pr "Maybe %s" string
10473    | RString _ -> pr "%s" string
10474    | RStringList _ -> pr "[%s]" string
10475    | RStruct (_, typ) ->
10476        let name = java_name_of_struct typ in
10477        pr "%s" name
10478    | RStructList (_, typ) ->
10479        let name = java_name_of_struct typ in
10480        pr "[%s]" name
10481    | RHashtable _ -> pr "Hashtable"
10482    | RBufferOut _ -> pr "%s" string
10483   );
10484   pr ")"
10485
10486 and generate_csharp () =
10487   generate_header CPlusPlusStyle LGPLv2plus;
10488
10489   (* XXX Make this configurable by the C# assembly users. *)
10490   let library = "libguestfs.so.0" in
10491
10492   pr "\
10493 // These C# bindings are highly experimental at present.
10494 //
10495 // Firstly they only work on Linux (ie. Mono).  In order to get them
10496 // to work on Windows (ie. .Net) you would need to port the library
10497 // itself to Windows first.
10498 //
10499 // The second issue is that some calls are known to be incorrect and
10500 // can cause Mono to segfault.  Particularly: calls which pass or
10501 // return string[], or return any structure value.  This is because
10502 // we haven't worked out the correct way to do this from C#.
10503 //
10504 // The third issue is that when compiling you get a lot of warnings.
10505 // We are not sure whether the warnings are important or not.
10506 //
10507 // Fourthly we do not routinely build or test these bindings as part
10508 // of the make && make check cycle, which means that regressions might
10509 // go unnoticed.
10510 //
10511 // Suggestions and patches are welcome.
10512
10513 // To compile:
10514 //
10515 // gmcs Libguestfs.cs
10516 // mono Libguestfs.exe
10517 //
10518 // (You'll probably want to add a Test class / static main function
10519 // otherwise this won't do anything useful).
10520
10521 using System;
10522 using System.IO;
10523 using System.Runtime.InteropServices;
10524 using System.Runtime.Serialization;
10525 using System.Collections;
10526
10527 namespace Guestfs
10528 {
10529   class Error : System.ApplicationException
10530   {
10531     public Error (string message) : base (message) {}
10532     protected Error (SerializationInfo info, StreamingContext context) {}
10533   }
10534
10535   class Guestfs
10536   {
10537     IntPtr _handle;
10538
10539     [DllImport (\"%s\")]
10540     static extern IntPtr guestfs_create ();
10541
10542     public Guestfs ()
10543     {
10544       _handle = guestfs_create ();
10545       if (_handle == IntPtr.Zero)
10546         throw new Error (\"could not create guestfs handle\");
10547     }
10548
10549     [DllImport (\"%s\")]
10550     static extern void guestfs_close (IntPtr h);
10551
10552     ~Guestfs ()
10553     {
10554       guestfs_close (_handle);
10555     }
10556
10557     [DllImport (\"%s\")]
10558     static extern string guestfs_last_error (IntPtr h);
10559
10560 " library library library;
10561
10562   (* Generate C# structure bindings.  We prefix struct names with
10563    * underscore because C# cannot have conflicting struct names and
10564    * method names (eg. "class stat" and "stat").
10565    *)
10566   List.iter (
10567     fun (typ, cols) ->
10568       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10569       pr "    public class _%s {\n" typ;
10570       List.iter (
10571         function
10572         | name, FChar -> pr "      char %s;\n" name
10573         | name, FString -> pr "      string %s;\n" name
10574         | name, FBuffer ->
10575             pr "      uint %s_len;\n" name;
10576             pr "      string %s;\n" name
10577         | name, FUUID ->
10578             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10579             pr "      string %s;\n" name
10580         | name, FUInt32 -> pr "      uint %s;\n" name
10581         | name, FInt32 -> pr "      int %s;\n" name
10582         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10583         | name, FInt64 -> pr "      long %s;\n" name
10584         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10585       ) cols;
10586       pr "    }\n";
10587       pr "\n"
10588   ) structs;
10589
10590   (* Generate C# function bindings. *)
10591   List.iter (
10592     fun (name, style, _, _, _, shortdesc, _) ->
10593       let rec csharp_return_type () =
10594         match fst style with
10595         | RErr -> "void"
10596         | RBool n -> "bool"
10597         | RInt n -> "int"
10598         | RInt64 n -> "long"
10599         | RConstString n
10600         | RConstOptString n
10601         | RString n
10602         | RBufferOut n -> "string"
10603         | RStruct (_,n) -> "_" ^ n
10604         | RHashtable n -> "Hashtable"
10605         | RStringList n -> "string[]"
10606         | RStructList (_,n) -> sprintf "_%s[]" n
10607
10608       and c_return_type () =
10609         match fst style with
10610         | RErr
10611         | RBool _
10612         | RInt _ -> "int"
10613         | RInt64 _ -> "long"
10614         | RConstString _
10615         | RConstOptString _
10616         | RString _
10617         | RBufferOut _ -> "string"
10618         | RStruct (_,n) -> "_" ^ n
10619         | RHashtable _
10620         | RStringList _ -> "string[]"
10621         | RStructList (_,n) -> sprintf "_%s[]" n
10622
10623       and c_error_comparison () =
10624         match fst style with
10625         | RErr
10626         | RBool _
10627         | RInt _
10628         | RInt64 _ -> "== -1"
10629         | RConstString _
10630         | RConstOptString _
10631         | RString _
10632         | RBufferOut _
10633         | RStruct (_,_)
10634         | RHashtable _
10635         | RStringList _
10636         | RStructList (_,_) -> "== null"
10637
10638       and generate_extern_prototype () =
10639         pr "    static extern %s guestfs_%s (IntPtr h"
10640           (c_return_type ()) name;
10641         List.iter (
10642           function
10643           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10644           | FileIn n | FileOut n ->
10645               pr ", [In] string %s" n
10646           | StringList n | DeviceList n ->
10647               pr ", [In] string[] %s" n
10648           | Bool n ->
10649               pr ", bool %s" n
10650           | Int n ->
10651               pr ", int %s" n
10652           | Int64 n ->
10653               pr ", long %s" n
10654         ) (snd style);
10655         pr ");\n"
10656
10657       and generate_public_prototype () =
10658         pr "    public %s %s (" (csharp_return_type ()) name;
10659         let comma = ref false in
10660         let next () =
10661           if !comma then pr ", ";
10662           comma := true
10663         in
10664         List.iter (
10665           function
10666           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10667           | FileIn n | FileOut n ->
10668               next (); pr "string %s" n
10669           | StringList n | DeviceList n ->
10670               next (); pr "string[] %s" n
10671           | Bool n ->
10672               next (); pr "bool %s" n
10673           | Int n ->
10674               next (); pr "int %s" n
10675           | Int64 n ->
10676               next (); pr "long %s" n
10677         ) (snd style);
10678         pr ")\n"
10679
10680       and generate_call () =
10681         pr "guestfs_%s (_handle" name;
10682         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10683         pr ");\n";
10684       in
10685
10686       pr "    [DllImport (\"%s\")]\n" library;
10687       generate_extern_prototype ();
10688       pr "\n";
10689       pr "    /// <summary>\n";
10690       pr "    /// %s\n" shortdesc;
10691       pr "    /// </summary>\n";
10692       generate_public_prototype ();
10693       pr "    {\n";
10694       pr "      %s r;\n" (c_return_type ());
10695       pr "      r = ";
10696       generate_call ();
10697       pr "      if (r %s)\n" (c_error_comparison ());
10698       pr "        throw new Error (guestfs_last_error (_handle));\n";
10699       (match fst style with
10700        | RErr -> ()
10701        | RBool _ ->
10702            pr "      return r != 0 ? true : false;\n"
10703        | RHashtable _ ->
10704            pr "      Hashtable rr = new Hashtable ();\n";
10705            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10706            pr "        rr.Add (r[i], r[i+1]);\n";
10707            pr "      return rr;\n"
10708        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10709        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10710        | RStructList _ ->
10711            pr "      return r;\n"
10712       );
10713       pr "    }\n";
10714       pr "\n";
10715   ) all_functions_sorted;
10716
10717   pr "  }
10718 }
10719 "
10720
10721 and generate_bindtests () =
10722   generate_header CStyle LGPLv2plus;
10723
10724   pr "\
10725 #include <stdio.h>
10726 #include <stdlib.h>
10727 #include <inttypes.h>
10728 #include <string.h>
10729
10730 #include \"guestfs.h\"
10731 #include \"guestfs-internal.h\"
10732 #include \"guestfs-internal-actions.h\"
10733 #include \"guestfs_protocol.h\"
10734
10735 #define error guestfs_error
10736 #define safe_calloc guestfs_safe_calloc
10737 #define safe_malloc guestfs_safe_malloc
10738
10739 static void
10740 print_strings (char *const *argv)
10741 {
10742   int argc;
10743
10744   printf (\"[\");
10745   for (argc = 0; argv[argc] != NULL; ++argc) {
10746     if (argc > 0) printf (\", \");
10747     printf (\"\\\"%%s\\\"\", argv[argc]);
10748   }
10749   printf (\"]\\n\");
10750 }
10751
10752 /* The test0 function prints its parameters to stdout. */
10753 ";
10754
10755   let test0, tests =
10756     match test_functions with
10757     | [] -> assert false
10758     | test0 :: tests -> test0, tests in
10759
10760   let () =
10761     let (name, style, _, _, _, _, _) = test0 in
10762     generate_prototype ~extern:false ~semicolon:false ~newline:true
10763       ~handle:"g" ~prefix:"guestfs__" name style;
10764     pr "{\n";
10765     List.iter (
10766       function
10767       | Pathname n
10768       | Device n | Dev_or_Path n
10769       | String n
10770       | FileIn n
10771       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10772       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10773       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10774       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10775       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10776       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10777     ) (snd style);
10778     pr "  /* Java changes stdout line buffering so we need this: */\n";
10779     pr "  fflush (stdout);\n";
10780     pr "  return 0;\n";
10781     pr "}\n";
10782     pr "\n" in
10783
10784   List.iter (
10785     fun (name, style, _, _, _, _, _) ->
10786       if String.sub name (String.length name - 3) 3 <> "err" then (
10787         pr "/* Test normal return. */\n";
10788         generate_prototype ~extern:false ~semicolon:false ~newline:true
10789           ~handle:"g" ~prefix:"guestfs__" name style;
10790         pr "{\n";
10791         (match fst style with
10792          | RErr ->
10793              pr "  return 0;\n"
10794          | RInt _ ->
10795              pr "  int r;\n";
10796              pr "  sscanf (val, \"%%d\", &r);\n";
10797              pr "  return r;\n"
10798          | RInt64 _ ->
10799              pr "  int64_t r;\n";
10800              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10801              pr "  return r;\n"
10802          | RBool _ ->
10803              pr "  return STREQ (val, \"true\");\n"
10804          | RConstString _
10805          | RConstOptString _ ->
10806              (* Can't return the input string here.  Return a static
10807               * string so we ensure we get a segfault if the caller
10808               * tries to free it.
10809               *)
10810              pr "  return \"static string\";\n"
10811          | RString _ ->
10812              pr "  return strdup (val);\n"
10813          | RStringList _ ->
10814              pr "  char **strs;\n";
10815              pr "  int n, i;\n";
10816              pr "  sscanf (val, \"%%d\", &n);\n";
10817              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10818              pr "  for (i = 0; i < n; ++i) {\n";
10819              pr "    strs[i] = safe_malloc (g, 16);\n";
10820              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10821              pr "  }\n";
10822              pr "  strs[n] = NULL;\n";
10823              pr "  return strs;\n"
10824          | RStruct (_, typ) ->
10825              pr "  struct guestfs_%s *r;\n" typ;
10826              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10827              pr "  return r;\n"
10828          | RStructList (_, typ) ->
10829              pr "  struct guestfs_%s_list *r;\n" typ;
10830              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10831              pr "  sscanf (val, \"%%d\", &r->len);\n";
10832              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10833              pr "  return r;\n"
10834          | RHashtable _ ->
10835              pr "  char **strs;\n";
10836              pr "  int n, i;\n";
10837              pr "  sscanf (val, \"%%d\", &n);\n";
10838              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10839              pr "  for (i = 0; i < n; ++i) {\n";
10840              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10841              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10842              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10843              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10844              pr "  }\n";
10845              pr "  strs[n*2] = NULL;\n";
10846              pr "  return strs;\n"
10847          | RBufferOut _ ->
10848              pr "  return strdup (val);\n"
10849         );
10850         pr "}\n";
10851         pr "\n"
10852       ) else (
10853         pr "/* Test error return. */\n";
10854         generate_prototype ~extern:false ~semicolon:false ~newline:true
10855           ~handle:"g" ~prefix:"guestfs__" name style;
10856         pr "{\n";
10857         pr "  error (g, \"error\");\n";
10858         (match fst style with
10859          | RErr | RInt _ | RInt64 _ | RBool _ ->
10860              pr "  return -1;\n"
10861          | RConstString _ | RConstOptString _
10862          | RString _ | RStringList _ | RStruct _
10863          | RStructList _
10864          | RHashtable _
10865          | RBufferOut _ ->
10866              pr "  return NULL;\n"
10867         );
10868         pr "}\n";
10869         pr "\n"
10870       )
10871   ) tests
10872
10873 and generate_ocaml_bindtests () =
10874   generate_header OCamlStyle GPLv2plus;
10875
10876   pr "\
10877 let () =
10878   let g = Guestfs.create () in
10879 ";
10880
10881   let mkargs args =
10882     String.concat " " (
10883       List.map (
10884         function
10885         | CallString s -> "\"" ^ s ^ "\""
10886         | CallOptString None -> "None"
10887         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10888         | CallStringList xs ->
10889             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10890         | CallInt i when i >= 0 -> string_of_int i
10891         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10892         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10893         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10894         | CallBool b -> string_of_bool b
10895       ) args
10896     )
10897   in
10898
10899   generate_lang_bindtests (
10900     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10901   );
10902
10903   pr "print_endline \"EOF\"\n"
10904
10905 and generate_perl_bindtests () =
10906   pr "#!/usr/bin/perl -w\n";
10907   generate_header HashStyle GPLv2plus;
10908
10909   pr "\
10910 use strict;
10911
10912 use Sys::Guestfs;
10913
10914 my $g = Sys::Guestfs->new ();
10915 ";
10916
10917   let mkargs args =
10918     String.concat ", " (
10919       List.map (
10920         function
10921         | CallString s -> "\"" ^ s ^ "\""
10922         | CallOptString None -> "undef"
10923         | CallOptString (Some s) -> sprintf "\"%s\"" s
10924         | CallStringList xs ->
10925             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10926         | CallInt i -> string_of_int i
10927         | CallInt64 i -> Int64.to_string i
10928         | CallBool b -> if b then "1" else "0"
10929       ) args
10930     )
10931   in
10932
10933   generate_lang_bindtests (
10934     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10935   );
10936
10937   pr "print \"EOF\\n\"\n"
10938
10939 and generate_python_bindtests () =
10940   generate_header HashStyle GPLv2plus;
10941
10942   pr "\
10943 import guestfs
10944
10945 g = guestfs.GuestFS ()
10946 ";
10947
10948   let mkargs args =
10949     String.concat ", " (
10950       List.map (
10951         function
10952         | CallString s -> "\"" ^ s ^ "\""
10953         | CallOptString None -> "None"
10954         | CallOptString (Some s) -> sprintf "\"%s\"" s
10955         | CallStringList xs ->
10956             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10957         | CallInt i -> string_of_int i
10958         | CallInt64 i -> Int64.to_string i
10959         | CallBool b -> if b then "1" else "0"
10960       ) args
10961     )
10962   in
10963
10964   generate_lang_bindtests (
10965     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10966   );
10967
10968   pr "print \"EOF\"\n"
10969
10970 and generate_ruby_bindtests () =
10971   generate_header HashStyle GPLv2plus;
10972
10973   pr "\
10974 require 'guestfs'
10975
10976 g = Guestfs::create()
10977 ";
10978
10979   let mkargs args =
10980     String.concat ", " (
10981       List.map (
10982         function
10983         | CallString s -> "\"" ^ s ^ "\""
10984         | CallOptString None -> "nil"
10985         | CallOptString (Some s) -> sprintf "\"%s\"" s
10986         | CallStringList xs ->
10987             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10988         | CallInt i -> string_of_int i
10989         | CallInt64 i -> Int64.to_string i
10990         | CallBool b -> string_of_bool b
10991       ) args
10992     )
10993   in
10994
10995   generate_lang_bindtests (
10996     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10997   );
10998
10999   pr "print \"EOF\\n\"\n"
11000
11001 and generate_java_bindtests () =
11002   generate_header CStyle GPLv2plus;
11003
11004   pr "\
11005 import com.redhat.et.libguestfs.*;
11006
11007 public class Bindtests {
11008     public static void main (String[] argv)
11009     {
11010         try {
11011             GuestFS g = new GuestFS ();
11012 ";
11013
11014   let mkargs args =
11015     String.concat ", " (
11016       List.map (
11017         function
11018         | CallString s -> "\"" ^ s ^ "\""
11019         | CallOptString None -> "null"
11020         | CallOptString (Some s) -> sprintf "\"%s\"" s
11021         | CallStringList xs ->
11022             "new String[]{" ^
11023               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
11024         | CallInt i -> string_of_int i
11025         | CallInt64 i -> Int64.to_string i
11026         | CallBool b -> string_of_bool b
11027       ) args
11028     )
11029   in
11030
11031   generate_lang_bindtests (
11032     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
11033   );
11034
11035   pr "
11036             System.out.println (\"EOF\");
11037         }
11038         catch (Exception exn) {
11039             System.err.println (exn);
11040             System.exit (1);
11041         }
11042     }
11043 }
11044 "
11045
11046 and generate_haskell_bindtests () =
11047   generate_header HaskellStyle GPLv2plus;
11048
11049   pr "\
11050 module Bindtests where
11051 import qualified Guestfs
11052
11053 main = do
11054   g <- Guestfs.create
11055 ";
11056
11057   let mkargs args =
11058     String.concat " " (
11059       List.map (
11060         function
11061         | CallString s -> "\"" ^ s ^ "\""
11062         | CallOptString None -> "Nothing"
11063         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
11064         | CallStringList xs ->
11065             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11066         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
11067         | CallInt i -> string_of_int i
11068         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
11069         | CallInt64 i -> Int64.to_string i
11070         | CallBool true -> "True"
11071         | CallBool false -> "False"
11072       ) args
11073     )
11074   in
11075
11076   generate_lang_bindtests (
11077     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
11078   );
11079
11080   pr "  putStrLn \"EOF\"\n"
11081
11082 (* Language-independent bindings tests - we do it this way to
11083  * ensure there is parity in testing bindings across all languages.
11084  *)
11085 and generate_lang_bindtests call =
11086   call "test0" [CallString "abc"; CallOptString (Some "def");
11087                 CallStringList []; CallBool false;
11088                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11089   call "test0" [CallString "abc"; CallOptString None;
11090                 CallStringList []; CallBool false;
11091                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11092   call "test0" [CallString ""; CallOptString (Some "def");
11093                 CallStringList []; CallBool false;
11094                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11095   call "test0" [CallString ""; CallOptString (Some "");
11096                 CallStringList []; CallBool false;
11097                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11098   call "test0" [CallString "abc"; CallOptString (Some "def");
11099                 CallStringList ["1"]; CallBool false;
11100                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11101   call "test0" [CallString "abc"; CallOptString (Some "def");
11102                 CallStringList ["1"; "2"]; CallBool false;
11103                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11104   call "test0" [CallString "abc"; CallOptString (Some "def");
11105                 CallStringList ["1"]; CallBool true;
11106                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11107   call "test0" [CallString "abc"; CallOptString (Some "def");
11108                 CallStringList ["1"]; CallBool false;
11109                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
11110   call "test0" [CallString "abc"; CallOptString (Some "def");
11111                 CallStringList ["1"]; CallBool false;
11112                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
11113   call "test0" [CallString "abc"; CallOptString (Some "def");
11114                 CallStringList ["1"]; CallBool false;
11115                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
11116   call "test0" [CallString "abc"; CallOptString (Some "def");
11117                 CallStringList ["1"]; CallBool false;
11118                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
11119   call "test0" [CallString "abc"; CallOptString (Some "def");
11120                 CallStringList ["1"]; CallBool false;
11121                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
11122   call "test0" [CallString "abc"; CallOptString (Some "def");
11123                 CallStringList ["1"]; CallBool false;
11124                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
11125
11126 (* XXX Add here tests of the return and error functions. *)
11127
11128 (* Code to generator bindings for virt-inspector.  Currently only
11129  * implemented for OCaml code (for virt-p2v 2.0).
11130  *)
11131 let rng_input = "inspector/virt-inspector.rng"
11132
11133 (* Read the input file and parse it into internal structures.  This is
11134  * by no means a complete RELAX NG parser, but is just enough to be
11135  * able to parse the specific input file.
11136  *)
11137 type rng =
11138   | Element of string * rng list        (* <element name=name/> *)
11139   | Attribute of string * rng list        (* <attribute name=name/> *)
11140   | Interleave of rng list                (* <interleave/> *)
11141   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
11142   | OneOrMore of rng                        (* <oneOrMore/> *)
11143   | Optional of rng                        (* <optional/> *)
11144   | Choice of string list                (* <choice><value/>*</choice> *)
11145   | Value of string                        (* <value>str</value> *)
11146   | Text                                (* <text/> *)
11147
11148 let rec string_of_rng = function
11149   | Element (name, xs) ->
11150       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11151   | Attribute (name, xs) ->
11152       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11153   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
11154   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
11155   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
11156   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
11157   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
11158   | Value value -> "Value \"" ^ value ^ "\""
11159   | Text -> "Text"
11160
11161 and string_of_rng_list xs =
11162   String.concat ", " (List.map string_of_rng xs)
11163
11164 let rec parse_rng ?defines context = function
11165   | [] -> []
11166   | Xml.Element ("element", ["name", name], children) :: rest ->
11167       Element (name, parse_rng ?defines context children)
11168       :: parse_rng ?defines context rest
11169   | Xml.Element ("attribute", ["name", name], children) :: rest ->
11170       Attribute (name, parse_rng ?defines context children)
11171       :: parse_rng ?defines context rest
11172   | Xml.Element ("interleave", [], children) :: rest ->
11173       Interleave (parse_rng ?defines context children)
11174       :: parse_rng ?defines context rest
11175   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
11176       let rng = parse_rng ?defines context [child] in
11177       (match rng with
11178        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
11179        | _ ->
11180            failwithf "%s: <zeroOrMore> contains more than one child element"
11181              context
11182       )
11183   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
11184       let rng = parse_rng ?defines context [child] in
11185       (match rng with
11186        | [child] -> OneOrMore child :: parse_rng ?defines context rest
11187        | _ ->
11188            failwithf "%s: <oneOrMore> contains more than one child element"
11189              context
11190       )
11191   | Xml.Element ("optional", [], [child]) :: rest ->
11192       let rng = parse_rng ?defines context [child] in
11193       (match rng with
11194        | [child] -> Optional child :: parse_rng ?defines context rest
11195        | _ ->
11196            failwithf "%s: <optional> contains more than one child element"
11197              context
11198       )
11199   | Xml.Element ("choice", [], children) :: rest ->
11200       let values = List.map (
11201         function Xml.Element ("value", [], [Xml.PCData value]) -> value
11202         | _ ->
11203             failwithf "%s: can't handle anything except <value> in <choice>"
11204               context
11205       ) children in
11206       Choice values
11207       :: parse_rng ?defines context rest
11208   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
11209       Value value :: parse_rng ?defines context rest
11210   | Xml.Element ("text", [], []) :: rest ->
11211       Text :: parse_rng ?defines context rest
11212   | Xml.Element ("ref", ["name", name], []) :: rest ->
11213       (* Look up the reference.  Because of limitations in this parser,
11214        * we can't handle arbitrarily nested <ref> yet.  You can only
11215        * use <ref> from inside <start>.
11216        *)
11217       (match defines with
11218        | None ->
11219            failwithf "%s: contains <ref>, but no refs are defined yet" context
11220        | Some map ->
11221            let rng = StringMap.find name map in
11222            rng @ parse_rng ?defines context rest
11223       )
11224   | x :: _ ->
11225       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
11226
11227 let grammar =
11228   let xml = Xml.parse_file rng_input in
11229   match xml with
11230   | Xml.Element ("grammar", _,
11231                  Xml.Element ("start", _, gram) :: defines) ->
11232       (* The <define/> elements are referenced in the <start> section,
11233        * so build a map of those first.
11234        *)
11235       let defines = List.fold_left (
11236         fun map ->
11237           function Xml.Element ("define", ["name", name], defn) ->
11238             StringMap.add name defn map
11239           | _ ->
11240               failwithf "%s: expected <define name=name/>" rng_input
11241       ) StringMap.empty defines in
11242       let defines = StringMap.mapi parse_rng defines in
11243
11244       (* Parse the <start> clause, passing the defines. *)
11245       parse_rng ~defines "<start>" gram
11246   | _ ->
11247       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
11248         rng_input
11249
11250 let name_of_field = function
11251   | Element (name, _) | Attribute (name, _)
11252   | ZeroOrMore (Element (name, _))
11253   | OneOrMore (Element (name, _))
11254   | Optional (Element (name, _)) -> name
11255   | Optional (Attribute (name, _)) -> name
11256   | Text -> (* an unnamed field in an element *)
11257       "data"
11258   | rng ->
11259       failwithf "name_of_field failed at: %s" (string_of_rng rng)
11260
11261 (* At the moment this function only generates OCaml types.  However we
11262  * should parameterize it later so it can generate types/structs in a
11263  * variety of languages.
11264  *)
11265 let generate_types xs =
11266   (* A simple type is one that can be printed out directly, eg.
11267    * "string option".  A complex type is one which has a name and has
11268    * to be defined via another toplevel definition, eg. a struct.
11269    *
11270    * generate_type generates code for either simple or complex types.
11271    * In the simple case, it returns the string ("string option").  In
11272    * the complex case, it returns the name ("mountpoint").  In the
11273    * complex case it has to print out the definition before returning,
11274    * so it should only be called when we are at the beginning of a
11275    * new line (BOL context).
11276    *)
11277   let rec generate_type = function
11278     | Text ->                                (* string *)
11279         "string", true
11280     | Choice values ->                        (* [`val1|`val2|...] *)
11281         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
11282     | ZeroOrMore rng ->                        (* <rng> list *)
11283         let t, is_simple = generate_type rng in
11284         t ^ " list (* 0 or more *)", is_simple
11285     | OneOrMore rng ->                        (* <rng> list *)
11286         let t, is_simple = generate_type rng in
11287         t ^ " list (* 1 or more *)", is_simple
11288                                         (* virt-inspector hack: bool *)
11289     | Optional (Attribute (name, [Value "1"])) ->
11290         "bool", true
11291     | Optional rng ->                        (* <rng> list *)
11292         let t, is_simple = generate_type rng in
11293         t ^ " option", is_simple
11294                                         (* type name = { fields ... } *)
11295     | Element (name, fields) when is_attrs_interleave fields ->
11296         generate_type_struct name (get_attrs_interleave fields)
11297     | Element (name, [field])                (* type name = field *)
11298     | Attribute (name, [field]) ->
11299         let t, is_simple = generate_type field in
11300         if is_simple then (t, true)
11301         else (
11302           pr "type %s = %s\n" name t;
11303           name, false
11304         )
11305     | Element (name, fields) ->              (* type name = { fields ... } *)
11306         generate_type_struct name fields
11307     | rng ->
11308         failwithf "generate_type failed at: %s" (string_of_rng rng)
11309
11310   and is_attrs_interleave = function
11311     | [Interleave _] -> true
11312     | Attribute _ :: fields -> is_attrs_interleave fields
11313     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11314     | _ -> false
11315
11316   and get_attrs_interleave = function
11317     | [Interleave fields] -> fields
11318     | ((Attribute _) as field) :: fields
11319     | ((Optional (Attribute _)) as field) :: fields ->
11320         field :: get_attrs_interleave fields
11321     | _ -> assert false
11322
11323   and generate_types xs =
11324     List.iter (fun x -> ignore (generate_type x)) xs
11325
11326   and generate_type_struct name fields =
11327     (* Calculate the types of the fields first.  We have to do this
11328      * before printing anything so we are still in BOL context.
11329      *)
11330     let types = List.map fst (List.map generate_type fields) in
11331
11332     (* Special case of a struct containing just a string and another
11333      * field.  Turn it into an assoc list.
11334      *)
11335     match types with
11336     | ["string"; other] ->
11337         let fname1, fname2 =
11338           match fields with
11339           | [f1; f2] -> name_of_field f1, name_of_field f2
11340           | _ -> assert false in
11341         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
11342         name, false
11343
11344     | types ->
11345         pr "type %s = {\n" name;
11346         List.iter (
11347           fun (field, ftype) ->
11348             let fname = name_of_field field in
11349             pr "  %s_%s : %s;\n" name fname ftype
11350         ) (List.combine fields types);
11351         pr "}\n";
11352         (* Return the name of this type, and
11353          * false because it's not a simple type.
11354          *)
11355         name, false
11356   in
11357
11358   generate_types xs
11359
11360 let generate_parsers xs =
11361   (* As for generate_type above, generate_parser makes a parser for
11362    * some type, and returns the name of the parser it has generated.
11363    * Because it (may) need to print something, it should always be
11364    * called in BOL context.
11365    *)
11366   let rec generate_parser = function
11367     | Text ->                                (* string *)
11368         "string_child_or_empty"
11369     | Choice values ->                        (* [`val1|`val2|...] *)
11370         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
11371           (String.concat "|"
11372              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
11373     | ZeroOrMore rng ->                        (* <rng> list *)
11374         let pa = generate_parser rng in
11375         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11376     | OneOrMore rng ->                        (* <rng> list *)
11377         let pa = generate_parser rng in
11378         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11379                                         (* virt-inspector hack: bool *)
11380     | Optional (Attribute (name, [Value "1"])) ->
11381         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
11382     | Optional rng ->                        (* <rng> list *)
11383         let pa = generate_parser rng in
11384         sprintf "(function None -> None | Some x -> Some (%s x))" pa
11385                                         (* type name = { fields ... } *)
11386     | Element (name, fields) when is_attrs_interleave fields ->
11387         generate_parser_struct name (get_attrs_interleave fields)
11388     | Element (name, [field]) ->        (* type name = field *)
11389         let pa = generate_parser field in
11390         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11391         pr "let %s =\n" parser_name;
11392         pr "  %s\n" pa;
11393         pr "let parse_%s = %s\n" name parser_name;
11394         parser_name
11395     | Attribute (name, [field]) ->
11396         let pa = generate_parser field in
11397         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11398         pr "let %s =\n" parser_name;
11399         pr "  %s\n" pa;
11400         pr "let parse_%s = %s\n" name parser_name;
11401         parser_name
11402     | Element (name, fields) ->              (* type name = { fields ... } *)
11403         generate_parser_struct name ([], fields)
11404     | rng ->
11405         failwithf "generate_parser failed at: %s" (string_of_rng rng)
11406
11407   and is_attrs_interleave = function
11408     | [Interleave _] -> true
11409     | Attribute _ :: fields -> is_attrs_interleave fields
11410     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11411     | _ -> false
11412
11413   and get_attrs_interleave = function
11414     | [Interleave fields] -> [], fields
11415     | ((Attribute _) as field) :: fields
11416     | ((Optional (Attribute _)) as field) :: fields ->
11417         let attrs, interleaves = get_attrs_interleave fields in
11418         (field :: attrs), interleaves
11419     | _ -> assert false
11420
11421   and generate_parsers xs =
11422     List.iter (fun x -> ignore (generate_parser x)) xs
11423
11424   and generate_parser_struct name (attrs, interleaves) =
11425     (* Generate parsers for the fields first.  We have to do this
11426      * before printing anything so we are still in BOL context.
11427      *)
11428     let fields = attrs @ interleaves in
11429     let pas = List.map generate_parser fields in
11430
11431     (* Generate an intermediate tuple from all the fields first.
11432      * If the type is just a string + another field, then we will
11433      * return this directly, otherwise it is turned into a record.
11434      *
11435      * RELAX NG note: This code treats <interleave> and plain lists of
11436      * fields the same.  In other words, it doesn't bother enforcing
11437      * any ordering of fields in the XML.
11438      *)
11439     pr "let parse_%s x =\n" name;
11440     pr "  let t = (\n    ";
11441     let comma = ref false in
11442     List.iter (
11443       fun x ->
11444         if !comma then pr ",\n    ";
11445         comma := true;
11446         match x with
11447         | Optional (Attribute (fname, [field])), pa ->
11448             pr "%s x" pa
11449         | Optional (Element (fname, [field])), pa ->
11450             pr "%s (optional_child %S x)" pa fname
11451         | Attribute (fname, [Text]), _ ->
11452             pr "attribute %S x" fname
11453         | (ZeroOrMore _ | OneOrMore _), pa ->
11454             pr "%s x" pa
11455         | Text, pa ->
11456             pr "%s x" pa
11457         | (field, pa) ->
11458             let fname = name_of_field field in
11459             pr "%s (child %S x)" pa fname
11460     ) (List.combine fields pas);
11461     pr "\n  ) in\n";
11462
11463     (match fields with
11464      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11465          pr "  t\n"
11466
11467      | _ ->
11468          pr "  (Obj.magic t : %s)\n" name
11469 (*
11470          List.iter (
11471            function
11472            | (Optional (Attribute (fname, [field])), pa) ->
11473                pr "  %s_%s =\n" name fname;
11474                pr "    %s x;\n" pa
11475            | (Optional (Element (fname, [field])), pa) ->
11476                pr "  %s_%s =\n" name fname;
11477                pr "    (let x = optional_child %S x in\n" fname;
11478                pr "     %s x);\n" pa
11479            | (field, pa) ->
11480                let fname = name_of_field field in
11481                pr "  %s_%s =\n" name fname;
11482                pr "    (let x = child %S x in\n" fname;
11483                pr "     %s x);\n" pa
11484          ) (List.combine fields pas);
11485          pr "}\n"
11486 *)
11487     );
11488     sprintf "parse_%s" name
11489   in
11490
11491   generate_parsers xs
11492
11493 (* Generate ocaml/guestfs_inspector.mli. *)
11494 let generate_ocaml_inspector_mli () =
11495   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11496
11497   pr "\
11498 (** This is an OCaml language binding to the external [virt-inspector]
11499     program.
11500
11501     For more information, please read the man page [virt-inspector(1)].
11502 *)
11503
11504 ";
11505
11506   generate_types grammar;
11507   pr "(** The nested information returned from the {!inspect} function. *)\n";
11508   pr "\n";
11509
11510   pr "\
11511 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11512 (** To inspect a libvirt domain called [name], pass a singleton
11513     list: [inspect [name]].  When using libvirt only, you may
11514     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11515
11516     To inspect a disk image or images, pass a list of the filenames
11517     of the disk images: [inspect filenames]
11518
11519     This function inspects the given guest or disk images and
11520     returns a list of operating system(s) found and a large amount
11521     of information about them.  In the vast majority of cases,
11522     a virtual machine only contains a single operating system.
11523
11524     If the optional [~xml] parameter is given, then this function
11525     skips running the external virt-inspector program and just
11526     parses the given XML directly (which is expected to be XML
11527     produced from a previous run of virt-inspector).  The list of
11528     names and connect URI are ignored in this case.
11529
11530     This function can throw a wide variety of exceptions, for example
11531     if the external virt-inspector program cannot be found, or if
11532     it doesn't generate valid XML.
11533 *)
11534 "
11535
11536 (* Generate ocaml/guestfs_inspector.ml. *)
11537 let generate_ocaml_inspector_ml () =
11538   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11539
11540   pr "open Unix\n";
11541   pr "\n";
11542
11543   generate_types grammar;
11544   pr "\n";
11545
11546   pr "\
11547 (* Misc functions which are used by the parser code below. *)
11548 let first_child = function
11549   | Xml.Element (_, _, c::_) -> c
11550   | Xml.Element (name, _, []) ->
11551       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11552   | Xml.PCData str ->
11553       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11554
11555 let string_child_or_empty = function
11556   | Xml.Element (_, _, [Xml.PCData s]) -> s
11557   | Xml.Element (_, _, []) -> \"\"
11558   | Xml.Element (x, _, _) ->
11559       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11560                 x ^ \" instead\")
11561   | Xml.PCData str ->
11562       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11563
11564 let optional_child name xml =
11565   let children = Xml.children xml in
11566   try
11567     Some (List.find (function
11568                      | Xml.Element (n, _, _) when n = name -> true
11569                      | _ -> false) children)
11570   with
11571     Not_found -> None
11572
11573 let child name xml =
11574   match optional_child name xml with
11575   | Some c -> c
11576   | None ->
11577       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11578
11579 let attribute name xml =
11580   try Xml.attrib xml name
11581   with Xml.No_attribute _ ->
11582     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11583
11584 ";
11585
11586   generate_parsers grammar;
11587   pr "\n";
11588
11589   pr "\
11590 (* Run external virt-inspector, then use parser to parse the XML. *)
11591 let inspect ?connect ?xml names =
11592   let xml =
11593     match xml with
11594     | None ->
11595         if names = [] then invalid_arg \"inspect: no names given\";
11596         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11597           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11598           names in
11599         let cmd = List.map Filename.quote cmd in
11600         let cmd = String.concat \" \" cmd in
11601         let chan = open_process_in cmd in
11602         let xml = Xml.parse_in chan in
11603         (match close_process_in chan with
11604          | WEXITED 0 -> ()
11605          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11606          | WSIGNALED i | WSTOPPED i ->
11607              failwith (\"external virt-inspector command died or stopped on sig \" ^
11608                        string_of_int i)
11609         );
11610         xml
11611     | Some doc ->
11612         Xml.parse_string doc in
11613   parse_operatingsystems xml
11614 "
11615
11616 (* This is used to generate the src/MAX_PROC_NR file which
11617  * contains the maximum procedure number, a surrogate for the
11618  * ABI version number.  See src/Makefile.am for the details.
11619  *)
11620 and generate_max_proc_nr () =
11621   let proc_nrs = List.map (
11622     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11623   ) daemon_functions in
11624
11625   let max_proc_nr = List.fold_left max 0 proc_nrs in
11626
11627   pr "%d\n" max_proc_nr
11628
11629 let output_to filename k =
11630   let filename_new = filename ^ ".new" in
11631   chan := open_out filename_new;
11632   k ();
11633   close_out !chan;
11634   chan := Pervasives.stdout;
11635
11636   (* Is the new file different from the current file? *)
11637   if Sys.file_exists filename && files_equal filename filename_new then
11638     unlink filename_new                 (* same, so skip it *)
11639   else (
11640     (* different, overwrite old one *)
11641     (try chmod filename 0o644 with Unix_error _ -> ());
11642     rename filename_new filename;
11643     chmod filename 0o444;
11644     printf "written %s\n%!" filename;
11645   )
11646
11647 let perror msg = function
11648   | Unix_error (err, _, _) ->
11649       eprintf "%s: %s\n" msg (error_message err)
11650   | exn ->
11651       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11652
11653 (* Main program. *)
11654 let () =
11655   let lock_fd =
11656     try openfile "HACKING" [O_RDWR] 0
11657     with
11658     | Unix_error (ENOENT, _, _) ->
11659         eprintf "\
11660 You are probably running this from the wrong directory.
11661 Run it from the top source directory using the command
11662   src/generator.ml
11663 ";
11664         exit 1
11665     | exn ->
11666         perror "open: HACKING" exn;
11667         exit 1 in
11668
11669   (* Acquire a lock so parallel builds won't try to run the generator
11670    * twice at the same time.  Subsequent builds will wait for the first
11671    * one to finish.  Note the lock is released implicitly when the
11672    * program exits.
11673    *)
11674   (try lockf lock_fd F_LOCK 1
11675    with exn ->
11676      perror "lock: HACKING" exn;
11677      exit 1);
11678
11679   check_functions ();
11680
11681   output_to "src/guestfs_protocol.x" generate_xdr;
11682   output_to "src/guestfs-structs.h" generate_structs_h;
11683   output_to "src/guestfs-actions.h" generate_actions_h;
11684   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11685   output_to "src/guestfs-actions.c" generate_client_actions;
11686   output_to "src/guestfs-bindtests.c" generate_bindtests;
11687   output_to "src/guestfs-structs.pod" generate_structs_pod;
11688   output_to "src/guestfs-actions.pod" generate_actions_pod;
11689   output_to "src/guestfs-availability.pod" generate_availability_pod;
11690   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11691   output_to "src/libguestfs.syms" generate_linker_script;
11692   output_to "daemon/actions.h" generate_daemon_actions_h;
11693   output_to "daemon/stubs.c" generate_daemon_actions;
11694   output_to "daemon/names.c" generate_daemon_names;
11695   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11696   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11697   output_to "capitests/tests.c" generate_tests;
11698   output_to "fish/cmds.c" generate_fish_cmds;
11699   output_to "fish/completion.c" generate_fish_completion;
11700   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11701   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11702   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11703   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11704   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11705   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11706   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11707   output_to "perl/Guestfs.xs" generate_perl_xs;
11708   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11709   output_to "perl/bindtests.pl" generate_perl_bindtests;
11710   output_to "python/guestfs-py.c" generate_python_c;
11711   output_to "python/guestfs.py" generate_python_py;
11712   output_to "python/bindtests.py" generate_python_bindtests;
11713   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11714   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11715   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11716
11717   List.iter (
11718     fun (typ, jtyp) ->
11719       let cols = cols_of_struct typ in
11720       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11721       output_to filename (generate_java_struct jtyp cols);
11722   ) java_structs;
11723
11724   output_to "java/Makefile.inc" generate_java_makefile_inc;
11725   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11726   output_to "java/Bindtests.java" generate_java_bindtests;
11727   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11728   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11729   output_to "csharp/Libguestfs.cs" generate_csharp;
11730
11731   (* Always generate this file last, and unconditionally.  It's used
11732    * by the Makefile to know when we must re-run the generator.
11733    *)
11734   let chan = open_out "src/stamp-generator" in
11735   fprintf chan "1\n";
11736   close_out chan;
11737
11738   printf "generated %d lines of code\n" !lines