daemon: Fix head and tail commands 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    "print the printable strings in a file",
2451    "\
2452 This runs the L<strings(1)> command on a file and returns
2453 the list of printable strings found.");
2454
2455   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2456    [InitISOFS, Always, TestOutputList (
2457       [["strings_e"; "b"; "/known-5"]], []);
2458     InitBasicFS, Disabled, TestOutputList (
2459       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2460        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2461    "print the printable strings in a file",
2462    "\
2463 This is like the C<guestfs_strings> command, but allows you to
2464 specify the encoding.
2465
2466 See the L<strings(1)> manpage for the full list of encodings.
2467
2468 Commonly useful encodings are C<l> (lower case L) which will
2469 show strings inside Windows/x86 files.
2470
2471 The returned strings are transcoded to UTF-8.");
2472
2473   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2474    [InitISOFS, Always, TestOutput (
2475       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2476     (* Test for RHBZ#501888c2 regression which caused large hexdump
2477      * commands to segfault.
2478      *)
2479     InitISOFS, Always, TestRun (
2480       [["hexdump"; "/100krandom"]]);
2481     (* Test for RHBZ#579608, absolute symbolic links. *)
2482     InitISOFS, Always, TestRun (
2483       [["hexdump"; "/abssymlink"]])],
2484    "dump a file in hexadecimal",
2485    "\
2486 This runs C<hexdump -C> on the given C<path>.  The result is
2487 the human-readable, canonical hex dump of the file.");
2488
2489   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2490    [InitNone, Always, TestOutput (
2491       [["part_disk"; "/dev/sda"; "mbr"];
2492        ["mkfs"; "ext3"; "/dev/sda1"];
2493        ["mount_options"; ""; "/dev/sda1"; "/"];
2494        ["write_file"; "/new"; "test file"; "0"];
2495        ["umount"; "/dev/sda1"];
2496        ["zerofree"; "/dev/sda1"];
2497        ["mount_options"; ""; "/dev/sda1"; "/"];
2498        ["cat"; "/new"]], "test file")],
2499    "zero unused inodes and disk blocks on ext2/3 filesystem",
2500    "\
2501 This runs the I<zerofree> program on C<device>.  This program
2502 claims to zero unused inodes and disk blocks on an ext2/3
2503 filesystem, thus making it possible to compress the filesystem
2504 more effectively.
2505
2506 You should B<not> run this program if the filesystem is
2507 mounted.
2508
2509 It is possible that using this program can damage the filesystem
2510 or data on the filesystem.");
2511
2512   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2513    [],
2514    "resize an LVM physical volume",
2515    "\
2516 This resizes (expands or shrinks) an existing LVM physical
2517 volume to match the new size of the underlying device.");
2518
2519   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2520                        Int "cyls"; Int "heads"; Int "sectors";
2521                        String "line"]), 99, [DangerWillRobinson],
2522    [],
2523    "modify a single partition on a block device",
2524    "\
2525 This runs L<sfdisk(8)> option to modify just the single
2526 partition C<n> (note: C<n> counts from 1).
2527
2528 For other parameters, see C<guestfs_sfdisk>.  You should usually
2529 pass C<0> for the cyls/heads/sectors parameters.
2530
2531 See also: C<guestfs_part_add>");
2532
2533   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2534    [],
2535    "display the partition table",
2536    "\
2537 This displays the partition table on C<device>, in the
2538 human-readable output of the L<sfdisk(8)> command.  It is
2539 not intended to be parsed.
2540
2541 See also: C<guestfs_part_list>");
2542
2543   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2544    [],
2545    "display the kernel geometry",
2546    "\
2547 This displays the kernel's idea of the geometry of C<device>.
2548
2549 The result is in human-readable format, and not designed to
2550 be parsed.");
2551
2552   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2553    [],
2554    "display the disk geometry from the partition table",
2555    "\
2556 This displays the disk geometry of C<device> read from the
2557 partition table.  Especially in the case where the underlying
2558 block device has been resized, this can be different from the
2559 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2560
2561 The result is in human-readable format, and not designed to
2562 be parsed.");
2563
2564   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2565    [],
2566    "activate or deactivate all volume groups",
2567    "\
2568 This command activates or (if C<activate> is false) deactivates
2569 all logical volumes in all volume groups.
2570 If activated, then they are made known to the
2571 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2572 then those devices disappear.
2573
2574 This command is the same as running C<vgchange -a y|n>");
2575
2576   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2577    [],
2578    "activate or deactivate some volume groups",
2579    "\
2580 This command activates or (if C<activate> is false) deactivates
2581 all logical volumes in the listed volume groups C<volgroups>.
2582 If activated, then they are made known to the
2583 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2584 then those devices disappear.
2585
2586 This command is the same as running C<vgchange -a y|n volgroups...>
2587
2588 Note that if C<volgroups> is an empty list then B<all> volume groups
2589 are activated or deactivated.");
2590
2591   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2592    [InitNone, Always, TestOutput (
2593       [["part_disk"; "/dev/sda"; "mbr"];
2594        ["pvcreate"; "/dev/sda1"];
2595        ["vgcreate"; "VG"; "/dev/sda1"];
2596        ["lvcreate"; "LV"; "VG"; "10"];
2597        ["mkfs"; "ext2"; "/dev/VG/LV"];
2598        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2599        ["write_file"; "/new"; "test content"; "0"];
2600        ["umount"; "/"];
2601        ["lvresize"; "/dev/VG/LV"; "20"];
2602        ["e2fsck_f"; "/dev/VG/LV"];
2603        ["resize2fs"; "/dev/VG/LV"];
2604        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2605        ["cat"; "/new"]], "test content");
2606     InitNone, Always, TestRun (
2607       (* Make an LV smaller to test RHBZ#587484. *)
2608       [["part_disk"; "/dev/sda"; "mbr"];
2609        ["pvcreate"; "/dev/sda1"];
2610        ["vgcreate"; "VG"; "/dev/sda1"];
2611        ["lvcreate"; "LV"; "VG"; "20"];
2612        ["lvresize"; "/dev/VG/LV"; "10"]])],
2613    "resize an LVM logical volume",
2614    "\
2615 This resizes (expands or shrinks) an existing LVM logical
2616 volume to C<mbytes>.  When reducing, data in the reduced part
2617 is lost.");
2618
2619   ("resize2fs", (RErr, [Device "device"]), 106, [],
2620    [], (* lvresize tests this *)
2621    "resize an ext2/ext3 filesystem",
2622    "\
2623 This resizes an ext2 or ext3 filesystem to match the size of
2624 the underlying device.
2625
2626 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2627 on the C<device> before calling this command.  For unknown reasons
2628 C<resize2fs> sometimes gives an error about this and sometimes not.
2629 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2630 calling this function.");
2631
2632   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2633    [InitBasicFS, Always, TestOutputList (
2634       [["find"; "/"]], ["lost+found"]);
2635     InitBasicFS, Always, TestOutputList (
2636       [["touch"; "/a"];
2637        ["mkdir"; "/b"];
2638        ["touch"; "/b/c"];
2639        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2640     InitBasicFS, Always, TestOutputList (
2641       [["mkdir_p"; "/a/b/c"];
2642        ["touch"; "/a/b/c/d"];
2643        ["find"; "/a/b/"]], ["c"; "c/d"])],
2644    "find all files and directories",
2645    "\
2646 This command lists out all files and directories, recursively,
2647 starting at C<directory>.  It is essentially equivalent to
2648 running the shell command C<find directory -print> but some
2649 post-processing happens on the output, described below.
2650
2651 This returns a list of strings I<without any prefix>.  Thus
2652 if the directory structure was:
2653
2654  /tmp/a
2655  /tmp/b
2656  /tmp/c/d
2657
2658 then the returned list from C<guestfs_find> C</tmp> would be
2659 4 elements:
2660
2661  a
2662  b
2663  c
2664  c/d
2665
2666 If C<directory> is not a directory, then this command returns
2667 an error.
2668
2669 The returned list is sorted.
2670
2671 See also C<guestfs_find0>.");
2672
2673   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2674    [], (* lvresize tests this *)
2675    "check an ext2/ext3 filesystem",
2676    "\
2677 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2678 filesystem checker on C<device>, noninteractively (C<-p>),
2679 even if the filesystem appears to be clean (C<-f>).
2680
2681 This command is only needed because of C<guestfs_resize2fs>
2682 (q.v.).  Normally you should use C<guestfs_fsck>.");
2683
2684   ("sleep", (RErr, [Int "secs"]), 109, [],
2685    [InitNone, Always, TestRun (
2686       [["sleep"; "1"]])],
2687    "sleep for some seconds",
2688    "\
2689 Sleep for C<secs> seconds.");
2690
2691   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2692    [InitNone, Always, TestOutputInt (
2693       [["part_disk"; "/dev/sda"; "mbr"];
2694        ["mkfs"; "ntfs"; "/dev/sda1"];
2695        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2696     InitNone, Always, TestOutputInt (
2697       [["part_disk"; "/dev/sda"; "mbr"];
2698        ["mkfs"; "ext2"; "/dev/sda1"];
2699        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2700    "probe NTFS volume",
2701    "\
2702 This command runs the L<ntfs-3g.probe(8)> command which probes
2703 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2704 be mounted read-write, and some cannot be mounted at all).
2705
2706 C<rw> is a boolean flag.  Set it to true if you want to test
2707 if the volume can be mounted read-write.  Set it to false if
2708 you want to test if the volume can be mounted read-only.
2709
2710 The return value is an integer which C<0> if the operation
2711 would succeed, or some non-zero value documented in the
2712 L<ntfs-3g.probe(8)> manual page.");
2713
2714   ("sh", (RString "output", [String "command"]), 111, [],
2715    [], (* XXX needs tests *)
2716    "run a command via the shell",
2717    "\
2718 This call runs a command from the guest filesystem via the
2719 guest's C</bin/sh>.
2720
2721 This is like C<guestfs_command>, but passes the command to:
2722
2723  /bin/sh -c \"command\"
2724
2725 Depending on the guest's shell, this usually results in
2726 wildcards being expanded, shell expressions being interpolated
2727 and so on.
2728
2729 All the provisos about C<guestfs_command> apply to this call.");
2730
2731   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2732    [], (* XXX needs tests *)
2733    "run a command via the shell returning lines",
2734    "\
2735 This is the same as C<guestfs_sh>, but splits the result
2736 into a list of lines.
2737
2738 See also: C<guestfs_command_lines>");
2739
2740   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2741    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2742     * code in stubs.c, since all valid glob patterns must start with "/".
2743     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2744     *)
2745    [InitBasicFS, Always, TestOutputList (
2746       [["mkdir_p"; "/a/b/c"];
2747        ["touch"; "/a/b/c/d"];
2748        ["touch"; "/a/b/c/e"];
2749        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2750     InitBasicFS, Always, TestOutputList (
2751       [["mkdir_p"; "/a/b/c"];
2752        ["touch"; "/a/b/c/d"];
2753        ["touch"; "/a/b/c/e"];
2754        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2755     InitBasicFS, Always, TestOutputList (
2756       [["mkdir_p"; "/a/b/c"];
2757        ["touch"; "/a/b/c/d"];
2758        ["touch"; "/a/b/c/e"];
2759        ["glob_expand"; "/a/*/x/*"]], [])],
2760    "expand a wildcard path",
2761    "\
2762 This command searches for all the pathnames matching
2763 C<pattern> according to the wildcard expansion rules
2764 used by the shell.
2765
2766 If no paths match, then this returns an empty list
2767 (note: not an error).
2768
2769 It is just a wrapper around the C L<glob(3)> function
2770 with flags C<GLOB_MARK|GLOB_BRACE>.
2771 See that manual page for more details.");
2772
2773   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2774    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2775       [["scrub_device"; "/dev/sdc"]])],
2776    "scrub (securely wipe) a device",
2777    "\
2778 This command writes patterns over C<device> to make data retrieval
2779 more difficult.
2780
2781 It is an interface to the L<scrub(1)> program.  See that
2782 manual page for more details.");
2783
2784   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2785    [InitBasicFS, Always, TestRun (
2786       [["write_file"; "/file"; "content"; "0"];
2787        ["scrub_file"; "/file"]])],
2788    "scrub (securely wipe) a file",
2789    "\
2790 This command writes patterns over a file to make data retrieval
2791 more difficult.
2792
2793 The file is I<removed> after scrubbing.
2794
2795 It is an interface to the L<scrub(1)> program.  See that
2796 manual page for more details.");
2797
2798   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2799    [], (* XXX needs testing *)
2800    "scrub (securely wipe) free space",
2801    "\
2802 This command creates the directory C<dir> and then fills it
2803 with files until the filesystem is full, and scrubs the files
2804 as for C<guestfs_scrub_file>, and deletes them.
2805 The intention is to scrub any free space on the partition
2806 containing C<dir>.
2807
2808 It is an interface to the L<scrub(1)> program.  See that
2809 manual page for more details.");
2810
2811   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2812    [InitBasicFS, Always, TestRun (
2813       [["mkdir"; "/tmp"];
2814        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2815    "create a temporary directory",
2816    "\
2817 This command creates a temporary directory.  The
2818 C<template> parameter should be a full pathname for the
2819 temporary directory name with the final six characters being
2820 \"XXXXXX\".
2821
2822 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2823 the second one being suitable for Windows filesystems.
2824
2825 The name of the temporary directory that was created
2826 is returned.
2827
2828 The temporary directory is created with mode 0700
2829 and is owned by root.
2830
2831 The caller is responsible for deleting the temporary
2832 directory and its contents after use.
2833
2834 See also: L<mkdtemp(3)>");
2835
2836   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2837    [InitISOFS, Always, TestOutputInt (
2838       [["wc_l"; "/10klines"]], 10000)],
2839    "count lines in a file",
2840    "\
2841 This command counts the lines in a file, using the
2842 C<wc -l> external command.");
2843
2844   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2845    [InitISOFS, Always, TestOutputInt (
2846       [["wc_w"; "/10klines"]], 10000)],
2847    "count words in a file",
2848    "\
2849 This command counts the words in a file, using the
2850 C<wc -w> external command.");
2851
2852   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2853    [InitISOFS, Always, TestOutputInt (
2854       [["wc_c"; "/100kallspaces"]], 102400)],
2855    "count characters in a file",
2856    "\
2857 This command counts the characters in a file, using the
2858 C<wc -c> external command.");
2859
2860   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2861    [InitISOFS, Always, TestOutputList (
2862       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"]);
2863     (* Test for RHBZ#579608, absolute symbolic links. *)
2864     InitISOFS, Always, TestOutputList (
2865       [["head"; "/abssymlink"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2866    "return first 10 lines of a file",
2867    "\
2868 This command returns up to the first 10 lines of a file as
2869 a list of strings.");
2870
2871   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2872    [InitISOFS, Always, TestOutputList (
2873       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2874     InitISOFS, Always, TestOutputList (
2875       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2876     InitISOFS, Always, TestOutputList (
2877       [["head_n"; "0"; "/10klines"]], [])],
2878    "return first N lines of a file",
2879    "\
2880 If the parameter C<nrlines> is a positive number, this returns the first
2881 C<nrlines> lines of the file C<path>.
2882
2883 If the parameter C<nrlines> is a negative number, this returns lines
2884 from the file C<path>, excluding the last C<nrlines> lines.
2885
2886 If the parameter C<nrlines> is zero, this returns an empty list.");
2887
2888   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2889    [InitISOFS, Always, TestOutputList (
2890       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2891    "return last 10 lines of a file",
2892    "\
2893 This command returns up to the last 10 lines of a file as
2894 a list of strings.");
2895
2896   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2897    [InitISOFS, Always, TestOutputList (
2898       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2899     InitISOFS, Always, TestOutputList (
2900       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2901     InitISOFS, Always, TestOutputList (
2902       [["tail_n"; "0"; "/10klines"]], [])],
2903    "return last N lines of a file",
2904    "\
2905 If the parameter C<nrlines> is a positive number, this returns the last
2906 C<nrlines> lines of the file C<path>.
2907
2908 If the parameter C<nrlines> is a negative number, this returns lines
2909 from the file C<path>, starting with the C<-nrlines>th line.
2910
2911 If the parameter C<nrlines> is zero, this returns an empty list.");
2912
2913   ("df", (RString "output", []), 125, [],
2914    [], (* XXX Tricky to test because it depends on the exact format
2915         * of the 'df' command and other imponderables.
2916         *)
2917    "report file system disk space usage",
2918    "\
2919 This command runs the C<df> command to report disk space used.
2920
2921 This command is mostly useful for interactive sessions.  It
2922 is I<not> intended that you try to parse the output string.
2923 Use C<statvfs> from programs.");
2924
2925   ("df_h", (RString "output", []), 126, [],
2926    [], (* XXX Tricky to test because it depends on the exact format
2927         * of the 'df' command and other imponderables.
2928         *)
2929    "report file system disk space usage (human readable)",
2930    "\
2931 This command runs the C<df -h> command to report disk space used
2932 in human-readable format.
2933
2934 This command is mostly useful for interactive sessions.  It
2935 is I<not> intended that you try to parse the output string.
2936 Use C<statvfs> from programs.");
2937
2938   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2939    [InitISOFS, Always, TestOutputInt (
2940       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2941    "estimate file space usage",
2942    "\
2943 This command runs the C<du -s> command to estimate file space
2944 usage for C<path>.
2945
2946 C<path> can be a file or a directory.  If C<path> is a directory
2947 then the estimate includes the contents of the directory and all
2948 subdirectories (recursively).
2949
2950 The result is the estimated size in I<kilobytes>
2951 (ie. units of 1024 bytes).");
2952
2953   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2954    [InitISOFS, Always, TestOutputList (
2955       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2956    "list files in an initrd",
2957    "\
2958 This command lists out files contained in an initrd.
2959
2960 The files are listed without any initial C</> character.  The
2961 files are listed in the order they appear (not necessarily
2962 alphabetical).  Directory names are listed as separate items.
2963
2964 Old Linux kernels (2.4 and earlier) used a compressed ext2
2965 filesystem as initrd.  We I<only> support the newer initramfs
2966 format (compressed cpio files).");
2967
2968   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2969    [],
2970    "mount a file using the loop device",
2971    "\
2972 This command lets you mount C<file> (a filesystem image
2973 in a file) on a mount point.  It is entirely equivalent to
2974 the command C<mount -o loop file mountpoint>.");
2975
2976   ("mkswap", (RErr, [Device "device"]), 130, [],
2977    [InitEmpty, Always, TestRun (
2978       [["part_disk"; "/dev/sda"; "mbr"];
2979        ["mkswap"; "/dev/sda1"]])],
2980    "create a swap partition",
2981    "\
2982 Create a swap partition on C<device>.");
2983
2984   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2985    [InitEmpty, Always, TestRun (
2986       [["part_disk"; "/dev/sda"; "mbr"];
2987        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2988    "create a swap partition with a label",
2989    "\
2990 Create a swap partition on C<device> with label C<label>.
2991
2992 Note that you cannot attach a swap label to a block device
2993 (eg. C</dev/sda>), just to a partition.  This appears to be
2994 a limitation of the kernel or swap tools.");
2995
2996   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
2997    (let uuid = uuidgen () in
2998     [InitEmpty, Always, TestRun (
2999        [["part_disk"; "/dev/sda"; "mbr"];
3000         ["mkswap_U"; uuid; "/dev/sda1"]])]),
3001    "create a swap partition with an explicit UUID",
3002    "\
3003 Create a swap partition on C<device> with UUID C<uuid>.");
3004
3005   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
3006    [InitBasicFS, Always, TestOutputStruct (
3007       [["mknod"; "0o10777"; "0"; "0"; "/node"];
3008        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
3009        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
3010     InitBasicFS, Always, TestOutputStruct (
3011       [["mknod"; "0o60777"; "66"; "99"; "/node"];
3012        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3013    "make block, character or FIFO devices",
3014    "\
3015 This call creates block or character special devices, or
3016 named pipes (FIFOs).
3017
3018 The C<mode> parameter should be the mode, using the standard
3019 constants.  C<devmajor> and C<devminor> are the
3020 device major and minor numbers, only used when creating block
3021 and character special devices.
3022
3023 Note that, just like L<mknod(2)>, the mode must be bitwise
3024 OR'd with S_IFBLK, S_IFCHR, S_IFIFO or S_IFSOCK (otherwise this call
3025 just creates a regular file).  These constants are
3026 available in the standard Linux header files, or you can use
3027 C<guestfs_mknod_b>, C<guestfs_mknod_c> or C<guestfs_mkfifo>
3028 which are wrappers around this command which bitwise OR
3029 in the appropriate constant for you.
3030
3031 The mode actually set is affected by the umask.");
3032
3033   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
3034    [InitBasicFS, Always, TestOutputStruct (
3035       [["mkfifo"; "0o777"; "/node"];
3036        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
3037    "make FIFO (named pipe)",
3038    "\
3039 This call creates a FIFO (named pipe) called C<path> with
3040 mode C<mode>.  It is just a convenient wrapper around
3041 C<guestfs_mknod>.
3042
3043 The mode actually set is affected by the umask.");
3044
3045   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
3046    [InitBasicFS, Always, TestOutputStruct (
3047       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
3048        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3049    "make block device node",
3050    "\
3051 This call creates a block device node called C<path> with
3052 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3053 It is just a convenient wrapper around C<guestfs_mknod>.
3054
3055 The mode actually set is affected by the umask.");
3056
3057   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
3058    [InitBasicFS, Always, TestOutputStruct (
3059       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
3060        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
3061    "make char device node",
3062    "\
3063 This call creates a char device node called C<path> with
3064 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3065 It is just a convenient wrapper around C<guestfs_mknod>.
3066
3067 The mode actually set is affected by the umask.");
3068
3069   ("umask", (RInt "oldmask", [Int "mask"]), 137, [FishOutput FishOutputOctal],
3070    [InitEmpty, Always, TestOutputInt (
3071       [["umask"; "0o22"]], 0o22)],
3072    "set file mode creation mask (umask)",
3073    "\
3074 This function sets the mask used for creating new files and
3075 device nodes to C<mask & 0777>.
3076
3077 Typical umask values would be C<022> which creates new files
3078 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
3079 C<002> which creates new files with permissions like
3080 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
3081
3082 The default umask is C<022>.  This is important because it
3083 means that directories and device nodes will be created with
3084 C<0644> or C<0755> mode even if you specify C<0777>.
3085
3086 See also C<guestfs_get_umask>,
3087 L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
3088
3089 This call returns the previous umask.");
3090
3091   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
3092    [],
3093    "read directories entries",
3094    "\
3095 This returns the list of directory entries in directory C<dir>.
3096
3097 All entries in the directory are returned, including C<.> and
3098 C<..>.  The entries are I<not> sorted, but returned in the same
3099 order as the underlying filesystem.
3100
3101 Also this call returns basic file type information about each
3102 file.  The C<ftyp> field will contain one of the following characters:
3103
3104 =over 4
3105
3106 =item 'b'
3107
3108 Block special
3109
3110 =item 'c'
3111
3112 Char special
3113
3114 =item 'd'
3115
3116 Directory
3117
3118 =item 'f'
3119
3120 FIFO (named pipe)
3121
3122 =item 'l'
3123
3124 Symbolic link
3125
3126 =item 'r'
3127
3128 Regular file
3129
3130 =item 's'
3131
3132 Socket
3133
3134 =item 'u'
3135
3136 Unknown file type
3137
3138 =item '?'
3139
3140 The L<readdir(3)> returned a C<d_type> field with an
3141 unexpected value
3142
3143 =back
3144
3145 This function is primarily intended for use by programs.  To
3146 get a simple list of names, use C<guestfs_ls>.  To get a printable
3147 directory for human consumption, use C<guestfs_ll>.");
3148
3149   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3150    [],
3151    "create partitions on a block device",
3152    "\
3153 This is a simplified interface to the C<guestfs_sfdisk>
3154 command, where partition sizes are specified in megabytes
3155 only (rounded to the nearest cylinder) and you don't need
3156 to specify the cyls, heads and sectors parameters which
3157 were rarely if ever used anyway.
3158
3159 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3160 and C<guestfs_part_disk>");
3161
3162   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3163    [],
3164    "determine file type inside a compressed file",
3165    "\
3166 This command runs C<file> after first decompressing C<path>
3167 using C<method>.
3168
3169 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3170
3171 Since 1.0.63, use C<guestfs_file> instead which can now
3172 process compressed files.");
3173
3174   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3175    [],
3176    "list extended attributes of a file or directory",
3177    "\
3178 This call lists the extended attributes of the file or directory
3179 C<path>.
3180
3181 At the system call level, this is a combination of the
3182 L<listxattr(2)> and L<getxattr(2)> calls.
3183
3184 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3185
3186   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3187    [],
3188    "list extended attributes of a file or directory",
3189    "\
3190 This is the same as C<guestfs_getxattrs>, but if C<path>
3191 is a symbolic link, then it returns the extended attributes
3192 of the link itself.");
3193
3194   ("setxattr", (RErr, [String "xattr";
3195                        String "val"; Int "vallen"; (* will be BufferIn *)
3196                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3197    [],
3198    "set extended attribute of a file or directory",
3199    "\
3200 This call sets the extended attribute named C<xattr>
3201 of the file C<path> to the value C<val> (of length C<vallen>).
3202 The value is arbitrary 8 bit data.
3203
3204 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3205
3206   ("lsetxattr", (RErr, [String "xattr";
3207                         String "val"; Int "vallen"; (* will be BufferIn *)
3208                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3209    [],
3210    "set extended attribute of a file or directory",
3211    "\
3212 This is the same as C<guestfs_setxattr>, but if C<path>
3213 is a symbolic link, then it sets an extended attribute
3214 of the link itself.");
3215
3216   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3217    [],
3218    "remove extended attribute of a file or directory",
3219    "\
3220 This call removes the extended attribute named C<xattr>
3221 of the file C<path>.
3222
3223 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3224
3225   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3226    [],
3227    "remove extended attribute of a file or directory",
3228    "\
3229 This is the same as C<guestfs_removexattr>, but if C<path>
3230 is a symbolic link, then it removes an extended attribute
3231 of the link itself.");
3232
3233   ("mountpoints", (RHashtable "mps", []), 147, [],
3234    [],
3235    "show mountpoints",
3236    "\
3237 This call is similar to C<guestfs_mounts>.  That call returns
3238 a list of devices.  This one returns a hash table (map) of
3239 device name to directory where the device is mounted.");
3240
3241   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3242    (* This is a special case: while you would expect a parameter
3243     * of type "Pathname", that doesn't work, because it implies
3244     * NEED_ROOT in the generated calling code in stubs.c, and
3245     * this function cannot use NEED_ROOT.
3246     *)
3247    [],
3248    "create a mountpoint",
3249    "\
3250 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3251 specialized calls that can be used to create extra mountpoints
3252 before mounting the first filesystem.
3253
3254 These calls are I<only> necessary in some very limited circumstances,
3255 mainly the case where you want to mount a mix of unrelated and/or
3256 read-only filesystems together.
3257
3258 For example, live CDs often contain a \"Russian doll\" nest of
3259 filesystems, an ISO outer layer, with a squashfs image inside, with
3260 an ext2/3 image inside that.  You can unpack this as follows
3261 in guestfish:
3262
3263  add-ro Fedora-11-i686-Live.iso
3264  run
3265  mkmountpoint /cd
3266  mkmountpoint /squash
3267  mkmountpoint /ext3
3268  mount /dev/sda /cd
3269  mount-loop /cd/LiveOS/squashfs.img /squash
3270  mount-loop /squash/LiveOS/ext3fs.img /ext3
3271
3272 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3273
3274   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3275    [],
3276    "remove a mountpoint",
3277    "\
3278 This calls removes a mountpoint that was previously created
3279 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3280 for full details.");
3281
3282   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3283    [InitISOFS, Always, TestOutputBuffer (
3284       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3285    "read a file",
3286    "\
3287 This calls returns the contents of the file C<path> as a
3288 buffer.
3289
3290 Unlike C<guestfs_cat>, this function can correctly
3291 handle files that contain embedded ASCII NUL characters.
3292 However unlike C<guestfs_download>, this function is limited
3293 in the total size of file that can be handled.");
3294
3295   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3296    [InitISOFS, Always, TestOutputList (
3297       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3298     InitISOFS, Always, TestOutputList (
3299       [["grep"; "nomatch"; "/test-grep.txt"]], []);
3300     (* Test for RHBZ#579608, absolute symbolic links. *)
3301     InitISOFS, Always, TestOutputList (
3302       [["grep"; "nomatch"; "/abssymlink"]], [])],
3303    "return lines matching a pattern",
3304    "\
3305 This calls the external C<grep> program and returns the
3306 matching lines.");
3307
3308   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3309    [InitISOFS, Always, TestOutputList (
3310       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3311    "return lines matching a pattern",
3312    "\
3313 This calls the external C<egrep> program and returns the
3314 matching lines.");
3315
3316   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3317    [InitISOFS, Always, TestOutputList (
3318       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3319    "return lines matching a pattern",
3320    "\
3321 This calls the external C<fgrep> program and returns the
3322 matching lines.");
3323
3324   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3325    [InitISOFS, Always, TestOutputList (
3326       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3327    "return lines matching a pattern",
3328    "\
3329 This calls the external C<grep -i> program and returns the
3330 matching lines.");
3331
3332   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3333    [InitISOFS, Always, TestOutputList (
3334       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3335    "return lines matching a pattern",
3336    "\
3337 This calls the external C<egrep -i> program and returns the
3338 matching lines.");
3339
3340   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3341    [InitISOFS, Always, TestOutputList (
3342       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3343    "return lines matching a pattern",
3344    "\
3345 This calls the external C<fgrep -i> program and returns the
3346 matching lines.");
3347
3348   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3349    [InitISOFS, Always, TestOutputList (
3350       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3351    "return lines matching a pattern",
3352    "\
3353 This calls the external C<zgrep> program and returns the
3354 matching lines.");
3355
3356   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3357    [InitISOFS, Always, TestOutputList (
3358       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3359    "return lines matching a pattern",
3360    "\
3361 This calls the external C<zegrep> program and returns the
3362 matching lines.");
3363
3364   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3365    [InitISOFS, Always, TestOutputList (
3366       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3367    "return lines matching a pattern",
3368    "\
3369 This calls the external C<zfgrep> program and returns the
3370 matching lines.");
3371
3372   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3373    [InitISOFS, Always, TestOutputList (
3374       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3375    "return lines matching a pattern",
3376    "\
3377 This calls the external C<zgrep -i> program and returns the
3378 matching lines.");
3379
3380   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3381    [InitISOFS, Always, TestOutputList (
3382       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3383    "return lines matching a pattern",
3384    "\
3385 This calls the external C<zegrep -i> program and returns the
3386 matching lines.");
3387
3388   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3389    [InitISOFS, Always, TestOutputList (
3390       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3391    "return lines matching a pattern",
3392    "\
3393 This calls the external C<zfgrep -i> program and returns the
3394 matching lines.");
3395
3396   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3397    [InitISOFS, Always, TestOutput (
3398       [["realpath"; "/../directory"]], "/directory")],
3399    "canonicalized absolute pathname",
3400    "\
3401 Return the canonicalized absolute pathname of C<path>.  The
3402 returned path has no C<.>, C<..> or symbolic link path elements.");
3403
3404   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3405    [InitBasicFS, Always, TestOutputStruct (
3406       [["touch"; "/a"];
3407        ["ln"; "/a"; "/b"];
3408        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3409    "create a hard link",
3410    "\
3411 This command creates a hard link using the C<ln> command.");
3412
3413   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3414    [InitBasicFS, Always, TestOutputStruct (
3415       [["touch"; "/a"];
3416        ["touch"; "/b"];
3417        ["ln_f"; "/a"; "/b"];
3418        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3419    "create a hard link",
3420    "\
3421 This command creates a hard link using the C<ln -f> command.
3422 The C<-f> option removes the link (C<linkname>) if it exists already.");
3423
3424   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3425    [InitBasicFS, Always, TestOutputStruct (
3426       [["touch"; "/a"];
3427        ["ln_s"; "a"; "/b"];
3428        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3429    "create a symbolic link",
3430    "\
3431 This command creates a symbolic link using the C<ln -s> command.");
3432
3433   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3434    [InitBasicFS, Always, TestOutput (
3435       [["mkdir_p"; "/a/b"];
3436        ["touch"; "/a/b/c"];
3437        ["ln_sf"; "../d"; "/a/b/c"];
3438        ["readlink"; "/a/b/c"]], "../d")],
3439    "create a symbolic link",
3440    "\
3441 This command creates a symbolic link using the C<ln -sf> command,
3442 The C<-f> option removes the link (C<linkname>) if it exists already.");
3443
3444   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3445    [] (* XXX tested above *),
3446    "read the target of a symbolic link",
3447    "\
3448 This command reads the target of a symbolic link.");
3449
3450   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3451    [InitBasicFS, Always, TestOutputStruct (
3452       [["fallocate"; "/a"; "1000000"];
3453        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3454    "preallocate a file in the guest filesystem",
3455    "\
3456 This command preallocates a file (containing zero bytes) named
3457 C<path> of size C<len> bytes.  If the file exists already, it
3458 is overwritten.
3459
3460 Do not confuse this with the guestfish-specific
3461 C<alloc> command which allocates a file in the host and
3462 attaches it as a device.");
3463
3464   ("swapon_device", (RErr, [Device "device"]), 170, [],
3465    [InitPartition, Always, TestRun (
3466       [["mkswap"; "/dev/sda1"];
3467        ["swapon_device"; "/dev/sda1"];
3468        ["swapoff_device"; "/dev/sda1"]])],
3469    "enable swap on device",
3470    "\
3471 This command enables the libguestfs appliance to use the
3472 swap device or partition named C<device>.  The increased
3473 memory is made available for all commands, for example
3474 those run using C<guestfs_command> or C<guestfs_sh>.
3475
3476 Note that you should not swap to existing guest swap
3477 partitions unless you know what you are doing.  They may
3478 contain hibernation information, or other information that
3479 the guest doesn't want you to trash.  You also risk leaking
3480 information about the host to the guest this way.  Instead,
3481 attach a new host device to the guest and swap on that.");
3482
3483   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3484    [], (* XXX tested by swapon_device *)
3485    "disable swap on device",
3486    "\
3487 This command disables the libguestfs appliance swap
3488 device or partition named C<device>.
3489 See C<guestfs_swapon_device>.");
3490
3491   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3492    [InitBasicFS, Always, TestRun (
3493       [["fallocate"; "/swap"; "8388608"];
3494        ["mkswap_file"; "/swap"];
3495        ["swapon_file"; "/swap"];
3496        ["swapoff_file"; "/swap"]])],
3497    "enable swap on file",
3498    "\
3499 This command enables swap to a file.
3500 See C<guestfs_swapon_device> for other notes.");
3501
3502   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3503    [], (* XXX tested by swapon_file *)
3504    "disable swap on file",
3505    "\
3506 This command disables the libguestfs appliance swap on file.");
3507
3508   ("swapon_label", (RErr, [String "label"]), 174, [],
3509    [InitEmpty, Always, TestRun (
3510       [["part_disk"; "/dev/sdb"; "mbr"];
3511        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3512        ["swapon_label"; "swapit"];
3513        ["swapoff_label"; "swapit"];
3514        ["zero"; "/dev/sdb"];
3515        ["blockdev_rereadpt"; "/dev/sdb"]])],
3516    "enable swap on labeled swap partition",
3517    "\
3518 This command enables swap to a labeled swap partition.
3519 See C<guestfs_swapon_device> for other notes.");
3520
3521   ("swapoff_label", (RErr, [String "label"]), 175, [],
3522    [], (* XXX tested by swapon_label *)
3523    "disable swap on labeled swap partition",
3524    "\
3525 This command disables the libguestfs appliance swap on
3526 labeled swap partition.");
3527
3528   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3529    (let uuid = uuidgen () in
3530     [InitEmpty, Always, TestRun (
3531        [["mkswap_U"; uuid; "/dev/sdb"];
3532         ["swapon_uuid"; uuid];
3533         ["swapoff_uuid"; uuid]])]),
3534    "enable swap on swap partition by UUID",
3535    "\
3536 This command enables swap to a swap partition with the given UUID.
3537 See C<guestfs_swapon_device> for other notes.");
3538
3539   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3540    [], (* XXX tested by swapon_uuid *)
3541    "disable swap on swap partition by UUID",
3542    "\
3543 This command disables the libguestfs appliance swap partition
3544 with the given UUID.");
3545
3546   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3547    [InitBasicFS, Always, TestRun (
3548       [["fallocate"; "/swap"; "8388608"];
3549        ["mkswap_file"; "/swap"]])],
3550    "create a swap file",
3551    "\
3552 Create a swap file.
3553
3554 This command just writes a swap file signature to an existing
3555 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3556
3557   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3558    [InitISOFS, Always, TestRun (
3559       [["inotify_init"; "0"]])],
3560    "create an inotify handle",
3561    "\
3562 This command creates a new inotify handle.
3563 The inotify subsystem can be used to notify events which happen to
3564 objects in the guest filesystem.
3565
3566 C<maxevents> is the maximum number of events which will be
3567 queued up between calls to C<guestfs_inotify_read> or
3568 C<guestfs_inotify_files>.
3569 If this is passed as C<0>, then the kernel (or previously set)
3570 default is used.  For Linux 2.6.29 the default was 16384 events.
3571 Beyond this limit, the kernel throws away events, but records
3572 the fact that it threw them away by setting a flag
3573 C<IN_Q_OVERFLOW> in the returned structure list (see
3574 C<guestfs_inotify_read>).
3575
3576 Before any events are generated, you have to add some
3577 watches to the internal watch list.  See:
3578 C<guestfs_inotify_add_watch>,
3579 C<guestfs_inotify_rm_watch> and
3580 C<guestfs_inotify_watch_all>.
3581
3582 Queued up events should be read periodically by calling
3583 C<guestfs_inotify_read>
3584 (or C<guestfs_inotify_files> which is just a helpful
3585 wrapper around C<guestfs_inotify_read>).  If you don't
3586 read the events out often enough then you risk the internal
3587 queue overflowing.
3588
3589 The handle should be closed after use by calling
3590 C<guestfs_inotify_close>.  This also removes any
3591 watches automatically.
3592
3593 See also L<inotify(7)> for an overview of the inotify interface
3594 as exposed by the Linux kernel, which is roughly what we expose
3595 via libguestfs.  Note that there is one global inotify handle
3596 per libguestfs instance.");
3597
3598   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3599    [InitBasicFS, Always, TestOutputList (
3600       [["inotify_init"; "0"];
3601        ["inotify_add_watch"; "/"; "1073741823"];
3602        ["touch"; "/a"];
3603        ["touch"; "/b"];
3604        ["inotify_files"]], ["a"; "b"])],
3605    "add an inotify watch",
3606    "\
3607 Watch C<path> for the events listed in C<mask>.
3608
3609 Note that if C<path> is a directory then events within that
3610 directory are watched, but this does I<not> happen recursively
3611 (in subdirectories).
3612
3613 Note for non-C or non-Linux callers: the inotify events are
3614 defined by the Linux kernel ABI and are listed in
3615 C</usr/include/sys/inotify.h>.");
3616
3617   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3618    [],
3619    "remove an inotify watch",
3620    "\
3621 Remove a previously defined inotify watch.
3622 See C<guestfs_inotify_add_watch>.");
3623
3624   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3625    [],
3626    "return list of inotify events",
3627    "\
3628 Return the complete queue of events that have happened
3629 since the previous read call.
3630
3631 If no events have happened, this returns an empty list.
3632
3633 I<Note>: In order to make sure that all events have been
3634 read, you must call this function repeatedly until it
3635 returns an empty list.  The reason is that the call will
3636 read events up to the maximum appliance-to-host message
3637 size and leave remaining events in the queue.");
3638
3639   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3640    [],
3641    "return list of watched files that had events",
3642    "\
3643 This function is a helpful wrapper around C<guestfs_inotify_read>
3644 which just returns a list of pathnames of objects that were
3645 touched.  The returned pathnames are sorted and deduplicated.");
3646
3647   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3648    [],
3649    "close the inotify handle",
3650    "\
3651 This closes the inotify handle which was previously
3652 opened by inotify_init.  It removes all watches, throws
3653 away any pending events, and deallocates all resources.");
3654
3655   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3656    [],
3657    "set SELinux security context",
3658    "\
3659 This sets the SELinux security context of the daemon
3660 to the string C<context>.
3661
3662 See the documentation about SELINUX in L<guestfs(3)>.");
3663
3664   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3665    [],
3666    "get SELinux security context",
3667    "\
3668 This gets the SELinux security context of the daemon.
3669
3670 See the documentation about SELINUX in L<guestfs(3)>,
3671 and C<guestfs_setcon>");
3672
3673   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3674    [InitEmpty, Always, TestOutput (
3675       [["part_disk"; "/dev/sda"; "mbr"];
3676        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3677        ["mount_options"; ""; "/dev/sda1"; "/"];
3678        ["write_file"; "/new"; "new file contents"; "0"];
3679        ["cat"; "/new"]], "new file contents")],
3680    "make a filesystem with block size",
3681    "\
3682 This call is similar to C<guestfs_mkfs>, but it allows you to
3683 control the block size of the resulting filesystem.  Supported
3684 block sizes depend on the filesystem type, but typically they
3685 are C<1024>, C<2048> or C<4096> only.");
3686
3687   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3688    [InitEmpty, Always, TestOutput (
3689       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3690        ["mke2journal"; "4096"; "/dev/sda1"];
3691        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3692        ["mount_options"; ""; "/dev/sda2"; "/"];
3693        ["write_file"; "/new"; "new file contents"; "0"];
3694        ["cat"; "/new"]], "new file contents")],
3695    "make ext2/3/4 external journal",
3696    "\
3697 This creates an ext2 external journal on C<device>.  It is equivalent
3698 to the command:
3699
3700  mke2fs -O journal_dev -b blocksize device");
3701
3702   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3703    [InitEmpty, Always, TestOutput (
3704       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3705        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3706        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3707        ["mount_options"; ""; "/dev/sda2"; "/"];
3708        ["write_file"; "/new"; "new file contents"; "0"];
3709        ["cat"; "/new"]], "new file contents")],
3710    "make ext2/3/4 external journal with label",
3711    "\
3712 This creates an ext2 external journal on C<device> with label C<label>.");
3713
3714   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3715    (let uuid = uuidgen () in
3716     [InitEmpty, Always, TestOutput (
3717        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3718         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3719         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3720         ["mount_options"; ""; "/dev/sda2"; "/"];
3721         ["write_file"; "/new"; "new file contents"; "0"];
3722         ["cat"; "/new"]], "new file contents")]),
3723    "make ext2/3/4 external journal with UUID",
3724    "\
3725 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3726
3727   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3728    [],
3729    "make ext2/3/4 filesystem with external journal",
3730    "\
3731 This creates an ext2/3/4 filesystem on C<device> with
3732 an external journal on C<journal>.  It is equivalent
3733 to the command:
3734
3735  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3736
3737 See also C<guestfs_mke2journal>.");
3738
3739   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3740    [],
3741    "make ext2/3/4 filesystem with external journal",
3742    "\
3743 This creates an ext2/3/4 filesystem on C<device> with
3744 an external journal on the journal labeled C<label>.
3745
3746 See also C<guestfs_mke2journal_L>.");
3747
3748   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3749    [],
3750    "make ext2/3/4 filesystem with external journal",
3751    "\
3752 This creates an ext2/3/4 filesystem on C<device> with
3753 an external journal on the journal with UUID C<uuid>.
3754
3755 See also C<guestfs_mke2journal_U>.");
3756
3757   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3758    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3759    "load a kernel module",
3760    "\
3761 This loads a kernel module in the appliance.
3762
3763 The kernel module must have been whitelisted when libguestfs
3764 was built (see C<appliance/kmod.whitelist.in> in the source).");
3765
3766   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3767    [InitNone, Always, TestOutput (
3768       [["echo_daemon"; "This is a test"]], "This is a test"
3769     )],
3770    "echo arguments back to the client",
3771    "\
3772 This command concatenate the list of C<words> passed with single spaces between
3773 them and returns the resulting string.
3774
3775 You can use this command to test the connection through to the daemon.
3776
3777 See also C<guestfs_ping_daemon>.");
3778
3779   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3780    [], (* There is a regression test for this. *)
3781    "find all files and directories, returning NUL-separated list",
3782    "\
3783 This command lists out all files and directories, recursively,
3784 starting at C<directory>, placing the resulting list in the
3785 external file called C<files>.
3786
3787 This command works the same way as C<guestfs_find> with the
3788 following exceptions:
3789
3790 =over 4
3791
3792 =item *
3793
3794 The resulting list is written to an external file.
3795
3796 =item *
3797
3798 Items (filenames) in the result are separated
3799 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3800
3801 =item *
3802
3803 This command is not limited in the number of names that it
3804 can return.
3805
3806 =item *
3807
3808 The result list is not sorted.
3809
3810 =back");
3811
3812   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3813    [InitISOFS, Always, TestOutput (
3814       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3815     InitISOFS, Always, TestOutput (
3816       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3817     InitISOFS, Always, TestOutput (
3818       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3819     InitISOFS, Always, TestLastFail (
3820       [["case_sensitive_path"; "/Known-1/"]]);
3821     InitBasicFS, Always, TestOutput (
3822       [["mkdir"; "/a"];
3823        ["mkdir"; "/a/bbb"];
3824        ["touch"; "/a/bbb/c"];
3825        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3826     InitBasicFS, Always, TestOutput (
3827       [["mkdir"; "/a"];
3828        ["mkdir"; "/a/bbb"];
3829        ["touch"; "/a/bbb/c"];
3830        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3831     InitBasicFS, Always, TestLastFail (
3832       [["mkdir"; "/a"];
3833        ["mkdir"; "/a/bbb"];
3834        ["touch"; "/a/bbb/c"];
3835        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3836    "return true path on case-insensitive filesystem",
3837    "\
3838 This can be used to resolve case insensitive paths on
3839 a filesystem which is case sensitive.  The use case is
3840 to resolve paths which you have read from Windows configuration
3841 files or the Windows Registry, to the true path.
3842
3843 The command handles a peculiarity of the Linux ntfs-3g
3844 filesystem driver (and probably others), which is that although
3845 the underlying filesystem is case-insensitive, the driver
3846 exports the filesystem to Linux as case-sensitive.
3847
3848 One consequence of this is that special directories such
3849 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3850 (or other things) depending on the precise details of how
3851 they were created.  In Windows itself this would not be
3852 a problem.
3853
3854 Bug or feature?  You decide:
3855 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3856
3857 This function resolves the true case of each element in the
3858 path and returns the case-sensitive path.
3859
3860 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3861 might return C<\"/WINDOWS/system32\"> (the exact return value
3862 would depend on details of how the directories were originally
3863 created under Windows).
3864
3865 I<Note>:
3866 This function does not handle drive names, backslashes etc.
3867
3868 See also C<guestfs_realpath>.");
3869
3870   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3871    [InitBasicFS, Always, TestOutput (
3872       [["vfs_type"; "/dev/sda1"]], "ext2")],
3873    "get the Linux VFS type corresponding to a mounted device",
3874    "\
3875 This command gets the block device type corresponding to
3876 a mounted device called C<device>.
3877
3878 Usually the result is the name of the Linux VFS module that
3879 is used to mount this device (probably determined automatically
3880 if you used the C<guestfs_mount> call).");
3881
3882   ("truncate", (RErr, [Pathname "path"]), 199, [],
3883    [InitBasicFS, Always, TestOutputStruct (
3884       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3885        ["truncate"; "/test"];
3886        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3887    "truncate a file to zero size",
3888    "\
3889 This command truncates C<path> to a zero-length file.  The
3890 file must exist already.");
3891
3892   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3893    [InitBasicFS, Always, TestOutputStruct (
3894       [["touch"; "/test"];
3895        ["truncate_size"; "/test"; "1000"];
3896        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3897    "truncate a file to a particular size",
3898    "\
3899 This command truncates C<path> to size C<size> bytes.  The file
3900 must exist already.  If the file is smaller than C<size> then
3901 the file is extended to the required size with null bytes.");
3902
3903   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3904    [InitBasicFS, Always, TestOutputStruct (
3905       [["touch"; "/test"];
3906        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3907        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3908    "set timestamp of a file with nanosecond precision",
3909    "\
3910 This command sets the timestamps of a file with nanosecond
3911 precision.
3912
3913 C<atsecs, atnsecs> are the last access time (atime) in secs and
3914 nanoseconds from the epoch.
3915
3916 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3917 secs and nanoseconds from the epoch.
3918
3919 If the C<*nsecs> field contains the special value C<-1> then
3920 the corresponding timestamp is set to the current time.  (The
3921 C<*secs> field is ignored in this case).
3922
3923 If the C<*nsecs> field contains the special value C<-2> then
3924 the corresponding timestamp is left unchanged.  (The
3925 C<*secs> field is ignored in this case).");
3926
3927   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3928    [InitBasicFS, Always, TestOutputStruct (
3929       [["mkdir_mode"; "/test"; "0o111"];
3930        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3931    "create a directory with a particular mode",
3932    "\
3933 This command creates a directory, setting the initial permissions
3934 of the directory to C<mode>.
3935
3936 For common Linux filesystems, the actual mode which is set will
3937 be C<mode & ~umask & 01777>.  Non-native-Linux filesystems may
3938 interpret the mode in other ways.
3939
3940 See also C<guestfs_mkdir>, C<guestfs_umask>");
3941
3942   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3943    [], (* XXX *)
3944    "change file owner and group",
3945    "\
3946 Change the file owner to C<owner> and group to C<group>.
3947 This is like C<guestfs_chown> but if C<path> is a symlink then
3948 the link itself is changed, not the target.
3949
3950 Only numeric uid and gid are supported.  If you want to use
3951 names, you will need to locate and parse the password file
3952 yourself (Augeas support makes this relatively easy).");
3953
3954   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3955    [], (* XXX *)
3956    "lstat on multiple files",
3957    "\
3958 This call allows you to perform the C<guestfs_lstat> operation
3959 on multiple files, where all files are in the directory C<path>.
3960 C<names> is the list of files from this directory.
3961
3962 On return you get a list of stat structs, with a one-to-one
3963 correspondence to the C<names> list.  If any name did not exist
3964 or could not be lstat'd, then the C<ino> field of that structure
3965 is set to C<-1>.
3966
3967 This call is intended for programs that want to efficiently
3968 list a directory contents without making many round-trips.
3969 See also C<guestfs_lxattrlist> for a similarly efficient call
3970 for getting extended attributes.  Very long directory listings
3971 might cause the protocol message size to be exceeded, causing
3972 this call to fail.  The caller must split up such requests
3973 into smaller groups of names.");
3974
3975   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3976    [], (* XXX *)
3977    "lgetxattr on multiple files",
3978    "\
3979 This call allows you to get the extended attributes
3980 of multiple files, where all files are in the directory C<path>.
3981 C<names> is the list of files from this directory.
3982
3983 On return you get a flat list of xattr structs which must be
3984 interpreted sequentially.  The first xattr struct always has a zero-length
3985 C<attrname>.  C<attrval> in this struct is zero-length
3986 to indicate there was an error doing C<lgetxattr> for this
3987 file, I<or> is a C string which is a decimal number
3988 (the number of following attributes for this file, which could
3989 be C<\"0\">).  Then after the first xattr struct are the
3990 zero or more attributes for the first named file.
3991 This repeats for the second and subsequent files.
3992
3993 This call is intended for programs that want to efficiently
3994 list a directory contents without making many round-trips.
3995 See also C<guestfs_lstatlist> for a similarly efficient call
3996 for getting standard stats.  Very long directory listings
3997 might cause the protocol message size to be exceeded, causing
3998 this call to fail.  The caller must split up such requests
3999 into smaller groups of names.");
4000
4001   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
4002    [], (* XXX *)
4003    "readlink on multiple files",
4004    "\
4005 This call allows you to do a C<readlink> operation
4006 on multiple files, where all files are in the directory C<path>.
4007 C<names> is the list of files from this directory.
4008
4009 On return you get a list of strings, with a one-to-one
4010 correspondence to the C<names> list.  Each string is the
4011 value of the symbol link.
4012
4013 If the C<readlink(2)> operation fails on any name, then
4014 the corresponding result string is the empty string C<\"\">.
4015 However the whole operation is completed even if there
4016 were C<readlink(2)> errors, and so you can call this
4017 function with names where you don't know if they are
4018 symbolic links already (albeit slightly less efficient).
4019
4020 This call is intended for programs that want to efficiently
4021 list a directory contents without making many round-trips.
4022 Very long directory listings might cause the protocol
4023 message size to be exceeded, causing
4024 this call to fail.  The caller must split up such requests
4025 into smaller groups of names.");
4026
4027   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
4028    [InitISOFS, Always, TestOutputBuffer (
4029       [["pread"; "/known-4"; "1"; "3"]], "\n");
4030     InitISOFS, Always, TestOutputBuffer (
4031       [["pread"; "/empty"; "0"; "100"]], "")],
4032    "read part of a file",
4033    "\
4034 This command lets you read part of a file.  It reads C<count>
4035 bytes of the file, starting at C<offset>, from file C<path>.
4036
4037 This may read fewer bytes than requested.  For further details
4038 see the L<pread(2)> system call.");
4039
4040   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
4041    [InitEmpty, Always, TestRun (
4042       [["part_init"; "/dev/sda"; "gpt"]])],
4043    "create an empty partition table",
4044    "\
4045 This creates an empty partition table on C<device> of one of the
4046 partition types listed below.  Usually C<parttype> should be
4047 either C<msdos> or C<gpt> (for large disks).
4048
4049 Initially there are no partitions.  Following this, you should
4050 call C<guestfs_part_add> for each partition required.
4051
4052 Possible values for C<parttype> are:
4053
4054 =over 4
4055
4056 =item B<efi> | B<gpt>
4057
4058 Intel EFI / GPT partition table.
4059
4060 This is recommended for >= 2 TB partitions that will be accessed
4061 from Linux and Intel-based Mac OS X.  It also has limited backwards
4062 compatibility with the C<mbr> format.
4063
4064 =item B<mbr> | B<msdos>
4065
4066 The standard PC \"Master Boot Record\" (MBR) format used
4067 by MS-DOS and Windows.  This partition type will B<only> work
4068 for device sizes up to 2 TB.  For large disks we recommend
4069 using C<gpt>.
4070
4071 =back
4072
4073 Other partition table types that may work but are not
4074 supported include:
4075
4076 =over 4
4077
4078 =item B<aix>
4079
4080 AIX disk labels.
4081
4082 =item B<amiga> | B<rdb>
4083
4084 Amiga \"Rigid Disk Block\" format.
4085
4086 =item B<bsd>
4087
4088 BSD disk labels.
4089
4090 =item B<dasd>
4091
4092 DASD, used on IBM mainframes.
4093
4094 =item B<dvh>
4095
4096 MIPS/SGI volumes.
4097
4098 =item B<mac>
4099
4100 Old Mac partition format.  Modern Macs use C<gpt>.
4101
4102 =item B<pc98>
4103
4104 NEC PC-98 format, common in Japan apparently.
4105
4106 =item B<sun>
4107
4108 Sun disk labels.
4109
4110 =back");
4111
4112   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
4113    [InitEmpty, Always, TestRun (
4114       [["part_init"; "/dev/sda"; "mbr"];
4115        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
4116     InitEmpty, Always, TestRun (
4117       [["part_init"; "/dev/sda"; "gpt"];
4118        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
4119        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
4120     InitEmpty, Always, TestRun (
4121       [["part_init"; "/dev/sda"; "mbr"];
4122        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
4123        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4124        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4125        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4126    "add a partition to the device",
4127    "\
4128 This command adds a partition to C<device>.  If there is no partition
4129 table on the device, call C<guestfs_part_init> first.
4130
4131 The C<prlogex> parameter is the type of partition.  Normally you
4132 should pass C<p> or C<primary> here, but MBR partition tables also
4133 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4134 types.
4135
4136 C<startsect> and C<endsect> are the start and end of the partition
4137 in I<sectors>.  C<endsect> may be negative, which means it counts
4138 backwards from the end of the disk (C<-1> is the last sector).
4139
4140 Creating a partition which covers the whole disk is not so easy.
4141 Use C<guestfs_part_disk> to do that.");
4142
4143   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4144    [InitEmpty, Always, TestRun (
4145       [["part_disk"; "/dev/sda"; "mbr"]]);
4146     InitEmpty, Always, TestRun (
4147       [["part_disk"; "/dev/sda"; "gpt"]])],
4148    "partition whole disk with a single primary partition",
4149    "\
4150 This command is simply a combination of C<guestfs_part_init>
4151 followed by C<guestfs_part_add> to create a single primary partition
4152 covering the whole disk.
4153
4154 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4155 but other possible values are described in C<guestfs_part_init>.");
4156
4157   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4158    [InitEmpty, Always, TestRun (
4159       [["part_disk"; "/dev/sda"; "mbr"];
4160        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4161    "make a partition bootable",
4162    "\
4163 This sets the bootable flag on partition numbered C<partnum> on
4164 device C<device>.  Note that partitions are numbered from 1.
4165
4166 The bootable flag is used by some operating systems (notably
4167 Windows) to determine which partition to boot from.  It is by
4168 no means universally recognized.");
4169
4170   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4171    [InitEmpty, Always, TestRun (
4172       [["part_disk"; "/dev/sda"; "gpt"];
4173        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4174    "set partition name",
4175    "\
4176 This sets the partition name on partition numbered C<partnum> on
4177 device C<device>.  Note that partitions are numbered from 1.
4178
4179 The partition name can only be set on certain types of partition
4180 table.  This works on C<gpt> but not on C<mbr> partitions.");
4181
4182   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4183    [], (* XXX Add a regression test for this. *)
4184    "list partitions on a device",
4185    "\
4186 This command parses the partition table on C<device> and
4187 returns the list of partitions found.
4188
4189 The fields in the returned structure are:
4190
4191 =over 4
4192
4193 =item B<part_num>
4194
4195 Partition number, counting from 1.
4196
4197 =item B<part_start>
4198
4199 Start of the partition I<in bytes>.  To get sectors you have to
4200 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4201
4202 =item B<part_end>
4203
4204 End of the partition in bytes.
4205
4206 =item B<part_size>
4207
4208 Size of the partition in bytes.
4209
4210 =back");
4211
4212   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4213    [InitEmpty, Always, TestOutput (
4214       [["part_disk"; "/dev/sda"; "gpt"];
4215        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4216    "get the partition table type",
4217    "\
4218 This command examines the partition table on C<device> and
4219 returns the partition table type (format) being used.
4220
4221 Common return values include: C<msdos> (a DOS/Windows style MBR
4222 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4223 values are possible, although unusual.  See C<guestfs_part_init>
4224 for a full list.");
4225
4226   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4227    [InitBasicFS, Always, TestOutputBuffer (
4228       [["fill"; "0x63"; "10"; "/test"];
4229        ["read_file"; "/test"]], "cccccccccc")],
4230    "fill a file with octets",
4231    "\
4232 This command creates a new file called C<path>.  The initial
4233 content of the file is C<len> octets of C<c>, where C<c>
4234 must be a number in the range C<[0..255]>.
4235
4236 To fill a file with zero bytes (sparsely), it is
4237 much more efficient to use C<guestfs_truncate_size>.");
4238
4239   ("available", (RErr, [StringList "groups"]), 216, [],
4240    [InitNone, Always, TestRun [["available"; ""]]],
4241    "test availability of some parts of the API",
4242    "\
4243 This command is used to check the availability of some
4244 groups of functionality in the appliance, which not all builds of
4245 the libguestfs appliance will be able to provide.
4246
4247 The libguestfs groups, and the functions that those
4248 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4249
4250 The argument C<groups> is a list of group names, eg:
4251 C<[\"inotify\", \"augeas\"]> would check for the availability of
4252 the Linux inotify functions and Augeas (configuration file
4253 editing) functions.
4254
4255 The command returns no error if I<all> requested groups are available.
4256
4257 It fails with an error if one or more of the requested
4258 groups is unavailable in the appliance.
4259
4260 If an unknown group name is included in the
4261 list of groups then an error is always returned.
4262
4263 I<Notes:>
4264
4265 =over 4
4266
4267 =item *
4268
4269 You must call C<guestfs_launch> before calling this function.
4270
4271 The reason is because we don't know what groups are
4272 supported by the appliance/daemon until it is running and can
4273 be queried.
4274
4275 =item *
4276
4277 If a group of functions is available, this does not necessarily
4278 mean that they will work.  You still have to check for errors
4279 when calling individual API functions even if they are
4280 available.
4281
4282 =item *
4283
4284 It is usually the job of distro packagers to build
4285 complete functionality into the libguestfs appliance.
4286 Upstream libguestfs, if built from source with all
4287 requirements satisfied, will support everything.
4288
4289 =item *
4290
4291 This call was added in version C<1.0.80>.  In previous
4292 versions of libguestfs all you could do would be to speculatively
4293 execute a command to find out if the daemon implemented it.
4294 See also C<guestfs_version>.
4295
4296 =back");
4297
4298   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4299    [InitBasicFS, Always, TestOutputBuffer (
4300       [["write_file"; "/src"; "hello, world"; "0"];
4301        ["dd"; "/src"; "/dest"];
4302        ["read_file"; "/dest"]], "hello, world")],
4303    "copy from source to destination using dd",
4304    "\
4305 This command copies from one source device or file C<src>
4306 to another destination device or file C<dest>.  Normally you
4307 would use this to copy to or from a device or partition, for
4308 example to duplicate a filesystem.
4309
4310 If the destination is a device, it must be as large or larger
4311 than the source file or device, otherwise the copy will fail.
4312 This command cannot do partial copies (see C<guestfs_copy_size>).");
4313
4314   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4315    [InitBasicFS, Always, TestOutputInt (
4316       [["write_file"; "/file"; "hello, world"; "0"];
4317        ["filesize"; "/file"]], 12)],
4318    "return the size of the file in bytes",
4319    "\
4320 This command returns the size of C<file> in bytes.
4321
4322 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4323 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4324 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4325
4326   ("lvrename", (RErr, [String "logvol"; String "newlogvol"]), 219, [],
4327    [InitBasicFSonLVM, Always, TestOutputList (
4328       [["lvrename"; "/dev/VG/LV"; "/dev/VG/LV2"];
4329        ["lvs"]], ["/dev/VG/LV2"])],
4330    "rename an LVM logical volume",
4331    "\
4332 Rename a logical volume C<logvol> with the new name C<newlogvol>.");
4333
4334   ("vgrename", (RErr, [String "volgroup"; String "newvolgroup"]), 220, [],
4335    [InitBasicFSonLVM, Always, TestOutputList (
4336       [["umount"; "/"];
4337        ["vg_activate"; "false"; "VG"];
4338        ["vgrename"; "VG"; "VG2"];
4339        ["vg_activate"; "true"; "VG2"];
4340        ["mount_options"; ""; "/dev/VG2/LV"; "/"];
4341        ["vgs"]], ["VG2"])],
4342    "rename an LVM volume group",
4343    "\
4344 Rename a volume group C<volgroup> with the new name C<newvolgroup>.");
4345
4346   ("initrd_cat", (RBufferOut "content", [Pathname "initrdpath"; String "filename"]), 221, [ProtocolLimitWarning],
4347    [InitISOFS, Always, TestOutputBuffer (
4348       [["initrd_cat"; "/initrd"; "known-4"]], "abc\ndef\nghi")],
4349    "list the contents of a single file in an initrd",
4350    "\
4351 This command unpacks the file C<filename> from the initrd file
4352 called C<initrdpath>.  The filename must be given I<without> the
4353 initial C</> character.
4354
4355 For example, in guestfish you could use the following command
4356 to examine the boot script (usually called C</init>)
4357 contained in a Linux initrd or initramfs image:
4358
4359  initrd-cat /boot/initrd-<version>.img init
4360
4361 See also C<guestfs_initrd_list>.");
4362
4363   ("pvuuid", (RString "uuid", [Device "device"]), 222, [],
4364    [],
4365    "get the UUID of a physical volume",
4366    "\
4367 This command returns the UUID of the LVM PV C<device>.");
4368
4369   ("vguuid", (RString "uuid", [String "vgname"]), 223, [],
4370    [],
4371    "get the UUID of a volume group",
4372    "\
4373 This command returns the UUID of the LVM VG named C<vgname>.");
4374
4375   ("lvuuid", (RString "uuid", [Device "device"]), 224, [],
4376    [],
4377    "get the UUID of a logical volume",
4378    "\
4379 This command returns the UUID of the LVM LV C<device>.");
4380
4381   ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [],
4382    [],
4383    "get the PV UUIDs containing the volume group",
4384    "\
4385 Given a VG called C<vgname>, this returns the UUIDs of all
4386 the physical volumes that this volume group resides on.
4387
4388 You can use this along with C<guestfs_pvs> and C<guestfs_pvuuid>
4389 calls to associate physical volumes and volume groups.
4390
4391 See also C<guestfs_vglvuuids>.");
4392
4393   ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [],
4394    [],
4395    "get the LV UUIDs of all LVs in the volume group",
4396    "\
4397 Given a VG called C<vgname>, this returns the UUIDs of all
4398 the logical volumes created in this volume group.
4399
4400 You can use this along with C<guestfs_lvs> and C<guestfs_lvuuid>
4401 calls to associate logical volumes and volume groups.
4402
4403 See also C<guestfs_vgpvuuids>.");
4404
4405   ("copy_size", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"; Int64 "size"]), 227, [],
4406    [InitBasicFS, Always, TestOutputBuffer (
4407       [["write_file"; "/src"; "hello, world"; "0"];
4408        ["copy_size"; "/src"; "/dest"; "5"];
4409        ["read_file"; "/dest"]], "hello")],
4410    "copy size bytes from source to destination using dd",
4411    "\
4412 This command copies exactly C<size> bytes from one source device
4413 or file C<src> to another destination device or file C<dest>.
4414
4415 Note this will fail if the source is too short or if the destination
4416 is not large enough.");
4417
4418   ("zero_device", (RErr, [Device "device"]), 228, [DangerWillRobinson],
4419    [InitBasicFSonLVM, Always, TestRun (
4420       [["zero_device"; "/dev/VG/LV"]])],
4421    "write zeroes to an entire device",
4422    "\
4423 This command writes zeroes over the entire C<device>.  Compare
4424 with C<guestfs_zero> which just zeroes the first few blocks of
4425 a device.");
4426
4427   ("txz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 229, [],
4428    [InitBasicFS, Always, TestOutput (
4429       [["txz_in"; "../images/helloworld.tar.xz"; "/"];
4430        ["cat"; "/hello"]], "hello\n")],
4431    "unpack compressed tarball to directory",
4432    "\
4433 This command uploads and unpacks local file C<tarball> (an
4434 I<xz compressed> tar file) into C<directory>.");
4435
4436   ("txz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 230, [],
4437    [],
4438    "pack directory into compressed tarball",
4439    "\
4440 This command packs the contents of C<directory> and downloads
4441 it to local file C<tarball> (as an xz compressed tar archive).");
4442
4443   ("ntfsresize", (RErr, [Device "device"]), 231, [Optional "ntfsprogs"],
4444    [],
4445    "resize an NTFS filesystem",
4446    "\
4447 This command resizes an NTFS filesystem, expanding or
4448 shrinking it to the size of the underlying device.
4449 See also L<ntfsresize(8)>.");
4450
4451   ("vgscan", (RErr, []), 232, [],
4452    [InitEmpty, Always, TestRun (
4453       [["vgscan"]])],
4454    "rescan for LVM physical volumes, volume groups and logical volumes",
4455    "\
4456 This rescans all block devices and rebuilds the list of LVM
4457 physical volumes, volume groups and logical volumes.");
4458
4459   ("part_del", (RErr, [Device "device"; Int "partnum"]), 233, [],
4460    [InitEmpty, Always, TestRun (
4461       [["part_init"; "/dev/sda"; "mbr"];
4462        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4463        ["part_del"; "/dev/sda"; "1"]])],
4464    "delete a partition",
4465    "\
4466 This command deletes the partition numbered C<partnum> on C<device>.
4467
4468 Note that in the case of MBR partitioning, deleting an
4469 extended partition also deletes any logical partitions
4470 it contains.");
4471
4472   ("part_get_bootable", (RBool "bootable", [Device "device"; Int "partnum"]), 234, [],
4473    [InitEmpty, Always, TestOutputTrue (
4474       [["part_init"; "/dev/sda"; "mbr"];
4475        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4476        ["part_set_bootable"; "/dev/sda"; "1"; "true"];
4477        ["part_get_bootable"; "/dev/sda"; "1"]])],
4478    "return true if a partition is bootable",
4479    "\
4480 This command returns true if the partition C<partnum> on
4481 C<device> has the bootable flag set.
4482
4483 See also C<guestfs_part_set_bootable>.");
4484
4485   ("part_get_mbr_id", (RInt "idbyte", [Device "device"; Int "partnum"]), 235, [FishOutput FishOutputHexadecimal],
4486    [InitEmpty, Always, TestOutputInt (
4487       [["part_init"; "/dev/sda"; "mbr"];
4488        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4489        ["part_set_mbr_id"; "/dev/sda"; "1"; "0x7f"];
4490        ["part_get_mbr_id"; "/dev/sda"; "1"]], 0x7f)],
4491    "get the MBR type byte (ID byte) from a partition",
4492    "\
4493 Returns the MBR type byte (also known as the ID byte) from
4494 the numbered partition C<partnum>.
4495
4496 Note that only MBR (old DOS-style) partitions have type bytes.
4497 You will get undefined results for other partition table
4498 types (see C<guestfs_part_get_parttype>).");
4499
4500   ("part_set_mbr_id", (RErr, [Device "device"; Int "partnum"; Int "idbyte"]), 236, [],
4501    [], (* tested by part_get_mbr_id *)
4502    "set the MBR type byte (ID byte) of a partition",
4503    "\
4504 Sets the MBR type byte (also known as the ID byte) of
4505 the numbered partition C<partnum> to C<idbyte>.  Note
4506 that the type bytes quoted in most documentation are
4507 in fact hexadecimal numbers, but usually documented
4508 without any leading \"0x\" which might be confusing.
4509
4510 Note that only MBR (old DOS-style) partitions have type bytes.
4511 You will get undefined results for other partition table
4512 types (see C<guestfs_part_get_parttype>).");
4513
4514   ("checksum_device", (RString "checksum", [String "csumtype"; Device "device"]), 237, [],
4515    [InitISOFS, Always, TestOutput (
4516       [["checksum_device"; "md5"; "/dev/sdd"]],
4517       (Digest.to_hex (Digest.file "images/test.iso")))],
4518    "compute MD5, SHAx or CRC checksum of the contents of a device",
4519    "\
4520 This call computes the MD5, SHAx or CRC checksum of the
4521 contents of the device named C<device>.  For the types of
4522 checksums supported see the C<guestfs_checksum> command.");
4523
4524   ("lvresize_free", (RErr, [Device "lv"; Int "percent"]), 238, [Optional "lvm2"],
4525    [InitNone, Always, TestRun (
4526       [["part_disk"; "/dev/sda"; "mbr"];
4527        ["pvcreate"; "/dev/sda1"];
4528        ["vgcreate"; "VG"; "/dev/sda1"];
4529        ["lvcreate"; "LV"; "VG"; "10"];
4530        ["lvresize_free"; "/dev/VG/LV"; "100"]])],
4531    "expand an LV to fill free space",
4532    "\
4533 This expands an existing logical volume C<lv> so that it fills
4534 C<pc>% of the remaining free space in the volume group.  Commonly
4535 you would call this with pc = 100 which expands the logical volume
4536 as much as possible, using all remaining free space in the volume
4537 group.");
4538
4539   ("aug_clear", (RErr, [String "augpath"]), 239, [Optional "augeas"],
4540    [], (* XXX Augeas code needs tests. *)
4541    "clear Augeas path",
4542    "\
4543 Set the value associated with C<path> to C<NULL>.  This
4544 is the same as the L<augtool(1)> C<clear> command.");
4545
4546   ("get_umask", (RInt "mask", []), 240, [FishOutput FishOutputOctal],
4547    [InitEmpty, Always, TestOutputInt (
4548       [["get_umask"]], 0o22)],
4549    "get the current umask",
4550    "\
4551 Return the current umask.  By default the umask is C<022>
4552 unless it has been set by calling C<guestfs_umask>.");
4553
4554   ("debug_upload", (RErr, [FileIn "filename"; String "tmpname"; Int "mode"]), 241, [],
4555    [],
4556    "upload a file to the appliance (internal use only)",
4557    "\
4558 The C<guestfs_debug_upload> command uploads a file to
4559 the libguestfs appliance.
4560
4561 There is no comprehensive help for this command.  You have
4562 to look at the file C<daemon/debug.c> in the libguestfs source
4563 to find out what it is for.");
4564
4565   ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [],
4566    [InitBasicFS, Always, TestOutput (
4567       [["base64_in"; "../images/hello.b64"; "/hello"];
4568        ["cat"; "/hello"]], "hello\n")],
4569    "upload base64-encoded data to file",
4570    "\
4571 This command uploads base64-encoded data from C<base64file>
4572 to C<filename>.");
4573
4574   ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [],
4575    [],
4576    "download file and encode as base64",
4577    "\
4578 This command downloads the contents of C<filename>, writing
4579 it out to local file C<base64file> encoded as base64.");
4580
4581   ("checksums_out", (RErr, [String "csumtype"; Pathname "directory"; FileOut "sumsfile"]), 244, [],
4582    [],
4583    "compute MD5, SHAx or CRC checksum of files in a directory",
4584    "\
4585 This command computes the checksums of all regular files in
4586 C<directory> and then emits a list of those checksums to
4587 the local output file C<sumsfile>.
4588
4589 This can be used for verifying the integrity of a virtual
4590 machine.  However to be properly secure you should pay
4591 attention to the output of the checksum command (it uses
4592 the ones from GNU coreutils).  In particular when the
4593 filename is not printable, coreutils uses a special
4594 backslash syntax.  For more information, see the GNU
4595 coreutils info file.");
4596
4597 ]
4598
4599 let all_functions = non_daemon_functions @ daemon_functions
4600
4601 (* In some places we want the functions to be displayed sorted
4602  * alphabetically, so this is useful:
4603  *)
4604 let all_functions_sorted =
4605   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4606                compare n1 n2) all_functions
4607
4608 (* Field types for structures. *)
4609 type field =
4610   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4611   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4612   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4613   | FUInt32
4614   | FInt32
4615   | FUInt64
4616   | FInt64
4617   | FBytes                      (* Any int measure that counts bytes. *)
4618   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4619   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4620
4621 (* Because we generate extra parsing code for LVM command line tools,
4622  * we have to pull out the LVM columns separately here.
4623  *)
4624 let lvm_pv_cols = [
4625   "pv_name", FString;
4626   "pv_uuid", FUUID;
4627   "pv_fmt", FString;
4628   "pv_size", FBytes;
4629   "dev_size", FBytes;
4630   "pv_free", FBytes;
4631   "pv_used", FBytes;
4632   "pv_attr", FString (* XXX *);
4633   "pv_pe_count", FInt64;
4634   "pv_pe_alloc_count", FInt64;
4635   "pv_tags", FString;
4636   "pe_start", FBytes;
4637   "pv_mda_count", FInt64;
4638   "pv_mda_free", FBytes;
4639   (* Not in Fedora 10:
4640      "pv_mda_size", FBytes;
4641   *)
4642 ]
4643 let lvm_vg_cols = [
4644   "vg_name", FString;
4645   "vg_uuid", FUUID;
4646   "vg_fmt", FString;
4647   "vg_attr", FString (* XXX *);
4648   "vg_size", FBytes;
4649   "vg_free", FBytes;
4650   "vg_sysid", FString;
4651   "vg_extent_size", FBytes;
4652   "vg_extent_count", FInt64;
4653   "vg_free_count", FInt64;
4654   "max_lv", FInt64;
4655   "max_pv", FInt64;
4656   "pv_count", FInt64;
4657   "lv_count", FInt64;
4658   "snap_count", FInt64;
4659   "vg_seqno", FInt64;
4660   "vg_tags", FString;
4661   "vg_mda_count", FInt64;
4662   "vg_mda_free", FBytes;
4663   (* Not in Fedora 10:
4664      "vg_mda_size", FBytes;
4665   *)
4666 ]
4667 let lvm_lv_cols = [
4668   "lv_name", FString;
4669   "lv_uuid", FUUID;
4670   "lv_attr", FString (* XXX *);
4671   "lv_major", FInt64;
4672   "lv_minor", FInt64;
4673   "lv_kernel_major", FInt64;
4674   "lv_kernel_minor", FInt64;
4675   "lv_size", FBytes;
4676   "seg_count", FInt64;
4677   "origin", FString;
4678   "snap_percent", FOptPercent;
4679   "copy_percent", FOptPercent;
4680   "move_pv", FString;
4681   "lv_tags", FString;
4682   "mirror_log", FString;
4683   "modules", FString;
4684 ]
4685
4686 (* Names and fields in all structures (in RStruct and RStructList)
4687  * that we support.
4688  *)
4689 let structs = [
4690   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4691    * not use this struct in any new code.
4692    *)
4693   "int_bool", [
4694     "i", FInt32;                (* for historical compatibility *)
4695     "b", FInt32;                (* for historical compatibility *)
4696   ];
4697
4698   (* LVM PVs, VGs, LVs. *)
4699   "lvm_pv", lvm_pv_cols;
4700   "lvm_vg", lvm_vg_cols;
4701   "lvm_lv", lvm_lv_cols;
4702
4703   (* Column names and types from stat structures.
4704    * NB. Can't use things like 'st_atime' because glibc header files
4705    * define some of these as macros.  Ugh.
4706    *)
4707   "stat", [
4708     "dev", FInt64;
4709     "ino", FInt64;
4710     "mode", FInt64;
4711     "nlink", FInt64;
4712     "uid", FInt64;
4713     "gid", FInt64;
4714     "rdev", FInt64;
4715     "size", FInt64;
4716     "blksize", FInt64;
4717     "blocks", FInt64;
4718     "atime", FInt64;
4719     "mtime", FInt64;
4720     "ctime", FInt64;
4721   ];
4722   "statvfs", [
4723     "bsize", FInt64;
4724     "frsize", FInt64;
4725     "blocks", FInt64;
4726     "bfree", FInt64;
4727     "bavail", FInt64;
4728     "files", FInt64;
4729     "ffree", FInt64;
4730     "favail", FInt64;
4731     "fsid", FInt64;
4732     "flag", FInt64;
4733     "namemax", FInt64;
4734   ];
4735
4736   (* Column names in dirent structure. *)
4737   "dirent", [
4738     "ino", FInt64;
4739     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4740     "ftyp", FChar;
4741     "name", FString;
4742   ];
4743
4744   (* Version numbers. *)
4745   "version", [
4746     "major", FInt64;
4747     "minor", FInt64;
4748     "release", FInt64;
4749     "extra", FString;
4750   ];
4751
4752   (* Extended attribute. *)
4753   "xattr", [
4754     "attrname", FString;
4755     "attrval", FBuffer;
4756   ];
4757
4758   (* Inotify events. *)
4759   "inotify_event", [
4760     "in_wd", FInt64;
4761     "in_mask", FUInt32;
4762     "in_cookie", FUInt32;
4763     "in_name", FString;
4764   ];
4765
4766   (* Partition table entry. *)
4767   "partition", [
4768     "part_num", FInt32;
4769     "part_start", FBytes;
4770     "part_end", FBytes;
4771     "part_size", FBytes;
4772   ];
4773 ] (* end of structs *)
4774
4775 (* Ugh, Java has to be different ..
4776  * These names are also used by the Haskell bindings.
4777  *)
4778 let java_structs = [
4779   "int_bool", "IntBool";
4780   "lvm_pv", "PV";
4781   "lvm_vg", "VG";
4782   "lvm_lv", "LV";
4783   "stat", "Stat";
4784   "statvfs", "StatVFS";
4785   "dirent", "Dirent";
4786   "version", "Version";
4787   "xattr", "XAttr";
4788   "inotify_event", "INotifyEvent";
4789   "partition", "Partition";
4790 ]
4791
4792 (* What structs are actually returned. *)
4793 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4794
4795 (* Returns a list of RStruct/RStructList structs that are returned
4796  * by any function.  Each element of returned list is a pair:
4797  *
4798  * (structname, RStructOnly)
4799  *    == there exists function which returns RStruct (_, structname)
4800  * (structname, RStructListOnly)
4801  *    == there exists function which returns RStructList (_, structname)
4802  * (structname, RStructAndList)
4803  *    == there are functions returning both RStruct (_, structname)
4804  *                                      and RStructList (_, structname)
4805  *)
4806 let rstructs_used_by functions =
4807   (* ||| is a "logical OR" for rstructs_used_t *)
4808   let (|||) a b =
4809     match a, b with
4810     | RStructAndList, _
4811     | _, RStructAndList -> RStructAndList
4812     | RStructOnly, RStructListOnly
4813     | RStructListOnly, RStructOnly -> RStructAndList
4814     | RStructOnly, RStructOnly -> RStructOnly
4815     | RStructListOnly, RStructListOnly -> RStructListOnly
4816   in
4817
4818   let h = Hashtbl.create 13 in
4819
4820   (* if elem->oldv exists, update entry using ||| operator,
4821    * else just add elem->newv to the hash
4822    *)
4823   let update elem newv =
4824     try  let oldv = Hashtbl.find h elem in
4825          Hashtbl.replace h elem (newv ||| oldv)
4826     with Not_found -> Hashtbl.add h elem newv
4827   in
4828
4829   List.iter (
4830     fun (_, style, _, _, _, _, _) ->
4831       match fst style with
4832       | RStruct (_, structname) -> update structname RStructOnly
4833       | RStructList (_, structname) -> update structname RStructListOnly
4834       | _ -> ()
4835   ) functions;
4836
4837   (* return key->values as a list of (key,value) *)
4838   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4839
4840 (* Used for testing language bindings. *)
4841 type callt =
4842   | CallString of string
4843   | CallOptString of string option
4844   | CallStringList of string list
4845   | CallInt of int
4846   | CallInt64 of int64
4847   | CallBool of bool
4848
4849 (* Used to memoize the result of pod2text. *)
4850 let pod2text_memo_filename = "src/.pod2text.data"
4851 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4852   try
4853     let chan = open_in pod2text_memo_filename in
4854     let v = input_value chan in
4855     close_in chan;
4856     v
4857   with
4858     _ -> Hashtbl.create 13
4859 let pod2text_memo_updated () =
4860   let chan = open_out pod2text_memo_filename in
4861   output_value chan pod2text_memo;
4862   close_out chan
4863
4864 (* Useful functions.
4865  * Note we don't want to use any external OCaml libraries which
4866  * makes this a bit harder than it should be.
4867  *)
4868 module StringMap = Map.Make (String)
4869
4870 let failwithf fs = ksprintf failwith fs
4871
4872 let unique = let i = ref 0 in fun () -> incr i; !i
4873
4874 let replace_char s c1 c2 =
4875   let s2 = String.copy s in
4876   let r = ref false in
4877   for i = 0 to String.length s2 - 1 do
4878     if String.unsafe_get s2 i = c1 then (
4879       String.unsafe_set s2 i c2;
4880       r := true
4881     )
4882   done;
4883   if not !r then s else s2
4884
4885 let isspace c =
4886   c = ' '
4887   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4888
4889 let triml ?(test = isspace) str =
4890   let i = ref 0 in
4891   let n = ref (String.length str) in
4892   while !n > 0 && test str.[!i]; do
4893     decr n;
4894     incr i
4895   done;
4896   if !i = 0 then str
4897   else String.sub str !i !n
4898
4899 let trimr ?(test = isspace) str =
4900   let n = ref (String.length str) in
4901   while !n > 0 && test str.[!n-1]; do
4902     decr n
4903   done;
4904   if !n = String.length str then str
4905   else String.sub str 0 !n
4906
4907 let trim ?(test = isspace) str =
4908   trimr ~test (triml ~test str)
4909
4910 let rec find s sub =
4911   let len = String.length s in
4912   let sublen = String.length sub in
4913   let rec loop i =
4914     if i <= len-sublen then (
4915       let rec loop2 j =
4916         if j < sublen then (
4917           if s.[i+j] = sub.[j] then loop2 (j+1)
4918           else -1
4919         ) else
4920           i (* found *)
4921       in
4922       let r = loop2 0 in
4923       if r = -1 then loop (i+1) else r
4924     ) else
4925       -1 (* not found *)
4926   in
4927   loop 0
4928
4929 let rec replace_str s s1 s2 =
4930   let len = String.length s in
4931   let sublen = String.length s1 in
4932   let i = find s s1 in
4933   if i = -1 then s
4934   else (
4935     let s' = String.sub s 0 i in
4936     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4937     s' ^ s2 ^ replace_str s'' s1 s2
4938   )
4939
4940 let rec string_split sep str =
4941   let len = String.length str in
4942   let seplen = String.length sep in
4943   let i = find str sep in
4944   if i = -1 then [str]
4945   else (
4946     let s' = String.sub str 0 i in
4947     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4948     s' :: string_split sep s''
4949   )
4950
4951 let files_equal n1 n2 =
4952   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4953   match Sys.command cmd with
4954   | 0 -> true
4955   | 1 -> false
4956   | i -> failwithf "%s: failed with error code %d" cmd i
4957
4958 let rec filter_map f = function
4959   | [] -> []
4960   | x :: xs ->
4961       match f x with
4962       | Some y -> y :: filter_map f xs
4963       | None -> filter_map f xs
4964
4965 let rec find_map f = function
4966   | [] -> raise Not_found
4967   | x :: xs ->
4968       match f x with
4969       | Some y -> y
4970       | None -> find_map f xs
4971
4972 let iteri f xs =
4973   let rec loop i = function
4974     | [] -> ()
4975     | x :: xs -> f i x; loop (i+1) xs
4976   in
4977   loop 0 xs
4978
4979 let mapi f xs =
4980   let rec loop i = function
4981     | [] -> []
4982     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4983   in
4984   loop 0 xs
4985
4986 let count_chars c str =
4987   let count = ref 0 in
4988   for i = 0 to String.length str - 1 do
4989     if c = String.unsafe_get str i then incr count
4990   done;
4991   !count
4992
4993 let name_of_argt = function
4994   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4995   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4996   | FileIn n | FileOut n -> n
4997
4998 let java_name_of_struct typ =
4999   try List.assoc typ java_structs
5000   with Not_found ->
5001     failwithf
5002       "java_name_of_struct: no java_structs entry corresponding to %s" typ
5003
5004 let cols_of_struct typ =
5005   try List.assoc typ structs
5006   with Not_found ->
5007     failwithf "cols_of_struct: unknown struct %s" typ
5008
5009 let seq_of_test = function
5010   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
5011   | TestOutputListOfDevices (s, _)
5012   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
5013   | TestOutputTrue s | TestOutputFalse s
5014   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
5015   | TestOutputStruct (s, _)
5016   | TestLastFail s -> s
5017
5018 (* Handling for function flags. *)
5019 let protocol_limit_warning =
5020   "Because of the message protocol, there is a transfer limit
5021 of somewhere between 2MB and 4MB.  See L<guestfs(3)/PROTOCOL LIMITS>."
5022
5023 let danger_will_robinson =
5024   "B<This command is dangerous.  Without careful use you
5025 can easily destroy all your data>."
5026
5027 let deprecation_notice flags =
5028   try
5029     let alt =
5030       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
5031     let txt =
5032       sprintf "This function is deprecated.
5033 In new code, use the C<%s> call instead.
5034
5035 Deprecated functions will not be removed from the API, but the
5036 fact that they are deprecated indicates that there are problems
5037 with correct use of these functions." alt in
5038     Some txt
5039   with
5040     Not_found -> None
5041
5042 (* Create list of optional groups. *)
5043 let optgroups =
5044   let h = Hashtbl.create 13 in
5045   List.iter (
5046     fun (name, _, _, flags, _, _, _) ->
5047       List.iter (
5048         function
5049         | Optional group ->
5050             let names = try Hashtbl.find h group with Not_found -> [] in
5051             Hashtbl.replace h group (name :: names)
5052         | _ -> ()
5053       ) flags
5054   ) daemon_functions;
5055   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
5056   let groups =
5057     List.map (
5058       fun group -> group, List.sort compare (Hashtbl.find h group)
5059     ) groups in
5060   List.sort (fun x y -> compare (fst x) (fst y)) groups
5061
5062 (* Check function names etc. for consistency. *)
5063 let check_functions () =
5064   let contains_uppercase str =
5065     let len = String.length str in
5066     let rec loop i =
5067       if i >= len then false
5068       else (
5069         let c = str.[i] in
5070         if c >= 'A' && c <= 'Z' then true
5071         else loop (i+1)
5072       )
5073     in
5074     loop 0
5075   in
5076
5077   (* Check function names. *)
5078   List.iter (
5079     fun (name, _, _, _, _, _, _) ->
5080       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
5081         failwithf "function name %s does not need 'guestfs' prefix" name;
5082       if name = "" then
5083         failwithf "function name is empty";
5084       if name.[0] < 'a' || name.[0] > 'z' then
5085         failwithf "function name %s must start with lowercase a-z" name;
5086       if String.contains name '-' then
5087         failwithf "function name %s should not contain '-', use '_' instead."
5088           name
5089   ) all_functions;
5090
5091   (* Check function parameter/return names. *)
5092   List.iter (
5093     fun (name, style, _, _, _, _, _) ->
5094       let check_arg_ret_name n =
5095         if contains_uppercase n then
5096           failwithf "%s param/ret %s should not contain uppercase chars"
5097             name n;
5098         if String.contains n '-' || String.contains n '_' then
5099           failwithf "%s param/ret %s should not contain '-' or '_'"
5100             name n;
5101         if n = "value" then
5102           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;
5103         if n = "int" || n = "char" || n = "short" || n = "long" then
5104           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
5105         if n = "i" || n = "n" then
5106           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
5107         if n = "argv" || n = "args" then
5108           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
5109
5110         (* List Haskell, OCaml and C keywords here.
5111          * http://www.haskell.org/haskellwiki/Keywords
5112          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
5113          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
5114          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
5115          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
5116          * Omitting _-containing words, since they're handled above.
5117          * Omitting the OCaml reserved word, "val", is ok,
5118          * and saves us from renaming several parameters.
5119          *)
5120         let reserved = [
5121           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
5122           "char"; "class"; "const"; "constraint"; "continue"; "data";
5123           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
5124           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
5125           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
5126           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
5127           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
5128           "interface";
5129           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
5130           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
5131           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
5132           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
5133           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
5134           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
5135           "volatile"; "when"; "where"; "while";
5136           ] in
5137         if List.mem n reserved then
5138           failwithf "%s has param/ret using reserved word %s" name n;
5139       in
5140
5141       (match fst style with
5142        | RErr -> ()
5143        | RInt n | RInt64 n | RBool n
5144        | RConstString n | RConstOptString n | RString n
5145        | RStringList n | RStruct (n, _) | RStructList (n, _)
5146        | RHashtable n | RBufferOut n ->
5147            check_arg_ret_name n
5148       );
5149       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
5150   ) all_functions;
5151
5152   (* Check short descriptions. *)
5153   List.iter (
5154     fun (name, _, _, _, _, shortdesc, _) ->
5155       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
5156         failwithf "short description of %s should begin with lowercase." name;
5157       let c = shortdesc.[String.length shortdesc-1] in
5158       if c = '\n' || c = '.' then
5159         failwithf "short description of %s should not end with . or \\n." name
5160   ) all_functions;
5161
5162   (* Check long descriptions. *)
5163   List.iter (
5164     fun (name, _, _, _, _, _, longdesc) ->
5165       if longdesc.[String.length longdesc-1] = '\n' then
5166         failwithf "long description of %s should not end with \\n." name
5167   ) all_functions;
5168
5169   (* Check proc_nrs. *)
5170   List.iter (
5171     fun (name, _, proc_nr, _, _, _, _) ->
5172       if proc_nr <= 0 then
5173         failwithf "daemon function %s should have proc_nr > 0" name
5174   ) daemon_functions;
5175
5176   List.iter (
5177     fun (name, _, proc_nr, _, _, _, _) ->
5178       if proc_nr <> -1 then
5179         failwithf "non-daemon function %s should have proc_nr -1" name
5180   ) non_daemon_functions;
5181
5182   let proc_nrs =
5183     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
5184       daemon_functions in
5185   let proc_nrs =
5186     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
5187   let rec loop = function
5188     | [] -> ()
5189     | [_] -> ()
5190     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
5191         loop rest
5192     | (name1,nr1) :: (name2,nr2) :: _ ->
5193         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
5194           name1 name2 nr1 nr2
5195   in
5196   loop proc_nrs;
5197
5198   (* Check tests. *)
5199   List.iter (
5200     function
5201       (* Ignore functions that have no tests.  We generate a
5202        * warning when the user does 'make check' instead.
5203        *)
5204     | name, _, _, _, [], _, _ -> ()
5205     | name, _, _, _, tests, _, _ ->
5206         let funcs =
5207           List.map (
5208             fun (_, _, test) ->
5209               match seq_of_test test with
5210               | [] ->
5211                   failwithf "%s has a test containing an empty sequence" name
5212               | cmds -> List.map List.hd cmds
5213           ) tests in
5214         let funcs = List.flatten funcs in
5215
5216         let tested = List.mem name funcs in
5217
5218         if not tested then
5219           failwithf "function %s has tests but does not test itself" name
5220   ) all_functions
5221
5222 (* 'pr' prints to the current output file. *)
5223 let chan = ref Pervasives.stdout
5224 let lines = ref 0
5225 let pr fs =
5226   ksprintf
5227     (fun str ->
5228        let i = count_chars '\n' str in
5229        lines := !lines + i;
5230        output_string !chan str
5231     ) fs
5232
5233 let copyright_years =
5234   let this_year = 1900 + (localtime (time ())).tm_year in
5235   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
5236
5237 (* Generate a header block in a number of standard styles. *)
5238 type comment_style =
5239     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
5240 type license = GPLv2plus | LGPLv2plus
5241
5242 let generate_header ?(extra_inputs = []) comment license =
5243   let inputs = "src/generator.ml" :: extra_inputs in
5244   let c = match comment with
5245     | CStyle ->         pr "/* "; " *"
5246     | CPlusPlusStyle -> pr "// "; "//"
5247     | HashStyle ->      pr "# ";  "#"
5248     | OCamlStyle ->     pr "(* "; " *"
5249     | HaskellStyle ->   pr "{- "; "  " in
5250   pr "libguestfs generated file\n";
5251   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
5252   List.iter (pr "%s   %s\n" c) inputs;
5253   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
5254   pr "%s\n" c;
5255   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
5256   pr "%s\n" c;
5257   (match license with
5258    | GPLv2plus ->
5259        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
5260        pr "%s it under the terms of the GNU General Public License as published by\n" c;
5261        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
5262        pr "%s (at your option) any later version.\n" c;
5263        pr "%s\n" c;
5264        pr "%s This program is distributed in the hope that it will be useful,\n" c;
5265        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5266        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
5267        pr "%s GNU General Public License for more details.\n" c;
5268        pr "%s\n" c;
5269        pr "%s You should have received a copy of the GNU General Public License along\n" c;
5270        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
5271        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
5272
5273    | LGPLv2plus ->
5274        pr "%s This library is free software; you can redistribute it and/or\n" c;
5275        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
5276        pr "%s License as published by the Free Software Foundation; either\n" c;
5277        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
5278        pr "%s\n" c;
5279        pr "%s This library is distributed in the hope that it will be useful,\n" c;
5280        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5281        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
5282        pr "%s Lesser General Public License for more details.\n" c;
5283        pr "%s\n" c;
5284        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
5285        pr "%s License along with this library; if not, write to the Free Software\n" c;
5286        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
5287   );
5288   (match comment with
5289    | CStyle -> pr " */\n"
5290    | CPlusPlusStyle
5291    | HashStyle -> ()
5292    | OCamlStyle -> pr " *)\n"
5293    | HaskellStyle -> pr "-}\n"
5294   );
5295   pr "\n"
5296
5297 (* Start of main code generation functions below this line. *)
5298
5299 (* Generate the pod documentation for the C API. *)
5300 let rec generate_actions_pod () =
5301   List.iter (
5302     fun (shortname, style, _, flags, _, _, longdesc) ->
5303       if not (List.mem NotInDocs flags) then (
5304         let name = "guestfs_" ^ shortname in
5305         pr "=head2 %s\n\n" name;
5306         pr " ";
5307         generate_prototype ~extern:false ~handle:"g" name style;
5308         pr "\n\n";
5309         pr "%s\n\n" longdesc;
5310         (match fst style with
5311          | RErr ->
5312              pr "This function returns 0 on success or -1 on error.\n\n"
5313          | RInt _ ->
5314              pr "On error this function returns -1.\n\n"
5315          | RInt64 _ ->
5316              pr "On error this function returns -1.\n\n"
5317          | RBool _ ->
5318              pr "This function returns a C truth value on success or -1 on error.\n\n"
5319          | RConstString _ ->
5320              pr "This function returns a string, or NULL on error.
5321 The string is owned by the guest handle and must I<not> be freed.\n\n"
5322          | RConstOptString _ ->
5323              pr "This function returns a string which may be NULL.
5324 There is way to return an error from this function.
5325 The string is owned by the guest handle and must I<not> be freed.\n\n"
5326          | RString _ ->
5327              pr "This function returns a string, or NULL on error.
5328 I<The caller must free the returned string after use>.\n\n"
5329          | RStringList _ ->
5330              pr "This function returns a NULL-terminated array of strings
5331 (like L<environ(3)>), or NULL if there was an error.
5332 I<The caller must free the strings and the array after use>.\n\n"
5333          | RStruct (_, typ) ->
5334              pr "This function returns a C<struct guestfs_%s *>,
5335 or NULL if there was an error.
5336 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
5337          | RStructList (_, typ) ->
5338              pr "This function returns a C<struct guestfs_%s_list *>
5339 (see E<lt>guestfs-structs.hE<gt>),
5340 or NULL if there was an error.
5341 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
5342          | RHashtable _ ->
5343              pr "This function returns a NULL-terminated array of
5344 strings, or NULL if there was an error.
5345 The array of strings will always have length C<2n+1>, where
5346 C<n> keys and values alternate, followed by the trailing NULL entry.
5347 I<The caller must free the strings and the array after use>.\n\n"
5348          | RBufferOut _ ->
5349              pr "This function returns a buffer, or NULL on error.
5350 The size of the returned buffer is written to C<*size_r>.
5351 I<The caller must free the returned buffer after use>.\n\n"
5352         );
5353         if List.mem ProtocolLimitWarning flags then
5354           pr "%s\n\n" protocol_limit_warning;
5355         if List.mem DangerWillRobinson flags then
5356           pr "%s\n\n" danger_will_robinson;
5357         match deprecation_notice flags with
5358         | None -> ()
5359         | Some txt -> pr "%s\n\n" txt
5360       )
5361   ) all_functions_sorted
5362
5363 and generate_structs_pod () =
5364   (* Structs documentation. *)
5365   List.iter (
5366     fun (typ, cols) ->
5367       pr "=head2 guestfs_%s\n" typ;
5368       pr "\n";
5369       pr " struct guestfs_%s {\n" typ;
5370       List.iter (
5371         function
5372         | name, FChar -> pr "   char %s;\n" name
5373         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5374         | name, FInt32 -> pr "   int32_t %s;\n" name
5375         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5376         | name, FInt64 -> pr "   int64_t %s;\n" name
5377         | name, FString -> pr "   char *%s;\n" name
5378         | name, FBuffer ->
5379             pr "   /* The next two fields describe a byte array. */\n";
5380             pr "   uint32_t %s_len;\n" name;
5381             pr "   char *%s;\n" name
5382         | name, FUUID ->
5383             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5384             pr "   char %s[32];\n" name
5385         | name, FOptPercent ->
5386             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5387             pr "   float %s;\n" name
5388       ) cols;
5389       pr " };\n";
5390       pr " \n";
5391       pr " struct guestfs_%s_list {\n" typ;
5392       pr "   uint32_t len; /* Number of elements in list. */\n";
5393       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5394       pr " };\n";
5395       pr " \n";
5396       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5397       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5398         typ typ;
5399       pr "\n"
5400   ) structs
5401
5402 and generate_availability_pod () =
5403   (* Availability documentation. *)
5404   pr "=over 4\n";
5405   pr "\n";
5406   List.iter (
5407     fun (group, functions) ->
5408       pr "=item B<%s>\n" group;
5409       pr "\n";
5410       pr "The following functions:\n";
5411       List.iter (pr "L</guestfs_%s>\n") functions;
5412       pr "\n"
5413   ) optgroups;
5414   pr "=back\n";
5415   pr "\n"
5416
5417 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5418  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5419  *
5420  * We have to use an underscore instead of a dash because otherwise
5421  * rpcgen generates incorrect code.
5422  *
5423  * This header is NOT exported to clients, but see also generate_structs_h.
5424  *)
5425 and generate_xdr () =
5426   generate_header CStyle LGPLv2plus;
5427
5428   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5429   pr "typedef string str<>;\n";
5430   pr "\n";
5431
5432   (* Internal structures. *)
5433   List.iter (
5434     function
5435     | typ, cols ->
5436         pr "struct guestfs_int_%s {\n" typ;
5437         List.iter (function
5438                    | name, FChar -> pr "  char %s;\n" name
5439                    | name, FString -> pr "  string %s<>;\n" name
5440                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5441                    | name, FUUID -> pr "  opaque %s[32];\n" name
5442                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5443                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5444                    | name, FOptPercent -> pr "  float %s;\n" name
5445                   ) cols;
5446         pr "};\n";
5447         pr "\n";
5448         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5449         pr "\n";
5450   ) structs;
5451
5452   List.iter (
5453     fun (shortname, style, _, _, _, _, _) ->
5454       let name = "guestfs_" ^ shortname in
5455
5456       (match snd style with
5457        | [] -> ()
5458        | args ->
5459            pr "struct %s_args {\n" name;
5460            List.iter (
5461              function
5462              | Pathname n | Device n | Dev_or_Path n | String n ->
5463                  pr "  string %s<>;\n" n
5464              | OptString n -> pr "  str *%s;\n" n
5465              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5466              | Bool n -> pr "  bool %s;\n" n
5467              | Int n -> pr "  int %s;\n" n
5468              | Int64 n -> pr "  hyper %s;\n" n
5469              | FileIn _ | FileOut _ -> ()
5470            ) args;
5471            pr "};\n\n"
5472       );
5473       (match fst style with
5474        | RErr -> ()
5475        | RInt n ->
5476            pr "struct %s_ret {\n" name;
5477            pr "  int %s;\n" n;
5478            pr "};\n\n"
5479        | RInt64 n ->
5480            pr "struct %s_ret {\n" name;
5481            pr "  hyper %s;\n" n;
5482            pr "};\n\n"
5483        | RBool n ->
5484            pr "struct %s_ret {\n" name;
5485            pr "  bool %s;\n" n;
5486            pr "};\n\n"
5487        | RConstString _ | RConstOptString _ ->
5488            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5489        | RString n ->
5490            pr "struct %s_ret {\n" name;
5491            pr "  string %s<>;\n" n;
5492            pr "};\n\n"
5493        | RStringList n ->
5494            pr "struct %s_ret {\n" name;
5495            pr "  str %s<>;\n" n;
5496            pr "};\n\n"
5497        | RStruct (n, typ) ->
5498            pr "struct %s_ret {\n" name;
5499            pr "  guestfs_int_%s %s;\n" typ n;
5500            pr "};\n\n"
5501        | RStructList (n, typ) ->
5502            pr "struct %s_ret {\n" name;
5503            pr "  guestfs_int_%s_list %s;\n" typ n;
5504            pr "};\n\n"
5505        | RHashtable n ->
5506            pr "struct %s_ret {\n" name;
5507            pr "  str %s<>;\n" n;
5508            pr "};\n\n"
5509        | RBufferOut n ->
5510            pr "struct %s_ret {\n" name;
5511            pr "  opaque %s<>;\n" n;
5512            pr "};\n\n"
5513       );
5514   ) daemon_functions;
5515
5516   (* Table of procedure numbers. *)
5517   pr "enum guestfs_procedure {\n";
5518   List.iter (
5519     fun (shortname, _, proc_nr, _, _, _, _) ->
5520       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5521   ) daemon_functions;
5522   pr "  GUESTFS_PROC_NR_PROCS\n";
5523   pr "};\n";
5524   pr "\n";
5525
5526   (* Having to choose a maximum message size is annoying for several
5527    * reasons (it limits what we can do in the API), but it (a) makes
5528    * the protocol a lot simpler, and (b) provides a bound on the size
5529    * of the daemon which operates in limited memory space.
5530    *)
5531   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5532   pr "\n";
5533
5534   (* Message header, etc. *)
5535   pr "\
5536 /* The communication protocol is now documented in the guestfs(3)
5537  * manpage.
5538  */
5539
5540 const GUESTFS_PROGRAM = 0x2000F5F5;
5541 const GUESTFS_PROTOCOL_VERSION = 1;
5542
5543 /* These constants must be larger than any possible message length. */
5544 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5545 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5546
5547 enum guestfs_message_direction {
5548   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5549   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5550 };
5551
5552 enum guestfs_message_status {
5553   GUESTFS_STATUS_OK = 0,
5554   GUESTFS_STATUS_ERROR = 1
5555 };
5556
5557 const GUESTFS_ERROR_LEN = 256;
5558
5559 struct guestfs_message_error {
5560   string error_message<GUESTFS_ERROR_LEN>;
5561 };
5562
5563 struct guestfs_message_header {
5564   unsigned prog;                     /* GUESTFS_PROGRAM */
5565   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5566   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5567   guestfs_message_direction direction;
5568   unsigned serial;                   /* message serial number */
5569   guestfs_message_status status;
5570 };
5571
5572 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5573
5574 struct guestfs_chunk {
5575   int cancel;                        /* if non-zero, transfer is cancelled */
5576   /* data size is 0 bytes if the transfer has finished successfully */
5577   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5578 };
5579 "
5580
5581 (* Generate the guestfs-structs.h file. *)
5582 and generate_structs_h () =
5583   generate_header CStyle LGPLv2plus;
5584
5585   (* This is a public exported header file containing various
5586    * structures.  The structures are carefully written to have
5587    * exactly the same in-memory format as the XDR structures that
5588    * we use on the wire to the daemon.  The reason for creating
5589    * copies of these structures here is just so we don't have to
5590    * export the whole of guestfs_protocol.h (which includes much
5591    * unrelated and XDR-dependent stuff that we don't want to be
5592    * public, or required by clients).
5593    *
5594    * To reiterate, we will pass these structures to and from the
5595    * client with a simple assignment or memcpy, so the format
5596    * must be identical to what rpcgen / the RFC defines.
5597    *)
5598
5599   (* Public structures. *)
5600   List.iter (
5601     fun (typ, cols) ->
5602       pr "struct guestfs_%s {\n" typ;
5603       List.iter (
5604         function
5605         | name, FChar -> pr "  char %s;\n" name
5606         | name, FString -> pr "  char *%s;\n" name
5607         | name, FBuffer ->
5608             pr "  uint32_t %s_len;\n" name;
5609             pr "  char *%s;\n" name
5610         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5611         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5612         | name, FInt32 -> pr "  int32_t %s;\n" name
5613         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5614         | name, FInt64 -> pr "  int64_t %s;\n" name
5615         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5616       ) cols;
5617       pr "};\n";
5618       pr "\n";
5619       pr "struct guestfs_%s_list {\n" typ;
5620       pr "  uint32_t len;\n";
5621       pr "  struct guestfs_%s *val;\n" typ;
5622       pr "};\n";
5623       pr "\n";
5624       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5625       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5626       pr "\n"
5627   ) structs
5628
5629 (* Generate the guestfs-actions.h file. *)
5630 and generate_actions_h () =
5631   generate_header CStyle LGPLv2plus;
5632   List.iter (
5633     fun (shortname, style, _, _, _, _, _) ->
5634       let name = "guestfs_" ^ shortname in
5635       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5636         name style
5637   ) all_functions
5638
5639 (* Generate the guestfs-internal-actions.h file. *)
5640 and generate_internal_actions_h () =
5641   generate_header CStyle LGPLv2plus;
5642   List.iter (
5643     fun (shortname, style, _, _, _, _, _) ->
5644       let name = "guestfs__" ^ shortname in
5645       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5646         name style
5647   ) non_daemon_functions
5648
5649 (* Generate the client-side dispatch stubs. *)
5650 and generate_client_actions () =
5651   generate_header CStyle LGPLv2plus;
5652
5653   pr "\
5654 #include <stdio.h>
5655 #include <stdlib.h>
5656 #include <stdint.h>
5657 #include <string.h>
5658 #include <inttypes.h>
5659
5660 #include \"guestfs.h\"
5661 #include \"guestfs-internal.h\"
5662 #include \"guestfs-internal-actions.h\"
5663 #include \"guestfs_protocol.h\"
5664
5665 #define error guestfs_error
5666 //#define perrorf guestfs_perrorf
5667 #define safe_malloc guestfs_safe_malloc
5668 #define safe_realloc guestfs_safe_realloc
5669 //#define safe_strdup guestfs_safe_strdup
5670 #define safe_memdup guestfs_safe_memdup
5671
5672 /* Check the return message from a call for validity. */
5673 static int
5674 check_reply_header (guestfs_h *g,
5675                     const struct guestfs_message_header *hdr,
5676                     unsigned int proc_nr, unsigned int serial)
5677 {
5678   if (hdr->prog != GUESTFS_PROGRAM) {
5679     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5680     return -1;
5681   }
5682   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5683     error (g, \"wrong protocol version (%%d/%%d)\",
5684            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5685     return -1;
5686   }
5687   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5688     error (g, \"unexpected message direction (%%d/%%d)\",
5689            hdr->direction, GUESTFS_DIRECTION_REPLY);
5690     return -1;
5691   }
5692   if (hdr->proc != proc_nr) {
5693     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5694     return -1;
5695   }
5696   if (hdr->serial != serial) {
5697     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5698     return -1;
5699   }
5700
5701   return 0;
5702 }
5703
5704 /* Check we are in the right state to run a high-level action. */
5705 static int
5706 check_state (guestfs_h *g, const char *caller)
5707 {
5708   if (!guestfs__is_ready (g)) {
5709     if (guestfs__is_config (g) || guestfs__is_launching (g))
5710       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5711         caller);
5712     else
5713       error (g, \"%%s called from the wrong state, %%d != READY\",
5714         caller, guestfs__get_state (g));
5715     return -1;
5716   }
5717   return 0;
5718 }
5719
5720 ";
5721
5722   (* Generate code to generate guestfish call traces. *)
5723   let trace_call shortname style =
5724     pr "  if (guestfs__get_trace (g)) {\n";
5725
5726     let needs_i =
5727       List.exists (function
5728                    | StringList _ | DeviceList _ -> true
5729                    | _ -> false) (snd style) in
5730     if needs_i then (
5731       pr "    int i;\n";
5732       pr "\n"
5733     );
5734
5735     pr "    printf (\"%s\");\n" shortname;
5736     List.iter (
5737       function
5738       | String n                        (* strings *)
5739       | Device n
5740       | Pathname n
5741       | Dev_or_Path n
5742       | FileIn n
5743       | FileOut n ->
5744           (* guestfish doesn't support string escaping, so neither do we *)
5745           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5746       | OptString n ->                  (* string option *)
5747           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5748           pr "    else printf (\" null\");\n"
5749       | StringList n
5750       | DeviceList n ->                 (* string list *)
5751           pr "    putchar (' ');\n";
5752           pr "    putchar ('\"');\n";
5753           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5754           pr "      if (i > 0) putchar (' ');\n";
5755           pr "      fputs (%s[i], stdout);\n" n;
5756           pr "    }\n";
5757           pr "    putchar ('\"');\n";
5758       | Bool n ->                       (* boolean *)
5759           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5760       | Int n ->                        (* int *)
5761           pr "    printf (\" %%d\", %s);\n" n
5762       | Int64 n ->
5763           pr "    printf (\" %%\" PRIi64, %s);\n" n
5764     ) (snd style);
5765     pr "    putchar ('\\n');\n";
5766     pr "  }\n";
5767     pr "\n";
5768   in
5769
5770   (* For non-daemon functions, generate a wrapper around each function. *)
5771   List.iter (
5772     fun (shortname, style, _, _, _, _, _) ->
5773       let name = "guestfs_" ^ shortname in
5774
5775       generate_prototype ~extern:false ~semicolon:false ~newline:true
5776         ~handle:"g" name style;
5777       pr "{\n";
5778       trace_call shortname style;
5779       pr "  return guestfs__%s " shortname;
5780       generate_c_call_args ~handle:"g" style;
5781       pr ";\n";
5782       pr "}\n";
5783       pr "\n"
5784   ) non_daemon_functions;
5785
5786   (* Client-side stubs for each function. *)
5787   List.iter (
5788     fun (shortname, style, _, _, _, _, _) ->
5789       let name = "guestfs_" ^ shortname in
5790
5791       (* Generate the action stub. *)
5792       generate_prototype ~extern:false ~semicolon:false ~newline:true
5793         ~handle:"g" name style;
5794
5795       let error_code =
5796         match fst style with
5797         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5798         | RConstString _ | RConstOptString _ ->
5799             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5800         | RString _ | RStringList _
5801         | RStruct _ | RStructList _
5802         | RHashtable _ | RBufferOut _ ->
5803             "NULL" in
5804
5805       pr "{\n";
5806
5807       (match snd style with
5808        | [] -> ()
5809        | _ -> pr "  struct %s_args args;\n" name
5810       );
5811
5812       pr "  guestfs_message_header hdr;\n";
5813       pr "  guestfs_message_error err;\n";
5814       let has_ret =
5815         match fst style with
5816         | RErr -> false
5817         | RConstString _ | RConstOptString _ ->
5818             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5819         | RInt _ | RInt64 _
5820         | RBool _ | RString _ | RStringList _
5821         | RStruct _ | RStructList _
5822         | RHashtable _ | RBufferOut _ ->
5823             pr "  struct %s_ret ret;\n" name;
5824             true in
5825
5826       pr "  int serial;\n";
5827       pr "  int r;\n";
5828       pr "\n";
5829       trace_call shortname style;
5830       pr "  if (check_state (g, \"%s\") == -1) return %s;\n"
5831         shortname error_code;
5832       pr "  guestfs___set_busy (g);\n";
5833       pr "\n";
5834
5835       (* Send the main header and arguments. *)
5836       (match snd style with
5837        | [] ->
5838            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5839              (String.uppercase shortname)
5840        | args ->
5841            List.iter (
5842              function
5843              | Pathname n | Device n | Dev_or_Path n | String n ->
5844                  pr "  args.%s = (char *) %s;\n" n n
5845              | OptString n ->
5846                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5847              | StringList n | DeviceList n ->
5848                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5849                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5850              | Bool n ->
5851                  pr "  args.%s = %s;\n" n n
5852              | Int n ->
5853                  pr "  args.%s = %s;\n" n n
5854              | Int64 n ->
5855                  pr "  args.%s = %s;\n" n n
5856              | FileIn _ | FileOut _ -> ()
5857            ) args;
5858            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5859              (String.uppercase shortname);
5860            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5861              name;
5862       );
5863       pr "  if (serial == -1) {\n";
5864       pr "    guestfs___end_busy (g);\n";
5865       pr "    return %s;\n" error_code;
5866       pr "  }\n";
5867       pr "\n";
5868
5869       (* Send any additional files (FileIn) requested. *)
5870       let need_read_reply_label = ref false in
5871       List.iter (
5872         function
5873         | FileIn n ->
5874             pr "  r = guestfs___send_file (g, %s);\n" n;
5875             pr "  if (r == -1) {\n";
5876             pr "    guestfs___end_busy (g);\n";
5877             pr "    return %s;\n" error_code;
5878             pr "  }\n";
5879             pr "  if (r == -2) /* daemon cancelled */\n";
5880             pr "    goto read_reply;\n";
5881             need_read_reply_label := true;
5882             pr "\n";
5883         | _ -> ()
5884       ) (snd style);
5885
5886       (* Wait for the reply from the remote end. *)
5887       if !need_read_reply_label then pr " read_reply:\n";
5888       pr "  memset (&hdr, 0, sizeof hdr);\n";
5889       pr "  memset (&err, 0, sizeof err);\n";
5890       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5891       pr "\n";
5892       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5893       if not has_ret then
5894         pr "NULL, NULL"
5895       else
5896         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5897       pr ");\n";
5898
5899       pr "  if (r == -1) {\n";
5900       pr "    guestfs___end_busy (g);\n";
5901       pr "    return %s;\n" error_code;
5902       pr "  }\n";
5903       pr "\n";
5904
5905       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5906         (String.uppercase shortname);
5907       pr "    guestfs___end_busy (g);\n";
5908       pr "    return %s;\n" error_code;
5909       pr "  }\n";
5910       pr "\n";
5911
5912       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5913       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5914       pr "    free (err.error_message);\n";
5915       pr "    guestfs___end_busy (g);\n";
5916       pr "    return %s;\n" error_code;
5917       pr "  }\n";
5918       pr "\n";
5919
5920       (* Expecting to receive further files (FileOut)? *)
5921       List.iter (
5922         function
5923         | FileOut n ->
5924             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5925             pr "    guestfs___end_busy (g);\n";
5926             pr "    return %s;\n" error_code;
5927             pr "  }\n";
5928             pr "\n";
5929         | _ -> ()
5930       ) (snd style);
5931
5932       pr "  guestfs___end_busy (g);\n";
5933
5934       (match fst style with
5935        | RErr -> pr "  return 0;\n"
5936        | RInt n | RInt64 n | RBool n ->
5937            pr "  return ret.%s;\n" n
5938        | RConstString _ | RConstOptString _ ->
5939            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5940        | RString n ->
5941            pr "  return ret.%s; /* caller will free */\n" n
5942        | RStringList n | RHashtable n ->
5943            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5944            pr "  ret.%s.%s_val =\n" n n;
5945            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5946            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5947              n n;
5948            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5949            pr "  return ret.%s.%s_val;\n" n n
5950        | RStruct (n, _) ->
5951            pr "  /* caller will free this */\n";
5952            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5953        | RStructList (n, _) ->
5954            pr "  /* caller will free this */\n";
5955            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5956        | RBufferOut n ->
5957            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5958            pr "   * _val might be NULL here.  To make the API saner for\n";
5959            pr "   * callers, we turn this case into a unique pointer (using\n";
5960            pr "   * malloc(1)).\n";
5961            pr "   */\n";
5962            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5963            pr "    *size_r = ret.%s.%s_len;\n" n n;
5964            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5965            pr "  } else {\n";
5966            pr "    free (ret.%s.%s_val);\n" n n;
5967            pr "    char *p = safe_malloc (g, 1);\n";
5968            pr "    *size_r = ret.%s.%s_len;\n" n n;
5969            pr "    return p;\n";
5970            pr "  }\n";
5971       );
5972
5973       pr "}\n\n"
5974   ) daemon_functions;
5975
5976   (* Functions to free structures. *)
5977   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5978   pr " * structure format is identical to the XDR format.  See note in\n";
5979   pr " * generator.ml.\n";
5980   pr " */\n";
5981   pr "\n";
5982
5983   List.iter (
5984     fun (typ, _) ->
5985       pr "void\n";
5986       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5987       pr "{\n";
5988       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5989       pr "  free (x);\n";
5990       pr "}\n";
5991       pr "\n";
5992
5993       pr "void\n";
5994       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5995       pr "{\n";
5996       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
5997       pr "  free (x);\n";
5998       pr "}\n";
5999       pr "\n";
6000
6001   ) structs;
6002
6003 (* Generate daemon/actions.h. *)
6004 and generate_daemon_actions_h () =
6005   generate_header CStyle GPLv2plus;
6006
6007   pr "#include \"../src/guestfs_protocol.h\"\n";
6008   pr "\n";
6009
6010   List.iter (
6011     fun (name, style, _, _, _, _, _) ->
6012       generate_prototype
6013         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
6014         name style;
6015   ) daemon_functions
6016
6017 (* Generate the linker script which controls the visibility of
6018  * symbols in the public ABI and ensures no other symbols get
6019  * exported accidentally.
6020  *)
6021 and generate_linker_script () =
6022   generate_header HashStyle GPLv2plus;
6023
6024   let globals = [
6025     "guestfs_create";
6026     "guestfs_close";
6027     "guestfs_get_error_handler";
6028     "guestfs_get_out_of_memory_handler";
6029     "guestfs_last_error";
6030     "guestfs_set_error_handler";
6031     "guestfs_set_launch_done_callback";
6032     "guestfs_set_log_message_callback";
6033     "guestfs_set_out_of_memory_handler";
6034     "guestfs_set_subprocess_quit_callback";
6035
6036     (* Unofficial parts of the API: the bindings code use these
6037      * functions, so it is useful to export them.
6038      *)
6039     "guestfs_safe_calloc";
6040     "guestfs_safe_malloc";
6041   ] in
6042   let functions =
6043     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
6044       all_functions in
6045   let structs =
6046     List.concat (
6047       List.map (fun (typ, _) ->
6048                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
6049         structs
6050     ) in
6051   let globals = List.sort compare (globals @ functions @ structs) in
6052
6053   pr "{\n";
6054   pr "    global:\n";
6055   List.iter (pr "        %s;\n") globals;
6056   pr "\n";
6057
6058   pr "    local:\n";
6059   pr "        *;\n";
6060   pr "};\n"
6061
6062 (* Generate the server-side stubs. *)
6063 and generate_daemon_actions () =
6064   generate_header CStyle GPLv2plus;
6065
6066   pr "#include <config.h>\n";
6067   pr "\n";
6068   pr "#include <stdio.h>\n";
6069   pr "#include <stdlib.h>\n";
6070   pr "#include <string.h>\n";
6071   pr "#include <inttypes.h>\n";
6072   pr "#include <rpc/types.h>\n";
6073   pr "#include <rpc/xdr.h>\n";
6074   pr "\n";
6075   pr "#include \"daemon.h\"\n";
6076   pr "#include \"c-ctype.h\"\n";
6077   pr "#include \"../src/guestfs_protocol.h\"\n";
6078   pr "#include \"actions.h\"\n";
6079   pr "\n";
6080
6081   List.iter (
6082     fun (name, style, _, _, _, _, _) ->
6083       (* Generate server-side stubs. *)
6084       pr "static void %s_stub (XDR *xdr_in)\n" name;
6085       pr "{\n";
6086       let error_code =
6087         match fst style with
6088         | RErr | RInt _ -> pr "  int r;\n"; "-1"
6089         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6090         | RBool _ -> pr "  int r;\n"; "-1"
6091         | RConstString _ | RConstOptString _ ->
6092             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6093         | RString _ -> pr "  char *r;\n"; "NULL"
6094         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6095         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
6096         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
6097         | RBufferOut _ ->
6098             pr "  size_t size = 1;\n";
6099             pr "  char *r;\n";
6100             "NULL" in
6101
6102       (match snd style with
6103        | [] -> ()
6104        | args ->
6105            pr "  struct guestfs_%s_args args;\n" name;
6106            List.iter (
6107              function
6108              | Device n | Dev_or_Path n
6109              | Pathname n
6110              | String n -> ()
6111              | OptString n -> pr "  char *%s;\n" n
6112              | StringList n | DeviceList n -> pr "  char **%s;\n" n
6113              | Bool n -> pr "  int %s;\n" n
6114              | Int n -> pr "  int %s;\n" n
6115              | Int64 n -> pr "  int64_t %s;\n" n
6116              | FileIn _ | FileOut _ -> ()
6117            ) args
6118       );
6119       pr "\n";
6120
6121       let is_filein =
6122         List.exists (function FileIn _ -> true | _ -> false) (snd style) in
6123
6124       (match snd style with
6125        | [] -> ()
6126        | args ->
6127            pr "  memset (&args, 0, sizeof args);\n";
6128            pr "\n";
6129            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
6130            if is_filein then
6131              pr "    cancel_receive ();\n";
6132            pr "    reply_with_error (\"daemon failed to decode procedure arguments\");\n";
6133            pr "    goto done;\n";
6134            pr "  }\n";
6135            let pr_args n =
6136              pr "  char *%s = args.%s;\n" n n
6137            in
6138            let pr_list_handling_code n =
6139              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
6140              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
6141              pr "  if (%s == NULL) {\n" n;
6142              if is_filein then
6143                pr "    cancel_receive ();\n";
6144              pr "    reply_with_perror (\"realloc\");\n";
6145              pr "    goto done;\n";
6146              pr "  }\n";
6147              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
6148              pr "  args.%s.%s_val = %s;\n" n n n;
6149            in
6150            List.iter (
6151              function
6152              | Pathname n ->
6153                  pr_args n;
6154                  pr "  ABS_PATH (%s, %s, goto done);\n"
6155                    n (if is_filein then "cancel_receive ()" else "");
6156              | Device n ->
6157                  pr_args n;
6158                  pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
6159                    n (if is_filein then "cancel_receive ()" else "");
6160              | Dev_or_Path n ->
6161                  pr_args n;
6162                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
6163                    n (if is_filein then "cancel_receive ()" else "");
6164              | String n -> pr_args n
6165              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
6166              | StringList n ->
6167                  pr_list_handling_code n;
6168              | DeviceList n ->
6169                  pr_list_handling_code n;
6170                  pr "  /* Ensure that each is a device,\n";
6171                  pr "   * and perform device name translation. */\n";
6172                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
6173                  pr "    RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n"
6174                    (if is_filein then "cancel_receive ()" else "");
6175                  pr "  }\n";
6176              | Bool n -> pr "  %s = args.%s;\n" n n
6177              | Int n -> pr "  %s = args.%s;\n" n n
6178              | Int64 n -> pr "  %s = args.%s;\n" n n
6179              | FileIn _ | FileOut _ -> ()
6180            ) args;
6181            pr "\n"
6182       );
6183
6184
6185       (* this is used at least for do_equal *)
6186       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
6187         (* Emit NEED_ROOT just once, even when there are two or
6188            more Pathname args *)
6189         pr "  NEED_ROOT (%s, goto done);\n"
6190           (if is_filein then "cancel_receive ()" else "");
6191       );
6192
6193       (* Don't want to call the impl with any FileIn or FileOut
6194        * parameters, since these go "outside" the RPC protocol.
6195        *)
6196       let args' =
6197         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
6198           (snd style) in
6199       pr "  r = do_%s " name;
6200       generate_c_call_args (fst style, args');
6201       pr ";\n";
6202
6203       (match fst style with
6204        | RErr | RInt _ | RInt64 _ | RBool _
6205        | RConstString _ | RConstOptString _
6206        | RString _ | RStringList _ | RHashtable _
6207        | RStruct (_, _) | RStructList (_, _) ->
6208            pr "  if (r == %s)\n" error_code;
6209            pr "    /* do_%s has already called reply_with_error */\n" name;
6210            pr "    goto done;\n";
6211            pr "\n"
6212        | RBufferOut _ ->
6213            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
6214            pr "   * an ordinary zero-length buffer), so be careful ...\n";
6215            pr "   */\n";
6216            pr "  if (size == 1 && r == %s)\n" error_code;
6217            pr "    /* do_%s has already called reply_with_error */\n" name;
6218            pr "    goto done;\n";
6219            pr "\n"
6220       );
6221
6222       (* If there are any FileOut parameters, then the impl must
6223        * send its own reply.
6224        *)
6225       let no_reply =
6226         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
6227       if no_reply then
6228         pr "  /* do_%s has already sent a reply */\n" name
6229       else (
6230         match fst style with
6231         | RErr -> pr "  reply (NULL, NULL);\n"
6232         | RInt n | RInt64 n | RBool n ->
6233             pr "  struct guestfs_%s_ret ret;\n" name;
6234             pr "  ret.%s = r;\n" n;
6235             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6236               name
6237         | RConstString _ | RConstOptString _ ->
6238             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6239         | RString n ->
6240             pr "  struct guestfs_%s_ret ret;\n" name;
6241             pr "  ret.%s = r;\n" n;
6242             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6243               name;
6244             pr "  free (r);\n"
6245         | RStringList n | RHashtable n ->
6246             pr "  struct guestfs_%s_ret ret;\n" name;
6247             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
6248             pr "  ret.%s.%s_val = r;\n" n n;
6249             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6250               name;
6251             pr "  free_strings (r);\n"
6252         | RStruct (n, _) ->
6253             pr "  struct guestfs_%s_ret ret;\n" name;
6254             pr "  ret.%s = *r;\n" n;
6255             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6256               name;
6257             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6258               name
6259         | RStructList (n, _) ->
6260             pr "  struct guestfs_%s_ret ret;\n" name;
6261             pr "  ret.%s = *r;\n" n;
6262             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6263               name;
6264             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6265               name
6266         | RBufferOut n ->
6267             pr "  struct guestfs_%s_ret ret;\n" name;
6268             pr "  ret.%s.%s_val = r;\n" n n;
6269             pr "  ret.%s.%s_len = size;\n" n n;
6270             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6271               name;
6272             pr "  free (r);\n"
6273       );
6274
6275       (* Free the args. *)
6276       pr "done:\n";
6277       (match snd style with
6278        | [] -> ()
6279        | _ ->
6280            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
6281              name
6282       );
6283       pr "  return;\n";
6284       pr "}\n\n";
6285   ) daemon_functions;
6286
6287   (* Dispatch function. *)
6288   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
6289   pr "{\n";
6290   pr "  switch (proc_nr) {\n";
6291
6292   List.iter (
6293     fun (name, style, _, _, _, _, _) ->
6294       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
6295       pr "      %s_stub (xdr_in);\n" name;
6296       pr "      break;\n"
6297   ) daemon_functions;
6298
6299   pr "    default:\n";
6300   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";
6301   pr "  }\n";
6302   pr "}\n";
6303   pr "\n";
6304
6305   (* LVM columns and tokenization functions. *)
6306   (* XXX This generates crap code.  We should rethink how we
6307    * do this parsing.
6308    *)
6309   List.iter (
6310     function
6311     | typ, cols ->
6312         pr "static const char *lvm_%s_cols = \"%s\";\n"
6313           typ (String.concat "," (List.map fst cols));
6314         pr "\n";
6315
6316         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
6317         pr "{\n";
6318         pr "  char *tok, *p, *next;\n";
6319         pr "  int i, j;\n";
6320         pr "\n";
6321         (*
6322           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
6323           pr "\n";
6324         *)
6325         pr "  if (!str) {\n";
6326         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
6327         pr "    return -1;\n";
6328         pr "  }\n";
6329         pr "  if (!*str || c_isspace (*str)) {\n";
6330         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
6331         pr "    return -1;\n";
6332         pr "  }\n";
6333         pr "  tok = str;\n";
6334         List.iter (
6335           fun (name, coltype) ->
6336             pr "  if (!tok) {\n";
6337             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
6338             pr "    return -1;\n";
6339             pr "  }\n";
6340             pr "  p = strchrnul (tok, ',');\n";
6341             pr "  if (*p) next = p+1; else next = NULL;\n";
6342             pr "  *p = '\\0';\n";
6343             (match coltype with
6344              | FString ->
6345                  pr "  r->%s = strdup (tok);\n" name;
6346                  pr "  if (r->%s == NULL) {\n" name;
6347                  pr "    perror (\"strdup\");\n";
6348                  pr "    return -1;\n";
6349                  pr "  }\n"
6350              | FUUID ->
6351                  pr "  for (i = j = 0; i < 32; ++j) {\n";
6352                  pr "    if (tok[j] == '\\0') {\n";
6353                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
6354                  pr "      return -1;\n";
6355                  pr "    } else if (tok[j] != '-')\n";
6356                  pr "      r->%s[i++] = tok[j];\n" name;
6357                  pr "  }\n";
6358              | FBytes ->
6359                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
6360                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6361                  pr "    return -1;\n";
6362                  pr "  }\n";
6363              | FInt64 ->
6364                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
6365                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6366                  pr "    return -1;\n";
6367                  pr "  }\n";
6368              | FOptPercent ->
6369                  pr "  if (tok[0] == '\\0')\n";
6370                  pr "    r->%s = -1;\n" name;
6371                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
6372                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6373                  pr "    return -1;\n";
6374                  pr "  }\n";
6375              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
6376                  assert false (* can never be an LVM column *)
6377             );
6378             pr "  tok = next;\n";
6379         ) cols;
6380
6381         pr "  if (tok != NULL) {\n";
6382         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6383         pr "    return -1;\n";
6384         pr "  }\n";
6385         pr "  return 0;\n";
6386         pr "}\n";
6387         pr "\n";
6388
6389         pr "guestfs_int_lvm_%s_list *\n" typ;
6390         pr "parse_command_line_%ss (void)\n" typ;
6391         pr "{\n";
6392         pr "  char *out, *err;\n";
6393         pr "  char *p, *pend;\n";
6394         pr "  int r, i;\n";
6395         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6396         pr "  void *newp;\n";
6397         pr "\n";
6398         pr "  ret = malloc (sizeof *ret);\n";
6399         pr "  if (!ret) {\n";
6400         pr "    reply_with_perror (\"malloc\");\n";
6401         pr "    return NULL;\n";
6402         pr "  }\n";
6403         pr "\n";
6404         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6405         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6406         pr "\n";
6407         pr "  r = command (&out, &err,\n";
6408         pr "           \"lvm\", \"%ss\",\n" typ;
6409         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6410         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6411         pr "  if (r == -1) {\n";
6412         pr "    reply_with_error (\"%%s\", err);\n";
6413         pr "    free (out);\n";
6414         pr "    free (err);\n";
6415         pr "    free (ret);\n";
6416         pr "    return NULL;\n";
6417         pr "  }\n";
6418         pr "\n";
6419         pr "  free (err);\n";
6420         pr "\n";
6421         pr "  /* Tokenize each line of the output. */\n";
6422         pr "  p = out;\n";
6423         pr "  i = 0;\n";
6424         pr "  while (p) {\n";
6425         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6426         pr "    if (pend) {\n";
6427         pr "      *pend = '\\0';\n";
6428         pr "      pend++;\n";
6429         pr "    }\n";
6430         pr "\n";
6431         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6432         pr "      p++;\n";
6433         pr "\n";
6434         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6435         pr "      p = pend;\n";
6436         pr "      continue;\n";
6437         pr "    }\n";
6438         pr "\n";
6439         pr "    /* Allocate some space to store this next entry. */\n";
6440         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6441         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6442         pr "    if (newp == NULL) {\n";
6443         pr "      reply_with_perror (\"realloc\");\n";
6444         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6445         pr "      free (ret);\n";
6446         pr "      free (out);\n";
6447         pr "      return NULL;\n";
6448         pr "    }\n";
6449         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6450         pr "\n";
6451         pr "    /* Tokenize the next entry. */\n";
6452         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6453         pr "    if (r == -1) {\n";
6454         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6455         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6456         pr "      free (ret);\n";
6457         pr "      free (out);\n";
6458         pr "      return NULL;\n";
6459         pr "    }\n";
6460         pr "\n";
6461         pr "    ++i;\n";
6462         pr "    p = pend;\n";
6463         pr "  }\n";
6464         pr "\n";
6465         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6466         pr "\n";
6467         pr "  free (out);\n";
6468         pr "  return ret;\n";
6469         pr "}\n"
6470
6471   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6472
6473 (* Generate a list of function names, for debugging in the daemon.. *)
6474 and generate_daemon_names () =
6475   generate_header CStyle GPLv2plus;
6476
6477   pr "#include <config.h>\n";
6478   pr "\n";
6479   pr "#include \"daemon.h\"\n";
6480   pr "\n";
6481
6482   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6483   pr "const char *function_names[] = {\n";
6484   List.iter (
6485     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6486   ) daemon_functions;
6487   pr "};\n";
6488
6489 (* Generate the optional groups for the daemon to implement
6490  * guestfs_available.
6491  *)
6492 and generate_daemon_optgroups_c () =
6493   generate_header CStyle GPLv2plus;
6494
6495   pr "#include <config.h>\n";
6496   pr "\n";
6497   pr "#include \"daemon.h\"\n";
6498   pr "#include \"optgroups.h\"\n";
6499   pr "\n";
6500
6501   pr "struct optgroup optgroups[] = {\n";
6502   List.iter (
6503     fun (group, _) ->
6504       pr "  { \"%s\", optgroup_%s_available },\n" group group
6505   ) optgroups;
6506   pr "  { NULL, NULL }\n";
6507   pr "};\n"
6508
6509 and generate_daemon_optgroups_h () =
6510   generate_header CStyle GPLv2plus;
6511
6512   List.iter (
6513     fun (group, _) ->
6514       pr "extern int optgroup_%s_available (void);\n" group
6515   ) optgroups
6516
6517 (* Generate the tests. *)
6518 and generate_tests () =
6519   generate_header CStyle GPLv2plus;
6520
6521   pr "\
6522 #include <stdio.h>
6523 #include <stdlib.h>
6524 #include <string.h>
6525 #include <unistd.h>
6526 #include <sys/types.h>
6527 #include <fcntl.h>
6528
6529 #include \"guestfs.h\"
6530 #include \"guestfs-internal.h\"
6531
6532 static guestfs_h *g;
6533 static int suppress_error = 0;
6534
6535 static void print_error (guestfs_h *g, void *data, const char *msg)
6536 {
6537   if (!suppress_error)
6538     fprintf (stderr, \"%%s\\n\", msg);
6539 }
6540
6541 /* FIXME: nearly identical code appears in fish.c */
6542 static void print_strings (char *const *argv)
6543 {
6544   int argc;
6545
6546   for (argc = 0; argv[argc] != NULL; ++argc)
6547     printf (\"\\t%%s\\n\", argv[argc]);
6548 }
6549
6550 /*
6551 static void print_table (char const *const *argv)
6552 {
6553   int i;
6554
6555   for (i = 0; argv[i] != NULL; i += 2)
6556     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6557 }
6558 */
6559
6560 ";
6561
6562   (* Generate a list of commands which are not tested anywhere. *)
6563   pr "static void no_test_warnings (void)\n";
6564   pr "{\n";
6565
6566   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6567   List.iter (
6568     fun (_, _, _, _, tests, _, _) ->
6569       let tests = filter_map (
6570         function
6571         | (_, (Always|If _|Unless _), test) -> Some test
6572         | (_, Disabled, _) -> None
6573       ) tests in
6574       let seq = List.concat (List.map seq_of_test tests) in
6575       let cmds_tested = List.map List.hd seq in
6576       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6577   ) all_functions;
6578
6579   List.iter (
6580     fun (name, _, _, _, _, _, _) ->
6581       if not (Hashtbl.mem hash name) then
6582         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6583   ) all_functions;
6584
6585   pr "}\n";
6586   pr "\n";
6587
6588   (* Generate the actual tests.  Note that we generate the tests
6589    * in reverse order, deliberately, so that (in general) the
6590    * newest tests run first.  This makes it quicker and easier to
6591    * debug them.
6592    *)
6593   let test_names =
6594     List.map (
6595       fun (name, _, _, flags, tests, _, _) ->
6596         mapi (generate_one_test name flags) tests
6597     ) (List.rev all_functions) in
6598   let test_names = List.concat test_names in
6599   let nr_tests = List.length test_names in
6600
6601   pr "\
6602 int main (int argc, char *argv[])
6603 {
6604   char c = 0;
6605   unsigned long int n_failed = 0;
6606   const char *filename;
6607   int fd;
6608   int nr_tests, test_num = 0;
6609
6610   setbuf (stdout, NULL);
6611
6612   no_test_warnings ();
6613
6614   g = guestfs_create ();
6615   if (g == NULL) {
6616     printf (\"guestfs_create FAILED\\n\");
6617     exit (EXIT_FAILURE);
6618   }
6619
6620   guestfs_set_error_handler (g, print_error, NULL);
6621
6622   guestfs_set_path (g, \"../appliance\");
6623
6624   filename = \"test1.img\";
6625   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6626   if (fd == -1) {
6627     perror (filename);
6628     exit (EXIT_FAILURE);
6629   }
6630   if (lseek (fd, %d, SEEK_SET) == -1) {
6631     perror (\"lseek\");
6632     close (fd);
6633     unlink (filename);
6634     exit (EXIT_FAILURE);
6635   }
6636   if (write (fd, &c, 1) == -1) {
6637     perror (\"write\");
6638     close (fd);
6639     unlink (filename);
6640     exit (EXIT_FAILURE);
6641   }
6642   if (close (fd) == -1) {
6643     perror (filename);
6644     unlink (filename);
6645     exit (EXIT_FAILURE);
6646   }
6647   if (guestfs_add_drive (g, filename) == -1) {
6648     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6649     exit (EXIT_FAILURE);
6650   }
6651
6652   filename = \"test2.img\";
6653   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6654   if (fd == -1) {
6655     perror (filename);
6656     exit (EXIT_FAILURE);
6657   }
6658   if (lseek (fd, %d, SEEK_SET) == -1) {
6659     perror (\"lseek\");
6660     close (fd);
6661     unlink (filename);
6662     exit (EXIT_FAILURE);
6663   }
6664   if (write (fd, &c, 1) == -1) {
6665     perror (\"write\");
6666     close (fd);
6667     unlink (filename);
6668     exit (EXIT_FAILURE);
6669   }
6670   if (close (fd) == -1) {
6671     perror (filename);
6672     unlink (filename);
6673     exit (EXIT_FAILURE);
6674   }
6675   if (guestfs_add_drive (g, filename) == -1) {
6676     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6677     exit (EXIT_FAILURE);
6678   }
6679
6680   filename = \"test3.img\";
6681   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6682   if (fd == -1) {
6683     perror (filename);
6684     exit (EXIT_FAILURE);
6685   }
6686   if (lseek (fd, %d, SEEK_SET) == -1) {
6687     perror (\"lseek\");
6688     close (fd);
6689     unlink (filename);
6690     exit (EXIT_FAILURE);
6691   }
6692   if (write (fd, &c, 1) == -1) {
6693     perror (\"write\");
6694     close (fd);
6695     unlink (filename);
6696     exit (EXIT_FAILURE);
6697   }
6698   if (close (fd) == -1) {
6699     perror (filename);
6700     unlink (filename);
6701     exit (EXIT_FAILURE);
6702   }
6703   if (guestfs_add_drive (g, filename) == -1) {
6704     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6705     exit (EXIT_FAILURE);
6706   }
6707
6708   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6709     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6710     exit (EXIT_FAILURE);
6711   }
6712
6713   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6714   alarm (600);
6715
6716   if (guestfs_launch (g) == -1) {
6717     printf (\"guestfs_launch FAILED\\n\");
6718     exit (EXIT_FAILURE);
6719   }
6720
6721   /* Cancel previous alarm. */
6722   alarm (0);
6723
6724   nr_tests = %d;
6725
6726 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6727
6728   iteri (
6729     fun i test_name ->
6730       pr "  test_num++;\n";
6731       pr "  if (guestfs_get_verbose (g))\n";
6732       pr "    printf (\"-------------------------------------------------------------------------------\\n\");\n";
6733       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6734       pr "  if (%s () == -1) {\n" test_name;
6735       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6736       pr "    n_failed++;\n";
6737       pr "  }\n";
6738   ) test_names;
6739   pr "\n";
6740
6741   pr "  guestfs_close (g);\n";
6742   pr "  unlink (\"test1.img\");\n";
6743   pr "  unlink (\"test2.img\");\n";
6744   pr "  unlink (\"test3.img\");\n";
6745   pr "\n";
6746
6747   pr "  if (n_failed > 0) {\n";
6748   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6749   pr "    exit (EXIT_FAILURE);\n";
6750   pr "  }\n";
6751   pr "\n";
6752
6753   pr "  exit (EXIT_SUCCESS);\n";
6754   pr "}\n"
6755
6756 and generate_one_test name flags i (init, prereq, test) =
6757   let test_name = sprintf "test_%s_%d" name i in
6758
6759   pr "\
6760 static int %s_skip (void)
6761 {
6762   const char *str;
6763
6764   str = getenv (\"TEST_ONLY\");
6765   if (str)
6766     return strstr (str, \"%s\") == NULL;
6767   str = getenv (\"SKIP_%s\");
6768   if (str && STREQ (str, \"1\")) return 1;
6769   str = getenv (\"SKIP_TEST_%s\");
6770   if (str && STREQ (str, \"1\")) return 1;
6771   return 0;
6772 }
6773
6774 " test_name name (String.uppercase test_name) (String.uppercase name);
6775
6776   (match prereq with
6777    | Disabled | Always -> ()
6778    | If code | Unless code ->
6779        pr "static int %s_prereq (void)\n" test_name;
6780        pr "{\n";
6781        pr "  %s\n" code;
6782        pr "}\n";
6783        pr "\n";
6784   );
6785
6786   pr "\
6787 static int %s (void)
6788 {
6789   if (%s_skip ()) {
6790     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6791     return 0;
6792   }
6793
6794 " test_name test_name test_name;
6795
6796   (* Optional functions should only be tested if the relevant
6797    * support is available in the daemon.
6798    *)
6799   List.iter (
6800     function
6801     | Optional group ->
6802         pr "  {\n";
6803         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6804         pr "    int r;\n";
6805         pr "    suppress_error = 1;\n";
6806         pr "    r = guestfs_available (g, (char **) groups);\n";
6807         pr "    suppress_error = 0;\n";
6808         pr "    if (r == -1) {\n";
6809         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6810         pr "      return 0;\n";
6811         pr "    }\n";
6812         pr "  }\n";
6813     | _ -> ()
6814   ) flags;
6815
6816   (match prereq with
6817    | Disabled ->
6818        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6819    | If _ ->
6820        pr "  if (! %s_prereq ()) {\n" test_name;
6821        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6822        pr "    return 0;\n";
6823        pr "  }\n";
6824        pr "\n";
6825        generate_one_test_body name i test_name init test;
6826    | Unless _ ->
6827        pr "  if (%s_prereq ()) {\n" test_name;
6828        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6829        pr "    return 0;\n";
6830        pr "  }\n";
6831        pr "\n";
6832        generate_one_test_body name i test_name init test;
6833    | Always ->
6834        generate_one_test_body name i test_name init test
6835   );
6836
6837   pr "  return 0;\n";
6838   pr "}\n";
6839   pr "\n";
6840   test_name
6841
6842 and generate_one_test_body name i test_name init test =
6843   (match init with
6844    | InitNone (* XXX at some point, InitNone and InitEmpty became
6845                * folded together as the same thing.  Really we should
6846                * make InitNone do nothing at all, but the tests may
6847                * need to be checked to make sure this is OK.
6848                *)
6849    | InitEmpty ->
6850        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6851        List.iter (generate_test_command_call test_name)
6852          [["blockdev_setrw"; "/dev/sda"];
6853           ["umount_all"];
6854           ["lvm_remove_all"]]
6855    | InitPartition ->
6856        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6857        List.iter (generate_test_command_call test_name)
6858          [["blockdev_setrw"; "/dev/sda"];
6859           ["umount_all"];
6860           ["lvm_remove_all"];
6861           ["part_disk"; "/dev/sda"; "mbr"]]
6862    | InitBasicFS ->
6863        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6864        List.iter (generate_test_command_call test_name)
6865          [["blockdev_setrw"; "/dev/sda"];
6866           ["umount_all"];
6867           ["lvm_remove_all"];
6868           ["part_disk"; "/dev/sda"; "mbr"];
6869           ["mkfs"; "ext2"; "/dev/sda1"];
6870           ["mount_options"; ""; "/dev/sda1"; "/"]]
6871    | InitBasicFSonLVM ->
6872        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6873          test_name;
6874        List.iter (generate_test_command_call test_name)
6875          [["blockdev_setrw"; "/dev/sda"];
6876           ["umount_all"];
6877           ["lvm_remove_all"];
6878           ["part_disk"; "/dev/sda"; "mbr"];
6879           ["pvcreate"; "/dev/sda1"];
6880           ["vgcreate"; "VG"; "/dev/sda1"];
6881           ["lvcreate"; "LV"; "VG"; "8"];
6882           ["mkfs"; "ext2"; "/dev/VG/LV"];
6883           ["mount_options"; ""; "/dev/VG/LV"; "/"]]
6884    | InitISOFS ->
6885        pr "  /* InitISOFS for %s */\n" test_name;
6886        List.iter (generate_test_command_call test_name)
6887          [["blockdev_setrw"; "/dev/sda"];
6888           ["umount_all"];
6889           ["lvm_remove_all"];
6890           ["mount_ro"; "/dev/sdd"; "/"]]
6891   );
6892
6893   let get_seq_last = function
6894     | [] ->
6895         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6896           test_name
6897     | seq ->
6898         let seq = List.rev seq in
6899         List.rev (List.tl seq), List.hd seq
6900   in
6901
6902   match test with
6903   | TestRun seq ->
6904       pr "  /* TestRun for %s (%d) */\n" name i;
6905       List.iter (generate_test_command_call test_name) seq
6906   | TestOutput (seq, expected) ->
6907       pr "  /* TestOutput for %s (%d) */\n" name i;
6908       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6909       let seq, last = get_seq_last seq in
6910       let test () =
6911         pr "    if (STRNEQ (r, expected)) {\n";
6912         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6913         pr "      return -1;\n";
6914         pr "    }\n"
6915       in
6916       List.iter (generate_test_command_call test_name) seq;
6917       generate_test_command_call ~test test_name last
6918   | TestOutputList (seq, expected) ->
6919       pr "  /* TestOutputList for %s (%d) */\n" name i;
6920       let seq, last = get_seq_last seq in
6921       let test () =
6922         iteri (
6923           fun i str ->
6924             pr "    if (!r[%d]) {\n" i;
6925             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6926             pr "      print_strings (r);\n";
6927             pr "      return -1;\n";
6928             pr "    }\n";
6929             pr "    {\n";
6930             pr "      const char *expected = \"%s\";\n" (c_quote str);
6931             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6932             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6933             pr "        return -1;\n";
6934             pr "      }\n";
6935             pr "    }\n"
6936         ) expected;
6937         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6938         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6939           test_name;
6940         pr "      print_strings (r);\n";
6941         pr "      return -1;\n";
6942         pr "    }\n"
6943       in
6944       List.iter (generate_test_command_call test_name) seq;
6945       generate_test_command_call ~test test_name last
6946   | TestOutputListOfDevices (seq, expected) ->
6947       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6948       let seq, last = get_seq_last seq in
6949       let test () =
6950         iteri (
6951           fun i str ->
6952             pr "    if (!r[%d]) {\n" i;
6953             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6954             pr "      print_strings (r);\n";
6955             pr "      return -1;\n";
6956             pr "    }\n";
6957             pr "    {\n";
6958             pr "      const char *expected = \"%s\";\n" (c_quote str);
6959             pr "      r[%d][5] = 's';\n" i;
6960             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6961             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6962             pr "        return -1;\n";
6963             pr "      }\n";
6964             pr "    }\n"
6965         ) expected;
6966         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6967         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6968           test_name;
6969         pr "      print_strings (r);\n";
6970         pr "      return -1;\n";
6971         pr "    }\n"
6972       in
6973       List.iter (generate_test_command_call test_name) seq;
6974       generate_test_command_call ~test test_name last
6975   | TestOutputInt (seq, expected) ->
6976       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6977       let seq, last = get_seq_last seq in
6978       let test () =
6979         pr "    if (r != %d) {\n" expected;
6980         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6981           test_name expected;
6982         pr "               (int) r);\n";
6983         pr "      return -1;\n";
6984         pr "    }\n"
6985       in
6986       List.iter (generate_test_command_call test_name) seq;
6987       generate_test_command_call ~test test_name last
6988   | TestOutputIntOp (seq, op, expected) ->
6989       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6990       let seq, last = get_seq_last seq in
6991       let test () =
6992         pr "    if (! (r %s %d)) {\n" op expected;
6993         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6994           test_name op expected;
6995         pr "               (int) r);\n";
6996         pr "      return -1;\n";
6997         pr "    }\n"
6998       in
6999       List.iter (generate_test_command_call test_name) seq;
7000       generate_test_command_call ~test test_name last
7001   | TestOutputTrue seq ->
7002       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
7003       let seq, last = get_seq_last seq in
7004       let test () =
7005         pr "    if (!r) {\n";
7006         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
7007           test_name;
7008         pr "      return -1;\n";
7009         pr "    }\n"
7010       in
7011       List.iter (generate_test_command_call test_name) seq;
7012       generate_test_command_call ~test test_name last
7013   | TestOutputFalse seq ->
7014       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
7015       let seq, last = get_seq_last seq in
7016       let test () =
7017         pr "    if (r) {\n";
7018         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
7019           test_name;
7020         pr "      return -1;\n";
7021         pr "    }\n"
7022       in
7023       List.iter (generate_test_command_call test_name) seq;
7024       generate_test_command_call ~test test_name last
7025   | TestOutputLength (seq, expected) ->
7026       pr "  /* TestOutputLength for %s (%d) */\n" name i;
7027       let seq, last = get_seq_last seq in
7028       let test () =
7029         pr "    int j;\n";
7030         pr "    for (j = 0; j < %d; ++j)\n" expected;
7031         pr "      if (r[j] == NULL) {\n";
7032         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
7033           test_name;
7034         pr "        print_strings (r);\n";
7035         pr "        return -1;\n";
7036         pr "      }\n";
7037         pr "    if (r[j] != NULL) {\n";
7038         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
7039           test_name;
7040         pr "      print_strings (r);\n";
7041         pr "      return -1;\n";
7042         pr "    }\n"
7043       in
7044       List.iter (generate_test_command_call test_name) seq;
7045       generate_test_command_call ~test test_name last
7046   | TestOutputBuffer (seq, expected) ->
7047       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
7048       pr "  const char *expected = \"%s\";\n" (c_quote expected);
7049       let seq, last = get_seq_last seq in
7050       let len = String.length expected in
7051       let test () =
7052         pr "    if (size != %d) {\n" len;
7053         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
7054         pr "      return -1;\n";
7055         pr "    }\n";
7056         pr "    if (STRNEQLEN (r, expected, size)) {\n";
7057         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
7058         pr "      return -1;\n";
7059         pr "    }\n"
7060       in
7061       List.iter (generate_test_command_call test_name) seq;
7062       generate_test_command_call ~test test_name last
7063   | TestOutputStruct (seq, checks) ->
7064       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
7065       let seq, last = get_seq_last seq in
7066       let test () =
7067         List.iter (
7068           function
7069           | CompareWithInt (field, expected) ->
7070               pr "    if (r->%s != %d) {\n" field expected;
7071               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
7072                 test_name field expected;
7073               pr "               (int) r->%s);\n" field;
7074               pr "      return -1;\n";
7075               pr "    }\n"
7076           | CompareWithIntOp (field, op, expected) ->
7077               pr "    if (!(r->%s %s %d)) {\n" field op expected;
7078               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
7079                 test_name field op expected;
7080               pr "               (int) r->%s);\n" field;
7081               pr "      return -1;\n";
7082               pr "    }\n"
7083           | CompareWithString (field, expected) ->
7084               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
7085               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
7086                 test_name field expected;
7087               pr "               r->%s);\n" field;
7088               pr "      return -1;\n";
7089               pr "    }\n"
7090           | CompareFieldsIntEq (field1, field2) ->
7091               pr "    if (r->%s != r->%s) {\n" field1 field2;
7092               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
7093                 test_name field1 field2;
7094               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
7095               pr "      return -1;\n";
7096               pr "    }\n"
7097           | CompareFieldsStrEq (field1, field2) ->
7098               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
7099               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
7100                 test_name field1 field2;
7101               pr "               r->%s, r->%s);\n" field1 field2;
7102               pr "      return -1;\n";
7103               pr "    }\n"
7104         ) checks
7105       in
7106       List.iter (generate_test_command_call test_name) seq;
7107       generate_test_command_call ~test test_name last
7108   | TestLastFail seq ->
7109       pr "  /* TestLastFail for %s (%d) */\n" name i;
7110       let seq, last = get_seq_last seq in
7111       List.iter (generate_test_command_call test_name) seq;
7112       generate_test_command_call test_name ~expect_error:true last
7113
7114 (* Generate the code to run a command, leaving the result in 'r'.
7115  * If you expect to get an error then you should set expect_error:true.
7116  *)
7117 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
7118   match cmd with
7119   | [] -> assert false
7120   | name :: args ->
7121       (* Look up the command to find out what args/ret it has. *)
7122       let style =
7123         try
7124           let _, style, _, _, _, _, _ =
7125             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
7126           style
7127         with Not_found ->
7128           failwithf "%s: in test, command %s was not found" test_name name in
7129
7130       if List.length (snd style) <> List.length args then
7131         failwithf "%s: in test, wrong number of args given to %s"
7132           test_name name;
7133
7134       pr "  {\n";
7135
7136       List.iter (
7137         function
7138         | OptString n, "NULL" -> ()
7139         | Pathname n, arg
7140         | Device n, arg
7141         | Dev_or_Path n, arg
7142         | String n, arg
7143         | OptString n, arg ->
7144             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
7145         | Int _, _
7146         | Int64 _, _
7147         | Bool _, _
7148         | FileIn _, _ | FileOut _, _ -> ()
7149         | StringList n, "" | DeviceList n, "" ->
7150             pr "    const char *const %s[1] = { NULL };\n" n
7151         | StringList n, arg | DeviceList n, arg ->
7152             let strs = string_split " " arg in
7153             iteri (
7154               fun i str ->
7155                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
7156             ) strs;
7157             pr "    const char *const %s[] = {\n" n;
7158             iteri (
7159               fun i _ -> pr "      %s_%d,\n" n i
7160             ) strs;
7161             pr "      NULL\n";
7162             pr "    };\n";
7163       ) (List.combine (snd style) args);
7164
7165       let error_code =
7166         match fst style with
7167         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
7168         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
7169         | RConstString _ | RConstOptString _ ->
7170             pr "    const char *r;\n"; "NULL"
7171         | RString _ -> pr "    char *r;\n"; "NULL"
7172         | RStringList _ | RHashtable _ ->
7173             pr "    char **r;\n";
7174             pr "    int i;\n";
7175             "NULL"
7176         | RStruct (_, typ) ->
7177             pr "    struct guestfs_%s *r;\n" typ; "NULL"
7178         | RStructList (_, typ) ->
7179             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
7180         | RBufferOut _ ->
7181             pr "    char *r;\n";
7182             pr "    size_t size;\n";
7183             "NULL" in
7184
7185       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
7186       pr "    r = guestfs_%s (g" name;
7187
7188       (* Generate the parameters. *)
7189       List.iter (
7190         function
7191         | OptString _, "NULL" -> pr ", NULL"
7192         | Pathname n, _
7193         | Device n, _ | Dev_or_Path n, _
7194         | String n, _
7195         | OptString n, _ ->
7196             pr ", %s" n
7197         | FileIn _, arg | FileOut _, arg ->
7198             pr ", \"%s\"" (c_quote arg)
7199         | StringList n, _ | DeviceList n, _ ->
7200             pr ", (char **) %s" n
7201         | Int _, arg ->
7202             let i =
7203               try int_of_string arg
7204               with Failure "int_of_string" ->
7205                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
7206             pr ", %d" i
7207         | Int64 _, arg ->
7208             let i =
7209               try Int64.of_string arg
7210               with Failure "int_of_string" ->
7211                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
7212             pr ", %Ld" i
7213         | Bool _, arg ->
7214             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
7215       ) (List.combine (snd style) args);
7216
7217       (match fst style with
7218        | RBufferOut _ -> pr ", &size"
7219        | _ -> ()
7220       );
7221
7222       pr ");\n";
7223
7224       if not expect_error then
7225         pr "    if (r == %s)\n" error_code
7226       else
7227         pr "    if (r != %s)\n" error_code;
7228       pr "      return -1;\n";
7229
7230       (* Insert the test code. *)
7231       (match test with
7232        | None -> ()
7233        | Some f -> f ()
7234       );
7235
7236       (match fst style with
7237        | RErr | RInt _ | RInt64 _ | RBool _
7238        | RConstString _ | RConstOptString _ -> ()
7239        | RString _ | RBufferOut _ -> pr "    free (r);\n"
7240        | RStringList _ | RHashtable _ ->
7241            pr "    for (i = 0; r[i] != NULL; ++i)\n";
7242            pr "      free (r[i]);\n";
7243            pr "    free (r);\n"
7244        | RStruct (_, typ) ->
7245            pr "    guestfs_free_%s (r);\n" typ
7246        | RStructList (_, typ) ->
7247            pr "    guestfs_free_%s_list (r);\n" typ
7248       );
7249
7250       pr "  }\n"
7251
7252 and c_quote str =
7253   let str = replace_str str "\r" "\\r" in
7254   let str = replace_str str "\n" "\\n" in
7255   let str = replace_str str "\t" "\\t" in
7256   let str = replace_str str "\000" "\\0" in
7257   str
7258
7259 (* Generate a lot of different functions for guestfish. *)
7260 and generate_fish_cmds () =
7261   generate_header CStyle GPLv2plus;
7262
7263   let all_functions =
7264     List.filter (
7265       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7266     ) all_functions in
7267   let all_functions_sorted =
7268     List.filter (
7269       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7270     ) all_functions_sorted in
7271
7272   pr "#include <config.h>\n";
7273   pr "\n";
7274   pr "#include <stdio.h>\n";
7275   pr "#include <stdlib.h>\n";
7276   pr "#include <string.h>\n";
7277   pr "#include <inttypes.h>\n";
7278   pr "\n";
7279   pr "#include <guestfs.h>\n";
7280   pr "#include \"c-ctype.h\"\n";
7281   pr "#include \"full-write.h\"\n";
7282   pr "#include \"xstrtol.h\"\n";
7283   pr "#include \"fish.h\"\n";
7284   pr "\n";
7285
7286   (* list_commands function, which implements guestfish -h *)
7287   pr "void list_commands (void)\n";
7288   pr "{\n";
7289   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
7290   pr "  list_builtin_commands ();\n";
7291   List.iter (
7292     fun (name, _, _, flags, _, shortdesc, _) ->
7293       let name = replace_char name '_' '-' in
7294       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
7295         name shortdesc
7296   ) all_functions_sorted;
7297   pr "  printf (\"    %%s\\n\",";
7298   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
7299   pr "}\n";
7300   pr "\n";
7301
7302   (* display_command function, which implements guestfish -h cmd *)
7303   pr "void display_command (const char *cmd)\n";
7304   pr "{\n";
7305   List.iter (
7306     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7307       let name2 = replace_char name '_' '-' in
7308       let alias =
7309         try find_map (function FishAlias n -> Some n | _ -> None) flags
7310         with Not_found -> name in
7311       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
7312       let synopsis =
7313         match snd style with
7314         | [] -> name2
7315         | args ->
7316             sprintf "%s %s"
7317               name2 (String.concat " " (List.map name_of_argt args)) in
7318
7319       let warnings =
7320         if List.mem ProtocolLimitWarning flags then
7321           ("\n\n" ^ protocol_limit_warning)
7322         else "" in
7323
7324       (* For DangerWillRobinson commands, we should probably have
7325        * guestfish prompt before allowing you to use them (especially
7326        * in interactive mode). XXX
7327        *)
7328       let warnings =
7329         warnings ^
7330           if List.mem DangerWillRobinson flags then
7331             ("\n\n" ^ danger_will_robinson)
7332           else "" in
7333
7334       let warnings =
7335         warnings ^
7336           match deprecation_notice flags with
7337           | None -> ""
7338           | Some txt -> "\n\n" ^ txt in
7339
7340       let describe_alias =
7341         if name <> alias then
7342           sprintf "\n\nYou can use '%s' as an alias for this command." alias
7343         else "" in
7344
7345       pr "  if (";
7346       pr "STRCASEEQ (cmd, \"%s\")" name;
7347       if name <> name2 then
7348         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7349       if name <> alias then
7350         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7351       pr ")\n";
7352       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
7353         name2 shortdesc
7354         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
7355          "=head1 DESCRIPTION\n\n" ^
7356          longdesc ^ warnings ^ describe_alias);
7357       pr "  else\n"
7358   ) all_functions;
7359   pr "    display_builtin_command (cmd);\n";
7360   pr "}\n";
7361   pr "\n";
7362
7363   let emit_print_list_function typ =
7364     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
7365       typ typ typ;
7366     pr "{\n";
7367     pr "  unsigned int i;\n";
7368     pr "\n";
7369     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
7370     pr "    printf (\"[%%d] = {\\n\", i);\n";
7371     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
7372     pr "    printf (\"}\\n\");\n";
7373     pr "  }\n";
7374     pr "}\n";
7375     pr "\n";
7376   in
7377
7378   (* print_* functions *)
7379   List.iter (
7380     fun (typ, cols) ->
7381       let needs_i =
7382         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
7383
7384       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7385       pr "{\n";
7386       if needs_i then (
7387         pr "  unsigned int i;\n";
7388         pr "\n"
7389       );
7390       List.iter (
7391         function
7392         | name, FString ->
7393             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7394         | name, FUUID ->
7395             pr "  printf (\"%%s%s: \", indent);\n" name;
7396             pr "  for (i = 0; i < 32; ++i)\n";
7397             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7398             pr "  printf (\"\\n\");\n"
7399         | name, FBuffer ->
7400             pr "  printf (\"%%s%s: \", indent);\n" name;
7401             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7402             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7403             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7404             pr "    else\n";
7405             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7406             pr "  printf (\"\\n\");\n"
7407         | name, (FUInt64|FBytes) ->
7408             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7409               name typ name
7410         | name, FInt64 ->
7411             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7412               name typ name
7413         | name, FUInt32 ->
7414             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7415               name typ name
7416         | name, FInt32 ->
7417             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7418               name typ name
7419         | name, FChar ->
7420             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7421               name typ name
7422         | name, FOptPercent ->
7423             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7424               typ name name typ name;
7425             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7426       ) cols;
7427       pr "}\n";
7428       pr "\n";
7429   ) structs;
7430
7431   (* Emit a print_TYPE_list function definition only if that function is used. *)
7432   List.iter (
7433     function
7434     | typ, (RStructListOnly | RStructAndList) ->
7435         (* generate the function for typ *)
7436         emit_print_list_function typ
7437     | typ, _ -> () (* empty *)
7438   ) (rstructs_used_by all_functions);
7439
7440   (* Emit a print_TYPE function definition only if that function is used. *)
7441   List.iter (
7442     function
7443     | typ, (RStructOnly | RStructAndList) ->
7444         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7445         pr "{\n";
7446         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7447         pr "}\n";
7448         pr "\n";
7449     | typ, _ -> () (* empty *)
7450   ) (rstructs_used_by all_functions);
7451
7452   (* run_<action> actions *)
7453   List.iter (
7454     fun (name, style, _, flags, _, _, _) ->
7455       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7456       pr "{\n";
7457       (match fst style with
7458        | RErr
7459        | RInt _
7460        | RBool _ -> pr "  int r;\n"
7461        | RInt64 _ -> pr "  int64_t r;\n"
7462        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7463        | RString _ -> pr "  char *r;\n"
7464        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7465        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7466        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7467        | RBufferOut _ ->
7468            pr "  char *r;\n";
7469            pr "  size_t size;\n";
7470       );
7471       List.iter (
7472         function
7473         | Device n
7474         | String n
7475         | OptString n -> pr "  const char *%s;\n" n
7476         | Pathname n
7477         | Dev_or_Path n
7478         | FileIn n
7479         | FileOut n -> pr "  char *%s;\n" n
7480         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7481         | Bool n -> pr "  int %s;\n" n
7482         | Int n -> pr "  int %s;\n" n
7483         | Int64 n -> pr "  int64_t %s;\n" n
7484       ) (snd style);
7485
7486       (* Check and convert parameters. *)
7487       let argc_expected = List.length (snd style) in
7488       pr "  if (argc != %d) {\n" argc_expected;
7489       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7490         argc_expected;
7491       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7492       pr "    return -1;\n";
7493       pr "  }\n";
7494
7495       let parse_integer fn fntyp rtyp range name i =
7496         pr "  {\n";
7497         pr "    strtol_error xerr;\n";
7498         pr "    %s r;\n" fntyp;
7499         pr "\n";
7500         pr "    xerr = %s (argv[%d], NULL, 0, &r, \"\");\n" fn i;
7501         pr "    if (xerr != LONGINT_OK) {\n";
7502         pr "      fprintf (stderr,\n";
7503         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7504         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7505         pr "      return -1;\n";
7506         pr "    }\n";
7507         (match range with
7508          | None -> ()
7509          | Some (min, max, comment) ->
7510              pr "    /* %s */\n" comment;
7511              pr "    if (r < %s || r > %s) {\n" min max;
7512              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7513                name;
7514              pr "      return -1;\n";
7515              pr "    }\n";
7516              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7517         );
7518         pr "    %s = r;\n" name;
7519         pr "  }\n";
7520       in
7521
7522       iteri (
7523         fun i ->
7524           function
7525           | Device name
7526           | String name ->
7527               pr "  %s = argv[%d];\n" name i
7528           | Pathname name
7529           | Dev_or_Path name ->
7530               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7531               pr "  if (%s == NULL) return -1;\n" name
7532           | OptString name ->
7533               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7534                 name i i
7535           | FileIn name ->
7536               pr "  %s = file_in (argv[%d]);\n" name i;
7537               pr "  if (%s == NULL) return -1;\n" name
7538           | FileOut name ->
7539               pr "  %s = file_out (argv[%d]);\n" name i;
7540               pr "  if (%s == NULL) return -1;\n" name
7541           | StringList name | DeviceList name ->
7542               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7543               pr "  if (%s == NULL) return -1;\n" name;
7544           | Bool name ->
7545               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7546           | Int name ->
7547               let range =
7548                 let min = "(-(2LL<<30))"
7549                 and max = "((2LL<<30)-1)"
7550                 and comment =
7551                   "The Int type in the generator is a signed 31 bit int." in
7552                 Some (min, max, comment) in
7553               parse_integer "xstrtoll" "long long" "int" range name i
7554           | Int64 name ->
7555               parse_integer "xstrtoll" "long long" "int64_t" None name i
7556       ) (snd style);
7557
7558       (* Call C API function. *)
7559       let fn =
7560         try find_map (function FishAction n -> Some n | _ -> None) flags
7561         with Not_found -> sprintf "guestfs_%s" name in
7562       pr "  r = %s " fn;
7563       generate_c_call_args ~handle:"g" style;
7564       pr ";\n";
7565
7566       List.iter (
7567         function
7568         | Device name | String name
7569         | OptString name | Bool name
7570         | Int name | Int64 name -> ()
7571         | Pathname name | Dev_or_Path name | FileOut name ->
7572             pr "  free (%s);\n" name
7573         | FileIn name ->
7574             pr "  free_file_in (%s);\n" name
7575         | StringList name | DeviceList name ->
7576             pr "  free_strings (%s);\n" name
7577       ) (snd style);
7578
7579       (* Any output flags? *)
7580       let fish_output =
7581         let flags = filter_map (
7582           function FishOutput flag -> Some flag | _ -> None
7583         ) flags in
7584         match flags with
7585         | [] -> None
7586         | [f] -> Some f
7587         | _ ->
7588             failwithf "%s: more than one FishOutput flag is not allowed" name in
7589
7590       (* Check return value for errors and display command results. *)
7591       (match fst style with
7592        | RErr -> pr "  return r;\n"
7593        | RInt _ ->
7594            pr "  if (r == -1) return -1;\n";
7595            (match fish_output with
7596             | None ->
7597                 pr "  printf (\"%%d\\n\", r);\n";
7598             | Some FishOutputOctal ->
7599                 pr "  printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n";
7600             | Some FishOutputHexadecimal ->
7601                 pr "  printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7602            pr "  return 0;\n"
7603        | RInt64 _ ->
7604            pr "  if (r == -1) return -1;\n";
7605            (match fish_output with
7606             | None ->
7607                 pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7608             | Some FishOutputOctal ->
7609                 pr "  printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n";
7610             | Some FishOutputHexadecimal ->
7611                 pr "  printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7612            pr "  return 0;\n"
7613        | RBool _ ->
7614            pr "  if (r == -1) return -1;\n";
7615            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7616            pr "  return 0;\n"
7617        | RConstString _ ->
7618            pr "  if (r == NULL) return -1;\n";
7619            pr "  printf (\"%%s\\n\", r);\n";
7620            pr "  return 0;\n"
7621        | RConstOptString _ ->
7622            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7623            pr "  return 0;\n"
7624        | RString _ ->
7625            pr "  if (r == NULL) return -1;\n";
7626            pr "  printf (\"%%s\\n\", r);\n";
7627            pr "  free (r);\n";
7628            pr "  return 0;\n"
7629        | RStringList _ ->
7630            pr "  if (r == NULL) return -1;\n";
7631            pr "  print_strings (r);\n";
7632            pr "  free_strings (r);\n";
7633            pr "  return 0;\n"
7634        | RStruct (_, typ) ->
7635            pr "  if (r == NULL) return -1;\n";
7636            pr "  print_%s (r);\n" typ;
7637            pr "  guestfs_free_%s (r);\n" typ;
7638            pr "  return 0;\n"
7639        | RStructList (_, typ) ->
7640            pr "  if (r == NULL) return -1;\n";
7641            pr "  print_%s_list (r);\n" typ;
7642            pr "  guestfs_free_%s_list (r);\n" typ;
7643            pr "  return 0;\n"
7644        | RHashtable _ ->
7645            pr "  if (r == NULL) return -1;\n";
7646            pr "  print_table (r);\n";
7647            pr "  free_strings (r);\n";
7648            pr "  return 0;\n"
7649        | RBufferOut _ ->
7650            pr "  if (r == NULL) return -1;\n";
7651            pr "  if (full_write (1, r, size) != size) {\n";
7652            pr "    perror (\"write\");\n";
7653            pr "    free (r);\n";
7654            pr "    return -1;\n";
7655            pr "  }\n";
7656            pr "  free (r);\n";
7657            pr "  return 0;\n"
7658       );
7659       pr "}\n";
7660       pr "\n"
7661   ) all_functions;
7662
7663   (* run_action function *)
7664   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7665   pr "{\n";
7666   List.iter (
7667     fun (name, _, _, flags, _, _, _) ->
7668       let name2 = replace_char name '_' '-' in
7669       let alias =
7670         try find_map (function FishAlias n -> Some n | _ -> None) flags
7671         with Not_found -> name in
7672       pr "  if (";
7673       pr "STRCASEEQ (cmd, \"%s\")" name;
7674       if name <> name2 then
7675         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7676       if name <> alias then
7677         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7678       pr ")\n";
7679       pr "    return run_%s (cmd, argc, argv);\n" name;
7680       pr "  else\n";
7681   ) all_functions;
7682   pr "    {\n";
7683   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7684   pr "      if (command_num == 1)\n";
7685   pr "        extended_help_message ();\n";
7686   pr "      return -1;\n";
7687   pr "    }\n";
7688   pr "  return 0;\n";
7689   pr "}\n";
7690   pr "\n"
7691
7692 (* Readline completion for guestfish. *)
7693 and generate_fish_completion () =
7694   generate_header CStyle GPLv2plus;
7695
7696   let all_functions =
7697     List.filter (
7698       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7699     ) all_functions in
7700
7701   pr "\
7702 #include <config.h>
7703
7704 #include <stdio.h>
7705 #include <stdlib.h>
7706 #include <string.h>
7707
7708 #ifdef HAVE_LIBREADLINE
7709 #include <readline/readline.h>
7710 #endif
7711
7712 #include \"fish.h\"
7713
7714 #ifdef HAVE_LIBREADLINE
7715
7716 static const char *const commands[] = {
7717   BUILTIN_COMMANDS_FOR_COMPLETION,
7718 ";
7719
7720   (* Get the commands, including the aliases.  They don't need to be
7721    * sorted - the generator() function just does a dumb linear search.
7722    *)
7723   let commands =
7724     List.map (
7725       fun (name, _, _, flags, _, _, _) ->
7726         let name2 = replace_char name '_' '-' in
7727         let alias =
7728           try find_map (function FishAlias n -> Some n | _ -> None) flags
7729           with Not_found -> name in
7730
7731         if name <> alias then [name2; alias] else [name2]
7732     ) all_functions in
7733   let commands = List.flatten commands in
7734
7735   List.iter (pr "  \"%s\",\n") commands;
7736
7737   pr "  NULL
7738 };
7739
7740 static char *
7741 generator (const char *text, int state)
7742 {
7743   static int index, len;
7744   const char *name;
7745
7746   if (!state) {
7747     index = 0;
7748     len = strlen (text);
7749   }
7750
7751   rl_attempted_completion_over = 1;
7752
7753   while ((name = commands[index]) != NULL) {
7754     index++;
7755     if (STRCASEEQLEN (name, text, len))
7756       return strdup (name);
7757   }
7758
7759   return NULL;
7760 }
7761
7762 #endif /* HAVE_LIBREADLINE */
7763
7764 #ifdef HAVE_RL_COMPLETION_MATCHES
7765 #define RL_COMPLETION_MATCHES rl_completion_matches
7766 #else
7767 #ifdef HAVE_COMPLETION_MATCHES
7768 #define RL_COMPLETION_MATCHES completion_matches
7769 #endif
7770 #endif /* else just fail if we don't have either symbol */
7771
7772 char **
7773 do_completion (const char *text, int start, int end)
7774 {
7775   char **matches = NULL;
7776
7777 #ifdef HAVE_LIBREADLINE
7778   rl_completion_append_character = ' ';
7779
7780   if (start == 0)
7781     matches = RL_COMPLETION_MATCHES (text, generator);
7782   else if (complete_dest_paths)
7783     matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
7784 #endif
7785
7786   return matches;
7787 }
7788 ";
7789
7790 (* Generate the POD documentation for guestfish. *)
7791 and generate_fish_actions_pod () =
7792   let all_functions_sorted =
7793     List.filter (
7794       fun (_, _, _, flags, _, _, _) ->
7795         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7796     ) all_functions_sorted in
7797
7798   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7799
7800   List.iter (
7801     fun (name, style, _, flags, _, _, longdesc) ->
7802       let longdesc =
7803         Str.global_substitute rex (
7804           fun s ->
7805             let sub =
7806               try Str.matched_group 1 s
7807               with Not_found ->
7808                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7809             "C<" ^ replace_char sub '_' '-' ^ ">"
7810         ) longdesc in
7811       let name = replace_char name '_' '-' in
7812       let alias =
7813         try find_map (function FishAlias n -> Some n | _ -> None) flags
7814         with Not_found -> name in
7815
7816       pr "=head2 %s" name;
7817       if name <> alias then
7818         pr " | %s" alias;
7819       pr "\n";
7820       pr "\n";
7821       pr " %s" name;
7822       List.iter (
7823         function
7824         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7825         | OptString n -> pr " %s" n
7826         | StringList n | DeviceList n -> pr " '%s ...'" n
7827         | Bool _ -> pr " true|false"
7828         | Int n -> pr " %s" n
7829         | Int64 n -> pr " %s" n
7830         | FileIn n | FileOut n -> pr " (%s|-)" n
7831       ) (snd style);
7832       pr "\n";
7833       pr "\n";
7834       pr "%s\n\n" longdesc;
7835
7836       if List.exists (function FileIn _ | FileOut _ -> true
7837                       | _ -> false) (snd style) then
7838         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7839
7840       if List.mem ProtocolLimitWarning flags then
7841         pr "%s\n\n" protocol_limit_warning;
7842
7843       if List.mem DangerWillRobinson flags then
7844         pr "%s\n\n" danger_will_robinson;
7845
7846       match deprecation_notice flags with
7847       | None -> ()
7848       | Some txt -> pr "%s\n\n" txt
7849   ) all_functions_sorted
7850
7851 (* Generate a C function prototype. *)
7852 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7853     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7854     ?(prefix = "")
7855     ?handle name style =
7856   if extern then pr "extern ";
7857   if static then pr "static ";
7858   (match fst style with
7859    | RErr -> pr "int "
7860    | RInt _ -> pr "int "
7861    | RInt64 _ -> pr "int64_t "
7862    | RBool _ -> pr "int "
7863    | RConstString _ | RConstOptString _ -> pr "const char *"
7864    | RString _ | RBufferOut _ -> pr "char *"
7865    | RStringList _ | RHashtable _ -> pr "char **"
7866    | RStruct (_, typ) ->
7867        if not in_daemon then pr "struct guestfs_%s *" typ
7868        else pr "guestfs_int_%s *" typ
7869    | RStructList (_, typ) ->
7870        if not in_daemon then pr "struct guestfs_%s_list *" typ
7871        else pr "guestfs_int_%s_list *" typ
7872   );
7873   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7874   pr "%s%s (" prefix name;
7875   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7876     pr "void"
7877   else (
7878     let comma = ref false in
7879     (match handle with
7880      | None -> ()
7881      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7882     );
7883     let next () =
7884       if !comma then (
7885         if single_line then pr ", " else pr ",\n\t\t"
7886       );
7887       comma := true
7888     in
7889     List.iter (
7890       function
7891       | Pathname n
7892       | Device n | Dev_or_Path n
7893       | String n
7894       | OptString n ->
7895           next ();
7896           pr "const char *%s" n
7897       | StringList n | DeviceList n ->
7898           next ();
7899           pr "char *const *%s" n
7900       | Bool n -> next (); pr "int %s" n
7901       | Int n -> next (); pr "int %s" n
7902       | Int64 n -> next (); pr "int64_t %s" n
7903       | FileIn n
7904       | FileOut n ->
7905           if not in_daemon then (next (); pr "const char *%s" n)
7906     ) (snd style);
7907     if is_RBufferOut then (next (); pr "size_t *size_r");
7908   );
7909   pr ")";
7910   if semicolon then pr ";";
7911   if newline then pr "\n"
7912
7913 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7914 and generate_c_call_args ?handle ?(decl = false) style =
7915   pr "(";
7916   let comma = ref false in
7917   let next () =
7918     if !comma then pr ", ";
7919     comma := true
7920   in
7921   (match handle with
7922    | None -> ()
7923    | Some handle -> pr "%s" handle; comma := true
7924   );
7925   List.iter (
7926     fun arg ->
7927       next ();
7928       pr "%s" (name_of_argt arg)
7929   ) (snd style);
7930   (* For RBufferOut calls, add implicit &size parameter. *)
7931   if not decl then (
7932     match fst style with
7933     | RBufferOut _ ->
7934         next ();
7935         pr "&size"
7936     | _ -> ()
7937   );
7938   pr ")"
7939
7940 (* Generate the OCaml bindings interface. *)
7941 and generate_ocaml_mli () =
7942   generate_header OCamlStyle LGPLv2plus;
7943
7944   pr "\
7945 (** For API documentation you should refer to the C API
7946     in the guestfs(3) manual page.  The OCaml API uses almost
7947     exactly the same calls. *)
7948
7949 type t
7950 (** A [guestfs_h] handle. *)
7951
7952 exception Error of string
7953 (** This exception is raised when there is an error. *)
7954
7955 exception Handle_closed of string
7956 (** This exception is raised if you use a {!Guestfs.t} handle
7957     after calling {!close} on it.  The string is the name of
7958     the function. *)
7959
7960 val create : unit -> t
7961 (** Create a {!Guestfs.t} handle. *)
7962
7963 val close : t -> unit
7964 (** Close the {!Guestfs.t} handle and free up all resources used
7965     by it immediately.
7966
7967     Handles are closed by the garbage collector when they become
7968     unreferenced, but callers can call this in order to provide
7969     predictable cleanup. *)
7970
7971 ";
7972   generate_ocaml_structure_decls ();
7973
7974   (* The actions. *)
7975   List.iter (
7976     fun (name, style, _, _, _, shortdesc, _) ->
7977       generate_ocaml_prototype name style;
7978       pr "(** %s *)\n" shortdesc;
7979       pr "\n"
7980   ) all_functions_sorted
7981
7982 (* Generate the OCaml bindings implementation. *)
7983 and generate_ocaml_ml () =
7984   generate_header OCamlStyle LGPLv2plus;
7985
7986   pr "\
7987 type t
7988
7989 exception Error of string
7990 exception Handle_closed of string
7991
7992 external create : unit -> t = \"ocaml_guestfs_create\"
7993 external close : t -> unit = \"ocaml_guestfs_close\"
7994
7995 (* Give the exceptions names, so they can be raised from the C code. *)
7996 let () =
7997   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
7998   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
7999
8000 ";
8001
8002   generate_ocaml_structure_decls ();
8003
8004   (* The actions. *)
8005   List.iter (
8006     fun (name, style, _, _, _, shortdesc, _) ->
8007       generate_ocaml_prototype ~is_external:true name style;
8008   ) all_functions_sorted
8009
8010 (* Generate the OCaml bindings C implementation. *)
8011 and generate_ocaml_c () =
8012   generate_header CStyle LGPLv2plus;
8013
8014   pr "\
8015 #include <stdio.h>
8016 #include <stdlib.h>
8017 #include <string.h>
8018
8019 #include <caml/config.h>
8020 #include <caml/alloc.h>
8021 #include <caml/callback.h>
8022 #include <caml/fail.h>
8023 #include <caml/memory.h>
8024 #include <caml/mlvalues.h>
8025 #include <caml/signals.h>
8026
8027 #include <guestfs.h>
8028
8029 #include \"guestfs_c.h\"
8030
8031 /* Copy a hashtable of string pairs into an assoc-list.  We return
8032  * the list in reverse order, but hashtables aren't supposed to be
8033  * ordered anyway.
8034  */
8035 static CAMLprim value
8036 copy_table (char * const * argv)
8037 {
8038   CAMLparam0 ();
8039   CAMLlocal5 (rv, pairv, kv, vv, cons);
8040   int i;
8041
8042   rv = Val_int (0);
8043   for (i = 0; argv[i] != NULL; i += 2) {
8044     kv = caml_copy_string (argv[i]);
8045     vv = caml_copy_string (argv[i+1]);
8046     pairv = caml_alloc (2, 0);
8047     Store_field (pairv, 0, kv);
8048     Store_field (pairv, 1, vv);
8049     cons = caml_alloc (2, 0);
8050     Store_field (cons, 1, rv);
8051     rv = cons;
8052     Store_field (cons, 0, pairv);
8053   }
8054
8055   CAMLreturn (rv);
8056 }
8057
8058 ";
8059
8060   (* Struct copy functions. *)
8061
8062   let emit_ocaml_copy_list_function typ =
8063     pr "static CAMLprim value\n";
8064     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
8065     pr "{\n";
8066     pr "  CAMLparam0 ();\n";
8067     pr "  CAMLlocal2 (rv, v);\n";
8068     pr "  unsigned int i;\n";
8069     pr "\n";
8070     pr "  if (%ss->len == 0)\n" typ;
8071     pr "    CAMLreturn (Atom (0));\n";
8072     pr "  else {\n";
8073     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
8074     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
8075     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
8076     pr "      caml_modify (&Field (rv, i), v);\n";
8077     pr "    }\n";
8078     pr "    CAMLreturn (rv);\n";
8079     pr "  }\n";
8080     pr "}\n";
8081     pr "\n";
8082   in
8083
8084   List.iter (
8085     fun (typ, cols) ->
8086       let has_optpercent_col =
8087         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
8088
8089       pr "static CAMLprim value\n";
8090       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
8091       pr "{\n";
8092       pr "  CAMLparam0 ();\n";
8093       if has_optpercent_col then
8094         pr "  CAMLlocal3 (rv, v, v2);\n"
8095       else
8096         pr "  CAMLlocal2 (rv, v);\n";
8097       pr "\n";
8098       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
8099       iteri (
8100         fun i col ->
8101           (match col with
8102            | name, FString ->
8103                pr "  v = caml_copy_string (%s->%s);\n" typ name
8104            | name, FBuffer ->
8105                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
8106                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
8107                  typ name typ name
8108            | name, FUUID ->
8109                pr "  v = caml_alloc_string (32);\n";
8110                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
8111            | name, (FBytes|FInt64|FUInt64) ->
8112                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
8113            | name, (FInt32|FUInt32) ->
8114                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
8115            | name, FOptPercent ->
8116                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
8117                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
8118                pr "    v = caml_alloc (1, 0);\n";
8119                pr "    Store_field (v, 0, v2);\n";
8120                pr "  } else /* None */\n";
8121                pr "    v = Val_int (0);\n";
8122            | name, FChar ->
8123                pr "  v = Val_int (%s->%s);\n" typ name
8124           );
8125           pr "  Store_field (rv, %d, v);\n" i
8126       ) cols;
8127       pr "  CAMLreturn (rv);\n";
8128       pr "}\n";
8129       pr "\n";
8130   ) structs;
8131
8132   (* Emit a copy_TYPE_list function definition only if that function is used. *)
8133   List.iter (
8134     function
8135     | typ, (RStructListOnly | RStructAndList) ->
8136         (* generate the function for typ *)
8137         emit_ocaml_copy_list_function typ
8138     | typ, _ -> () (* empty *)
8139   ) (rstructs_used_by all_functions);
8140
8141   (* The wrappers. *)
8142   List.iter (
8143     fun (name, style, _, _, _, _, _) ->
8144       pr "/* Automatically generated wrapper for function\n";
8145       pr " * ";
8146       generate_ocaml_prototype name style;
8147       pr " */\n";
8148       pr "\n";
8149
8150       let params =
8151         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
8152
8153       let needs_extra_vs =
8154         match fst style with RConstOptString _ -> true | _ -> false in
8155
8156       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8157       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
8158       List.iter (pr ", value %s") (List.tl params); pr ");\n";
8159       pr "\n";
8160
8161       pr "CAMLprim value\n";
8162       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
8163       List.iter (pr ", value %s") (List.tl params);
8164       pr ")\n";
8165       pr "{\n";
8166
8167       (match params with
8168        | [p1; p2; p3; p4; p5] ->
8169            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
8170        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
8171            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
8172            pr "  CAMLxparam%d (%s);\n"
8173              (List.length rest) (String.concat ", " rest)
8174        | ps ->
8175            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
8176       );
8177       if not needs_extra_vs then
8178         pr "  CAMLlocal1 (rv);\n"
8179       else
8180         pr "  CAMLlocal3 (rv, v, v2);\n";
8181       pr "\n";
8182
8183       pr "  guestfs_h *g = Guestfs_val (gv);\n";
8184       pr "  if (g == NULL)\n";
8185       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
8186       pr "\n";
8187
8188       List.iter (
8189         function
8190         | Pathname n
8191         | Device n | Dev_or_Path n
8192         | String n
8193         | FileIn n
8194         | FileOut n ->
8195             pr "  const char *%s = String_val (%sv);\n" n n
8196         | OptString n ->
8197             pr "  const char *%s =\n" n;
8198             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
8199               n n
8200         | StringList n | DeviceList n ->
8201             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
8202         | Bool n ->
8203             pr "  int %s = Bool_val (%sv);\n" n n
8204         | Int n ->
8205             pr "  int %s = Int_val (%sv);\n" n n
8206         | Int64 n ->
8207             pr "  int64_t %s = Int64_val (%sv);\n" n n
8208       ) (snd style);
8209       let error_code =
8210         match fst style with
8211         | RErr -> pr "  int r;\n"; "-1"
8212         | RInt _ -> pr "  int r;\n"; "-1"
8213         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8214         | RBool _ -> pr "  int r;\n"; "-1"
8215         | RConstString _ | RConstOptString _ ->
8216             pr "  const char *r;\n"; "NULL"
8217         | RString _ -> pr "  char *r;\n"; "NULL"
8218         | RStringList _ ->
8219             pr "  int i;\n";
8220             pr "  char **r;\n";
8221             "NULL"
8222         | RStruct (_, typ) ->
8223             pr "  struct guestfs_%s *r;\n" typ; "NULL"
8224         | RStructList (_, typ) ->
8225             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8226         | RHashtable _ ->
8227             pr "  int i;\n";
8228             pr "  char **r;\n";
8229             "NULL"
8230         | RBufferOut _ ->
8231             pr "  char *r;\n";
8232             pr "  size_t size;\n";
8233             "NULL" in
8234       pr "\n";
8235
8236       pr "  caml_enter_blocking_section ();\n";
8237       pr "  r = guestfs_%s " name;
8238       generate_c_call_args ~handle:"g" style;
8239       pr ";\n";
8240       pr "  caml_leave_blocking_section ();\n";
8241
8242       List.iter (
8243         function
8244         | StringList n | DeviceList n ->
8245             pr "  ocaml_guestfs_free_strings (%s);\n" n;
8246         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8247         | Bool _ | Int _ | Int64 _
8248         | FileIn _ | FileOut _ -> ()
8249       ) (snd style);
8250
8251       pr "  if (r == %s)\n" error_code;
8252       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
8253       pr "\n";
8254
8255       (match fst style with
8256        | RErr -> pr "  rv = Val_unit;\n"
8257        | RInt _ -> pr "  rv = Val_int (r);\n"
8258        | RInt64 _ ->
8259            pr "  rv = caml_copy_int64 (r);\n"
8260        | RBool _ -> pr "  rv = Val_bool (r);\n"
8261        | RConstString _ ->
8262            pr "  rv = caml_copy_string (r);\n"
8263        | RConstOptString _ ->
8264            pr "  if (r) { /* Some string */\n";
8265            pr "    v = caml_alloc (1, 0);\n";
8266            pr "    v2 = caml_copy_string (r);\n";
8267            pr "    Store_field (v, 0, v2);\n";
8268            pr "  } else /* None */\n";
8269            pr "    v = Val_int (0);\n";
8270        | RString _ ->
8271            pr "  rv = caml_copy_string (r);\n";
8272            pr "  free (r);\n"
8273        | RStringList _ ->
8274            pr "  rv = caml_copy_string_array ((const char **) r);\n";
8275            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8276            pr "  free (r);\n"
8277        | RStruct (_, typ) ->
8278            pr "  rv = copy_%s (r);\n" typ;
8279            pr "  guestfs_free_%s (r);\n" typ;
8280        | RStructList (_, typ) ->
8281            pr "  rv = copy_%s_list (r);\n" typ;
8282            pr "  guestfs_free_%s_list (r);\n" typ;
8283        | RHashtable _ ->
8284            pr "  rv = copy_table (r);\n";
8285            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8286            pr "  free (r);\n";
8287        | RBufferOut _ ->
8288            pr "  rv = caml_alloc_string (size);\n";
8289            pr "  memcpy (String_val (rv), r, size);\n";
8290       );
8291
8292       pr "  CAMLreturn (rv);\n";
8293       pr "}\n";
8294       pr "\n";
8295
8296       if List.length params > 5 then (
8297         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8298         pr "CAMLprim value ";
8299         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
8300         pr "CAMLprim value\n";
8301         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
8302         pr "{\n";
8303         pr "  return ocaml_guestfs_%s (argv[0]" name;
8304         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
8305         pr ");\n";
8306         pr "}\n";
8307         pr "\n"
8308       )
8309   ) all_functions_sorted
8310
8311 and generate_ocaml_structure_decls () =
8312   List.iter (
8313     fun (typ, cols) ->
8314       pr "type %s = {\n" typ;
8315       List.iter (
8316         function
8317         | name, FString -> pr "  %s : string;\n" name
8318         | name, FBuffer -> pr "  %s : string;\n" name
8319         | name, FUUID -> pr "  %s : string;\n" name
8320         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
8321         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
8322         | name, FChar -> pr "  %s : char;\n" name
8323         | name, FOptPercent -> pr "  %s : float option;\n" name
8324       ) cols;
8325       pr "}\n";
8326       pr "\n"
8327   ) structs
8328
8329 and generate_ocaml_prototype ?(is_external = false) name style =
8330   if is_external then pr "external " else pr "val ";
8331   pr "%s : t -> " name;
8332   List.iter (
8333     function
8334     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
8335     | OptString _ -> pr "string option -> "
8336     | StringList _ | DeviceList _ -> pr "string array -> "
8337     | Bool _ -> pr "bool -> "
8338     | Int _ -> pr "int -> "
8339     | Int64 _ -> pr "int64 -> "
8340   ) (snd style);
8341   (match fst style with
8342    | RErr -> pr "unit" (* all errors are turned into exceptions *)
8343    | RInt _ -> pr "int"
8344    | RInt64 _ -> pr "int64"
8345    | RBool _ -> pr "bool"
8346    | RConstString _ -> pr "string"
8347    | RConstOptString _ -> pr "string option"
8348    | RString _ | RBufferOut _ -> pr "string"
8349    | RStringList _ -> pr "string array"
8350    | RStruct (_, typ) -> pr "%s" typ
8351    | RStructList (_, typ) -> pr "%s array" typ
8352    | RHashtable _ -> pr "(string * string) list"
8353   );
8354   if is_external then (
8355     pr " = ";
8356     if List.length (snd style) + 1 > 5 then
8357       pr "\"ocaml_guestfs_%s_byte\" " name;
8358     pr "\"ocaml_guestfs_%s\"" name
8359   );
8360   pr "\n"
8361
8362 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
8363 and generate_perl_xs () =
8364   generate_header CStyle LGPLv2plus;
8365
8366   pr "\
8367 #include \"EXTERN.h\"
8368 #include \"perl.h\"
8369 #include \"XSUB.h\"
8370
8371 #include <guestfs.h>
8372
8373 #ifndef PRId64
8374 #define PRId64 \"lld\"
8375 #endif
8376
8377 static SV *
8378 my_newSVll(long long val) {
8379 #ifdef USE_64_BIT_ALL
8380   return newSViv(val);
8381 #else
8382   char buf[100];
8383   int len;
8384   len = snprintf(buf, 100, \"%%\" PRId64, val);
8385   return newSVpv(buf, len);
8386 #endif
8387 }
8388
8389 #ifndef PRIu64
8390 #define PRIu64 \"llu\"
8391 #endif
8392
8393 static SV *
8394 my_newSVull(unsigned long long val) {
8395 #ifdef USE_64_BIT_ALL
8396   return newSVuv(val);
8397 #else
8398   char buf[100];
8399   int len;
8400   len = snprintf(buf, 100, \"%%\" PRIu64, val);
8401   return newSVpv(buf, len);
8402 #endif
8403 }
8404
8405 /* http://www.perlmonks.org/?node_id=680842 */
8406 static char **
8407 XS_unpack_charPtrPtr (SV *arg) {
8408   char **ret;
8409   AV *av;
8410   I32 i;
8411
8412   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
8413     croak (\"array reference expected\");
8414
8415   av = (AV *)SvRV (arg);
8416   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
8417   if (!ret)
8418     croak (\"malloc failed\");
8419
8420   for (i = 0; i <= av_len (av); i++) {
8421     SV **elem = av_fetch (av, i, 0);
8422
8423     if (!elem || !*elem)
8424       croak (\"missing element in list\");
8425
8426     ret[i] = SvPV_nolen (*elem);
8427   }
8428
8429   ret[i] = NULL;
8430
8431   return ret;
8432 }
8433
8434 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8435
8436 PROTOTYPES: ENABLE
8437
8438 guestfs_h *
8439 _create ()
8440    CODE:
8441       RETVAL = guestfs_create ();
8442       if (!RETVAL)
8443         croak (\"could not create guestfs handle\");
8444       guestfs_set_error_handler (RETVAL, NULL, NULL);
8445  OUTPUT:
8446       RETVAL
8447
8448 void
8449 DESTROY (g)
8450       guestfs_h *g;
8451  PPCODE:
8452       guestfs_close (g);
8453
8454 ";
8455
8456   List.iter (
8457     fun (name, style, _, _, _, _, _) ->
8458       (match fst style with
8459        | RErr -> pr "void\n"
8460        | RInt _ -> pr "SV *\n"
8461        | RInt64 _ -> pr "SV *\n"
8462        | RBool _ -> pr "SV *\n"
8463        | RConstString _ -> pr "SV *\n"
8464        | RConstOptString _ -> pr "SV *\n"
8465        | RString _ -> pr "SV *\n"
8466        | RBufferOut _ -> pr "SV *\n"
8467        | RStringList _
8468        | RStruct _ | RStructList _
8469        | RHashtable _ ->
8470            pr "void\n" (* all lists returned implictly on the stack *)
8471       );
8472       (* Call and arguments. *)
8473       pr "%s " name;
8474       generate_c_call_args ~handle:"g" ~decl:true style;
8475       pr "\n";
8476       pr "      guestfs_h *g;\n";
8477       iteri (
8478         fun i ->
8479           function
8480           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8481               pr "      char *%s;\n" n
8482           | OptString n ->
8483               (* http://www.perlmonks.org/?node_id=554277
8484                * Note that the implicit handle argument means we have
8485                * to add 1 to the ST(x) operator.
8486                *)
8487               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8488           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8489           | Bool n -> pr "      int %s;\n" n
8490           | Int n -> pr "      int %s;\n" n
8491           | Int64 n -> pr "      int64_t %s;\n" n
8492       ) (snd style);
8493
8494       let do_cleanups () =
8495         List.iter (
8496           function
8497           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8498           | Bool _ | Int _ | Int64 _
8499           | FileIn _ | FileOut _ -> ()
8500           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8501         ) (snd style)
8502       in
8503
8504       (* Code. *)
8505       (match fst style with
8506        | RErr ->
8507            pr "PREINIT:\n";
8508            pr "      int r;\n";
8509            pr " PPCODE:\n";
8510            pr "      r = guestfs_%s " name;
8511            generate_c_call_args ~handle:"g" style;
8512            pr ";\n";
8513            do_cleanups ();
8514            pr "      if (r == -1)\n";
8515            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8516        | RInt n
8517        | RBool n ->
8518            pr "PREINIT:\n";
8519            pr "      int %s;\n" n;
8520            pr "   CODE:\n";
8521            pr "      %s = guestfs_%s " n name;
8522            generate_c_call_args ~handle:"g" style;
8523            pr ";\n";
8524            do_cleanups ();
8525            pr "      if (%s == -1)\n" n;
8526            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8527            pr "      RETVAL = newSViv (%s);\n" n;
8528            pr " OUTPUT:\n";
8529            pr "      RETVAL\n"
8530        | RInt64 n ->
8531            pr "PREINIT:\n";
8532            pr "      int64_t %s;\n" n;
8533            pr "   CODE:\n";
8534            pr "      %s = guestfs_%s " n name;
8535            generate_c_call_args ~handle:"g" style;
8536            pr ";\n";
8537            do_cleanups ();
8538            pr "      if (%s == -1)\n" n;
8539            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8540            pr "      RETVAL = my_newSVll (%s);\n" n;
8541            pr " OUTPUT:\n";
8542            pr "      RETVAL\n"
8543        | RConstString n ->
8544            pr "PREINIT:\n";
8545            pr "      const char *%s;\n" n;
8546            pr "   CODE:\n";
8547            pr "      %s = guestfs_%s " n name;
8548            generate_c_call_args ~handle:"g" style;
8549            pr ";\n";
8550            do_cleanups ();
8551            pr "      if (%s == NULL)\n" n;
8552            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8553            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8554            pr " OUTPUT:\n";
8555            pr "      RETVAL\n"
8556        | RConstOptString n ->
8557            pr "PREINIT:\n";
8558            pr "      const char *%s;\n" n;
8559            pr "   CODE:\n";
8560            pr "      %s = guestfs_%s " n name;
8561            generate_c_call_args ~handle:"g" style;
8562            pr ";\n";
8563            do_cleanups ();
8564            pr "      if (%s == NULL)\n" n;
8565            pr "        RETVAL = &PL_sv_undef;\n";
8566            pr "      else\n";
8567            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8568            pr " OUTPUT:\n";
8569            pr "      RETVAL\n"
8570        | RString n ->
8571            pr "PREINIT:\n";
8572            pr "      char *%s;\n" n;
8573            pr "   CODE:\n";
8574            pr "      %s = guestfs_%s " n name;
8575            generate_c_call_args ~handle:"g" style;
8576            pr ";\n";
8577            do_cleanups ();
8578            pr "      if (%s == NULL)\n" n;
8579            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8580            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8581            pr "      free (%s);\n" n;
8582            pr " OUTPUT:\n";
8583            pr "      RETVAL\n"
8584        | RStringList n | RHashtable n ->
8585            pr "PREINIT:\n";
8586            pr "      char **%s;\n" n;
8587            pr "      int i, n;\n";
8588            pr " PPCODE:\n";
8589            pr "      %s = guestfs_%s " n name;
8590            generate_c_call_args ~handle:"g" style;
8591            pr ";\n";
8592            do_cleanups ();
8593            pr "      if (%s == NULL)\n" n;
8594            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8595            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8596            pr "      EXTEND (SP, n);\n";
8597            pr "      for (i = 0; i < n; ++i) {\n";
8598            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8599            pr "        free (%s[i]);\n" n;
8600            pr "      }\n";
8601            pr "      free (%s);\n" n;
8602        | RStruct (n, typ) ->
8603            let cols = cols_of_struct typ in
8604            generate_perl_struct_code typ cols name style n do_cleanups
8605        | RStructList (n, typ) ->
8606            let cols = cols_of_struct typ in
8607            generate_perl_struct_list_code typ cols name style n do_cleanups
8608        | RBufferOut n ->
8609            pr "PREINIT:\n";
8610            pr "      char *%s;\n" n;
8611            pr "      size_t size;\n";
8612            pr "   CODE:\n";
8613            pr "      %s = guestfs_%s " n name;
8614            generate_c_call_args ~handle:"g" style;
8615            pr ";\n";
8616            do_cleanups ();
8617            pr "      if (%s == NULL)\n" n;
8618            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8619            pr "      RETVAL = newSVpvn (%s, size);\n" n;
8620            pr "      free (%s);\n" n;
8621            pr " OUTPUT:\n";
8622            pr "      RETVAL\n"
8623       );
8624
8625       pr "\n"
8626   ) all_functions
8627
8628 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8629   pr "PREINIT:\n";
8630   pr "      struct guestfs_%s_list *%s;\n" typ n;
8631   pr "      int i;\n";
8632   pr "      HV *hv;\n";
8633   pr " PPCODE:\n";
8634   pr "      %s = guestfs_%s " n name;
8635   generate_c_call_args ~handle:"g" style;
8636   pr ";\n";
8637   do_cleanups ();
8638   pr "      if (%s == NULL)\n" n;
8639   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8640   pr "      EXTEND (SP, %s->len);\n" n;
8641   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8642   pr "        hv = newHV ();\n";
8643   List.iter (
8644     function
8645     | name, FString ->
8646         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8647           name (String.length name) n name
8648     | name, FUUID ->
8649         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8650           name (String.length name) n name
8651     | name, FBuffer ->
8652         pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8653           name (String.length name) n name n name
8654     | name, (FBytes|FUInt64) ->
8655         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8656           name (String.length name) n name
8657     | name, FInt64 ->
8658         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8659           name (String.length name) n name
8660     | name, (FInt32|FUInt32) ->
8661         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8662           name (String.length name) n name
8663     | name, FChar ->
8664         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8665           name (String.length name) n name
8666     | name, FOptPercent ->
8667         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8668           name (String.length name) n name
8669   ) cols;
8670   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8671   pr "      }\n";
8672   pr "      guestfs_free_%s_list (%s);\n" typ n
8673
8674 and generate_perl_struct_code typ cols name style n do_cleanups =
8675   pr "PREINIT:\n";
8676   pr "      struct guestfs_%s *%s;\n" typ n;
8677   pr " PPCODE:\n";
8678   pr "      %s = guestfs_%s " n name;
8679   generate_c_call_args ~handle:"g" style;
8680   pr ";\n";
8681   do_cleanups ();
8682   pr "      if (%s == NULL)\n" n;
8683   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8684   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8685   List.iter (
8686     fun ((name, _) as col) ->
8687       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8688
8689       match col with
8690       | name, FString ->
8691           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8692             n name
8693       | name, FBuffer ->
8694           pr "      PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
8695             n name n name
8696       | name, FUUID ->
8697           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8698             n name
8699       | name, (FBytes|FUInt64) ->
8700           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8701             n name
8702       | name, FInt64 ->
8703           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8704             n name
8705       | name, (FInt32|FUInt32) ->
8706           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8707             n name
8708       | name, FChar ->
8709           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8710             n name
8711       | name, FOptPercent ->
8712           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8713             n name
8714   ) cols;
8715   pr "      free (%s);\n" n
8716
8717 (* Generate Sys/Guestfs.pm. *)
8718 and generate_perl_pm () =
8719   generate_header HashStyle LGPLv2plus;
8720
8721   pr "\
8722 =pod
8723
8724 =head1 NAME
8725
8726 Sys::Guestfs - Perl bindings for libguestfs
8727
8728 =head1 SYNOPSIS
8729
8730  use Sys::Guestfs;
8731
8732  my $h = Sys::Guestfs->new ();
8733  $h->add_drive ('guest.img');
8734  $h->launch ();
8735  $h->mount ('/dev/sda1', '/');
8736  $h->touch ('/hello');
8737  $h->sync ();
8738
8739 =head1 DESCRIPTION
8740
8741 The C<Sys::Guestfs> module provides a Perl XS binding to the
8742 libguestfs API for examining and modifying virtual machine
8743 disk images.
8744
8745 Amongst the things this is good for: making batch configuration
8746 changes to guests, getting disk used/free statistics (see also:
8747 virt-df), migrating between virtualization systems (see also:
8748 virt-p2v), performing partial backups, performing partial guest
8749 clones, cloning guests and changing registry/UUID/hostname info, and
8750 much else besides.
8751
8752 Libguestfs uses Linux kernel and qemu code, and can access any type of
8753 guest filesystem that Linux and qemu can, including but not limited
8754 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8755 schemes, qcow, qcow2, vmdk.
8756
8757 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8758 LVs, what filesystem is in each LV, etc.).  It can also run commands
8759 in the context of the guest.  Also you can access filesystems over
8760 FUSE.
8761
8762 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8763 functions for using libguestfs from Perl, including integration
8764 with libvirt.
8765
8766 =head1 ERRORS
8767
8768 All errors turn into calls to C<croak> (see L<Carp(3)>).
8769
8770 =head1 METHODS
8771
8772 =over 4
8773
8774 =cut
8775
8776 package Sys::Guestfs;
8777
8778 use strict;
8779 use warnings;
8780
8781 require XSLoader;
8782 XSLoader::load ('Sys::Guestfs');
8783
8784 =item $h = Sys::Guestfs->new ();
8785
8786 Create a new guestfs handle.
8787
8788 =cut
8789
8790 sub new {
8791   my $proto = shift;
8792   my $class = ref ($proto) || $proto;
8793
8794   my $self = Sys::Guestfs::_create ();
8795   bless $self, $class;
8796   return $self;
8797 }
8798
8799 ";
8800
8801   (* Actions.  We only need to print documentation for these as
8802    * they are pulled in from the XS code automatically.
8803    *)
8804   List.iter (
8805     fun (name, style, _, flags, _, _, longdesc) ->
8806       if not (List.mem NotInDocs flags) then (
8807         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8808         pr "=item ";
8809         generate_perl_prototype name style;
8810         pr "\n\n";
8811         pr "%s\n\n" longdesc;
8812         if List.mem ProtocolLimitWarning flags then
8813           pr "%s\n\n" protocol_limit_warning;
8814         if List.mem DangerWillRobinson flags then
8815           pr "%s\n\n" danger_will_robinson;
8816         match deprecation_notice flags with
8817         | None -> ()
8818         | Some txt -> pr "%s\n\n" txt
8819       )
8820   ) all_functions_sorted;
8821
8822   (* End of file. *)
8823   pr "\
8824 =cut
8825
8826 1;
8827
8828 =back
8829
8830 =head1 COPYRIGHT
8831
8832 Copyright (C) %s Red Hat Inc.
8833
8834 =head1 LICENSE
8835
8836 Please see the file COPYING.LIB for the full license.
8837
8838 =head1 SEE ALSO
8839
8840 L<guestfs(3)>,
8841 L<guestfish(1)>,
8842 L<http://libguestfs.org>,
8843 L<Sys::Guestfs::Lib(3)>.
8844
8845 =cut
8846 " copyright_years
8847
8848 and generate_perl_prototype name style =
8849   (match fst style with
8850    | RErr -> ()
8851    | RBool n
8852    | RInt n
8853    | RInt64 n
8854    | RConstString n
8855    | RConstOptString n
8856    | RString n
8857    | RBufferOut n -> pr "$%s = " n
8858    | RStruct (n,_)
8859    | RHashtable n -> pr "%%%s = " n
8860    | RStringList n
8861    | RStructList (n,_) -> pr "@%s = " n
8862   );
8863   pr "$h->%s (" name;
8864   let comma = ref false in
8865   List.iter (
8866     fun arg ->
8867       if !comma then pr ", ";
8868       comma := true;
8869       match arg with
8870       | Pathname n | Device n | Dev_or_Path n | String n
8871       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8872           pr "$%s" n
8873       | StringList n | DeviceList n ->
8874           pr "\\@%s" n
8875   ) (snd style);
8876   pr ");"
8877
8878 (* Generate Python C module. *)
8879 and generate_python_c () =
8880   generate_header CStyle LGPLv2plus;
8881
8882   pr "\
8883 #include <Python.h>
8884
8885 #include <stdio.h>
8886 #include <stdlib.h>
8887 #include <assert.h>
8888
8889 #include \"guestfs.h\"
8890
8891 typedef struct {
8892   PyObject_HEAD
8893   guestfs_h *g;
8894 } Pyguestfs_Object;
8895
8896 static guestfs_h *
8897 get_handle (PyObject *obj)
8898 {
8899   assert (obj);
8900   assert (obj != Py_None);
8901   return ((Pyguestfs_Object *) obj)->g;
8902 }
8903
8904 static PyObject *
8905 put_handle (guestfs_h *g)
8906 {
8907   assert (g);
8908   return
8909     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8910 }
8911
8912 /* This list should be freed (but not the strings) after use. */
8913 static char **
8914 get_string_list (PyObject *obj)
8915 {
8916   int i, len;
8917   char **r;
8918
8919   assert (obj);
8920
8921   if (!PyList_Check (obj)) {
8922     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8923     return NULL;
8924   }
8925
8926   len = PyList_Size (obj);
8927   r = malloc (sizeof (char *) * (len+1));
8928   if (r == NULL) {
8929     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8930     return NULL;
8931   }
8932
8933   for (i = 0; i < len; ++i)
8934     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8935   r[len] = NULL;
8936
8937   return r;
8938 }
8939
8940 static PyObject *
8941 put_string_list (char * const * const argv)
8942 {
8943   PyObject *list;
8944   int argc, i;
8945
8946   for (argc = 0; argv[argc] != NULL; ++argc)
8947     ;
8948
8949   list = PyList_New (argc);
8950   for (i = 0; i < argc; ++i)
8951     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8952
8953   return list;
8954 }
8955
8956 static PyObject *
8957 put_table (char * const * const argv)
8958 {
8959   PyObject *list, *item;
8960   int argc, i;
8961
8962   for (argc = 0; argv[argc] != NULL; ++argc)
8963     ;
8964
8965   list = PyList_New (argc >> 1);
8966   for (i = 0; i < argc; i += 2) {
8967     item = PyTuple_New (2);
8968     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8969     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8970     PyList_SetItem (list, i >> 1, item);
8971   }
8972
8973   return list;
8974 }
8975
8976 static void
8977 free_strings (char **argv)
8978 {
8979   int argc;
8980
8981   for (argc = 0; argv[argc] != NULL; ++argc)
8982     free (argv[argc]);
8983   free (argv);
8984 }
8985
8986 static PyObject *
8987 py_guestfs_create (PyObject *self, PyObject *args)
8988 {
8989   guestfs_h *g;
8990
8991   g = guestfs_create ();
8992   if (g == NULL) {
8993     PyErr_SetString (PyExc_RuntimeError,
8994                      \"guestfs.create: failed to allocate handle\");
8995     return NULL;
8996   }
8997   guestfs_set_error_handler (g, NULL, NULL);
8998   return put_handle (g);
8999 }
9000
9001 static PyObject *
9002 py_guestfs_close (PyObject *self, PyObject *args)
9003 {
9004   PyObject *py_g;
9005   guestfs_h *g;
9006
9007   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
9008     return NULL;
9009   g = get_handle (py_g);
9010
9011   guestfs_close (g);
9012
9013   Py_INCREF (Py_None);
9014   return Py_None;
9015 }
9016
9017 ";
9018
9019   let emit_put_list_function typ =
9020     pr "static PyObject *\n";
9021     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
9022     pr "{\n";
9023     pr "  PyObject *list;\n";
9024     pr "  int i;\n";
9025     pr "\n";
9026     pr "  list = PyList_New (%ss->len);\n" typ;
9027     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
9028     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
9029     pr "  return list;\n";
9030     pr "};\n";
9031     pr "\n"
9032   in
9033
9034   (* Structures, turned into Python dictionaries. *)
9035   List.iter (
9036     fun (typ, cols) ->
9037       pr "static PyObject *\n";
9038       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
9039       pr "{\n";
9040       pr "  PyObject *dict;\n";
9041       pr "\n";
9042       pr "  dict = PyDict_New ();\n";
9043       List.iter (
9044         function
9045         | name, FString ->
9046             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9047             pr "                        PyString_FromString (%s->%s));\n"
9048               typ name
9049         | name, FBuffer ->
9050             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9051             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
9052               typ name typ name
9053         | name, FUUID ->
9054             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9055             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
9056               typ name
9057         | name, (FBytes|FUInt64) ->
9058             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9059             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
9060               typ name
9061         | name, FInt64 ->
9062             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9063             pr "                        PyLong_FromLongLong (%s->%s));\n"
9064               typ name
9065         | name, FUInt32 ->
9066             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9067             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
9068               typ name
9069         | name, FInt32 ->
9070             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9071             pr "                        PyLong_FromLong (%s->%s));\n"
9072               typ name
9073         | name, FOptPercent ->
9074             pr "  if (%s->%s >= 0)\n" typ name;
9075             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
9076             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
9077               typ name;
9078             pr "  else {\n";
9079             pr "    Py_INCREF (Py_None);\n";
9080             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
9081             pr "  }\n"
9082         | name, FChar ->
9083             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9084             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
9085       ) cols;
9086       pr "  return dict;\n";
9087       pr "};\n";
9088       pr "\n";
9089
9090   ) structs;
9091
9092   (* Emit a put_TYPE_list function definition only if that function is used. *)
9093   List.iter (
9094     function
9095     | typ, (RStructListOnly | RStructAndList) ->
9096         (* generate the function for typ *)
9097         emit_put_list_function typ
9098     | typ, _ -> () (* empty *)
9099   ) (rstructs_used_by all_functions);
9100
9101   (* Python wrapper functions. *)
9102   List.iter (
9103     fun (name, style, _, _, _, _, _) ->
9104       pr "static PyObject *\n";
9105       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
9106       pr "{\n";
9107
9108       pr "  PyObject *py_g;\n";
9109       pr "  guestfs_h *g;\n";
9110       pr "  PyObject *py_r;\n";
9111
9112       let error_code =
9113         match fst style with
9114         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9115         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9116         | RConstString _ | RConstOptString _ ->
9117             pr "  const char *r;\n"; "NULL"
9118         | RString _ -> pr "  char *r;\n"; "NULL"
9119         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9120         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9121         | RStructList (_, typ) ->
9122             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9123         | RBufferOut _ ->
9124             pr "  char *r;\n";
9125             pr "  size_t size;\n";
9126             "NULL" in
9127
9128       List.iter (
9129         function
9130         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9131             pr "  const char *%s;\n" n
9132         | OptString n -> pr "  const char *%s;\n" n
9133         | StringList n | DeviceList n ->
9134             pr "  PyObject *py_%s;\n" n;
9135             pr "  char **%s;\n" n
9136         | Bool n -> pr "  int %s;\n" n
9137         | Int n -> pr "  int %s;\n" n
9138         | Int64 n -> pr "  long long %s;\n" n
9139       ) (snd style);
9140
9141       pr "\n";
9142
9143       (* Convert the parameters. *)
9144       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
9145       List.iter (
9146         function
9147         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
9148         | OptString _ -> pr "z"
9149         | StringList _ | DeviceList _ -> pr "O"
9150         | Bool _ -> pr "i" (* XXX Python has booleans? *)
9151         | Int _ -> pr "i"
9152         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
9153                              * emulate C's int/long/long long in Python?
9154                              *)
9155       ) (snd style);
9156       pr ":guestfs_%s\",\n" name;
9157       pr "                         &py_g";
9158       List.iter (
9159         function
9160         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
9161         | OptString n -> pr ", &%s" n
9162         | StringList n | DeviceList n -> pr ", &py_%s" n
9163         | Bool n -> pr ", &%s" n
9164         | Int n -> pr ", &%s" n
9165         | Int64 n -> pr ", &%s" n
9166       ) (snd style);
9167
9168       pr "))\n";
9169       pr "    return NULL;\n";
9170
9171       pr "  g = get_handle (py_g);\n";
9172       List.iter (
9173         function
9174         | Pathname _ | Device _ | Dev_or_Path _ | String _
9175         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9176         | StringList n | DeviceList n ->
9177             pr "  %s = get_string_list (py_%s);\n" n n;
9178             pr "  if (!%s) return NULL;\n" n
9179       ) (snd style);
9180
9181       pr "\n";
9182
9183       pr "  r = guestfs_%s " name;
9184       generate_c_call_args ~handle:"g" style;
9185       pr ";\n";
9186
9187       List.iter (
9188         function
9189         | Pathname _ | Device _ | Dev_or_Path _ | String _
9190         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9191         | StringList n | DeviceList n ->
9192             pr "  free (%s);\n" n
9193       ) (snd style);
9194
9195       pr "  if (r == %s) {\n" error_code;
9196       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
9197       pr "    return NULL;\n";
9198       pr "  }\n";
9199       pr "\n";
9200
9201       (match fst style with
9202        | RErr ->
9203            pr "  Py_INCREF (Py_None);\n";
9204            pr "  py_r = Py_None;\n"
9205        | RInt _
9206        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
9207        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
9208        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
9209        | RConstOptString _ ->
9210            pr "  if (r)\n";
9211            pr "    py_r = PyString_FromString (r);\n";
9212            pr "  else {\n";
9213            pr "    Py_INCREF (Py_None);\n";
9214            pr "    py_r = Py_None;\n";
9215            pr "  }\n"
9216        | RString _ ->
9217            pr "  py_r = PyString_FromString (r);\n";
9218            pr "  free (r);\n"
9219        | RStringList _ ->
9220            pr "  py_r = put_string_list (r);\n";
9221            pr "  free_strings (r);\n"
9222        | RStruct (_, typ) ->
9223            pr "  py_r = put_%s (r);\n" typ;
9224            pr "  guestfs_free_%s (r);\n" typ
9225        | RStructList (_, typ) ->
9226            pr "  py_r = put_%s_list (r);\n" typ;
9227            pr "  guestfs_free_%s_list (r);\n" typ
9228        | RHashtable n ->
9229            pr "  py_r = put_table (r);\n";
9230            pr "  free_strings (r);\n"
9231        | RBufferOut _ ->
9232            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
9233            pr "  free (r);\n"
9234       );
9235
9236       pr "  return py_r;\n";
9237       pr "}\n";
9238       pr "\n"
9239   ) all_functions;
9240
9241   (* Table of functions. *)
9242   pr "static PyMethodDef methods[] = {\n";
9243   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
9244   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
9245   List.iter (
9246     fun (name, _, _, _, _, _, _) ->
9247       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
9248         name name
9249   ) all_functions;
9250   pr "  { NULL, NULL, 0, NULL }\n";
9251   pr "};\n";
9252   pr "\n";
9253
9254   (* Init function. *)
9255   pr "\
9256 void
9257 initlibguestfsmod (void)
9258 {
9259   static int initialized = 0;
9260
9261   if (initialized) return;
9262   Py_InitModule ((char *) \"libguestfsmod\", methods);
9263   initialized = 1;
9264 }
9265 "
9266
9267 (* Generate Python module. *)
9268 and generate_python_py () =
9269   generate_header HashStyle LGPLv2plus;
9270
9271   pr "\
9272 u\"\"\"Python bindings for libguestfs
9273
9274 import guestfs
9275 g = guestfs.GuestFS ()
9276 g.add_drive (\"guest.img\")
9277 g.launch ()
9278 parts = g.list_partitions ()
9279
9280 The guestfs module provides a Python binding to the libguestfs API
9281 for examining and modifying virtual machine disk images.
9282
9283 Amongst the things this is good for: making batch configuration
9284 changes to guests, getting disk used/free statistics (see also:
9285 virt-df), migrating between virtualization systems (see also:
9286 virt-p2v), performing partial backups, performing partial guest
9287 clones, cloning guests and changing registry/UUID/hostname info, and
9288 much else besides.
9289
9290 Libguestfs uses Linux kernel and qemu code, and can access any type of
9291 guest filesystem that Linux and qemu can, including but not limited
9292 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
9293 schemes, qcow, qcow2, vmdk.
9294
9295 Libguestfs provides ways to enumerate guest storage (eg. partitions,
9296 LVs, what filesystem is in each LV, etc.).  It can also run commands
9297 in the context of the guest.  Also you can access filesystems over
9298 FUSE.
9299
9300 Errors which happen while using the API are turned into Python
9301 RuntimeError exceptions.
9302
9303 To create a guestfs handle you usually have to perform the following
9304 sequence of calls:
9305
9306 # Create the handle, call add_drive at least once, and possibly
9307 # several times if the guest has multiple block devices:
9308 g = guestfs.GuestFS ()
9309 g.add_drive (\"guest.img\")
9310
9311 # Launch the qemu subprocess and wait for it to become ready:
9312 g.launch ()
9313
9314 # Now you can issue commands, for example:
9315 logvols = g.lvs ()
9316
9317 \"\"\"
9318
9319 import libguestfsmod
9320
9321 class GuestFS:
9322     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
9323
9324     def __init__ (self):
9325         \"\"\"Create a new libguestfs handle.\"\"\"
9326         self._o = libguestfsmod.create ()
9327
9328     def __del__ (self):
9329         libguestfsmod.close (self._o)
9330
9331 ";
9332
9333   List.iter (
9334     fun (name, style, _, flags, _, _, longdesc) ->
9335       pr "    def %s " name;
9336       generate_py_call_args ~handle:"self" (snd style);
9337       pr ":\n";
9338
9339       if not (List.mem NotInDocs flags) then (
9340         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9341         let doc =
9342           match fst style with
9343           | RErr | RInt _ | RInt64 _ | RBool _
9344           | RConstOptString _ | RConstString _
9345           | RString _ | RBufferOut _ -> doc
9346           | RStringList _ ->
9347               doc ^ "\n\nThis function returns a list of strings."
9348           | RStruct (_, typ) ->
9349               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
9350           | RStructList (_, typ) ->
9351               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
9352           | RHashtable _ ->
9353               doc ^ "\n\nThis function returns a dictionary." in
9354         let doc =
9355           if List.mem ProtocolLimitWarning flags then
9356             doc ^ "\n\n" ^ protocol_limit_warning
9357           else doc in
9358         let doc =
9359           if List.mem DangerWillRobinson flags then
9360             doc ^ "\n\n" ^ danger_will_robinson
9361           else doc in
9362         let doc =
9363           match deprecation_notice flags with
9364           | None -> doc
9365           | Some txt -> doc ^ "\n\n" ^ txt in
9366         let doc = pod2text ~width:60 name doc in
9367         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
9368         let doc = String.concat "\n        " doc in
9369         pr "        u\"\"\"%s\"\"\"\n" doc;
9370       );
9371       pr "        return libguestfsmod.%s " name;
9372       generate_py_call_args ~handle:"self._o" (snd style);
9373       pr "\n";
9374       pr "\n";
9375   ) all_functions
9376
9377 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
9378 and generate_py_call_args ~handle args =
9379   pr "(%s" handle;
9380   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9381   pr ")"
9382
9383 (* Useful if you need the longdesc POD text as plain text.  Returns a
9384  * list of lines.
9385  *
9386  * Because this is very slow (the slowest part of autogeneration),
9387  * we memoize the results.
9388  *)
9389 and pod2text ~width name longdesc =
9390   let key = width, name, longdesc in
9391   try Hashtbl.find pod2text_memo key
9392   with Not_found ->
9393     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
9394     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
9395     close_out chan;
9396     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
9397     let chan = open_process_in cmd in
9398     let lines = ref [] in
9399     let rec loop i =
9400       let line = input_line chan in
9401       if i = 1 then             (* discard the first line of output *)
9402         loop (i+1)
9403       else (
9404         let line = triml line in
9405         lines := line :: !lines;
9406         loop (i+1)
9407       ) in
9408     let lines = try loop 1 with End_of_file -> List.rev !lines in
9409     unlink filename;
9410     (match close_process_in chan with
9411      | WEXITED 0 -> ()
9412      | WEXITED i ->
9413          failwithf "pod2text: process exited with non-zero status (%d)" i
9414      | WSIGNALED i | WSTOPPED i ->
9415          failwithf "pod2text: process signalled or stopped by signal %d" i
9416     );
9417     Hashtbl.add pod2text_memo key lines;
9418     pod2text_memo_updated ();
9419     lines
9420
9421 (* Generate ruby bindings. *)
9422 and generate_ruby_c () =
9423   generate_header CStyle LGPLv2plus;
9424
9425   pr "\
9426 #include <stdio.h>
9427 #include <stdlib.h>
9428
9429 #include <ruby.h>
9430
9431 #include \"guestfs.h\"
9432
9433 #include \"extconf.h\"
9434
9435 /* For Ruby < 1.9 */
9436 #ifndef RARRAY_LEN
9437 #define RARRAY_LEN(r) (RARRAY((r))->len)
9438 #endif
9439
9440 static VALUE m_guestfs;                 /* guestfs module */
9441 static VALUE c_guestfs;                 /* guestfs_h handle */
9442 static VALUE e_Error;                   /* used for all errors */
9443
9444 static void ruby_guestfs_free (void *p)
9445 {
9446   if (!p) return;
9447   guestfs_close ((guestfs_h *) p);
9448 }
9449
9450 static VALUE ruby_guestfs_create (VALUE m)
9451 {
9452   guestfs_h *g;
9453
9454   g = guestfs_create ();
9455   if (!g)
9456     rb_raise (e_Error, \"failed to create guestfs handle\");
9457
9458   /* Don't print error messages to stderr by default. */
9459   guestfs_set_error_handler (g, NULL, NULL);
9460
9461   /* Wrap it, and make sure the close function is called when the
9462    * handle goes away.
9463    */
9464   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9465 }
9466
9467 static VALUE ruby_guestfs_close (VALUE gv)
9468 {
9469   guestfs_h *g;
9470   Data_Get_Struct (gv, guestfs_h, g);
9471
9472   ruby_guestfs_free (g);
9473   DATA_PTR (gv) = NULL;
9474
9475   return Qnil;
9476 }
9477
9478 ";
9479
9480   List.iter (
9481     fun (name, style, _, _, _, _, _) ->
9482       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9483       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9484       pr ")\n";
9485       pr "{\n";
9486       pr "  guestfs_h *g;\n";
9487       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9488       pr "  if (!g)\n";
9489       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9490         name;
9491       pr "\n";
9492
9493       List.iter (
9494         function
9495         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9496             pr "  Check_Type (%sv, T_STRING);\n" n;
9497             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9498             pr "  if (!%s)\n" n;
9499             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9500             pr "              \"%s\", \"%s\");\n" n name
9501         | OptString n ->
9502             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9503         | StringList n | DeviceList n ->
9504             pr "  char **%s;\n" n;
9505             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9506             pr "  {\n";
9507             pr "    int i, len;\n";
9508             pr "    len = RARRAY_LEN (%sv);\n" n;
9509             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9510               n;
9511             pr "    for (i = 0; i < len; ++i) {\n";
9512             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9513             pr "      %s[i] = StringValueCStr (v);\n" n;
9514             pr "    }\n";
9515             pr "    %s[len] = NULL;\n" n;
9516             pr "  }\n";
9517         | Bool n ->
9518             pr "  int %s = RTEST (%sv);\n" n n
9519         | Int n ->
9520             pr "  int %s = NUM2INT (%sv);\n" n n
9521         | Int64 n ->
9522             pr "  long long %s = NUM2LL (%sv);\n" n n
9523       ) (snd style);
9524       pr "\n";
9525
9526       let error_code =
9527         match fst style with
9528         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9529         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9530         | RConstString _ | RConstOptString _ ->
9531             pr "  const char *r;\n"; "NULL"
9532         | RString _ -> pr "  char *r;\n"; "NULL"
9533         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9534         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9535         | RStructList (_, typ) ->
9536             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9537         | RBufferOut _ ->
9538             pr "  char *r;\n";
9539             pr "  size_t size;\n";
9540             "NULL" in
9541       pr "\n";
9542
9543       pr "  r = guestfs_%s " name;
9544       generate_c_call_args ~handle:"g" style;
9545       pr ";\n";
9546
9547       List.iter (
9548         function
9549         | Pathname _ | Device _ | Dev_or_Path _ | String _
9550         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9551         | StringList n | DeviceList n ->
9552             pr "  free (%s);\n" n
9553       ) (snd style);
9554
9555       pr "  if (r == %s)\n" error_code;
9556       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9557       pr "\n";
9558
9559       (match fst style with
9560        | RErr ->
9561            pr "  return Qnil;\n"
9562        | RInt _ | RBool _ ->
9563            pr "  return INT2NUM (r);\n"
9564        | RInt64 _ ->
9565            pr "  return ULL2NUM (r);\n"
9566        | RConstString _ ->
9567            pr "  return rb_str_new2 (r);\n";
9568        | RConstOptString _ ->
9569            pr "  if (r)\n";
9570            pr "    return rb_str_new2 (r);\n";
9571            pr "  else\n";
9572            pr "    return Qnil;\n";
9573        | RString _ ->
9574            pr "  VALUE rv = rb_str_new2 (r);\n";
9575            pr "  free (r);\n";
9576            pr "  return rv;\n";
9577        | RStringList _ ->
9578            pr "  int i, len = 0;\n";
9579            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9580            pr "  VALUE rv = rb_ary_new2 (len);\n";
9581            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9582            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9583            pr "    free (r[i]);\n";
9584            pr "  }\n";
9585            pr "  free (r);\n";
9586            pr "  return rv;\n"
9587        | RStruct (_, typ) ->
9588            let cols = cols_of_struct typ in
9589            generate_ruby_struct_code typ cols
9590        | RStructList (_, typ) ->
9591            let cols = cols_of_struct typ in
9592            generate_ruby_struct_list_code typ cols
9593        | RHashtable _ ->
9594            pr "  VALUE rv = rb_hash_new ();\n";
9595            pr "  int i;\n";
9596            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9597            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9598            pr "    free (r[i]);\n";
9599            pr "    free (r[i+1]);\n";
9600            pr "  }\n";
9601            pr "  free (r);\n";
9602            pr "  return rv;\n"
9603        | RBufferOut _ ->
9604            pr "  VALUE rv = rb_str_new (r, size);\n";
9605            pr "  free (r);\n";
9606            pr "  return rv;\n";
9607       );
9608
9609       pr "}\n";
9610       pr "\n"
9611   ) all_functions;
9612
9613   pr "\
9614 /* Initialize the module. */
9615 void Init__guestfs ()
9616 {
9617   m_guestfs = rb_define_module (\"Guestfs\");
9618   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9619   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9620
9621   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9622   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9623
9624 ";
9625   (* Define the rest of the methods. *)
9626   List.iter (
9627     fun (name, style, _, _, _, _, _) ->
9628       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9629       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9630   ) all_functions;
9631
9632   pr "}\n"
9633
9634 (* Ruby code to return a struct. *)
9635 and generate_ruby_struct_code typ cols =
9636   pr "  VALUE rv = rb_hash_new ();\n";
9637   List.iter (
9638     function
9639     | name, FString ->
9640         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9641     | name, FBuffer ->
9642         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9643     | name, FUUID ->
9644         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9645     | name, (FBytes|FUInt64) ->
9646         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9647     | name, FInt64 ->
9648         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9649     | name, FUInt32 ->
9650         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9651     | name, FInt32 ->
9652         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9653     | name, FOptPercent ->
9654         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9655     | name, FChar -> (* XXX wrong? *)
9656         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9657   ) cols;
9658   pr "  guestfs_free_%s (r);\n" typ;
9659   pr "  return rv;\n"
9660
9661 (* Ruby code to return a struct list. *)
9662 and generate_ruby_struct_list_code typ cols =
9663   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9664   pr "  int i;\n";
9665   pr "  for (i = 0; i < r->len; ++i) {\n";
9666   pr "    VALUE hv = rb_hash_new ();\n";
9667   List.iter (
9668     function
9669     | name, FString ->
9670         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9671     | name, FBuffer ->
9672         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
9673     | name, FUUID ->
9674         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9675     | name, (FBytes|FUInt64) ->
9676         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9677     | name, FInt64 ->
9678         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9679     | name, FUInt32 ->
9680         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9681     | name, FInt32 ->
9682         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9683     | name, FOptPercent ->
9684         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9685     | name, FChar -> (* XXX wrong? *)
9686         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9687   ) cols;
9688   pr "    rb_ary_push (rv, hv);\n";
9689   pr "  }\n";
9690   pr "  guestfs_free_%s_list (r);\n" typ;
9691   pr "  return rv;\n"
9692
9693 (* Generate Java bindings GuestFS.java file. *)
9694 and generate_java_java () =
9695   generate_header CStyle LGPLv2plus;
9696
9697   pr "\
9698 package com.redhat.et.libguestfs;
9699
9700 import java.util.HashMap;
9701 import com.redhat.et.libguestfs.LibGuestFSException;
9702 import com.redhat.et.libguestfs.PV;
9703 import com.redhat.et.libguestfs.VG;
9704 import com.redhat.et.libguestfs.LV;
9705 import com.redhat.et.libguestfs.Stat;
9706 import com.redhat.et.libguestfs.StatVFS;
9707 import com.redhat.et.libguestfs.IntBool;
9708 import com.redhat.et.libguestfs.Dirent;
9709
9710 /**
9711  * The GuestFS object is a libguestfs handle.
9712  *
9713  * @author rjones
9714  */
9715 public class GuestFS {
9716   // Load the native code.
9717   static {
9718     System.loadLibrary (\"guestfs_jni\");
9719   }
9720
9721   /**
9722    * The native guestfs_h pointer.
9723    */
9724   long g;
9725
9726   /**
9727    * Create a libguestfs handle.
9728    *
9729    * @throws LibGuestFSException
9730    */
9731   public GuestFS () throws LibGuestFSException
9732   {
9733     g = _create ();
9734   }
9735   private native long _create () throws LibGuestFSException;
9736
9737   /**
9738    * Close a libguestfs handle.
9739    *
9740    * You can also leave handles to be collected by the garbage
9741    * collector, but this method ensures that the resources used
9742    * by the handle are freed up immediately.  If you call any
9743    * other methods after closing the handle, you will get an
9744    * exception.
9745    *
9746    * @throws LibGuestFSException
9747    */
9748   public void close () throws LibGuestFSException
9749   {
9750     if (g != 0)
9751       _close (g);
9752     g = 0;
9753   }
9754   private native void _close (long g) throws LibGuestFSException;
9755
9756   public void finalize () throws LibGuestFSException
9757   {
9758     close ();
9759   }
9760
9761 ";
9762
9763   List.iter (
9764     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9765       if not (List.mem NotInDocs flags); then (
9766         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9767         let doc =
9768           if List.mem ProtocolLimitWarning flags then
9769             doc ^ "\n\n" ^ protocol_limit_warning
9770           else doc in
9771         let doc =
9772           if List.mem DangerWillRobinson flags then
9773             doc ^ "\n\n" ^ danger_will_robinson
9774           else doc in
9775         let doc =
9776           match deprecation_notice flags with
9777           | None -> doc
9778           | Some txt -> doc ^ "\n\n" ^ txt in
9779         let doc = pod2text ~width:60 name doc in
9780         let doc = List.map (            (* RHBZ#501883 *)
9781           function
9782           | "" -> "<p>"
9783           | nonempty -> nonempty
9784         ) doc in
9785         let doc = String.concat "\n   * " doc in
9786
9787         pr "  /**\n";
9788         pr "   * %s\n" shortdesc;
9789         pr "   * <p>\n";
9790         pr "   * %s\n" doc;
9791         pr "   * @throws LibGuestFSException\n";
9792         pr "   */\n";
9793         pr "  ";
9794       );
9795       generate_java_prototype ~public:true ~semicolon:false name style;
9796       pr "\n";
9797       pr "  {\n";
9798       pr "    if (g == 0)\n";
9799       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9800         name;
9801       pr "    ";
9802       if fst style <> RErr then pr "return ";
9803       pr "_%s " name;
9804       generate_java_call_args ~handle:"g" (snd style);
9805       pr ";\n";
9806       pr "  }\n";
9807       pr "  ";
9808       generate_java_prototype ~privat:true ~native:true name style;
9809       pr "\n";
9810       pr "\n";
9811   ) all_functions;
9812
9813   pr "}\n"
9814
9815 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9816 and generate_java_call_args ~handle args =
9817   pr "(%s" handle;
9818   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9819   pr ")"
9820
9821 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9822     ?(semicolon=true) name style =
9823   if privat then pr "private ";
9824   if public then pr "public ";
9825   if native then pr "native ";
9826
9827   (* return type *)
9828   (match fst style with
9829    | RErr -> pr "void ";
9830    | RInt _ -> pr "int ";
9831    | RInt64 _ -> pr "long ";
9832    | RBool _ -> pr "boolean ";
9833    | RConstString _ | RConstOptString _ | RString _
9834    | RBufferOut _ -> pr "String ";
9835    | RStringList _ -> pr "String[] ";
9836    | RStruct (_, typ) ->
9837        let name = java_name_of_struct typ in
9838        pr "%s " name;
9839    | RStructList (_, typ) ->
9840        let name = java_name_of_struct typ in
9841        pr "%s[] " name;
9842    | RHashtable _ -> pr "HashMap<String,String> ";
9843   );
9844
9845   if native then pr "_%s " name else pr "%s " name;
9846   pr "(";
9847   let needs_comma = ref false in
9848   if native then (
9849     pr "long g";
9850     needs_comma := true
9851   );
9852
9853   (* args *)
9854   List.iter (
9855     fun arg ->
9856       if !needs_comma then pr ", ";
9857       needs_comma := true;
9858
9859       match arg with
9860       | Pathname n
9861       | Device n | Dev_or_Path n
9862       | String n
9863       | OptString n
9864       | FileIn n
9865       | FileOut n ->
9866           pr "String %s" n
9867       | StringList n | DeviceList n ->
9868           pr "String[] %s" n
9869       | Bool n ->
9870           pr "boolean %s" n
9871       | Int n ->
9872           pr "int %s" n
9873       | Int64 n ->
9874           pr "long %s" n
9875   ) (snd style);
9876
9877   pr ")\n";
9878   pr "    throws LibGuestFSException";
9879   if semicolon then pr ";"
9880
9881 and generate_java_struct jtyp cols () =
9882   generate_header CStyle LGPLv2plus;
9883
9884   pr "\
9885 package com.redhat.et.libguestfs;
9886
9887 /**
9888  * Libguestfs %s structure.
9889  *
9890  * @author rjones
9891  * @see GuestFS
9892  */
9893 public class %s {
9894 " jtyp jtyp;
9895
9896   List.iter (
9897     function
9898     | name, FString
9899     | name, FUUID
9900     | name, FBuffer -> pr "  public String %s;\n" name
9901     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9902     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9903     | name, FChar -> pr "  public char %s;\n" name
9904     | name, FOptPercent ->
9905         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9906         pr "  public float %s;\n" name
9907   ) cols;
9908
9909   pr "}\n"
9910
9911 and generate_java_c () =
9912   generate_header CStyle LGPLv2plus;
9913
9914   pr "\
9915 #include <stdio.h>
9916 #include <stdlib.h>
9917 #include <string.h>
9918
9919 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9920 #include \"guestfs.h\"
9921
9922 /* Note that this function returns.  The exception is not thrown
9923  * until after the wrapper function returns.
9924  */
9925 static void
9926 throw_exception (JNIEnv *env, const char *msg)
9927 {
9928   jclass cl;
9929   cl = (*env)->FindClass (env,
9930                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9931   (*env)->ThrowNew (env, cl, msg);
9932 }
9933
9934 JNIEXPORT jlong JNICALL
9935 Java_com_redhat_et_libguestfs_GuestFS__1create
9936   (JNIEnv *env, jobject obj)
9937 {
9938   guestfs_h *g;
9939
9940   g = guestfs_create ();
9941   if (g == NULL) {
9942     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9943     return 0;
9944   }
9945   guestfs_set_error_handler (g, NULL, NULL);
9946   return (jlong) (long) g;
9947 }
9948
9949 JNIEXPORT void JNICALL
9950 Java_com_redhat_et_libguestfs_GuestFS__1close
9951   (JNIEnv *env, jobject obj, jlong jg)
9952 {
9953   guestfs_h *g = (guestfs_h *) (long) jg;
9954   guestfs_close (g);
9955 }
9956
9957 ";
9958
9959   List.iter (
9960     fun (name, style, _, _, _, _, _) ->
9961       pr "JNIEXPORT ";
9962       (match fst style with
9963        | RErr -> pr "void ";
9964        | RInt _ -> pr "jint ";
9965        | RInt64 _ -> pr "jlong ";
9966        | RBool _ -> pr "jboolean ";
9967        | RConstString _ | RConstOptString _ | RString _
9968        | RBufferOut _ -> pr "jstring ";
9969        | RStruct _ | RHashtable _ ->
9970            pr "jobject ";
9971        | RStringList _ | RStructList _ ->
9972            pr "jobjectArray ";
9973       );
9974       pr "JNICALL\n";
9975       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9976       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9977       pr "\n";
9978       pr "  (JNIEnv *env, jobject obj, jlong jg";
9979       List.iter (
9980         function
9981         | Pathname n
9982         | Device n | Dev_or_Path n
9983         | String n
9984         | OptString n
9985         | FileIn n
9986         | FileOut n ->
9987             pr ", jstring j%s" n
9988         | StringList n | DeviceList n ->
9989             pr ", jobjectArray j%s" n
9990         | Bool n ->
9991             pr ", jboolean j%s" n
9992         | Int n ->
9993             pr ", jint j%s" n
9994         | Int64 n ->
9995             pr ", jlong j%s" n
9996       ) (snd style);
9997       pr ")\n";
9998       pr "{\n";
9999       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
10000       let error_code, no_ret =
10001         match fst style with
10002         | RErr -> pr "  int r;\n"; "-1", ""
10003         | RBool _
10004         | RInt _ -> pr "  int r;\n"; "-1", "0"
10005         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
10006         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10007         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10008         | RString _ ->
10009             pr "  jstring jr;\n";
10010             pr "  char *r;\n"; "NULL", "NULL"
10011         | RStringList _ ->
10012             pr "  jobjectArray jr;\n";
10013             pr "  int r_len;\n";
10014             pr "  jclass cl;\n";
10015             pr "  jstring jstr;\n";
10016             pr "  char **r;\n"; "NULL", "NULL"
10017         | RStruct (_, typ) ->
10018             pr "  jobject jr;\n";
10019             pr "  jclass cl;\n";
10020             pr "  jfieldID fl;\n";
10021             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
10022         | RStructList (_, typ) ->
10023             pr "  jobjectArray jr;\n";
10024             pr "  jclass cl;\n";
10025             pr "  jfieldID fl;\n";
10026             pr "  jobject jfl;\n";
10027             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
10028         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
10029         | RBufferOut _ ->
10030             pr "  jstring jr;\n";
10031             pr "  char *r;\n";
10032             pr "  size_t size;\n";
10033             "NULL", "NULL" in
10034       List.iter (
10035         function
10036         | Pathname n
10037         | Device n | Dev_or_Path n
10038         | String n
10039         | OptString n
10040         | FileIn n
10041         | FileOut n ->
10042             pr "  const char *%s;\n" n
10043         | StringList n | DeviceList n ->
10044             pr "  int %s_len;\n" n;
10045             pr "  const char **%s;\n" n
10046         | Bool n
10047         | Int n ->
10048             pr "  int %s;\n" n
10049         | Int64 n ->
10050             pr "  int64_t %s;\n" n
10051       ) (snd style);
10052
10053       let needs_i =
10054         (match fst style with
10055          | RStringList _ | RStructList _ -> true
10056          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
10057          | RConstOptString _
10058          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
10059           List.exists (function
10060                        | StringList _ -> true
10061                        | DeviceList _ -> true
10062                        | _ -> false) (snd style) in
10063       if needs_i then
10064         pr "  int i;\n";
10065
10066       pr "\n";
10067
10068       (* Get the parameters. *)
10069       List.iter (
10070         function
10071         | Pathname n
10072         | Device n | Dev_or_Path n
10073         | String n
10074         | FileIn n
10075         | FileOut n ->
10076             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
10077         | OptString n ->
10078             (* This is completely undocumented, but Java null becomes
10079              * a NULL parameter.
10080              *)
10081             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
10082         | StringList n | DeviceList n ->
10083             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
10084             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
10085             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10086             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10087               n;
10088             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
10089             pr "  }\n";
10090             pr "  %s[%s_len] = NULL;\n" n n;
10091         | Bool n
10092         | Int n
10093         | Int64 n ->
10094             pr "  %s = j%s;\n" n n
10095       ) (snd style);
10096
10097       (* Make the call. *)
10098       pr "  r = guestfs_%s " name;
10099       generate_c_call_args ~handle:"g" style;
10100       pr ";\n";
10101
10102       (* Release the parameters. *)
10103       List.iter (
10104         function
10105         | Pathname n
10106         | Device n | Dev_or_Path n
10107         | String n
10108         | FileIn n
10109         | FileOut n ->
10110             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10111         | OptString n ->
10112             pr "  if (j%s)\n" n;
10113             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10114         | StringList n | DeviceList n ->
10115             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10116             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10117               n;
10118             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
10119             pr "  }\n";
10120             pr "  free (%s);\n" n
10121         | Bool n
10122         | Int n
10123         | Int64 n -> ()
10124       ) (snd style);
10125
10126       (* Check for errors. *)
10127       pr "  if (r == %s) {\n" error_code;
10128       pr "    throw_exception (env, guestfs_last_error (g));\n";
10129       pr "    return %s;\n" no_ret;
10130       pr "  }\n";
10131
10132       (* Return value. *)
10133       (match fst style with
10134        | RErr -> ()
10135        | RInt _ -> pr "  return (jint) r;\n"
10136        | RBool _ -> pr "  return (jboolean) r;\n"
10137        | RInt64 _ -> pr "  return (jlong) r;\n"
10138        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
10139        | RConstOptString _ ->
10140            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
10141        | RString _ ->
10142            pr "  jr = (*env)->NewStringUTF (env, r);\n";
10143            pr "  free (r);\n";
10144            pr "  return jr;\n"
10145        | RStringList _ ->
10146            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
10147            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
10148            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
10149            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
10150            pr "  for (i = 0; i < r_len; ++i) {\n";
10151            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
10152            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
10153            pr "    free (r[i]);\n";
10154            pr "  }\n";
10155            pr "  free (r);\n";
10156            pr "  return jr;\n"
10157        | RStruct (_, typ) ->
10158            let jtyp = java_name_of_struct typ in
10159            let cols = cols_of_struct typ in
10160            generate_java_struct_return typ jtyp cols
10161        | RStructList (_, typ) ->
10162            let jtyp = java_name_of_struct typ in
10163            let cols = cols_of_struct typ in
10164            generate_java_struct_list_return typ jtyp cols
10165        | RHashtable _ ->
10166            (* XXX *)
10167            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
10168            pr "  return NULL;\n"
10169        | RBufferOut _ ->
10170            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
10171            pr "  free (r);\n";
10172            pr "  return jr;\n"
10173       );
10174
10175       pr "}\n";
10176       pr "\n"
10177   ) all_functions
10178
10179 and generate_java_struct_return typ jtyp cols =
10180   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10181   pr "  jr = (*env)->AllocObject (env, cl);\n";
10182   List.iter (
10183     function
10184     | name, FString ->
10185         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10186         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
10187     | name, FUUID ->
10188         pr "  {\n";
10189         pr "    char s[33];\n";
10190         pr "    memcpy (s, r->%s, 32);\n" name;
10191         pr "    s[32] = 0;\n";
10192         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10193         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10194         pr "  }\n";
10195     | name, FBuffer ->
10196         pr "  {\n";
10197         pr "    int len = r->%s_len;\n" name;
10198         pr "    char s[len+1];\n";
10199         pr "    memcpy (s, r->%s, len);\n" name;
10200         pr "    s[len] = 0;\n";
10201         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10202         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10203         pr "  }\n";
10204     | name, (FBytes|FUInt64|FInt64) ->
10205         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10206         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10207     | name, (FUInt32|FInt32) ->
10208         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10209         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10210     | name, FOptPercent ->
10211         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10212         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
10213     | name, FChar ->
10214         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10215         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10216   ) cols;
10217   pr "  free (r);\n";
10218   pr "  return jr;\n"
10219
10220 and generate_java_struct_list_return typ jtyp cols =
10221   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10222   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
10223   pr "  for (i = 0; i < r->len; ++i) {\n";
10224   pr "    jfl = (*env)->AllocObject (env, cl);\n";
10225   List.iter (
10226     function
10227     | name, FString ->
10228         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10229         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
10230     | name, FUUID ->
10231         pr "    {\n";
10232         pr "      char s[33];\n";
10233         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
10234         pr "      s[32] = 0;\n";
10235         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10236         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10237         pr "    }\n";
10238     | name, FBuffer ->
10239         pr "    {\n";
10240         pr "      int len = r->val[i].%s_len;\n" name;
10241         pr "      char s[len+1];\n";
10242         pr "      memcpy (s, r->val[i].%s, len);\n" name;
10243         pr "      s[len] = 0;\n";
10244         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10245         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10246         pr "    }\n";
10247     | name, (FBytes|FUInt64|FInt64) ->
10248         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10249         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10250     | name, (FUInt32|FInt32) ->
10251         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10252         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10253     | name, FOptPercent ->
10254         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10255         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
10256     | name, FChar ->
10257         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10258         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10259   ) cols;
10260   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
10261   pr "  }\n";
10262   pr "  guestfs_free_%s_list (r);\n" typ;
10263   pr "  return jr;\n"
10264
10265 and generate_java_makefile_inc () =
10266   generate_header HashStyle GPLv2plus;
10267
10268   pr "java_built_sources = \\\n";
10269   List.iter (
10270     fun (typ, jtyp) ->
10271         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
10272   ) java_structs;
10273   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
10274
10275 and generate_haskell_hs () =
10276   generate_header HaskellStyle LGPLv2plus;
10277
10278   (* XXX We only know how to generate partial FFI for Haskell
10279    * at the moment.  Please help out!
10280    *)
10281   let can_generate style =
10282     match style with
10283     | RErr, _
10284     | RInt _, _
10285     | RInt64 _, _ -> true
10286     | RBool _, _
10287     | RConstString _, _
10288     | RConstOptString _, _
10289     | RString _, _
10290     | RStringList _, _
10291     | RStruct _, _
10292     | RStructList _, _
10293     | RHashtable _, _
10294     | RBufferOut _, _ -> false in
10295
10296   pr "\
10297 {-# INCLUDE <guestfs.h> #-}
10298 {-# LANGUAGE ForeignFunctionInterface #-}
10299
10300 module Guestfs (
10301   create";
10302
10303   (* List out the names of the actions we want to export. *)
10304   List.iter (
10305     fun (name, style, _, _, _, _, _) ->
10306       if can_generate style then pr ",\n  %s" name
10307   ) all_functions;
10308
10309   pr "
10310   ) where
10311
10312 -- Unfortunately some symbols duplicate ones already present
10313 -- in Prelude.  We don't know which, so we hard-code a list
10314 -- here.
10315 import Prelude hiding (truncate)
10316
10317 import Foreign
10318 import Foreign.C
10319 import Foreign.C.Types
10320 import IO
10321 import Control.Exception
10322 import Data.Typeable
10323
10324 data GuestfsS = GuestfsS            -- represents the opaque C struct
10325 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
10326 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
10327
10328 -- XXX define properly later XXX
10329 data PV = PV
10330 data VG = VG
10331 data LV = LV
10332 data IntBool = IntBool
10333 data Stat = Stat
10334 data StatVFS = StatVFS
10335 data Hashtable = Hashtable
10336
10337 foreign import ccall unsafe \"guestfs_create\" c_create
10338   :: IO GuestfsP
10339 foreign import ccall unsafe \"&guestfs_close\" c_close
10340   :: FunPtr (GuestfsP -> IO ())
10341 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
10342   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
10343
10344 create :: IO GuestfsH
10345 create = do
10346   p <- c_create
10347   c_set_error_handler p nullPtr nullPtr
10348   h <- newForeignPtr c_close p
10349   return h
10350
10351 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
10352   :: GuestfsP -> IO CString
10353
10354 -- last_error :: GuestfsH -> IO (Maybe String)
10355 -- last_error h = do
10356 --   str <- withForeignPtr h (\\p -> c_last_error p)
10357 --   maybePeek peekCString str
10358
10359 last_error :: GuestfsH -> IO (String)
10360 last_error h = do
10361   str <- withForeignPtr h (\\p -> c_last_error p)
10362   if (str == nullPtr)
10363     then return \"no error\"
10364     else peekCString str
10365
10366 ";
10367
10368   (* Generate wrappers for each foreign function. *)
10369   List.iter (
10370     fun (name, style, _, _, _, _, _) ->
10371       if can_generate style then (
10372         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
10373         pr "  :: ";
10374         generate_haskell_prototype ~handle:"GuestfsP" style;
10375         pr "\n";
10376         pr "\n";
10377         pr "%s :: " name;
10378         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
10379         pr "\n";
10380         pr "%s %s = do\n" name
10381           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
10382         pr "  r <- ";
10383         (* Convert pointer arguments using with* functions. *)
10384         List.iter (
10385           function
10386           | FileIn n
10387           | FileOut n
10388           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
10389           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
10390           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
10391           | Bool _ | Int _ | Int64 _ -> ()
10392         ) (snd style);
10393         (* Convert integer arguments. *)
10394         let args =
10395           List.map (
10396             function
10397             | Bool n -> sprintf "(fromBool %s)" n
10398             | Int n -> sprintf "(fromIntegral %s)" n
10399             | Int64 n -> sprintf "(fromIntegral %s)" n
10400             | FileIn n | FileOut n
10401             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
10402           ) (snd style) in
10403         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
10404           (String.concat " " ("p" :: args));
10405         (match fst style with
10406          | RErr | RInt _ | RInt64 _ | RBool _ ->
10407              pr "  if (r == -1)\n";
10408              pr "    then do\n";
10409              pr "      err <- last_error h\n";
10410              pr "      fail err\n";
10411          | RConstString _ | RConstOptString _ | RString _
10412          | RStringList _ | RStruct _
10413          | RStructList _ | RHashtable _ | RBufferOut _ ->
10414              pr "  if (r == nullPtr)\n";
10415              pr "    then do\n";
10416              pr "      err <- last_error h\n";
10417              pr "      fail err\n";
10418         );
10419         (match fst style with
10420          | RErr ->
10421              pr "    else return ()\n"
10422          | RInt _ ->
10423              pr "    else return (fromIntegral r)\n"
10424          | RInt64 _ ->
10425              pr "    else return (fromIntegral r)\n"
10426          | RBool _ ->
10427              pr "    else return (toBool r)\n"
10428          | RConstString _
10429          | RConstOptString _
10430          | RString _
10431          | RStringList _
10432          | RStruct _
10433          | RStructList _
10434          | RHashtable _
10435          | RBufferOut _ ->
10436              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10437         );
10438         pr "\n";
10439       )
10440   ) all_functions
10441
10442 and generate_haskell_prototype ~handle ?(hs = false) style =
10443   pr "%s -> " handle;
10444   let string = if hs then "String" else "CString" in
10445   let int = if hs then "Int" else "CInt" in
10446   let bool = if hs then "Bool" else "CInt" in
10447   let int64 = if hs then "Integer" else "Int64" in
10448   List.iter (
10449     fun arg ->
10450       (match arg with
10451        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10452        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10453        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10454        | Bool _ -> pr "%s" bool
10455        | Int _ -> pr "%s" int
10456        | Int64 _ -> pr "%s" int
10457        | FileIn _ -> pr "%s" string
10458        | FileOut _ -> pr "%s" string
10459       );
10460       pr " -> ";
10461   ) (snd style);
10462   pr "IO (";
10463   (match fst style with
10464    | RErr -> if not hs then pr "CInt"
10465    | RInt _ -> pr "%s" int
10466    | RInt64 _ -> pr "%s" int64
10467    | RBool _ -> pr "%s" bool
10468    | RConstString _ -> pr "%s" string
10469    | RConstOptString _ -> pr "Maybe %s" string
10470    | RString _ -> pr "%s" string
10471    | RStringList _ -> pr "[%s]" string
10472    | RStruct (_, typ) ->
10473        let name = java_name_of_struct typ in
10474        pr "%s" name
10475    | RStructList (_, typ) ->
10476        let name = java_name_of_struct typ in
10477        pr "[%s]" name
10478    | RHashtable _ -> pr "Hashtable"
10479    | RBufferOut _ -> pr "%s" string
10480   );
10481   pr ")"
10482
10483 and generate_csharp () =
10484   generate_header CPlusPlusStyle LGPLv2plus;
10485
10486   (* XXX Make this configurable by the C# assembly users. *)
10487   let library = "libguestfs.so.0" in
10488
10489   pr "\
10490 // These C# bindings are highly experimental at present.
10491 //
10492 // Firstly they only work on Linux (ie. Mono).  In order to get them
10493 // to work on Windows (ie. .Net) you would need to port the library
10494 // itself to Windows first.
10495 //
10496 // The second issue is that some calls are known to be incorrect and
10497 // can cause Mono to segfault.  Particularly: calls which pass or
10498 // return string[], or return any structure value.  This is because
10499 // we haven't worked out the correct way to do this from C#.
10500 //
10501 // The third issue is that when compiling you get a lot of warnings.
10502 // We are not sure whether the warnings are important or not.
10503 //
10504 // Fourthly we do not routinely build or test these bindings as part
10505 // of the make && make check cycle, which means that regressions might
10506 // go unnoticed.
10507 //
10508 // Suggestions and patches are welcome.
10509
10510 // To compile:
10511 //
10512 // gmcs Libguestfs.cs
10513 // mono Libguestfs.exe
10514 //
10515 // (You'll probably want to add a Test class / static main function
10516 // otherwise this won't do anything useful).
10517
10518 using System;
10519 using System.IO;
10520 using System.Runtime.InteropServices;
10521 using System.Runtime.Serialization;
10522 using System.Collections;
10523
10524 namespace Guestfs
10525 {
10526   class Error : System.ApplicationException
10527   {
10528     public Error (string message) : base (message) {}
10529     protected Error (SerializationInfo info, StreamingContext context) {}
10530   }
10531
10532   class Guestfs
10533   {
10534     IntPtr _handle;
10535
10536     [DllImport (\"%s\")]
10537     static extern IntPtr guestfs_create ();
10538
10539     public Guestfs ()
10540     {
10541       _handle = guestfs_create ();
10542       if (_handle == IntPtr.Zero)
10543         throw new Error (\"could not create guestfs handle\");
10544     }
10545
10546     [DllImport (\"%s\")]
10547     static extern void guestfs_close (IntPtr h);
10548
10549     ~Guestfs ()
10550     {
10551       guestfs_close (_handle);
10552     }
10553
10554     [DllImport (\"%s\")]
10555     static extern string guestfs_last_error (IntPtr h);
10556
10557 " library library library;
10558
10559   (* Generate C# structure bindings.  We prefix struct names with
10560    * underscore because C# cannot have conflicting struct names and
10561    * method names (eg. "class stat" and "stat").
10562    *)
10563   List.iter (
10564     fun (typ, cols) ->
10565       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10566       pr "    public class _%s {\n" typ;
10567       List.iter (
10568         function
10569         | name, FChar -> pr "      char %s;\n" name
10570         | name, FString -> pr "      string %s;\n" name
10571         | name, FBuffer ->
10572             pr "      uint %s_len;\n" name;
10573             pr "      string %s;\n" name
10574         | name, FUUID ->
10575             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10576             pr "      string %s;\n" name
10577         | name, FUInt32 -> pr "      uint %s;\n" name
10578         | name, FInt32 -> pr "      int %s;\n" name
10579         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10580         | name, FInt64 -> pr "      long %s;\n" name
10581         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10582       ) cols;
10583       pr "    }\n";
10584       pr "\n"
10585   ) structs;
10586
10587   (* Generate C# function bindings. *)
10588   List.iter (
10589     fun (name, style, _, _, _, shortdesc, _) ->
10590       let rec csharp_return_type () =
10591         match fst style with
10592         | RErr -> "void"
10593         | RBool n -> "bool"
10594         | RInt n -> "int"
10595         | RInt64 n -> "long"
10596         | RConstString n
10597         | RConstOptString n
10598         | RString n
10599         | RBufferOut n -> "string"
10600         | RStruct (_,n) -> "_" ^ n
10601         | RHashtable n -> "Hashtable"
10602         | RStringList n -> "string[]"
10603         | RStructList (_,n) -> sprintf "_%s[]" n
10604
10605       and c_return_type () =
10606         match fst style with
10607         | RErr
10608         | RBool _
10609         | RInt _ -> "int"
10610         | RInt64 _ -> "long"
10611         | RConstString _
10612         | RConstOptString _
10613         | RString _
10614         | RBufferOut _ -> "string"
10615         | RStruct (_,n) -> "_" ^ n
10616         | RHashtable _
10617         | RStringList _ -> "string[]"
10618         | RStructList (_,n) -> sprintf "_%s[]" n
10619
10620       and c_error_comparison () =
10621         match fst style with
10622         | RErr
10623         | RBool _
10624         | RInt _
10625         | RInt64 _ -> "== -1"
10626         | RConstString _
10627         | RConstOptString _
10628         | RString _
10629         | RBufferOut _
10630         | RStruct (_,_)
10631         | RHashtable _
10632         | RStringList _
10633         | RStructList (_,_) -> "== null"
10634
10635       and generate_extern_prototype () =
10636         pr "    static extern %s guestfs_%s (IntPtr h"
10637           (c_return_type ()) name;
10638         List.iter (
10639           function
10640           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10641           | FileIn n | FileOut n ->
10642               pr ", [In] string %s" n
10643           | StringList n | DeviceList n ->
10644               pr ", [In] string[] %s" n
10645           | Bool n ->
10646               pr ", bool %s" n
10647           | Int n ->
10648               pr ", int %s" n
10649           | Int64 n ->
10650               pr ", long %s" n
10651         ) (snd style);
10652         pr ");\n"
10653
10654       and generate_public_prototype () =
10655         pr "    public %s %s (" (csharp_return_type ()) name;
10656         let comma = ref false in
10657         let next () =
10658           if !comma then pr ", ";
10659           comma := true
10660         in
10661         List.iter (
10662           function
10663           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10664           | FileIn n | FileOut n ->
10665               next (); pr "string %s" n
10666           | StringList n | DeviceList n ->
10667               next (); pr "string[] %s" n
10668           | Bool n ->
10669               next (); pr "bool %s" n
10670           | Int n ->
10671               next (); pr "int %s" n
10672           | Int64 n ->
10673               next (); pr "long %s" n
10674         ) (snd style);
10675         pr ")\n"
10676
10677       and generate_call () =
10678         pr "guestfs_%s (_handle" name;
10679         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10680         pr ");\n";
10681       in
10682
10683       pr "    [DllImport (\"%s\")]\n" library;
10684       generate_extern_prototype ();
10685       pr "\n";
10686       pr "    /// <summary>\n";
10687       pr "    /// %s\n" shortdesc;
10688       pr "    /// </summary>\n";
10689       generate_public_prototype ();
10690       pr "    {\n";
10691       pr "      %s r;\n" (c_return_type ());
10692       pr "      r = ";
10693       generate_call ();
10694       pr "      if (r %s)\n" (c_error_comparison ());
10695       pr "        throw new Error (guestfs_last_error (_handle));\n";
10696       (match fst style with
10697        | RErr -> ()
10698        | RBool _ ->
10699            pr "      return r != 0 ? true : false;\n"
10700        | RHashtable _ ->
10701            pr "      Hashtable rr = new Hashtable ();\n";
10702            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10703            pr "        rr.Add (r[i], r[i+1]);\n";
10704            pr "      return rr;\n"
10705        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10706        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10707        | RStructList _ ->
10708            pr "      return r;\n"
10709       );
10710       pr "    }\n";
10711       pr "\n";
10712   ) all_functions_sorted;
10713
10714   pr "  }
10715 }
10716 "
10717
10718 and generate_bindtests () =
10719   generate_header CStyle LGPLv2plus;
10720
10721   pr "\
10722 #include <stdio.h>
10723 #include <stdlib.h>
10724 #include <inttypes.h>
10725 #include <string.h>
10726
10727 #include \"guestfs.h\"
10728 #include \"guestfs-internal.h\"
10729 #include \"guestfs-internal-actions.h\"
10730 #include \"guestfs_protocol.h\"
10731
10732 #define error guestfs_error
10733 #define safe_calloc guestfs_safe_calloc
10734 #define safe_malloc guestfs_safe_malloc
10735
10736 static void
10737 print_strings (char *const *argv)
10738 {
10739   int argc;
10740
10741   printf (\"[\");
10742   for (argc = 0; argv[argc] != NULL; ++argc) {
10743     if (argc > 0) printf (\", \");
10744     printf (\"\\\"%%s\\\"\", argv[argc]);
10745   }
10746   printf (\"]\\n\");
10747 }
10748
10749 /* The test0 function prints its parameters to stdout. */
10750 ";
10751
10752   let test0, tests =
10753     match test_functions with
10754     | [] -> assert false
10755     | test0 :: tests -> test0, tests in
10756
10757   let () =
10758     let (name, style, _, _, _, _, _) = test0 in
10759     generate_prototype ~extern:false ~semicolon:false ~newline:true
10760       ~handle:"g" ~prefix:"guestfs__" name style;
10761     pr "{\n";
10762     List.iter (
10763       function
10764       | Pathname n
10765       | Device n | Dev_or_Path n
10766       | String n
10767       | FileIn n
10768       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10769       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10770       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10771       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10772       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10773       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10774     ) (snd style);
10775     pr "  /* Java changes stdout line buffering so we need this: */\n";
10776     pr "  fflush (stdout);\n";
10777     pr "  return 0;\n";
10778     pr "}\n";
10779     pr "\n" in
10780
10781   List.iter (
10782     fun (name, style, _, _, _, _, _) ->
10783       if String.sub name (String.length name - 3) 3 <> "err" then (
10784         pr "/* Test normal return. */\n";
10785         generate_prototype ~extern:false ~semicolon:false ~newline:true
10786           ~handle:"g" ~prefix:"guestfs__" name style;
10787         pr "{\n";
10788         (match fst style with
10789          | RErr ->
10790              pr "  return 0;\n"
10791          | RInt _ ->
10792              pr "  int r;\n";
10793              pr "  sscanf (val, \"%%d\", &r);\n";
10794              pr "  return r;\n"
10795          | RInt64 _ ->
10796              pr "  int64_t r;\n";
10797              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10798              pr "  return r;\n"
10799          | RBool _ ->
10800              pr "  return STREQ (val, \"true\");\n"
10801          | RConstString _
10802          | RConstOptString _ ->
10803              (* Can't return the input string here.  Return a static
10804               * string so we ensure we get a segfault if the caller
10805               * tries to free it.
10806               *)
10807              pr "  return \"static string\";\n"
10808          | RString _ ->
10809              pr "  return strdup (val);\n"
10810          | RStringList _ ->
10811              pr "  char **strs;\n";
10812              pr "  int n, i;\n";
10813              pr "  sscanf (val, \"%%d\", &n);\n";
10814              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10815              pr "  for (i = 0; i < n; ++i) {\n";
10816              pr "    strs[i] = safe_malloc (g, 16);\n";
10817              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10818              pr "  }\n";
10819              pr "  strs[n] = NULL;\n";
10820              pr "  return strs;\n"
10821          | RStruct (_, typ) ->
10822              pr "  struct guestfs_%s *r;\n" typ;
10823              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10824              pr "  return r;\n"
10825          | RStructList (_, typ) ->
10826              pr "  struct guestfs_%s_list *r;\n" typ;
10827              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10828              pr "  sscanf (val, \"%%d\", &r->len);\n";
10829              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10830              pr "  return r;\n"
10831          | RHashtable _ ->
10832              pr "  char **strs;\n";
10833              pr "  int n, i;\n";
10834              pr "  sscanf (val, \"%%d\", &n);\n";
10835              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10836              pr "  for (i = 0; i < n; ++i) {\n";
10837              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10838              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10839              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10840              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10841              pr "  }\n";
10842              pr "  strs[n*2] = NULL;\n";
10843              pr "  return strs;\n"
10844          | RBufferOut _ ->
10845              pr "  return strdup (val);\n"
10846         );
10847         pr "}\n";
10848         pr "\n"
10849       ) else (
10850         pr "/* Test error return. */\n";
10851         generate_prototype ~extern:false ~semicolon:false ~newline:true
10852           ~handle:"g" ~prefix:"guestfs__" name style;
10853         pr "{\n";
10854         pr "  error (g, \"error\");\n";
10855         (match fst style with
10856          | RErr | RInt _ | RInt64 _ | RBool _ ->
10857              pr "  return -1;\n"
10858          | RConstString _ | RConstOptString _
10859          | RString _ | RStringList _ | RStruct _
10860          | RStructList _
10861          | RHashtable _
10862          | RBufferOut _ ->
10863              pr "  return NULL;\n"
10864         );
10865         pr "}\n";
10866         pr "\n"
10867       )
10868   ) tests
10869
10870 and generate_ocaml_bindtests () =
10871   generate_header OCamlStyle GPLv2plus;
10872
10873   pr "\
10874 let () =
10875   let g = Guestfs.create () in
10876 ";
10877
10878   let mkargs args =
10879     String.concat " " (
10880       List.map (
10881         function
10882         | CallString s -> "\"" ^ s ^ "\""
10883         | CallOptString None -> "None"
10884         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10885         | CallStringList xs ->
10886             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10887         | CallInt i when i >= 0 -> string_of_int i
10888         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10889         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10890         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10891         | CallBool b -> string_of_bool b
10892       ) args
10893     )
10894   in
10895
10896   generate_lang_bindtests (
10897     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10898   );
10899
10900   pr "print_endline \"EOF\"\n"
10901
10902 and generate_perl_bindtests () =
10903   pr "#!/usr/bin/perl -w\n";
10904   generate_header HashStyle GPLv2plus;
10905
10906   pr "\
10907 use strict;
10908
10909 use Sys::Guestfs;
10910
10911 my $g = Sys::Guestfs->new ();
10912 ";
10913
10914   let mkargs args =
10915     String.concat ", " (
10916       List.map (
10917         function
10918         | CallString s -> "\"" ^ s ^ "\""
10919         | CallOptString None -> "undef"
10920         | CallOptString (Some s) -> sprintf "\"%s\"" s
10921         | CallStringList xs ->
10922             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10923         | CallInt i -> string_of_int i
10924         | CallInt64 i -> Int64.to_string i
10925         | CallBool b -> if b then "1" else "0"
10926       ) args
10927     )
10928   in
10929
10930   generate_lang_bindtests (
10931     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10932   );
10933
10934   pr "print \"EOF\\n\"\n"
10935
10936 and generate_python_bindtests () =
10937   generate_header HashStyle GPLv2plus;
10938
10939   pr "\
10940 import guestfs
10941
10942 g = guestfs.GuestFS ()
10943 ";
10944
10945   let mkargs args =
10946     String.concat ", " (
10947       List.map (
10948         function
10949         | CallString s -> "\"" ^ s ^ "\""
10950         | CallOptString None -> "None"
10951         | CallOptString (Some s) -> sprintf "\"%s\"" s
10952         | CallStringList xs ->
10953             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10954         | CallInt i -> string_of_int i
10955         | CallInt64 i -> Int64.to_string i
10956         | CallBool b -> if b then "1" else "0"
10957       ) args
10958     )
10959   in
10960
10961   generate_lang_bindtests (
10962     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10963   );
10964
10965   pr "print \"EOF\"\n"
10966
10967 and generate_ruby_bindtests () =
10968   generate_header HashStyle GPLv2plus;
10969
10970   pr "\
10971 require 'guestfs'
10972
10973 g = Guestfs::create()
10974 ";
10975
10976   let mkargs args =
10977     String.concat ", " (
10978       List.map (
10979         function
10980         | CallString s -> "\"" ^ s ^ "\""
10981         | CallOptString None -> "nil"
10982         | CallOptString (Some s) -> sprintf "\"%s\"" s
10983         | CallStringList xs ->
10984             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10985         | CallInt i -> string_of_int i
10986         | CallInt64 i -> Int64.to_string i
10987         | CallBool b -> string_of_bool b
10988       ) args
10989     )
10990   in
10991
10992   generate_lang_bindtests (
10993     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10994   );
10995
10996   pr "print \"EOF\\n\"\n"
10997
10998 and generate_java_bindtests () =
10999   generate_header CStyle GPLv2plus;
11000
11001   pr "\
11002 import com.redhat.et.libguestfs.*;
11003
11004 public class Bindtests {
11005     public static void main (String[] argv)
11006     {
11007         try {
11008             GuestFS g = new GuestFS ();
11009 ";
11010
11011   let mkargs args =
11012     String.concat ", " (
11013       List.map (
11014         function
11015         | CallString s -> "\"" ^ s ^ "\""
11016         | CallOptString None -> "null"
11017         | CallOptString (Some s) -> sprintf "\"%s\"" s
11018         | CallStringList xs ->
11019             "new String[]{" ^
11020               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
11021         | CallInt i -> string_of_int i
11022         | CallInt64 i -> Int64.to_string i
11023         | CallBool b -> string_of_bool b
11024       ) args
11025     )
11026   in
11027
11028   generate_lang_bindtests (
11029     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
11030   );
11031
11032   pr "
11033             System.out.println (\"EOF\");
11034         }
11035         catch (Exception exn) {
11036             System.err.println (exn);
11037             System.exit (1);
11038         }
11039     }
11040 }
11041 "
11042
11043 and generate_haskell_bindtests () =
11044   generate_header HaskellStyle GPLv2plus;
11045
11046   pr "\
11047 module Bindtests where
11048 import qualified Guestfs
11049
11050 main = do
11051   g <- Guestfs.create
11052 ";
11053
11054   let mkargs args =
11055     String.concat " " (
11056       List.map (
11057         function
11058         | CallString s -> "\"" ^ s ^ "\""
11059         | CallOptString None -> "Nothing"
11060         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
11061         | CallStringList xs ->
11062             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11063         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
11064         | CallInt i -> string_of_int i
11065         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
11066         | CallInt64 i -> Int64.to_string i
11067         | CallBool true -> "True"
11068         | CallBool false -> "False"
11069       ) args
11070     )
11071   in
11072
11073   generate_lang_bindtests (
11074     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
11075   );
11076
11077   pr "  putStrLn \"EOF\"\n"
11078
11079 (* Language-independent bindings tests - we do it this way to
11080  * ensure there is parity in testing bindings across all languages.
11081  *)
11082 and generate_lang_bindtests call =
11083   call "test0" [CallString "abc"; CallOptString (Some "def");
11084                 CallStringList []; CallBool false;
11085                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11086   call "test0" [CallString "abc"; CallOptString None;
11087                 CallStringList []; CallBool false;
11088                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11089   call "test0" [CallString ""; CallOptString (Some "def");
11090                 CallStringList []; CallBool false;
11091                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11092   call "test0" [CallString ""; CallOptString (Some "");
11093                 CallStringList []; CallBool false;
11094                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11095   call "test0" [CallString "abc"; CallOptString (Some "def");
11096                 CallStringList ["1"]; CallBool false;
11097                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11098   call "test0" [CallString "abc"; CallOptString (Some "def");
11099                 CallStringList ["1"; "2"]; CallBool false;
11100                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11101   call "test0" [CallString "abc"; CallOptString (Some "def");
11102                 CallStringList ["1"]; CallBool true;
11103                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11104   call "test0" [CallString "abc"; CallOptString (Some "def");
11105                 CallStringList ["1"]; CallBool false;
11106                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
11107   call "test0" [CallString "abc"; CallOptString (Some "def");
11108                 CallStringList ["1"]; CallBool false;
11109                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
11110   call "test0" [CallString "abc"; CallOptString (Some "def");
11111                 CallStringList ["1"]; CallBool false;
11112                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
11113   call "test0" [CallString "abc"; CallOptString (Some "def");
11114                 CallStringList ["1"]; CallBool false;
11115                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
11116   call "test0" [CallString "abc"; CallOptString (Some "def");
11117                 CallStringList ["1"]; CallBool false;
11118                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
11119   call "test0" [CallString "abc"; CallOptString (Some "def");
11120                 CallStringList ["1"]; CallBool false;
11121                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
11122
11123 (* XXX Add here tests of the return and error functions. *)
11124
11125 (* Code to generator bindings for virt-inspector.  Currently only
11126  * implemented for OCaml code (for virt-p2v 2.0).
11127  *)
11128 let rng_input = "inspector/virt-inspector.rng"
11129
11130 (* Read the input file and parse it into internal structures.  This is
11131  * by no means a complete RELAX NG parser, but is just enough to be
11132  * able to parse the specific input file.
11133  *)
11134 type rng =
11135   | Element of string * rng list        (* <element name=name/> *)
11136   | Attribute of string * rng list        (* <attribute name=name/> *)
11137   | Interleave of rng list                (* <interleave/> *)
11138   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
11139   | OneOrMore of rng                        (* <oneOrMore/> *)
11140   | Optional of rng                        (* <optional/> *)
11141   | Choice of string list                (* <choice><value/>*</choice> *)
11142   | Value of string                        (* <value>str</value> *)
11143   | Text                                (* <text/> *)
11144
11145 let rec string_of_rng = function
11146   | Element (name, xs) ->
11147       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11148   | Attribute (name, xs) ->
11149       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11150   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
11151   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
11152   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
11153   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
11154   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
11155   | Value value -> "Value \"" ^ value ^ "\""
11156   | Text -> "Text"
11157
11158 and string_of_rng_list xs =
11159   String.concat ", " (List.map string_of_rng xs)
11160
11161 let rec parse_rng ?defines context = function
11162   | [] -> []
11163   | Xml.Element ("element", ["name", name], children) :: rest ->
11164       Element (name, parse_rng ?defines context children)
11165       :: parse_rng ?defines context rest
11166   | Xml.Element ("attribute", ["name", name], children) :: rest ->
11167       Attribute (name, parse_rng ?defines context children)
11168       :: parse_rng ?defines context rest
11169   | Xml.Element ("interleave", [], children) :: rest ->
11170       Interleave (parse_rng ?defines context children)
11171       :: parse_rng ?defines context rest
11172   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
11173       let rng = parse_rng ?defines context [child] in
11174       (match rng with
11175        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
11176        | _ ->
11177            failwithf "%s: <zeroOrMore> contains more than one child element"
11178              context
11179       )
11180   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
11181       let rng = parse_rng ?defines context [child] in
11182       (match rng with
11183        | [child] -> OneOrMore child :: parse_rng ?defines context rest
11184        | _ ->
11185            failwithf "%s: <oneOrMore> contains more than one child element"
11186              context
11187       )
11188   | Xml.Element ("optional", [], [child]) :: rest ->
11189       let rng = parse_rng ?defines context [child] in
11190       (match rng with
11191        | [child] -> Optional child :: parse_rng ?defines context rest
11192        | _ ->
11193            failwithf "%s: <optional> contains more than one child element"
11194              context
11195       )
11196   | Xml.Element ("choice", [], children) :: rest ->
11197       let values = List.map (
11198         function Xml.Element ("value", [], [Xml.PCData value]) -> value
11199         | _ ->
11200             failwithf "%s: can't handle anything except <value> in <choice>"
11201               context
11202       ) children in
11203       Choice values
11204       :: parse_rng ?defines context rest
11205   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
11206       Value value :: parse_rng ?defines context rest
11207   | Xml.Element ("text", [], []) :: rest ->
11208       Text :: parse_rng ?defines context rest
11209   | Xml.Element ("ref", ["name", name], []) :: rest ->
11210       (* Look up the reference.  Because of limitations in this parser,
11211        * we can't handle arbitrarily nested <ref> yet.  You can only
11212        * use <ref> from inside <start>.
11213        *)
11214       (match defines with
11215        | None ->
11216            failwithf "%s: contains <ref>, but no refs are defined yet" context
11217        | Some map ->
11218            let rng = StringMap.find name map in
11219            rng @ parse_rng ?defines context rest
11220       )
11221   | x :: _ ->
11222       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
11223
11224 let grammar =
11225   let xml = Xml.parse_file rng_input in
11226   match xml with
11227   | Xml.Element ("grammar", _,
11228                  Xml.Element ("start", _, gram) :: defines) ->
11229       (* The <define/> elements are referenced in the <start> section,
11230        * so build a map of those first.
11231        *)
11232       let defines = List.fold_left (
11233         fun map ->
11234           function Xml.Element ("define", ["name", name], defn) ->
11235             StringMap.add name defn map
11236           | _ ->
11237               failwithf "%s: expected <define name=name/>" rng_input
11238       ) StringMap.empty defines in
11239       let defines = StringMap.mapi parse_rng defines in
11240
11241       (* Parse the <start> clause, passing the defines. *)
11242       parse_rng ~defines "<start>" gram
11243   | _ ->
11244       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
11245         rng_input
11246
11247 let name_of_field = function
11248   | Element (name, _) | Attribute (name, _)
11249   | ZeroOrMore (Element (name, _))
11250   | OneOrMore (Element (name, _))
11251   | Optional (Element (name, _)) -> name
11252   | Optional (Attribute (name, _)) -> name
11253   | Text -> (* an unnamed field in an element *)
11254       "data"
11255   | rng ->
11256       failwithf "name_of_field failed at: %s" (string_of_rng rng)
11257
11258 (* At the moment this function only generates OCaml types.  However we
11259  * should parameterize it later so it can generate types/structs in a
11260  * variety of languages.
11261  *)
11262 let generate_types xs =
11263   (* A simple type is one that can be printed out directly, eg.
11264    * "string option".  A complex type is one which has a name and has
11265    * to be defined via another toplevel definition, eg. a struct.
11266    *
11267    * generate_type generates code for either simple or complex types.
11268    * In the simple case, it returns the string ("string option").  In
11269    * the complex case, it returns the name ("mountpoint").  In the
11270    * complex case it has to print out the definition before returning,
11271    * so it should only be called when we are at the beginning of a
11272    * new line (BOL context).
11273    *)
11274   let rec generate_type = function
11275     | Text ->                                (* string *)
11276         "string", true
11277     | Choice values ->                        (* [`val1|`val2|...] *)
11278         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
11279     | ZeroOrMore rng ->                        (* <rng> list *)
11280         let t, is_simple = generate_type rng in
11281         t ^ " list (* 0 or more *)", is_simple
11282     | OneOrMore rng ->                        (* <rng> list *)
11283         let t, is_simple = generate_type rng in
11284         t ^ " list (* 1 or more *)", is_simple
11285                                         (* virt-inspector hack: bool *)
11286     | Optional (Attribute (name, [Value "1"])) ->
11287         "bool", true
11288     | Optional rng ->                        (* <rng> list *)
11289         let t, is_simple = generate_type rng in
11290         t ^ " option", is_simple
11291                                         (* type name = { fields ... } *)
11292     | Element (name, fields) when is_attrs_interleave fields ->
11293         generate_type_struct name (get_attrs_interleave fields)
11294     | Element (name, [field])                (* type name = field *)
11295     | Attribute (name, [field]) ->
11296         let t, is_simple = generate_type field in
11297         if is_simple then (t, true)
11298         else (
11299           pr "type %s = %s\n" name t;
11300           name, false
11301         )
11302     | Element (name, fields) ->              (* type name = { fields ... } *)
11303         generate_type_struct name fields
11304     | rng ->
11305         failwithf "generate_type failed at: %s" (string_of_rng rng)
11306
11307   and is_attrs_interleave = function
11308     | [Interleave _] -> true
11309     | Attribute _ :: fields -> is_attrs_interleave fields
11310     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11311     | _ -> false
11312
11313   and get_attrs_interleave = function
11314     | [Interleave fields] -> fields
11315     | ((Attribute _) as field) :: fields
11316     | ((Optional (Attribute _)) as field) :: fields ->
11317         field :: get_attrs_interleave fields
11318     | _ -> assert false
11319
11320   and generate_types xs =
11321     List.iter (fun x -> ignore (generate_type x)) xs
11322
11323   and generate_type_struct name fields =
11324     (* Calculate the types of the fields first.  We have to do this
11325      * before printing anything so we are still in BOL context.
11326      *)
11327     let types = List.map fst (List.map generate_type fields) in
11328
11329     (* Special case of a struct containing just a string and another
11330      * field.  Turn it into an assoc list.
11331      *)
11332     match types with
11333     | ["string"; other] ->
11334         let fname1, fname2 =
11335           match fields with
11336           | [f1; f2] -> name_of_field f1, name_of_field f2
11337           | _ -> assert false in
11338         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
11339         name, false
11340
11341     | types ->
11342         pr "type %s = {\n" name;
11343         List.iter (
11344           fun (field, ftype) ->
11345             let fname = name_of_field field in
11346             pr "  %s_%s : %s;\n" name fname ftype
11347         ) (List.combine fields types);
11348         pr "}\n";
11349         (* Return the name of this type, and
11350          * false because it's not a simple type.
11351          *)
11352         name, false
11353   in
11354
11355   generate_types xs
11356
11357 let generate_parsers xs =
11358   (* As for generate_type above, generate_parser makes a parser for
11359    * some type, and returns the name of the parser it has generated.
11360    * Because it (may) need to print something, it should always be
11361    * called in BOL context.
11362    *)
11363   let rec generate_parser = function
11364     | Text ->                                (* string *)
11365         "string_child_or_empty"
11366     | Choice values ->                        (* [`val1|`val2|...] *)
11367         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
11368           (String.concat "|"
11369              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
11370     | ZeroOrMore rng ->                        (* <rng> list *)
11371         let pa = generate_parser rng in
11372         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11373     | OneOrMore rng ->                        (* <rng> list *)
11374         let pa = generate_parser rng in
11375         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11376                                         (* virt-inspector hack: bool *)
11377     | Optional (Attribute (name, [Value "1"])) ->
11378         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
11379     | Optional rng ->                        (* <rng> list *)
11380         let pa = generate_parser rng in
11381         sprintf "(function None -> None | Some x -> Some (%s x))" pa
11382                                         (* type name = { fields ... } *)
11383     | Element (name, fields) when is_attrs_interleave fields ->
11384         generate_parser_struct name (get_attrs_interleave fields)
11385     | Element (name, [field]) ->        (* type name = field *)
11386         let pa = generate_parser field in
11387         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11388         pr "let %s =\n" parser_name;
11389         pr "  %s\n" pa;
11390         pr "let parse_%s = %s\n" name parser_name;
11391         parser_name
11392     | Attribute (name, [field]) ->
11393         let pa = generate_parser field in
11394         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11395         pr "let %s =\n" parser_name;
11396         pr "  %s\n" pa;
11397         pr "let parse_%s = %s\n" name parser_name;
11398         parser_name
11399     | Element (name, fields) ->              (* type name = { fields ... } *)
11400         generate_parser_struct name ([], fields)
11401     | rng ->
11402         failwithf "generate_parser failed at: %s" (string_of_rng rng)
11403
11404   and is_attrs_interleave = function
11405     | [Interleave _] -> true
11406     | Attribute _ :: fields -> is_attrs_interleave fields
11407     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11408     | _ -> false
11409
11410   and get_attrs_interleave = function
11411     | [Interleave fields] -> [], fields
11412     | ((Attribute _) as field) :: fields
11413     | ((Optional (Attribute _)) as field) :: fields ->
11414         let attrs, interleaves = get_attrs_interleave fields in
11415         (field :: attrs), interleaves
11416     | _ -> assert false
11417
11418   and generate_parsers xs =
11419     List.iter (fun x -> ignore (generate_parser x)) xs
11420
11421   and generate_parser_struct name (attrs, interleaves) =
11422     (* Generate parsers for the fields first.  We have to do this
11423      * before printing anything so we are still in BOL context.
11424      *)
11425     let fields = attrs @ interleaves in
11426     let pas = List.map generate_parser fields in
11427
11428     (* Generate an intermediate tuple from all the fields first.
11429      * If the type is just a string + another field, then we will
11430      * return this directly, otherwise it is turned into a record.
11431      *
11432      * RELAX NG note: This code treats <interleave> and plain lists of
11433      * fields the same.  In other words, it doesn't bother enforcing
11434      * any ordering of fields in the XML.
11435      *)
11436     pr "let parse_%s x =\n" name;
11437     pr "  let t = (\n    ";
11438     let comma = ref false in
11439     List.iter (
11440       fun x ->
11441         if !comma then pr ",\n    ";
11442         comma := true;
11443         match x with
11444         | Optional (Attribute (fname, [field])), pa ->
11445             pr "%s x" pa
11446         | Optional (Element (fname, [field])), pa ->
11447             pr "%s (optional_child %S x)" pa fname
11448         | Attribute (fname, [Text]), _ ->
11449             pr "attribute %S x" fname
11450         | (ZeroOrMore _ | OneOrMore _), pa ->
11451             pr "%s x" pa
11452         | Text, pa ->
11453             pr "%s x" pa
11454         | (field, pa) ->
11455             let fname = name_of_field field in
11456             pr "%s (child %S x)" pa fname
11457     ) (List.combine fields pas);
11458     pr "\n  ) in\n";
11459
11460     (match fields with
11461      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11462          pr "  t\n"
11463
11464      | _ ->
11465          pr "  (Obj.magic t : %s)\n" name
11466 (*
11467          List.iter (
11468            function
11469            | (Optional (Attribute (fname, [field])), pa) ->
11470                pr "  %s_%s =\n" name fname;
11471                pr "    %s x;\n" pa
11472            | (Optional (Element (fname, [field])), pa) ->
11473                pr "  %s_%s =\n" name fname;
11474                pr "    (let x = optional_child %S x in\n" fname;
11475                pr "     %s x);\n" pa
11476            | (field, pa) ->
11477                let fname = name_of_field field in
11478                pr "  %s_%s =\n" name fname;
11479                pr "    (let x = child %S x in\n" fname;
11480                pr "     %s x);\n" pa
11481          ) (List.combine fields pas);
11482          pr "}\n"
11483 *)
11484     );
11485     sprintf "parse_%s" name
11486   in
11487
11488   generate_parsers xs
11489
11490 (* Generate ocaml/guestfs_inspector.mli. *)
11491 let generate_ocaml_inspector_mli () =
11492   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11493
11494   pr "\
11495 (** This is an OCaml language binding to the external [virt-inspector]
11496     program.
11497
11498     For more information, please read the man page [virt-inspector(1)].
11499 *)
11500
11501 ";
11502
11503   generate_types grammar;
11504   pr "(** The nested information returned from the {!inspect} function. *)\n";
11505   pr "\n";
11506
11507   pr "\
11508 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11509 (** To inspect a libvirt domain called [name], pass a singleton
11510     list: [inspect [name]].  When using libvirt only, you may
11511     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11512
11513     To inspect a disk image or images, pass a list of the filenames
11514     of the disk images: [inspect filenames]
11515
11516     This function inspects the given guest or disk images and
11517     returns a list of operating system(s) found and a large amount
11518     of information about them.  In the vast majority of cases,
11519     a virtual machine only contains a single operating system.
11520
11521     If the optional [~xml] parameter is given, then this function
11522     skips running the external virt-inspector program and just
11523     parses the given XML directly (which is expected to be XML
11524     produced from a previous run of virt-inspector).  The list of
11525     names and connect URI are ignored in this case.
11526
11527     This function can throw a wide variety of exceptions, for example
11528     if the external virt-inspector program cannot be found, or if
11529     it doesn't generate valid XML.
11530 *)
11531 "
11532
11533 (* Generate ocaml/guestfs_inspector.ml. *)
11534 let generate_ocaml_inspector_ml () =
11535   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11536
11537   pr "open Unix\n";
11538   pr "\n";
11539
11540   generate_types grammar;
11541   pr "\n";
11542
11543   pr "\
11544 (* Misc functions which are used by the parser code below. *)
11545 let first_child = function
11546   | Xml.Element (_, _, c::_) -> c
11547   | Xml.Element (name, _, []) ->
11548       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11549   | Xml.PCData str ->
11550       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11551
11552 let string_child_or_empty = function
11553   | Xml.Element (_, _, [Xml.PCData s]) -> s
11554   | Xml.Element (_, _, []) -> \"\"
11555   | Xml.Element (x, _, _) ->
11556       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11557                 x ^ \" instead\")
11558   | Xml.PCData str ->
11559       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11560
11561 let optional_child name xml =
11562   let children = Xml.children xml in
11563   try
11564     Some (List.find (function
11565                      | Xml.Element (n, _, _) when n = name -> true
11566                      | _ -> false) children)
11567   with
11568     Not_found -> None
11569
11570 let child name xml =
11571   match optional_child name xml with
11572   | Some c -> c
11573   | None ->
11574       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11575
11576 let attribute name xml =
11577   try Xml.attrib xml name
11578   with Xml.No_attribute _ ->
11579     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11580
11581 ";
11582
11583   generate_parsers grammar;
11584   pr "\n";
11585
11586   pr "\
11587 (* Run external virt-inspector, then use parser to parse the XML. *)
11588 let inspect ?connect ?xml names =
11589   let xml =
11590     match xml with
11591     | None ->
11592         if names = [] then invalid_arg \"inspect: no names given\";
11593         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11594           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11595           names in
11596         let cmd = List.map Filename.quote cmd in
11597         let cmd = String.concat \" \" cmd in
11598         let chan = open_process_in cmd in
11599         let xml = Xml.parse_in chan in
11600         (match close_process_in chan with
11601          | WEXITED 0 -> ()
11602          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11603          | WSIGNALED i | WSTOPPED i ->
11604              failwith (\"external virt-inspector command died or stopped on sig \" ^
11605                        string_of_int i)
11606         );
11607         xml
11608     | Some doc ->
11609         Xml.parse_string doc in
11610   parse_operatingsystems xml
11611 "
11612
11613 (* This is used to generate the src/MAX_PROC_NR file which
11614  * contains the maximum procedure number, a surrogate for the
11615  * ABI version number.  See src/Makefile.am for the details.
11616  *)
11617 and generate_max_proc_nr () =
11618   let proc_nrs = List.map (
11619     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11620   ) daemon_functions in
11621
11622   let max_proc_nr = List.fold_left max 0 proc_nrs in
11623
11624   pr "%d\n" max_proc_nr
11625
11626 let output_to filename k =
11627   let filename_new = filename ^ ".new" in
11628   chan := open_out filename_new;
11629   k ();
11630   close_out !chan;
11631   chan := Pervasives.stdout;
11632
11633   (* Is the new file different from the current file? *)
11634   if Sys.file_exists filename && files_equal filename filename_new then
11635     unlink filename_new                 (* same, so skip it *)
11636   else (
11637     (* different, overwrite old one *)
11638     (try chmod filename 0o644 with Unix_error _ -> ());
11639     rename filename_new filename;
11640     chmod filename 0o444;
11641     printf "written %s\n%!" filename;
11642   )
11643
11644 let perror msg = function
11645   | Unix_error (err, _, _) ->
11646       eprintf "%s: %s\n" msg (error_message err)
11647   | exn ->
11648       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11649
11650 (* Main program. *)
11651 let () =
11652   let lock_fd =
11653     try openfile "HACKING" [O_RDWR] 0
11654     with
11655     | Unix_error (ENOENT, _, _) ->
11656         eprintf "\
11657 You are probably running this from the wrong directory.
11658 Run it from the top source directory using the command
11659   src/generator.ml
11660 ";
11661         exit 1
11662     | exn ->
11663         perror "open: HACKING" exn;
11664         exit 1 in
11665
11666   (* Acquire a lock so parallel builds won't try to run the generator
11667    * twice at the same time.  Subsequent builds will wait for the first
11668    * one to finish.  Note the lock is released implicitly when the
11669    * program exits.
11670    *)
11671   (try lockf lock_fd F_LOCK 1
11672    with exn ->
11673      perror "lock: HACKING" exn;
11674      exit 1);
11675
11676   check_functions ();
11677
11678   output_to "src/guestfs_protocol.x" generate_xdr;
11679   output_to "src/guestfs-structs.h" generate_structs_h;
11680   output_to "src/guestfs-actions.h" generate_actions_h;
11681   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11682   output_to "src/guestfs-actions.c" generate_client_actions;
11683   output_to "src/guestfs-bindtests.c" generate_bindtests;
11684   output_to "src/guestfs-structs.pod" generate_structs_pod;
11685   output_to "src/guestfs-actions.pod" generate_actions_pod;
11686   output_to "src/guestfs-availability.pod" generate_availability_pod;
11687   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11688   output_to "src/libguestfs.syms" generate_linker_script;
11689   output_to "daemon/actions.h" generate_daemon_actions_h;
11690   output_to "daemon/stubs.c" generate_daemon_actions;
11691   output_to "daemon/names.c" generate_daemon_names;
11692   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11693   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11694   output_to "capitests/tests.c" generate_tests;
11695   output_to "fish/cmds.c" generate_fish_cmds;
11696   output_to "fish/completion.c" generate_fish_completion;
11697   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11698   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11699   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11700   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11701   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11702   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11703   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11704   output_to "perl/Guestfs.xs" generate_perl_xs;
11705   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11706   output_to "perl/bindtests.pl" generate_perl_bindtests;
11707   output_to "python/guestfs-py.c" generate_python_c;
11708   output_to "python/guestfs.py" generate_python_py;
11709   output_to "python/bindtests.py" generate_python_bindtests;
11710   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11711   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11712   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11713
11714   List.iter (
11715     fun (typ, jtyp) ->
11716       let cols = cols_of_struct typ in
11717       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11718       output_to filename (generate_java_struct jtyp cols);
11719   ) java_structs;
11720
11721   output_to "java/Makefile.inc" generate_java_makefile_inc;
11722   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11723   output_to "java/Bindtests.java" generate_java_bindtests;
11724   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11725   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11726   output_to "csharp/Libguestfs.cs" generate_csharp;
11727
11728   (* Always generate this file last, and unconditionally.  It's used
11729    * by the Makefile to know when we must re-run the generator.
11730    *)
11731   let chan = open_out "src/stamp-generator" in
11732   fprintf chan "1\n";
11733   close_out chan;
11734
11735   printf "generated %d lines of code\n" !lines