Mac OS X: kill(2) requires <signal.h>
[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   | NotInFish             (* do not export via guestfish *)
186   | NotInDocs             (* do not add this function to documentation *)
187   | DeprecatedBy of string (* function is deprecated, use .. instead *)
188   | Optional of string    (* function is part of an optional group *)
189
190 (* You can supply zero or as many tests as you want per API call.
191  *
192  * Note that the test environment has 3 block devices, of size 500MB,
193  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
194  * a fourth ISO block device with some known files on it (/dev/sdd).
195  *
196  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
197  * Number of cylinders was 63 for IDE emulated disks with precisely
198  * the same size.  How exactly this is calculated is a mystery.
199  *
200  * The ISO block device (/dev/sdd) comes from images/test.iso.
201  *
202  * To be able to run the tests in a reasonable amount of time,
203  * the virtual machine and block devices are reused between tests.
204  * So don't try testing kill_subprocess :-x
205  *
206  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
207  *
208  * Don't assume anything about the previous contents of the block
209  * devices.  Use 'Init*' to create some initial scenarios.
210  *
211  * You can add a prerequisite clause to any individual test.  This
212  * is a run-time check, which, if it fails, causes the test to be
213  * skipped.  Useful if testing a command which might not work on
214  * all variations of libguestfs builds.  A test that has prerequisite
215  * of 'Always' is run unconditionally.
216  *
217  * In addition, packagers can skip individual tests by setting the
218  * environment variables:     eg:
219  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
220  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
221  *)
222 type tests = (test_init * test_prereq * test) list
223 and test =
224     (* Run the command sequence and just expect nothing to fail. *)
225   | TestRun of seq
226
227     (* Run the command sequence and expect the output of the final
228      * command to be the string.
229      *)
230   | TestOutput of seq * string
231
232     (* Run the command sequence and expect the output of the final
233      * command to be the list of strings.
234      *)
235   | TestOutputList of seq * string list
236
237     (* Run the command sequence and expect the output of the final
238      * command to be the list of block devices (could be either
239      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
240      * character of each string).
241      *)
242   | TestOutputListOfDevices of seq * string list
243
244     (* Run the command sequence and expect the output of the final
245      * command to be the integer.
246      *)
247   | TestOutputInt of seq * int
248
249     (* Run the command sequence and expect the output of the final
250      * command to be <op> <int>, eg. ">=", "1".
251      *)
252   | TestOutputIntOp of seq * string * int
253
254     (* Run the command sequence and expect the output of the final
255      * command to be a true value (!= 0 or != NULL).
256      *)
257   | TestOutputTrue of seq
258
259     (* Run the command sequence and expect the output of the final
260      * command to be a false value (== 0 or == NULL, but not an error).
261      *)
262   | TestOutputFalse of seq
263
264     (* Run the command sequence and expect the output of the final
265      * command to be a list of the given length (but don't care about
266      * content).
267      *)
268   | TestOutputLength of seq * int
269
270     (* Run the command sequence and expect the output of the final
271      * command to be a buffer (RBufferOut), ie. string + size.
272      *)
273   | TestOutputBuffer of seq * string
274
275     (* Run the command sequence and expect the output of the final
276      * command to be a structure.
277      *)
278   | TestOutputStruct of seq * test_field_compare list
279
280     (* Run the command sequence and expect the final command (only)
281      * to fail.
282      *)
283   | TestLastFail of seq
284
285 and test_field_compare =
286   | CompareWithInt of string * int
287   | CompareWithIntOp of string * string * int
288   | CompareWithString of string * string
289   | CompareFieldsIntEq of string * string
290   | CompareFieldsStrEq of string * string
291
292 (* Test prerequisites. *)
293 and test_prereq =
294     (* Test always runs. *)
295   | Always
296
297     (* Test is currently disabled - eg. it fails, or it tests some
298      * unimplemented feature.
299      *)
300   | Disabled
301
302     (* 'string' is some C code (a function body) that should return
303      * true or false.  The test will run if the code returns true.
304      *)
305   | If of string
306
307     (* As for 'If' but the test runs _unless_ the code returns true. *)
308   | Unless of string
309
310 (* Some initial scenarios for testing. *)
311 and test_init =
312     (* Do nothing, block devices could contain random stuff including
313      * LVM PVs, and some filesystems might be mounted.  This is usually
314      * a bad idea.
315      *)
316   | InitNone
317
318     (* Block devices are empty and no filesystems are mounted. *)
319   | InitEmpty
320
321     (* /dev/sda contains a single partition /dev/sda1, with random
322      * content.  /dev/sdb and /dev/sdc may have random content.
323      * No LVM.
324      *)
325   | InitPartition
326
327     (* /dev/sda contains a single partition /dev/sda1, which is formatted
328      * as ext2, empty [except for lost+found] and mounted on /.
329      * /dev/sdb and /dev/sdc may have random content.
330      * No LVM.
331      *)
332   | InitBasicFS
333
334     (* /dev/sda:
335      *   /dev/sda1 (is a PV):
336      *     /dev/VG/LV (size 8MB):
337      *       formatted as ext2, empty [except for lost+found], mounted on /
338      * /dev/sdb and /dev/sdc may have random content.
339      *)
340   | InitBasicFSonLVM
341
342     (* /dev/sdd (the ISO, see images/ directory in source)
343      * is mounted on /
344      *)
345   | InitISOFS
346
347 (* Sequence of commands for testing. *)
348 and seq = cmd list
349 and cmd = string list
350
351 (* Note about long descriptions: When referring to another
352  * action, use the format C<guestfs_other> (ie. the full name of
353  * the C function).  This will be replaced as appropriate in other
354  * language bindings.
355  *
356  * Apart from that, long descriptions are just perldoc paragraphs.
357  *)
358
359 (* Generate a random UUID (used in tests). *)
360 let uuidgen () =
361   let chan = open_process_in "uuidgen" in
362   let uuid = input_line chan in
363   (match close_process_in chan with
364    | WEXITED 0 -> ()
365    | WEXITED _ ->
366        failwith "uuidgen: process exited with non-zero status"
367    | WSIGNALED _ | WSTOPPED _ ->
368        failwith "uuidgen: process signalled or stopped by signal"
369   );
370   uuid
371
372 (* These test functions are used in the language binding tests. *)
373
374 let test_all_args = [
375   String "str";
376   OptString "optstr";
377   StringList "strlist";
378   Bool "b";
379   Int "integer";
380   Int64 "integer64";
381   FileIn "filein";
382   FileOut "fileout";
383 ]
384
385 let test_all_rets = [
386   (* except for RErr, which is tested thoroughly elsewhere *)
387   "test0rint",         RInt "valout";
388   "test0rint64",       RInt64 "valout";
389   "test0rbool",        RBool "valout";
390   "test0rconststring", RConstString "valout";
391   "test0rconstoptstring", RConstOptString "valout";
392   "test0rstring",      RString "valout";
393   "test0rstringlist",  RStringList "valout";
394   "test0rstruct",      RStruct ("valout", "lvm_pv");
395   "test0rstructlist",  RStructList ("valout", "lvm_pv");
396   "test0rhashtable",   RHashtable "valout";
397 ]
398
399 let test_functions = [
400   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
401    [],
402    "internal test function - do not use",
403    "\
404 This is an internal test function which is used to test whether
405 the automatically generated bindings can handle every possible
406 parameter type correctly.
407
408 It echos the contents of each parameter to stdout.
409
410 You probably don't want to call this function.");
411 ] @ List.flatten (
412   List.map (
413     fun (name, ret) ->
414       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
415         [],
416         "internal test function - do not use",
417         "\
418 This is an internal test function which is used to test whether
419 the automatically generated bindings can handle every possible
420 return type correctly.
421
422 It converts string C<val> to the return type.
423
424 You probably don't want to call this function.");
425        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
426         [],
427         "internal test function - do not use",
428         "\
429 This is an internal test function which is used to test whether
430 the automatically generated bindings can handle every possible
431 return type correctly.
432
433 This function always returns an error.
434
435 You probably don't want to call this function.")]
436   ) test_all_rets
437 )
438
439 (* non_daemon_functions are any functions which don't get processed
440  * in the daemon, eg. functions for setting and getting local
441  * configuration values.
442  *)
443
444 let non_daemon_functions = test_functions @ [
445   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
446    [],
447    "launch the qemu subprocess",
448    "\
449 Internally libguestfs is implemented by running a virtual machine
450 using L<qemu(1)>.
451
452 You should call this after configuring the handle
453 (eg. adding drives) but before performing any actions.");
454
455   ("wait_ready", (RErr, []), -1, [NotInFish],
456    [],
457    "wait until the qemu subprocess launches (no op)",
458    "\
459 This function is a no op.
460
461 In versions of the API E<lt> 1.0.71 you had to call this function
462 just after calling C<guestfs_launch> to wait for the launch
463 to complete.  However this is no longer necessary because
464 C<guestfs_launch> now does the waiting.
465
466 If you see any calls to this function in code then you can just
467 remove them, unless you want to retain compatibility with older
468 versions of the API.");
469
470   ("kill_subprocess", (RErr, []), -1, [],
471    [],
472    "kill the qemu subprocess",
473    "\
474 This kills the qemu subprocess.  You should never need to call this.");
475
476   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
477    [],
478    "add an image to examine or modify",
479    "\
480 This function adds a virtual machine disk image C<filename> to the
481 guest.  The first time you call this function, the disk appears as IDE
482 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
483 so on.
484
485 You don't necessarily need to be root when using libguestfs.  However
486 you obviously do need sufficient permissions to access the filename
487 for whatever operations you want to perform (ie. read access if you
488 just want to read the image or write access if you want to modify the
489 image).
490
491 This is equivalent to the qemu parameter
492 C<-drive file=filename,cache=off,if=...>.
493
494 C<cache=off> is omitted in cases where it is not supported by
495 the underlying filesystem.
496
497 C<if=...> is set at compile time by the configuration option
498 C<./configure --with-drive-if=...>.  In the rare case where you
499 might need to change this at run time, use C<guestfs_add_drive_with_if>
500 or C<guestfs_add_drive_ro_with_if>.
501
502 Note that this call checks for the existence of C<filename>.  This
503 stops you from specifying other types of drive which are supported
504 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
505 the general C<guestfs_config> call instead.");
506
507   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
508    [],
509    "add a CD-ROM disk image to examine",
510    "\
511 This function adds a virtual CD-ROM disk image to the guest.
512
513 This is equivalent to the qemu parameter C<-cdrom filename>.
514
515 Notes:
516
517 =over 4
518
519 =item *
520
521 This call checks for the existence of C<filename>.  This
522 stops you from specifying other types of drive which are supported
523 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
524 the general C<guestfs_config> call instead.
525
526 =item *
527
528 If you just want to add an ISO file (often you use this as an
529 efficient way to transfer large files into the guest), then you
530 should probably use C<guestfs_add_drive_ro> instead.
531
532 =back");
533
534   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
535    [],
536    "add a drive in snapshot mode (read-only)",
537    "\
538 This adds a drive in snapshot mode, making it effectively
539 read-only.
540
541 Note that writes to the device are allowed, and will be seen for
542 the duration of the guestfs handle, but they are written
543 to a temporary file which is discarded as soon as the guestfs
544 handle is closed.  We don't currently have any method to enable
545 changes to be committed, although qemu can support this.
546
547 This is equivalent to the qemu parameter
548 C<-drive file=filename,snapshot=on,readonly=on,if=...>.
549
550 C<if=...> is set at compile time by the configuration option
551 C<./configure --with-drive-if=...>.  In the rare case where you
552 might need to change this at run time, use C<guestfs_add_drive_with_if>
553 or C<guestfs_add_drive_ro_with_if>.
554
555 C<readonly=on> is only added where qemu supports this option.
556
557 Note that this call checks for the existence of C<filename>.  This
558 stops you from specifying other types of drive which are supported
559 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
560 the general C<guestfs_config> call instead.");
561
562   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
563    [],
564    "add qemu parameters",
565    "\
566 This can be used to add arbitrary qemu command line parameters
567 of the form C<-param value>.  Actually it's not quite arbitrary - we
568 prevent you from setting some parameters which would interfere with
569 parameters that we use.
570
571 The first character of C<param> string must be a C<-> (dash).
572
573 C<value> can be NULL.");
574
575   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
576    [],
577    "set the qemu binary",
578    "\
579 Set the qemu binary that we will use.
580
581 The default is chosen when the library was compiled by the
582 configure script.
583
584 You can also override this by setting the C<LIBGUESTFS_QEMU>
585 environment variable.
586
587 Setting C<qemu> to C<NULL> restores the default qemu binary.
588
589 Note that you should call this function as early as possible
590 after creating the handle.  This is because some pre-launch
591 operations depend on testing qemu features (by running C<qemu -help>).
592 If the qemu binary changes, we don't retest features, and
593 so you might see inconsistent results.  Using the environment
594 variable C<LIBGUESTFS_QEMU> is safest of all since that picks
595 the qemu binary at the same time as the handle is created.");
596
597   ("get_qemu", (RConstString "qemu", []), -1, [],
598    [InitNone, Always, TestRun (
599       [["get_qemu"]])],
600    "get the qemu binary",
601    "\
602 Return the current qemu binary.
603
604 This is always non-NULL.  If it wasn't set already, then this will
605 return the default qemu binary name.");
606
607   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
608    [],
609    "set the search path",
610    "\
611 Set the path that libguestfs searches for kernel and initrd.img.
612
613 The default is C<$libdir/guestfs> unless overridden by setting
614 C<LIBGUESTFS_PATH> environment variable.
615
616 Setting C<path> to C<NULL> restores the default path.");
617
618   ("get_path", (RConstString "path", []), -1, [],
619    [InitNone, Always, TestRun (
620       [["get_path"]])],
621    "get the search path",
622    "\
623 Return the current search path.
624
625 This is always non-NULL.  If it wasn't set already, then this will
626 return the default path.");
627
628   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
629    [],
630    "add options to kernel command line",
631    "\
632 This function is used to add additional options to the
633 guest kernel command line.
634
635 The default is C<NULL> unless overridden by setting
636 C<LIBGUESTFS_APPEND> environment variable.
637
638 Setting C<append> to C<NULL> means I<no> additional options
639 are passed (libguestfs always adds a few of its own).");
640
641   ("get_append", (RConstOptString "append", []), -1, [],
642    (* This cannot be tested with the current framework.  The
643     * function can return NULL in normal operations, which the
644     * test framework interprets as an error.
645     *)
646    [],
647    "get the additional kernel options",
648    "\
649 Return the additional kernel options which are added to the
650 guest kernel command line.
651
652 If C<NULL> then no options are added.");
653
654   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
655    [],
656    "set autosync mode",
657    "\
658 If C<autosync> is true, this enables autosync.  Libguestfs will make a
659 best effort attempt to run C<guestfs_umount_all> followed by
660 C<guestfs_sync> when the handle is closed
661 (also if the program exits without closing handles).
662
663 This is disabled by default (except in guestfish where it is
664 enabled by default).");
665
666   ("get_autosync", (RBool "autosync", []), -1, [],
667    [InitNone, Always, TestRun (
668       [["get_autosync"]])],
669    "get autosync mode",
670    "\
671 Get the autosync flag.");
672
673   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
674    [],
675    "set verbose mode",
676    "\
677 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
678
679 Verbose messages are disabled unless the environment variable
680 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
681
682   ("get_verbose", (RBool "verbose", []), -1, [],
683    [],
684    "get verbose mode",
685    "\
686 This returns the verbose messages flag.");
687
688   ("is_ready", (RBool "ready", []), -1, [],
689    [InitNone, Always, TestOutputTrue (
690       [["is_ready"]])],
691    "is ready to accept commands",
692    "\
693 This returns true iff this handle is ready to accept commands
694 (in the C<READY> state).
695
696 For more information on states, see L<guestfs(3)>.");
697
698   ("is_config", (RBool "config", []), -1, [],
699    [InitNone, Always, TestOutputFalse (
700       [["is_config"]])],
701    "is in configuration state",
702    "\
703 This returns true iff this handle is being configured
704 (in the C<CONFIG> state).
705
706 For more information on states, see L<guestfs(3)>.");
707
708   ("is_launching", (RBool "launching", []), -1, [],
709    [InitNone, Always, TestOutputFalse (
710       [["is_launching"]])],
711    "is launching subprocess",
712    "\
713 This returns true iff this handle is launching the subprocess
714 (in the C<LAUNCHING> state).
715
716 For more information on states, see L<guestfs(3)>.");
717
718   ("is_busy", (RBool "busy", []), -1, [],
719    [InitNone, Always, TestOutputFalse (
720       [["is_busy"]])],
721    "is busy processing a command",
722    "\
723 This returns true iff this handle is busy processing a command
724 (in the C<BUSY> state).
725
726 For more information on states, see L<guestfs(3)>.");
727
728   ("get_state", (RInt "state", []), -1, [],
729    [],
730    "get the current state",
731    "\
732 This returns the current state as an opaque integer.  This is
733 only useful for printing debug and internal error messages.
734
735 For more information on states, see L<guestfs(3)>.");
736
737   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
738    [InitNone, Always, TestOutputInt (
739       [["set_memsize"; "500"];
740        ["get_memsize"]], 500)],
741    "set memory allocated to the qemu subprocess",
742    "\
743 This sets the memory size in megabytes allocated to the
744 qemu subprocess.  This only has any effect if called before
745 C<guestfs_launch>.
746
747 You can also change this by setting the environment
748 variable C<LIBGUESTFS_MEMSIZE> before the handle is
749 created.
750
751 For more information on the architecture of libguestfs,
752 see L<guestfs(3)>.");
753
754   ("get_memsize", (RInt "memsize", []), -1, [],
755    [InitNone, Always, TestOutputIntOp (
756       [["get_memsize"]], ">=", 256)],
757    "get memory allocated to the qemu subprocess",
758    "\
759 This gets the memory size in megabytes allocated to the
760 qemu subprocess.
761
762 If C<guestfs_set_memsize> was not called
763 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
764 then this returns the compiled-in default value for memsize.
765
766 For more information on the architecture of libguestfs,
767 see L<guestfs(3)>.");
768
769   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
770    [InitNone, Always, TestOutputIntOp (
771       [["get_pid"]], ">=", 1)],
772    "get PID of qemu subprocess",
773    "\
774 Return the process ID of the qemu subprocess.  If there is no
775 qemu subprocess, then this will return an error.
776
777 This is an internal call used for debugging and testing.");
778
779   ("version", (RStruct ("version", "version"), []), -1, [],
780    [InitNone, Always, TestOutputStruct (
781       [["version"]], [CompareWithInt ("major", 1)])],
782    "get the library version number",
783    "\
784 Return the libguestfs version number that the program is linked
785 against.
786
787 Note that because of dynamic linking this is not necessarily
788 the version of libguestfs that you compiled against.  You can
789 compile the program, and then at runtime dynamically link
790 against a completely different C<libguestfs.so> library.
791
792 This call was added in version C<1.0.58>.  In previous
793 versions of libguestfs there was no way to get the version
794 number.  From C code you can use ELF weak linking tricks to find out if
795 this symbol exists (if it doesn't, then it's an earlier version).
796
797 The call returns a structure with four elements.  The first
798 three (C<major>, C<minor> and C<release>) are numbers and
799 correspond to the usual version triplet.  The fourth element
800 (C<extra>) is a string and is normally empty, but may be
801 used for distro-specific information.
802
803 To construct the original version string:
804 C<$major.$minor.$release$extra>
805
806 I<Note:> Don't use this call to test for availability
807 of features.  Distro backports makes this unreliable.  Use
808 C<guestfs_available> instead.");
809
810   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
811    [InitNone, Always, TestOutputTrue (
812       [["set_selinux"; "true"];
813        ["get_selinux"]])],
814    "set SELinux enabled or disabled at appliance boot",
815    "\
816 This sets the selinux flag that is passed to the appliance
817 at boot time.  The default is C<selinux=0> (disabled).
818
819 Note that if SELinux is enabled, it is always in
820 Permissive mode (C<enforcing=0>).
821
822 For more information on the architecture of libguestfs,
823 see L<guestfs(3)>.");
824
825   ("get_selinux", (RBool "selinux", []), -1, [],
826    [],
827    "get SELinux enabled flag",
828    "\
829 This returns the current setting of the selinux flag which
830 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
831
832 For more information on the architecture of libguestfs,
833 see L<guestfs(3)>.");
834
835   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
836    [InitNone, Always, TestOutputFalse (
837       [["set_trace"; "false"];
838        ["get_trace"]])],
839    "enable or disable command traces",
840    "\
841 If the command trace flag is set to 1, then commands are
842 printed on stdout before they are executed in a format
843 which is very similar to the one used by guestfish.  In
844 other words, you can run a program with this enabled, and
845 you will get out a script which you can feed to guestfish
846 to perform the same set of actions.
847
848 If you want to trace C API calls into libguestfs (and
849 other libraries) then possibly a better way is to use
850 the external ltrace(1) command.
851
852 Command traces are disabled unless the environment variable
853 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
854
855   ("get_trace", (RBool "trace", []), -1, [],
856    [],
857    "get command trace enabled flag",
858    "\
859 Return the command trace flag.");
860
861   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
862    [InitNone, Always, TestOutputFalse (
863       [["set_direct"; "false"];
864        ["get_direct"]])],
865    "enable or disable direct appliance mode",
866    "\
867 If the direct appliance mode flag is enabled, then stdin and
868 stdout are passed directly through to the appliance once it
869 is launched.
870
871 One consequence of this is that log messages aren't caught
872 by the library and handled by C<guestfs_set_log_message_callback>,
873 but go straight to stdout.
874
875 You probably don't want to use this unless you know what you
876 are doing.
877
878 The default is disabled.");
879
880   ("get_direct", (RBool "direct", []), -1, [],
881    [],
882    "get direct appliance mode flag",
883    "\
884 Return the direct appliance mode flag.");
885
886   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
887    [InitNone, Always, TestOutputTrue (
888       [["set_recovery_proc"; "true"];
889        ["get_recovery_proc"]])],
890    "enable or disable the recovery process",
891    "\
892 If this is called with the parameter C<false> then
893 C<guestfs_launch> does not create a recovery process.  The
894 purpose of the recovery process is to stop runaway qemu
895 processes in the case where the main program aborts abruptly.
896
897 This only has any effect if called before C<guestfs_launch>,
898 and the default is true.
899
900 About the only time when you would want to disable this is
901 if the main process will fork itself into the background
902 (\"daemonize\" itself).  In this case the recovery process
903 thinks that the main program has disappeared and so kills
904 qemu, which is not very helpful.");
905
906   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
907    [],
908    "get recovery process enabled flag",
909    "\
910 Return the recovery process enabled flag.");
911
912   ("add_drive_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
913    [],
914    "add a drive specifying the QEMU block emulation to use",
915    "\
916 This is the same as C<guestfs_add_drive> but it allows you
917 to specify the QEMU interface emulation to use at run time.");
918
919   ("add_drive_ro_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
920    [],
921    "add a drive read-only specifying the QEMU block emulation to use",
922    "\
923 This is the same as C<guestfs_add_drive_ro> but it allows you
924 to specify the QEMU interface emulation to use at run time.");
925
926 ]
927
928 (* daemon_functions are any functions which cause some action
929  * to take place in the daemon.
930  *)
931
932 let daemon_functions = [
933   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
934    [InitEmpty, Always, TestOutput (
935       [["part_disk"; "/dev/sda"; "mbr"];
936        ["mkfs"; "ext2"; "/dev/sda1"];
937        ["mount"; "/dev/sda1"; "/"];
938        ["write_file"; "/new"; "new file contents"; "0"];
939        ["cat"; "/new"]], "new file contents")],
940    "mount a guest disk at a position in the filesystem",
941    "\
942 Mount a guest disk at a position in the filesystem.  Block devices
943 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
944 the guest.  If those block devices contain partitions, they will have
945 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
946 names can be used.
947
948 The rules are the same as for L<mount(2)>:  A filesystem must
949 first be mounted on C</> before others can be mounted.  Other
950 filesystems can only be mounted on directories which already
951 exist.
952
953 The mounted filesystem is writable, if we have sufficient permissions
954 on the underlying device.
955
956 The filesystem options C<sync> and C<noatime> are set with this
957 call, in order to improve reliability.");
958
959   ("sync", (RErr, []), 2, [],
960    [ InitEmpty, Always, TestRun [["sync"]]],
961    "sync disks, writes are flushed through to the disk image",
962    "\
963 This syncs the disk, so that any writes are flushed through to the
964 underlying disk image.
965
966 You should always call this if you have modified a disk image, before
967 closing the handle.");
968
969   ("touch", (RErr, [Pathname "path"]), 3, [],
970    [InitBasicFS, Always, TestOutputTrue (
971       [["touch"; "/new"];
972        ["exists"; "/new"]])],
973    "update file timestamps or create a new file",
974    "\
975 Touch acts like the L<touch(1)> command.  It can be used to
976 update the timestamps on a file, or, if the file does not exist,
977 to create a new zero-length file.");
978
979   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
980    [InitISOFS, Always, TestOutput (
981       [["cat"; "/known-2"]], "abcdef\n")],
982    "list the contents of a file",
983    "\
984 Return the contents of the file named C<path>.
985
986 Note that this function cannot correctly handle binary files
987 (specifically, files containing C<\\0> character which is treated
988 as end of string).  For those you need to use the C<guestfs_read_file>
989 or C<guestfs_download> functions which have a more complex interface.");
990
991   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
992    [], (* XXX Tricky to test because it depends on the exact format
993         * of the 'ls -l' command, which changes between F10 and F11.
994         *)
995    "list the files in a directory (long format)",
996    "\
997 List the files in C<directory> (relative to the root directory,
998 there is no cwd) in the format of 'ls -la'.
999
1000 This command is mostly useful for interactive sessions.  It
1001 is I<not> intended that you try to parse the output string.");
1002
1003   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
1004    [InitBasicFS, Always, TestOutputList (
1005       [["touch"; "/new"];
1006        ["touch"; "/newer"];
1007        ["touch"; "/newest"];
1008        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
1009    "list the files in a directory",
1010    "\
1011 List the files in C<directory> (relative to the root directory,
1012 there is no cwd).  The '.' and '..' entries are not returned, but
1013 hidden files are shown.
1014
1015 This command is mostly useful for interactive sessions.  Programs
1016 should probably use C<guestfs_readdir> instead.");
1017
1018   ("list_devices", (RStringList "devices", []), 7, [],
1019    [InitEmpty, Always, TestOutputListOfDevices (
1020       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
1021    "list the block devices",
1022    "\
1023 List all the block devices.
1024
1025 The full block device names are returned, eg. C</dev/sda>");
1026
1027   ("list_partitions", (RStringList "partitions", []), 8, [],
1028    [InitBasicFS, Always, TestOutputListOfDevices (
1029       [["list_partitions"]], ["/dev/sda1"]);
1030     InitEmpty, Always, TestOutputListOfDevices (
1031       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1032        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1033    "list the partitions",
1034    "\
1035 List all the partitions detected on all block devices.
1036
1037 The full partition device names are returned, eg. C</dev/sda1>
1038
1039 This does not return logical volumes.  For that you will need to
1040 call C<guestfs_lvs>.");
1041
1042   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
1043    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
1044       [["pvs"]], ["/dev/sda1"]);
1045     InitEmpty, Always, TestOutputListOfDevices (
1046       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1047        ["pvcreate"; "/dev/sda1"];
1048        ["pvcreate"; "/dev/sda2"];
1049        ["pvcreate"; "/dev/sda3"];
1050        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1051    "list the LVM physical volumes (PVs)",
1052    "\
1053 List all the physical volumes detected.  This is the equivalent
1054 of the L<pvs(8)> command.
1055
1056 This returns a list of just the device names that contain
1057 PVs (eg. C</dev/sda2>).
1058
1059 See also C<guestfs_pvs_full>.");
1060
1061   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1062    [InitBasicFSonLVM, Always, TestOutputList (
1063       [["vgs"]], ["VG"]);
1064     InitEmpty, Always, TestOutputList (
1065       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1066        ["pvcreate"; "/dev/sda1"];
1067        ["pvcreate"; "/dev/sda2"];
1068        ["pvcreate"; "/dev/sda3"];
1069        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1070        ["vgcreate"; "VG2"; "/dev/sda3"];
1071        ["vgs"]], ["VG1"; "VG2"])],
1072    "list the LVM volume groups (VGs)",
1073    "\
1074 List all the volumes groups detected.  This is the equivalent
1075 of the L<vgs(8)> command.
1076
1077 This returns a list of just the volume group names that were
1078 detected (eg. C<VolGroup00>).
1079
1080 See also C<guestfs_vgs_full>.");
1081
1082   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1083    [InitBasicFSonLVM, Always, TestOutputList (
1084       [["lvs"]], ["/dev/VG/LV"]);
1085     InitEmpty, Always, TestOutputList (
1086       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1087        ["pvcreate"; "/dev/sda1"];
1088        ["pvcreate"; "/dev/sda2"];
1089        ["pvcreate"; "/dev/sda3"];
1090        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1091        ["vgcreate"; "VG2"; "/dev/sda3"];
1092        ["lvcreate"; "LV1"; "VG1"; "50"];
1093        ["lvcreate"; "LV2"; "VG1"; "50"];
1094        ["lvcreate"; "LV3"; "VG2"; "50"];
1095        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1096    "list the LVM logical volumes (LVs)",
1097    "\
1098 List all the logical volumes detected.  This is the equivalent
1099 of the L<lvs(8)> command.
1100
1101 This returns a list of the logical volume device names
1102 (eg. C</dev/VolGroup00/LogVol00>).
1103
1104 See also C<guestfs_lvs_full>.");
1105
1106   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1107    [], (* XXX how to test? *)
1108    "list the LVM physical volumes (PVs)",
1109    "\
1110 List all the physical volumes detected.  This is the equivalent
1111 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1112
1113   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1114    [], (* XXX how to test? *)
1115    "list the LVM volume groups (VGs)",
1116    "\
1117 List all the volumes groups detected.  This is the equivalent
1118 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1119
1120   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1121    [], (* XXX how to test? *)
1122    "list the LVM logical volumes (LVs)",
1123    "\
1124 List all the logical volumes detected.  This is the equivalent
1125 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1126
1127   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1128    [InitISOFS, Always, TestOutputList (
1129       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1130     InitISOFS, Always, TestOutputList (
1131       [["read_lines"; "/empty"]], [])],
1132    "read file as lines",
1133    "\
1134 Return the contents of the file named C<path>.
1135
1136 The file contents are returned as a list of lines.  Trailing
1137 C<LF> and C<CRLF> character sequences are I<not> returned.
1138
1139 Note that this function cannot correctly handle binary files
1140 (specifically, files containing C<\\0> character which is treated
1141 as end of line).  For those you need to use the C<guestfs_read_file>
1142 function which has a more complex interface.");
1143
1144   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1145    [], (* XXX Augeas code needs tests. *)
1146    "create a new Augeas handle",
1147    "\
1148 Create a new Augeas handle for editing configuration files.
1149 If there was any previous Augeas handle associated with this
1150 guestfs session, then it is closed.
1151
1152 You must call this before using any other C<guestfs_aug_*>
1153 commands.
1154
1155 C<root> is the filesystem root.  C<root> must not be NULL,
1156 use C</> instead.
1157
1158 The flags are the same as the flags defined in
1159 E<lt>augeas.hE<gt>, the logical I<or> of the following
1160 integers:
1161
1162 =over 4
1163
1164 =item C<AUG_SAVE_BACKUP> = 1
1165
1166 Keep the original file with a C<.augsave> extension.
1167
1168 =item C<AUG_SAVE_NEWFILE> = 2
1169
1170 Save changes into a file with extension C<.augnew>, and
1171 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1172
1173 =item C<AUG_TYPE_CHECK> = 4
1174
1175 Typecheck lenses (can be expensive).
1176
1177 =item C<AUG_NO_STDINC> = 8
1178
1179 Do not use standard load path for modules.
1180
1181 =item C<AUG_SAVE_NOOP> = 16
1182
1183 Make save a no-op, just record what would have been changed.
1184
1185 =item C<AUG_NO_LOAD> = 32
1186
1187 Do not load the tree in C<guestfs_aug_init>.
1188
1189 =back
1190
1191 To close the handle, you can call C<guestfs_aug_close>.
1192
1193 To find out more about Augeas, see L<http://augeas.net/>.");
1194
1195   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1196    [], (* XXX Augeas code needs tests. *)
1197    "close the current Augeas handle",
1198    "\
1199 Close the current Augeas handle and free up any resources
1200 used by it.  After calling this, you have to call
1201 C<guestfs_aug_init> again before you can use any other
1202 Augeas functions.");
1203
1204   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1205    [], (* XXX Augeas code needs tests. *)
1206    "define an Augeas variable",
1207    "\
1208 Defines an Augeas variable C<name> whose value is the result
1209 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1210 undefined.
1211
1212 On success this returns the number of nodes in C<expr>, or
1213 C<0> if C<expr> evaluates to something which is not a nodeset.");
1214
1215   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1216    [], (* XXX Augeas code needs tests. *)
1217    "define an Augeas node",
1218    "\
1219 Defines a variable C<name> whose value is the result of
1220 evaluating C<expr>.
1221
1222 If C<expr> evaluates to an empty nodeset, a node is created,
1223 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1224 C<name> will be the nodeset containing that single node.
1225
1226 On success this returns a pair containing the
1227 number of nodes in the nodeset, and a boolean flag
1228 if a node was created.");
1229
1230   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1231    [], (* XXX Augeas code needs tests. *)
1232    "look up the value of an Augeas path",
1233    "\
1234 Look up the value associated with C<path>.  If C<path>
1235 matches exactly one node, the C<value> is returned.");
1236
1237   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1238    [], (* XXX Augeas code needs tests. *)
1239    "set Augeas path to value",
1240    "\
1241 Set the value associated with C<path> to C<value>.");
1242
1243   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1244    [], (* XXX Augeas code needs tests. *)
1245    "insert a sibling Augeas node",
1246    "\
1247 Create a new sibling C<label> for C<path>, inserting it into
1248 the tree before or after C<path> (depending on the boolean
1249 flag C<before>).
1250
1251 C<path> must match exactly one existing node in the tree, and
1252 C<label> must be a label, ie. not contain C</>, C<*> or end
1253 with a bracketed index C<[N]>.");
1254
1255   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1256    [], (* XXX Augeas code needs tests. *)
1257    "remove an Augeas path",
1258    "\
1259 Remove C<path> and all of its children.
1260
1261 On success this returns the number of entries which were removed.");
1262
1263   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1264    [], (* XXX Augeas code needs tests. *)
1265    "move Augeas node",
1266    "\
1267 Move the node C<src> to C<dest>.  C<src> must match exactly
1268 one node.  C<dest> is overwritten if it exists.");
1269
1270   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1271    [], (* XXX Augeas code needs tests. *)
1272    "return Augeas nodes which match augpath",
1273    "\
1274 Returns a list of paths which match the path expression C<path>.
1275 The returned paths are sufficiently qualified so that they match
1276 exactly one node in the current tree.");
1277
1278   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1279    [], (* XXX Augeas code needs tests. *)
1280    "write all pending Augeas changes to disk",
1281    "\
1282 This writes all pending changes to disk.
1283
1284 The flags which were passed to C<guestfs_aug_init> affect exactly
1285 how files are saved.");
1286
1287   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1288    [], (* XXX Augeas code needs tests. *)
1289    "load files into the tree",
1290    "\
1291 Load files into the tree.
1292
1293 See C<aug_load> in the Augeas documentation for the full gory
1294 details.");
1295
1296   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1297    [], (* XXX Augeas code needs tests. *)
1298    "list Augeas nodes under augpath",
1299    "\
1300 This is just a shortcut for listing C<guestfs_aug_match>
1301 C<path/*> and sorting the resulting nodes into alphabetical order.");
1302
1303   ("rm", (RErr, [Pathname "path"]), 29, [],
1304    [InitBasicFS, Always, TestRun
1305       [["touch"; "/new"];
1306        ["rm"; "/new"]];
1307     InitBasicFS, Always, TestLastFail
1308       [["rm"; "/new"]];
1309     InitBasicFS, Always, TestLastFail
1310       [["mkdir"; "/new"];
1311        ["rm"; "/new"]]],
1312    "remove a file",
1313    "\
1314 Remove the single file C<path>.");
1315
1316   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1317    [InitBasicFS, Always, TestRun
1318       [["mkdir"; "/new"];
1319        ["rmdir"; "/new"]];
1320     InitBasicFS, Always, TestLastFail
1321       [["rmdir"; "/new"]];
1322     InitBasicFS, Always, TestLastFail
1323       [["touch"; "/new"];
1324        ["rmdir"; "/new"]]],
1325    "remove a directory",
1326    "\
1327 Remove the single directory C<path>.");
1328
1329   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1330    [InitBasicFS, Always, TestOutputFalse
1331       [["mkdir"; "/new"];
1332        ["mkdir"; "/new/foo"];
1333        ["touch"; "/new/foo/bar"];
1334        ["rm_rf"; "/new"];
1335        ["exists"; "/new"]]],
1336    "remove a file or directory recursively",
1337    "\
1338 Remove the file or directory C<path>, recursively removing the
1339 contents if its a directory.  This is like the C<rm -rf> shell
1340 command.");
1341
1342   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1343    [InitBasicFS, Always, TestOutputTrue
1344       [["mkdir"; "/new"];
1345        ["is_dir"; "/new"]];
1346     InitBasicFS, Always, TestLastFail
1347       [["mkdir"; "/new/foo/bar"]]],
1348    "create a directory",
1349    "\
1350 Create a directory named C<path>.");
1351
1352   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1353    [InitBasicFS, Always, TestOutputTrue
1354       [["mkdir_p"; "/new/foo/bar"];
1355        ["is_dir"; "/new/foo/bar"]];
1356     InitBasicFS, Always, TestOutputTrue
1357       [["mkdir_p"; "/new/foo/bar"];
1358        ["is_dir"; "/new/foo"]];
1359     InitBasicFS, Always, TestOutputTrue
1360       [["mkdir_p"; "/new/foo/bar"];
1361        ["is_dir"; "/new"]];
1362     (* Regression tests for RHBZ#503133: *)
1363     InitBasicFS, Always, TestRun
1364       [["mkdir"; "/new"];
1365        ["mkdir_p"; "/new"]];
1366     InitBasicFS, Always, TestLastFail
1367       [["touch"; "/new"];
1368        ["mkdir_p"; "/new"]]],
1369    "create a directory and parents",
1370    "\
1371 Create a directory named C<path>, creating any parent directories
1372 as necessary.  This is like the C<mkdir -p> shell command.");
1373
1374   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1375    [], (* XXX Need stat command to test *)
1376    "change file mode",
1377    "\
1378 Change the mode (permissions) of C<path> to C<mode>.  Only
1379 numeric modes are supported.
1380
1381 I<Note>: When using this command from guestfish, C<mode>
1382 by default would be decimal, unless you prefix it with
1383 C<0> to get octal, ie. use C<0700> not C<700>.");
1384
1385   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1386    [], (* XXX Need stat command to test *)
1387    "change file owner and group",
1388    "\
1389 Change the file owner to C<owner> and group to C<group>.
1390
1391 Only numeric uid and gid are supported.  If you want to use
1392 names, you will need to locate and parse the password file
1393 yourself (Augeas support makes this relatively easy).");
1394
1395   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1396    [InitISOFS, Always, TestOutputTrue (
1397       [["exists"; "/empty"]]);
1398     InitISOFS, Always, TestOutputTrue (
1399       [["exists"; "/directory"]])],
1400    "test if file or directory exists",
1401    "\
1402 This returns C<true> if and only if there is a file, directory
1403 (or anything) with the given C<path> name.
1404
1405 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1406
1407   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1408    [InitISOFS, Always, TestOutputTrue (
1409       [["is_file"; "/known-1"]]);
1410     InitISOFS, Always, TestOutputFalse (
1411       [["is_file"; "/directory"]])],
1412    "test if file exists",
1413    "\
1414 This returns C<true> if and only if there is a file
1415 with the given C<path> name.  Note that it returns false for
1416 other objects like directories.
1417
1418 See also C<guestfs_stat>.");
1419
1420   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1421    [InitISOFS, Always, TestOutputFalse (
1422       [["is_dir"; "/known-3"]]);
1423     InitISOFS, Always, TestOutputTrue (
1424       [["is_dir"; "/directory"]])],
1425    "test if file exists",
1426    "\
1427 This returns C<true> if and only if there is a directory
1428 with the given C<path> name.  Note that it returns false for
1429 other objects like files.
1430
1431 See also C<guestfs_stat>.");
1432
1433   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1434    [InitEmpty, Always, TestOutputListOfDevices (
1435       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1436        ["pvcreate"; "/dev/sda1"];
1437        ["pvcreate"; "/dev/sda2"];
1438        ["pvcreate"; "/dev/sda3"];
1439        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1440    "create an LVM physical volume",
1441    "\
1442 This creates an LVM physical volume on the named C<device>,
1443 where C<device> should usually be a partition name such
1444 as C</dev/sda1>.");
1445
1446   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1447    [InitEmpty, Always, TestOutputList (
1448       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1449        ["pvcreate"; "/dev/sda1"];
1450        ["pvcreate"; "/dev/sda2"];
1451        ["pvcreate"; "/dev/sda3"];
1452        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1453        ["vgcreate"; "VG2"; "/dev/sda3"];
1454        ["vgs"]], ["VG1"; "VG2"])],
1455    "create an LVM volume group",
1456    "\
1457 This creates an LVM volume group called C<volgroup>
1458 from the non-empty list of physical volumes C<physvols>.");
1459
1460   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1461    [InitEmpty, Always, TestOutputList (
1462       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1463        ["pvcreate"; "/dev/sda1"];
1464        ["pvcreate"; "/dev/sda2"];
1465        ["pvcreate"; "/dev/sda3"];
1466        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1467        ["vgcreate"; "VG2"; "/dev/sda3"];
1468        ["lvcreate"; "LV1"; "VG1"; "50"];
1469        ["lvcreate"; "LV2"; "VG1"; "50"];
1470        ["lvcreate"; "LV3"; "VG2"; "50"];
1471        ["lvcreate"; "LV4"; "VG2"; "50"];
1472        ["lvcreate"; "LV5"; "VG2"; "50"];
1473        ["lvs"]],
1474       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1475        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1476    "create an LVM volume group",
1477    "\
1478 This creates an LVM volume group called C<logvol>
1479 on the volume group C<volgroup>, with C<size> megabytes.");
1480
1481   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1482    [InitEmpty, Always, TestOutput (
1483       [["part_disk"; "/dev/sda"; "mbr"];
1484        ["mkfs"; "ext2"; "/dev/sda1"];
1485        ["mount_options"; ""; "/dev/sda1"; "/"];
1486        ["write_file"; "/new"; "new file contents"; "0"];
1487        ["cat"; "/new"]], "new file contents")],
1488    "make a filesystem",
1489    "\
1490 This creates a filesystem on C<device> (usually a partition
1491 or LVM logical volume).  The filesystem type is C<fstype>, for
1492 example C<ext3>.");
1493
1494   ("sfdisk", (RErr, [Device "device";
1495                      Int "cyls"; Int "heads"; Int "sectors";
1496                      StringList "lines"]), 43, [DangerWillRobinson],
1497    [],
1498    "create partitions on a block device",
1499    "\
1500 This is a direct interface to the L<sfdisk(8)> program for creating
1501 partitions on block devices.
1502
1503 C<device> should be a block device, for example C</dev/sda>.
1504
1505 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1506 and sectors on the device, which are passed directly to sfdisk as
1507 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1508 of these, then the corresponding parameter is omitted.  Usually for
1509 'large' disks, you can just pass C<0> for these, but for small
1510 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1511 out the right geometry and you will need to tell it.
1512
1513 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1514 information refer to the L<sfdisk(8)> manpage.
1515
1516 To create a single partition occupying the whole disk, you would
1517 pass C<lines> as a single element list, when the single element being
1518 the string C<,> (comma).
1519
1520 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1521 C<guestfs_part_init>");
1522
1523   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1524    [InitBasicFS, Always, TestOutput (
1525       [["write_file"; "/new"; "new file contents"; "0"];
1526        ["cat"; "/new"]], "new file contents");
1527     InitBasicFS, Always, TestOutput (
1528       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1529        ["cat"; "/new"]], "\nnew file contents\n");
1530     InitBasicFS, Always, TestOutput (
1531       [["write_file"; "/new"; "\n\n"; "0"];
1532        ["cat"; "/new"]], "\n\n");
1533     InitBasicFS, Always, TestOutput (
1534       [["write_file"; "/new"; ""; "0"];
1535        ["cat"; "/new"]], "");
1536     InitBasicFS, Always, TestOutput (
1537       [["write_file"; "/new"; "\n\n\n"; "0"];
1538        ["cat"; "/new"]], "\n\n\n");
1539     InitBasicFS, Always, TestOutput (
1540       [["write_file"; "/new"; "\n"; "0"];
1541        ["cat"; "/new"]], "\n")],
1542    "create a file",
1543    "\
1544 This call creates a file called C<path>.  The contents of the
1545 file is the string C<content> (which can contain any 8 bit data),
1546 with length C<size>.
1547
1548 As a special case, if C<size> is C<0>
1549 then the length is calculated using C<strlen> (so in this case
1550 the content cannot contain embedded ASCII NULs).
1551
1552 I<NB.> Owing to a bug, writing content containing ASCII NUL
1553 characters does I<not> work, even if the length is specified.
1554 We hope to resolve this bug in a future version.  In the meantime
1555 use C<guestfs_upload>.");
1556
1557   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1558    [InitEmpty, Always, TestOutputListOfDevices (
1559       [["part_disk"; "/dev/sda"; "mbr"];
1560        ["mkfs"; "ext2"; "/dev/sda1"];
1561        ["mount_options"; ""; "/dev/sda1"; "/"];
1562        ["mounts"]], ["/dev/sda1"]);
1563     InitEmpty, Always, TestOutputList (
1564       [["part_disk"; "/dev/sda"; "mbr"];
1565        ["mkfs"; "ext2"; "/dev/sda1"];
1566        ["mount_options"; ""; "/dev/sda1"; "/"];
1567        ["umount"; "/"];
1568        ["mounts"]], [])],
1569    "unmount a filesystem",
1570    "\
1571 This unmounts the given filesystem.  The filesystem may be
1572 specified either by its mountpoint (path) or the device which
1573 contains the filesystem.");
1574
1575   ("mounts", (RStringList "devices", []), 46, [],
1576    [InitBasicFS, Always, TestOutputListOfDevices (
1577       [["mounts"]], ["/dev/sda1"])],
1578    "show mounted filesystems",
1579    "\
1580 This returns the list of currently mounted filesystems.  It returns
1581 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1582
1583 Some internal mounts are not shown.
1584
1585 See also: C<guestfs_mountpoints>");
1586
1587   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1588    [InitBasicFS, Always, TestOutputList (
1589       [["umount_all"];
1590        ["mounts"]], []);
1591     (* check that umount_all can unmount nested mounts correctly: *)
1592     InitEmpty, Always, TestOutputList (
1593       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1594        ["mkfs"; "ext2"; "/dev/sda1"];
1595        ["mkfs"; "ext2"; "/dev/sda2"];
1596        ["mkfs"; "ext2"; "/dev/sda3"];
1597        ["mount_options"; ""; "/dev/sda1"; "/"];
1598        ["mkdir"; "/mp1"];
1599        ["mount_options"; ""; "/dev/sda2"; "/mp1"];
1600        ["mkdir"; "/mp1/mp2"];
1601        ["mount_options"; ""; "/dev/sda3"; "/mp1/mp2"];
1602        ["mkdir"; "/mp1/mp2/mp3"];
1603        ["umount_all"];
1604        ["mounts"]], [])],
1605    "unmount all filesystems",
1606    "\
1607 This unmounts all mounted filesystems.
1608
1609 Some internal mounts are not unmounted by this call.");
1610
1611   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1612    [],
1613    "remove all LVM LVs, VGs and PVs",
1614    "\
1615 This command removes all LVM logical volumes, volume groups
1616 and physical volumes.");
1617
1618   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1619    [InitISOFS, Always, TestOutput (
1620       [["file"; "/empty"]], "empty");
1621     InitISOFS, Always, TestOutput (
1622       [["file"; "/known-1"]], "ASCII text");
1623     InitISOFS, Always, TestLastFail (
1624       [["file"; "/notexists"]])],
1625    "determine file type",
1626    "\
1627 This call uses the standard L<file(1)> command to determine
1628 the type or contents of the file.  This also works on devices,
1629 for example to find out whether a partition contains a filesystem.
1630
1631 This call will also transparently look inside various types
1632 of compressed file.
1633
1634 The exact command which runs is C<file -zbsL path>.  Note in
1635 particular that the filename is not prepended to the output
1636 (the C<-b> option).");
1637
1638   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1639    [InitBasicFS, Always, TestOutput (
1640       [["upload"; "test-command"; "/test-command"];
1641        ["chmod"; "0o755"; "/test-command"];
1642        ["command"; "/test-command 1"]], "Result1");
1643     InitBasicFS, Always, TestOutput (
1644       [["upload"; "test-command"; "/test-command"];
1645        ["chmod"; "0o755"; "/test-command"];
1646        ["command"; "/test-command 2"]], "Result2\n");
1647     InitBasicFS, Always, TestOutput (
1648       [["upload"; "test-command"; "/test-command"];
1649        ["chmod"; "0o755"; "/test-command"];
1650        ["command"; "/test-command 3"]], "\nResult3");
1651     InitBasicFS, Always, TestOutput (
1652       [["upload"; "test-command"; "/test-command"];
1653        ["chmod"; "0o755"; "/test-command"];
1654        ["command"; "/test-command 4"]], "\nResult4\n");
1655     InitBasicFS, Always, TestOutput (
1656       [["upload"; "test-command"; "/test-command"];
1657        ["chmod"; "0o755"; "/test-command"];
1658        ["command"; "/test-command 5"]], "\nResult5\n\n");
1659     InitBasicFS, Always, TestOutput (
1660       [["upload"; "test-command"; "/test-command"];
1661        ["chmod"; "0o755"; "/test-command"];
1662        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1663     InitBasicFS, Always, TestOutput (
1664       [["upload"; "test-command"; "/test-command"];
1665        ["chmod"; "0o755"; "/test-command"];
1666        ["command"; "/test-command 7"]], "");
1667     InitBasicFS, Always, TestOutput (
1668       [["upload"; "test-command"; "/test-command"];
1669        ["chmod"; "0o755"; "/test-command"];
1670        ["command"; "/test-command 8"]], "\n");
1671     InitBasicFS, Always, TestOutput (
1672       [["upload"; "test-command"; "/test-command"];
1673        ["chmod"; "0o755"; "/test-command"];
1674        ["command"; "/test-command 9"]], "\n\n");
1675     InitBasicFS, Always, TestOutput (
1676       [["upload"; "test-command"; "/test-command"];
1677        ["chmod"; "0o755"; "/test-command"];
1678        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1679     InitBasicFS, Always, TestOutput (
1680       [["upload"; "test-command"; "/test-command"];
1681        ["chmod"; "0o755"; "/test-command"];
1682        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1683     InitBasicFS, Always, TestLastFail (
1684       [["upload"; "test-command"; "/test-command"];
1685        ["chmod"; "0o755"; "/test-command"];
1686        ["command"; "/test-command"]])],
1687    "run a command from the guest filesystem",
1688    "\
1689 This call runs a command from the guest filesystem.  The
1690 filesystem must be mounted, and must contain a compatible
1691 operating system (ie. something Linux, with the same
1692 or compatible processor architecture).
1693
1694 The single parameter is an argv-style list of arguments.
1695 The first element is the name of the program to run.
1696 Subsequent elements are parameters.  The list must be
1697 non-empty (ie. must contain a program name).  Note that
1698 the command runs directly, and is I<not> invoked via
1699 the shell (see C<guestfs_sh>).
1700
1701 The return value is anything printed to I<stdout> by
1702 the command.
1703
1704 If the command returns a non-zero exit status, then
1705 this function returns an error message.  The error message
1706 string is the content of I<stderr> from the command.
1707
1708 The C<$PATH> environment variable will contain at least
1709 C</usr/bin> and C</bin>.  If you require a program from
1710 another location, you should provide the full path in the
1711 first parameter.
1712
1713 Shared libraries and data files required by the program
1714 must be available on filesystems which are mounted in the
1715 correct places.  It is the caller's responsibility to ensure
1716 all filesystems that are needed are mounted at the right
1717 locations.");
1718
1719   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1720    [InitBasicFS, Always, TestOutputList (
1721       [["upload"; "test-command"; "/test-command"];
1722        ["chmod"; "0o755"; "/test-command"];
1723        ["command_lines"; "/test-command 1"]], ["Result1"]);
1724     InitBasicFS, Always, TestOutputList (
1725       [["upload"; "test-command"; "/test-command"];
1726        ["chmod"; "0o755"; "/test-command"];
1727        ["command_lines"; "/test-command 2"]], ["Result2"]);
1728     InitBasicFS, Always, TestOutputList (
1729       [["upload"; "test-command"; "/test-command"];
1730        ["chmod"; "0o755"; "/test-command"];
1731        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1732     InitBasicFS, Always, TestOutputList (
1733       [["upload"; "test-command"; "/test-command"];
1734        ["chmod"; "0o755"; "/test-command"];
1735        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1736     InitBasicFS, Always, TestOutputList (
1737       [["upload"; "test-command"; "/test-command"];
1738        ["chmod"; "0o755"; "/test-command"];
1739        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1740     InitBasicFS, Always, TestOutputList (
1741       [["upload"; "test-command"; "/test-command"];
1742        ["chmod"; "0o755"; "/test-command"];
1743        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1744     InitBasicFS, Always, TestOutputList (
1745       [["upload"; "test-command"; "/test-command"];
1746        ["chmod"; "0o755"; "/test-command"];
1747        ["command_lines"; "/test-command 7"]], []);
1748     InitBasicFS, Always, TestOutputList (
1749       [["upload"; "test-command"; "/test-command"];
1750        ["chmod"; "0o755"; "/test-command"];
1751        ["command_lines"; "/test-command 8"]], [""]);
1752     InitBasicFS, Always, TestOutputList (
1753       [["upload"; "test-command"; "/test-command"];
1754        ["chmod"; "0o755"; "/test-command"];
1755        ["command_lines"; "/test-command 9"]], ["";""]);
1756     InitBasicFS, Always, TestOutputList (
1757       [["upload"; "test-command"; "/test-command"];
1758        ["chmod"; "0o755"; "/test-command"];
1759        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1760     InitBasicFS, Always, TestOutputList (
1761       [["upload"; "test-command"; "/test-command"];
1762        ["chmod"; "0o755"; "/test-command"];
1763        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1764    "run a command, returning lines",
1765    "\
1766 This is the same as C<guestfs_command>, but splits the
1767 result into a list of lines.
1768
1769 See also: C<guestfs_sh_lines>");
1770
1771   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1772    [InitISOFS, Always, TestOutputStruct (
1773       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1774    "get file information",
1775    "\
1776 Returns file information for the given C<path>.
1777
1778 This is the same as the C<stat(2)> system call.");
1779
1780   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1781    [InitISOFS, Always, TestOutputStruct (
1782       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1783    "get file information for a symbolic link",
1784    "\
1785 Returns file information for the given C<path>.
1786
1787 This is the same as C<guestfs_stat> except that if C<path>
1788 is a symbolic link, then the link is stat-ed, not the file it
1789 refers to.
1790
1791 This is the same as the C<lstat(2)> system call.");
1792
1793   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1794    [InitISOFS, Always, TestOutputStruct (
1795       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1796    "get file system statistics",
1797    "\
1798 Returns file system statistics for any mounted file system.
1799 C<path> should be a file or directory in the mounted file system
1800 (typically it is the mount point itself, but it doesn't need to be).
1801
1802 This is the same as the C<statvfs(2)> system call.");
1803
1804   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1805    [], (* XXX test *)
1806    "get ext2/ext3/ext4 superblock details",
1807    "\
1808 This returns the contents of the ext2, ext3 or ext4 filesystem
1809 superblock on C<device>.
1810
1811 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1812 manpage for more details.  The list of fields returned isn't
1813 clearly defined, and depends on both the version of C<tune2fs>
1814 that libguestfs was built against, and the filesystem itself.");
1815
1816   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1817    [InitEmpty, Always, TestOutputTrue (
1818       [["blockdev_setro"; "/dev/sda"];
1819        ["blockdev_getro"; "/dev/sda"]])],
1820    "set block device to read-only",
1821    "\
1822 Sets the block device named C<device> to read-only.
1823
1824 This uses the L<blockdev(8)> command.");
1825
1826   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1827    [InitEmpty, Always, TestOutputFalse (
1828       [["blockdev_setrw"; "/dev/sda"];
1829        ["blockdev_getro"; "/dev/sda"]])],
1830    "set block device to read-write",
1831    "\
1832 Sets the block device named C<device> to read-write.
1833
1834 This uses the L<blockdev(8)> command.");
1835
1836   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1837    [InitEmpty, Always, TestOutputTrue (
1838       [["blockdev_setro"; "/dev/sda"];
1839        ["blockdev_getro"; "/dev/sda"]])],
1840    "is block device set to read-only",
1841    "\
1842 Returns a boolean indicating if the block device is read-only
1843 (true if read-only, false if not).
1844
1845 This uses the L<blockdev(8)> command.");
1846
1847   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1848    [InitEmpty, Always, TestOutputInt (
1849       [["blockdev_getss"; "/dev/sda"]], 512)],
1850    "get sectorsize of block device",
1851    "\
1852 This returns the size of sectors on a block device.
1853 Usually 512, but can be larger for modern devices.
1854
1855 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1856 for that).
1857
1858 This uses the L<blockdev(8)> command.");
1859
1860   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1861    [InitEmpty, Always, TestOutputInt (
1862       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1863    "get blocksize of block device",
1864    "\
1865 This returns the block size of a device.
1866
1867 (Note this is different from both I<size in blocks> and
1868 I<filesystem block size>).
1869
1870 This uses the L<blockdev(8)> command.");
1871
1872   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1873    [], (* XXX test *)
1874    "set blocksize of block device",
1875    "\
1876 This sets the block size of a device.
1877
1878 (Note this is different from both I<size in blocks> and
1879 I<filesystem block size>).
1880
1881 This uses the L<blockdev(8)> command.");
1882
1883   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1884    [InitEmpty, Always, TestOutputInt (
1885       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1886    "get total size of device in 512-byte sectors",
1887    "\
1888 This returns the size of the device in units of 512-byte sectors
1889 (even if the sectorsize isn't 512 bytes ... weird).
1890
1891 See also C<guestfs_blockdev_getss> for the real sector size of
1892 the device, and C<guestfs_blockdev_getsize64> for the more
1893 useful I<size in bytes>.
1894
1895 This uses the L<blockdev(8)> command.");
1896
1897   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1898    [InitEmpty, Always, TestOutputInt (
1899       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1900    "get total size of device in bytes",
1901    "\
1902 This returns the size of the device in bytes.
1903
1904 See also C<guestfs_blockdev_getsz>.
1905
1906 This uses the L<blockdev(8)> command.");
1907
1908   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1909    [InitEmpty, Always, TestRun
1910       [["blockdev_flushbufs"; "/dev/sda"]]],
1911    "flush device buffers",
1912    "\
1913 This tells the kernel to flush internal buffers associated
1914 with C<device>.
1915
1916 This uses the L<blockdev(8)> command.");
1917
1918   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1919    [InitEmpty, Always, TestRun
1920       [["blockdev_rereadpt"; "/dev/sda"]]],
1921    "reread partition table",
1922    "\
1923 Reread the partition table on C<device>.
1924
1925 This uses the L<blockdev(8)> command.");
1926
1927   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1928    [InitBasicFS, Always, TestOutput (
1929       (* Pick a file from cwd which isn't likely to change. *)
1930       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1931        ["checksum"; "md5"; "/COPYING.LIB"]],
1932       Digest.to_hex (Digest.file "COPYING.LIB"))],
1933    "upload a file from the local machine",
1934    "\
1935 Upload local file C<filename> to C<remotefilename> on the
1936 filesystem.
1937
1938 C<filename> can also be a named pipe.
1939
1940 See also C<guestfs_download>.");
1941
1942   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1943    [InitBasicFS, Always, TestOutput (
1944       (* Pick a file from cwd which isn't likely to change. *)
1945       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1946        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1947        ["upload"; "testdownload.tmp"; "/upload"];
1948        ["checksum"; "md5"; "/upload"]],
1949       Digest.to_hex (Digest.file "COPYING.LIB"))],
1950    "download a file to the local machine",
1951    "\
1952 Download file C<remotefilename> and save it as C<filename>
1953 on the local machine.
1954
1955 C<filename> can also be a named pipe.
1956
1957 See also C<guestfs_upload>, C<guestfs_cat>.");
1958
1959   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1960    [InitISOFS, Always, TestOutput (
1961       [["checksum"; "crc"; "/known-3"]], "2891671662");
1962     InitISOFS, Always, TestLastFail (
1963       [["checksum"; "crc"; "/notexists"]]);
1964     InitISOFS, Always, TestOutput (
1965       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1966     InitISOFS, Always, TestOutput (
1967       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1968     InitISOFS, Always, TestOutput (
1969       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1970     InitISOFS, Always, TestOutput (
1971       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1972     InitISOFS, Always, TestOutput (
1973       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1974     InitISOFS, Always, TestOutput (
1975       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1976    "compute MD5, SHAx or CRC checksum of file",
1977    "\
1978 This call computes the MD5, SHAx or CRC checksum of the
1979 file named C<path>.
1980
1981 The type of checksum to compute is given by the C<csumtype>
1982 parameter which must have one of the following values:
1983
1984 =over 4
1985
1986 =item C<crc>
1987
1988 Compute the cyclic redundancy check (CRC) specified by POSIX
1989 for the C<cksum> command.
1990
1991 =item C<md5>
1992
1993 Compute the MD5 hash (using the C<md5sum> program).
1994
1995 =item C<sha1>
1996
1997 Compute the SHA1 hash (using the C<sha1sum> program).
1998
1999 =item C<sha224>
2000
2001 Compute the SHA224 hash (using the C<sha224sum> program).
2002
2003 =item C<sha256>
2004
2005 Compute the SHA256 hash (using the C<sha256sum> program).
2006
2007 =item C<sha384>
2008
2009 Compute the SHA384 hash (using the C<sha384sum> program).
2010
2011 =item C<sha512>
2012
2013 Compute the SHA512 hash (using the C<sha512sum> program).
2014
2015 =back
2016
2017 The checksum is returned as a printable string.");
2018
2019   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
2020    [InitBasicFS, Always, TestOutput (
2021       [["tar_in"; "../images/helloworld.tar"; "/"];
2022        ["cat"; "/hello"]], "hello\n")],
2023    "unpack tarfile to directory",
2024    "\
2025 This command uploads and unpacks local file C<tarfile> (an
2026 I<uncompressed> tar file) into C<directory>.
2027
2028 To upload a compressed tarball, use C<guestfs_tgz_in>.");
2029
2030   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
2031    [],
2032    "pack directory into tarfile",
2033    "\
2034 This command packs the contents of C<directory> and downloads
2035 it to local file C<tarfile>.
2036
2037 To download a compressed tarball, use C<guestfs_tgz_out>.");
2038
2039   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
2040    [InitBasicFS, Always, TestOutput (
2041       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
2042        ["cat"; "/hello"]], "hello\n")],
2043    "unpack compressed tarball to directory",
2044    "\
2045 This command uploads and unpacks local file C<tarball> (a
2046 I<gzip compressed> tar file) into C<directory>.
2047
2048 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
2049
2050   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
2051    [],
2052    "pack directory into compressed tarball",
2053    "\
2054 This command packs the contents of C<directory> and downloads
2055 it to local file C<tarball>.
2056
2057 To download an uncompressed tarball, use C<guestfs_tar_out>.");
2058
2059   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
2060    [InitBasicFS, Always, TestLastFail (
2061       [["umount"; "/"];
2062        ["mount_ro"; "/dev/sda1"; "/"];
2063        ["touch"; "/new"]]);
2064     InitBasicFS, Always, TestOutput (
2065       [["write_file"; "/new"; "data"; "0"];
2066        ["umount"; "/"];
2067        ["mount_ro"; "/dev/sda1"; "/"];
2068        ["cat"; "/new"]], "data")],
2069    "mount a guest disk, read-only",
2070    "\
2071 This is the same as the C<guestfs_mount> command, but it
2072 mounts the filesystem with the read-only (I<-o ro>) flag.");
2073
2074   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
2075    [],
2076    "mount a guest disk with mount options",
2077    "\
2078 This is the same as the C<guestfs_mount> command, but it
2079 allows you to set the mount options as for the
2080 L<mount(8)> I<-o> flag.");
2081
2082   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2083    [],
2084    "mount a guest disk with mount options and vfstype",
2085    "\
2086 This is the same as the C<guestfs_mount> command, but it
2087 allows you to set both the mount options and the vfstype
2088 as for the L<mount(8)> I<-o> and I<-t> flags.");
2089
2090   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2091    [],
2092    "debugging and internals",
2093    "\
2094 The C<guestfs_debug> command exposes some internals of
2095 C<guestfsd> (the guestfs daemon) that runs inside the
2096 qemu subprocess.
2097
2098 There is no comprehensive help for this command.  You have
2099 to look at the file C<daemon/debug.c> in the libguestfs source
2100 to find out what you can do.");
2101
2102   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2103    [InitEmpty, Always, TestOutputList (
2104       [["part_disk"; "/dev/sda"; "mbr"];
2105        ["pvcreate"; "/dev/sda1"];
2106        ["vgcreate"; "VG"; "/dev/sda1"];
2107        ["lvcreate"; "LV1"; "VG"; "50"];
2108        ["lvcreate"; "LV2"; "VG"; "50"];
2109        ["lvremove"; "/dev/VG/LV1"];
2110        ["lvs"]], ["/dev/VG/LV2"]);
2111     InitEmpty, Always, TestOutputList (
2112       [["part_disk"; "/dev/sda"; "mbr"];
2113        ["pvcreate"; "/dev/sda1"];
2114        ["vgcreate"; "VG"; "/dev/sda1"];
2115        ["lvcreate"; "LV1"; "VG"; "50"];
2116        ["lvcreate"; "LV2"; "VG"; "50"];
2117        ["lvremove"; "/dev/VG"];
2118        ["lvs"]], []);
2119     InitEmpty, Always, TestOutputList (
2120       [["part_disk"; "/dev/sda"; "mbr"];
2121        ["pvcreate"; "/dev/sda1"];
2122        ["vgcreate"; "VG"; "/dev/sda1"];
2123        ["lvcreate"; "LV1"; "VG"; "50"];
2124        ["lvcreate"; "LV2"; "VG"; "50"];
2125        ["lvremove"; "/dev/VG"];
2126        ["vgs"]], ["VG"])],
2127    "remove an LVM logical volume",
2128    "\
2129 Remove an LVM logical volume C<device>, where C<device> is
2130 the path to the LV, such as C</dev/VG/LV>.
2131
2132 You can also remove all LVs in a volume group by specifying
2133 the VG name, C</dev/VG>.");
2134
2135   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2136    [InitEmpty, Always, TestOutputList (
2137       [["part_disk"; "/dev/sda"; "mbr"];
2138        ["pvcreate"; "/dev/sda1"];
2139        ["vgcreate"; "VG"; "/dev/sda1"];
2140        ["lvcreate"; "LV1"; "VG"; "50"];
2141        ["lvcreate"; "LV2"; "VG"; "50"];
2142        ["vgremove"; "VG"];
2143        ["lvs"]], []);
2144     InitEmpty, Always, TestOutputList (
2145       [["part_disk"; "/dev/sda"; "mbr"];
2146        ["pvcreate"; "/dev/sda1"];
2147        ["vgcreate"; "VG"; "/dev/sda1"];
2148        ["lvcreate"; "LV1"; "VG"; "50"];
2149        ["lvcreate"; "LV2"; "VG"; "50"];
2150        ["vgremove"; "VG"];
2151        ["vgs"]], [])],
2152    "remove an LVM volume group",
2153    "\
2154 Remove an LVM volume group C<vgname>, (for example C<VG>).
2155
2156 This also forcibly removes all logical volumes in the volume
2157 group (if any).");
2158
2159   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2160    [InitEmpty, Always, TestOutputListOfDevices (
2161       [["part_disk"; "/dev/sda"; "mbr"];
2162        ["pvcreate"; "/dev/sda1"];
2163        ["vgcreate"; "VG"; "/dev/sda1"];
2164        ["lvcreate"; "LV1"; "VG"; "50"];
2165        ["lvcreate"; "LV2"; "VG"; "50"];
2166        ["vgremove"; "VG"];
2167        ["pvremove"; "/dev/sda1"];
2168        ["lvs"]], []);
2169     InitEmpty, Always, TestOutputListOfDevices (
2170       [["part_disk"; "/dev/sda"; "mbr"];
2171        ["pvcreate"; "/dev/sda1"];
2172        ["vgcreate"; "VG"; "/dev/sda1"];
2173        ["lvcreate"; "LV1"; "VG"; "50"];
2174        ["lvcreate"; "LV2"; "VG"; "50"];
2175        ["vgremove"; "VG"];
2176        ["pvremove"; "/dev/sda1"];
2177        ["vgs"]], []);
2178     InitEmpty, Always, TestOutputListOfDevices (
2179       [["part_disk"; "/dev/sda"; "mbr"];
2180        ["pvcreate"; "/dev/sda1"];
2181        ["vgcreate"; "VG"; "/dev/sda1"];
2182        ["lvcreate"; "LV1"; "VG"; "50"];
2183        ["lvcreate"; "LV2"; "VG"; "50"];
2184        ["vgremove"; "VG"];
2185        ["pvremove"; "/dev/sda1"];
2186        ["pvs"]], [])],
2187    "remove an LVM physical volume",
2188    "\
2189 This wipes a physical volume C<device> so that LVM will no longer
2190 recognise it.
2191
2192 The implementation uses the C<pvremove> command which refuses to
2193 wipe physical volumes that contain any volume groups, so you have
2194 to remove those first.");
2195
2196   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2197    [InitBasicFS, Always, TestOutput (
2198       [["set_e2label"; "/dev/sda1"; "testlabel"];
2199        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2200    "set the ext2/3/4 filesystem label",
2201    "\
2202 This sets the ext2/3/4 filesystem label of the filesystem on
2203 C<device> to C<label>.  Filesystem labels are limited to
2204 16 characters.
2205
2206 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2207 to return the existing label on a filesystem.");
2208
2209   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2210    [],
2211    "get the ext2/3/4 filesystem label",
2212    "\
2213 This returns the ext2/3/4 filesystem label of the filesystem on
2214 C<device>.");
2215
2216   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2217    (let uuid = uuidgen () in
2218     [InitBasicFS, Always, TestOutput (
2219        [["set_e2uuid"; "/dev/sda1"; uuid];
2220         ["get_e2uuid"; "/dev/sda1"]], uuid);
2221      InitBasicFS, Always, TestOutput (
2222        [["set_e2uuid"; "/dev/sda1"; "clear"];
2223         ["get_e2uuid"; "/dev/sda1"]], "");
2224      (* We can't predict what UUIDs will be, so just check the commands run. *)
2225      InitBasicFS, Always, TestRun (
2226        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2227      InitBasicFS, Always, TestRun (
2228        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2229    "set the ext2/3/4 filesystem UUID",
2230    "\
2231 This sets the ext2/3/4 filesystem UUID of the filesystem on
2232 C<device> to C<uuid>.  The format of the UUID and alternatives
2233 such as C<clear>, C<random> and C<time> are described in the
2234 L<tune2fs(8)> manpage.
2235
2236 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2237 to return the existing UUID of a filesystem.");
2238
2239   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2240    [],
2241    "get the ext2/3/4 filesystem UUID",
2242    "\
2243 This returns the ext2/3/4 filesystem UUID of the filesystem on
2244 C<device>.");
2245
2246   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [],
2247    [InitBasicFS, Always, TestOutputInt (
2248       [["umount"; "/dev/sda1"];
2249        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2250     InitBasicFS, Always, TestOutputInt (
2251       [["umount"; "/dev/sda1"];
2252        ["zero"; "/dev/sda1"];
2253        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2254    "run the filesystem checker",
2255    "\
2256 This runs the filesystem checker (fsck) on C<device> which
2257 should have filesystem type C<fstype>.
2258
2259 The returned integer is the status.  See L<fsck(8)> for the
2260 list of status codes from C<fsck>.
2261
2262 Notes:
2263
2264 =over 4
2265
2266 =item *
2267
2268 Multiple status codes can be summed together.
2269
2270 =item *
2271
2272 A non-zero return code can mean \"success\", for example if
2273 errors have been corrected on the filesystem.
2274
2275 =item *
2276
2277 Checking or repairing NTFS volumes is not supported
2278 (by linux-ntfs).
2279
2280 =back
2281
2282 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2283
2284   ("zero", (RErr, [Device "device"]), 85, [],
2285    [InitBasicFS, Always, TestOutput (
2286       [["umount"; "/dev/sda1"];
2287        ["zero"; "/dev/sda1"];
2288        ["file"; "/dev/sda1"]], "data")],
2289    "write zeroes to the device",
2290    "\
2291 This command writes zeroes over the first few blocks of C<device>.
2292
2293 How many blocks are zeroed isn't specified (but it's I<not> enough
2294 to securely wipe the device).  It should be sufficient to remove
2295 any partition tables, filesystem superblocks and so on.
2296
2297 See also: C<guestfs_scrub_device>.");
2298
2299   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2300    (* Test disabled because grub-install incompatible with virtio-blk driver.
2301     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2302     *)
2303    [InitBasicFS, Disabled, TestOutputTrue (
2304       [["grub_install"; "/"; "/dev/sda1"];
2305        ["is_dir"; "/boot"]])],
2306    "install GRUB",
2307    "\
2308 This command installs GRUB (the Grand Unified Bootloader) on
2309 C<device>, with the root directory being C<root>.");
2310
2311   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2312    [InitBasicFS, Always, TestOutput (
2313       [["write_file"; "/old"; "file content"; "0"];
2314        ["cp"; "/old"; "/new"];
2315        ["cat"; "/new"]], "file content");
2316     InitBasicFS, Always, TestOutputTrue (
2317       [["write_file"; "/old"; "file content"; "0"];
2318        ["cp"; "/old"; "/new"];
2319        ["is_file"; "/old"]]);
2320     InitBasicFS, Always, TestOutput (
2321       [["write_file"; "/old"; "file content"; "0"];
2322        ["mkdir"; "/dir"];
2323        ["cp"; "/old"; "/dir/new"];
2324        ["cat"; "/dir/new"]], "file content")],
2325    "copy a file",
2326    "\
2327 This copies a file from C<src> to C<dest> where C<dest> is
2328 either a destination filename or destination directory.");
2329
2330   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2331    [InitBasicFS, Always, TestOutput (
2332       [["mkdir"; "/olddir"];
2333        ["mkdir"; "/newdir"];
2334        ["write_file"; "/olddir/file"; "file content"; "0"];
2335        ["cp_a"; "/olddir"; "/newdir"];
2336        ["cat"; "/newdir/olddir/file"]], "file content")],
2337    "copy a file or directory recursively",
2338    "\
2339 This copies a file or directory from C<src> to C<dest>
2340 recursively using the C<cp -a> command.");
2341
2342   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2343    [InitBasicFS, Always, TestOutput (
2344       [["write_file"; "/old"; "file content"; "0"];
2345        ["mv"; "/old"; "/new"];
2346        ["cat"; "/new"]], "file content");
2347     InitBasicFS, Always, TestOutputFalse (
2348       [["write_file"; "/old"; "file content"; "0"];
2349        ["mv"; "/old"; "/new"];
2350        ["is_file"; "/old"]])],
2351    "move a file",
2352    "\
2353 This moves a file from C<src> to C<dest> where C<dest> is
2354 either a destination filename or destination directory.");
2355
2356   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2357    [InitEmpty, Always, TestRun (
2358       [["drop_caches"; "3"]])],
2359    "drop kernel page cache, dentries and inodes",
2360    "\
2361 This instructs the guest kernel to drop its page cache,
2362 and/or dentries and inode caches.  The parameter C<whattodrop>
2363 tells the kernel what precisely to drop, see
2364 L<http://linux-mm.org/Drop_Caches>
2365
2366 Setting C<whattodrop> to 3 should drop everything.
2367
2368 This automatically calls L<sync(2)> before the operation,
2369 so that the maximum guest memory is freed.");
2370
2371   ("dmesg", (RString "kmsgs", []), 91, [],
2372    [InitEmpty, Always, TestRun (
2373       [["dmesg"]])],
2374    "return kernel messages",
2375    "\
2376 This returns the kernel messages (C<dmesg> output) from
2377 the guest kernel.  This is sometimes useful for extended
2378 debugging of problems.
2379
2380 Another way to get the same information is to enable
2381 verbose messages with C<guestfs_set_verbose> or by setting
2382 the environment variable C<LIBGUESTFS_DEBUG=1> before
2383 running the program.");
2384
2385   ("ping_daemon", (RErr, []), 92, [],
2386    [InitEmpty, Always, TestRun (
2387       [["ping_daemon"]])],
2388    "ping the guest daemon",
2389    "\
2390 This is a test probe into the guestfs daemon running inside
2391 the qemu subprocess.  Calling this function checks that the
2392 daemon responds to the ping message, without affecting the daemon
2393 or attached block device(s) in any other way.");
2394
2395   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2396    [InitBasicFS, Always, TestOutputTrue (
2397       [["write_file"; "/file1"; "contents of a file"; "0"];
2398        ["cp"; "/file1"; "/file2"];
2399        ["equal"; "/file1"; "/file2"]]);
2400     InitBasicFS, Always, TestOutputFalse (
2401       [["write_file"; "/file1"; "contents of a file"; "0"];
2402        ["write_file"; "/file2"; "contents of another file"; "0"];
2403        ["equal"; "/file1"; "/file2"]]);
2404     InitBasicFS, Always, TestLastFail (
2405       [["equal"; "/file1"; "/file2"]])],
2406    "test if two files have equal contents",
2407    "\
2408 This compares the two files C<file1> and C<file2> and returns
2409 true if their content is exactly equal, or false otherwise.
2410
2411 The external L<cmp(1)> program is used for the comparison.");
2412
2413   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2414    [InitISOFS, Always, TestOutputList (
2415       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2416     InitISOFS, Always, TestOutputList (
2417       [["strings"; "/empty"]], [])],
2418    "print the printable strings in a file",
2419    "\
2420 This runs the L<strings(1)> command on a file and returns
2421 the list of printable strings found.");
2422
2423   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2424    [InitISOFS, Always, TestOutputList (
2425       [["strings_e"; "b"; "/known-5"]], []);
2426     InitBasicFS, Disabled, TestOutputList (
2427       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2428        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2429    "print the printable strings in a file",
2430    "\
2431 This is like the C<guestfs_strings> command, but allows you to
2432 specify the encoding.
2433
2434 See the L<strings(1)> manpage for the full list of encodings.
2435
2436 Commonly useful encodings are C<l> (lower case L) which will
2437 show strings inside Windows/x86 files.
2438
2439 The returned strings are transcoded to UTF-8.");
2440
2441   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2442    [InitISOFS, Always, TestOutput (
2443       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2444     (* Test for RHBZ#501888c2 regression which caused large hexdump
2445      * commands to segfault.
2446      *)
2447     InitISOFS, Always, TestRun (
2448       [["hexdump"; "/100krandom"]])],
2449    "dump a file in hexadecimal",
2450    "\
2451 This runs C<hexdump -C> on the given C<path>.  The result is
2452 the human-readable, canonical hex dump of the file.");
2453
2454   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2455    [InitNone, Always, TestOutput (
2456       [["part_disk"; "/dev/sda"; "mbr"];
2457        ["mkfs"; "ext3"; "/dev/sda1"];
2458        ["mount_options"; ""; "/dev/sda1"; "/"];
2459        ["write_file"; "/new"; "test file"; "0"];
2460        ["umount"; "/dev/sda1"];
2461        ["zerofree"; "/dev/sda1"];
2462        ["mount_options"; ""; "/dev/sda1"; "/"];
2463        ["cat"; "/new"]], "test file")],
2464    "zero unused inodes and disk blocks on ext2/3 filesystem",
2465    "\
2466 This runs the I<zerofree> program on C<device>.  This program
2467 claims to zero unused inodes and disk blocks on an ext2/3
2468 filesystem, thus making it possible to compress the filesystem
2469 more effectively.
2470
2471 You should B<not> run this program if the filesystem is
2472 mounted.
2473
2474 It is possible that using this program can damage the filesystem
2475 or data on the filesystem.");
2476
2477   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2478    [],
2479    "resize an LVM physical volume",
2480    "\
2481 This resizes (expands or shrinks) an existing LVM physical
2482 volume to match the new size of the underlying device.");
2483
2484   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2485                        Int "cyls"; Int "heads"; Int "sectors";
2486                        String "line"]), 99, [DangerWillRobinson],
2487    [],
2488    "modify a single partition on a block device",
2489    "\
2490 This runs L<sfdisk(8)> option to modify just the single
2491 partition C<n> (note: C<n> counts from 1).
2492
2493 For other parameters, see C<guestfs_sfdisk>.  You should usually
2494 pass C<0> for the cyls/heads/sectors parameters.
2495
2496 See also: C<guestfs_part_add>");
2497
2498   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2499    [],
2500    "display the partition table",
2501    "\
2502 This displays the partition table on C<device>, in the
2503 human-readable output of the L<sfdisk(8)> command.  It is
2504 not intended to be parsed.
2505
2506 See also: C<guestfs_part_list>");
2507
2508   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2509    [],
2510    "display the kernel geometry",
2511    "\
2512 This displays the kernel's idea of the geometry of C<device>.
2513
2514 The result is in human-readable format, and not designed to
2515 be parsed.");
2516
2517   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2518    [],
2519    "display the disk geometry from the partition table",
2520    "\
2521 This displays the disk geometry of C<device> read from the
2522 partition table.  Especially in the case where the underlying
2523 block device has been resized, this can be different from the
2524 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2525
2526 The result is in human-readable format, and not designed to
2527 be parsed.");
2528
2529   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2530    [],
2531    "activate or deactivate all volume groups",
2532    "\
2533 This command activates or (if C<activate> is false) deactivates
2534 all logical volumes in all volume groups.
2535 If activated, then they are made known to the
2536 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2537 then those devices disappear.
2538
2539 This command is the same as running C<vgchange -a y|n>");
2540
2541   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2542    [],
2543    "activate or deactivate some volume groups",
2544    "\
2545 This command activates or (if C<activate> is false) deactivates
2546 all logical volumes in the listed volume groups C<volgroups>.
2547 If activated, then they are made known to the
2548 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2549 then those devices disappear.
2550
2551 This command is the same as running C<vgchange -a y|n volgroups...>
2552
2553 Note that if C<volgroups> is an empty list then B<all> volume groups
2554 are activated or deactivated.");
2555
2556   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2557    [InitNone, Always, TestOutput (
2558       [["part_disk"; "/dev/sda"; "mbr"];
2559        ["pvcreate"; "/dev/sda1"];
2560        ["vgcreate"; "VG"; "/dev/sda1"];
2561        ["lvcreate"; "LV"; "VG"; "10"];
2562        ["mkfs"; "ext2"; "/dev/VG/LV"];
2563        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2564        ["write_file"; "/new"; "test content"; "0"];
2565        ["umount"; "/"];
2566        ["lvresize"; "/dev/VG/LV"; "20"];
2567        ["e2fsck_f"; "/dev/VG/LV"];
2568        ["resize2fs"; "/dev/VG/LV"];
2569        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2570        ["cat"; "/new"]], "test content")],
2571    "resize an LVM logical volume",
2572    "\
2573 This resizes (expands or shrinks) an existing LVM logical
2574 volume to C<mbytes>.  When reducing, data in the reduced part
2575 is lost.");
2576
2577   ("resize2fs", (RErr, [Device "device"]), 106, [],
2578    [], (* lvresize tests this *)
2579    "resize an ext2/ext3 filesystem",
2580    "\
2581 This resizes an ext2 or ext3 filesystem to match the size of
2582 the underlying device.
2583
2584 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2585 on the C<device> before calling this command.  For unknown reasons
2586 C<resize2fs> sometimes gives an error about this and sometimes not.
2587 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2588 calling this function.");
2589
2590   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2591    [InitBasicFS, Always, TestOutputList (
2592       [["find"; "/"]], ["lost+found"]);
2593     InitBasicFS, Always, TestOutputList (
2594       [["touch"; "/a"];
2595        ["mkdir"; "/b"];
2596        ["touch"; "/b/c"];
2597        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2598     InitBasicFS, Always, TestOutputList (
2599       [["mkdir_p"; "/a/b/c"];
2600        ["touch"; "/a/b/c/d"];
2601        ["find"; "/a/b/"]], ["c"; "c/d"])],
2602    "find all files and directories",
2603    "\
2604 This command lists out all files and directories, recursively,
2605 starting at C<directory>.  It is essentially equivalent to
2606 running the shell command C<find directory -print> but some
2607 post-processing happens on the output, described below.
2608
2609 This returns a list of strings I<without any prefix>.  Thus
2610 if the directory structure was:
2611
2612  /tmp/a
2613  /tmp/b
2614  /tmp/c/d
2615
2616 then the returned list from C<guestfs_find> C</tmp> would be
2617 4 elements:
2618
2619  a
2620  b
2621  c
2622  c/d
2623
2624 If C<directory> is not a directory, then this command returns
2625 an error.
2626
2627 The returned list is sorted.
2628
2629 See also C<guestfs_find0>.");
2630
2631   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2632    [], (* lvresize tests this *)
2633    "check an ext2/ext3 filesystem",
2634    "\
2635 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2636 filesystem checker on C<device>, noninteractively (C<-p>),
2637 even if the filesystem appears to be clean (C<-f>).
2638
2639 This command is only needed because of C<guestfs_resize2fs>
2640 (q.v.).  Normally you should use C<guestfs_fsck>.");
2641
2642   ("sleep", (RErr, [Int "secs"]), 109, [],
2643    [InitNone, Always, TestRun (
2644       [["sleep"; "1"]])],
2645    "sleep for some seconds",
2646    "\
2647 Sleep for C<secs> seconds.");
2648
2649   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2650    [InitNone, Always, TestOutputInt (
2651       [["part_disk"; "/dev/sda"; "mbr"];
2652        ["mkfs"; "ntfs"; "/dev/sda1"];
2653        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2654     InitNone, Always, TestOutputInt (
2655       [["part_disk"; "/dev/sda"; "mbr"];
2656        ["mkfs"; "ext2"; "/dev/sda1"];
2657        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2658    "probe NTFS volume",
2659    "\
2660 This command runs the L<ntfs-3g.probe(8)> command which probes
2661 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2662 be mounted read-write, and some cannot be mounted at all).
2663
2664 C<rw> is a boolean flag.  Set it to true if you want to test
2665 if the volume can be mounted read-write.  Set it to false if
2666 you want to test if the volume can be mounted read-only.
2667
2668 The return value is an integer which C<0> if the operation
2669 would succeed, or some non-zero value documented in the
2670 L<ntfs-3g.probe(8)> manual page.");
2671
2672   ("sh", (RString "output", [String "command"]), 111, [],
2673    [], (* XXX needs tests *)
2674    "run a command via the shell",
2675    "\
2676 This call runs a command from the guest filesystem via the
2677 guest's C</bin/sh>.
2678
2679 This is like C<guestfs_command>, but passes the command to:
2680
2681  /bin/sh -c \"command\"
2682
2683 Depending on the guest's shell, this usually results in
2684 wildcards being expanded, shell expressions being interpolated
2685 and so on.
2686
2687 All the provisos about C<guestfs_command> apply to this call.");
2688
2689   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2690    [], (* XXX needs tests *)
2691    "run a command via the shell returning lines",
2692    "\
2693 This is the same as C<guestfs_sh>, but splits the result
2694 into a list of lines.
2695
2696 See also: C<guestfs_command_lines>");
2697
2698   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2699    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2700     * code in stubs.c, since all valid glob patterns must start with "/".
2701     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2702     *)
2703    [InitBasicFS, Always, TestOutputList (
2704       [["mkdir_p"; "/a/b/c"];
2705        ["touch"; "/a/b/c/d"];
2706        ["touch"; "/a/b/c/e"];
2707        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2708     InitBasicFS, Always, TestOutputList (
2709       [["mkdir_p"; "/a/b/c"];
2710        ["touch"; "/a/b/c/d"];
2711        ["touch"; "/a/b/c/e"];
2712        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2713     InitBasicFS, Always, TestOutputList (
2714       [["mkdir_p"; "/a/b/c"];
2715        ["touch"; "/a/b/c/d"];
2716        ["touch"; "/a/b/c/e"];
2717        ["glob_expand"; "/a/*/x/*"]], [])],
2718    "expand a wildcard path",
2719    "\
2720 This command searches for all the pathnames matching
2721 C<pattern> according to the wildcard expansion rules
2722 used by the shell.
2723
2724 If no paths match, then this returns an empty list
2725 (note: not an error).
2726
2727 It is just a wrapper around the C L<glob(3)> function
2728 with flags C<GLOB_MARK|GLOB_BRACE>.
2729 See that manual page for more details.");
2730
2731   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2732    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2733       [["scrub_device"; "/dev/sdc"]])],
2734    "scrub (securely wipe) a device",
2735    "\
2736 This command writes patterns over C<device> to make data retrieval
2737 more difficult.
2738
2739 It is an interface to the L<scrub(1)> program.  See that
2740 manual page for more details.");
2741
2742   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2743    [InitBasicFS, Always, TestRun (
2744       [["write_file"; "/file"; "content"; "0"];
2745        ["scrub_file"; "/file"]])],
2746    "scrub (securely wipe) a file",
2747    "\
2748 This command writes patterns over a file to make data retrieval
2749 more difficult.
2750
2751 The file is I<removed> after scrubbing.
2752
2753 It is an interface to the L<scrub(1)> program.  See that
2754 manual page for more details.");
2755
2756   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2757    [], (* XXX needs testing *)
2758    "scrub (securely wipe) free space",
2759    "\
2760 This command creates the directory C<dir> and then fills it
2761 with files until the filesystem is full, and scrubs the files
2762 as for C<guestfs_scrub_file>, and deletes them.
2763 The intention is to scrub any free space on the partition
2764 containing C<dir>.
2765
2766 It is an interface to the L<scrub(1)> program.  See that
2767 manual page for more details.");
2768
2769   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2770    [InitBasicFS, Always, TestRun (
2771       [["mkdir"; "/tmp"];
2772        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2773    "create a temporary directory",
2774    "\
2775 This command creates a temporary directory.  The
2776 C<template> parameter should be a full pathname for the
2777 temporary directory name with the final six characters being
2778 \"XXXXXX\".
2779
2780 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2781 the second one being suitable for Windows filesystems.
2782
2783 The name of the temporary directory that was created
2784 is returned.
2785
2786 The temporary directory is created with mode 0700
2787 and is owned by root.
2788
2789 The caller is responsible for deleting the temporary
2790 directory and its contents after use.
2791
2792 See also: L<mkdtemp(3)>");
2793
2794   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2795    [InitISOFS, Always, TestOutputInt (
2796       [["wc_l"; "/10klines"]], 10000)],
2797    "count lines in a file",
2798    "\
2799 This command counts the lines in a file, using the
2800 C<wc -l> external command.");
2801
2802   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2803    [InitISOFS, Always, TestOutputInt (
2804       [["wc_w"; "/10klines"]], 10000)],
2805    "count words in a file",
2806    "\
2807 This command counts the words in a file, using the
2808 C<wc -w> external command.");
2809
2810   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2811    [InitISOFS, Always, TestOutputInt (
2812       [["wc_c"; "/100kallspaces"]], 102400)],
2813    "count characters in a file",
2814    "\
2815 This command counts the characters in a file, using the
2816 C<wc -c> external command.");
2817
2818   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2819    [InitISOFS, Always, TestOutputList (
2820       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2821    "return first 10 lines of a file",
2822    "\
2823 This command returns up to the first 10 lines of a file as
2824 a list of strings.");
2825
2826   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2827    [InitISOFS, Always, TestOutputList (
2828       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2829     InitISOFS, Always, TestOutputList (
2830       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2831     InitISOFS, Always, TestOutputList (
2832       [["head_n"; "0"; "/10klines"]], [])],
2833    "return first N lines of a file",
2834    "\
2835 If the parameter C<nrlines> is a positive number, this returns the first
2836 C<nrlines> lines of the file C<path>.
2837
2838 If the parameter C<nrlines> is a negative number, this returns lines
2839 from the file C<path>, excluding the last C<nrlines> lines.
2840
2841 If the parameter C<nrlines> is zero, this returns an empty list.");
2842
2843   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2844    [InitISOFS, Always, TestOutputList (
2845       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2846    "return last 10 lines of a file",
2847    "\
2848 This command returns up to the last 10 lines of a file as
2849 a list of strings.");
2850
2851   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2852    [InitISOFS, Always, TestOutputList (
2853       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2854     InitISOFS, Always, TestOutputList (
2855       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2856     InitISOFS, Always, TestOutputList (
2857       [["tail_n"; "0"; "/10klines"]], [])],
2858    "return last N lines of a file",
2859    "\
2860 If the parameter C<nrlines> is a positive number, this returns the last
2861 C<nrlines> lines of the file C<path>.
2862
2863 If the parameter C<nrlines> is a negative number, this returns lines
2864 from the file C<path>, starting with the C<-nrlines>th line.
2865
2866 If the parameter C<nrlines> is zero, this returns an empty list.");
2867
2868   ("df", (RString "output", []), 125, [],
2869    [], (* XXX Tricky to test because it depends on the exact format
2870         * of the 'df' command and other imponderables.
2871         *)
2872    "report file system disk space usage",
2873    "\
2874 This command runs the C<df> command to report disk space used.
2875
2876 This command is mostly useful for interactive sessions.  It
2877 is I<not> intended that you try to parse the output string.
2878 Use C<statvfs> from programs.");
2879
2880   ("df_h", (RString "output", []), 126, [],
2881    [], (* XXX Tricky to test because it depends on the exact format
2882         * of the 'df' command and other imponderables.
2883         *)
2884    "report file system disk space usage (human readable)",
2885    "\
2886 This command runs the C<df -h> command to report disk space used
2887 in human-readable format.
2888
2889 This command is mostly useful for interactive sessions.  It
2890 is I<not> intended that you try to parse the output string.
2891 Use C<statvfs> from programs.");
2892
2893   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2894    [InitISOFS, Always, TestOutputInt (
2895       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2896    "estimate file space usage",
2897    "\
2898 This command runs the C<du -s> command to estimate file space
2899 usage for C<path>.
2900
2901 C<path> can be a file or a directory.  If C<path> is a directory
2902 then the estimate includes the contents of the directory and all
2903 subdirectories (recursively).
2904
2905 The result is the estimated size in I<kilobytes>
2906 (ie. units of 1024 bytes).");
2907
2908   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2909    [InitISOFS, Always, TestOutputList (
2910       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2911    "list files in an initrd",
2912    "\
2913 This command lists out files contained in an initrd.
2914
2915 The files are listed without any initial C</> character.  The
2916 files are listed in the order they appear (not necessarily
2917 alphabetical).  Directory names are listed as separate items.
2918
2919 Old Linux kernels (2.4 and earlier) used a compressed ext2
2920 filesystem as initrd.  We I<only> support the newer initramfs
2921 format (compressed cpio files).");
2922
2923   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2924    [],
2925    "mount a file using the loop device",
2926    "\
2927 This command lets you mount C<file> (a filesystem image
2928 in a file) on a mount point.  It is entirely equivalent to
2929 the command C<mount -o loop file mountpoint>.");
2930
2931   ("mkswap", (RErr, [Device "device"]), 130, [],
2932    [InitEmpty, Always, TestRun (
2933       [["part_disk"; "/dev/sda"; "mbr"];
2934        ["mkswap"; "/dev/sda1"]])],
2935    "create a swap partition",
2936    "\
2937 Create a swap partition on C<device>.");
2938
2939   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2940    [InitEmpty, Always, TestRun (
2941       [["part_disk"; "/dev/sda"; "mbr"];
2942        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2943    "create a swap partition with a label",
2944    "\
2945 Create a swap partition on C<device> with label C<label>.
2946
2947 Note that you cannot attach a swap label to a block device
2948 (eg. C</dev/sda>), just to a partition.  This appears to be
2949 a limitation of the kernel or swap tools.");
2950
2951   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
2952    (let uuid = uuidgen () in
2953     [InitEmpty, Always, TestRun (
2954        [["part_disk"; "/dev/sda"; "mbr"];
2955         ["mkswap_U"; uuid; "/dev/sda1"]])]),
2956    "create a swap partition with an explicit UUID",
2957    "\
2958 Create a swap partition on C<device> with UUID C<uuid>.");
2959
2960   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
2961    [InitBasicFS, Always, TestOutputStruct (
2962       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2963        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2964        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2965     InitBasicFS, Always, TestOutputStruct (
2966       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2967        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2968    "make block, character or FIFO devices",
2969    "\
2970 This call creates block or character special devices, or
2971 named pipes (FIFOs).
2972
2973 The C<mode> parameter should be the mode, using the standard
2974 constants.  C<devmajor> and C<devminor> are the
2975 device major and minor numbers, only used when creating block
2976 and character special devices.");
2977
2978   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
2979    [InitBasicFS, Always, TestOutputStruct (
2980       [["mkfifo"; "0o777"; "/node"];
2981        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2982    "make FIFO (named pipe)",
2983    "\
2984 This call creates a FIFO (named pipe) called C<path> with
2985 mode C<mode>.  It is just a convenient wrapper around
2986 C<guestfs_mknod>.");
2987
2988   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
2989    [InitBasicFS, Always, TestOutputStruct (
2990       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2991        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2992    "make block device node",
2993    "\
2994 This call creates a block device node called C<path> with
2995 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2996 It is just a convenient wrapper around C<guestfs_mknod>.");
2997
2998   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
2999    [InitBasicFS, Always, TestOutputStruct (
3000       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
3001        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
3002    "make char device node",
3003    "\
3004 This call creates a char device node called C<path> with
3005 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3006 It is just a convenient wrapper around C<guestfs_mknod>.");
3007
3008   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
3009    [], (* XXX umask is one of those stateful things that we should
3010         * reset between each test.
3011         *)
3012    "set file mode creation mask (umask)",
3013    "\
3014 This function sets the mask used for creating new files and
3015 device nodes to C<mask & 0777>.
3016
3017 Typical umask values would be C<022> which creates new files
3018 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
3019 C<002> which creates new files with permissions like
3020 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
3021
3022 The default umask is C<022>.  This is important because it
3023 means that directories and device nodes will be created with
3024 C<0644> or C<0755> mode even if you specify C<0777>.
3025
3026 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
3027
3028 This call returns the previous umask.");
3029
3030   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
3031    [],
3032    "read directories entries",
3033    "\
3034 This returns the list of directory entries in directory C<dir>.
3035
3036 All entries in the directory are returned, including C<.> and
3037 C<..>.  The entries are I<not> sorted, but returned in the same
3038 order as the underlying filesystem.
3039
3040 Also this call returns basic file type information about each
3041 file.  The C<ftyp> field will contain one of the following characters:
3042
3043 =over 4
3044
3045 =item 'b'
3046
3047 Block special
3048
3049 =item 'c'
3050
3051 Char special
3052
3053 =item 'd'
3054
3055 Directory
3056
3057 =item 'f'
3058
3059 FIFO (named pipe)
3060
3061 =item 'l'
3062
3063 Symbolic link
3064
3065 =item 'r'
3066
3067 Regular file
3068
3069 =item 's'
3070
3071 Socket
3072
3073 =item 'u'
3074
3075 Unknown file type
3076
3077 =item '?'
3078
3079 The L<readdir(3)> returned a C<d_type> field with an
3080 unexpected value
3081
3082 =back
3083
3084 This function is primarily intended for use by programs.  To
3085 get a simple list of names, use C<guestfs_ls>.  To get a printable
3086 directory for human consumption, use C<guestfs_ll>.");
3087
3088   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3089    [],
3090    "create partitions on a block device",
3091    "\
3092 This is a simplified interface to the C<guestfs_sfdisk>
3093 command, where partition sizes are specified in megabytes
3094 only (rounded to the nearest cylinder) and you don't need
3095 to specify the cyls, heads and sectors parameters which
3096 were rarely if ever used anyway.
3097
3098 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3099 and C<guestfs_part_disk>");
3100
3101   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3102    [],
3103    "determine file type inside a compressed file",
3104    "\
3105 This command runs C<file> after first decompressing C<path>
3106 using C<method>.
3107
3108 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3109
3110 Since 1.0.63, use C<guestfs_file> instead which can now
3111 process compressed files.");
3112
3113   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3114    [],
3115    "list extended attributes of a file or directory",
3116    "\
3117 This call lists the extended attributes of the file or directory
3118 C<path>.
3119
3120 At the system call level, this is a combination of the
3121 L<listxattr(2)> and L<getxattr(2)> calls.
3122
3123 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3124
3125   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3126    [],
3127    "list extended attributes of a file or directory",
3128    "\
3129 This is the same as C<guestfs_getxattrs>, but if C<path>
3130 is a symbolic link, then it returns the extended attributes
3131 of the link itself.");
3132
3133   ("setxattr", (RErr, [String "xattr";
3134                        String "val"; Int "vallen"; (* will be BufferIn *)
3135                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3136    [],
3137    "set extended attribute of a file or directory",
3138    "\
3139 This call sets the extended attribute named C<xattr>
3140 of the file C<path> to the value C<val> (of length C<vallen>).
3141 The value is arbitrary 8 bit data.
3142
3143 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3144
3145   ("lsetxattr", (RErr, [String "xattr";
3146                         String "val"; Int "vallen"; (* will be BufferIn *)
3147                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3148    [],
3149    "set extended attribute of a file or directory",
3150    "\
3151 This is the same as C<guestfs_setxattr>, but if C<path>
3152 is a symbolic link, then it sets an extended attribute
3153 of the link itself.");
3154
3155   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3156    [],
3157    "remove extended attribute of a file or directory",
3158    "\
3159 This call removes the extended attribute named C<xattr>
3160 of the file C<path>.
3161
3162 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3163
3164   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3165    [],
3166    "remove extended attribute of a file or directory",
3167    "\
3168 This is the same as C<guestfs_removexattr>, but if C<path>
3169 is a symbolic link, then it removes an extended attribute
3170 of the link itself.");
3171
3172   ("mountpoints", (RHashtable "mps", []), 147, [],
3173    [],
3174    "show mountpoints",
3175    "\
3176 This call is similar to C<guestfs_mounts>.  That call returns
3177 a list of devices.  This one returns a hash table (map) of
3178 device name to directory where the device is mounted.");
3179
3180   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3181    (* This is a special case: while you would expect a parameter
3182     * of type "Pathname", that doesn't work, because it implies
3183     * NEED_ROOT in the generated calling code in stubs.c, and
3184     * this function cannot use NEED_ROOT.
3185     *)
3186    [],
3187    "create a mountpoint",
3188    "\
3189 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3190 specialized calls that can be used to create extra mountpoints
3191 before mounting the first filesystem.
3192
3193 These calls are I<only> necessary in some very limited circumstances,
3194 mainly the case where you want to mount a mix of unrelated and/or
3195 read-only filesystems together.
3196
3197 For example, live CDs often contain a \"Russian doll\" nest of
3198 filesystems, an ISO outer layer, with a squashfs image inside, with
3199 an ext2/3 image inside that.  You can unpack this as follows
3200 in guestfish:
3201
3202  add-ro Fedora-11-i686-Live.iso
3203  run
3204  mkmountpoint /cd
3205  mkmountpoint /squash
3206  mkmountpoint /ext3
3207  mount /dev/sda /cd
3208  mount-loop /cd/LiveOS/squashfs.img /squash
3209  mount-loop /squash/LiveOS/ext3fs.img /ext3
3210
3211 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3212
3213   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3214    [],
3215    "remove a mountpoint",
3216    "\
3217 This calls removes a mountpoint that was previously created
3218 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3219 for full details.");
3220
3221   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3222    [InitISOFS, Always, TestOutputBuffer (
3223       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3224    "read a file",
3225    "\
3226 This calls returns the contents of the file C<path> as a
3227 buffer.
3228
3229 Unlike C<guestfs_cat>, this function can correctly
3230 handle files that contain embedded ASCII NUL characters.
3231 However unlike C<guestfs_download>, this function is limited
3232 in the total size of file that can be handled.");
3233
3234   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3235    [InitISOFS, Always, TestOutputList (
3236       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3237     InitISOFS, Always, TestOutputList (
3238       [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3239    "return lines matching a pattern",
3240    "\
3241 This calls the external C<grep> program and returns the
3242 matching lines.");
3243
3244   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3245    [InitISOFS, Always, TestOutputList (
3246       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3247    "return lines matching a pattern",
3248    "\
3249 This calls the external C<egrep> program and returns the
3250 matching lines.");
3251
3252   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3253    [InitISOFS, Always, TestOutputList (
3254       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3255    "return lines matching a pattern",
3256    "\
3257 This calls the external C<fgrep> program and returns the
3258 matching lines.");
3259
3260   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3261    [InitISOFS, Always, TestOutputList (
3262       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3263    "return lines matching a pattern",
3264    "\
3265 This calls the external C<grep -i> program and returns the
3266 matching lines.");
3267
3268   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3269    [InitISOFS, Always, TestOutputList (
3270       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3271    "return lines matching a pattern",
3272    "\
3273 This calls the external C<egrep -i> program and returns the
3274 matching lines.");
3275
3276   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3277    [InitISOFS, Always, TestOutputList (
3278       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3279    "return lines matching a pattern",
3280    "\
3281 This calls the external C<fgrep -i> program and returns the
3282 matching lines.");
3283
3284   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3285    [InitISOFS, Always, TestOutputList (
3286       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3287    "return lines matching a pattern",
3288    "\
3289 This calls the external C<zgrep> program and returns the
3290 matching lines.");
3291
3292   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3293    [InitISOFS, Always, TestOutputList (
3294       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3295    "return lines matching a pattern",
3296    "\
3297 This calls the external C<zegrep> program and returns the
3298 matching lines.");
3299
3300   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3301    [InitISOFS, Always, TestOutputList (
3302       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3303    "return lines matching a pattern",
3304    "\
3305 This calls the external C<zfgrep> program and returns the
3306 matching lines.");
3307
3308   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3309    [InitISOFS, Always, TestOutputList (
3310       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3311    "return lines matching a pattern",
3312    "\
3313 This calls the external C<zgrep -i> program and returns the
3314 matching lines.");
3315
3316   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3317    [InitISOFS, Always, TestOutputList (
3318       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3319    "return lines matching a pattern",
3320    "\
3321 This calls the external C<zegrep -i> program and returns the
3322 matching lines.");
3323
3324   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3325    [InitISOFS, Always, TestOutputList (
3326       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3327    "return lines matching a pattern",
3328    "\
3329 This calls the external C<zfgrep -i> program and returns the
3330 matching lines.");
3331
3332   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3333    [InitISOFS, Always, TestOutput (
3334       [["realpath"; "/../directory"]], "/directory")],
3335    "canonicalized absolute pathname",
3336    "\
3337 Return the canonicalized absolute pathname of C<path>.  The
3338 returned path has no C<.>, C<..> or symbolic link path elements.");
3339
3340   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3341    [InitBasicFS, Always, TestOutputStruct (
3342       [["touch"; "/a"];
3343        ["ln"; "/a"; "/b"];
3344        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3345    "create a hard link",
3346    "\
3347 This command creates a hard link using the C<ln> command.");
3348
3349   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3350    [InitBasicFS, Always, TestOutputStruct (
3351       [["touch"; "/a"];
3352        ["touch"; "/b"];
3353        ["ln_f"; "/a"; "/b"];
3354        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3355    "create a hard link",
3356    "\
3357 This command creates a hard link using the C<ln -f> command.
3358 The C<-f> option removes the link (C<linkname>) if it exists already.");
3359
3360   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3361    [InitBasicFS, Always, TestOutputStruct (
3362       [["touch"; "/a"];
3363        ["ln_s"; "a"; "/b"];
3364        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3365    "create a symbolic link",
3366    "\
3367 This command creates a symbolic link using the C<ln -s> command.");
3368
3369   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3370    [InitBasicFS, Always, TestOutput (
3371       [["mkdir_p"; "/a/b"];
3372        ["touch"; "/a/b/c"];
3373        ["ln_sf"; "../d"; "/a/b/c"];
3374        ["readlink"; "/a/b/c"]], "../d")],
3375    "create a symbolic link",
3376    "\
3377 This command creates a symbolic link using the C<ln -sf> command,
3378 The C<-f> option removes the link (C<linkname>) if it exists already.");
3379
3380   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3381    [] (* XXX tested above *),
3382    "read the target of a symbolic link",
3383    "\
3384 This command reads the target of a symbolic link.");
3385
3386   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3387    [InitBasicFS, Always, TestOutputStruct (
3388       [["fallocate"; "/a"; "1000000"];
3389        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3390    "preallocate a file in the guest filesystem",
3391    "\
3392 This command preallocates a file (containing zero bytes) named
3393 C<path> of size C<len> bytes.  If the file exists already, it
3394 is overwritten.
3395
3396 Do not confuse this with the guestfish-specific
3397 C<alloc> command which allocates a file in the host and
3398 attaches it as a device.");
3399
3400   ("swapon_device", (RErr, [Device "device"]), 170, [],
3401    [InitPartition, Always, TestRun (
3402       [["mkswap"; "/dev/sda1"];
3403        ["swapon_device"; "/dev/sda1"];
3404        ["swapoff_device"; "/dev/sda1"]])],
3405    "enable swap on device",
3406    "\
3407 This command enables the libguestfs appliance to use the
3408 swap device or partition named C<device>.  The increased
3409 memory is made available for all commands, for example
3410 those run using C<guestfs_command> or C<guestfs_sh>.
3411
3412 Note that you should not swap to existing guest swap
3413 partitions unless you know what you are doing.  They may
3414 contain hibernation information, or other information that
3415 the guest doesn't want you to trash.  You also risk leaking
3416 information about the host to the guest this way.  Instead,
3417 attach a new host device to the guest and swap on that.");
3418
3419   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3420    [], (* XXX tested by swapon_device *)
3421    "disable swap on device",
3422    "\
3423 This command disables the libguestfs appliance swap
3424 device or partition named C<device>.
3425 See C<guestfs_swapon_device>.");
3426
3427   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3428    [InitBasicFS, Always, TestRun (
3429       [["fallocate"; "/swap"; "8388608"];
3430        ["mkswap_file"; "/swap"];
3431        ["swapon_file"; "/swap"];
3432        ["swapoff_file"; "/swap"]])],
3433    "enable swap on file",
3434    "\
3435 This command enables swap to a file.
3436 See C<guestfs_swapon_device> for other notes.");
3437
3438   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3439    [], (* XXX tested by swapon_file *)
3440    "disable swap on file",
3441    "\
3442 This command disables the libguestfs appliance swap on file.");
3443
3444   ("swapon_label", (RErr, [String "label"]), 174, [],
3445    [InitEmpty, Always, TestRun (
3446       [["part_disk"; "/dev/sdb"; "mbr"];
3447        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3448        ["swapon_label"; "swapit"];
3449        ["swapoff_label"; "swapit"];
3450        ["zero"; "/dev/sdb"];
3451        ["blockdev_rereadpt"; "/dev/sdb"]])],
3452    "enable swap on labeled swap partition",
3453    "\
3454 This command enables swap to a labeled swap partition.
3455 See C<guestfs_swapon_device> for other notes.");
3456
3457   ("swapoff_label", (RErr, [String "label"]), 175, [],
3458    [], (* XXX tested by swapon_label *)
3459    "disable swap on labeled swap partition",
3460    "\
3461 This command disables the libguestfs appliance swap on
3462 labeled swap partition.");
3463
3464   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3465    (let uuid = uuidgen () in
3466     [InitEmpty, Always, TestRun (
3467        [["mkswap_U"; uuid; "/dev/sdb"];
3468         ["swapon_uuid"; uuid];
3469         ["swapoff_uuid"; uuid]])]),
3470    "enable swap on swap partition by UUID",
3471    "\
3472 This command enables swap to a swap partition with the given UUID.
3473 See C<guestfs_swapon_device> for other notes.");
3474
3475   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3476    [], (* XXX tested by swapon_uuid *)
3477    "disable swap on swap partition by UUID",
3478    "\
3479 This command disables the libguestfs appliance swap partition
3480 with the given UUID.");
3481
3482   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3483    [InitBasicFS, Always, TestRun (
3484       [["fallocate"; "/swap"; "8388608"];
3485        ["mkswap_file"; "/swap"]])],
3486    "create a swap file",
3487    "\
3488 Create a swap file.
3489
3490 This command just writes a swap file signature to an existing
3491 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3492
3493   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3494    [InitISOFS, Always, TestRun (
3495       [["inotify_init"; "0"]])],
3496    "create an inotify handle",
3497    "\
3498 This command creates a new inotify handle.
3499 The inotify subsystem can be used to notify events which happen to
3500 objects in the guest filesystem.
3501
3502 C<maxevents> is the maximum number of events which will be
3503 queued up between calls to C<guestfs_inotify_read> or
3504 C<guestfs_inotify_files>.
3505 If this is passed as C<0>, then the kernel (or previously set)
3506 default is used.  For Linux 2.6.29 the default was 16384 events.
3507 Beyond this limit, the kernel throws away events, but records
3508 the fact that it threw them away by setting a flag
3509 C<IN_Q_OVERFLOW> in the returned structure list (see
3510 C<guestfs_inotify_read>).
3511
3512 Before any events are generated, you have to add some
3513 watches to the internal watch list.  See:
3514 C<guestfs_inotify_add_watch>,
3515 C<guestfs_inotify_rm_watch> and
3516 C<guestfs_inotify_watch_all>.
3517
3518 Queued up events should be read periodically by calling
3519 C<guestfs_inotify_read>
3520 (or C<guestfs_inotify_files> which is just a helpful
3521 wrapper around C<guestfs_inotify_read>).  If you don't
3522 read the events out often enough then you risk the internal
3523 queue overflowing.
3524
3525 The handle should be closed after use by calling
3526 C<guestfs_inotify_close>.  This also removes any
3527 watches automatically.
3528
3529 See also L<inotify(7)> for an overview of the inotify interface
3530 as exposed by the Linux kernel, which is roughly what we expose
3531 via libguestfs.  Note that there is one global inotify handle
3532 per libguestfs instance.");
3533
3534   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3535    [InitBasicFS, Always, TestOutputList (
3536       [["inotify_init"; "0"];
3537        ["inotify_add_watch"; "/"; "1073741823"];
3538        ["touch"; "/a"];
3539        ["touch"; "/b"];
3540        ["inotify_files"]], ["a"; "b"])],
3541    "add an inotify watch",
3542    "\
3543 Watch C<path> for the events listed in C<mask>.
3544
3545 Note that if C<path> is a directory then events within that
3546 directory are watched, but this does I<not> happen recursively
3547 (in subdirectories).
3548
3549 Note for non-C or non-Linux callers: the inotify events are
3550 defined by the Linux kernel ABI and are listed in
3551 C</usr/include/sys/inotify.h>.");
3552
3553   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3554    [],
3555    "remove an inotify watch",
3556    "\
3557 Remove a previously defined inotify watch.
3558 See C<guestfs_inotify_add_watch>.");
3559
3560   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3561    [],
3562    "return list of inotify events",
3563    "\
3564 Return the complete queue of events that have happened
3565 since the previous read call.
3566
3567 If no events have happened, this returns an empty list.
3568
3569 I<Note>: In order to make sure that all events have been
3570 read, you must call this function repeatedly until it
3571 returns an empty list.  The reason is that the call will
3572 read events up to the maximum appliance-to-host message
3573 size and leave remaining events in the queue.");
3574
3575   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3576    [],
3577    "return list of watched files that had events",
3578    "\
3579 This function is a helpful wrapper around C<guestfs_inotify_read>
3580 which just returns a list of pathnames of objects that were
3581 touched.  The returned pathnames are sorted and deduplicated.");
3582
3583   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3584    [],
3585    "close the inotify handle",
3586    "\
3587 This closes the inotify handle which was previously
3588 opened by inotify_init.  It removes all watches, throws
3589 away any pending events, and deallocates all resources.");
3590
3591   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3592    [],
3593    "set SELinux security context",
3594    "\
3595 This sets the SELinux security context of the daemon
3596 to the string C<context>.
3597
3598 See the documentation about SELINUX in L<guestfs(3)>.");
3599
3600   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3601    [],
3602    "get SELinux security context",
3603    "\
3604 This gets the SELinux security context of the daemon.
3605
3606 See the documentation about SELINUX in L<guestfs(3)>,
3607 and C<guestfs_setcon>");
3608
3609   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3610    [InitEmpty, Always, TestOutput (
3611       [["part_disk"; "/dev/sda"; "mbr"];
3612        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3613        ["mount_options"; ""; "/dev/sda1"; "/"];
3614        ["write_file"; "/new"; "new file contents"; "0"];
3615        ["cat"; "/new"]], "new file contents")],
3616    "make a filesystem with block size",
3617    "\
3618 This call is similar to C<guestfs_mkfs>, but it allows you to
3619 control the block size of the resulting filesystem.  Supported
3620 block sizes depend on the filesystem type, but typically they
3621 are C<1024>, C<2048> or C<4096> only.");
3622
3623   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3624    [InitEmpty, Always, TestOutput (
3625       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3626        ["mke2journal"; "4096"; "/dev/sda1"];
3627        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3628        ["mount_options"; ""; "/dev/sda2"; "/"];
3629        ["write_file"; "/new"; "new file contents"; "0"];
3630        ["cat"; "/new"]], "new file contents")],
3631    "make ext2/3/4 external journal",
3632    "\
3633 This creates an ext2 external journal on C<device>.  It is equivalent
3634 to the command:
3635
3636  mke2fs -O journal_dev -b blocksize device");
3637
3638   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3639    [InitEmpty, Always, TestOutput (
3640       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3641        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3642        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3643        ["mount_options"; ""; "/dev/sda2"; "/"];
3644        ["write_file"; "/new"; "new file contents"; "0"];
3645        ["cat"; "/new"]], "new file contents")],
3646    "make ext2/3/4 external journal with label",
3647    "\
3648 This creates an ext2 external journal on C<device> with label C<label>.");
3649
3650   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3651    (let uuid = uuidgen () in
3652     [InitEmpty, Always, TestOutput (
3653        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3654         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3655         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3656         ["mount_options"; ""; "/dev/sda2"; "/"];
3657         ["write_file"; "/new"; "new file contents"; "0"];
3658         ["cat"; "/new"]], "new file contents")]),
3659    "make ext2/3/4 external journal with UUID",
3660    "\
3661 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3662
3663   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3664    [],
3665    "make ext2/3/4 filesystem with external journal",
3666    "\
3667 This creates an ext2/3/4 filesystem on C<device> with
3668 an external journal on C<journal>.  It is equivalent
3669 to the command:
3670
3671  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3672
3673 See also C<guestfs_mke2journal>.");
3674
3675   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3676    [],
3677    "make ext2/3/4 filesystem with external journal",
3678    "\
3679 This creates an ext2/3/4 filesystem on C<device> with
3680 an external journal on the journal labeled C<label>.
3681
3682 See also C<guestfs_mke2journal_L>.");
3683
3684   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3685    [],
3686    "make ext2/3/4 filesystem with external journal",
3687    "\
3688 This creates an ext2/3/4 filesystem on C<device> with
3689 an external journal on the journal with UUID C<uuid>.
3690
3691 See also C<guestfs_mke2journal_U>.");
3692
3693   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3694    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3695    "load a kernel module",
3696    "\
3697 This loads a kernel module in the appliance.
3698
3699 The kernel module must have been whitelisted when libguestfs
3700 was built (see C<appliance/kmod.whitelist.in> in the source).");
3701
3702   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3703    [InitNone, Always, TestOutput (
3704       [["echo_daemon"; "This is a test"]], "This is a test"
3705     )],
3706    "echo arguments back to the client",
3707    "\
3708 This command concatenate the list of C<words> passed with single spaces between
3709 them and returns the resulting string.
3710
3711 You can use this command to test the connection through to the daemon.
3712
3713 See also C<guestfs_ping_daemon>.");
3714
3715   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3716    [], (* There is a regression test for this. *)
3717    "find all files and directories, returning NUL-separated list",
3718    "\
3719 This command lists out all files and directories, recursively,
3720 starting at C<directory>, placing the resulting list in the
3721 external file called C<files>.
3722
3723 This command works the same way as C<guestfs_find> with the
3724 following exceptions:
3725
3726 =over 4
3727
3728 =item *
3729
3730 The resulting list is written to an external file.
3731
3732 =item *
3733
3734 Items (filenames) in the result are separated
3735 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3736
3737 =item *
3738
3739 This command is not limited in the number of names that it
3740 can return.
3741
3742 =item *
3743
3744 The result list is not sorted.
3745
3746 =back");
3747
3748   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3749    [InitISOFS, Always, TestOutput (
3750       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3751     InitISOFS, Always, TestOutput (
3752       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3753     InitISOFS, Always, TestOutput (
3754       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3755     InitISOFS, Always, TestLastFail (
3756       [["case_sensitive_path"; "/Known-1/"]]);
3757     InitBasicFS, Always, TestOutput (
3758       [["mkdir"; "/a"];
3759        ["mkdir"; "/a/bbb"];
3760        ["touch"; "/a/bbb/c"];
3761        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3762     InitBasicFS, Always, TestOutput (
3763       [["mkdir"; "/a"];
3764        ["mkdir"; "/a/bbb"];
3765        ["touch"; "/a/bbb/c"];
3766        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3767     InitBasicFS, Always, TestLastFail (
3768       [["mkdir"; "/a"];
3769        ["mkdir"; "/a/bbb"];
3770        ["touch"; "/a/bbb/c"];
3771        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3772    "return true path on case-insensitive filesystem",
3773    "\
3774 This can be used to resolve case insensitive paths on
3775 a filesystem which is case sensitive.  The use case is
3776 to resolve paths which you have read from Windows configuration
3777 files or the Windows Registry, to the true path.
3778
3779 The command handles a peculiarity of the Linux ntfs-3g
3780 filesystem driver (and probably others), which is that although
3781 the underlying filesystem is case-insensitive, the driver
3782 exports the filesystem to Linux as case-sensitive.
3783
3784 One consequence of this is that special directories such
3785 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3786 (or other things) depending on the precise details of how
3787 they were created.  In Windows itself this would not be
3788 a problem.
3789
3790 Bug or feature?  You decide:
3791 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3792
3793 This function resolves the true case of each element in the
3794 path and returns the case-sensitive path.
3795
3796 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3797 might return C<\"/WINDOWS/system32\"> (the exact return value
3798 would depend on details of how the directories were originally
3799 created under Windows).
3800
3801 I<Note>:
3802 This function does not handle drive names, backslashes etc.
3803
3804 See also C<guestfs_realpath>.");
3805
3806   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3807    [InitBasicFS, Always, TestOutput (
3808       [["vfs_type"; "/dev/sda1"]], "ext2")],
3809    "get the Linux VFS type corresponding to a mounted device",
3810    "\
3811 This command gets the block device type corresponding to
3812 a mounted device called C<device>.
3813
3814 Usually the result is the name of the Linux VFS module that
3815 is used to mount this device (probably determined automatically
3816 if you used the C<guestfs_mount> call).");
3817
3818   ("truncate", (RErr, [Pathname "path"]), 199, [],
3819    [InitBasicFS, Always, TestOutputStruct (
3820       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3821        ["truncate"; "/test"];
3822        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3823    "truncate a file to zero size",
3824    "\
3825 This command truncates C<path> to a zero-length file.  The
3826 file must exist already.");
3827
3828   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3829    [InitBasicFS, Always, TestOutputStruct (
3830       [["touch"; "/test"];
3831        ["truncate_size"; "/test"; "1000"];
3832        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3833    "truncate a file to a particular size",
3834    "\
3835 This command truncates C<path> to size C<size> bytes.  The file
3836 must exist already.  If the file is smaller than C<size> then
3837 the file is extended to the required size with null bytes.");
3838
3839   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3840    [InitBasicFS, Always, TestOutputStruct (
3841       [["touch"; "/test"];
3842        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3843        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3844    "set timestamp of a file with nanosecond precision",
3845    "\
3846 This command sets the timestamps of a file with nanosecond
3847 precision.
3848
3849 C<atsecs, atnsecs> are the last access time (atime) in secs and
3850 nanoseconds from the epoch.
3851
3852 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3853 secs and nanoseconds from the epoch.
3854
3855 If the C<*nsecs> field contains the special value C<-1> then
3856 the corresponding timestamp is set to the current time.  (The
3857 C<*secs> field is ignored in this case).
3858
3859 If the C<*nsecs> field contains the special value C<-2> then
3860 the corresponding timestamp is left unchanged.  (The
3861 C<*secs> field is ignored in this case).");
3862
3863   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3864    [InitBasicFS, Always, TestOutputStruct (
3865       [["mkdir_mode"; "/test"; "0o111"];
3866        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3867    "create a directory with a particular mode",
3868    "\
3869 This command creates a directory, setting the initial permissions
3870 of the directory to C<mode>.  See also C<guestfs_mkdir>.");
3871
3872   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3873    [], (* XXX *)
3874    "change file owner and group",
3875    "\
3876 Change the file owner to C<owner> and group to C<group>.
3877 This is like C<guestfs_chown> but if C<path> is a symlink then
3878 the link itself is changed, not the target.
3879
3880 Only numeric uid and gid are supported.  If you want to use
3881 names, you will need to locate and parse the password file
3882 yourself (Augeas support makes this relatively easy).");
3883
3884   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3885    [], (* XXX *)
3886    "lstat on multiple files",
3887    "\
3888 This call allows you to perform the C<guestfs_lstat> operation
3889 on multiple files, where all files are in the directory C<path>.
3890 C<names> is the list of files from this directory.
3891
3892 On return you get a list of stat structs, with a one-to-one
3893 correspondence to the C<names> list.  If any name did not exist
3894 or could not be lstat'd, then the C<ino> field of that structure
3895 is set to C<-1>.
3896
3897 This call is intended for programs that want to efficiently
3898 list a directory contents without making many round-trips.
3899 See also C<guestfs_lxattrlist> for a similarly efficient call
3900 for getting extended attributes.  Very long directory listings
3901 might cause the protocol message size to be exceeded, causing
3902 this call to fail.  The caller must split up such requests
3903 into smaller groups of names.");
3904
3905   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3906    [], (* XXX *)
3907    "lgetxattr on multiple files",
3908    "\
3909 This call allows you to get the extended attributes
3910 of multiple files, where all files are in the directory C<path>.
3911 C<names> is the list of files from this directory.
3912
3913 On return you get a flat list of xattr structs which must be
3914 interpreted sequentially.  The first xattr struct always has a zero-length
3915 C<attrname>.  C<attrval> in this struct is zero-length
3916 to indicate there was an error doing C<lgetxattr> for this
3917 file, I<or> is a C string which is a decimal number
3918 (the number of following attributes for this file, which could
3919 be C<\"0\">).  Then after the first xattr struct are the
3920 zero or more attributes for the first named file.
3921 This repeats for the second and subsequent files.
3922
3923 This call is intended for programs that want to efficiently
3924 list a directory contents without making many round-trips.
3925 See also C<guestfs_lstatlist> for a similarly efficient call
3926 for getting standard stats.  Very long directory listings
3927 might cause the protocol message size to be exceeded, causing
3928 this call to fail.  The caller must split up such requests
3929 into smaller groups of names.");
3930
3931   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
3932    [], (* XXX *)
3933    "readlink on multiple files",
3934    "\
3935 This call allows you to do a C<readlink> operation
3936 on multiple files, where all files are in the directory C<path>.
3937 C<names> is the list of files from this directory.
3938
3939 On return you get a list of strings, with a one-to-one
3940 correspondence to the C<names> list.  Each string is the
3941 value of the symbol link.
3942
3943 If the C<readlink(2)> operation fails on any name, then
3944 the corresponding result string is the empty string C<\"\">.
3945 However the whole operation is completed even if there
3946 were C<readlink(2)> errors, and so you can call this
3947 function with names where you don't know if they are
3948 symbolic links already (albeit slightly less efficient).
3949
3950 This call is intended for programs that want to efficiently
3951 list a directory contents without making many round-trips.
3952 Very long directory listings might cause the protocol
3953 message size to be exceeded, causing
3954 this call to fail.  The caller must split up such requests
3955 into smaller groups of names.");
3956
3957   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
3958    [InitISOFS, Always, TestOutputBuffer (
3959       [["pread"; "/known-4"; "1"; "3"]], "\n");
3960     InitISOFS, Always, TestOutputBuffer (
3961       [["pread"; "/empty"; "0"; "100"]], "")],
3962    "read part of a file",
3963    "\
3964 This command lets you read part of a file.  It reads C<count>
3965 bytes of the file, starting at C<offset>, from file C<path>.
3966
3967 This may read fewer bytes than requested.  For further details
3968 see the L<pread(2)> system call.");
3969
3970   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
3971    [InitEmpty, Always, TestRun (
3972       [["part_init"; "/dev/sda"; "gpt"]])],
3973    "create an empty partition table",
3974    "\
3975 This creates an empty partition table on C<device> of one of the
3976 partition types listed below.  Usually C<parttype> should be
3977 either C<msdos> or C<gpt> (for large disks).
3978
3979 Initially there are no partitions.  Following this, you should
3980 call C<guestfs_part_add> for each partition required.
3981
3982 Possible values for C<parttype> are:
3983
3984 =over 4
3985
3986 =item B<efi> | B<gpt>
3987
3988 Intel EFI / GPT partition table.
3989
3990 This is recommended for >= 2 TB partitions that will be accessed
3991 from Linux and Intel-based Mac OS X.  It also has limited backwards
3992 compatibility with the C<mbr> format.
3993
3994 =item B<mbr> | B<msdos>
3995
3996 The standard PC \"Master Boot Record\" (MBR) format used
3997 by MS-DOS and Windows.  This partition type will B<only> work
3998 for device sizes up to 2 TB.  For large disks we recommend
3999 using C<gpt>.
4000
4001 =back
4002
4003 Other partition table types that may work but are not
4004 supported include:
4005
4006 =over 4
4007
4008 =item B<aix>
4009
4010 AIX disk labels.
4011
4012 =item B<amiga> | B<rdb>
4013
4014 Amiga \"Rigid Disk Block\" format.
4015
4016 =item B<bsd>
4017
4018 BSD disk labels.
4019
4020 =item B<dasd>
4021
4022 DASD, used on IBM mainframes.
4023
4024 =item B<dvh>
4025
4026 MIPS/SGI volumes.
4027
4028 =item B<mac>
4029
4030 Old Mac partition format.  Modern Macs use C<gpt>.
4031
4032 =item B<pc98>
4033
4034 NEC PC-98 format, common in Japan apparently.
4035
4036 =item B<sun>
4037
4038 Sun disk labels.
4039
4040 =back");
4041
4042   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
4043    [InitEmpty, Always, TestRun (
4044       [["part_init"; "/dev/sda"; "mbr"];
4045        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
4046     InitEmpty, Always, TestRun (
4047       [["part_init"; "/dev/sda"; "gpt"];
4048        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
4049        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
4050     InitEmpty, Always, TestRun (
4051       [["part_init"; "/dev/sda"; "mbr"];
4052        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
4053        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4054        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4055        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4056    "add a partition to the device",
4057    "\
4058 This command adds a partition to C<device>.  If there is no partition
4059 table on the device, call C<guestfs_part_init> first.
4060
4061 The C<prlogex> parameter is the type of partition.  Normally you
4062 should pass C<p> or C<primary> here, but MBR partition tables also
4063 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4064 types.
4065
4066 C<startsect> and C<endsect> are the start and end of the partition
4067 in I<sectors>.  C<endsect> may be negative, which means it counts
4068 backwards from the end of the disk (C<-1> is the last sector).
4069
4070 Creating a partition which covers the whole disk is not so easy.
4071 Use C<guestfs_part_disk> to do that.");
4072
4073   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4074    [InitEmpty, Always, TestRun (
4075       [["part_disk"; "/dev/sda"; "mbr"]]);
4076     InitEmpty, Always, TestRun (
4077       [["part_disk"; "/dev/sda"; "gpt"]])],
4078    "partition whole disk with a single primary partition",
4079    "\
4080 This command is simply a combination of C<guestfs_part_init>
4081 followed by C<guestfs_part_add> to create a single primary partition
4082 covering the whole disk.
4083
4084 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4085 but other possible values are described in C<guestfs_part_init>.");
4086
4087   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4088    [InitEmpty, Always, TestRun (
4089       [["part_disk"; "/dev/sda"; "mbr"];
4090        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4091    "make a partition bootable",
4092    "\
4093 This sets the bootable flag on partition numbered C<partnum> on
4094 device C<device>.  Note that partitions are numbered from 1.
4095
4096 The bootable flag is used by some PC BIOSes to determine which
4097 partition to boot from.  It is by no means universally recognized,
4098 and in any case if your operating system installed a boot
4099 sector on the device itself, then that takes precedence.");
4100
4101   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4102    [InitEmpty, Always, TestRun (
4103       [["part_disk"; "/dev/sda"; "gpt"];
4104        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4105    "set partition name",
4106    "\
4107 This sets the partition name on partition numbered C<partnum> on
4108 device C<device>.  Note that partitions are numbered from 1.
4109
4110 The partition name can only be set on certain types of partition
4111 table.  This works on C<gpt> but not on C<mbr> partitions.");
4112
4113   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4114    [], (* XXX Add a regression test for this. *)
4115    "list partitions on a device",
4116    "\
4117 This command parses the partition table on C<device> and
4118 returns the list of partitions found.
4119
4120 The fields in the returned structure are:
4121
4122 =over 4
4123
4124 =item B<part_num>
4125
4126 Partition number, counting from 1.
4127
4128 =item B<part_start>
4129
4130 Start of the partition I<in bytes>.  To get sectors you have to
4131 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4132
4133 =item B<part_end>
4134
4135 End of the partition in bytes.
4136
4137 =item B<part_size>
4138
4139 Size of the partition in bytes.
4140
4141 =back");
4142
4143   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4144    [InitEmpty, Always, TestOutput (
4145       [["part_disk"; "/dev/sda"; "gpt"];
4146        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4147    "get the partition table type",
4148    "\
4149 This command examines the partition table on C<device> and
4150 returns the partition table type (format) being used.
4151
4152 Common return values include: C<msdos> (a DOS/Windows style MBR
4153 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4154 values are possible, although unusual.  See C<guestfs_part_init>
4155 for a full list.");
4156
4157   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4158    [InitBasicFS, Always, TestOutputBuffer (
4159       [["fill"; "0x63"; "10"; "/test"];
4160        ["read_file"; "/test"]], "cccccccccc")],
4161    "fill a file with octets",
4162    "\
4163 This command creates a new file called C<path>.  The initial
4164 content of the file is C<len> octets of C<c>, where C<c>
4165 must be a number in the range C<[0..255]>.
4166
4167 To fill a file with zero bytes (sparsely), it is
4168 much more efficient to use C<guestfs_truncate_size>.");
4169
4170   ("available", (RErr, [StringList "groups"]), 216, [],
4171    [InitNone, Always, TestRun [["available"; ""]]],
4172    "test availability of some parts of the API",
4173    "\
4174 This command is used to check the availability of some
4175 groups of functionality in the appliance, which not all builds of
4176 the libguestfs appliance will be able to provide.
4177
4178 The libguestfs groups, and the functions that those
4179 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4180
4181 The argument C<groups> is a list of group names, eg:
4182 C<[\"inotify\", \"augeas\"]> would check for the availability of
4183 the Linux inotify functions and Augeas (configuration file
4184 editing) functions.
4185
4186 The command returns no error if I<all> requested groups are available.
4187
4188 It fails with an error if one or more of the requested
4189 groups is unavailable in the appliance.
4190
4191 If an unknown group name is included in the
4192 list of groups then an error is always returned.
4193
4194 I<Notes:>
4195
4196 =over 4
4197
4198 =item *
4199
4200 You must call C<guestfs_launch> before calling this function.
4201
4202 The reason is because we don't know what groups are
4203 supported by the appliance/daemon until it is running and can
4204 be queried.
4205
4206 =item *
4207
4208 If a group of functions is available, this does not necessarily
4209 mean that they will work.  You still have to check for errors
4210 when calling individual API functions even if they are
4211 available.
4212
4213 =item *
4214
4215 It is usually the job of distro packagers to build
4216 complete functionality into the libguestfs appliance.
4217 Upstream libguestfs, if built from source with all
4218 requirements satisfied, will support everything.
4219
4220 =item *
4221
4222 This call was added in version C<1.0.80>.  In previous
4223 versions of libguestfs all you could do would be to speculatively
4224 execute a command to find out if the daemon implemented it.
4225 See also C<guestfs_version>.
4226
4227 =back");
4228
4229   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4230    [InitBasicFS, Always, TestOutputBuffer (
4231       [["write_file"; "/src"; "hello, world"; "0"];
4232        ["dd"; "/src"; "/dest"];
4233        ["read_file"; "/dest"]], "hello, world")],
4234    "copy from source to destination using dd",
4235    "\
4236 This command copies from one source device or file C<src>
4237 to another destination device or file C<dest>.  Normally you
4238 would use this to copy to or from a device or partition, for
4239 example to duplicate a filesystem.
4240
4241 If the destination is a device, it must be as large or larger
4242 than the source file or device, otherwise the copy will fail.
4243 This command cannot do partial copies.");
4244
4245   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4246    [InitBasicFS, Always, TestOutputInt (
4247       [["write_file"; "/file"; "hello, world"; "0"];
4248        ["filesize"; "/file"]], 12)],
4249    "return the size of the file in bytes",
4250    "\
4251 This command returns the size of C<file> in bytes.
4252
4253 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4254 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4255 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4256
4257   ("lvrename", (RErr, [String "logvol"; String "newlogvol"]), 219, [],
4258    [InitBasicFSonLVM, Always, TestOutputList (
4259       [["lvrename"; "/dev/VG/LV"; "/dev/VG/LV2"];
4260        ["lvs"]], ["/dev/VG/LV2"])],
4261    "rename an LVM logical volume",
4262    "\
4263 Rename a logical volume C<logvol> with the new name C<newlogvol>.");
4264
4265   ("vgrename", (RErr, [String "volgroup"; String "newvolgroup"]), 220, [],
4266    [InitBasicFSonLVM, Always, TestOutputList (
4267       [["umount"; "/"];
4268        ["vg_activate"; "false"; "VG"];
4269        ["vgrename"; "VG"; "VG2"];
4270        ["vg_activate"; "true"; "VG2"];
4271        ["mount_options"; ""; "/dev/VG2/LV"; "/"];
4272        ["vgs"]], ["VG2"])],
4273    "rename an LVM volume group",
4274    "\
4275 Rename a volume group C<volgroup> with the new name C<newvolgroup>.");
4276
4277   ("initrd_cat", (RBufferOut "content", [Pathname "initrdpath"; String "filename"]), 221, [ProtocolLimitWarning],
4278    [InitISOFS, Always, TestOutputBuffer (
4279       [["initrd_cat"; "/initrd"; "known-4"]], "abc\ndef\nghi")],
4280    "list the contents of a single file in an initrd",
4281    "\
4282 This command unpacks the file C<filename> from the initrd file
4283 called C<initrdpath>.  The filename must be given I<without> the
4284 initial C</> character.
4285
4286 For example, in guestfish you could use the following command
4287 to examine the boot script (usually called C</init>)
4288 contained in a Linux initrd or initramfs image:
4289
4290  initrd-cat /boot/initrd-<version>.img init
4291
4292 See also C<guestfs_initrd_list>.");
4293
4294   ("pvuuid", (RString "uuid", [Device "device"]), 222, [],
4295    [],
4296    "get the UUID of a physical volume",
4297    "\
4298 This command returns the UUID of the LVM PV C<device>.");
4299
4300   ("vguuid", (RString "uuid", [String "vgname"]), 223, [],
4301    [],
4302    "get the UUID of a volume group",
4303    "\
4304 This command returns the UUID of the LVM VG named C<vgname>.");
4305
4306   ("lvuuid", (RString "uuid", [Device "device"]), 224, [],
4307    [],
4308    "get the UUID of a logical volume",
4309    "\
4310 This command returns the UUID of the LVM LV C<device>.");
4311
4312   ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [],
4313    [],
4314    "get the PV UUIDs containing the volume group",
4315    "\
4316 Given a VG called C<vgname>, this returns the UUIDs of all
4317 the physical volumes that this volume group resides on.
4318
4319 You can use this along with C<guestfs_pvs> and C<guestfs_pvuuid>
4320 calls to associate physical volumes and volume groups.
4321
4322 See also C<guestfs_vglvuuids>.");
4323
4324   ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [],
4325    [],
4326    "get the LV UUIDs of all LVs in the volume group",
4327    "\
4328 Given a VG called C<vgname>, this returns the UUIDs of all
4329 the logical volumes created in this volume group.
4330
4331 You can use this along with C<guestfs_lvs> and C<guestfs_lvuuid>
4332 calls to associate logical volumes and volume groups.
4333
4334 See also C<guestfs_vgpvuuids>.");
4335
4336 ]
4337
4338 let all_functions = non_daemon_functions @ daemon_functions
4339
4340 (* In some places we want the functions to be displayed sorted
4341  * alphabetically, so this is useful:
4342  *)
4343 let all_functions_sorted =
4344   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4345                compare n1 n2) all_functions
4346
4347 (* Field types for structures. *)
4348 type field =
4349   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4350   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4351   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4352   | FUInt32
4353   | FInt32
4354   | FUInt64
4355   | FInt64
4356   | FBytes                      (* Any int measure that counts bytes. *)
4357   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4358   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4359
4360 (* Because we generate extra parsing code for LVM command line tools,
4361  * we have to pull out the LVM columns separately here.
4362  *)
4363 let lvm_pv_cols = [
4364   "pv_name", FString;
4365   "pv_uuid", FUUID;
4366   "pv_fmt", FString;
4367   "pv_size", FBytes;
4368   "dev_size", FBytes;
4369   "pv_free", FBytes;
4370   "pv_used", FBytes;
4371   "pv_attr", FString (* XXX *);
4372   "pv_pe_count", FInt64;
4373   "pv_pe_alloc_count", FInt64;
4374   "pv_tags", FString;
4375   "pe_start", FBytes;
4376   "pv_mda_count", FInt64;
4377   "pv_mda_free", FBytes;
4378   (* Not in Fedora 10:
4379      "pv_mda_size", FBytes;
4380   *)
4381 ]
4382 let lvm_vg_cols = [
4383   "vg_name", FString;
4384   "vg_uuid", FUUID;
4385   "vg_fmt", FString;
4386   "vg_attr", FString (* XXX *);
4387   "vg_size", FBytes;
4388   "vg_free", FBytes;
4389   "vg_sysid", FString;
4390   "vg_extent_size", FBytes;
4391   "vg_extent_count", FInt64;
4392   "vg_free_count", FInt64;
4393   "max_lv", FInt64;
4394   "max_pv", FInt64;
4395   "pv_count", FInt64;
4396   "lv_count", FInt64;
4397   "snap_count", FInt64;
4398   "vg_seqno", FInt64;
4399   "vg_tags", FString;
4400   "vg_mda_count", FInt64;
4401   "vg_mda_free", FBytes;
4402   (* Not in Fedora 10:
4403      "vg_mda_size", FBytes;
4404   *)
4405 ]
4406 let lvm_lv_cols = [
4407   "lv_name", FString;
4408   "lv_uuid", FUUID;
4409   "lv_attr", FString (* XXX *);
4410   "lv_major", FInt64;
4411   "lv_minor", FInt64;
4412   "lv_kernel_major", FInt64;
4413   "lv_kernel_minor", FInt64;
4414   "lv_size", FBytes;
4415   "seg_count", FInt64;
4416   "origin", FString;
4417   "snap_percent", FOptPercent;
4418   "copy_percent", FOptPercent;
4419   "move_pv", FString;
4420   "lv_tags", FString;
4421   "mirror_log", FString;
4422   "modules", FString;
4423 ]
4424
4425 (* Names and fields in all structures (in RStruct and RStructList)
4426  * that we support.
4427  *)
4428 let structs = [
4429   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4430    * not use this struct in any new code.
4431    *)
4432   "int_bool", [
4433     "i", FInt32;                (* for historical compatibility *)
4434     "b", FInt32;                (* for historical compatibility *)
4435   ];
4436
4437   (* LVM PVs, VGs, LVs. *)
4438   "lvm_pv", lvm_pv_cols;
4439   "lvm_vg", lvm_vg_cols;
4440   "lvm_lv", lvm_lv_cols;
4441
4442   (* Column names and types from stat structures.
4443    * NB. Can't use things like 'st_atime' because glibc header files
4444    * define some of these as macros.  Ugh.
4445    *)
4446   "stat", [
4447     "dev", FInt64;
4448     "ino", FInt64;
4449     "mode", FInt64;
4450     "nlink", FInt64;
4451     "uid", FInt64;
4452     "gid", FInt64;
4453     "rdev", FInt64;
4454     "size", FInt64;
4455     "blksize", FInt64;
4456     "blocks", FInt64;
4457     "atime", FInt64;
4458     "mtime", FInt64;
4459     "ctime", FInt64;
4460   ];
4461   "statvfs", [
4462     "bsize", FInt64;
4463     "frsize", FInt64;
4464     "blocks", FInt64;
4465     "bfree", FInt64;
4466     "bavail", FInt64;
4467     "files", FInt64;
4468     "ffree", FInt64;
4469     "favail", FInt64;
4470     "fsid", FInt64;
4471     "flag", FInt64;
4472     "namemax", FInt64;
4473   ];
4474
4475   (* Column names in dirent structure. *)
4476   "dirent", [
4477     "ino", FInt64;
4478     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4479     "ftyp", FChar;
4480     "name", FString;
4481   ];
4482
4483   (* Version numbers. *)
4484   "version", [
4485     "major", FInt64;
4486     "minor", FInt64;
4487     "release", FInt64;
4488     "extra", FString;
4489   ];
4490
4491   (* Extended attribute. *)
4492   "xattr", [
4493     "attrname", FString;
4494     "attrval", FBuffer;
4495   ];
4496
4497   (* Inotify events. *)
4498   "inotify_event", [
4499     "in_wd", FInt64;
4500     "in_mask", FUInt32;
4501     "in_cookie", FUInt32;
4502     "in_name", FString;
4503   ];
4504
4505   (* Partition table entry. *)
4506   "partition", [
4507     "part_num", FInt32;
4508     "part_start", FBytes;
4509     "part_end", FBytes;
4510     "part_size", FBytes;
4511   ];
4512 ] (* end of structs *)
4513
4514 (* Ugh, Java has to be different ..
4515  * These names are also used by the Haskell bindings.
4516  *)
4517 let java_structs = [
4518   "int_bool", "IntBool";
4519   "lvm_pv", "PV";
4520   "lvm_vg", "VG";
4521   "lvm_lv", "LV";
4522   "stat", "Stat";
4523   "statvfs", "StatVFS";
4524   "dirent", "Dirent";
4525   "version", "Version";
4526   "xattr", "XAttr";
4527   "inotify_event", "INotifyEvent";
4528   "partition", "Partition";
4529 ]
4530
4531 (* What structs are actually returned. *)
4532 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4533
4534 (* Returns a list of RStruct/RStructList structs that are returned
4535  * by any function.  Each element of returned list is a pair:
4536  *
4537  * (structname, RStructOnly)
4538  *    == there exists function which returns RStruct (_, structname)
4539  * (structname, RStructListOnly)
4540  *    == there exists function which returns RStructList (_, structname)
4541  * (structname, RStructAndList)
4542  *    == there are functions returning both RStruct (_, structname)
4543  *                                      and RStructList (_, structname)
4544  *)
4545 let rstructs_used_by functions =
4546   (* ||| is a "logical OR" for rstructs_used_t *)
4547   let (|||) a b =
4548     match a, b with
4549     | RStructAndList, _
4550     | _, RStructAndList -> RStructAndList
4551     | RStructOnly, RStructListOnly
4552     | RStructListOnly, RStructOnly -> RStructAndList
4553     | RStructOnly, RStructOnly -> RStructOnly
4554     | RStructListOnly, RStructListOnly -> RStructListOnly
4555   in
4556
4557   let h = Hashtbl.create 13 in
4558
4559   (* if elem->oldv exists, update entry using ||| operator,
4560    * else just add elem->newv to the hash
4561    *)
4562   let update elem newv =
4563     try  let oldv = Hashtbl.find h elem in
4564          Hashtbl.replace h elem (newv ||| oldv)
4565     with Not_found -> Hashtbl.add h elem newv
4566   in
4567
4568   List.iter (
4569     fun (_, style, _, _, _, _, _) ->
4570       match fst style with
4571       | RStruct (_, structname) -> update structname RStructOnly
4572       | RStructList (_, structname) -> update structname RStructListOnly
4573       | _ -> ()
4574   ) functions;
4575
4576   (* return key->values as a list of (key,value) *)
4577   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4578
4579 (* Used for testing language bindings. *)
4580 type callt =
4581   | CallString of string
4582   | CallOptString of string option
4583   | CallStringList of string list
4584   | CallInt of int
4585   | CallInt64 of int64
4586   | CallBool of bool
4587
4588 (* Used to memoize the result of pod2text. *)
4589 let pod2text_memo_filename = "src/.pod2text.data"
4590 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4591   try
4592     let chan = open_in pod2text_memo_filename in
4593     let v = input_value chan in
4594     close_in chan;
4595     v
4596   with
4597     _ -> Hashtbl.create 13
4598 let pod2text_memo_updated () =
4599   let chan = open_out pod2text_memo_filename in
4600   output_value chan pod2text_memo;
4601   close_out chan
4602
4603 (* Useful functions.
4604  * Note we don't want to use any external OCaml libraries which
4605  * makes this a bit harder than it should be.
4606  *)
4607 module StringMap = Map.Make (String)
4608
4609 let failwithf fs = ksprintf failwith fs
4610
4611 let unique = let i = ref 0 in fun () -> incr i; !i
4612
4613 let replace_char s c1 c2 =
4614   let s2 = String.copy s in
4615   let r = ref false in
4616   for i = 0 to String.length s2 - 1 do
4617     if String.unsafe_get s2 i = c1 then (
4618       String.unsafe_set s2 i c2;
4619       r := true
4620     )
4621   done;
4622   if not !r then s else s2
4623
4624 let isspace c =
4625   c = ' '
4626   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4627
4628 let triml ?(test = isspace) str =
4629   let i = ref 0 in
4630   let n = ref (String.length str) in
4631   while !n > 0 && test str.[!i]; do
4632     decr n;
4633     incr i
4634   done;
4635   if !i = 0 then str
4636   else String.sub str !i !n
4637
4638 let trimr ?(test = isspace) str =
4639   let n = ref (String.length str) in
4640   while !n > 0 && test str.[!n-1]; do
4641     decr n
4642   done;
4643   if !n = String.length str then str
4644   else String.sub str 0 !n
4645
4646 let trim ?(test = isspace) str =
4647   trimr ~test (triml ~test str)
4648
4649 let rec find s sub =
4650   let len = String.length s in
4651   let sublen = String.length sub in
4652   let rec loop i =
4653     if i <= len-sublen then (
4654       let rec loop2 j =
4655         if j < sublen then (
4656           if s.[i+j] = sub.[j] then loop2 (j+1)
4657           else -1
4658         ) else
4659           i (* found *)
4660       in
4661       let r = loop2 0 in
4662       if r = -1 then loop (i+1) else r
4663     ) else
4664       -1 (* not found *)
4665   in
4666   loop 0
4667
4668 let rec replace_str s s1 s2 =
4669   let len = String.length s in
4670   let sublen = String.length s1 in
4671   let i = find s s1 in
4672   if i = -1 then s
4673   else (
4674     let s' = String.sub s 0 i in
4675     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4676     s' ^ s2 ^ replace_str s'' s1 s2
4677   )
4678
4679 let rec string_split sep str =
4680   let len = String.length str in
4681   let seplen = String.length sep in
4682   let i = find str sep in
4683   if i = -1 then [str]
4684   else (
4685     let s' = String.sub str 0 i in
4686     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4687     s' :: string_split sep s''
4688   )
4689
4690 let files_equal n1 n2 =
4691   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4692   match Sys.command cmd with
4693   | 0 -> true
4694   | 1 -> false
4695   | i -> failwithf "%s: failed with error code %d" cmd i
4696
4697 let rec filter_map f = function
4698   | [] -> []
4699   | x :: xs ->
4700       match f x with
4701       | Some y -> y :: filter_map f xs
4702       | None -> filter_map f xs
4703
4704 let rec find_map f = function
4705   | [] -> raise Not_found
4706   | x :: xs ->
4707       match f x with
4708       | Some y -> y
4709       | None -> find_map f xs
4710
4711 let iteri f xs =
4712   let rec loop i = function
4713     | [] -> ()
4714     | x :: xs -> f i x; loop (i+1) xs
4715   in
4716   loop 0 xs
4717
4718 let mapi f xs =
4719   let rec loop i = function
4720     | [] -> []
4721     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4722   in
4723   loop 0 xs
4724
4725 let count_chars c str =
4726   let count = ref 0 in
4727   for i = 0 to String.length str - 1 do
4728     if c = String.unsafe_get str i then incr count
4729   done;
4730   !count
4731
4732 let name_of_argt = function
4733   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4734   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4735   | FileIn n | FileOut n -> n
4736
4737 let java_name_of_struct typ =
4738   try List.assoc typ java_structs
4739   with Not_found ->
4740     failwithf
4741       "java_name_of_struct: no java_structs entry corresponding to %s" typ
4742
4743 let cols_of_struct typ =
4744   try List.assoc typ structs
4745   with Not_found ->
4746     failwithf "cols_of_struct: unknown struct %s" typ
4747
4748 let seq_of_test = function
4749   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
4750   | TestOutputListOfDevices (s, _)
4751   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
4752   | TestOutputTrue s | TestOutputFalse s
4753   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
4754   | TestOutputStruct (s, _)
4755   | TestLastFail s -> s
4756
4757 (* Handling for function flags. *)
4758 let protocol_limit_warning =
4759   "Because of the message protocol, there is a transfer limit
4760 of somewhere between 2MB and 4MB.  See L<guestfs(3)/PROTOCOL LIMITS>."
4761
4762 let danger_will_robinson =
4763   "B<This command is dangerous.  Without careful use you
4764 can easily destroy all your data>."
4765
4766 let deprecation_notice flags =
4767   try
4768     let alt =
4769       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
4770     let txt =
4771       sprintf "This function is deprecated.
4772 In new code, use the C<%s> call instead.
4773
4774 Deprecated functions will not be removed from the API, but the
4775 fact that they are deprecated indicates that there are problems
4776 with correct use of these functions." alt in
4777     Some txt
4778   with
4779     Not_found -> None
4780
4781 (* Create list of optional groups. *)
4782 let optgroups =
4783   let h = Hashtbl.create 13 in
4784   List.iter (
4785     fun (name, _, _, flags, _, _, _) ->
4786       List.iter (
4787         function
4788         | Optional group ->
4789             let names = try Hashtbl.find h group with Not_found -> [] in
4790             Hashtbl.replace h group (name :: names)
4791         | _ -> ()
4792       ) flags
4793   ) daemon_functions;
4794   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
4795   let groups =
4796     List.map (
4797       fun group -> group, List.sort compare (Hashtbl.find h group)
4798     ) groups in
4799   List.sort (fun x y -> compare (fst x) (fst y)) groups
4800
4801 (* Check function names etc. for consistency. *)
4802 let check_functions () =
4803   let contains_uppercase str =
4804     let len = String.length str in
4805     let rec loop i =
4806       if i >= len then false
4807       else (
4808         let c = str.[i] in
4809         if c >= 'A' && c <= 'Z' then true
4810         else loop (i+1)
4811       )
4812     in
4813     loop 0
4814   in
4815
4816   (* Check function names. *)
4817   List.iter (
4818     fun (name, _, _, _, _, _, _) ->
4819       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
4820         failwithf "function name %s does not need 'guestfs' prefix" name;
4821       if name = "" then
4822         failwithf "function name is empty";
4823       if name.[0] < 'a' || name.[0] > 'z' then
4824         failwithf "function name %s must start with lowercase a-z" name;
4825       if String.contains name '-' then
4826         failwithf "function name %s should not contain '-', use '_' instead."
4827           name
4828   ) all_functions;
4829
4830   (* Check function parameter/return names. *)
4831   List.iter (
4832     fun (name, style, _, _, _, _, _) ->
4833       let check_arg_ret_name n =
4834         if contains_uppercase n then
4835           failwithf "%s param/ret %s should not contain uppercase chars"
4836             name n;
4837         if String.contains n '-' || String.contains n '_' then
4838           failwithf "%s param/ret %s should not contain '-' or '_'"
4839             name n;
4840         if n = "value" then
4841           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;
4842         if n = "int" || n = "char" || n = "short" || n = "long" then
4843           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
4844         if n = "i" || n = "n" then
4845           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
4846         if n = "argv" || n = "args" then
4847           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
4848
4849         (* List Haskell, OCaml and C keywords here.
4850          * http://www.haskell.org/haskellwiki/Keywords
4851          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
4852          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
4853          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
4854          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
4855          * Omitting _-containing words, since they're handled above.
4856          * Omitting the OCaml reserved word, "val", is ok,
4857          * and saves us from renaming several parameters.
4858          *)
4859         let reserved = [
4860           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
4861           "char"; "class"; "const"; "constraint"; "continue"; "data";
4862           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
4863           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
4864           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
4865           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
4866           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
4867           "interface";
4868           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
4869           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
4870           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
4871           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
4872           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
4873           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
4874           "volatile"; "when"; "where"; "while";
4875           ] in
4876         if List.mem n reserved then
4877           failwithf "%s has param/ret using reserved word %s" name n;
4878       in
4879
4880       (match fst style with
4881        | RErr -> ()
4882        | RInt n | RInt64 n | RBool n
4883        | RConstString n | RConstOptString n | RString n
4884        | RStringList n | RStruct (n, _) | RStructList (n, _)
4885        | RHashtable n | RBufferOut n ->
4886            check_arg_ret_name n
4887       );
4888       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
4889   ) all_functions;
4890
4891   (* Check short descriptions. *)
4892   List.iter (
4893     fun (name, _, _, _, _, shortdesc, _) ->
4894       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
4895         failwithf "short description of %s should begin with lowercase." name;
4896       let c = shortdesc.[String.length shortdesc-1] in
4897       if c = '\n' || c = '.' then
4898         failwithf "short description of %s should not end with . or \\n." name
4899   ) all_functions;
4900
4901   (* Check long dscriptions. *)
4902   List.iter (
4903     fun (name, _, _, _, _, _, longdesc) ->
4904       if longdesc.[String.length longdesc-1] = '\n' then
4905         failwithf "long description of %s should not end with \\n." name
4906   ) all_functions;
4907
4908   (* Check proc_nrs. *)
4909   List.iter (
4910     fun (name, _, proc_nr, _, _, _, _) ->
4911       if proc_nr <= 0 then
4912         failwithf "daemon function %s should have proc_nr > 0" name
4913   ) daemon_functions;
4914
4915   List.iter (
4916     fun (name, _, proc_nr, _, _, _, _) ->
4917       if proc_nr <> -1 then
4918         failwithf "non-daemon function %s should have proc_nr -1" name
4919   ) non_daemon_functions;
4920
4921   let proc_nrs =
4922     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
4923       daemon_functions in
4924   let proc_nrs =
4925     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
4926   let rec loop = function
4927     | [] -> ()
4928     | [_] -> ()
4929     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
4930         loop rest
4931     | (name1,nr1) :: (name2,nr2) :: _ ->
4932         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
4933           name1 name2 nr1 nr2
4934   in
4935   loop proc_nrs;
4936
4937   (* Check tests. *)
4938   List.iter (
4939     function
4940       (* Ignore functions that have no tests.  We generate a
4941        * warning when the user does 'make check' instead.
4942        *)
4943     | name, _, _, _, [], _, _ -> ()
4944     | name, _, _, _, tests, _, _ ->
4945         let funcs =
4946           List.map (
4947             fun (_, _, test) ->
4948               match seq_of_test test with
4949               | [] ->
4950                   failwithf "%s has a test containing an empty sequence" name
4951               | cmds -> List.map List.hd cmds
4952           ) tests in
4953         let funcs = List.flatten funcs in
4954
4955         let tested = List.mem name funcs in
4956
4957         if not tested then
4958           failwithf "function %s has tests but does not test itself" name
4959   ) all_functions
4960
4961 (* 'pr' prints to the current output file. *)
4962 let chan = ref Pervasives.stdout
4963 let lines = ref 0
4964 let pr fs =
4965   ksprintf
4966     (fun str ->
4967        let i = count_chars '\n' str in
4968        lines := !lines + i;
4969        output_string !chan str
4970     ) fs
4971
4972 let copyright_years =
4973   let this_year = 1900 + (localtime (time ())).tm_year in
4974   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
4975
4976 (* Generate a header block in a number of standard styles. *)
4977 type comment_style =
4978     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
4979 type license = GPLv2plus | LGPLv2plus
4980
4981 let generate_header ?(extra_inputs = []) comment license =
4982   let inputs = "src/generator.ml" :: extra_inputs in
4983   let c = match comment with
4984     | CStyle ->         pr "/* "; " *"
4985     | CPlusPlusStyle -> pr "// "; "//"
4986     | HashStyle ->      pr "# ";  "#"
4987     | OCamlStyle ->     pr "(* "; " *"
4988     | HaskellStyle ->   pr "{- "; "  " in
4989   pr "libguestfs generated file\n";
4990   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
4991   List.iter (pr "%s   %s\n" c) inputs;
4992   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
4993   pr "%s\n" c;
4994   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
4995   pr "%s\n" c;
4996   (match license with
4997    | GPLv2plus ->
4998        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
4999        pr "%s it under the terms of the GNU General Public License as published by\n" c;
5000        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
5001        pr "%s (at your option) any later version.\n" c;
5002        pr "%s\n" c;
5003        pr "%s This program is distributed in the hope that it will be useful,\n" c;
5004        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5005        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
5006        pr "%s GNU General Public License for more details.\n" c;
5007        pr "%s\n" c;
5008        pr "%s You should have received a copy of the GNU General Public License along\n" c;
5009        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
5010        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
5011
5012    | LGPLv2plus ->
5013        pr "%s This library is free software; you can redistribute it and/or\n" c;
5014        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
5015        pr "%s License as published by the Free Software Foundation; either\n" c;
5016        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
5017        pr "%s\n" c;
5018        pr "%s This library is distributed in the hope that it will be useful,\n" c;
5019        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5020        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
5021        pr "%s Lesser General Public License for more details.\n" c;
5022        pr "%s\n" c;
5023        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
5024        pr "%s License along with this library; if not, write to the Free Software\n" c;
5025        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
5026   );
5027   (match comment with
5028    | CStyle -> pr " */\n"
5029    | CPlusPlusStyle
5030    | HashStyle -> ()
5031    | OCamlStyle -> pr " *)\n"
5032    | HaskellStyle -> pr "-}\n"
5033   );
5034   pr "\n"
5035
5036 (* Start of main code generation functions below this line. *)
5037
5038 (* Generate the pod documentation for the C API. *)
5039 let rec generate_actions_pod () =
5040   List.iter (
5041     fun (shortname, style, _, flags, _, _, longdesc) ->
5042       if not (List.mem NotInDocs flags) then (
5043         let name = "guestfs_" ^ shortname in
5044         pr "=head2 %s\n\n" name;
5045         pr " ";
5046         generate_prototype ~extern:false ~handle:"handle" name style;
5047         pr "\n\n";
5048         pr "%s\n\n" longdesc;
5049         (match fst style with
5050          | RErr ->
5051              pr "This function returns 0 on success or -1 on error.\n\n"
5052          | RInt _ ->
5053              pr "On error this function returns -1.\n\n"
5054          | RInt64 _ ->
5055              pr "On error this function returns -1.\n\n"
5056          | RBool _ ->
5057              pr "This function returns a C truth value on success or -1 on error.\n\n"
5058          | RConstString _ ->
5059              pr "This function returns a string, or NULL on error.
5060 The string is owned by the guest handle and must I<not> be freed.\n\n"
5061          | RConstOptString _ ->
5062              pr "This function returns a string which may be NULL.
5063 There is way to return an error from this function.
5064 The string is owned by the guest handle and must I<not> be freed.\n\n"
5065          | RString _ ->
5066              pr "This function returns a string, or NULL on error.
5067 I<The caller must free the returned string after use>.\n\n"
5068          | RStringList _ ->
5069              pr "This function returns a NULL-terminated array of strings
5070 (like L<environ(3)>), or NULL if there was an error.
5071 I<The caller must free the strings and the array after use>.\n\n"
5072          | RStruct (_, typ) ->
5073              pr "This function returns a C<struct guestfs_%s *>,
5074 or NULL if there was an error.
5075 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
5076          | RStructList (_, typ) ->
5077              pr "This function returns a C<struct guestfs_%s_list *>
5078 (see E<lt>guestfs-structs.hE<gt>),
5079 or NULL if there was an error.
5080 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
5081          | RHashtable _ ->
5082              pr "This function returns a NULL-terminated array of
5083 strings, or NULL if there was an error.
5084 The array of strings will always have length C<2n+1>, where
5085 C<n> keys and values alternate, followed by the trailing NULL entry.
5086 I<The caller must free the strings and the array after use>.\n\n"
5087          | RBufferOut _ ->
5088              pr "This function returns a buffer, or NULL on error.
5089 The size of the returned buffer is written to C<*size_r>.
5090 I<The caller must free the returned buffer after use>.\n\n"
5091         );
5092         if List.mem ProtocolLimitWarning flags then
5093           pr "%s\n\n" protocol_limit_warning;
5094         if List.mem DangerWillRobinson flags then
5095           pr "%s\n\n" danger_will_robinson;
5096         match deprecation_notice flags with
5097         | None -> ()
5098         | Some txt -> pr "%s\n\n" txt
5099       )
5100   ) all_functions_sorted
5101
5102 and generate_structs_pod () =
5103   (* Structs documentation. *)
5104   List.iter (
5105     fun (typ, cols) ->
5106       pr "=head2 guestfs_%s\n" typ;
5107       pr "\n";
5108       pr " struct guestfs_%s {\n" typ;
5109       List.iter (
5110         function
5111         | name, FChar -> pr "   char %s;\n" name
5112         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5113         | name, FInt32 -> pr "   int32_t %s;\n" name
5114         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5115         | name, FInt64 -> pr "   int64_t %s;\n" name
5116         | name, FString -> pr "   char *%s;\n" name
5117         | name, FBuffer ->
5118             pr "   /* The next two fields describe a byte array. */\n";
5119             pr "   uint32_t %s_len;\n" name;
5120             pr "   char *%s;\n" name
5121         | name, FUUID ->
5122             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5123             pr "   char %s[32];\n" name
5124         | name, FOptPercent ->
5125             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5126             pr "   float %s;\n" name
5127       ) cols;
5128       pr " };\n";
5129       pr " \n";
5130       pr " struct guestfs_%s_list {\n" typ;
5131       pr "   uint32_t len; /* Number of elements in list. */\n";
5132       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5133       pr " };\n";
5134       pr " \n";
5135       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5136       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5137         typ typ;
5138       pr "\n"
5139   ) structs
5140
5141 and generate_availability_pod () =
5142   (* Availability documentation. *)
5143   pr "=over 4\n";
5144   pr "\n";
5145   List.iter (
5146     fun (group, functions) ->
5147       pr "=item B<%s>\n" group;
5148       pr "\n";
5149       pr "The following functions:\n";
5150       List.iter (pr "L</guestfs_%s>\n") functions;
5151       pr "\n"
5152   ) optgroups;
5153   pr "=back\n";
5154   pr "\n"
5155
5156 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5157  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5158  *
5159  * We have to use an underscore instead of a dash because otherwise
5160  * rpcgen generates incorrect code.
5161  *
5162  * This header is NOT exported to clients, but see also generate_structs_h.
5163  *)
5164 and generate_xdr () =
5165   generate_header CStyle LGPLv2plus;
5166
5167   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5168   pr "typedef string str<>;\n";
5169   pr "\n";
5170
5171   (* Internal structures. *)
5172   List.iter (
5173     function
5174     | typ, cols ->
5175         pr "struct guestfs_int_%s {\n" typ;
5176         List.iter (function
5177                    | name, FChar -> pr "  char %s;\n" name
5178                    | name, FString -> pr "  string %s<>;\n" name
5179                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5180                    | name, FUUID -> pr "  opaque %s[32];\n" name
5181                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5182                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5183                    | name, FOptPercent -> pr "  float %s;\n" name
5184                   ) cols;
5185         pr "};\n";
5186         pr "\n";
5187         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5188         pr "\n";
5189   ) structs;
5190
5191   List.iter (
5192     fun (shortname, style, _, _, _, _, _) ->
5193       let name = "guestfs_" ^ shortname in
5194
5195       (match snd style with
5196        | [] -> ()
5197        | args ->
5198            pr "struct %s_args {\n" name;
5199            List.iter (
5200              function
5201              | Pathname n | Device n | Dev_or_Path n | String n ->
5202                  pr "  string %s<>;\n" n
5203              | OptString n -> pr "  str *%s;\n" n
5204              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5205              | Bool n -> pr "  bool %s;\n" n
5206              | Int n -> pr "  int %s;\n" n
5207              | Int64 n -> pr "  hyper %s;\n" n
5208              | FileIn _ | FileOut _ -> ()
5209            ) args;
5210            pr "};\n\n"
5211       );
5212       (match fst style with
5213        | RErr -> ()
5214        | RInt n ->
5215            pr "struct %s_ret {\n" name;
5216            pr "  int %s;\n" n;
5217            pr "};\n\n"
5218        | RInt64 n ->
5219            pr "struct %s_ret {\n" name;
5220            pr "  hyper %s;\n" n;
5221            pr "};\n\n"
5222        | RBool n ->
5223            pr "struct %s_ret {\n" name;
5224            pr "  bool %s;\n" n;
5225            pr "};\n\n"
5226        | RConstString _ | RConstOptString _ ->
5227            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5228        | RString n ->
5229            pr "struct %s_ret {\n" name;
5230            pr "  string %s<>;\n" n;
5231            pr "};\n\n"
5232        | RStringList n ->
5233            pr "struct %s_ret {\n" name;
5234            pr "  str %s<>;\n" n;
5235            pr "};\n\n"
5236        | RStruct (n, typ) ->
5237            pr "struct %s_ret {\n" name;
5238            pr "  guestfs_int_%s %s;\n" typ n;
5239            pr "};\n\n"
5240        | RStructList (n, typ) ->
5241            pr "struct %s_ret {\n" name;
5242            pr "  guestfs_int_%s_list %s;\n" typ n;
5243            pr "};\n\n"
5244        | RHashtable n ->
5245            pr "struct %s_ret {\n" name;
5246            pr "  str %s<>;\n" n;
5247            pr "};\n\n"
5248        | RBufferOut n ->
5249            pr "struct %s_ret {\n" name;
5250            pr "  opaque %s<>;\n" n;
5251            pr "};\n\n"
5252       );
5253   ) daemon_functions;
5254
5255   (* Table of procedure numbers. *)
5256   pr "enum guestfs_procedure {\n";
5257   List.iter (
5258     fun (shortname, _, proc_nr, _, _, _, _) ->
5259       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5260   ) daemon_functions;
5261   pr "  GUESTFS_PROC_NR_PROCS\n";
5262   pr "};\n";
5263   pr "\n";
5264
5265   (* Having to choose a maximum message size is annoying for several
5266    * reasons (it limits what we can do in the API), but it (a) makes
5267    * the protocol a lot simpler, and (b) provides a bound on the size
5268    * of the daemon which operates in limited memory space.
5269    *)
5270   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5271   pr "\n";
5272
5273   (* Message header, etc. *)
5274   pr "\
5275 /* The communication protocol is now documented in the guestfs(3)
5276  * manpage.
5277  */
5278
5279 const GUESTFS_PROGRAM = 0x2000F5F5;
5280 const GUESTFS_PROTOCOL_VERSION = 1;
5281
5282 /* These constants must be larger than any possible message length. */
5283 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5284 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5285
5286 enum guestfs_message_direction {
5287   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5288   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5289 };
5290
5291 enum guestfs_message_status {
5292   GUESTFS_STATUS_OK = 0,
5293   GUESTFS_STATUS_ERROR = 1
5294 };
5295
5296 const GUESTFS_ERROR_LEN = 256;
5297
5298 struct guestfs_message_error {
5299   string error_message<GUESTFS_ERROR_LEN>;
5300 };
5301
5302 struct guestfs_message_header {
5303   unsigned prog;                     /* GUESTFS_PROGRAM */
5304   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5305   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5306   guestfs_message_direction direction;
5307   unsigned serial;                   /* message serial number */
5308   guestfs_message_status status;
5309 };
5310
5311 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5312
5313 struct guestfs_chunk {
5314   int cancel;                        /* if non-zero, transfer is cancelled */
5315   /* data size is 0 bytes if the transfer has finished successfully */
5316   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5317 };
5318 "
5319
5320 (* Generate the guestfs-structs.h file. *)
5321 and generate_structs_h () =
5322   generate_header CStyle LGPLv2plus;
5323
5324   (* This is a public exported header file containing various
5325    * structures.  The structures are carefully written to have
5326    * exactly the same in-memory format as the XDR structures that
5327    * we use on the wire to the daemon.  The reason for creating
5328    * copies of these structures here is just so we don't have to
5329    * export the whole of guestfs_protocol.h (which includes much
5330    * unrelated and XDR-dependent stuff that we don't want to be
5331    * public, or required by clients).
5332    *
5333    * To reiterate, we will pass these structures to and from the
5334    * client with a simple assignment or memcpy, so the format
5335    * must be identical to what rpcgen / the RFC defines.
5336    *)
5337
5338   (* Public structures. *)
5339   List.iter (
5340     fun (typ, cols) ->
5341       pr "struct guestfs_%s {\n" typ;
5342       List.iter (
5343         function
5344         | name, FChar -> pr "  char %s;\n" name
5345         | name, FString -> pr "  char *%s;\n" name
5346         | name, FBuffer ->
5347             pr "  uint32_t %s_len;\n" name;
5348             pr "  char *%s;\n" name
5349         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5350         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5351         | name, FInt32 -> pr "  int32_t %s;\n" name
5352         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5353         | name, FInt64 -> pr "  int64_t %s;\n" name
5354         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5355       ) cols;
5356       pr "};\n";
5357       pr "\n";
5358       pr "struct guestfs_%s_list {\n" typ;
5359       pr "  uint32_t len;\n";
5360       pr "  struct guestfs_%s *val;\n" typ;
5361       pr "};\n";
5362       pr "\n";
5363       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5364       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5365       pr "\n"
5366   ) structs
5367
5368 (* Generate the guestfs-actions.h file. *)
5369 and generate_actions_h () =
5370   generate_header CStyle LGPLv2plus;
5371   List.iter (
5372     fun (shortname, style, _, _, _, _, _) ->
5373       let name = "guestfs_" ^ shortname in
5374       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5375         name style
5376   ) all_functions
5377
5378 (* Generate the guestfs-internal-actions.h file. *)
5379 and generate_internal_actions_h () =
5380   generate_header CStyle LGPLv2plus;
5381   List.iter (
5382     fun (shortname, style, _, _, _, _, _) ->
5383       let name = "guestfs__" ^ shortname in
5384       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
5385         name style
5386   ) non_daemon_functions
5387
5388 (* Generate the client-side dispatch stubs. *)
5389 and generate_client_actions () =
5390   generate_header CStyle LGPLv2plus;
5391
5392   pr "\
5393 #include <stdio.h>
5394 #include <stdlib.h>
5395 #include <stdint.h>
5396 #include <inttypes.h>
5397
5398 #include \"guestfs.h\"
5399 #include \"guestfs-internal.h\"
5400 #include \"guestfs-internal-actions.h\"
5401 #include \"guestfs_protocol.h\"
5402
5403 #define error guestfs_error
5404 //#define perrorf guestfs_perrorf
5405 #define safe_malloc guestfs_safe_malloc
5406 #define safe_realloc guestfs_safe_realloc
5407 //#define safe_strdup guestfs_safe_strdup
5408 #define safe_memdup guestfs_safe_memdup
5409
5410 /* Check the return message from a call for validity. */
5411 static int
5412 check_reply_header (guestfs_h *g,
5413                     const struct guestfs_message_header *hdr,
5414                     unsigned int proc_nr, unsigned int serial)
5415 {
5416   if (hdr->prog != GUESTFS_PROGRAM) {
5417     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5418     return -1;
5419   }
5420   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5421     error (g, \"wrong protocol version (%%d/%%d)\",
5422            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5423     return -1;
5424   }
5425   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5426     error (g, \"unexpected message direction (%%d/%%d)\",
5427            hdr->direction, GUESTFS_DIRECTION_REPLY);
5428     return -1;
5429   }
5430   if (hdr->proc != proc_nr) {
5431     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5432     return -1;
5433   }
5434   if (hdr->serial != serial) {
5435     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5436     return -1;
5437   }
5438
5439   return 0;
5440 }
5441
5442 /* Check we are in the right state to run a high-level action. */
5443 static int
5444 check_state (guestfs_h *g, const char *caller)
5445 {
5446   if (!guestfs__is_ready (g)) {
5447     if (guestfs__is_config (g) || guestfs__is_launching (g))
5448       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5449         caller);
5450     else
5451       error (g, \"%%s called from the wrong state, %%d != READY\",
5452         caller, guestfs__get_state (g));
5453     return -1;
5454   }
5455   return 0;
5456 }
5457
5458 ";
5459
5460   (* Generate code to generate guestfish call traces. *)
5461   let trace_call shortname style =
5462     pr "  if (guestfs__get_trace (g)) {\n";
5463
5464     let needs_i =
5465       List.exists (function
5466                    | StringList _ | DeviceList _ -> true
5467                    | _ -> false) (snd style) in
5468     if needs_i then (
5469       pr "    int i;\n";
5470       pr "\n"
5471     );
5472
5473     pr "    printf (\"%s\");\n" shortname;
5474     List.iter (
5475       function
5476       | String n                        (* strings *)
5477       | Device n
5478       | Pathname n
5479       | Dev_or_Path n
5480       | FileIn n
5481       | FileOut n ->
5482           (* guestfish doesn't support string escaping, so neither do we *)
5483           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5484       | OptString n ->                  (* string option *)
5485           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5486           pr "    else printf (\" null\");\n"
5487       | StringList n
5488       | DeviceList n ->                 (* string list *)
5489           pr "    putchar (' ');\n";
5490           pr "    putchar ('\"');\n";
5491           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5492           pr "      if (i > 0) putchar (' ');\n";
5493           pr "      fputs (%s[i], stdout);\n" n;
5494           pr "    }\n";
5495           pr "    putchar ('\"');\n";
5496       | Bool n ->                       (* boolean *)
5497           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5498       | Int n ->                        (* int *)
5499           pr "    printf (\" %%d\", %s);\n" n
5500       | Int64 n ->
5501           pr "    printf (\" %%\" PRIi64, %s);\n" n
5502     ) (snd style);
5503     pr "    putchar ('\\n');\n";
5504     pr "  }\n";
5505     pr "\n";
5506   in
5507
5508   (* For non-daemon functions, generate a wrapper around each function. *)
5509   List.iter (
5510     fun (shortname, style, _, _, _, _, _) ->
5511       let name = "guestfs_" ^ shortname in
5512
5513       generate_prototype ~extern:false ~semicolon:false ~newline:true
5514         ~handle:"g" name style;
5515       pr "{\n";
5516       trace_call shortname style;
5517       pr "  return guestfs__%s " shortname;
5518       generate_c_call_args ~handle:"g" style;
5519       pr ";\n";
5520       pr "}\n";
5521       pr "\n"
5522   ) non_daemon_functions;
5523
5524   (* Client-side stubs for each function. *)
5525   List.iter (
5526     fun (shortname, style, _, _, _, _, _) ->
5527       let name = "guestfs_" ^ shortname in
5528
5529       (* Generate the action stub. *)
5530       generate_prototype ~extern:false ~semicolon:false ~newline:true
5531         ~handle:"g" name style;
5532
5533       let error_code =
5534         match fst style with
5535         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5536         | RConstString _ | RConstOptString _ ->
5537             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5538         | RString _ | RStringList _
5539         | RStruct _ | RStructList _
5540         | RHashtable _ | RBufferOut _ ->
5541             "NULL" in
5542
5543       pr "{\n";
5544
5545       (match snd style with
5546        | [] -> ()
5547        | _ -> pr "  struct %s_args args;\n" name
5548       );
5549
5550       pr "  guestfs_message_header hdr;\n";
5551       pr "  guestfs_message_error err;\n";
5552       let has_ret =
5553         match fst style with
5554         | RErr -> false
5555         | RConstString _ | RConstOptString _ ->
5556             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5557         | RInt _ | RInt64 _
5558         | RBool _ | RString _ | RStringList _
5559         | RStruct _ | RStructList _
5560         | RHashtable _ | RBufferOut _ ->
5561             pr "  struct %s_ret ret;\n" name;
5562             true in
5563
5564       pr "  int serial;\n";
5565       pr "  int r;\n";
5566       pr "\n";
5567       trace_call shortname style;
5568       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
5569       pr "  guestfs___set_busy (g);\n";
5570       pr "\n";
5571
5572       (* Send the main header and arguments. *)
5573       (match snd style with
5574        | [] ->
5575            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5576              (String.uppercase shortname)
5577        | args ->
5578            List.iter (
5579              function
5580              | Pathname n | Device n | Dev_or_Path n | String n ->
5581                  pr "  args.%s = (char *) %s;\n" n n
5582              | OptString n ->
5583                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5584              | StringList n | DeviceList n ->
5585                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5586                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5587              | Bool n ->
5588                  pr "  args.%s = %s;\n" n n
5589              | Int n ->
5590                  pr "  args.%s = %s;\n" n n
5591              | Int64 n ->
5592                  pr "  args.%s = %s;\n" n n
5593              | FileIn _ | FileOut _ -> ()
5594            ) args;
5595            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5596              (String.uppercase shortname);
5597            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5598              name;
5599       );
5600       pr "  if (serial == -1) {\n";
5601       pr "    guestfs___end_busy (g);\n";
5602       pr "    return %s;\n" error_code;
5603       pr "  }\n";
5604       pr "\n";
5605
5606       (* Send any additional files (FileIn) requested. *)
5607       let need_read_reply_label = ref false in
5608       List.iter (
5609         function
5610         | FileIn n ->
5611             pr "  r = guestfs___send_file (g, %s);\n" n;
5612             pr "  if (r == -1) {\n";
5613             pr "    guestfs___end_busy (g);\n";
5614             pr "    return %s;\n" error_code;
5615             pr "  }\n";
5616             pr "  if (r == -2) /* daemon cancelled */\n";
5617             pr "    goto read_reply;\n";
5618             need_read_reply_label := true;
5619             pr "\n";
5620         | _ -> ()
5621       ) (snd style);
5622
5623       (* Wait for the reply from the remote end. *)
5624       if !need_read_reply_label then pr " read_reply:\n";
5625       pr "  memset (&hdr, 0, sizeof hdr);\n";
5626       pr "  memset (&err, 0, sizeof err);\n";
5627       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5628       pr "\n";
5629       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5630       if not has_ret then
5631         pr "NULL, NULL"
5632       else
5633         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5634       pr ");\n";
5635
5636       pr "  if (r == -1) {\n";
5637       pr "    guestfs___end_busy (g);\n";
5638       pr "    return %s;\n" error_code;
5639       pr "  }\n";
5640       pr "\n";
5641
5642       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5643         (String.uppercase shortname);
5644       pr "    guestfs___end_busy (g);\n";
5645       pr "    return %s;\n" error_code;
5646       pr "  }\n";
5647       pr "\n";
5648
5649       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5650       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5651       pr "    free (err.error_message);\n";
5652       pr "    guestfs___end_busy (g);\n";
5653       pr "    return %s;\n" error_code;
5654       pr "  }\n";
5655       pr "\n";
5656
5657       (* Expecting to receive further files (FileOut)? *)
5658       List.iter (
5659         function
5660         | FileOut n ->
5661             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5662             pr "    guestfs___end_busy (g);\n";
5663             pr "    return %s;\n" error_code;
5664             pr "  }\n";
5665             pr "\n";
5666         | _ -> ()
5667       ) (snd style);
5668
5669       pr "  guestfs___end_busy (g);\n";
5670
5671       (match fst style with
5672        | RErr -> pr "  return 0;\n"
5673        | RInt n | RInt64 n | RBool n ->
5674            pr "  return ret.%s;\n" n
5675        | RConstString _ | RConstOptString _ ->
5676            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5677        | RString n ->
5678            pr "  return ret.%s; /* caller will free */\n" n
5679        | RStringList n | RHashtable n ->
5680            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5681            pr "  ret.%s.%s_val =\n" n n;
5682            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5683            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5684              n n;
5685            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5686            pr "  return ret.%s.%s_val;\n" n n
5687        | RStruct (n, _) ->
5688            pr "  /* caller will free this */\n";
5689            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5690        | RStructList (n, _) ->
5691            pr "  /* caller will free this */\n";
5692            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5693        | RBufferOut n ->
5694            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5695            pr "   * _val might be NULL here.  To make the API saner for\n";
5696            pr "   * callers, we turn this case into a unique pointer (using\n";
5697            pr "   * malloc(1)).\n";
5698            pr "   */\n";
5699            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5700            pr "    *size_r = ret.%s.%s_len;\n" n n;
5701            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5702            pr "  } else {\n";
5703            pr "    free (ret.%s.%s_val);\n" n n;
5704            pr "    char *p = safe_malloc (g, 1);\n";
5705            pr "    *size_r = ret.%s.%s_len;\n" n n;
5706            pr "    return p;\n";
5707            pr "  }\n";
5708       );
5709
5710       pr "}\n\n"
5711   ) daemon_functions;
5712
5713   (* Functions to free structures. *)
5714   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5715   pr " * structure format is identical to the XDR format.  See note in\n";
5716   pr " * generator.ml.\n";
5717   pr " */\n";
5718   pr "\n";
5719
5720   List.iter (
5721     fun (typ, _) ->
5722       pr "void\n";
5723       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5724       pr "{\n";
5725       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5726       pr "  free (x);\n";
5727       pr "}\n";
5728       pr "\n";
5729
5730       pr "void\n";
5731       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5732       pr "{\n";
5733       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
5734       pr "  free (x);\n";
5735       pr "}\n";
5736       pr "\n";
5737
5738   ) structs;
5739
5740 (* Generate daemon/actions.h. *)
5741 and generate_daemon_actions_h () =
5742   generate_header CStyle GPLv2plus;
5743
5744   pr "#include \"../src/guestfs_protocol.h\"\n";
5745   pr "\n";
5746
5747   List.iter (
5748     fun (name, style, _, _, _, _, _) ->
5749       generate_prototype
5750         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
5751         name style;
5752   ) daemon_functions
5753
5754 (* Generate the linker script which controls the visibility of
5755  * symbols in the public ABI and ensures no other symbols get
5756  * exported accidentally.
5757  *)
5758 and generate_linker_script () =
5759   generate_header HashStyle GPLv2plus;
5760
5761   let globals = [
5762     "guestfs_create";
5763     "guestfs_close";
5764     "guestfs_get_error_handler";
5765     "guestfs_get_out_of_memory_handler";
5766     "guestfs_last_error";
5767     "guestfs_set_error_handler";
5768     "guestfs_set_launch_done_callback";
5769     "guestfs_set_log_message_callback";
5770     "guestfs_set_out_of_memory_handler";
5771     "guestfs_set_subprocess_quit_callback";
5772
5773     (* Unofficial parts of the API: the bindings code use these
5774      * functions, so it is useful to export them.
5775      *)
5776     "guestfs_safe_calloc";
5777     "guestfs_safe_malloc";
5778   ] in
5779   let functions =
5780     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
5781       all_functions in
5782   let structs =
5783     List.concat (
5784       List.map (fun (typ, _) ->
5785                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
5786         structs
5787     ) in
5788   let globals = List.sort compare (globals @ functions @ structs) in
5789
5790   pr "{\n";
5791   pr "    global:\n";
5792   List.iter (pr "        %s;\n") globals;
5793   pr "\n";
5794
5795   pr "    local:\n";
5796   pr "        *;\n";
5797   pr "};\n"
5798
5799 (* Generate the server-side stubs. *)
5800 and generate_daemon_actions () =
5801   generate_header CStyle GPLv2plus;
5802
5803   pr "#include <config.h>\n";
5804   pr "\n";
5805   pr "#include <stdio.h>\n";
5806   pr "#include <stdlib.h>\n";
5807   pr "#include <string.h>\n";
5808   pr "#include <inttypes.h>\n";
5809   pr "#include <rpc/types.h>\n";
5810   pr "#include <rpc/xdr.h>\n";
5811   pr "\n";
5812   pr "#include \"daemon.h\"\n";
5813   pr "#include \"c-ctype.h\"\n";
5814   pr "#include \"../src/guestfs_protocol.h\"\n";
5815   pr "#include \"actions.h\"\n";
5816   pr "\n";
5817
5818   List.iter (
5819     fun (name, style, _, _, _, _, _) ->
5820       (* Generate server-side stubs. *)
5821       pr "static void %s_stub (XDR *xdr_in)\n" name;
5822       pr "{\n";
5823       let error_code =
5824         match fst style with
5825         | RErr | RInt _ -> pr "  int r;\n"; "-1"
5826         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
5827         | RBool _ -> pr "  int r;\n"; "-1"
5828         | RConstString _ | RConstOptString _ ->
5829             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5830         | RString _ -> pr "  char *r;\n"; "NULL"
5831         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
5832         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
5833         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
5834         | RBufferOut _ ->
5835             pr "  size_t size = 1;\n";
5836             pr "  char *r;\n";
5837             "NULL" in
5838
5839       (match snd style with
5840        | [] -> ()
5841        | args ->
5842            pr "  struct guestfs_%s_args args;\n" name;
5843            List.iter (
5844              function
5845              | Device n | Dev_or_Path n
5846              | Pathname n
5847              | String n -> ()
5848              | OptString n -> pr "  char *%s;\n" n
5849              | StringList n | DeviceList n -> pr "  char **%s;\n" n
5850              | Bool n -> pr "  int %s;\n" n
5851              | Int n -> pr "  int %s;\n" n
5852              | Int64 n -> pr "  int64_t %s;\n" n
5853              | FileIn _ | FileOut _ -> ()
5854            ) args
5855       );
5856       pr "\n";
5857
5858       (match snd style with
5859        | [] -> ()
5860        | args ->
5861            pr "  memset (&args, 0, sizeof args);\n";
5862            pr "\n";
5863            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
5864            pr "    reply_with_error (\"daemon failed to decode procedure arguments\");\n";
5865            pr "    return;\n";
5866            pr "  }\n";
5867            let pr_args n =
5868              pr "  char *%s = args.%s;\n" n n
5869            in
5870            let pr_list_handling_code n =
5871              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
5872              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
5873              pr "  if (%s == NULL) {\n" n;
5874              pr "    reply_with_perror (\"realloc\");\n";
5875              pr "    goto done;\n";
5876              pr "  }\n";
5877              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
5878              pr "  args.%s.%s_val = %s;\n" n n n;
5879            in
5880            List.iter (
5881              function
5882              | Pathname n ->
5883                  pr_args n;
5884                  pr "  ABS_PATH (%s, goto done);\n" n;
5885              | Device n ->
5886                  pr_args n;
5887                  pr "  RESOLVE_DEVICE (%s, goto done);\n" n;
5888              | Dev_or_Path n ->
5889                  pr_args n;
5890                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n;
5891              | String n -> pr_args n
5892              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
5893              | StringList n ->
5894                  pr_list_handling_code n;
5895              | DeviceList n ->
5896                  pr_list_handling_code n;
5897                  pr "  /* Ensure that each is a device,\n";
5898                  pr "   * and perform device name translation. */\n";
5899                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
5900                  pr "    RESOLVE_DEVICE (physvols[pvi], goto done);\n";
5901                  pr "  }\n";
5902              | Bool n -> pr "  %s = args.%s;\n" n n
5903              | Int n -> pr "  %s = args.%s;\n" n n
5904              | Int64 n -> pr "  %s = args.%s;\n" n n
5905              | FileIn _ | FileOut _ -> ()
5906            ) args;
5907            pr "\n"
5908       );
5909
5910
5911       (* this is used at least for do_equal *)
5912       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
5913         (* Emit NEED_ROOT just once, even when there are two or
5914            more Pathname args *)
5915         pr "  NEED_ROOT (goto done);\n";
5916       );
5917
5918       (* Don't want to call the impl with any FileIn or FileOut
5919        * parameters, since these go "outside" the RPC protocol.
5920        *)
5921       let args' =
5922         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
5923           (snd style) in
5924       pr "  r = do_%s " name;
5925       generate_c_call_args (fst style, args');
5926       pr ";\n";
5927
5928       (match fst style with
5929        | RErr | RInt _ | RInt64 _ | RBool _
5930        | RConstString _ | RConstOptString _
5931        | RString _ | RStringList _ | RHashtable _
5932        | RStruct (_, _) | RStructList (_, _) ->
5933            pr "  if (r == %s)\n" error_code;
5934            pr "    /* do_%s has already called reply_with_error */\n" name;
5935            pr "    goto done;\n";
5936            pr "\n"
5937        | RBufferOut _ ->
5938            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
5939            pr "   * an ordinary zero-length buffer), so be careful ...\n";
5940            pr "   */\n";
5941            pr "  if (size == 1 && r == %s)\n" error_code;
5942            pr "    /* do_%s has already called reply_with_error */\n" name;
5943            pr "    goto done;\n";
5944            pr "\n"
5945       );
5946
5947       (* If there are any FileOut parameters, then the impl must
5948        * send its own reply.
5949        *)
5950       let no_reply =
5951         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
5952       if no_reply then
5953         pr "  /* do_%s has already sent a reply */\n" name
5954       else (
5955         match fst style with
5956         | RErr -> pr "  reply (NULL, NULL);\n"
5957         | RInt n | RInt64 n | RBool n ->
5958             pr "  struct guestfs_%s_ret ret;\n" name;
5959             pr "  ret.%s = r;\n" n;
5960             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5961               name
5962         | RConstString _ | RConstOptString _ ->
5963             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5964         | RString n ->
5965             pr "  struct guestfs_%s_ret ret;\n" name;
5966             pr "  ret.%s = r;\n" n;
5967             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5968               name;
5969             pr "  free (r);\n"
5970         | RStringList n | RHashtable n ->
5971             pr "  struct guestfs_%s_ret ret;\n" name;
5972             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
5973             pr "  ret.%s.%s_val = r;\n" n n;
5974             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5975               name;
5976             pr "  free_strings (r);\n"
5977         | RStruct (n, _) ->
5978             pr "  struct guestfs_%s_ret ret;\n" name;
5979             pr "  ret.%s = *r;\n" n;
5980             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5981               name;
5982             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5983               name
5984         | RStructList (n, _) ->
5985             pr "  struct guestfs_%s_ret ret;\n" name;
5986             pr "  ret.%s = *r;\n" n;
5987             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5988               name;
5989             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5990               name
5991         | RBufferOut n ->
5992             pr "  struct guestfs_%s_ret ret;\n" name;
5993             pr "  ret.%s.%s_val = r;\n" n n;
5994             pr "  ret.%s.%s_len = size;\n" n n;
5995             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5996               name;
5997             pr "  free (r);\n"
5998       );
5999
6000       (* Free the args. *)
6001       (match snd style with
6002        | [] ->
6003            pr "done: ;\n";
6004        | _ ->
6005            pr "done:\n";
6006            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
6007              name
6008       );
6009
6010       pr "}\n\n";
6011   ) daemon_functions;
6012
6013   (* Dispatch function. *)
6014   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
6015   pr "{\n";
6016   pr "  switch (proc_nr) {\n";
6017
6018   List.iter (
6019     fun (name, style, _, _, _, _, _) ->
6020       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
6021       pr "      %s_stub (xdr_in);\n" name;
6022       pr "      break;\n"
6023   ) daemon_functions;
6024
6025   pr "    default:\n";
6026   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";
6027   pr "  }\n";
6028   pr "}\n";
6029   pr "\n";
6030
6031   (* LVM columns and tokenization functions. *)
6032   (* XXX This generates crap code.  We should rethink how we
6033    * do this parsing.
6034    *)
6035   List.iter (
6036     function
6037     | typ, cols ->
6038         pr "static const char *lvm_%s_cols = \"%s\";\n"
6039           typ (String.concat "," (List.map fst cols));
6040         pr "\n";
6041
6042         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
6043         pr "{\n";
6044         pr "  char *tok, *p, *next;\n";
6045         pr "  int i, j;\n";
6046         pr "\n";
6047         (*
6048           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
6049           pr "\n";
6050         *)
6051         pr "  if (!str) {\n";
6052         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
6053         pr "    return -1;\n";
6054         pr "  }\n";
6055         pr "  if (!*str || c_isspace (*str)) {\n";
6056         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
6057         pr "    return -1;\n";
6058         pr "  }\n";
6059         pr "  tok = str;\n";
6060         List.iter (
6061           fun (name, coltype) ->
6062             pr "  if (!tok) {\n";
6063             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
6064             pr "    return -1;\n";
6065             pr "  }\n";
6066             pr "  p = strchrnul (tok, ',');\n";
6067             pr "  if (*p) next = p+1; else next = NULL;\n";
6068             pr "  *p = '\\0';\n";
6069             (match coltype with
6070              | FString ->
6071                  pr "  r->%s = strdup (tok);\n" name;
6072                  pr "  if (r->%s == NULL) {\n" name;
6073                  pr "    perror (\"strdup\");\n";
6074                  pr "    return -1;\n";
6075                  pr "  }\n"
6076              | FUUID ->
6077                  pr "  for (i = j = 0; i < 32; ++j) {\n";
6078                  pr "    if (tok[j] == '\\0') {\n";
6079                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
6080                  pr "      return -1;\n";
6081                  pr "    } else if (tok[j] != '-')\n";
6082                  pr "      r->%s[i++] = tok[j];\n" name;
6083                  pr "  }\n";
6084              | FBytes ->
6085                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
6086                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6087                  pr "    return -1;\n";
6088                  pr "  }\n";
6089              | FInt64 ->
6090                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
6091                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6092                  pr "    return -1;\n";
6093                  pr "  }\n";
6094              | FOptPercent ->
6095                  pr "  if (tok[0] == '\\0')\n";
6096                  pr "    r->%s = -1;\n" name;
6097                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
6098                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6099                  pr "    return -1;\n";
6100                  pr "  }\n";
6101              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
6102                  assert false (* can never be an LVM column *)
6103             );
6104             pr "  tok = next;\n";
6105         ) cols;
6106
6107         pr "  if (tok != NULL) {\n";
6108         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6109         pr "    return -1;\n";
6110         pr "  }\n";
6111         pr "  return 0;\n";
6112         pr "}\n";
6113         pr "\n";
6114
6115         pr "guestfs_int_lvm_%s_list *\n" typ;
6116         pr "parse_command_line_%ss (void)\n" typ;
6117         pr "{\n";
6118         pr "  char *out, *err;\n";
6119         pr "  char *p, *pend;\n";
6120         pr "  int r, i;\n";
6121         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6122         pr "  void *newp;\n";
6123         pr "\n";
6124         pr "  ret = malloc (sizeof *ret);\n";
6125         pr "  if (!ret) {\n";
6126         pr "    reply_with_perror (\"malloc\");\n";
6127         pr "    return NULL;\n";
6128         pr "  }\n";
6129         pr "\n";
6130         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6131         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6132         pr "\n";
6133         pr "  r = command (&out, &err,\n";
6134         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
6135         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6136         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6137         pr "  if (r == -1) {\n";
6138         pr "    reply_with_error (\"%%s\", err);\n";
6139         pr "    free (out);\n";
6140         pr "    free (err);\n";
6141         pr "    free (ret);\n";
6142         pr "    return NULL;\n";
6143         pr "  }\n";
6144         pr "\n";
6145         pr "  free (err);\n";
6146         pr "\n";
6147         pr "  /* Tokenize each line of the output. */\n";
6148         pr "  p = out;\n";
6149         pr "  i = 0;\n";
6150         pr "  while (p) {\n";
6151         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6152         pr "    if (pend) {\n";
6153         pr "      *pend = '\\0';\n";
6154         pr "      pend++;\n";
6155         pr "    }\n";
6156         pr "\n";
6157         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6158         pr "      p++;\n";
6159         pr "\n";
6160         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6161         pr "      p = pend;\n";
6162         pr "      continue;\n";
6163         pr "    }\n";
6164         pr "\n";
6165         pr "    /* Allocate some space to store this next entry. */\n";
6166         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6167         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6168         pr "    if (newp == NULL) {\n";
6169         pr "      reply_with_perror (\"realloc\");\n";
6170         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6171         pr "      free (ret);\n";
6172         pr "      free (out);\n";
6173         pr "      return NULL;\n";
6174         pr "    }\n";
6175         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6176         pr "\n";
6177         pr "    /* Tokenize the next entry. */\n";
6178         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6179         pr "    if (r == -1) {\n";
6180         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6181         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6182         pr "      free (ret);\n";
6183         pr "      free (out);\n";
6184         pr "      return NULL;\n";
6185         pr "    }\n";
6186         pr "\n";
6187         pr "    ++i;\n";
6188         pr "    p = pend;\n";
6189         pr "  }\n";
6190         pr "\n";
6191         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6192         pr "\n";
6193         pr "  free (out);\n";
6194         pr "  return ret;\n";
6195         pr "}\n"
6196
6197   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6198
6199 (* Generate a list of function names, for debugging in the daemon.. *)
6200 and generate_daemon_names () =
6201   generate_header CStyle GPLv2plus;
6202
6203   pr "#include <config.h>\n";
6204   pr "\n";
6205   pr "#include \"daemon.h\"\n";
6206   pr "\n";
6207
6208   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6209   pr "const char *function_names[] = {\n";
6210   List.iter (
6211     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6212   ) daemon_functions;
6213   pr "};\n";
6214
6215 (* Generate the optional groups for the daemon to implement
6216  * guestfs_available.
6217  *)
6218 and generate_daemon_optgroups_c () =
6219   generate_header CStyle GPLv2plus;
6220
6221   pr "#include <config.h>\n";
6222   pr "\n";
6223   pr "#include \"daemon.h\"\n";
6224   pr "#include \"optgroups.h\"\n";
6225   pr "\n";
6226
6227   pr "struct optgroup optgroups[] = {\n";
6228   List.iter (
6229     fun (group, _) ->
6230       pr "  { \"%s\", optgroup_%s_available },\n" group group
6231   ) optgroups;
6232   pr "  { NULL, NULL }\n";
6233   pr "};\n"
6234
6235 and generate_daemon_optgroups_h () =
6236   generate_header CStyle GPLv2plus;
6237
6238   List.iter (
6239     fun (group, _) ->
6240       pr "extern int optgroup_%s_available (void);\n" group
6241   ) optgroups
6242
6243 (* Generate the tests. *)
6244 and generate_tests () =
6245   generate_header CStyle GPLv2plus;
6246
6247   pr "\
6248 #include <stdio.h>
6249 #include <stdlib.h>
6250 #include <string.h>
6251 #include <unistd.h>
6252 #include <sys/types.h>
6253 #include <fcntl.h>
6254
6255 #include \"guestfs.h\"
6256 #include \"guestfs-internal.h\"
6257
6258 static guestfs_h *g;
6259 static int suppress_error = 0;
6260
6261 static void print_error (guestfs_h *g, void *data, const char *msg)
6262 {
6263   if (!suppress_error)
6264     fprintf (stderr, \"%%s\\n\", msg);
6265 }
6266
6267 /* FIXME: nearly identical code appears in fish.c */
6268 static void print_strings (char *const *argv)
6269 {
6270   int argc;
6271
6272   for (argc = 0; argv[argc] != NULL; ++argc)
6273     printf (\"\\t%%s\\n\", argv[argc]);
6274 }
6275
6276 /*
6277 static void print_table (char const *const *argv)
6278 {
6279   int i;
6280
6281   for (i = 0; argv[i] != NULL; i += 2)
6282     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6283 }
6284 */
6285
6286 ";
6287
6288   (* Generate a list of commands which are not tested anywhere. *)
6289   pr "static void no_test_warnings (void)\n";
6290   pr "{\n";
6291
6292   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6293   List.iter (
6294     fun (_, _, _, _, tests, _, _) ->
6295       let tests = filter_map (
6296         function
6297         | (_, (Always|If _|Unless _), test) -> Some test
6298         | (_, Disabled, _) -> None
6299       ) tests in
6300       let seq = List.concat (List.map seq_of_test tests) in
6301       let cmds_tested = List.map List.hd seq in
6302       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6303   ) all_functions;
6304
6305   List.iter (
6306     fun (name, _, _, _, _, _, _) ->
6307       if not (Hashtbl.mem hash name) then
6308         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6309   ) all_functions;
6310
6311   pr "}\n";
6312   pr "\n";
6313
6314   (* Generate the actual tests.  Note that we generate the tests
6315    * in reverse order, deliberately, so that (in general) the
6316    * newest tests run first.  This makes it quicker and easier to
6317    * debug them.
6318    *)
6319   let test_names =
6320     List.map (
6321       fun (name, _, _, flags, tests, _, _) ->
6322         mapi (generate_one_test name flags) tests
6323     ) (List.rev all_functions) in
6324   let test_names = List.concat test_names in
6325   let nr_tests = List.length test_names in
6326
6327   pr "\
6328 int main (int argc, char *argv[])
6329 {
6330   char c = 0;
6331   unsigned long int n_failed = 0;
6332   const char *filename;
6333   int fd;
6334   int nr_tests, test_num = 0;
6335
6336   setbuf (stdout, NULL);
6337
6338   no_test_warnings ();
6339
6340   g = guestfs_create ();
6341   if (g == NULL) {
6342     printf (\"guestfs_create FAILED\\n\");
6343     exit (EXIT_FAILURE);
6344   }
6345
6346   guestfs_set_error_handler (g, print_error, NULL);
6347
6348   guestfs_set_path (g, \"../appliance\");
6349
6350   filename = \"test1.img\";
6351   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6352   if (fd == -1) {
6353     perror (filename);
6354     exit (EXIT_FAILURE);
6355   }
6356   if (lseek (fd, %d, SEEK_SET) == -1) {
6357     perror (\"lseek\");
6358     close (fd);
6359     unlink (filename);
6360     exit (EXIT_FAILURE);
6361   }
6362   if (write (fd, &c, 1) == -1) {
6363     perror (\"write\");
6364     close (fd);
6365     unlink (filename);
6366     exit (EXIT_FAILURE);
6367   }
6368   if (close (fd) == -1) {
6369     perror (filename);
6370     unlink (filename);
6371     exit (EXIT_FAILURE);
6372   }
6373   if (guestfs_add_drive (g, filename) == -1) {
6374     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6375     exit (EXIT_FAILURE);
6376   }
6377
6378   filename = \"test2.img\";
6379   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6380   if (fd == -1) {
6381     perror (filename);
6382     exit (EXIT_FAILURE);
6383   }
6384   if (lseek (fd, %d, SEEK_SET) == -1) {
6385     perror (\"lseek\");
6386     close (fd);
6387     unlink (filename);
6388     exit (EXIT_FAILURE);
6389   }
6390   if (write (fd, &c, 1) == -1) {
6391     perror (\"write\");
6392     close (fd);
6393     unlink (filename);
6394     exit (EXIT_FAILURE);
6395   }
6396   if (close (fd) == -1) {
6397     perror (filename);
6398     unlink (filename);
6399     exit (EXIT_FAILURE);
6400   }
6401   if (guestfs_add_drive (g, filename) == -1) {
6402     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6403     exit (EXIT_FAILURE);
6404   }
6405
6406   filename = \"test3.img\";
6407   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6408   if (fd == -1) {
6409     perror (filename);
6410     exit (EXIT_FAILURE);
6411   }
6412   if (lseek (fd, %d, SEEK_SET) == -1) {
6413     perror (\"lseek\");
6414     close (fd);
6415     unlink (filename);
6416     exit (EXIT_FAILURE);
6417   }
6418   if (write (fd, &c, 1) == -1) {
6419     perror (\"write\");
6420     close (fd);
6421     unlink (filename);
6422     exit (EXIT_FAILURE);
6423   }
6424   if (close (fd) == -1) {
6425     perror (filename);
6426     unlink (filename);
6427     exit (EXIT_FAILURE);
6428   }
6429   if (guestfs_add_drive (g, filename) == -1) {
6430     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6431     exit (EXIT_FAILURE);
6432   }
6433
6434   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6435     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6436     exit (EXIT_FAILURE);
6437   }
6438
6439   if (guestfs_launch (g) == -1) {
6440     printf (\"guestfs_launch FAILED\\n\");
6441     exit (EXIT_FAILURE);
6442   }
6443
6444   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6445   alarm (600);
6446
6447   /* Cancel previous alarm. */
6448   alarm (0);
6449
6450   nr_tests = %d;
6451
6452 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6453
6454   iteri (
6455     fun i test_name ->
6456       pr "  test_num++;\n";
6457       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6458       pr "  if (%s () == -1) {\n" test_name;
6459       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6460       pr "    n_failed++;\n";
6461       pr "  }\n";
6462   ) test_names;
6463   pr "\n";
6464
6465   pr "  guestfs_close (g);\n";
6466   pr "  unlink (\"test1.img\");\n";
6467   pr "  unlink (\"test2.img\");\n";
6468   pr "  unlink (\"test3.img\");\n";
6469   pr "\n";
6470
6471   pr "  if (n_failed > 0) {\n";
6472   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6473   pr "    exit (EXIT_FAILURE);\n";
6474   pr "  }\n";
6475   pr "\n";
6476
6477   pr "  exit (EXIT_SUCCESS);\n";
6478   pr "}\n"
6479
6480 and generate_one_test name flags i (init, prereq, test) =
6481   let test_name = sprintf "test_%s_%d" name i in
6482
6483   pr "\
6484 static int %s_skip (void)
6485 {
6486   const char *str;
6487
6488   str = getenv (\"TEST_ONLY\");
6489   if (str)
6490     return strstr (str, \"%s\") == NULL;
6491   str = getenv (\"SKIP_%s\");
6492   if (str && STREQ (str, \"1\")) return 1;
6493   str = getenv (\"SKIP_TEST_%s\");
6494   if (str && STREQ (str, \"1\")) return 1;
6495   return 0;
6496 }
6497
6498 " test_name name (String.uppercase test_name) (String.uppercase name);
6499
6500   (match prereq with
6501    | Disabled | Always -> ()
6502    | If code | Unless code ->
6503        pr "static int %s_prereq (void)\n" test_name;
6504        pr "{\n";
6505        pr "  %s\n" code;
6506        pr "}\n";
6507        pr "\n";
6508   );
6509
6510   pr "\
6511 static int %s (void)
6512 {
6513   if (%s_skip ()) {
6514     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6515     return 0;
6516   }
6517
6518 " test_name test_name test_name;
6519
6520   (* Optional functions should only be tested if the relevant
6521    * support is available in the daemon.
6522    *)
6523   List.iter (
6524     function
6525     | Optional group ->
6526         pr "  {\n";
6527         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6528         pr "    int r;\n";
6529         pr "    suppress_error = 1;\n";
6530         pr "    r = guestfs_available (g, (char **) groups);\n";
6531         pr "    suppress_error = 0;\n";
6532         pr "    if (r == -1) {\n";
6533         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6534         pr "      return 0;\n";
6535         pr "    }\n";
6536         pr "  }\n";
6537     | _ -> ()
6538   ) flags;
6539
6540   (match prereq with
6541    | Disabled ->
6542        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6543    | If _ ->
6544        pr "  if (! %s_prereq ()) {\n" test_name;
6545        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6546        pr "    return 0;\n";
6547        pr "  }\n";
6548        pr "\n";
6549        generate_one_test_body name i test_name init test;
6550    | Unless _ ->
6551        pr "  if (%s_prereq ()) {\n" test_name;
6552        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6553        pr "    return 0;\n";
6554        pr "  }\n";
6555        pr "\n";
6556        generate_one_test_body name i test_name init test;
6557    | Always ->
6558        generate_one_test_body name i test_name init test
6559   );
6560
6561   pr "  return 0;\n";
6562   pr "}\n";
6563   pr "\n";
6564   test_name
6565
6566 and generate_one_test_body name i test_name init test =
6567   (match init with
6568    | InitNone (* XXX at some point, InitNone and InitEmpty became
6569                * folded together as the same thing.  Really we should
6570                * make InitNone do nothing at all, but the tests may
6571                * need to be checked to make sure this is OK.
6572                *)
6573    | InitEmpty ->
6574        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6575        List.iter (generate_test_command_call test_name)
6576          [["blockdev_setrw"; "/dev/sda"];
6577           ["umount_all"];
6578           ["lvm_remove_all"]]
6579    | InitPartition ->
6580        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6581        List.iter (generate_test_command_call test_name)
6582          [["blockdev_setrw"; "/dev/sda"];
6583           ["umount_all"];
6584           ["lvm_remove_all"];
6585           ["part_disk"; "/dev/sda"; "mbr"]]
6586    | InitBasicFS ->
6587        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6588        List.iter (generate_test_command_call test_name)
6589          [["blockdev_setrw"; "/dev/sda"];
6590           ["umount_all"];
6591           ["lvm_remove_all"];
6592           ["part_disk"; "/dev/sda"; "mbr"];
6593           ["mkfs"; "ext2"; "/dev/sda1"];
6594           ["mount_options"; ""; "/dev/sda1"; "/"]]
6595    | InitBasicFSonLVM ->
6596        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6597          test_name;
6598        List.iter (generate_test_command_call test_name)
6599          [["blockdev_setrw"; "/dev/sda"];
6600           ["umount_all"];
6601           ["lvm_remove_all"];
6602           ["part_disk"; "/dev/sda"; "mbr"];
6603           ["pvcreate"; "/dev/sda1"];
6604           ["vgcreate"; "VG"; "/dev/sda1"];
6605           ["lvcreate"; "LV"; "VG"; "8"];
6606           ["mkfs"; "ext2"; "/dev/VG/LV"];
6607           ["mount_options"; ""; "/dev/VG/LV"; "/"]]
6608    | InitISOFS ->
6609        pr "  /* InitISOFS for %s */\n" test_name;
6610        List.iter (generate_test_command_call test_name)
6611          [["blockdev_setrw"; "/dev/sda"];
6612           ["umount_all"];
6613           ["lvm_remove_all"];
6614           ["mount_ro"; "/dev/sdd"; "/"]]
6615   );
6616
6617   let get_seq_last = function
6618     | [] ->
6619         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6620           test_name
6621     | seq ->
6622         let seq = List.rev seq in
6623         List.rev (List.tl seq), List.hd seq
6624   in
6625
6626   match test with
6627   | TestRun seq ->
6628       pr "  /* TestRun for %s (%d) */\n" name i;
6629       List.iter (generate_test_command_call test_name) seq
6630   | TestOutput (seq, expected) ->
6631       pr "  /* TestOutput for %s (%d) */\n" name i;
6632       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6633       let seq, last = get_seq_last seq in
6634       let test () =
6635         pr "    if (STRNEQ (r, expected)) {\n";
6636         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6637         pr "      return -1;\n";
6638         pr "    }\n"
6639       in
6640       List.iter (generate_test_command_call test_name) seq;
6641       generate_test_command_call ~test test_name last
6642   | TestOutputList (seq, expected) ->
6643       pr "  /* TestOutputList for %s (%d) */\n" name i;
6644       let seq, last = get_seq_last seq in
6645       let test () =
6646         iteri (
6647           fun i str ->
6648             pr "    if (!r[%d]) {\n" i;
6649             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6650             pr "      print_strings (r);\n";
6651             pr "      return -1;\n";
6652             pr "    }\n";
6653             pr "    {\n";
6654             pr "      const char *expected = \"%s\";\n" (c_quote str);
6655             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6656             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6657             pr "        return -1;\n";
6658             pr "      }\n";
6659             pr "    }\n"
6660         ) expected;
6661         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6662         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6663           test_name;
6664         pr "      print_strings (r);\n";
6665         pr "      return -1;\n";
6666         pr "    }\n"
6667       in
6668       List.iter (generate_test_command_call test_name) seq;
6669       generate_test_command_call ~test test_name last
6670   | TestOutputListOfDevices (seq, expected) ->
6671       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6672       let seq, last = get_seq_last seq in
6673       let test () =
6674         iteri (
6675           fun i str ->
6676             pr "    if (!r[%d]) {\n" i;
6677             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6678             pr "      print_strings (r);\n";
6679             pr "      return -1;\n";
6680             pr "    }\n";
6681             pr "    {\n";
6682             pr "      const char *expected = \"%s\";\n" (c_quote str);
6683             pr "      r[%d][5] = 's';\n" i;
6684             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6685             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6686             pr "        return -1;\n";
6687             pr "      }\n";
6688             pr "    }\n"
6689         ) expected;
6690         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6691         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6692           test_name;
6693         pr "      print_strings (r);\n";
6694         pr "      return -1;\n";
6695         pr "    }\n"
6696       in
6697       List.iter (generate_test_command_call test_name) seq;
6698       generate_test_command_call ~test test_name last
6699   | TestOutputInt (seq, expected) ->
6700       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6701       let seq, last = get_seq_last seq in
6702       let test () =
6703         pr "    if (r != %d) {\n" expected;
6704         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6705           test_name expected;
6706         pr "               (int) r);\n";
6707         pr "      return -1;\n";
6708         pr "    }\n"
6709       in
6710       List.iter (generate_test_command_call test_name) seq;
6711       generate_test_command_call ~test test_name last
6712   | TestOutputIntOp (seq, op, expected) ->
6713       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6714       let seq, last = get_seq_last seq in
6715       let test () =
6716         pr "    if (! (r %s %d)) {\n" op expected;
6717         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6718           test_name op expected;
6719         pr "               (int) r);\n";
6720         pr "      return -1;\n";
6721         pr "    }\n"
6722       in
6723       List.iter (generate_test_command_call test_name) seq;
6724       generate_test_command_call ~test test_name last
6725   | TestOutputTrue seq ->
6726       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
6727       let seq, last = get_seq_last seq in
6728       let test () =
6729         pr "    if (!r) {\n";
6730         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
6731           test_name;
6732         pr "      return -1;\n";
6733         pr "    }\n"
6734       in
6735       List.iter (generate_test_command_call test_name) seq;
6736       generate_test_command_call ~test test_name last
6737   | TestOutputFalse seq ->
6738       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
6739       let seq, last = get_seq_last seq in
6740       let test () =
6741         pr "    if (r) {\n";
6742         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
6743           test_name;
6744         pr "      return -1;\n";
6745         pr "    }\n"
6746       in
6747       List.iter (generate_test_command_call test_name) seq;
6748       generate_test_command_call ~test test_name last
6749   | TestOutputLength (seq, expected) ->
6750       pr "  /* TestOutputLength for %s (%d) */\n" name i;
6751       let seq, last = get_seq_last seq in
6752       let test () =
6753         pr "    int j;\n";
6754         pr "    for (j = 0; j < %d; ++j)\n" expected;
6755         pr "      if (r[j] == NULL) {\n";
6756         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
6757           test_name;
6758         pr "        print_strings (r);\n";
6759         pr "        return -1;\n";
6760         pr "      }\n";
6761         pr "    if (r[j] != NULL) {\n";
6762         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
6763           test_name;
6764         pr "      print_strings (r);\n";
6765         pr "      return -1;\n";
6766         pr "    }\n"
6767       in
6768       List.iter (generate_test_command_call test_name) seq;
6769       generate_test_command_call ~test test_name last
6770   | TestOutputBuffer (seq, expected) ->
6771       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
6772       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6773       let seq, last = get_seq_last seq in
6774       let len = String.length expected in
6775       let test () =
6776         pr "    if (size != %d) {\n" len;
6777         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
6778         pr "      return -1;\n";
6779         pr "    }\n";
6780         pr "    if (STRNEQLEN (r, expected, size)) {\n";
6781         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6782         pr "      return -1;\n";
6783         pr "    }\n"
6784       in
6785       List.iter (generate_test_command_call test_name) seq;
6786       generate_test_command_call ~test test_name last
6787   | TestOutputStruct (seq, checks) ->
6788       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
6789       let seq, last = get_seq_last seq in
6790       let test () =
6791         List.iter (
6792           function
6793           | CompareWithInt (field, expected) ->
6794               pr "    if (r->%s != %d) {\n" field expected;
6795               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
6796                 test_name field expected;
6797               pr "               (int) r->%s);\n" field;
6798               pr "      return -1;\n";
6799               pr "    }\n"
6800           | CompareWithIntOp (field, op, expected) ->
6801               pr "    if (!(r->%s %s %d)) {\n" field op expected;
6802               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
6803                 test_name field op expected;
6804               pr "               (int) r->%s);\n" field;
6805               pr "      return -1;\n";
6806               pr "    }\n"
6807           | CompareWithString (field, expected) ->
6808               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
6809               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
6810                 test_name field expected;
6811               pr "               r->%s);\n" field;
6812               pr "      return -1;\n";
6813               pr "    }\n"
6814           | CompareFieldsIntEq (field1, field2) ->
6815               pr "    if (r->%s != r->%s) {\n" field1 field2;
6816               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
6817                 test_name field1 field2;
6818               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
6819               pr "      return -1;\n";
6820               pr "    }\n"
6821           | CompareFieldsStrEq (field1, field2) ->
6822               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
6823               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
6824                 test_name field1 field2;
6825               pr "               r->%s, r->%s);\n" field1 field2;
6826               pr "      return -1;\n";
6827               pr "    }\n"
6828         ) checks
6829       in
6830       List.iter (generate_test_command_call test_name) seq;
6831       generate_test_command_call ~test test_name last
6832   | TestLastFail seq ->
6833       pr "  /* TestLastFail for %s (%d) */\n" name i;
6834       let seq, last = get_seq_last seq in
6835       List.iter (generate_test_command_call test_name) seq;
6836       generate_test_command_call test_name ~expect_error:true last
6837
6838 (* Generate the code to run a command, leaving the result in 'r'.
6839  * If you expect to get an error then you should set expect_error:true.
6840  *)
6841 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
6842   match cmd with
6843   | [] -> assert false
6844   | name :: args ->
6845       (* Look up the command to find out what args/ret it has. *)
6846       let style =
6847         try
6848           let _, style, _, _, _, _, _ =
6849             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
6850           style
6851         with Not_found ->
6852           failwithf "%s: in test, command %s was not found" test_name name in
6853
6854       if List.length (snd style) <> List.length args then
6855         failwithf "%s: in test, wrong number of args given to %s"
6856           test_name name;
6857
6858       pr "  {\n";
6859
6860       List.iter (
6861         function
6862         | OptString n, "NULL" -> ()
6863         | Pathname n, arg
6864         | Device n, arg
6865         | Dev_or_Path n, arg
6866         | String n, arg
6867         | OptString n, arg ->
6868             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
6869         | Int _, _
6870         | Int64 _, _
6871         | Bool _, _
6872         | FileIn _, _ | FileOut _, _ -> ()
6873         | StringList n, "" | DeviceList n, "" ->
6874             pr "    const char *const %s[1] = { NULL };\n" n
6875         | StringList n, arg | DeviceList n, arg ->
6876             let strs = string_split " " arg in
6877             iteri (
6878               fun i str ->
6879                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
6880             ) strs;
6881             pr "    const char *const %s[] = {\n" n;
6882             iteri (
6883               fun i _ -> pr "      %s_%d,\n" n i
6884             ) strs;
6885             pr "      NULL\n";
6886             pr "    };\n";
6887       ) (List.combine (snd style) args);
6888
6889       let error_code =
6890         match fst style with
6891         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
6892         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
6893         | RConstString _ | RConstOptString _ ->
6894             pr "    const char *r;\n"; "NULL"
6895         | RString _ -> pr "    char *r;\n"; "NULL"
6896         | RStringList _ | RHashtable _ ->
6897             pr "    char **r;\n";
6898             pr "    int i;\n";
6899             "NULL"
6900         | RStruct (_, typ) ->
6901             pr "    struct guestfs_%s *r;\n" typ; "NULL"
6902         | RStructList (_, typ) ->
6903             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
6904         | RBufferOut _ ->
6905             pr "    char *r;\n";
6906             pr "    size_t size;\n";
6907             "NULL" in
6908
6909       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
6910       pr "    r = guestfs_%s (g" name;
6911
6912       (* Generate the parameters. *)
6913       List.iter (
6914         function
6915         | OptString _, "NULL" -> pr ", NULL"
6916         | Pathname n, _
6917         | Device n, _ | Dev_or_Path n, _
6918         | String n, _
6919         | OptString n, _ ->
6920             pr ", %s" n
6921         | FileIn _, arg | FileOut _, arg ->
6922             pr ", \"%s\"" (c_quote arg)
6923         | StringList n, _ | DeviceList n, _ ->
6924             pr ", (char **) %s" n
6925         | Int _, arg ->
6926             let i =
6927               try int_of_string arg
6928               with Failure "int_of_string" ->
6929                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
6930             pr ", %d" i
6931         | Int64 _, arg ->
6932             let i =
6933               try Int64.of_string arg
6934               with Failure "int_of_string" ->
6935                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
6936             pr ", %Ld" i
6937         | Bool _, arg ->
6938             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
6939       ) (List.combine (snd style) args);
6940
6941       (match fst style with
6942        | RBufferOut _ -> pr ", &size"
6943        | _ -> ()
6944       );
6945
6946       pr ");\n";
6947
6948       if not expect_error then
6949         pr "    if (r == %s)\n" error_code
6950       else
6951         pr "    if (r != %s)\n" error_code;
6952       pr "      return -1;\n";
6953
6954       (* Insert the test code. *)
6955       (match test with
6956        | None -> ()
6957        | Some f -> f ()
6958       );
6959
6960       (match fst style with
6961        | RErr | RInt _ | RInt64 _ | RBool _
6962        | RConstString _ | RConstOptString _ -> ()
6963        | RString _ | RBufferOut _ -> pr "    free (r);\n"
6964        | RStringList _ | RHashtable _ ->
6965            pr "    for (i = 0; r[i] != NULL; ++i)\n";
6966            pr "      free (r[i]);\n";
6967            pr "    free (r);\n"
6968        | RStruct (_, typ) ->
6969            pr "    guestfs_free_%s (r);\n" typ
6970        | RStructList (_, typ) ->
6971            pr "    guestfs_free_%s_list (r);\n" typ
6972       );
6973
6974       pr "  }\n"
6975
6976 and c_quote str =
6977   let str = replace_str str "\r" "\\r" in
6978   let str = replace_str str "\n" "\\n" in
6979   let str = replace_str str "\t" "\\t" in
6980   let str = replace_str str "\000" "\\0" in
6981   str
6982
6983 (* Generate a lot of different functions for guestfish. *)
6984 and generate_fish_cmds () =
6985   generate_header CStyle GPLv2plus;
6986
6987   let all_functions =
6988     List.filter (
6989       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6990     ) all_functions in
6991   let all_functions_sorted =
6992     List.filter (
6993       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6994     ) all_functions_sorted in
6995
6996   pr "#include <config.h>\n";
6997   pr "\n";
6998   pr "#include <stdio.h>\n";
6999   pr "#include <stdlib.h>\n";
7000   pr "#include <string.h>\n";
7001   pr "#include <inttypes.h>\n";
7002   pr "\n";
7003   pr "#include <guestfs.h>\n";
7004   pr "#include \"c-ctype.h\"\n";
7005   pr "#include \"full-write.h\"\n";
7006   pr "#include \"xstrtol.h\"\n";
7007   pr "#include \"fish.h\"\n";
7008   pr "\n";
7009
7010   (* list_commands function, which implements guestfish -h *)
7011   pr "void list_commands (void)\n";
7012   pr "{\n";
7013   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
7014   pr "  list_builtin_commands ();\n";
7015   List.iter (
7016     fun (name, _, _, flags, _, shortdesc, _) ->
7017       let name = replace_char name '_' '-' in
7018       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
7019         name shortdesc
7020   ) all_functions_sorted;
7021   pr "  printf (\"    %%s\\n\",";
7022   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
7023   pr "}\n";
7024   pr "\n";
7025
7026   (* display_command function, which implements guestfish -h cmd *)
7027   pr "void display_command (const char *cmd)\n";
7028   pr "{\n";
7029   List.iter (
7030     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7031       let name2 = replace_char name '_' '-' in
7032       let alias =
7033         try find_map (function FishAlias n -> Some n | _ -> None) flags
7034         with Not_found -> name in
7035       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
7036       let synopsis =
7037         match snd style with
7038         | [] -> name2
7039         | args ->
7040             sprintf "%s %s"
7041               name2 (String.concat " " (List.map name_of_argt args)) in
7042
7043       let warnings =
7044         if List.mem ProtocolLimitWarning flags then
7045           ("\n\n" ^ protocol_limit_warning)
7046         else "" in
7047
7048       (* For DangerWillRobinson commands, we should probably have
7049        * guestfish prompt before allowing you to use them (especially
7050        * in interactive mode). XXX
7051        *)
7052       let warnings =
7053         warnings ^
7054           if List.mem DangerWillRobinson flags then
7055             ("\n\n" ^ danger_will_robinson)
7056           else "" in
7057
7058       let warnings =
7059         warnings ^
7060           match deprecation_notice flags with
7061           | None -> ""
7062           | Some txt -> "\n\n" ^ txt in
7063
7064       let describe_alias =
7065         if name <> alias then
7066           sprintf "\n\nYou can use '%s' as an alias for this command." alias
7067         else "" in
7068
7069       pr "  if (";
7070       pr "STRCASEEQ (cmd, \"%s\")" name;
7071       if name <> name2 then
7072         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7073       if name <> alias then
7074         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7075       pr ")\n";
7076       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
7077         name2 shortdesc
7078         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
7079          "=head1 DESCRIPTION\n\n" ^
7080          longdesc ^ warnings ^ describe_alias);
7081       pr "  else\n"
7082   ) all_functions;
7083   pr "    display_builtin_command (cmd);\n";
7084   pr "}\n";
7085   pr "\n";
7086
7087   let emit_print_list_function typ =
7088     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
7089       typ typ typ;
7090     pr "{\n";
7091     pr "  unsigned int i;\n";
7092     pr "\n";
7093     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
7094     pr "    printf (\"[%%d] = {\\n\", i);\n";
7095     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
7096     pr "    printf (\"}\\n\");\n";
7097     pr "  }\n";
7098     pr "}\n";
7099     pr "\n";
7100   in
7101
7102   (* print_* functions *)
7103   List.iter (
7104     fun (typ, cols) ->
7105       let needs_i =
7106         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
7107
7108       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7109       pr "{\n";
7110       if needs_i then (
7111         pr "  unsigned int i;\n";
7112         pr "\n"
7113       );
7114       List.iter (
7115         function
7116         | name, FString ->
7117             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7118         | name, FUUID ->
7119             pr "  printf (\"%%s%s: \", indent);\n" name;
7120             pr "  for (i = 0; i < 32; ++i)\n";
7121             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7122             pr "  printf (\"\\n\");\n"
7123         | name, FBuffer ->
7124             pr "  printf (\"%%s%s: \", indent);\n" name;
7125             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7126             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7127             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7128             pr "    else\n";
7129             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7130             pr "  printf (\"\\n\");\n"
7131         | name, (FUInt64|FBytes) ->
7132             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7133               name typ name
7134         | name, FInt64 ->
7135             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7136               name typ name
7137         | name, FUInt32 ->
7138             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7139               name typ name
7140         | name, FInt32 ->
7141             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7142               name typ name
7143         | name, FChar ->
7144             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7145               name typ name
7146         | name, FOptPercent ->
7147             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7148               typ name name typ name;
7149             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7150       ) cols;
7151       pr "}\n";
7152       pr "\n";
7153   ) structs;
7154
7155   (* Emit a print_TYPE_list function definition only if that function is used. *)
7156   List.iter (
7157     function
7158     | typ, (RStructListOnly | RStructAndList) ->
7159         (* generate the function for typ *)
7160         emit_print_list_function typ
7161     | typ, _ -> () (* empty *)
7162   ) (rstructs_used_by all_functions);
7163
7164   (* Emit a print_TYPE function definition only if that function is used. *)
7165   List.iter (
7166     function
7167     | typ, (RStructOnly | RStructAndList) ->
7168         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7169         pr "{\n";
7170         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7171         pr "}\n";
7172         pr "\n";
7173     | typ, _ -> () (* empty *)
7174   ) (rstructs_used_by all_functions);
7175
7176   (* run_<action> actions *)
7177   List.iter (
7178     fun (name, style, _, flags, _, _, _) ->
7179       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7180       pr "{\n";
7181       (match fst style with
7182        | RErr
7183        | RInt _
7184        | RBool _ -> pr "  int r;\n"
7185        | RInt64 _ -> pr "  int64_t r;\n"
7186        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7187        | RString _ -> pr "  char *r;\n"
7188        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7189        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7190        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7191        | RBufferOut _ ->
7192            pr "  char *r;\n";
7193            pr "  size_t size;\n";
7194       );
7195       List.iter (
7196         function
7197         | Device n
7198         | String n
7199         | OptString n
7200         | FileIn n
7201         | FileOut n -> pr "  const char *%s;\n" n
7202         | Pathname n
7203         | Dev_or_Path n -> pr "  char *%s;\n" n
7204         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7205         | Bool n -> pr "  int %s;\n" n
7206         | Int n -> pr "  int %s;\n" n
7207         | Int64 n -> pr "  int64_t %s;\n" n
7208       ) (snd style);
7209
7210       (* Check and convert parameters. *)
7211       let argc_expected = List.length (snd style) in
7212       pr "  if (argc != %d) {\n" argc_expected;
7213       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7214         argc_expected;
7215       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7216       pr "    return -1;\n";
7217       pr "  }\n";
7218
7219       let parse_integer fn fntyp rtyp range name i =
7220         pr "  {\n";
7221         pr "    strtol_error xerr;\n";
7222         pr "    %s r;\n" fntyp;
7223         pr "\n";
7224         pr "    xerr = %s (argv[%d], NULL, 0, &r, \"\");\n" fn i;
7225         pr "    if (xerr != LONGINT_OK) {\n";
7226         pr "      fprintf (stderr,\n";
7227         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7228         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7229         pr "      return -1;\n";
7230         pr "    }\n";
7231         (match range with
7232          | None -> ()
7233          | Some (min, max, comment) ->
7234              pr "    /* %s */\n" comment;
7235              pr "    if (r < %s || r > %s) {\n" min max;
7236              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7237                name;
7238              pr "      return -1;\n";
7239              pr "    }\n";
7240              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7241         );
7242         pr "    %s = r;\n" name;
7243         pr "  }\n";
7244       in
7245
7246       iteri (
7247         fun i ->
7248           function
7249           | Device name
7250           | String name ->
7251               pr "  %s = argv[%d];\n" name i
7252           | Pathname name
7253           | Dev_or_Path name ->
7254               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7255               pr "  if (%s == NULL) return -1;\n" name
7256           | OptString name ->
7257               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7258                 name i i
7259           | FileIn name ->
7260               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdin\";\n"
7261                 name i i
7262           | FileOut name ->
7263               pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdout\";\n"
7264                 name i i
7265           | StringList name | DeviceList name ->
7266               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7267               pr "  if (%s == NULL) return -1;\n" name;
7268           | Bool name ->
7269               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7270           | Int name ->
7271               let range =
7272                 let min = "(-(2LL<<30))"
7273                 and max = "((2LL<<30)-1)"
7274                 and comment =
7275                   "The Int type in the generator is a signed 31 bit int." in
7276                 Some (min, max, comment) in
7277               parse_integer "xstrtoll" "long long" "int" range name i
7278           | Int64 name ->
7279               parse_integer "xstrtoll" "long long" "int64_t" None name i
7280       ) (snd style);
7281
7282       (* Call C API function. *)
7283       let fn =
7284         try find_map (function FishAction n -> Some n | _ -> None) flags
7285         with Not_found -> sprintf "guestfs_%s" name in
7286       pr "  r = %s " fn;
7287       generate_c_call_args ~handle:"g" style;
7288       pr ";\n";
7289
7290       List.iter (
7291         function
7292         | Device name | String name
7293         | OptString name | FileIn name | FileOut name | Bool name
7294         | Int name | Int64 name -> ()
7295         | Pathname name | Dev_or_Path name ->
7296             pr "  free (%s);\n" name
7297         | StringList name | DeviceList name ->
7298             pr "  free_strings (%s);\n" name
7299       ) (snd style);
7300
7301       (* Check return value for errors and display command results. *)
7302       (match fst style with
7303        | RErr -> pr "  return r;\n"
7304        | RInt _ ->
7305            pr "  if (r == -1) return -1;\n";
7306            pr "  printf (\"%%d\\n\", r);\n";
7307            pr "  return 0;\n"
7308        | RInt64 _ ->
7309            pr "  if (r == -1) return -1;\n";
7310            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7311            pr "  return 0;\n"
7312        | RBool _ ->
7313            pr "  if (r == -1) return -1;\n";
7314            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7315            pr "  return 0;\n"
7316        | RConstString _ ->
7317            pr "  if (r == NULL) return -1;\n";
7318            pr "  printf (\"%%s\\n\", r);\n";
7319            pr "  return 0;\n"
7320        | RConstOptString _ ->
7321            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7322            pr "  return 0;\n"
7323        | RString _ ->
7324            pr "  if (r == NULL) return -1;\n";
7325            pr "  printf (\"%%s\\n\", r);\n";
7326            pr "  free (r);\n";
7327            pr "  return 0;\n"
7328        | RStringList _ ->
7329            pr "  if (r == NULL) return -1;\n";
7330            pr "  print_strings (r);\n";
7331            pr "  free_strings (r);\n";
7332            pr "  return 0;\n"
7333        | RStruct (_, typ) ->
7334            pr "  if (r == NULL) return -1;\n";
7335            pr "  print_%s (r);\n" typ;
7336            pr "  guestfs_free_%s (r);\n" typ;
7337            pr "  return 0;\n"
7338        | RStructList (_, typ) ->
7339            pr "  if (r == NULL) return -1;\n";
7340            pr "  print_%s_list (r);\n" typ;
7341            pr "  guestfs_free_%s_list (r);\n" typ;
7342            pr "  return 0;\n"
7343        | RHashtable _ ->
7344            pr "  if (r == NULL) return -1;\n";
7345            pr "  print_table (r);\n";
7346            pr "  free_strings (r);\n";
7347            pr "  return 0;\n"
7348        | RBufferOut _ ->
7349            pr "  if (r == NULL) return -1;\n";
7350            pr "  if (full_write (1, r, size) != size) {\n";
7351            pr "    perror (\"write\");\n";
7352            pr "    free (r);\n";
7353            pr "    return -1;\n";
7354            pr "  }\n";
7355            pr "  free (r);\n";
7356            pr "  return 0;\n"
7357       );
7358       pr "}\n";
7359       pr "\n"
7360   ) all_functions;
7361
7362   (* run_action function *)
7363   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7364   pr "{\n";
7365   List.iter (
7366     fun (name, _, _, flags, _, _, _) ->
7367       let name2 = replace_char name '_' '-' in
7368       let alias =
7369         try find_map (function FishAlias n -> Some n | _ -> None) flags
7370         with Not_found -> name in
7371       pr "  if (";
7372       pr "STRCASEEQ (cmd, \"%s\")" name;
7373       if name <> name2 then
7374         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7375       if name <> alias then
7376         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7377       pr ")\n";
7378       pr "    return run_%s (cmd, argc, argv);\n" name;
7379       pr "  else\n";
7380   ) all_functions;
7381   pr "    {\n";
7382   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7383   pr "      return -1;\n";
7384   pr "    }\n";
7385   pr "  return 0;\n";
7386   pr "}\n";
7387   pr "\n"
7388
7389 (* Readline completion for guestfish. *)
7390 and generate_fish_completion () =
7391   generate_header CStyle GPLv2plus;
7392
7393   let all_functions =
7394     List.filter (
7395       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7396     ) all_functions in
7397
7398   pr "\
7399 #include <config.h>
7400
7401 #include <stdio.h>
7402 #include <stdlib.h>
7403 #include <string.h>
7404
7405 #ifdef HAVE_LIBREADLINE
7406 #include <readline/readline.h>
7407 #endif
7408
7409 #include \"fish.h\"
7410
7411 #ifdef HAVE_LIBREADLINE
7412
7413 static const char *const commands[] = {
7414   BUILTIN_COMMANDS_FOR_COMPLETION,
7415 ";
7416
7417   (* Get the commands, including the aliases.  They don't need to be
7418    * sorted - the generator() function just does a dumb linear search.
7419    *)
7420   let commands =
7421     List.map (
7422       fun (name, _, _, flags, _, _, _) ->
7423         let name2 = replace_char name '_' '-' in
7424         let alias =
7425           try find_map (function FishAlias n -> Some n | _ -> None) flags
7426           with Not_found -> name in
7427
7428         if name <> alias then [name2; alias] else [name2]
7429     ) all_functions in
7430   let commands = List.flatten commands in
7431
7432   List.iter (pr "  \"%s\",\n") commands;
7433
7434   pr "  NULL
7435 };
7436
7437 static char *
7438 generator (const char *text, int state)
7439 {
7440   static int index, len;
7441   const char *name;
7442
7443   if (!state) {
7444     index = 0;
7445     len = strlen (text);
7446   }
7447
7448   rl_attempted_completion_over = 1;
7449
7450   while ((name = commands[index]) != NULL) {
7451     index++;
7452     if (STRCASEEQLEN (name, text, len))
7453       return strdup (name);
7454   }
7455
7456   return NULL;
7457 }
7458
7459 #endif /* HAVE_LIBREADLINE */
7460
7461 char **do_completion (const char *text, int start, int end)
7462 {
7463   char **matches = NULL;
7464
7465 #ifdef HAVE_LIBREADLINE
7466   rl_completion_append_character = ' ';
7467
7468   if (start == 0)
7469     matches = rl_completion_matches (text, generator);
7470   else if (complete_dest_paths)
7471     matches = rl_completion_matches (text, complete_dest_paths_generator);
7472 #endif
7473
7474   return matches;
7475 }
7476 ";
7477
7478 (* Generate the POD documentation for guestfish. *)
7479 and generate_fish_actions_pod () =
7480   let all_functions_sorted =
7481     List.filter (
7482       fun (_, _, _, flags, _, _, _) ->
7483         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7484     ) all_functions_sorted in
7485
7486   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7487
7488   List.iter (
7489     fun (name, style, _, flags, _, _, longdesc) ->
7490       let longdesc =
7491         Str.global_substitute rex (
7492           fun s ->
7493             let sub =
7494               try Str.matched_group 1 s
7495               with Not_found ->
7496                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7497             "C<" ^ replace_char sub '_' '-' ^ ">"
7498         ) longdesc in
7499       let name = replace_char name '_' '-' in
7500       let alias =
7501         try find_map (function FishAlias n -> Some n | _ -> None) flags
7502         with Not_found -> name in
7503
7504       pr "=head2 %s" name;
7505       if name <> alias then
7506         pr " | %s" alias;
7507       pr "\n";
7508       pr "\n";
7509       pr " %s" name;
7510       List.iter (
7511         function
7512         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7513         | OptString n -> pr " %s" n
7514         | StringList n | DeviceList n -> pr " '%s ...'" n
7515         | Bool _ -> pr " true|false"
7516         | Int n -> pr " %s" n
7517         | Int64 n -> pr " %s" n
7518         | FileIn n | FileOut n -> pr " (%s|-)" n
7519       ) (snd style);
7520       pr "\n";
7521       pr "\n";
7522       pr "%s\n\n" longdesc;
7523
7524       if List.exists (function FileIn _ | FileOut _ -> true
7525                       | _ -> false) (snd style) then
7526         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7527
7528       if List.mem ProtocolLimitWarning flags then
7529         pr "%s\n\n" protocol_limit_warning;
7530
7531       if List.mem DangerWillRobinson flags then
7532         pr "%s\n\n" danger_will_robinson;
7533
7534       match deprecation_notice flags with
7535       | None -> ()
7536       | Some txt -> pr "%s\n\n" txt
7537   ) all_functions_sorted
7538
7539 (* Generate a C function prototype. *)
7540 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7541     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7542     ?(prefix = "")
7543     ?handle name style =
7544   if extern then pr "extern ";
7545   if static then pr "static ";
7546   (match fst style with
7547    | RErr -> pr "int "
7548    | RInt _ -> pr "int "
7549    | RInt64 _ -> pr "int64_t "
7550    | RBool _ -> pr "int "
7551    | RConstString _ | RConstOptString _ -> pr "const char *"
7552    | RString _ | RBufferOut _ -> pr "char *"
7553    | RStringList _ | RHashtable _ -> pr "char **"
7554    | RStruct (_, typ) ->
7555        if not in_daemon then pr "struct guestfs_%s *" typ
7556        else pr "guestfs_int_%s *" typ
7557    | RStructList (_, typ) ->
7558        if not in_daemon then pr "struct guestfs_%s_list *" typ
7559        else pr "guestfs_int_%s_list *" typ
7560   );
7561   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7562   pr "%s%s (" prefix name;
7563   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7564     pr "void"
7565   else (
7566     let comma = ref false in
7567     (match handle with
7568      | None -> ()
7569      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7570     );
7571     let next () =
7572       if !comma then (
7573         if single_line then pr ", " else pr ",\n\t\t"
7574       );
7575       comma := true
7576     in
7577     List.iter (
7578       function
7579       | Pathname n
7580       | Device n | Dev_or_Path n
7581       | String n
7582       | OptString n ->
7583           next ();
7584           pr "const char *%s" n
7585       | StringList n | DeviceList n ->
7586           next ();
7587           pr "char *const *%s" n
7588       | Bool n -> next (); pr "int %s" n
7589       | Int n -> next (); pr "int %s" n
7590       | Int64 n -> next (); pr "int64_t %s" n
7591       | FileIn n
7592       | FileOut n ->
7593           if not in_daemon then (next (); pr "const char *%s" n)
7594     ) (snd style);
7595     if is_RBufferOut then (next (); pr "size_t *size_r");
7596   );
7597   pr ")";
7598   if semicolon then pr ";";
7599   if newline then pr "\n"
7600
7601 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7602 and generate_c_call_args ?handle ?(decl = false) style =
7603   pr "(";
7604   let comma = ref false in
7605   let next () =
7606     if !comma then pr ", ";
7607     comma := true
7608   in
7609   (match handle with
7610    | None -> ()
7611    | Some handle -> pr "%s" handle; comma := true
7612   );
7613   List.iter (
7614     fun arg ->
7615       next ();
7616       pr "%s" (name_of_argt arg)
7617   ) (snd style);
7618   (* For RBufferOut calls, add implicit &size parameter. *)
7619   if not decl then (
7620     match fst style with
7621     | RBufferOut _ ->
7622         next ();
7623         pr "&size"
7624     | _ -> ()
7625   );
7626   pr ")"
7627
7628 (* Generate the OCaml bindings interface. *)
7629 and generate_ocaml_mli () =
7630   generate_header OCamlStyle LGPLv2plus;
7631
7632   pr "\
7633 (** For API documentation you should refer to the C API
7634     in the guestfs(3) manual page.  The OCaml API uses almost
7635     exactly the same calls. *)
7636
7637 type t
7638 (** A [guestfs_h] handle. *)
7639
7640 exception Error of string
7641 (** This exception is raised when there is an error. *)
7642
7643 exception Handle_closed of string
7644 (** This exception is raised if you use a {!Guestfs.t} handle
7645     after calling {!close} on it.  The string is the name of
7646     the function. *)
7647
7648 val create : unit -> t
7649 (** Create a {!Guestfs.t} handle. *)
7650
7651 val close : t -> unit
7652 (** Close the {!Guestfs.t} handle and free up all resources used
7653     by it immediately.
7654
7655     Handles are closed by the garbage collector when they become
7656     unreferenced, but callers can call this in order to provide
7657     predictable cleanup. *)
7658
7659 ";
7660   generate_ocaml_structure_decls ();
7661
7662   (* The actions. *)
7663   List.iter (
7664     fun (name, style, _, _, _, shortdesc, _) ->
7665       generate_ocaml_prototype name style;
7666       pr "(** %s *)\n" shortdesc;
7667       pr "\n"
7668   ) all_functions_sorted
7669
7670 (* Generate the OCaml bindings implementation. *)
7671 and generate_ocaml_ml () =
7672   generate_header OCamlStyle LGPLv2plus;
7673
7674   pr "\
7675 type t
7676
7677 exception Error of string
7678 exception Handle_closed of string
7679
7680 external create : unit -> t = \"ocaml_guestfs_create\"
7681 external close : t -> unit = \"ocaml_guestfs_close\"
7682
7683 (* Give the exceptions names, so they can be raised from the C code. *)
7684 let () =
7685   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
7686   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
7687
7688 ";
7689
7690   generate_ocaml_structure_decls ();
7691
7692   (* The actions. *)
7693   List.iter (
7694     fun (name, style, _, _, _, shortdesc, _) ->
7695       generate_ocaml_prototype ~is_external:true name style;
7696   ) all_functions_sorted
7697
7698 (* Generate the OCaml bindings C implementation. *)
7699 and generate_ocaml_c () =
7700   generate_header CStyle LGPLv2plus;
7701
7702   pr "\
7703 #include <stdio.h>
7704 #include <stdlib.h>
7705 #include <string.h>
7706
7707 #include <caml/config.h>
7708 #include <caml/alloc.h>
7709 #include <caml/callback.h>
7710 #include <caml/fail.h>
7711 #include <caml/memory.h>
7712 #include <caml/mlvalues.h>
7713 #include <caml/signals.h>
7714
7715 #include <guestfs.h>
7716
7717 #include \"guestfs_c.h\"
7718
7719 /* Copy a hashtable of string pairs into an assoc-list.  We return
7720  * the list in reverse order, but hashtables aren't supposed to be
7721  * ordered anyway.
7722  */
7723 static CAMLprim value
7724 copy_table (char * const * argv)
7725 {
7726   CAMLparam0 ();
7727   CAMLlocal5 (rv, pairv, kv, vv, cons);
7728   int i;
7729
7730   rv = Val_int (0);
7731   for (i = 0; argv[i] != NULL; i += 2) {
7732     kv = caml_copy_string (argv[i]);
7733     vv = caml_copy_string (argv[i+1]);
7734     pairv = caml_alloc (2, 0);
7735     Store_field (pairv, 0, kv);
7736     Store_field (pairv, 1, vv);
7737     cons = caml_alloc (2, 0);
7738     Store_field (cons, 1, rv);
7739     rv = cons;
7740     Store_field (cons, 0, pairv);
7741   }
7742
7743   CAMLreturn (rv);
7744 }
7745
7746 ";
7747
7748   (* Struct copy functions. *)
7749
7750   let emit_ocaml_copy_list_function typ =
7751     pr "static CAMLprim value\n";
7752     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
7753     pr "{\n";
7754     pr "  CAMLparam0 ();\n";
7755     pr "  CAMLlocal2 (rv, v);\n";
7756     pr "  unsigned int i;\n";
7757     pr "\n";
7758     pr "  if (%ss->len == 0)\n" typ;
7759     pr "    CAMLreturn (Atom (0));\n";
7760     pr "  else {\n";
7761     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
7762     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
7763     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
7764     pr "      caml_modify (&Field (rv, i), v);\n";
7765     pr "    }\n";
7766     pr "    CAMLreturn (rv);\n";
7767     pr "  }\n";
7768     pr "}\n";
7769     pr "\n";
7770   in
7771
7772   List.iter (
7773     fun (typ, cols) ->
7774       let has_optpercent_col =
7775         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
7776
7777       pr "static CAMLprim value\n";
7778       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
7779       pr "{\n";
7780       pr "  CAMLparam0 ();\n";
7781       if has_optpercent_col then
7782         pr "  CAMLlocal3 (rv, v, v2);\n"
7783       else
7784         pr "  CAMLlocal2 (rv, v);\n";
7785       pr "\n";
7786       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
7787       iteri (
7788         fun i col ->
7789           (match col with
7790            | name, FString ->
7791                pr "  v = caml_copy_string (%s->%s);\n" typ name
7792            | name, FBuffer ->
7793                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
7794                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
7795                  typ name typ name
7796            | name, FUUID ->
7797                pr "  v = caml_alloc_string (32);\n";
7798                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
7799            | name, (FBytes|FInt64|FUInt64) ->
7800                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
7801            | name, (FInt32|FUInt32) ->
7802                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
7803            | name, FOptPercent ->
7804                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
7805                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
7806                pr "    v = caml_alloc (1, 0);\n";
7807                pr "    Store_field (v, 0, v2);\n";
7808                pr "  } else /* None */\n";
7809                pr "    v = Val_int (0);\n";
7810            | name, FChar ->
7811                pr "  v = Val_int (%s->%s);\n" typ name
7812           );
7813           pr "  Store_field (rv, %d, v);\n" i
7814       ) cols;
7815       pr "  CAMLreturn (rv);\n";
7816       pr "}\n";
7817       pr "\n";
7818   ) structs;
7819
7820   (* Emit a copy_TYPE_list function definition only if that function is used. *)
7821   List.iter (
7822     function
7823     | typ, (RStructListOnly | RStructAndList) ->
7824         (* generate the function for typ *)
7825         emit_ocaml_copy_list_function typ
7826     | typ, _ -> () (* empty *)
7827   ) (rstructs_used_by all_functions);
7828
7829   (* The wrappers. *)
7830   List.iter (
7831     fun (name, style, _, _, _, _, _) ->
7832       pr "/* Automatically generated wrapper for function\n";
7833       pr " * ";
7834       generate_ocaml_prototype name style;
7835       pr " */\n";
7836       pr "\n";
7837
7838       let params =
7839         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
7840
7841       let needs_extra_vs =
7842         match fst style with RConstOptString _ -> true | _ -> false in
7843
7844       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7845       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
7846       List.iter (pr ", value %s") (List.tl params); pr ");\n";
7847       pr "\n";
7848
7849       pr "CAMLprim value\n";
7850       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
7851       List.iter (pr ", value %s") (List.tl params);
7852       pr ")\n";
7853       pr "{\n";
7854
7855       (match params with
7856        | [p1; p2; p3; p4; p5] ->
7857            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
7858        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
7859            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
7860            pr "  CAMLxparam%d (%s);\n"
7861              (List.length rest) (String.concat ", " rest)
7862        | ps ->
7863            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
7864       );
7865       if not needs_extra_vs then
7866         pr "  CAMLlocal1 (rv);\n"
7867       else
7868         pr "  CAMLlocal3 (rv, v, v2);\n";
7869       pr "\n";
7870
7871       pr "  guestfs_h *g = Guestfs_val (gv);\n";
7872       pr "  if (g == NULL)\n";
7873       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
7874       pr "\n";
7875
7876       List.iter (
7877         function
7878         | Pathname n
7879         | Device n | Dev_or_Path n
7880         | String n
7881         | FileIn n
7882         | FileOut n ->
7883             pr "  const char *%s = String_val (%sv);\n" n n
7884         | OptString n ->
7885             pr "  const char *%s =\n" n;
7886             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
7887               n n
7888         | StringList n | DeviceList n ->
7889             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
7890         | Bool n ->
7891             pr "  int %s = Bool_val (%sv);\n" n n
7892         | Int n ->
7893             pr "  int %s = Int_val (%sv);\n" n n
7894         | Int64 n ->
7895             pr "  int64_t %s = Int64_val (%sv);\n" n n
7896       ) (snd style);
7897       let error_code =
7898         match fst style with
7899         | RErr -> pr "  int r;\n"; "-1"
7900         | RInt _ -> pr "  int r;\n"; "-1"
7901         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7902         | RBool _ -> pr "  int r;\n"; "-1"
7903         | RConstString _ | RConstOptString _ ->
7904             pr "  const char *r;\n"; "NULL"
7905         | RString _ -> pr "  char *r;\n"; "NULL"
7906         | RStringList _ ->
7907             pr "  int i;\n";
7908             pr "  char **r;\n";
7909             "NULL"
7910         | RStruct (_, typ) ->
7911             pr "  struct guestfs_%s *r;\n" typ; "NULL"
7912         | RStructList (_, typ) ->
7913             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7914         | RHashtable _ ->
7915             pr "  int i;\n";
7916             pr "  char **r;\n";
7917             "NULL"
7918         | RBufferOut _ ->
7919             pr "  char *r;\n";
7920             pr "  size_t size;\n";
7921             "NULL" in
7922       pr "\n";
7923
7924       pr "  caml_enter_blocking_section ();\n";
7925       pr "  r = guestfs_%s " name;
7926       generate_c_call_args ~handle:"g" style;
7927       pr ";\n";
7928       pr "  caml_leave_blocking_section ();\n";
7929
7930       List.iter (
7931         function
7932         | StringList n | DeviceList n ->
7933             pr "  ocaml_guestfs_free_strings (%s);\n" n;
7934         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
7935         | Bool _ | Int _ | Int64 _
7936         | FileIn _ | FileOut _ -> ()
7937       ) (snd style);
7938
7939       pr "  if (r == %s)\n" error_code;
7940       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
7941       pr "\n";
7942
7943       (match fst style with
7944        | RErr -> pr "  rv = Val_unit;\n"
7945        | RInt _ -> pr "  rv = Val_int (r);\n"
7946        | RInt64 _ ->
7947            pr "  rv = caml_copy_int64 (r);\n"
7948        | RBool _ -> pr "  rv = Val_bool (r);\n"
7949        | RConstString _ ->
7950            pr "  rv = caml_copy_string (r);\n"
7951        | RConstOptString _ ->
7952            pr "  if (r) { /* Some string */\n";
7953            pr "    v = caml_alloc (1, 0);\n";
7954            pr "    v2 = caml_copy_string (r);\n";
7955            pr "    Store_field (v, 0, v2);\n";
7956            pr "  } else /* None */\n";
7957            pr "    v = Val_int (0);\n";
7958        | RString _ ->
7959            pr "  rv = caml_copy_string (r);\n";
7960            pr "  free (r);\n"
7961        | RStringList _ ->
7962            pr "  rv = caml_copy_string_array ((const char **) r);\n";
7963            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7964            pr "  free (r);\n"
7965        | RStruct (_, typ) ->
7966            pr "  rv = copy_%s (r);\n" typ;
7967            pr "  guestfs_free_%s (r);\n" typ;
7968        | RStructList (_, typ) ->
7969            pr "  rv = copy_%s_list (r);\n" typ;
7970            pr "  guestfs_free_%s_list (r);\n" typ;
7971        | RHashtable _ ->
7972            pr "  rv = copy_table (r);\n";
7973            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
7974            pr "  free (r);\n";
7975        | RBufferOut _ ->
7976            pr "  rv = caml_alloc_string (size);\n";
7977            pr "  memcpy (String_val (rv), r, size);\n";
7978       );
7979
7980       pr "  CAMLreturn (rv);\n";
7981       pr "}\n";
7982       pr "\n";
7983
7984       if List.length params > 5 then (
7985         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
7986         pr "CAMLprim value ";
7987         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
7988         pr "CAMLprim value\n";
7989         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
7990         pr "{\n";
7991         pr "  return ocaml_guestfs_%s (argv[0]" name;
7992         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
7993         pr ");\n";
7994         pr "}\n";
7995         pr "\n"
7996       )
7997   ) all_functions_sorted
7998
7999 and generate_ocaml_structure_decls () =
8000   List.iter (
8001     fun (typ, cols) ->
8002       pr "type %s = {\n" typ;
8003       List.iter (
8004         function
8005         | name, FString -> pr "  %s : string;\n" name
8006         | name, FBuffer -> pr "  %s : string;\n" name
8007         | name, FUUID -> pr "  %s : string;\n" name
8008         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
8009         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
8010         | name, FChar -> pr "  %s : char;\n" name
8011         | name, FOptPercent -> pr "  %s : float option;\n" name
8012       ) cols;
8013       pr "}\n";
8014       pr "\n"
8015   ) structs
8016
8017 and generate_ocaml_prototype ?(is_external = false) name style =
8018   if is_external then pr "external " else pr "val ";
8019   pr "%s : t -> " name;
8020   List.iter (
8021     function
8022     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
8023     | OptString _ -> pr "string option -> "
8024     | StringList _ | DeviceList _ -> pr "string array -> "
8025     | Bool _ -> pr "bool -> "
8026     | Int _ -> pr "int -> "
8027     | Int64 _ -> pr "int64 -> "
8028   ) (snd style);
8029   (match fst style with
8030    | RErr -> pr "unit" (* all errors are turned into exceptions *)
8031    | RInt _ -> pr "int"
8032    | RInt64 _ -> pr "int64"
8033    | RBool _ -> pr "bool"
8034    | RConstString _ -> pr "string"
8035    | RConstOptString _ -> pr "string option"
8036    | RString _ | RBufferOut _ -> pr "string"
8037    | RStringList _ -> pr "string array"
8038    | RStruct (_, typ) -> pr "%s" typ
8039    | RStructList (_, typ) -> pr "%s array" typ
8040    | RHashtable _ -> pr "(string * string) list"
8041   );
8042   if is_external then (
8043     pr " = ";
8044     if List.length (snd style) + 1 > 5 then
8045       pr "\"ocaml_guestfs_%s_byte\" " name;
8046     pr "\"ocaml_guestfs_%s\"" name
8047   );
8048   pr "\n"
8049
8050 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
8051 and generate_perl_xs () =
8052   generate_header CStyle LGPLv2plus;
8053
8054   pr "\
8055 #include \"EXTERN.h\"
8056 #include \"perl.h\"
8057 #include \"XSUB.h\"
8058
8059 #include <guestfs.h>
8060
8061 #ifndef PRId64
8062 #define PRId64 \"lld\"
8063 #endif
8064
8065 static SV *
8066 my_newSVll(long long val) {
8067 #ifdef USE_64_BIT_ALL
8068   return newSViv(val);
8069 #else
8070   char buf[100];
8071   int len;
8072   len = snprintf(buf, 100, \"%%\" PRId64, val);
8073   return newSVpv(buf, len);
8074 #endif
8075 }
8076
8077 #ifndef PRIu64
8078 #define PRIu64 \"llu\"
8079 #endif
8080
8081 static SV *
8082 my_newSVull(unsigned long long val) {
8083 #ifdef USE_64_BIT_ALL
8084   return newSVuv(val);
8085 #else
8086   char buf[100];
8087   int len;
8088   len = snprintf(buf, 100, \"%%\" PRIu64, val);
8089   return newSVpv(buf, len);
8090 #endif
8091 }
8092
8093 /* http://www.perlmonks.org/?node_id=680842 */
8094 static char **
8095 XS_unpack_charPtrPtr (SV *arg) {
8096   char **ret;
8097   AV *av;
8098   I32 i;
8099
8100   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
8101     croak (\"array reference expected\");
8102
8103   av = (AV *)SvRV (arg);
8104   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
8105   if (!ret)
8106     croak (\"malloc failed\");
8107
8108   for (i = 0; i <= av_len (av); i++) {
8109     SV **elem = av_fetch (av, i, 0);
8110
8111     if (!elem || !*elem)
8112       croak (\"missing element in list\");
8113
8114     ret[i] = SvPV_nolen (*elem);
8115   }
8116
8117   ret[i] = NULL;
8118
8119   return ret;
8120 }
8121
8122 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8123
8124 PROTOTYPES: ENABLE
8125
8126 guestfs_h *
8127 _create ()
8128    CODE:
8129       RETVAL = guestfs_create ();
8130       if (!RETVAL)
8131         croak (\"could not create guestfs handle\");
8132       guestfs_set_error_handler (RETVAL, NULL, NULL);
8133  OUTPUT:
8134       RETVAL
8135
8136 void
8137 DESTROY (g)
8138       guestfs_h *g;
8139  PPCODE:
8140       guestfs_close (g);
8141
8142 ";
8143
8144   List.iter (
8145     fun (name, style, _, _, _, _, _) ->
8146       (match fst style with
8147        | RErr -> pr "void\n"
8148        | RInt _ -> pr "SV *\n"
8149        | RInt64 _ -> pr "SV *\n"
8150        | RBool _ -> pr "SV *\n"
8151        | RConstString _ -> pr "SV *\n"
8152        | RConstOptString _ -> pr "SV *\n"
8153        | RString _ -> pr "SV *\n"
8154        | RBufferOut _ -> pr "SV *\n"
8155        | RStringList _
8156        | RStruct _ | RStructList _
8157        | RHashtable _ ->
8158            pr "void\n" (* all lists returned implictly on the stack *)
8159       );
8160       (* Call and arguments. *)
8161       pr "%s " name;
8162       generate_c_call_args ~handle:"g" ~decl:true style;
8163       pr "\n";
8164       pr "      guestfs_h *g;\n";
8165       iteri (
8166         fun i ->
8167           function
8168           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8169               pr "      char *%s;\n" n
8170           | OptString n ->
8171               (* http://www.perlmonks.org/?node_id=554277
8172                * Note that the implicit handle argument means we have
8173                * to add 1 to the ST(x) operator.
8174                *)
8175               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8176           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8177           | Bool n -> pr "      int %s;\n" n
8178           | Int n -> pr "      int %s;\n" n
8179           | Int64 n -> pr "      int64_t %s;\n" n
8180       ) (snd style);
8181
8182       let do_cleanups () =
8183         List.iter (
8184           function
8185           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8186           | Bool _ | Int _ | Int64 _
8187           | FileIn _ | FileOut _ -> ()
8188           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8189         ) (snd style)
8190       in
8191
8192       (* Code. *)
8193       (match fst style with
8194        | RErr ->
8195            pr "PREINIT:\n";
8196            pr "      int r;\n";
8197            pr " PPCODE:\n";
8198            pr "      r = guestfs_%s " name;
8199            generate_c_call_args ~handle:"g" style;
8200            pr ";\n";
8201            do_cleanups ();
8202            pr "      if (r == -1)\n";
8203            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8204        | RInt n
8205        | RBool n ->
8206            pr "PREINIT:\n";
8207            pr "      int %s;\n" n;
8208            pr "   CODE:\n";
8209            pr "      %s = guestfs_%s " n name;
8210            generate_c_call_args ~handle:"g" style;
8211            pr ";\n";
8212            do_cleanups ();
8213            pr "      if (%s == -1)\n" n;
8214            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8215            pr "      RETVAL = newSViv (%s);\n" n;
8216            pr " OUTPUT:\n";
8217            pr "      RETVAL\n"
8218        | RInt64 n ->
8219            pr "PREINIT:\n";
8220            pr "      int64_t %s;\n" n;
8221            pr "   CODE:\n";
8222            pr "      %s = guestfs_%s " n name;
8223            generate_c_call_args ~handle:"g" style;
8224            pr ";\n";
8225            do_cleanups ();
8226            pr "      if (%s == -1)\n" n;
8227            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8228            pr "      RETVAL = my_newSVll (%s);\n" n;
8229            pr " OUTPUT:\n";
8230            pr "      RETVAL\n"
8231        | RConstString n ->
8232            pr "PREINIT:\n";
8233            pr "      const char *%s;\n" n;
8234            pr "   CODE:\n";
8235            pr "      %s = guestfs_%s " n name;
8236            generate_c_call_args ~handle:"g" style;
8237            pr ";\n";
8238            do_cleanups ();
8239            pr "      if (%s == NULL)\n" n;
8240            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8241            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8242            pr " OUTPUT:\n";
8243            pr "      RETVAL\n"
8244        | RConstOptString n ->
8245            pr "PREINIT:\n";
8246            pr "      const char *%s;\n" n;
8247            pr "   CODE:\n";
8248            pr "      %s = guestfs_%s " n name;
8249            generate_c_call_args ~handle:"g" style;
8250            pr ";\n";
8251            do_cleanups ();
8252            pr "      if (%s == NULL)\n" n;
8253            pr "        RETVAL = &PL_sv_undef;\n";
8254            pr "      else\n";
8255            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8256            pr " OUTPUT:\n";
8257            pr "      RETVAL\n"
8258        | RString n ->
8259            pr "PREINIT:\n";
8260            pr "      char *%s;\n" n;
8261            pr "   CODE:\n";
8262            pr "      %s = guestfs_%s " n name;
8263            generate_c_call_args ~handle:"g" style;
8264            pr ";\n";
8265            do_cleanups ();
8266            pr "      if (%s == NULL)\n" n;
8267            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8268            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8269            pr "      free (%s);\n" n;
8270            pr " OUTPUT:\n";
8271            pr "      RETVAL\n"
8272        | RStringList n | RHashtable n ->
8273            pr "PREINIT:\n";
8274            pr "      char **%s;\n" n;
8275            pr "      int i, n;\n";
8276            pr " PPCODE:\n";
8277            pr "      %s = guestfs_%s " n name;
8278            generate_c_call_args ~handle:"g" style;
8279            pr ";\n";
8280            do_cleanups ();
8281            pr "      if (%s == NULL)\n" n;
8282            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8283            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8284            pr "      EXTEND (SP, n);\n";
8285            pr "      for (i = 0; i < n; ++i) {\n";
8286            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8287            pr "        free (%s[i]);\n" n;
8288            pr "      }\n";
8289            pr "      free (%s);\n" n;
8290        | RStruct (n, typ) ->
8291            let cols = cols_of_struct typ in
8292            generate_perl_struct_code typ cols name style n do_cleanups
8293        | RStructList (n, typ) ->
8294            let cols = cols_of_struct typ in
8295            generate_perl_struct_list_code typ cols name style n do_cleanups
8296        | RBufferOut n ->
8297            pr "PREINIT:\n";
8298            pr "      char *%s;\n" n;
8299            pr "      size_t size;\n";
8300            pr "   CODE:\n";
8301            pr "      %s = guestfs_%s " n name;
8302            generate_c_call_args ~handle:"g" style;
8303            pr ";\n";
8304            do_cleanups ();
8305            pr "      if (%s == NULL)\n" n;
8306            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8307            pr "      RETVAL = newSVpv (%s, size);\n" n;
8308            pr "      free (%s);\n" n;
8309            pr " OUTPUT:\n";
8310            pr "      RETVAL\n"
8311       );
8312
8313       pr "\n"
8314   ) all_functions
8315
8316 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8317   pr "PREINIT:\n";
8318   pr "      struct guestfs_%s_list *%s;\n" typ n;
8319   pr "      int i;\n";
8320   pr "      HV *hv;\n";
8321   pr " PPCODE:\n";
8322   pr "      %s = guestfs_%s " n name;
8323   generate_c_call_args ~handle:"g" style;
8324   pr ";\n";
8325   do_cleanups ();
8326   pr "      if (%s == NULL)\n" n;
8327   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8328   pr "      EXTEND (SP, %s->len);\n" n;
8329   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8330   pr "        hv = newHV ();\n";
8331   List.iter (
8332     function
8333     | name, FString ->
8334         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8335           name (String.length name) n name
8336     | name, FUUID ->
8337         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8338           name (String.length name) n name
8339     | name, FBuffer ->
8340         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8341           name (String.length name) n name n name
8342     | name, (FBytes|FUInt64) ->
8343         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8344           name (String.length name) n name
8345     | name, FInt64 ->
8346         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8347           name (String.length name) n name
8348     | name, (FInt32|FUInt32) ->
8349         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8350           name (String.length name) n name
8351     | name, FChar ->
8352         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8353           name (String.length name) n name
8354     | name, FOptPercent ->
8355         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8356           name (String.length name) n name
8357   ) cols;
8358   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8359   pr "      }\n";
8360   pr "      guestfs_free_%s_list (%s);\n" typ n
8361
8362 and generate_perl_struct_code typ cols name style n do_cleanups =
8363   pr "PREINIT:\n";
8364   pr "      struct guestfs_%s *%s;\n" typ n;
8365   pr " PPCODE:\n";
8366   pr "      %s = guestfs_%s " n name;
8367   generate_c_call_args ~handle:"g" style;
8368   pr ";\n";
8369   do_cleanups ();
8370   pr "      if (%s == NULL)\n" n;
8371   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8372   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8373   List.iter (
8374     fun ((name, _) as col) ->
8375       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8376
8377       match col with
8378       | name, FString ->
8379           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8380             n name
8381       | name, FBuffer ->
8382           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
8383             n name n name
8384       | name, FUUID ->
8385           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8386             n name
8387       | name, (FBytes|FUInt64) ->
8388           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8389             n name
8390       | name, FInt64 ->
8391           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8392             n name
8393       | name, (FInt32|FUInt32) ->
8394           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8395             n name
8396       | name, FChar ->
8397           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8398             n name
8399       | name, FOptPercent ->
8400           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8401             n name
8402   ) cols;
8403   pr "      free (%s);\n" n
8404
8405 (* Generate Sys/Guestfs.pm. *)
8406 and generate_perl_pm () =
8407   generate_header HashStyle LGPLv2plus;
8408
8409   pr "\
8410 =pod
8411
8412 =head1 NAME
8413
8414 Sys::Guestfs - Perl bindings for libguestfs
8415
8416 =head1 SYNOPSIS
8417
8418  use Sys::Guestfs;
8419
8420  my $h = Sys::Guestfs->new ();
8421  $h->add_drive ('guest.img');
8422  $h->launch ();
8423  $h->mount ('/dev/sda1', '/');
8424  $h->touch ('/hello');
8425  $h->sync ();
8426
8427 =head1 DESCRIPTION
8428
8429 The C<Sys::Guestfs> module provides a Perl XS binding to the
8430 libguestfs API for examining and modifying virtual machine
8431 disk images.
8432
8433 Amongst the things this is good for: making batch configuration
8434 changes to guests, getting disk used/free statistics (see also:
8435 virt-df), migrating between virtualization systems (see also:
8436 virt-p2v), performing partial backups, performing partial guest
8437 clones, cloning guests and changing registry/UUID/hostname info, and
8438 much else besides.
8439
8440 Libguestfs uses Linux kernel and qemu code, and can access any type of
8441 guest filesystem that Linux and qemu can, including but not limited
8442 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8443 schemes, qcow, qcow2, vmdk.
8444
8445 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8446 LVs, what filesystem is in each LV, etc.).  It can also run commands
8447 in the context of the guest.  Also you can access filesystems over
8448 FUSE.
8449
8450 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8451 functions for using libguestfs from Perl, including integration
8452 with libvirt.
8453
8454 =head1 ERRORS
8455
8456 All errors turn into calls to C<croak> (see L<Carp(3)>).
8457
8458 =head1 METHODS
8459
8460 =over 4
8461
8462 =cut
8463
8464 package Sys::Guestfs;
8465
8466 use strict;
8467 use warnings;
8468
8469 require XSLoader;
8470 XSLoader::load ('Sys::Guestfs');
8471
8472 =item $h = Sys::Guestfs->new ();
8473
8474 Create a new guestfs handle.
8475
8476 =cut
8477
8478 sub new {
8479   my $proto = shift;
8480   my $class = ref ($proto) || $proto;
8481
8482   my $self = Sys::Guestfs::_create ();
8483   bless $self, $class;
8484   return $self;
8485 }
8486
8487 ";
8488
8489   (* Actions.  We only need to print documentation for these as
8490    * they are pulled in from the XS code automatically.
8491    *)
8492   List.iter (
8493     fun (name, style, _, flags, _, _, longdesc) ->
8494       if not (List.mem NotInDocs flags) then (
8495         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8496         pr "=item ";
8497         generate_perl_prototype name style;
8498         pr "\n\n";
8499         pr "%s\n\n" longdesc;
8500         if List.mem ProtocolLimitWarning flags then
8501           pr "%s\n\n" protocol_limit_warning;
8502         if List.mem DangerWillRobinson flags then
8503           pr "%s\n\n" danger_will_robinson;
8504         match deprecation_notice flags with
8505         | None -> ()
8506         | Some txt -> pr "%s\n\n" txt
8507       )
8508   ) all_functions_sorted;
8509
8510   (* End of file. *)
8511   pr "\
8512 =cut
8513
8514 1;
8515
8516 =back
8517
8518 =head1 COPYRIGHT
8519
8520 Copyright (C) %s Red Hat Inc.
8521
8522 =head1 LICENSE
8523
8524 Please see the file COPYING.LIB for the full license.
8525
8526 =head1 SEE ALSO
8527
8528 L<guestfs(3)>,
8529 L<guestfish(1)>,
8530 L<http://libguestfs.org>,
8531 L<Sys::Guestfs::Lib(3)>.
8532
8533 =cut
8534 " copyright_years
8535
8536 and generate_perl_prototype name style =
8537   (match fst style with
8538    | RErr -> ()
8539    | RBool n
8540    | RInt n
8541    | RInt64 n
8542    | RConstString n
8543    | RConstOptString n
8544    | RString n
8545    | RBufferOut n -> pr "$%s = " n
8546    | RStruct (n,_)
8547    | RHashtable n -> pr "%%%s = " n
8548    | RStringList n
8549    | RStructList (n,_) -> pr "@%s = " n
8550   );
8551   pr "$h->%s (" name;
8552   let comma = ref false in
8553   List.iter (
8554     fun arg ->
8555       if !comma then pr ", ";
8556       comma := true;
8557       match arg with
8558       | Pathname n | Device n | Dev_or_Path n | String n
8559       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8560           pr "$%s" n
8561       | StringList n | DeviceList n ->
8562           pr "\\@%s" n
8563   ) (snd style);
8564   pr ");"
8565
8566 (* Generate Python C module. *)
8567 and generate_python_c () =
8568   generate_header CStyle LGPLv2plus;
8569
8570   pr "\
8571 #include <Python.h>
8572
8573 #include <stdio.h>
8574 #include <stdlib.h>
8575 #include <assert.h>
8576
8577 #include \"guestfs.h\"
8578
8579 typedef struct {
8580   PyObject_HEAD
8581   guestfs_h *g;
8582 } Pyguestfs_Object;
8583
8584 static guestfs_h *
8585 get_handle (PyObject *obj)
8586 {
8587   assert (obj);
8588   assert (obj != Py_None);
8589   return ((Pyguestfs_Object *) obj)->g;
8590 }
8591
8592 static PyObject *
8593 put_handle (guestfs_h *g)
8594 {
8595   assert (g);
8596   return
8597     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8598 }
8599
8600 /* This list should be freed (but not the strings) after use. */
8601 static char **
8602 get_string_list (PyObject *obj)
8603 {
8604   int i, len;
8605   char **r;
8606
8607   assert (obj);
8608
8609   if (!PyList_Check (obj)) {
8610     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8611     return NULL;
8612   }
8613
8614   len = PyList_Size (obj);
8615   r = malloc (sizeof (char *) * (len+1));
8616   if (r == NULL) {
8617     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8618     return NULL;
8619   }
8620
8621   for (i = 0; i < len; ++i)
8622     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8623   r[len] = NULL;
8624
8625   return r;
8626 }
8627
8628 static PyObject *
8629 put_string_list (char * const * const argv)
8630 {
8631   PyObject *list;
8632   int argc, i;
8633
8634   for (argc = 0; argv[argc] != NULL; ++argc)
8635     ;
8636
8637   list = PyList_New (argc);
8638   for (i = 0; i < argc; ++i)
8639     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8640
8641   return list;
8642 }
8643
8644 static PyObject *
8645 put_table (char * const * const argv)
8646 {
8647   PyObject *list, *item;
8648   int argc, i;
8649
8650   for (argc = 0; argv[argc] != NULL; ++argc)
8651     ;
8652
8653   list = PyList_New (argc >> 1);
8654   for (i = 0; i < argc; i += 2) {
8655     item = PyTuple_New (2);
8656     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8657     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8658     PyList_SetItem (list, i >> 1, item);
8659   }
8660
8661   return list;
8662 }
8663
8664 static void
8665 free_strings (char **argv)
8666 {
8667   int argc;
8668
8669   for (argc = 0; argv[argc] != NULL; ++argc)
8670     free (argv[argc]);
8671   free (argv);
8672 }
8673
8674 static PyObject *
8675 py_guestfs_create (PyObject *self, PyObject *args)
8676 {
8677   guestfs_h *g;
8678
8679   g = guestfs_create ();
8680   if (g == NULL) {
8681     PyErr_SetString (PyExc_RuntimeError,
8682                      \"guestfs.create: failed to allocate handle\");
8683     return NULL;
8684   }
8685   guestfs_set_error_handler (g, NULL, NULL);
8686   return put_handle (g);
8687 }
8688
8689 static PyObject *
8690 py_guestfs_close (PyObject *self, PyObject *args)
8691 {
8692   PyObject *py_g;
8693   guestfs_h *g;
8694
8695   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
8696     return NULL;
8697   g = get_handle (py_g);
8698
8699   guestfs_close (g);
8700
8701   Py_INCREF (Py_None);
8702   return Py_None;
8703 }
8704
8705 ";
8706
8707   let emit_put_list_function typ =
8708     pr "static PyObject *\n";
8709     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
8710     pr "{\n";
8711     pr "  PyObject *list;\n";
8712     pr "  int i;\n";
8713     pr "\n";
8714     pr "  list = PyList_New (%ss->len);\n" typ;
8715     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
8716     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
8717     pr "  return list;\n";
8718     pr "};\n";
8719     pr "\n"
8720   in
8721
8722   (* Structures, turned into Python dictionaries. *)
8723   List.iter (
8724     fun (typ, cols) ->
8725       pr "static PyObject *\n";
8726       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
8727       pr "{\n";
8728       pr "  PyObject *dict;\n";
8729       pr "\n";
8730       pr "  dict = PyDict_New ();\n";
8731       List.iter (
8732         function
8733         | name, FString ->
8734             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8735             pr "                        PyString_FromString (%s->%s));\n"
8736               typ name
8737         | name, FBuffer ->
8738             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8739             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
8740               typ name typ name
8741         | name, FUUID ->
8742             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8743             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
8744               typ name
8745         | name, (FBytes|FUInt64) ->
8746             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8747             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
8748               typ name
8749         | name, FInt64 ->
8750             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8751             pr "                        PyLong_FromLongLong (%s->%s));\n"
8752               typ name
8753         | name, FUInt32 ->
8754             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8755             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
8756               typ name
8757         | name, FInt32 ->
8758             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8759             pr "                        PyLong_FromLong (%s->%s));\n"
8760               typ name
8761         | name, FOptPercent ->
8762             pr "  if (%s->%s >= 0)\n" typ name;
8763             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
8764             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
8765               typ name;
8766             pr "  else {\n";
8767             pr "    Py_INCREF (Py_None);\n";
8768             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
8769             pr "  }\n"
8770         | name, FChar ->
8771             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8772             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
8773       ) cols;
8774       pr "  return dict;\n";
8775       pr "};\n";
8776       pr "\n";
8777
8778   ) structs;
8779
8780   (* Emit a put_TYPE_list function definition only if that function is used. *)
8781   List.iter (
8782     function
8783     | typ, (RStructListOnly | RStructAndList) ->
8784         (* generate the function for typ *)
8785         emit_put_list_function typ
8786     | typ, _ -> () (* empty *)
8787   ) (rstructs_used_by all_functions);
8788
8789   (* Python wrapper functions. *)
8790   List.iter (
8791     fun (name, style, _, _, _, _, _) ->
8792       pr "static PyObject *\n";
8793       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
8794       pr "{\n";
8795
8796       pr "  PyObject *py_g;\n";
8797       pr "  guestfs_h *g;\n";
8798       pr "  PyObject *py_r;\n";
8799
8800       let error_code =
8801         match fst style with
8802         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
8803         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8804         | RConstString _ | RConstOptString _ ->
8805             pr "  const char *r;\n"; "NULL"
8806         | RString _ -> pr "  char *r;\n"; "NULL"
8807         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
8808         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
8809         | RStructList (_, typ) ->
8810             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8811         | RBufferOut _ ->
8812             pr "  char *r;\n";
8813             pr "  size_t size;\n";
8814             "NULL" in
8815
8816       List.iter (
8817         function
8818         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8819             pr "  const char *%s;\n" n
8820         | OptString n -> pr "  const char *%s;\n" n
8821         | StringList n | DeviceList n ->
8822             pr "  PyObject *py_%s;\n" n;
8823             pr "  char **%s;\n" n
8824         | Bool n -> pr "  int %s;\n" n
8825         | Int n -> pr "  int %s;\n" n
8826         | Int64 n -> pr "  long long %s;\n" n
8827       ) (snd style);
8828
8829       pr "\n";
8830
8831       (* Convert the parameters. *)
8832       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
8833       List.iter (
8834         function
8835         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
8836         | OptString _ -> pr "z"
8837         | StringList _ | DeviceList _ -> pr "O"
8838         | Bool _ -> pr "i" (* XXX Python has booleans? *)
8839         | Int _ -> pr "i"
8840         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
8841                              * emulate C's int/long/long long in Python?
8842                              *)
8843       ) (snd style);
8844       pr ":guestfs_%s\",\n" name;
8845       pr "                         &py_g";
8846       List.iter (
8847         function
8848         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
8849         | OptString n -> pr ", &%s" n
8850         | StringList n | DeviceList n -> pr ", &py_%s" n
8851         | Bool n -> pr ", &%s" n
8852         | Int n -> pr ", &%s" n
8853         | Int64 n -> pr ", &%s" n
8854       ) (snd style);
8855
8856       pr "))\n";
8857       pr "    return NULL;\n";
8858
8859       pr "  g = get_handle (py_g);\n";
8860       List.iter (
8861         function
8862         | Pathname _ | Device _ | Dev_or_Path _ | String _
8863         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8864         | StringList n | DeviceList n ->
8865             pr "  %s = get_string_list (py_%s);\n" n n;
8866             pr "  if (!%s) return NULL;\n" n
8867       ) (snd style);
8868
8869       pr "\n";
8870
8871       pr "  r = guestfs_%s " name;
8872       generate_c_call_args ~handle:"g" style;
8873       pr ";\n";
8874
8875       List.iter (
8876         function
8877         | Pathname _ | Device _ | Dev_or_Path _ | String _
8878         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
8879         | StringList n | DeviceList n ->
8880             pr "  free (%s);\n" n
8881       ) (snd style);
8882
8883       pr "  if (r == %s) {\n" error_code;
8884       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
8885       pr "    return NULL;\n";
8886       pr "  }\n";
8887       pr "\n";
8888
8889       (match fst style with
8890        | RErr ->
8891            pr "  Py_INCREF (Py_None);\n";
8892            pr "  py_r = Py_None;\n"
8893        | RInt _
8894        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
8895        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
8896        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
8897        | RConstOptString _ ->
8898            pr "  if (r)\n";
8899            pr "    py_r = PyString_FromString (r);\n";
8900            pr "  else {\n";
8901            pr "    Py_INCREF (Py_None);\n";
8902            pr "    py_r = Py_None;\n";
8903            pr "  }\n"
8904        | RString _ ->
8905            pr "  py_r = PyString_FromString (r);\n";
8906            pr "  free (r);\n"
8907        | RStringList _ ->
8908            pr "  py_r = put_string_list (r);\n";
8909            pr "  free_strings (r);\n"
8910        | RStruct (_, typ) ->
8911            pr "  py_r = put_%s (r);\n" typ;
8912            pr "  guestfs_free_%s (r);\n" typ
8913        | RStructList (_, typ) ->
8914            pr "  py_r = put_%s_list (r);\n" typ;
8915            pr "  guestfs_free_%s_list (r);\n" typ
8916        | RHashtable n ->
8917            pr "  py_r = put_table (r);\n";
8918            pr "  free_strings (r);\n"
8919        | RBufferOut _ ->
8920            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
8921            pr "  free (r);\n"
8922       );
8923
8924       pr "  return py_r;\n";
8925       pr "}\n";
8926       pr "\n"
8927   ) all_functions;
8928
8929   (* Table of functions. *)
8930   pr "static PyMethodDef methods[] = {\n";
8931   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
8932   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
8933   List.iter (
8934     fun (name, _, _, _, _, _, _) ->
8935       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
8936         name name
8937   ) all_functions;
8938   pr "  { NULL, NULL, 0, NULL }\n";
8939   pr "};\n";
8940   pr "\n";
8941
8942   (* Init function. *)
8943   pr "\
8944 void
8945 initlibguestfsmod (void)
8946 {
8947   static int initialized = 0;
8948
8949   if (initialized) return;
8950   Py_InitModule ((char *) \"libguestfsmod\", methods);
8951   initialized = 1;
8952 }
8953 "
8954
8955 (* Generate Python module. *)
8956 and generate_python_py () =
8957   generate_header HashStyle LGPLv2plus;
8958
8959   pr "\
8960 u\"\"\"Python bindings for libguestfs
8961
8962 import guestfs
8963 g = guestfs.GuestFS ()
8964 g.add_drive (\"guest.img\")
8965 g.launch ()
8966 parts = g.list_partitions ()
8967
8968 The guestfs module provides a Python binding to the libguestfs API
8969 for examining and modifying virtual machine disk images.
8970
8971 Amongst the things this is good for: making batch configuration
8972 changes to guests, getting disk used/free statistics (see also:
8973 virt-df), migrating between virtualization systems (see also:
8974 virt-p2v), performing partial backups, performing partial guest
8975 clones, cloning guests and changing registry/UUID/hostname info, and
8976 much else besides.
8977
8978 Libguestfs uses Linux kernel and qemu code, and can access any type of
8979 guest filesystem that Linux and qemu can, including but not limited
8980 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8981 schemes, qcow, qcow2, vmdk.
8982
8983 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8984 LVs, what filesystem is in each LV, etc.).  It can also run commands
8985 in the context of the guest.  Also you can access filesystems over
8986 FUSE.
8987
8988 Errors which happen while using the API are turned into Python
8989 RuntimeError exceptions.
8990
8991 To create a guestfs handle you usually have to perform the following
8992 sequence of calls:
8993
8994 # Create the handle, call add_drive at least once, and possibly
8995 # several times if the guest has multiple block devices:
8996 g = guestfs.GuestFS ()
8997 g.add_drive (\"guest.img\")
8998
8999 # Launch the qemu subprocess and wait for it to become ready:
9000 g.launch ()
9001
9002 # Now you can issue commands, for example:
9003 logvols = g.lvs ()
9004
9005 \"\"\"
9006
9007 import libguestfsmod
9008
9009 class GuestFS:
9010     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
9011
9012     def __init__ (self):
9013         \"\"\"Create a new libguestfs handle.\"\"\"
9014         self._o = libguestfsmod.create ()
9015
9016     def __del__ (self):
9017         libguestfsmod.close (self._o)
9018
9019 ";
9020
9021   List.iter (
9022     fun (name, style, _, flags, _, _, longdesc) ->
9023       pr "    def %s " name;
9024       generate_py_call_args ~handle:"self" (snd style);
9025       pr ":\n";
9026
9027       if not (List.mem NotInDocs flags) then (
9028         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9029         let doc =
9030           match fst style with
9031           | RErr | RInt _ | RInt64 _ | RBool _
9032           | RConstOptString _ | RConstString _
9033           | RString _ | RBufferOut _ -> doc
9034           | RStringList _ ->
9035               doc ^ "\n\nThis function returns a list of strings."
9036           | RStruct (_, typ) ->
9037               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
9038           | RStructList (_, typ) ->
9039               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
9040           | RHashtable _ ->
9041               doc ^ "\n\nThis function returns a dictionary." in
9042         let doc =
9043           if List.mem ProtocolLimitWarning flags then
9044             doc ^ "\n\n" ^ protocol_limit_warning
9045           else doc in
9046         let doc =
9047           if List.mem DangerWillRobinson flags then
9048             doc ^ "\n\n" ^ danger_will_robinson
9049           else doc in
9050         let doc =
9051           match deprecation_notice flags with
9052           | None -> doc
9053           | Some txt -> doc ^ "\n\n" ^ txt in
9054         let doc = pod2text ~width:60 name doc in
9055         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
9056         let doc = String.concat "\n        " doc in
9057         pr "        u\"\"\"%s\"\"\"\n" doc;
9058       );
9059       pr "        return libguestfsmod.%s " name;
9060       generate_py_call_args ~handle:"self._o" (snd style);
9061       pr "\n";
9062       pr "\n";
9063   ) all_functions
9064
9065 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
9066 and generate_py_call_args ~handle args =
9067   pr "(%s" handle;
9068   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9069   pr ")"
9070
9071 (* Useful if you need the longdesc POD text as plain text.  Returns a
9072  * list of lines.
9073  *
9074  * Because this is very slow (the slowest part of autogeneration),
9075  * we memoize the results.
9076  *)
9077 and pod2text ~width name longdesc =
9078   let key = width, name, longdesc in
9079   try Hashtbl.find pod2text_memo key
9080   with Not_found ->
9081     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
9082     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
9083     close_out chan;
9084     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
9085     let chan = open_process_in cmd in
9086     let lines = ref [] in
9087     let rec loop i =
9088       let line = input_line chan in
9089       if i = 1 then             (* discard the first line of output *)
9090         loop (i+1)
9091       else (
9092         let line = triml line in
9093         lines := line :: !lines;
9094         loop (i+1)
9095       ) in
9096     let lines = try loop 1 with End_of_file -> List.rev !lines in
9097     unlink filename;
9098     (match close_process_in chan with
9099      | WEXITED 0 -> ()
9100      | WEXITED i ->
9101          failwithf "pod2text: process exited with non-zero status (%d)" i
9102      | WSIGNALED i | WSTOPPED i ->
9103          failwithf "pod2text: process signalled or stopped by signal %d" i
9104     );
9105     Hashtbl.add pod2text_memo key lines;
9106     pod2text_memo_updated ();
9107     lines
9108
9109 (* Generate ruby bindings. *)
9110 and generate_ruby_c () =
9111   generate_header CStyle LGPLv2plus;
9112
9113   pr "\
9114 #include <stdio.h>
9115 #include <stdlib.h>
9116
9117 #include <ruby.h>
9118
9119 #include \"guestfs.h\"
9120
9121 #include \"extconf.h\"
9122
9123 /* For Ruby < 1.9 */
9124 #ifndef RARRAY_LEN
9125 #define RARRAY_LEN(r) (RARRAY((r))->len)
9126 #endif
9127
9128 static VALUE m_guestfs;                 /* guestfs module */
9129 static VALUE c_guestfs;                 /* guestfs_h handle */
9130 static VALUE e_Error;                   /* used for all errors */
9131
9132 static void ruby_guestfs_free (void *p)
9133 {
9134   if (!p) return;
9135   guestfs_close ((guestfs_h *) p);
9136 }
9137
9138 static VALUE ruby_guestfs_create (VALUE m)
9139 {
9140   guestfs_h *g;
9141
9142   g = guestfs_create ();
9143   if (!g)
9144     rb_raise (e_Error, \"failed to create guestfs handle\");
9145
9146   /* Don't print error messages to stderr by default. */
9147   guestfs_set_error_handler (g, NULL, NULL);
9148
9149   /* Wrap it, and make sure the close function is called when the
9150    * handle goes away.
9151    */
9152   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9153 }
9154
9155 static VALUE ruby_guestfs_close (VALUE gv)
9156 {
9157   guestfs_h *g;
9158   Data_Get_Struct (gv, guestfs_h, g);
9159
9160   ruby_guestfs_free (g);
9161   DATA_PTR (gv) = NULL;
9162
9163   return Qnil;
9164 }
9165
9166 ";
9167
9168   List.iter (
9169     fun (name, style, _, _, _, _, _) ->
9170       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9171       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9172       pr ")\n";
9173       pr "{\n";
9174       pr "  guestfs_h *g;\n";
9175       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9176       pr "  if (!g)\n";
9177       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9178         name;
9179       pr "\n";
9180
9181       List.iter (
9182         function
9183         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9184             pr "  Check_Type (%sv, T_STRING);\n" n;
9185             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9186             pr "  if (!%s)\n" n;
9187             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9188             pr "              \"%s\", \"%s\");\n" n name
9189         | OptString n ->
9190             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9191         | StringList n | DeviceList n ->
9192             pr "  char **%s;\n" n;
9193             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9194             pr "  {\n";
9195             pr "    int i, len;\n";
9196             pr "    len = RARRAY_LEN (%sv);\n" n;
9197             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9198               n;
9199             pr "    for (i = 0; i < len; ++i) {\n";
9200             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9201             pr "      %s[i] = StringValueCStr (v);\n" n;
9202             pr "    }\n";
9203             pr "    %s[len] = NULL;\n" n;
9204             pr "  }\n";
9205         | Bool n ->
9206             pr "  int %s = RTEST (%sv);\n" n n
9207         | Int n ->
9208             pr "  int %s = NUM2INT (%sv);\n" n n
9209         | Int64 n ->
9210             pr "  long long %s = NUM2LL (%sv);\n" n n
9211       ) (snd style);
9212       pr "\n";
9213
9214       let error_code =
9215         match fst style with
9216         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9217         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9218         | RConstString _ | RConstOptString _ ->
9219             pr "  const char *r;\n"; "NULL"
9220         | RString _ -> pr "  char *r;\n"; "NULL"
9221         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9222         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9223         | RStructList (_, typ) ->
9224             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9225         | RBufferOut _ ->
9226             pr "  char *r;\n";
9227             pr "  size_t size;\n";
9228             "NULL" in
9229       pr "\n";
9230
9231       pr "  r = guestfs_%s " name;
9232       generate_c_call_args ~handle:"g" style;
9233       pr ";\n";
9234
9235       List.iter (
9236         function
9237         | Pathname _ | Device _ | Dev_or_Path _ | String _
9238         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9239         | StringList n | DeviceList n ->
9240             pr "  free (%s);\n" n
9241       ) (snd style);
9242
9243       pr "  if (r == %s)\n" error_code;
9244       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9245       pr "\n";
9246
9247       (match fst style with
9248        | RErr ->
9249            pr "  return Qnil;\n"
9250        | RInt _ | RBool _ ->
9251            pr "  return INT2NUM (r);\n"
9252        | RInt64 _ ->
9253            pr "  return ULL2NUM (r);\n"
9254        | RConstString _ ->
9255            pr "  return rb_str_new2 (r);\n";
9256        | RConstOptString _ ->
9257            pr "  if (r)\n";
9258            pr "    return rb_str_new2 (r);\n";
9259            pr "  else\n";
9260            pr "    return Qnil;\n";
9261        | RString _ ->
9262            pr "  VALUE rv = rb_str_new2 (r);\n";
9263            pr "  free (r);\n";
9264            pr "  return rv;\n";
9265        | RStringList _ ->
9266            pr "  int i, len = 0;\n";
9267            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9268            pr "  VALUE rv = rb_ary_new2 (len);\n";
9269            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9270            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9271            pr "    free (r[i]);\n";
9272            pr "  }\n";
9273            pr "  free (r);\n";
9274            pr "  return rv;\n"
9275        | RStruct (_, typ) ->
9276            let cols = cols_of_struct typ in
9277            generate_ruby_struct_code typ cols
9278        | RStructList (_, typ) ->
9279            let cols = cols_of_struct typ in
9280            generate_ruby_struct_list_code typ cols
9281        | RHashtable _ ->
9282            pr "  VALUE rv = rb_hash_new ();\n";
9283            pr "  int i;\n";
9284            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9285            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9286            pr "    free (r[i]);\n";
9287            pr "    free (r[i+1]);\n";
9288            pr "  }\n";
9289            pr "  free (r);\n";
9290            pr "  return rv;\n"
9291        | RBufferOut _ ->
9292            pr "  VALUE rv = rb_str_new (r, size);\n";
9293            pr "  free (r);\n";
9294            pr "  return rv;\n";
9295       );
9296
9297       pr "}\n";
9298       pr "\n"
9299   ) all_functions;
9300
9301   pr "\
9302 /* Initialize the module. */
9303 void Init__guestfs ()
9304 {
9305   m_guestfs = rb_define_module (\"Guestfs\");
9306   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9307   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9308
9309   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9310   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9311
9312 ";
9313   (* Define the rest of the methods. *)
9314   List.iter (
9315     fun (name, style, _, _, _, _, _) ->
9316       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9317       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9318   ) all_functions;
9319
9320   pr "}\n"
9321
9322 (* Ruby code to return a struct. *)
9323 and generate_ruby_struct_code typ cols =
9324   pr "  VALUE rv = rb_hash_new ();\n";
9325   List.iter (
9326     function
9327     | name, FString ->
9328         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9329     | name, FBuffer ->
9330         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9331     | name, FUUID ->
9332         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9333     | name, (FBytes|FUInt64) ->
9334         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9335     | name, FInt64 ->
9336         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9337     | name, FUInt32 ->
9338         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9339     | name, FInt32 ->
9340         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9341     | name, FOptPercent ->
9342         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9343     | name, FChar -> (* XXX wrong? *)
9344         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9345   ) cols;
9346   pr "  guestfs_free_%s (r);\n" typ;
9347   pr "  return rv;\n"
9348
9349 (* Ruby code to return a struct list. *)
9350 and generate_ruby_struct_list_code typ cols =
9351   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9352   pr "  int i;\n";
9353   pr "  for (i = 0; i < r->len; ++i) {\n";
9354   pr "    VALUE hv = rb_hash_new ();\n";
9355   List.iter (
9356     function
9357     | name, FString ->
9358         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9359     | name, FBuffer ->
9360         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
9361     | name, FUUID ->
9362         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9363     | name, (FBytes|FUInt64) ->
9364         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9365     | name, FInt64 ->
9366         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9367     | name, FUInt32 ->
9368         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9369     | name, FInt32 ->
9370         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9371     | name, FOptPercent ->
9372         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9373     | name, FChar -> (* XXX wrong? *)
9374         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9375   ) cols;
9376   pr "    rb_ary_push (rv, hv);\n";
9377   pr "  }\n";
9378   pr "  guestfs_free_%s_list (r);\n" typ;
9379   pr "  return rv;\n"
9380
9381 (* Generate Java bindings GuestFS.java file. *)
9382 and generate_java_java () =
9383   generate_header CStyle LGPLv2plus;
9384
9385   pr "\
9386 package com.redhat.et.libguestfs;
9387
9388 import java.util.HashMap;
9389 import com.redhat.et.libguestfs.LibGuestFSException;
9390 import com.redhat.et.libguestfs.PV;
9391 import com.redhat.et.libguestfs.VG;
9392 import com.redhat.et.libguestfs.LV;
9393 import com.redhat.et.libguestfs.Stat;
9394 import com.redhat.et.libguestfs.StatVFS;
9395 import com.redhat.et.libguestfs.IntBool;
9396 import com.redhat.et.libguestfs.Dirent;
9397
9398 /**
9399  * The GuestFS object is a libguestfs handle.
9400  *
9401  * @author rjones
9402  */
9403 public class GuestFS {
9404   // Load the native code.
9405   static {
9406     System.loadLibrary (\"guestfs_jni\");
9407   }
9408
9409   /**
9410    * The native guestfs_h pointer.
9411    */
9412   long g;
9413
9414   /**
9415    * Create a libguestfs handle.
9416    *
9417    * @throws LibGuestFSException
9418    */
9419   public GuestFS () throws LibGuestFSException
9420   {
9421     g = _create ();
9422   }
9423   private native long _create () throws LibGuestFSException;
9424
9425   /**
9426    * Close a libguestfs handle.
9427    *
9428    * You can also leave handles to be collected by the garbage
9429    * collector, but this method ensures that the resources used
9430    * by the handle are freed up immediately.  If you call any
9431    * other methods after closing the handle, you will get an
9432    * exception.
9433    *
9434    * @throws LibGuestFSException
9435    */
9436   public void close () throws LibGuestFSException
9437   {
9438     if (g != 0)
9439       _close (g);
9440     g = 0;
9441   }
9442   private native void _close (long g) throws LibGuestFSException;
9443
9444   public void finalize () throws LibGuestFSException
9445   {
9446     close ();
9447   }
9448
9449 ";
9450
9451   List.iter (
9452     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9453       if not (List.mem NotInDocs flags); then (
9454         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9455         let doc =
9456           if List.mem ProtocolLimitWarning flags then
9457             doc ^ "\n\n" ^ protocol_limit_warning
9458           else doc in
9459         let doc =
9460           if List.mem DangerWillRobinson flags then
9461             doc ^ "\n\n" ^ danger_will_robinson
9462           else doc in
9463         let doc =
9464           match deprecation_notice flags with
9465           | None -> doc
9466           | Some txt -> doc ^ "\n\n" ^ txt in
9467         let doc = pod2text ~width:60 name doc in
9468         let doc = List.map (            (* RHBZ#501883 *)
9469           function
9470           | "" -> "<p>"
9471           | nonempty -> nonempty
9472         ) doc in
9473         let doc = String.concat "\n   * " doc in
9474
9475         pr "  /**\n";
9476         pr "   * %s\n" shortdesc;
9477         pr "   * <p>\n";
9478         pr "   * %s\n" doc;
9479         pr "   * @throws LibGuestFSException\n";
9480         pr "   */\n";
9481         pr "  ";
9482       );
9483       generate_java_prototype ~public:true ~semicolon:false name style;
9484       pr "\n";
9485       pr "  {\n";
9486       pr "    if (g == 0)\n";
9487       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9488         name;
9489       pr "    ";
9490       if fst style <> RErr then pr "return ";
9491       pr "_%s " name;
9492       generate_java_call_args ~handle:"g" (snd style);
9493       pr ";\n";
9494       pr "  }\n";
9495       pr "  ";
9496       generate_java_prototype ~privat:true ~native:true name style;
9497       pr "\n";
9498       pr "\n";
9499   ) all_functions;
9500
9501   pr "}\n"
9502
9503 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9504 and generate_java_call_args ~handle args =
9505   pr "(%s" handle;
9506   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9507   pr ")"
9508
9509 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9510     ?(semicolon=true) name style =
9511   if privat then pr "private ";
9512   if public then pr "public ";
9513   if native then pr "native ";
9514
9515   (* return type *)
9516   (match fst style with
9517    | RErr -> pr "void ";
9518    | RInt _ -> pr "int ";
9519    | RInt64 _ -> pr "long ";
9520    | RBool _ -> pr "boolean ";
9521    | RConstString _ | RConstOptString _ | RString _
9522    | RBufferOut _ -> pr "String ";
9523    | RStringList _ -> pr "String[] ";
9524    | RStruct (_, typ) ->
9525        let name = java_name_of_struct typ in
9526        pr "%s " name;
9527    | RStructList (_, typ) ->
9528        let name = java_name_of_struct typ in
9529        pr "%s[] " name;
9530    | RHashtable _ -> pr "HashMap<String,String> ";
9531   );
9532
9533   if native then pr "_%s " name else pr "%s " name;
9534   pr "(";
9535   let needs_comma = ref false in
9536   if native then (
9537     pr "long g";
9538     needs_comma := true
9539   );
9540
9541   (* args *)
9542   List.iter (
9543     fun arg ->
9544       if !needs_comma then pr ", ";
9545       needs_comma := true;
9546
9547       match arg with
9548       | Pathname n
9549       | Device n | Dev_or_Path n
9550       | String n
9551       | OptString n
9552       | FileIn n
9553       | FileOut n ->
9554           pr "String %s" n
9555       | StringList n | DeviceList n ->
9556           pr "String[] %s" n
9557       | Bool n ->
9558           pr "boolean %s" n
9559       | Int n ->
9560           pr "int %s" n
9561       | Int64 n ->
9562           pr "long %s" n
9563   ) (snd style);
9564
9565   pr ")\n";
9566   pr "    throws LibGuestFSException";
9567   if semicolon then pr ";"
9568
9569 and generate_java_struct jtyp cols () =
9570   generate_header CStyle LGPLv2plus;
9571
9572   pr "\
9573 package com.redhat.et.libguestfs;
9574
9575 /**
9576  * Libguestfs %s structure.
9577  *
9578  * @author rjones
9579  * @see GuestFS
9580  */
9581 public class %s {
9582 " jtyp jtyp;
9583
9584   List.iter (
9585     function
9586     | name, FString
9587     | name, FUUID
9588     | name, FBuffer -> pr "  public String %s;\n" name
9589     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9590     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9591     | name, FChar -> pr "  public char %s;\n" name
9592     | name, FOptPercent ->
9593         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9594         pr "  public float %s;\n" name
9595   ) cols;
9596
9597   pr "}\n"
9598
9599 and generate_java_c () =
9600   generate_header CStyle LGPLv2plus;
9601
9602   pr "\
9603 #include <stdio.h>
9604 #include <stdlib.h>
9605 #include <string.h>
9606
9607 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9608 #include \"guestfs.h\"
9609
9610 /* Note that this function returns.  The exception is not thrown
9611  * until after the wrapper function returns.
9612  */
9613 static void
9614 throw_exception (JNIEnv *env, const char *msg)
9615 {
9616   jclass cl;
9617   cl = (*env)->FindClass (env,
9618                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9619   (*env)->ThrowNew (env, cl, msg);
9620 }
9621
9622 JNIEXPORT jlong JNICALL
9623 Java_com_redhat_et_libguestfs_GuestFS__1create
9624   (JNIEnv *env, jobject obj)
9625 {
9626   guestfs_h *g;
9627
9628   g = guestfs_create ();
9629   if (g == NULL) {
9630     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9631     return 0;
9632   }
9633   guestfs_set_error_handler (g, NULL, NULL);
9634   return (jlong) (long) g;
9635 }
9636
9637 JNIEXPORT void JNICALL
9638 Java_com_redhat_et_libguestfs_GuestFS__1close
9639   (JNIEnv *env, jobject obj, jlong jg)
9640 {
9641   guestfs_h *g = (guestfs_h *) (long) jg;
9642   guestfs_close (g);
9643 }
9644
9645 ";
9646
9647   List.iter (
9648     fun (name, style, _, _, _, _, _) ->
9649       pr "JNIEXPORT ";
9650       (match fst style with
9651        | RErr -> pr "void ";
9652        | RInt _ -> pr "jint ";
9653        | RInt64 _ -> pr "jlong ";
9654        | RBool _ -> pr "jboolean ";
9655        | RConstString _ | RConstOptString _ | RString _
9656        | RBufferOut _ -> pr "jstring ";
9657        | RStruct _ | RHashtable _ ->
9658            pr "jobject ";
9659        | RStringList _ | RStructList _ ->
9660            pr "jobjectArray ";
9661       );
9662       pr "JNICALL\n";
9663       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9664       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9665       pr "\n";
9666       pr "  (JNIEnv *env, jobject obj, jlong jg";
9667       List.iter (
9668         function
9669         | Pathname n
9670         | Device n | Dev_or_Path n
9671         | String n
9672         | OptString n
9673         | FileIn n
9674         | FileOut n ->
9675             pr ", jstring j%s" n
9676         | StringList n | DeviceList n ->
9677             pr ", jobjectArray j%s" n
9678         | Bool n ->
9679             pr ", jboolean j%s" n
9680         | Int n ->
9681             pr ", jint j%s" n
9682         | Int64 n ->
9683             pr ", jlong j%s" n
9684       ) (snd style);
9685       pr ")\n";
9686       pr "{\n";
9687       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
9688       let error_code, no_ret =
9689         match fst style with
9690         | RErr -> pr "  int r;\n"; "-1", ""
9691         | RBool _
9692         | RInt _ -> pr "  int r;\n"; "-1", "0"
9693         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
9694         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9695         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9696         | RString _ ->
9697             pr "  jstring jr;\n";
9698             pr "  char *r;\n"; "NULL", "NULL"
9699         | RStringList _ ->
9700             pr "  jobjectArray jr;\n";
9701             pr "  int r_len;\n";
9702             pr "  jclass cl;\n";
9703             pr "  jstring jstr;\n";
9704             pr "  char **r;\n"; "NULL", "NULL"
9705         | RStruct (_, typ) ->
9706             pr "  jobject jr;\n";
9707             pr "  jclass cl;\n";
9708             pr "  jfieldID fl;\n";
9709             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
9710         | RStructList (_, typ) ->
9711             pr "  jobjectArray jr;\n";
9712             pr "  jclass cl;\n";
9713             pr "  jfieldID fl;\n";
9714             pr "  jobject jfl;\n";
9715             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
9716         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
9717         | RBufferOut _ ->
9718             pr "  jstring jr;\n";
9719             pr "  char *r;\n";
9720             pr "  size_t size;\n";
9721             "NULL", "NULL" in
9722       List.iter (
9723         function
9724         | Pathname n
9725         | Device n | Dev_or_Path n
9726         | String n
9727         | OptString n
9728         | FileIn n
9729         | FileOut n ->
9730             pr "  const char *%s;\n" n
9731         | StringList n | DeviceList n ->
9732             pr "  int %s_len;\n" n;
9733             pr "  const char **%s;\n" n
9734         | Bool n
9735         | Int n ->
9736             pr "  int %s;\n" n
9737         | Int64 n ->
9738             pr "  int64_t %s;\n" n
9739       ) (snd style);
9740
9741       let needs_i =
9742         (match fst style with
9743          | RStringList _ | RStructList _ -> true
9744          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
9745          | RConstOptString _
9746          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
9747           List.exists (function
9748                        | StringList _ -> true
9749                        | DeviceList _ -> true
9750                        | _ -> false) (snd style) in
9751       if needs_i then
9752         pr "  int i;\n";
9753
9754       pr "\n";
9755
9756       (* Get the parameters. *)
9757       List.iter (
9758         function
9759         | Pathname n
9760         | Device n | Dev_or_Path n
9761         | String n
9762         | FileIn n
9763         | FileOut n ->
9764             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
9765         | OptString n ->
9766             (* This is completely undocumented, but Java null becomes
9767              * a NULL parameter.
9768              *)
9769             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
9770         | StringList n | DeviceList n ->
9771             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
9772             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
9773             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9774             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9775               n;
9776             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
9777             pr "  }\n";
9778             pr "  %s[%s_len] = NULL;\n" n n;
9779         | Bool n
9780         | Int n
9781         | Int64 n ->
9782             pr "  %s = j%s;\n" n n
9783       ) (snd style);
9784
9785       (* Make the call. *)
9786       pr "  r = guestfs_%s " name;
9787       generate_c_call_args ~handle:"g" style;
9788       pr ";\n";
9789
9790       (* Release the parameters. *)
9791       List.iter (
9792         function
9793         | Pathname n
9794         | Device n | Dev_or_Path n
9795         | String n
9796         | FileIn n
9797         | FileOut n ->
9798             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9799         | OptString n ->
9800             pr "  if (j%s)\n" n;
9801             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
9802         | StringList n | DeviceList n ->
9803             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
9804             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
9805               n;
9806             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
9807             pr "  }\n";
9808             pr "  free (%s);\n" n
9809         | Bool n
9810         | Int n
9811         | Int64 n -> ()
9812       ) (snd style);
9813
9814       (* Check for errors. *)
9815       pr "  if (r == %s) {\n" error_code;
9816       pr "    throw_exception (env, guestfs_last_error (g));\n";
9817       pr "    return %s;\n" no_ret;
9818       pr "  }\n";
9819
9820       (* Return value. *)
9821       (match fst style with
9822        | RErr -> ()
9823        | RInt _ -> pr "  return (jint) r;\n"
9824        | RBool _ -> pr "  return (jboolean) r;\n"
9825        | RInt64 _ -> pr "  return (jlong) r;\n"
9826        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
9827        | RConstOptString _ ->
9828            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
9829        | RString _ ->
9830            pr "  jr = (*env)->NewStringUTF (env, r);\n";
9831            pr "  free (r);\n";
9832            pr "  return jr;\n"
9833        | RStringList _ ->
9834            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
9835            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
9836            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
9837            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
9838            pr "  for (i = 0; i < r_len; ++i) {\n";
9839            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
9840            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
9841            pr "    free (r[i]);\n";
9842            pr "  }\n";
9843            pr "  free (r);\n";
9844            pr "  return jr;\n"
9845        | RStruct (_, typ) ->
9846            let jtyp = java_name_of_struct typ in
9847            let cols = cols_of_struct typ in
9848            generate_java_struct_return typ jtyp cols
9849        | RStructList (_, typ) ->
9850            let jtyp = java_name_of_struct typ in
9851            let cols = cols_of_struct typ in
9852            generate_java_struct_list_return typ jtyp cols
9853        | RHashtable _ ->
9854            (* XXX *)
9855            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
9856            pr "  return NULL;\n"
9857        | RBufferOut _ ->
9858            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
9859            pr "  free (r);\n";
9860            pr "  return jr;\n"
9861       );
9862
9863       pr "}\n";
9864       pr "\n"
9865   ) all_functions
9866
9867 and generate_java_struct_return typ jtyp cols =
9868   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9869   pr "  jr = (*env)->AllocObject (env, cl);\n";
9870   List.iter (
9871     function
9872     | name, FString ->
9873         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9874         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
9875     | name, FUUID ->
9876         pr "  {\n";
9877         pr "    char s[33];\n";
9878         pr "    memcpy (s, r->%s, 32);\n" name;
9879         pr "    s[32] = 0;\n";
9880         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9881         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9882         pr "  }\n";
9883     | name, FBuffer ->
9884         pr "  {\n";
9885         pr "    int len = r->%s_len;\n" name;
9886         pr "    char s[len+1];\n";
9887         pr "    memcpy (s, r->%s, len);\n" name;
9888         pr "    s[len] = 0;\n";
9889         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9890         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
9891         pr "  }\n";
9892     | name, (FBytes|FUInt64|FInt64) ->
9893         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9894         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9895     | name, (FUInt32|FInt32) ->
9896         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9897         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9898     | name, FOptPercent ->
9899         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9900         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
9901     | name, FChar ->
9902         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9903         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
9904   ) cols;
9905   pr "  free (r);\n";
9906   pr "  return jr;\n"
9907
9908 and generate_java_struct_list_return typ jtyp cols =
9909   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
9910   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
9911   pr "  for (i = 0; i < r->len; ++i) {\n";
9912   pr "    jfl = (*env)->AllocObject (env, cl);\n";
9913   List.iter (
9914     function
9915     | name, FString ->
9916         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9917         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
9918     | name, FUUID ->
9919         pr "    {\n";
9920         pr "      char s[33];\n";
9921         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
9922         pr "      s[32] = 0;\n";
9923         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9924         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9925         pr "    }\n";
9926     | name, FBuffer ->
9927         pr "    {\n";
9928         pr "      int len = r->val[i].%s_len;\n" name;
9929         pr "      char s[len+1];\n";
9930         pr "      memcpy (s, r->val[i].%s, len);\n" name;
9931         pr "      s[len] = 0;\n";
9932         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
9933         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
9934         pr "    }\n";
9935     | name, (FBytes|FUInt64|FInt64) ->
9936         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
9937         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9938     | name, (FUInt32|FInt32) ->
9939         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
9940         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9941     | name, FOptPercent ->
9942         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
9943         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
9944     | name, FChar ->
9945         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
9946         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
9947   ) cols;
9948   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
9949   pr "  }\n";
9950   pr "  guestfs_free_%s_list (r);\n" typ;
9951   pr "  return jr;\n"
9952
9953 and generate_java_makefile_inc () =
9954   generate_header HashStyle GPLv2plus;
9955
9956   pr "java_built_sources = \\\n";
9957   List.iter (
9958     fun (typ, jtyp) ->
9959         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
9960   ) java_structs;
9961   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
9962
9963 and generate_haskell_hs () =
9964   generate_header HaskellStyle LGPLv2plus;
9965
9966   (* XXX We only know how to generate partial FFI for Haskell
9967    * at the moment.  Please help out!
9968    *)
9969   let can_generate style =
9970     match style with
9971     | RErr, _
9972     | RInt _, _
9973     | RInt64 _, _ -> true
9974     | RBool _, _
9975     | RConstString _, _
9976     | RConstOptString _, _
9977     | RString _, _
9978     | RStringList _, _
9979     | RStruct _, _
9980     | RStructList _, _
9981     | RHashtable _, _
9982     | RBufferOut _, _ -> false in
9983
9984   pr "\
9985 {-# INCLUDE <guestfs.h> #-}
9986 {-# LANGUAGE ForeignFunctionInterface #-}
9987
9988 module Guestfs (
9989   create";
9990
9991   (* List out the names of the actions we want to export. *)
9992   List.iter (
9993     fun (name, style, _, _, _, _, _) ->
9994       if can_generate style then pr ",\n  %s" name
9995   ) all_functions;
9996
9997   pr "
9998   ) where
9999
10000 -- Unfortunately some symbols duplicate ones already present
10001 -- in Prelude.  We don't know which, so we hard-code a list
10002 -- here.
10003 import Prelude hiding (truncate)
10004
10005 import Foreign
10006 import Foreign.C
10007 import Foreign.C.Types
10008 import IO
10009 import Control.Exception
10010 import Data.Typeable
10011
10012 data GuestfsS = GuestfsS            -- represents the opaque C struct
10013 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
10014 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
10015
10016 -- XXX define properly later XXX
10017 data PV = PV
10018 data VG = VG
10019 data LV = LV
10020 data IntBool = IntBool
10021 data Stat = Stat
10022 data StatVFS = StatVFS
10023 data Hashtable = Hashtable
10024
10025 foreign import ccall unsafe \"guestfs_create\" c_create
10026   :: IO GuestfsP
10027 foreign import ccall unsafe \"&guestfs_close\" c_close
10028   :: FunPtr (GuestfsP -> IO ())
10029 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
10030   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
10031
10032 create :: IO GuestfsH
10033 create = do
10034   p <- c_create
10035   c_set_error_handler p nullPtr nullPtr
10036   h <- newForeignPtr c_close p
10037   return h
10038
10039 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
10040   :: GuestfsP -> IO CString
10041
10042 -- last_error :: GuestfsH -> IO (Maybe String)
10043 -- last_error h = do
10044 --   str <- withForeignPtr h (\\p -> c_last_error p)
10045 --   maybePeek peekCString str
10046
10047 last_error :: GuestfsH -> IO (String)
10048 last_error h = do
10049   str <- withForeignPtr h (\\p -> c_last_error p)
10050   if (str == nullPtr)
10051     then return \"no error\"
10052     else peekCString str
10053
10054 ";
10055
10056   (* Generate wrappers for each foreign function. *)
10057   List.iter (
10058     fun (name, style, _, _, _, _, _) ->
10059       if can_generate style then (
10060         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
10061         pr "  :: ";
10062         generate_haskell_prototype ~handle:"GuestfsP" style;
10063         pr "\n";
10064         pr "\n";
10065         pr "%s :: " name;
10066         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
10067         pr "\n";
10068         pr "%s %s = do\n" name
10069           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
10070         pr "  r <- ";
10071         (* Convert pointer arguments using with* functions. *)
10072         List.iter (
10073           function
10074           | FileIn n
10075           | FileOut n
10076           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
10077           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
10078           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
10079           | Bool _ | Int _ | Int64 _ -> ()
10080         ) (snd style);
10081         (* Convert integer arguments. *)
10082         let args =
10083           List.map (
10084             function
10085             | Bool n -> sprintf "(fromBool %s)" n
10086             | Int n -> sprintf "(fromIntegral %s)" n
10087             | Int64 n -> sprintf "(fromIntegral %s)" n
10088             | FileIn n | FileOut n
10089             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
10090           ) (snd style) in
10091         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
10092           (String.concat " " ("p" :: args));
10093         (match fst style with
10094          | RErr | RInt _ | RInt64 _ | RBool _ ->
10095              pr "  if (r == -1)\n";
10096              pr "    then do\n";
10097              pr "      err <- last_error h\n";
10098              pr "      fail err\n";
10099          | RConstString _ | RConstOptString _ | RString _
10100          | RStringList _ | RStruct _
10101          | RStructList _ | RHashtable _ | RBufferOut _ ->
10102              pr "  if (r == nullPtr)\n";
10103              pr "    then do\n";
10104              pr "      err <- last_error h\n";
10105              pr "      fail err\n";
10106         );
10107         (match fst style with
10108          | RErr ->
10109              pr "    else return ()\n"
10110          | RInt _ ->
10111              pr "    else return (fromIntegral r)\n"
10112          | RInt64 _ ->
10113              pr "    else return (fromIntegral r)\n"
10114          | RBool _ ->
10115              pr "    else return (toBool r)\n"
10116          | RConstString _
10117          | RConstOptString _
10118          | RString _
10119          | RStringList _
10120          | RStruct _
10121          | RStructList _
10122          | RHashtable _
10123          | RBufferOut _ ->
10124              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10125         );
10126         pr "\n";
10127       )
10128   ) all_functions
10129
10130 and generate_haskell_prototype ~handle ?(hs = false) style =
10131   pr "%s -> " handle;
10132   let string = if hs then "String" else "CString" in
10133   let int = if hs then "Int" else "CInt" in
10134   let bool = if hs then "Bool" else "CInt" in
10135   let int64 = if hs then "Integer" else "Int64" in
10136   List.iter (
10137     fun arg ->
10138       (match arg with
10139        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10140        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10141        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10142        | Bool _ -> pr "%s" bool
10143        | Int _ -> pr "%s" int
10144        | Int64 _ -> pr "%s" int
10145        | FileIn _ -> pr "%s" string
10146        | FileOut _ -> pr "%s" string
10147       );
10148       pr " -> ";
10149   ) (snd style);
10150   pr "IO (";
10151   (match fst style with
10152    | RErr -> if not hs then pr "CInt"
10153    | RInt _ -> pr "%s" int
10154    | RInt64 _ -> pr "%s" int64
10155    | RBool _ -> pr "%s" bool
10156    | RConstString _ -> pr "%s" string
10157    | RConstOptString _ -> pr "Maybe %s" string
10158    | RString _ -> pr "%s" string
10159    | RStringList _ -> pr "[%s]" string
10160    | RStruct (_, typ) ->
10161        let name = java_name_of_struct typ in
10162        pr "%s" name
10163    | RStructList (_, typ) ->
10164        let name = java_name_of_struct typ in
10165        pr "[%s]" name
10166    | RHashtable _ -> pr "Hashtable"
10167    | RBufferOut _ -> pr "%s" string
10168   );
10169   pr ")"
10170
10171 and generate_csharp () =
10172   generate_header CPlusPlusStyle LGPLv2plus;
10173
10174   (* XXX Make this configurable by the C# assembly users. *)
10175   let library = "libguestfs.so.0" in
10176
10177   pr "\
10178 // These C# bindings are highly experimental at present.
10179 //
10180 // Firstly they only work on Linux (ie. Mono).  In order to get them
10181 // to work on Windows (ie. .Net) you would need to port the library
10182 // itself to Windows first.
10183 //
10184 // The second issue is that some calls are known to be incorrect and
10185 // can cause Mono to segfault.  Particularly: calls which pass or
10186 // return string[], or return any structure value.  This is because
10187 // we haven't worked out the correct way to do this from C#.
10188 //
10189 // The third issue is that when compiling you get a lot of warnings.
10190 // We are not sure whether the warnings are important or not.
10191 //
10192 // Fourthly we do not routinely build or test these bindings as part
10193 // of the make && make check cycle, which means that regressions might
10194 // go unnoticed.
10195 //
10196 // Suggestions and patches are welcome.
10197
10198 // To compile:
10199 //
10200 // gmcs Libguestfs.cs
10201 // mono Libguestfs.exe
10202 //
10203 // (You'll probably want to add a Test class / static main function
10204 // otherwise this won't do anything useful).
10205
10206 using System;
10207 using System.IO;
10208 using System.Runtime.InteropServices;
10209 using System.Runtime.Serialization;
10210 using System.Collections;
10211
10212 namespace Guestfs
10213 {
10214   class Error : System.ApplicationException
10215   {
10216     public Error (string message) : base (message) {}
10217     protected Error (SerializationInfo info, StreamingContext context) {}
10218   }
10219
10220   class Guestfs
10221   {
10222     IntPtr _handle;
10223
10224     [DllImport (\"%s\")]
10225     static extern IntPtr guestfs_create ();
10226
10227     public Guestfs ()
10228     {
10229       _handle = guestfs_create ();
10230       if (_handle == IntPtr.Zero)
10231         throw new Error (\"could not create guestfs handle\");
10232     }
10233
10234     [DllImport (\"%s\")]
10235     static extern void guestfs_close (IntPtr h);
10236
10237     ~Guestfs ()
10238     {
10239       guestfs_close (_handle);
10240     }
10241
10242     [DllImport (\"%s\")]
10243     static extern string guestfs_last_error (IntPtr h);
10244
10245 " library library library;
10246
10247   (* Generate C# structure bindings.  We prefix struct names with
10248    * underscore because C# cannot have conflicting struct names and
10249    * method names (eg. "class stat" and "stat").
10250    *)
10251   List.iter (
10252     fun (typ, cols) ->
10253       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10254       pr "    public class _%s {\n" typ;
10255       List.iter (
10256         function
10257         | name, FChar -> pr "      char %s;\n" name
10258         | name, FString -> pr "      string %s;\n" name
10259         | name, FBuffer ->
10260             pr "      uint %s_len;\n" name;
10261             pr "      string %s;\n" name
10262         | name, FUUID ->
10263             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10264             pr "      string %s;\n" name
10265         | name, FUInt32 -> pr "      uint %s;\n" name
10266         | name, FInt32 -> pr "      int %s;\n" name
10267         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10268         | name, FInt64 -> pr "      long %s;\n" name
10269         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10270       ) cols;
10271       pr "    }\n";
10272       pr "\n"
10273   ) structs;
10274
10275   (* Generate C# function bindings. *)
10276   List.iter (
10277     fun (name, style, _, _, _, shortdesc, _) ->
10278       let rec csharp_return_type () =
10279         match fst style with
10280         | RErr -> "void"
10281         | RBool n -> "bool"
10282         | RInt n -> "int"
10283         | RInt64 n -> "long"
10284         | RConstString n
10285         | RConstOptString n
10286         | RString n
10287         | RBufferOut n -> "string"
10288         | RStruct (_,n) -> "_" ^ n
10289         | RHashtable n -> "Hashtable"
10290         | RStringList n -> "string[]"
10291         | RStructList (_,n) -> sprintf "_%s[]" n
10292
10293       and c_return_type () =
10294         match fst style with
10295         | RErr
10296         | RBool _
10297         | RInt _ -> "int"
10298         | RInt64 _ -> "long"
10299         | RConstString _
10300         | RConstOptString _
10301         | RString _
10302         | RBufferOut _ -> "string"
10303         | RStruct (_,n) -> "_" ^ n
10304         | RHashtable _
10305         | RStringList _ -> "string[]"
10306         | RStructList (_,n) -> sprintf "_%s[]" n
10307
10308       and c_error_comparison () =
10309         match fst style with
10310         | RErr
10311         | RBool _
10312         | RInt _
10313         | RInt64 _ -> "== -1"
10314         | RConstString _
10315         | RConstOptString _
10316         | RString _
10317         | RBufferOut _
10318         | RStruct (_,_)
10319         | RHashtable _
10320         | RStringList _
10321         | RStructList (_,_) -> "== null"
10322
10323       and generate_extern_prototype () =
10324         pr "    static extern %s guestfs_%s (IntPtr h"
10325           (c_return_type ()) name;
10326         List.iter (
10327           function
10328           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10329           | FileIn n | FileOut n ->
10330               pr ", [In] string %s" n
10331           | StringList n | DeviceList n ->
10332               pr ", [In] string[] %s" n
10333           | Bool n ->
10334               pr ", bool %s" n
10335           | Int n ->
10336               pr ", int %s" n
10337           | Int64 n ->
10338               pr ", long %s" n
10339         ) (snd style);
10340         pr ");\n"
10341
10342       and generate_public_prototype () =
10343         pr "    public %s %s (" (csharp_return_type ()) name;
10344         let comma = ref false in
10345         let next () =
10346           if !comma then pr ", ";
10347           comma := true
10348         in
10349         List.iter (
10350           function
10351           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10352           | FileIn n | FileOut n ->
10353               next (); pr "string %s" n
10354           | StringList n | DeviceList n ->
10355               next (); pr "string[] %s" n
10356           | Bool n ->
10357               next (); pr "bool %s" n
10358           | Int n ->
10359               next (); pr "int %s" n
10360           | Int64 n ->
10361               next (); pr "long %s" n
10362         ) (snd style);
10363         pr ")\n"
10364
10365       and generate_call () =
10366         pr "guestfs_%s (_handle" name;
10367         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10368         pr ");\n";
10369       in
10370
10371       pr "    [DllImport (\"%s\")]\n" library;
10372       generate_extern_prototype ();
10373       pr "\n";
10374       pr "    /// <summary>\n";
10375       pr "    /// %s\n" shortdesc;
10376       pr "    /// </summary>\n";
10377       generate_public_prototype ();
10378       pr "    {\n";
10379       pr "      %s r;\n" (c_return_type ());
10380       pr "      r = ";
10381       generate_call ();
10382       pr "      if (r %s)\n" (c_error_comparison ());
10383       pr "        throw new Error (guestfs_last_error (_handle));\n";
10384       (match fst style with
10385        | RErr -> ()
10386        | RBool _ ->
10387            pr "      return r != 0 ? true : false;\n"
10388        | RHashtable _ ->
10389            pr "      Hashtable rr = new Hashtable ();\n";
10390            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10391            pr "        rr.Add (r[i], r[i+1]);\n";
10392            pr "      return rr;\n"
10393        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10394        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10395        | RStructList _ ->
10396            pr "      return r;\n"
10397       );
10398       pr "    }\n";
10399       pr "\n";
10400   ) all_functions_sorted;
10401
10402   pr "  }
10403 }
10404 "
10405
10406 and generate_bindtests () =
10407   generate_header CStyle LGPLv2plus;
10408
10409   pr "\
10410 #include <stdio.h>
10411 #include <stdlib.h>
10412 #include <inttypes.h>
10413 #include <string.h>
10414
10415 #include \"guestfs.h\"
10416 #include \"guestfs-internal.h\"
10417 #include \"guestfs-internal-actions.h\"
10418 #include \"guestfs_protocol.h\"
10419
10420 #define error guestfs_error
10421 #define safe_calloc guestfs_safe_calloc
10422 #define safe_malloc guestfs_safe_malloc
10423
10424 static void
10425 print_strings (char *const *argv)
10426 {
10427   int argc;
10428
10429   printf (\"[\");
10430   for (argc = 0; argv[argc] != NULL; ++argc) {
10431     if (argc > 0) printf (\", \");
10432     printf (\"\\\"%%s\\\"\", argv[argc]);
10433   }
10434   printf (\"]\\n\");
10435 }
10436
10437 /* The test0 function prints its parameters to stdout. */
10438 ";
10439
10440   let test0, tests =
10441     match test_functions with
10442     | [] -> assert false
10443     | test0 :: tests -> test0, tests in
10444
10445   let () =
10446     let (name, style, _, _, _, _, _) = test0 in
10447     generate_prototype ~extern:false ~semicolon:false ~newline:true
10448       ~handle:"g" ~prefix:"guestfs__" name style;
10449     pr "{\n";
10450     List.iter (
10451       function
10452       | Pathname n
10453       | Device n | Dev_or_Path n
10454       | String n
10455       | FileIn n
10456       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10457       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10458       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10459       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10460       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10461       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10462     ) (snd style);
10463     pr "  /* Java changes stdout line buffering so we need this: */\n";
10464     pr "  fflush (stdout);\n";
10465     pr "  return 0;\n";
10466     pr "}\n";
10467     pr "\n" in
10468
10469   List.iter (
10470     fun (name, style, _, _, _, _, _) ->
10471       if String.sub name (String.length name - 3) 3 <> "err" then (
10472         pr "/* Test normal return. */\n";
10473         generate_prototype ~extern:false ~semicolon:false ~newline:true
10474           ~handle:"g" ~prefix:"guestfs__" name style;
10475         pr "{\n";
10476         (match fst style with
10477          | RErr ->
10478              pr "  return 0;\n"
10479          | RInt _ ->
10480              pr "  int r;\n";
10481              pr "  sscanf (val, \"%%d\", &r);\n";
10482              pr "  return r;\n"
10483          | RInt64 _ ->
10484              pr "  int64_t r;\n";
10485              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10486              pr "  return r;\n"
10487          | RBool _ ->
10488              pr "  return STREQ (val, \"true\");\n"
10489          | RConstString _
10490          | RConstOptString _ ->
10491              (* Can't return the input string here.  Return a static
10492               * string so we ensure we get a segfault if the caller
10493               * tries to free it.
10494               *)
10495              pr "  return \"static string\";\n"
10496          | RString _ ->
10497              pr "  return strdup (val);\n"
10498          | RStringList _ ->
10499              pr "  char **strs;\n";
10500              pr "  int n, i;\n";
10501              pr "  sscanf (val, \"%%d\", &n);\n";
10502              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10503              pr "  for (i = 0; i < n; ++i) {\n";
10504              pr "    strs[i] = safe_malloc (g, 16);\n";
10505              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10506              pr "  }\n";
10507              pr "  strs[n] = NULL;\n";
10508              pr "  return strs;\n"
10509          | RStruct (_, typ) ->
10510              pr "  struct guestfs_%s *r;\n" typ;
10511              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10512              pr "  return r;\n"
10513          | RStructList (_, typ) ->
10514              pr "  struct guestfs_%s_list *r;\n" typ;
10515              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10516              pr "  sscanf (val, \"%%d\", &r->len);\n";
10517              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10518              pr "  return r;\n"
10519          | RHashtable _ ->
10520              pr "  char **strs;\n";
10521              pr "  int n, i;\n";
10522              pr "  sscanf (val, \"%%d\", &n);\n";
10523              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10524              pr "  for (i = 0; i < n; ++i) {\n";
10525              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10526              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10527              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10528              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10529              pr "  }\n";
10530              pr "  strs[n*2] = NULL;\n";
10531              pr "  return strs;\n"
10532          | RBufferOut _ ->
10533              pr "  return strdup (val);\n"
10534         );
10535         pr "}\n";
10536         pr "\n"
10537       ) else (
10538         pr "/* Test error return. */\n";
10539         generate_prototype ~extern:false ~semicolon:false ~newline:true
10540           ~handle:"g" ~prefix:"guestfs__" name style;
10541         pr "{\n";
10542         pr "  error (g, \"error\");\n";
10543         (match fst style with
10544          | RErr | RInt _ | RInt64 _ | RBool _ ->
10545              pr "  return -1;\n"
10546          | RConstString _ | RConstOptString _
10547          | RString _ | RStringList _ | RStruct _
10548          | RStructList _
10549          | RHashtable _
10550          | RBufferOut _ ->
10551              pr "  return NULL;\n"
10552         );
10553         pr "}\n";
10554         pr "\n"
10555       )
10556   ) tests
10557
10558 and generate_ocaml_bindtests () =
10559   generate_header OCamlStyle GPLv2plus;
10560
10561   pr "\
10562 let () =
10563   let g = Guestfs.create () in
10564 ";
10565
10566   let mkargs args =
10567     String.concat " " (
10568       List.map (
10569         function
10570         | CallString s -> "\"" ^ s ^ "\""
10571         | CallOptString None -> "None"
10572         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10573         | CallStringList xs ->
10574             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10575         | CallInt i when i >= 0 -> string_of_int i
10576         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10577         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10578         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10579         | CallBool b -> string_of_bool b
10580       ) args
10581     )
10582   in
10583
10584   generate_lang_bindtests (
10585     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10586   );
10587
10588   pr "print_endline \"EOF\"\n"
10589
10590 and generate_perl_bindtests () =
10591   pr "#!/usr/bin/perl -w\n";
10592   generate_header HashStyle GPLv2plus;
10593
10594   pr "\
10595 use strict;
10596
10597 use Sys::Guestfs;
10598
10599 my $g = Sys::Guestfs->new ();
10600 ";
10601
10602   let mkargs args =
10603     String.concat ", " (
10604       List.map (
10605         function
10606         | CallString s -> "\"" ^ s ^ "\""
10607         | CallOptString None -> "undef"
10608         | CallOptString (Some s) -> sprintf "\"%s\"" s
10609         | CallStringList xs ->
10610             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10611         | CallInt i -> string_of_int i
10612         | CallInt64 i -> Int64.to_string i
10613         | CallBool b -> if b then "1" else "0"
10614       ) args
10615     )
10616   in
10617
10618   generate_lang_bindtests (
10619     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10620   );
10621
10622   pr "print \"EOF\\n\"\n"
10623
10624 and generate_python_bindtests () =
10625   generate_header HashStyle GPLv2plus;
10626
10627   pr "\
10628 import guestfs
10629
10630 g = guestfs.GuestFS ()
10631 ";
10632
10633   let mkargs args =
10634     String.concat ", " (
10635       List.map (
10636         function
10637         | CallString s -> "\"" ^ s ^ "\""
10638         | CallOptString None -> "None"
10639         | CallOptString (Some s) -> sprintf "\"%s\"" s
10640         | CallStringList xs ->
10641             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10642         | CallInt i -> string_of_int i
10643         | CallInt64 i -> Int64.to_string i
10644         | CallBool b -> if b then "1" else "0"
10645       ) args
10646     )
10647   in
10648
10649   generate_lang_bindtests (
10650     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10651   );
10652
10653   pr "print \"EOF\"\n"
10654
10655 and generate_ruby_bindtests () =
10656   generate_header HashStyle GPLv2plus;
10657
10658   pr "\
10659 require 'guestfs'
10660
10661 g = Guestfs::create()
10662 ";
10663
10664   let mkargs args =
10665     String.concat ", " (
10666       List.map (
10667         function
10668         | CallString s -> "\"" ^ s ^ "\""
10669         | CallOptString None -> "nil"
10670         | CallOptString (Some s) -> sprintf "\"%s\"" s
10671         | CallStringList xs ->
10672             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10673         | CallInt i -> string_of_int i
10674         | CallInt64 i -> Int64.to_string i
10675         | CallBool b -> string_of_bool b
10676       ) args
10677     )
10678   in
10679
10680   generate_lang_bindtests (
10681     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10682   );
10683
10684   pr "print \"EOF\\n\"\n"
10685
10686 and generate_java_bindtests () =
10687   generate_header CStyle GPLv2plus;
10688
10689   pr "\
10690 import com.redhat.et.libguestfs.*;
10691
10692 public class Bindtests {
10693     public static void main (String[] argv)
10694     {
10695         try {
10696             GuestFS g = new GuestFS ();
10697 ";
10698
10699   let mkargs args =
10700     String.concat ", " (
10701       List.map (
10702         function
10703         | CallString s -> "\"" ^ s ^ "\""
10704         | CallOptString None -> "null"
10705         | CallOptString (Some s) -> sprintf "\"%s\"" s
10706         | CallStringList xs ->
10707             "new String[]{" ^
10708               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
10709         | CallInt i -> string_of_int i
10710         | CallInt64 i -> Int64.to_string i
10711         | CallBool b -> string_of_bool b
10712       ) args
10713     )
10714   in
10715
10716   generate_lang_bindtests (
10717     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
10718   );
10719
10720   pr "
10721             System.out.println (\"EOF\");
10722         }
10723         catch (Exception exn) {
10724             System.err.println (exn);
10725             System.exit (1);
10726         }
10727     }
10728 }
10729 "
10730
10731 and generate_haskell_bindtests () =
10732   generate_header HaskellStyle GPLv2plus;
10733
10734   pr "\
10735 module Bindtests where
10736 import qualified Guestfs
10737
10738 main = do
10739   g <- Guestfs.create
10740 ";
10741
10742   let mkargs args =
10743     String.concat " " (
10744       List.map (
10745         function
10746         | CallString s -> "\"" ^ s ^ "\""
10747         | CallOptString None -> "Nothing"
10748         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
10749         | CallStringList xs ->
10750             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10751         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
10752         | CallInt i -> string_of_int i
10753         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
10754         | CallInt64 i -> Int64.to_string i
10755         | CallBool true -> "True"
10756         | CallBool false -> "False"
10757       ) args
10758     )
10759   in
10760
10761   generate_lang_bindtests (
10762     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
10763   );
10764
10765   pr "  putStrLn \"EOF\"\n"
10766
10767 (* Language-independent bindings tests - we do it this way to
10768  * ensure there is parity in testing bindings across all languages.
10769  *)
10770 and generate_lang_bindtests call =
10771   call "test0" [CallString "abc"; CallOptString (Some "def");
10772                 CallStringList []; CallBool false;
10773                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10774   call "test0" [CallString "abc"; CallOptString None;
10775                 CallStringList []; CallBool false;
10776                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10777   call "test0" [CallString ""; CallOptString (Some "def");
10778                 CallStringList []; CallBool false;
10779                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10780   call "test0" [CallString ""; CallOptString (Some "");
10781                 CallStringList []; CallBool false;
10782                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10783   call "test0" [CallString "abc"; CallOptString (Some "def");
10784                 CallStringList ["1"]; CallBool false;
10785                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10786   call "test0" [CallString "abc"; CallOptString (Some "def");
10787                 CallStringList ["1"; "2"]; CallBool false;
10788                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10789   call "test0" [CallString "abc"; CallOptString (Some "def");
10790                 CallStringList ["1"]; CallBool true;
10791                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
10792   call "test0" [CallString "abc"; CallOptString (Some "def");
10793                 CallStringList ["1"]; CallBool false;
10794                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
10795   call "test0" [CallString "abc"; CallOptString (Some "def");
10796                 CallStringList ["1"]; CallBool false;
10797                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
10798   call "test0" [CallString "abc"; CallOptString (Some "def");
10799                 CallStringList ["1"]; CallBool false;
10800                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
10801   call "test0" [CallString "abc"; CallOptString (Some "def");
10802                 CallStringList ["1"]; CallBool false;
10803                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
10804   call "test0" [CallString "abc"; CallOptString (Some "def");
10805                 CallStringList ["1"]; CallBool false;
10806                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
10807   call "test0" [CallString "abc"; CallOptString (Some "def");
10808                 CallStringList ["1"]; CallBool false;
10809                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
10810
10811 (* XXX Add here tests of the return and error functions. *)
10812
10813 (* Code to generator bindings for virt-inspector.  Currently only
10814  * implemented for OCaml code (for virt-p2v 2.0).
10815  *)
10816 let rng_input = "inspector/virt-inspector.rng"
10817
10818 (* Read the input file and parse it into internal structures.  This is
10819  * by no means a complete RELAX NG parser, but is just enough to be
10820  * able to parse the specific input file.
10821  *)
10822 type rng =
10823   | Element of string * rng list        (* <element name=name/> *)
10824   | Attribute of string * rng list        (* <attribute name=name/> *)
10825   | Interleave of rng list                (* <interleave/> *)
10826   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
10827   | OneOrMore of rng                        (* <oneOrMore/> *)
10828   | Optional of rng                        (* <optional/> *)
10829   | Choice of string list                (* <choice><value/>*</choice> *)
10830   | Value of string                        (* <value>str</value> *)
10831   | Text                                (* <text/> *)
10832
10833 let rec string_of_rng = function
10834   | Element (name, xs) ->
10835       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10836   | Attribute (name, xs) ->
10837       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
10838   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
10839   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
10840   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
10841   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
10842   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
10843   | Value value -> "Value \"" ^ value ^ "\""
10844   | Text -> "Text"
10845
10846 and string_of_rng_list xs =
10847   String.concat ", " (List.map string_of_rng xs)
10848
10849 let rec parse_rng ?defines context = function
10850   | [] -> []
10851   | Xml.Element ("element", ["name", name], children) :: rest ->
10852       Element (name, parse_rng ?defines context children)
10853       :: parse_rng ?defines context rest
10854   | Xml.Element ("attribute", ["name", name], children) :: rest ->
10855       Attribute (name, parse_rng ?defines context children)
10856       :: parse_rng ?defines context rest
10857   | Xml.Element ("interleave", [], children) :: rest ->
10858       Interleave (parse_rng ?defines context children)
10859       :: parse_rng ?defines context rest
10860   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
10861       let rng = parse_rng ?defines context [child] in
10862       (match rng with
10863        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
10864        | _ ->
10865            failwithf "%s: <zeroOrMore> contains more than one child element"
10866              context
10867       )
10868   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
10869       let rng = parse_rng ?defines context [child] in
10870       (match rng with
10871        | [child] -> OneOrMore child :: parse_rng ?defines context rest
10872        | _ ->
10873            failwithf "%s: <oneOrMore> contains more than one child element"
10874              context
10875       )
10876   | Xml.Element ("optional", [], [child]) :: rest ->
10877       let rng = parse_rng ?defines context [child] in
10878       (match rng with
10879        | [child] -> Optional child :: parse_rng ?defines context rest
10880        | _ ->
10881            failwithf "%s: <optional> contains more than one child element"
10882              context
10883       )
10884   | Xml.Element ("choice", [], children) :: rest ->
10885       let values = List.map (
10886         function Xml.Element ("value", [], [Xml.PCData value]) -> value
10887         | _ ->
10888             failwithf "%s: can't handle anything except <value> in <choice>"
10889               context
10890       ) children in
10891       Choice values
10892       :: parse_rng ?defines context rest
10893   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
10894       Value value :: parse_rng ?defines context rest
10895   | Xml.Element ("text", [], []) :: rest ->
10896       Text :: parse_rng ?defines context rest
10897   | Xml.Element ("ref", ["name", name], []) :: rest ->
10898       (* Look up the reference.  Because of limitations in this parser,
10899        * we can't handle arbitrarily nested <ref> yet.  You can only
10900        * use <ref> from inside <start>.
10901        *)
10902       (match defines with
10903        | None ->
10904            failwithf "%s: contains <ref>, but no refs are defined yet" context
10905        | Some map ->
10906            let rng = StringMap.find name map in
10907            rng @ parse_rng ?defines context rest
10908       )
10909   | x :: _ ->
10910       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
10911
10912 let grammar =
10913   let xml = Xml.parse_file rng_input in
10914   match xml with
10915   | Xml.Element ("grammar", _,
10916                  Xml.Element ("start", _, gram) :: defines) ->
10917       (* The <define/> elements are referenced in the <start> section,
10918        * so build a map of those first.
10919        *)
10920       let defines = List.fold_left (
10921         fun map ->
10922           function Xml.Element ("define", ["name", name], defn) ->
10923             StringMap.add name defn map
10924           | _ ->
10925               failwithf "%s: expected <define name=name/>" rng_input
10926       ) StringMap.empty defines in
10927       let defines = StringMap.mapi parse_rng defines in
10928
10929       (* Parse the <start> clause, passing the defines. *)
10930       parse_rng ~defines "<start>" gram
10931   | _ ->
10932       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
10933         rng_input
10934
10935 let name_of_field = function
10936   | Element (name, _) | Attribute (name, _)
10937   | ZeroOrMore (Element (name, _))
10938   | OneOrMore (Element (name, _))
10939   | Optional (Element (name, _)) -> name
10940   | Optional (Attribute (name, _)) -> name
10941   | Text -> (* an unnamed field in an element *)
10942       "data"
10943   | rng ->
10944       failwithf "name_of_field failed at: %s" (string_of_rng rng)
10945
10946 (* At the moment this function only generates OCaml types.  However we
10947  * should parameterize it later so it can generate types/structs in a
10948  * variety of languages.
10949  *)
10950 let generate_types xs =
10951   (* A simple type is one that can be printed out directly, eg.
10952    * "string option".  A complex type is one which has a name and has
10953    * to be defined via another toplevel definition, eg. a struct.
10954    *
10955    * generate_type generates code for either simple or complex types.
10956    * In the simple case, it returns the string ("string option").  In
10957    * the complex case, it returns the name ("mountpoint").  In the
10958    * complex case it has to print out the definition before returning,
10959    * so it should only be called when we are at the beginning of a
10960    * new line (BOL context).
10961    *)
10962   let rec generate_type = function
10963     | Text ->                                (* string *)
10964         "string", true
10965     | Choice values ->                        (* [`val1|`val2|...] *)
10966         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
10967     | ZeroOrMore rng ->                        (* <rng> list *)
10968         let t, is_simple = generate_type rng in
10969         t ^ " list (* 0 or more *)", is_simple
10970     | OneOrMore rng ->                        (* <rng> list *)
10971         let t, is_simple = generate_type rng in
10972         t ^ " list (* 1 or more *)", is_simple
10973                                         (* virt-inspector hack: bool *)
10974     | Optional (Attribute (name, [Value "1"])) ->
10975         "bool", true
10976     | Optional rng ->                        (* <rng> list *)
10977         let t, is_simple = generate_type rng in
10978         t ^ " option", is_simple
10979                                         (* type name = { fields ... } *)
10980     | Element (name, fields) when is_attrs_interleave fields ->
10981         generate_type_struct name (get_attrs_interleave fields)
10982     | Element (name, [field])                (* type name = field *)
10983     | Attribute (name, [field]) ->
10984         let t, is_simple = generate_type field in
10985         if is_simple then (t, true)
10986         else (
10987           pr "type %s = %s\n" name t;
10988           name, false
10989         )
10990     | Element (name, fields) ->              (* type name = { fields ... } *)
10991         generate_type_struct name fields
10992     | rng ->
10993         failwithf "generate_type failed at: %s" (string_of_rng rng)
10994
10995   and is_attrs_interleave = function
10996     | [Interleave _] -> true
10997     | Attribute _ :: fields -> is_attrs_interleave fields
10998     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
10999     | _ -> false
11000
11001   and get_attrs_interleave = function
11002     | [Interleave fields] -> fields
11003     | ((Attribute _) as field) :: fields
11004     | ((Optional (Attribute _)) as field) :: fields ->
11005         field :: get_attrs_interleave fields
11006     | _ -> assert false
11007
11008   and generate_types xs =
11009     List.iter (fun x -> ignore (generate_type x)) xs
11010
11011   and generate_type_struct name fields =
11012     (* Calculate the types of the fields first.  We have to do this
11013      * before printing anything so we are still in BOL context.
11014      *)
11015     let types = List.map fst (List.map generate_type fields) in
11016
11017     (* Special case of a struct containing just a string and another
11018      * field.  Turn it into an assoc list.
11019      *)
11020     match types with
11021     | ["string"; other] ->
11022         let fname1, fname2 =
11023           match fields with
11024           | [f1; f2] -> name_of_field f1, name_of_field f2
11025           | _ -> assert false in
11026         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
11027         name, false
11028
11029     | types ->
11030         pr "type %s = {\n" name;
11031         List.iter (
11032           fun (field, ftype) ->
11033             let fname = name_of_field field in
11034             pr "  %s_%s : %s;\n" name fname ftype
11035         ) (List.combine fields types);
11036         pr "}\n";
11037         (* Return the name of this type, and
11038          * false because it's not a simple type.
11039          *)
11040         name, false
11041   in
11042
11043   generate_types xs
11044
11045 let generate_parsers xs =
11046   (* As for generate_type above, generate_parser makes a parser for
11047    * some type, and returns the name of the parser it has generated.
11048    * Because it (may) need to print something, it should always be
11049    * called in BOL context.
11050    *)
11051   let rec generate_parser = function
11052     | Text ->                                (* string *)
11053         "string_child_or_empty"
11054     | Choice values ->                        (* [`val1|`val2|...] *)
11055         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
11056           (String.concat "|"
11057              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
11058     | ZeroOrMore rng ->                        (* <rng> list *)
11059         let pa = generate_parser rng in
11060         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11061     | OneOrMore rng ->                        (* <rng> list *)
11062         let pa = generate_parser rng in
11063         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11064                                         (* virt-inspector hack: bool *)
11065     | Optional (Attribute (name, [Value "1"])) ->
11066         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
11067     | Optional rng ->                        (* <rng> list *)
11068         let pa = generate_parser rng in
11069         sprintf "(function None -> None | Some x -> Some (%s x))" pa
11070                                         (* type name = { fields ... } *)
11071     | Element (name, fields) when is_attrs_interleave fields ->
11072         generate_parser_struct name (get_attrs_interleave fields)
11073     | Element (name, [field]) ->        (* type name = field *)
11074         let pa = generate_parser field in
11075         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11076         pr "let %s =\n" parser_name;
11077         pr "  %s\n" pa;
11078         pr "let parse_%s = %s\n" name parser_name;
11079         parser_name
11080     | Attribute (name, [field]) ->
11081         let pa = generate_parser field in
11082         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11083         pr "let %s =\n" parser_name;
11084         pr "  %s\n" pa;
11085         pr "let parse_%s = %s\n" name parser_name;
11086         parser_name
11087     | Element (name, fields) ->              (* type name = { fields ... } *)
11088         generate_parser_struct name ([], fields)
11089     | rng ->
11090         failwithf "generate_parser failed at: %s" (string_of_rng rng)
11091
11092   and is_attrs_interleave = function
11093     | [Interleave _] -> true
11094     | Attribute _ :: fields -> is_attrs_interleave fields
11095     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11096     | _ -> false
11097
11098   and get_attrs_interleave = function
11099     | [Interleave fields] -> [], fields
11100     | ((Attribute _) as field) :: fields
11101     | ((Optional (Attribute _)) as field) :: fields ->
11102         let attrs, interleaves = get_attrs_interleave fields in
11103         (field :: attrs), interleaves
11104     | _ -> assert false
11105
11106   and generate_parsers xs =
11107     List.iter (fun x -> ignore (generate_parser x)) xs
11108
11109   and generate_parser_struct name (attrs, interleaves) =
11110     (* Generate parsers for the fields first.  We have to do this
11111      * before printing anything so we are still in BOL context.
11112      *)
11113     let fields = attrs @ interleaves in
11114     let pas = List.map generate_parser fields in
11115
11116     (* Generate an intermediate tuple from all the fields first.
11117      * If the type is just a string + another field, then we will
11118      * return this directly, otherwise it is turned into a record.
11119      *
11120      * RELAX NG note: This code treats <interleave> and plain lists of
11121      * fields the same.  In other words, it doesn't bother enforcing
11122      * any ordering of fields in the XML.
11123      *)
11124     pr "let parse_%s x =\n" name;
11125     pr "  let t = (\n    ";
11126     let comma = ref false in
11127     List.iter (
11128       fun x ->
11129         if !comma then pr ",\n    ";
11130         comma := true;
11131         match x with
11132         | Optional (Attribute (fname, [field])), pa ->
11133             pr "%s x" pa
11134         | Optional (Element (fname, [field])), pa ->
11135             pr "%s (optional_child %S x)" pa fname
11136         | Attribute (fname, [Text]), _ ->
11137             pr "attribute %S x" fname
11138         | (ZeroOrMore _ | OneOrMore _), pa ->
11139             pr "%s x" pa
11140         | Text, pa ->
11141             pr "%s x" pa
11142         | (field, pa) ->
11143             let fname = name_of_field field in
11144             pr "%s (child %S x)" pa fname
11145     ) (List.combine fields pas);
11146     pr "\n  ) in\n";
11147
11148     (match fields with
11149      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11150          pr "  t\n"
11151
11152      | _ ->
11153          pr "  (Obj.magic t : %s)\n" name
11154 (*
11155          List.iter (
11156            function
11157            | (Optional (Attribute (fname, [field])), pa) ->
11158                pr "  %s_%s =\n" name fname;
11159                pr "    %s x;\n" pa
11160            | (Optional (Element (fname, [field])), pa) ->
11161                pr "  %s_%s =\n" name fname;
11162                pr "    (let x = optional_child %S x in\n" fname;
11163                pr "     %s x);\n" pa
11164            | (field, pa) ->
11165                let fname = name_of_field field in
11166                pr "  %s_%s =\n" name fname;
11167                pr "    (let x = child %S x in\n" fname;
11168                pr "     %s x);\n" pa
11169          ) (List.combine fields pas);
11170          pr "}\n"
11171 *)
11172     );
11173     sprintf "parse_%s" name
11174   in
11175
11176   generate_parsers xs
11177
11178 (* Generate ocaml/guestfs_inspector.mli. *)
11179 let generate_ocaml_inspector_mli () =
11180   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11181
11182   pr "\
11183 (** This is an OCaml language binding to the external [virt-inspector]
11184     program.
11185
11186     For more information, please read the man page [virt-inspector(1)].
11187 *)
11188
11189 ";
11190
11191   generate_types grammar;
11192   pr "(** The nested information returned from the {!inspect} function. *)\n";
11193   pr "\n";
11194
11195   pr "\
11196 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11197 (** To inspect a libvirt domain called [name], pass a singleton
11198     list: [inspect [name]].  When using libvirt only, you may
11199     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11200
11201     To inspect a disk image or images, pass a list of the filenames
11202     of the disk images: [inspect filenames]
11203
11204     This function inspects the given guest or disk images and
11205     returns a list of operating system(s) found and a large amount
11206     of information about them.  In the vast majority of cases,
11207     a virtual machine only contains a single operating system.
11208
11209     If the optional [~xml] parameter is given, then this function
11210     skips running the external virt-inspector program and just
11211     parses the given XML directly (which is expected to be XML
11212     produced from a previous run of virt-inspector).  The list of
11213     names and connect URI are ignored in this case.
11214
11215     This function can throw a wide variety of exceptions, for example
11216     if the external virt-inspector program cannot be found, or if
11217     it doesn't generate valid XML.
11218 *)
11219 "
11220
11221 (* Generate ocaml/guestfs_inspector.ml. *)
11222 let generate_ocaml_inspector_ml () =
11223   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11224
11225   pr "open Unix\n";
11226   pr "\n";
11227
11228   generate_types grammar;
11229   pr "\n";
11230
11231   pr "\
11232 (* Misc functions which are used by the parser code below. *)
11233 let first_child = function
11234   | Xml.Element (_, _, c::_) -> c
11235   | Xml.Element (name, _, []) ->
11236       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11237   | Xml.PCData str ->
11238       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11239
11240 let string_child_or_empty = function
11241   | Xml.Element (_, _, [Xml.PCData s]) -> s
11242   | Xml.Element (_, _, []) -> \"\"
11243   | Xml.Element (x, _, _) ->
11244       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11245                 x ^ \" instead\")
11246   | Xml.PCData str ->
11247       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11248
11249 let optional_child name xml =
11250   let children = Xml.children xml in
11251   try
11252     Some (List.find (function
11253                      | Xml.Element (n, _, _) when n = name -> true
11254                      | _ -> false) children)
11255   with
11256     Not_found -> None
11257
11258 let child name xml =
11259   match optional_child name xml with
11260   | Some c -> c
11261   | None ->
11262       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11263
11264 let attribute name xml =
11265   try Xml.attrib xml name
11266   with Xml.No_attribute _ ->
11267     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11268
11269 ";
11270
11271   generate_parsers grammar;
11272   pr "\n";
11273
11274   pr "\
11275 (* Run external virt-inspector, then use parser to parse the XML. *)
11276 let inspect ?connect ?xml names =
11277   let xml =
11278     match xml with
11279     | None ->
11280         if names = [] then invalid_arg \"inspect: no names given\";
11281         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11282           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11283           names in
11284         let cmd = List.map Filename.quote cmd in
11285         let cmd = String.concat \" \" cmd in
11286         let chan = open_process_in cmd in
11287         let xml = Xml.parse_in chan in
11288         (match close_process_in chan with
11289          | WEXITED 0 -> ()
11290          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11291          | WSIGNALED i | WSTOPPED i ->
11292              failwith (\"external virt-inspector command died or stopped on sig \" ^
11293                        string_of_int i)
11294         );
11295         xml
11296     | Some doc ->
11297         Xml.parse_string doc in
11298   parse_operatingsystems xml
11299 "
11300
11301 (* This is used to generate the src/MAX_PROC_NR file which
11302  * contains the maximum procedure number, a surrogate for the
11303  * ABI version number.  See src/Makefile.am for the details.
11304  *)
11305 and generate_max_proc_nr () =
11306   let proc_nrs = List.map (
11307     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11308   ) daemon_functions in
11309
11310   let max_proc_nr = List.fold_left max 0 proc_nrs in
11311
11312   pr "%d\n" max_proc_nr
11313
11314 let output_to filename k =
11315   let filename_new = filename ^ ".new" in
11316   chan := open_out filename_new;
11317   k ();
11318   close_out !chan;
11319   chan := Pervasives.stdout;
11320
11321   (* Is the new file different from the current file? *)
11322   if Sys.file_exists filename && files_equal filename filename_new then
11323     unlink filename_new                 (* same, so skip it *)
11324   else (
11325     (* different, overwrite old one *)
11326     (try chmod filename 0o644 with Unix_error _ -> ());
11327     rename filename_new filename;
11328     chmod filename 0o444;
11329     printf "written %s\n%!" filename;
11330   )
11331
11332 let perror msg = function
11333   | Unix_error (err, _, _) ->
11334       eprintf "%s: %s\n" msg (error_message err)
11335   | exn ->
11336       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11337
11338 (* Main program. *)
11339 let () =
11340   let lock_fd =
11341     try openfile "HACKING" [O_RDWR] 0
11342     with
11343     | Unix_error (ENOENT, _, _) ->
11344         eprintf "\
11345 You are probably running this from the wrong directory.
11346 Run it from the top source directory using the command
11347   src/generator.ml
11348 ";
11349         exit 1
11350     | exn ->
11351         perror "open: HACKING" exn;
11352         exit 1 in
11353
11354   (* Acquire a lock so parallel builds won't try to run the generator
11355    * twice at the same time.  Subsequent builds will wait for the first
11356    * one to finish.  Note the lock is released implicitly when the
11357    * program exits.
11358    *)
11359   (try lockf lock_fd F_LOCK 1
11360    with exn ->
11361      perror "lock: HACKING" exn;
11362      exit 1);
11363
11364   check_functions ();
11365
11366   output_to "src/guestfs_protocol.x" generate_xdr;
11367   output_to "src/guestfs-structs.h" generate_structs_h;
11368   output_to "src/guestfs-actions.h" generate_actions_h;
11369   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11370   output_to "src/guestfs-actions.c" generate_client_actions;
11371   output_to "src/guestfs-bindtests.c" generate_bindtests;
11372   output_to "src/guestfs-structs.pod" generate_structs_pod;
11373   output_to "src/guestfs-actions.pod" generate_actions_pod;
11374   output_to "src/guestfs-availability.pod" generate_availability_pod;
11375   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11376   output_to "src/libguestfs.syms" generate_linker_script;
11377   output_to "daemon/actions.h" generate_daemon_actions_h;
11378   output_to "daemon/stubs.c" generate_daemon_actions;
11379   output_to "daemon/names.c" generate_daemon_names;
11380   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11381   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11382   output_to "capitests/tests.c" generate_tests;
11383   output_to "fish/cmds.c" generate_fish_cmds;
11384   output_to "fish/completion.c" generate_fish_completion;
11385   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11386   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11387   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11388   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11389   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11390   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11391   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11392   output_to "perl/Guestfs.xs" generate_perl_xs;
11393   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11394   output_to "perl/bindtests.pl" generate_perl_bindtests;
11395   output_to "python/guestfs-py.c" generate_python_c;
11396   output_to "python/guestfs.py" generate_python_py;
11397   output_to "python/bindtests.py" generate_python_bindtests;
11398   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11399   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11400   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11401
11402   List.iter (
11403     fun (typ, jtyp) ->
11404       let cols = cols_of_struct typ in
11405       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11406       output_to filename (generate_java_struct jtyp cols);
11407   ) java_structs;
11408
11409   output_to "java/Makefile.inc" generate_java_makefile_inc;
11410   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11411   output_to "java/Bindtests.java" generate_java_bindtests;
11412   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11413   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11414   output_to "csharp/Libguestfs.cs" generate_csharp;
11415
11416   (* Always generate this file last, and unconditionally.  It's used
11417    * by the Makefile to know when we must re-run the generator.
11418    *)
11419   let chan = open_out "src/stamp-generator" in
11420   fprintf chan "1\n";
11421   close_out chan;
11422
11423   printf "generated %d lines of code\n" !lines