New APIs: base64-in and base64-out for uploading/downloading base64 content.
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009-2010 Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *)
19
20 (* This script generates a large amount of code and documentation for
21  * all the daemon actions.
22  *
23  * To add a new action there are only two files you need to change,
24  * this one to describe the interface (see the big table of
25  * 'daemon_functions' below), and daemon/<somefile>.c to write the
26  * implementation.
27  *
28  * After editing this file, run it (./src/generator.ml) to regenerate
29  * all the output files.  'make' will rerun this automatically when
30  * necessary.  Note that if you are using a separate build directory
31  * you must run generator.ml from the _source_ directory.
32  *
33  * IMPORTANT: This script should NOT print any warnings.  If it prints
34  * warnings, you should treat them as errors.
35  *
36  * OCaml tips:
37  * (1) In emacs, install tuareg-mode to display and format OCaml code
38  * correctly.  'vim' comes with a good OCaml editing mode by default.
39  * (2) Read the resources at http://ocaml-tutorial.org/
40  *)
41
42 #load "unix.cma";;
43 #load "str.cma";;
44 #directory "+xml-light";;
45 #directory "+../pkg-lib/xml-light";; (* for GODI users *)
46 #load "xml-light.cma";;
47
48 open Unix
49 open Printf
50
51 type style = ret * args
52 and ret =
53     (* "RErr" as a return value means an int used as a simple error
54      * indication, ie. 0 or -1.
55      *)
56   | RErr
57
58     (* "RInt" as a return value means an int which is -1 for error
59      * or any value >= 0 on success.  Only use this for smallish
60      * positive ints (0 <= i < 2^30).
61      *)
62   | RInt of string
63
64     (* "RInt64" is the same as RInt, but is guaranteed to be able
65      * to return a full 64 bit value, _except_ that -1 means error
66      * (so -1 cannot be a valid, non-error return value).
67      *)
68   | RInt64 of string
69
70     (* "RBool" is a bool return value which can be true/false or
71      * -1 for error.
72      *)
73   | RBool of string
74
75     (* "RConstString" is a string that refers to a constant value.
76      * The return value must NOT be NULL (since NULL indicates
77      * an error).
78      *
79      * Try to avoid using this.  In particular you cannot use this
80      * for values returned from the daemon, because there is no
81      * thread-safe way to return them in the C API.
82      *)
83   | RConstString of string
84
85     (* "RConstOptString" is an even more broken version of
86      * "RConstString".  The returned string may be NULL and there
87      * is no way to return an error indication.  Avoid using this!
88      *)
89   | RConstOptString of string
90
91     (* "RString" is a returned string.  It must NOT be NULL, since
92      * a NULL return indicates an error.  The caller frees this.
93      *)
94   | RString of string
95
96     (* "RStringList" is a list of strings.  No string in the list
97      * can be NULL.  The caller frees the strings and the array.
98      *)
99   | RStringList of string
100
101     (* "RStruct" is a function which returns a single named structure
102      * or an error indication (in C, a struct, and in other languages
103      * with varying representations, but usually very efficient).  See
104      * after the function list below for the structures.
105      *)
106   | RStruct of string * string          (* name of retval, name of struct *)
107
108     (* "RStructList" is a function which returns either a list/array
109      * of structures (could be zero-length), or an error indication.
110      *)
111   | RStructList of string * string      (* name of retval, name of struct *)
112
113     (* Key-value pairs of untyped strings.  Turns into a hashtable or
114      * dictionary in languages which support it.  DON'T use this as a
115      * general "bucket" for results.  Prefer a stronger typed return
116      * value if one is available, or write a custom struct.  Don't use
117      * this if the list could potentially be very long, since it is
118      * inefficient.  Keys should be unique.  NULLs are not permitted.
119      *)
120   | RHashtable of string
121
122     (* "RBufferOut" is handled almost exactly like RString, but
123      * it allows the string to contain arbitrary 8 bit data including
124      * ASCII NUL.  In the C API this causes an implicit extra parameter
125      * to be added of type <size_t *size_r>.  The extra parameter
126      * returns the actual size of the return buffer in bytes.
127      *
128      * Other programming languages support strings with arbitrary 8 bit
129      * data.
130      *
131      * At the RPC layer we have to use the opaque<> type instead of
132      * string<>.  Returned data is still limited to the max message
133      * size (ie. ~ 2 MB).
134      *)
135   | RBufferOut of string
136
137 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
138
139     (* Note in future we should allow a "variable args" parameter as
140      * the final parameter, to allow commands like
141      *   chmod mode file [file(s)...]
142      * This is not implemented yet, but many commands (such as chmod)
143      * are currently defined with the argument order keeping this future
144      * possibility in mind.
145      *)
146 and argt =
147   | String of string    (* const char *name, cannot be NULL *)
148   | Device of string    (* /dev device name, cannot be NULL *)
149   | Pathname of string  (* file name, cannot be NULL *)
150   | Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
151   | OptString of string (* const char *name, may be NULL *)
152   | StringList of string(* list of strings (each string cannot be NULL) *)
153   | DeviceList of string(* list of Device names (each cannot be NULL) *)
154   | Bool of string      (* boolean *)
155   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
156   | Int64 of string     (* any 64 bit int *)
157     (* These are treated as filenames (simple string parameters) in
158      * the C API and bindings.  But in the RPC protocol, we transfer
159      * the actual file content up to or down from the daemon.
160      * FileIn: local machine -> daemon (in request)
161      * FileOut: daemon -> local machine (in reply)
162      * In guestfish (only), the special name "-" means read from
163      * stdin or write to stdout.
164      *)
165   | FileIn of string
166   | FileOut of string
167 (* Not implemented:
168     (* Opaque buffer which can contain arbitrary 8 bit data.
169      * In the C API, this is expressed as <char *, int> pair.
170      * Most other languages have a string type which can contain
171      * ASCII NUL.  We use whatever type is appropriate for each
172      * language.
173      * Buffers are limited by the total message size.  To transfer
174      * large blocks of data, use FileIn/FileOut parameters instead.
175      * To return an arbitrary buffer, use RBufferOut.
176      *)
177   | BufferIn of string
178 *)
179
180 type flags =
181   | ProtocolLimitWarning  (* display warning about protocol size limits *)
182   | DangerWillRobinson    (* flags particularly dangerous commands *)
183   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
184   | FishAction of string  (* call this function in guestfish *)
185   | FishOutput of fish_output_t (* how to display output in guestfish *)
186   | NotInFish             (* do not export via guestfish *)
187   | NotInDocs             (* do not add this function to documentation *)
188   | DeprecatedBy of string (* function is deprecated, use .. instead *)
189   | Optional of string    (* function is part of an optional group *)
190
191 and fish_output_t =
192   | FishOutputOctal       (* for int return, print in octal *)
193   | FishOutputHexadecimal (* for int return, print in hex *)
194
195 (* You can supply zero or as many tests as you want per API call.
196  *
197  * Note that the test environment has 3 block devices, of size 500MB,
198  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
199  * a fourth ISO block device with some known files on it (/dev/sdd).
200  *
201  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
202  * Number of cylinders was 63 for IDE emulated disks with precisely
203  * the same size.  How exactly this is calculated is a mystery.
204  *
205  * The ISO block device (/dev/sdd) comes from images/test.iso.
206  *
207  * To be able to run the tests in a reasonable amount of time,
208  * the virtual machine and block devices are reused between tests.
209  * So don't try testing kill_subprocess :-x
210  *
211  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
212  *
213  * Don't assume anything about the previous contents of the block
214  * devices.  Use 'Init*' to create some initial scenarios.
215  *
216  * You can add a prerequisite clause to any individual test.  This
217  * is a run-time check, which, if it fails, causes the test to be
218  * skipped.  Useful if testing a command which might not work on
219  * all variations of libguestfs builds.  A test that has prerequisite
220  * of 'Always' is run unconditionally.
221  *
222  * In addition, packagers can skip individual tests by setting the
223  * environment variables:     eg:
224  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
225  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
226  *)
227 type tests = (test_init * test_prereq * test) list
228 and test =
229     (* Run the command sequence and just expect nothing to fail. *)
230   | TestRun of seq
231
232     (* Run the command sequence and expect the output of the final
233      * command to be the string.
234      *)
235   | TestOutput of seq * string
236
237     (* Run the command sequence and expect the output of the final
238      * command to be the list of strings.
239      *)
240   | TestOutputList of seq * string list
241
242     (* Run the command sequence and expect the output of the final
243      * command to be the list of block devices (could be either
244      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
245      * character of each string).
246      *)
247   | TestOutputListOfDevices of seq * string list
248
249     (* Run the command sequence and expect the output of the final
250      * command to be the integer.
251      *)
252   | TestOutputInt of seq * int
253
254     (* Run the command sequence and expect the output of the final
255      * command to be <op> <int>, eg. ">=", "1".
256      *)
257   | TestOutputIntOp of seq * string * int
258
259     (* Run the command sequence and expect the output of the final
260      * command to be a true value (!= 0 or != NULL).
261      *)
262   | TestOutputTrue of seq
263
264     (* Run the command sequence and expect the output of the final
265      * command to be a false value (== 0 or == NULL, but not an error).
266      *)
267   | TestOutputFalse of seq
268
269     (* Run the command sequence and expect the output of the final
270      * command to be a list of the given length (but don't care about
271      * content).
272      *)
273   | TestOutputLength of seq * int
274
275     (* Run the command sequence and expect the output of the final
276      * command to be a buffer (RBufferOut), ie. string + size.
277      *)
278   | TestOutputBuffer of seq * string
279
280     (* Run the command sequence and expect the output of the final
281      * command to be a structure.
282      *)
283   | TestOutputStruct of seq * test_field_compare list
284
285     (* Run the command sequence and expect the final command (only)
286      * to fail.
287      *)
288   | TestLastFail of seq
289
290 and test_field_compare =
291   | CompareWithInt of string * int
292   | CompareWithIntOp of string * string * int
293   | CompareWithString of string * string
294   | CompareFieldsIntEq of string * string
295   | CompareFieldsStrEq of string * string
296
297 (* Test prerequisites. *)
298 and test_prereq =
299     (* Test always runs. *)
300   | Always
301
302     (* Test is currently disabled - eg. it fails, or it tests some
303      * unimplemented feature.
304      *)
305   | Disabled
306
307     (* 'string' is some C code (a function body) that should return
308      * true or false.  The test will run if the code returns true.
309      *)
310   | If of string
311
312     (* As for 'If' but the test runs _unless_ the code returns true. *)
313   | Unless of string
314
315 (* Some initial scenarios for testing. *)
316 and test_init =
317     (* Do nothing, block devices could contain random stuff including
318      * LVM PVs, and some filesystems might be mounted.  This is usually
319      * a bad idea.
320      *)
321   | InitNone
322
323     (* Block devices are empty and no filesystems are mounted. *)
324   | InitEmpty
325
326     (* /dev/sda contains a single partition /dev/sda1, with random
327      * content.  /dev/sdb and /dev/sdc may have random content.
328      * No LVM.
329      *)
330   | InitPartition
331
332     (* /dev/sda contains a single partition /dev/sda1, which is formatted
333      * as ext2, empty [except for lost+found] and mounted on /.
334      * /dev/sdb and /dev/sdc may have random content.
335      * No LVM.
336      *)
337   | InitBasicFS
338
339     (* /dev/sda:
340      *   /dev/sda1 (is a PV):
341      *     /dev/VG/LV (size 8MB):
342      *       formatted as ext2, empty [except for lost+found], mounted on /
343      * /dev/sdb and /dev/sdc may have random content.
344      *)
345   | InitBasicFSonLVM
346
347     (* /dev/sdd (the ISO, see images/ directory in source)
348      * is mounted on /
349      *)
350   | InitISOFS
351
352 (* Sequence of commands for testing. *)
353 and seq = cmd list
354 and cmd = string list
355
356 (* Note about long descriptions: When referring to another
357  * action, use the format C<guestfs_other> (ie. the full name of
358  * the C function).  This will be replaced as appropriate in other
359  * language bindings.
360  *
361  * Apart from that, long descriptions are just perldoc paragraphs.
362  *)
363
364 (* Generate a random UUID (used in tests). *)
365 let uuidgen () =
366   let chan = open_process_in "uuidgen" in
367   let uuid = input_line chan in
368   (match close_process_in chan with
369    | WEXITED 0 -> ()
370    | WEXITED _ ->
371        failwith "uuidgen: process exited with non-zero status"
372    | WSIGNALED _ | WSTOPPED _ ->
373        failwith "uuidgen: process signalled or stopped by signal"
374   );
375   uuid
376
377 (* These test functions are used in the language binding tests. *)
378
379 let test_all_args = [
380   String "str";
381   OptString "optstr";
382   StringList "strlist";
383   Bool "b";
384   Int "integer";
385   Int64 "integer64";
386   FileIn "filein";
387   FileOut "fileout";
388 ]
389
390 let test_all_rets = [
391   (* except for RErr, which is tested thoroughly elsewhere *)
392   "test0rint",         RInt "valout";
393   "test0rint64",       RInt64 "valout";
394   "test0rbool",        RBool "valout";
395   "test0rconststring", RConstString "valout";
396   "test0rconstoptstring", RConstOptString "valout";
397   "test0rstring",      RString "valout";
398   "test0rstringlist",  RStringList "valout";
399   "test0rstruct",      RStruct ("valout", "lvm_pv");
400   "test0rstructlist",  RStructList ("valout", "lvm_pv");
401   "test0rhashtable",   RHashtable "valout";
402 ]
403
404 let test_functions = [
405   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
406    [],
407    "internal test function - do not use",
408    "\
409 This is an internal test function which is used to test whether
410 the automatically generated bindings can handle every possible
411 parameter type correctly.
412
413 It echos the contents of each parameter to stdout.
414
415 You probably don't want to call this function.");
416 ] @ List.flatten (
417   List.map (
418     fun (name, ret) ->
419       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
420         [],
421         "internal test function - do not use",
422         "\
423 This is an internal test function which is used to test whether
424 the automatically generated bindings can handle every possible
425 return type correctly.
426
427 It converts string C<val> to the return type.
428
429 You probably don't want to call this function.");
430        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
431         [],
432         "internal test function - do not use",
433         "\
434 This is an internal test function which is used to test whether
435 the automatically generated bindings can handle every possible
436 return type correctly.
437
438 This function always returns an error.
439
440 You probably don't want to call this function.")]
441   ) test_all_rets
442 )
443
444 (* non_daemon_functions are any functions which don't get processed
445  * in the daemon, eg. functions for setting and getting local
446  * configuration values.
447  *)
448
449 let non_daemon_functions = test_functions @ [
450   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
451    [],
452    "launch the qemu subprocess",
453    "\
454 Internally libguestfs is implemented by running a virtual machine
455 using L<qemu(1)>.
456
457 You should call this after configuring the handle
458 (eg. adding drives) but before performing any actions.");
459
460   ("wait_ready", (RErr, []), -1, [NotInFish],
461    [],
462    "wait until the qemu subprocess launches (no op)",
463    "\
464 This function is a no op.
465
466 In versions of the API E<lt> 1.0.71 you had to call this function
467 just after calling C<guestfs_launch> to wait for the launch
468 to complete.  However this is no longer necessary because
469 C<guestfs_launch> now does the waiting.
470
471 If you see any calls to this function in code then you can just
472 remove them, unless you want to retain compatibility with older
473 versions of the API.");
474
475   ("kill_subprocess", (RErr, []), -1, [],
476    [],
477    "kill the qemu subprocess",
478    "\
479 This kills the qemu subprocess.  You should never need to call this.");
480
481   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
482    [],
483    "add an image to examine or modify",
484    "\
485 This function adds a virtual machine disk image C<filename> to the
486 guest.  The first time you call this function, the disk appears as IDE
487 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
488 so on.
489
490 You don't necessarily need to be root when using libguestfs.  However
491 you obviously do need sufficient permissions to access the filename
492 for whatever operations you want to perform (ie. read access if you
493 just want to read the image or write access if you want to modify the
494 image).
495
496 This is equivalent to the qemu parameter
497 C<-drive file=filename,cache=off,if=...>.
498
499 C<cache=off> is omitted in cases where it is not supported by
500 the underlying filesystem.
501
502 C<if=...> is set at compile time by the configuration option
503 C<./configure --with-drive-if=...>.  In the rare case where you
504 might need to change this at run time, use C<guestfs_add_drive_with_if>
505 or C<guestfs_add_drive_ro_with_if>.
506
507 Note that this call checks for the existence of C<filename>.  This
508 stops you from specifying other types of drive which are supported
509 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
510 the general C<guestfs_config> call instead.");
511
512   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
513    [],
514    "add a CD-ROM disk image to examine",
515    "\
516 This function adds a virtual CD-ROM disk image to the guest.
517
518 This is equivalent to the qemu parameter C<-cdrom filename>.
519
520 Notes:
521
522 =over 4
523
524 =item *
525
526 This call checks for the existence of C<filename>.  This
527 stops you from specifying other types of drive which are supported
528 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
529 the general C<guestfs_config> call instead.
530
531 =item *
532
533 If you just want to add an ISO file (often you use this as an
534 efficient way to transfer large files into the guest), then you
535 should probably use C<guestfs_add_drive_ro> instead.
536
537 =back");
538
539   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
540    [],
541    "add a drive in snapshot mode (read-only)",
542    "\
543 This adds a drive in snapshot mode, making it effectively
544 read-only.
545
546 Note that writes to the device are allowed, and will be seen for
547 the duration of the guestfs handle, but they are written
548 to a temporary file which is discarded as soon as the guestfs
549 handle is closed.  We don't currently have any method to enable
550 changes to be committed, although qemu can support this.
551
552 This is equivalent to the qemu parameter
553 C<-drive file=filename,snapshot=on,readonly=on,if=...>.
554
555 C<if=...> is set at compile time by the configuration option
556 C<./configure --with-drive-if=...>.  In the rare case where you
557 might need to change this at run time, use C<guestfs_add_drive_with_if>
558 or C<guestfs_add_drive_ro_with_if>.
559
560 C<readonly=on> is only added where qemu supports this option.
561
562 Note that this call checks for the existence of C<filename>.  This
563 stops you from specifying other types of drive which are supported
564 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
565 the general C<guestfs_config> call instead.");
566
567   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
568    [],
569    "add qemu parameters",
570    "\
571 This can be used to add arbitrary qemu command line parameters
572 of the form C<-param value>.  Actually it's not quite arbitrary - we
573 prevent you from setting some parameters which would interfere with
574 parameters that we use.
575
576 The first character of C<param> string must be a C<-> (dash).
577
578 C<value> can be NULL.");
579
580   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
581    [],
582    "set the qemu binary",
583    "\
584 Set the qemu binary that we will use.
585
586 The default is chosen when the library was compiled by the
587 configure script.
588
589 You can also override this by setting the C<LIBGUESTFS_QEMU>
590 environment variable.
591
592 Setting C<qemu> to C<NULL> restores the default qemu binary.
593
594 Note that you should call this function as early as possible
595 after creating the handle.  This is because some pre-launch
596 operations depend on testing qemu features (by running C<qemu -help>).
597 If the qemu binary changes, we don't retest features, and
598 so you might see inconsistent results.  Using the environment
599 variable C<LIBGUESTFS_QEMU> is safest of all since that picks
600 the qemu binary at the same time as the handle is created.");
601
602   ("get_qemu", (RConstString "qemu", []), -1, [],
603    [InitNone, Always, TestRun (
604       [["get_qemu"]])],
605    "get the qemu binary",
606    "\
607 Return the current qemu binary.
608
609 This is always non-NULL.  If it wasn't set already, then this will
610 return the default qemu binary name.");
611
612   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
613    [],
614    "set the search path",
615    "\
616 Set the path that libguestfs searches for kernel and initrd.img.
617
618 The default is C<$libdir/guestfs> unless overridden by setting
619 C<LIBGUESTFS_PATH> environment variable.
620
621 Setting C<path> to C<NULL> restores the default path.");
622
623   ("get_path", (RConstString "path", []), -1, [],
624    [InitNone, Always, TestRun (
625       [["get_path"]])],
626    "get the search path",
627    "\
628 Return the current search path.
629
630 This is always non-NULL.  If it wasn't set already, then this will
631 return the default path.");
632
633   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
634    [],
635    "add options to kernel command line",
636    "\
637 This function is used to add additional options to the
638 guest kernel command line.
639
640 The default is C<NULL> unless overridden by setting
641 C<LIBGUESTFS_APPEND> environment variable.
642
643 Setting C<append> to C<NULL> means I<no> additional options
644 are passed (libguestfs always adds a few of its own).");
645
646   ("get_append", (RConstOptString "append", []), -1, [],
647    (* This cannot be tested with the current framework.  The
648     * function can return NULL in normal operations, which the
649     * test framework interprets as an error.
650     *)
651    [],
652    "get the additional kernel options",
653    "\
654 Return the additional kernel options which are added to the
655 guest kernel command line.
656
657 If C<NULL> then no options are added.");
658
659   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
660    [],
661    "set autosync mode",
662    "\
663 If C<autosync> is true, this enables autosync.  Libguestfs will make a
664 best effort attempt to run C<guestfs_umount_all> followed by
665 C<guestfs_sync> when the handle is closed
666 (also if the program exits without closing handles).
667
668 This is disabled by default (except in guestfish where it is
669 enabled by default).");
670
671   ("get_autosync", (RBool "autosync", []), -1, [],
672    [InitNone, Always, TestRun (
673       [["get_autosync"]])],
674    "get autosync mode",
675    "\
676 Get the autosync flag.");
677
678   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
679    [],
680    "set verbose mode",
681    "\
682 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
683
684 Verbose messages are disabled unless the environment variable
685 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
686
687   ("get_verbose", (RBool "verbose", []), -1, [],
688    [],
689    "get verbose mode",
690    "\
691 This returns the verbose messages flag.");
692
693   ("is_ready", (RBool "ready", []), -1, [],
694    [InitNone, Always, TestOutputTrue (
695       [["is_ready"]])],
696    "is ready to accept commands",
697    "\
698 This returns true iff this handle is ready to accept commands
699 (in the C<READY> state).
700
701 For more information on states, see L<guestfs(3)>.");
702
703   ("is_config", (RBool "config", []), -1, [],
704    [InitNone, Always, TestOutputFalse (
705       [["is_config"]])],
706    "is in configuration state",
707    "\
708 This returns true iff this handle is being configured
709 (in the C<CONFIG> state).
710
711 For more information on states, see L<guestfs(3)>.");
712
713   ("is_launching", (RBool "launching", []), -1, [],
714    [InitNone, Always, TestOutputFalse (
715       [["is_launching"]])],
716    "is launching subprocess",
717    "\
718 This returns true iff this handle is launching the subprocess
719 (in the C<LAUNCHING> state).
720
721 For more information on states, see L<guestfs(3)>.");
722
723   ("is_busy", (RBool "busy", []), -1, [],
724    [InitNone, Always, TestOutputFalse (
725       [["is_busy"]])],
726    "is busy processing a command",
727    "\
728 This returns true iff this handle is busy processing a command
729 (in the C<BUSY> state).
730
731 For more information on states, see L<guestfs(3)>.");
732
733   ("get_state", (RInt "state", []), -1, [],
734    [],
735    "get the current state",
736    "\
737 This returns the current state as an opaque integer.  This is
738 only useful for printing debug and internal error messages.
739
740 For more information on states, see L<guestfs(3)>.");
741
742   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
743    [InitNone, Always, TestOutputInt (
744       [["set_memsize"; "500"];
745        ["get_memsize"]], 500)],
746    "set memory allocated to the qemu subprocess",
747    "\
748 This sets the memory size in megabytes allocated to the
749 qemu subprocess.  This only has any effect if called before
750 C<guestfs_launch>.
751
752 You can also change this by setting the environment
753 variable C<LIBGUESTFS_MEMSIZE> before the handle is
754 created.
755
756 For more information on the architecture of libguestfs,
757 see L<guestfs(3)>.");
758
759   ("get_memsize", (RInt "memsize", []), -1, [],
760    [InitNone, Always, TestOutputIntOp (
761       [["get_memsize"]], ">=", 256)],
762    "get memory allocated to the qemu subprocess",
763    "\
764 This gets the memory size in megabytes allocated to the
765 qemu subprocess.
766
767 If C<guestfs_set_memsize> was not called
768 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
769 then this returns the compiled-in default value for memsize.
770
771 For more information on the architecture of libguestfs,
772 see L<guestfs(3)>.");
773
774   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
775    [InitNone, Always, TestOutputIntOp (
776       [["get_pid"]], ">=", 1)],
777    "get PID of qemu subprocess",
778    "\
779 Return the process ID of the qemu subprocess.  If there is no
780 qemu subprocess, then this will return an error.
781
782 This is an internal call used for debugging and testing.");
783
784   ("version", (RStruct ("version", "version"), []), -1, [],
785    [InitNone, Always, TestOutputStruct (
786       [["version"]], [CompareWithInt ("major", 1)])],
787    "get the library version number",
788    "\
789 Return the libguestfs version number that the program is linked
790 against.
791
792 Note that because of dynamic linking this is not necessarily
793 the version of libguestfs that you compiled against.  You can
794 compile the program, and then at runtime dynamically link
795 against a completely different C<libguestfs.so> library.
796
797 This call was added in version C<1.0.58>.  In previous
798 versions of libguestfs there was no way to get the version
799 number.  From C code you can use ELF weak linking tricks to find out if
800 this symbol exists (if it doesn't, then it's an earlier version).
801
802 The call returns a structure with four elements.  The first
803 three (C<major>, C<minor> and C<release>) are numbers and
804 correspond to the usual version triplet.  The fourth element
805 (C<extra>) is a string and is normally empty, but may be
806 used for distro-specific information.
807
808 To construct the original version string:
809 C<$major.$minor.$release$extra>
810
811 I<Note:> Don't use this call to test for availability
812 of features.  Distro backports makes this unreliable.  Use
813 C<guestfs_available> instead.");
814
815   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
816    [InitNone, Always, TestOutputTrue (
817       [["set_selinux"; "true"];
818        ["get_selinux"]])],
819    "set SELinux enabled or disabled at appliance boot",
820    "\
821 This sets the selinux flag that is passed to the appliance
822 at boot time.  The default is C<selinux=0> (disabled).
823
824 Note that if SELinux is enabled, it is always in
825 Permissive mode (C<enforcing=0>).
826
827 For more information on the architecture of libguestfs,
828 see L<guestfs(3)>.");
829
830   ("get_selinux", (RBool "selinux", []), -1, [],
831    [],
832    "get SELinux enabled flag",
833    "\
834 This returns the current setting of the selinux flag which
835 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
836
837 For more information on the architecture of libguestfs,
838 see L<guestfs(3)>.");
839
840   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
841    [InitNone, Always, TestOutputFalse (
842       [["set_trace"; "false"];
843        ["get_trace"]])],
844    "enable or disable command traces",
845    "\
846 If the command trace flag is set to 1, then commands are
847 printed on stdout before they are executed in a format
848 which is very similar to the one used by guestfish.  In
849 other words, you can run a program with this enabled, and
850 you will get out a script which you can feed to guestfish
851 to perform the same set of actions.
852
853 If you want to trace C API calls into libguestfs (and
854 other libraries) then possibly a better way is to use
855 the external ltrace(1) command.
856
857 Command traces are disabled unless the environment variable
858 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
859
860   ("get_trace", (RBool "trace", []), -1, [],
861    [],
862    "get command trace enabled flag",
863    "\
864 Return the command trace flag.");
865
866   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
867    [InitNone, Always, TestOutputFalse (
868       [["set_direct"; "false"];
869        ["get_direct"]])],
870    "enable or disable direct appliance mode",
871    "\
872 If the direct appliance mode flag is enabled, then stdin and
873 stdout are passed directly through to the appliance once it
874 is launched.
875
876 One consequence of this is that log messages aren't caught
877 by the library and handled by C<guestfs_set_log_message_callback>,
878 but go straight to stdout.
879
880 You probably don't want to use this unless you know what you
881 are doing.
882
883 The default is disabled.");
884
885   ("get_direct", (RBool "direct", []), -1, [],
886    [],
887    "get direct appliance mode flag",
888    "\
889 Return the direct appliance mode flag.");
890
891   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
892    [InitNone, Always, TestOutputTrue (
893       [["set_recovery_proc"; "true"];
894        ["get_recovery_proc"]])],
895    "enable or disable the recovery process",
896    "\
897 If this is called with the parameter C<false> then
898 C<guestfs_launch> does not create a recovery process.  The
899 purpose of the recovery process is to stop runaway qemu
900 processes in the case where the main program aborts abruptly.
901
902 This only has any effect if called before C<guestfs_launch>,
903 and the default is true.
904
905 About the only time when you would want to disable this is
906 if the main process will fork itself into the background
907 (\"daemonize\" itself).  In this case the recovery process
908 thinks that the main program has disappeared and so kills
909 qemu, which is not very helpful.");
910
911   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
912    [],
913    "get recovery process enabled flag",
914    "\
915 Return the recovery process enabled flag.");
916
917   ("add_drive_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
918    [],
919    "add a drive specifying the QEMU block emulation to use",
920    "\
921 This is the same as C<guestfs_add_drive> but it allows you
922 to specify the QEMU interface emulation to use at run time.");
923
924   ("add_drive_ro_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
925    [],
926    "add a drive read-only specifying the QEMU block emulation to use",
927    "\
928 This is the same as C<guestfs_add_drive_ro> but it allows you
929 to specify the QEMU interface emulation to use at run time.");
930
931 ]
932
933 (* daemon_functions are any functions which cause some action
934  * to take place in the daemon.
935  *)
936
937 let daemon_functions = [
938   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
939    [InitEmpty, Always, TestOutput (
940       [["part_disk"; "/dev/sda"; "mbr"];
941        ["mkfs"; "ext2"; "/dev/sda1"];
942        ["mount"; "/dev/sda1"; "/"];
943        ["write_file"; "/new"; "new file contents"; "0"];
944        ["cat"; "/new"]], "new file contents")],
945    "mount a guest disk at a position in the filesystem",
946    "\
947 Mount a guest disk at a position in the filesystem.  Block devices
948 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
949 the guest.  If those block devices contain partitions, they will have
950 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
951 names can be used.
952
953 The rules are the same as for L<mount(2)>:  A filesystem must
954 first be mounted on C</> before others can be mounted.  Other
955 filesystems can only be mounted on directories which already
956 exist.
957
958 The mounted filesystem is writable, if we have sufficient permissions
959 on the underlying device.
960
961 The filesystem options C<sync> and C<noatime> are set with this
962 call, in order to improve reliability.");
963
964   ("sync", (RErr, []), 2, [],
965    [ InitEmpty, Always, TestRun [["sync"]]],
966    "sync disks, writes are flushed through to the disk image",
967    "\
968 This syncs the disk, so that any writes are flushed through to the
969 underlying disk image.
970
971 You should always call this if you have modified a disk image, before
972 closing the handle.");
973
974   ("touch", (RErr, [Pathname "path"]), 3, [],
975    [InitBasicFS, Always, TestOutputTrue (
976       [["touch"; "/new"];
977        ["exists"; "/new"]])],
978    "update file timestamps or create a new file",
979    "\
980 Touch acts like the L<touch(1)> command.  It can be used to
981 update the timestamps on a file, or, if the file does not exist,
982 to create a new zero-length file.");
983
984   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
985    [InitISOFS, Always, TestOutput (
986       [["cat"; "/known-2"]], "abcdef\n")],
987    "list the contents of a file",
988    "\
989 Return the contents of the file named C<path>.
990
991 Note that this function cannot correctly handle binary files
992 (specifically, files containing C<\\0> character which is treated
993 as end of string).  For those you need to use the C<guestfs_read_file>
994 or C<guestfs_download> functions which have a more complex interface.");
995
996   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
997    [], (* XXX Tricky to test because it depends on the exact format
998         * of the 'ls -l' command, which changes between F10 and F11.
999         *)
1000    "list the files in a directory (long format)",
1001    "\
1002 List the files in C<directory> (relative to the root directory,
1003 there is no cwd) in the format of 'ls -la'.
1004
1005 This command is mostly useful for interactive sessions.  It
1006 is I<not> intended that you try to parse the output string.");
1007
1008   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
1009    [InitBasicFS, Always, TestOutputList (
1010       [["touch"; "/new"];
1011        ["touch"; "/newer"];
1012        ["touch"; "/newest"];
1013        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
1014    "list the files in a directory",
1015    "\
1016 List the files in C<directory> (relative to the root directory,
1017 there is no cwd).  The '.' and '..' entries are not returned, but
1018 hidden files are shown.
1019
1020 This command is mostly useful for interactive sessions.  Programs
1021 should probably use C<guestfs_readdir> instead.");
1022
1023   ("list_devices", (RStringList "devices", []), 7, [],
1024    [InitEmpty, Always, TestOutputListOfDevices (
1025       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
1026    "list the block devices",
1027    "\
1028 List all the block devices.
1029
1030 The full block device names are returned, eg. C</dev/sda>");
1031
1032   ("list_partitions", (RStringList "partitions", []), 8, [],
1033    [InitBasicFS, Always, TestOutputListOfDevices (
1034       [["list_partitions"]], ["/dev/sda1"]);
1035     InitEmpty, Always, TestOutputListOfDevices (
1036       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1037        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1038    "list the partitions",
1039    "\
1040 List all the partitions detected on all block devices.
1041
1042 The full partition device names are returned, eg. C</dev/sda1>
1043
1044 This does not return logical volumes.  For that you will need to
1045 call C<guestfs_lvs>.");
1046
1047   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
1048    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
1049       [["pvs"]], ["/dev/sda1"]);
1050     InitEmpty, Always, TestOutputListOfDevices (
1051       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1052        ["pvcreate"; "/dev/sda1"];
1053        ["pvcreate"; "/dev/sda2"];
1054        ["pvcreate"; "/dev/sda3"];
1055        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1056    "list the LVM physical volumes (PVs)",
1057    "\
1058 List all the physical volumes detected.  This is the equivalent
1059 of the L<pvs(8)> command.
1060
1061 This returns a list of just the device names that contain
1062 PVs (eg. C</dev/sda2>).
1063
1064 See also C<guestfs_pvs_full>.");
1065
1066   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1067    [InitBasicFSonLVM, Always, TestOutputList (
1068       [["vgs"]], ["VG"]);
1069     InitEmpty, Always, TestOutputList (
1070       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1071        ["pvcreate"; "/dev/sda1"];
1072        ["pvcreate"; "/dev/sda2"];
1073        ["pvcreate"; "/dev/sda3"];
1074        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1075        ["vgcreate"; "VG2"; "/dev/sda3"];
1076        ["vgs"]], ["VG1"; "VG2"])],
1077    "list the LVM volume groups (VGs)",
1078    "\
1079 List all the volumes groups detected.  This is the equivalent
1080 of the L<vgs(8)> command.
1081
1082 This returns a list of just the volume group names that were
1083 detected (eg. C<VolGroup00>).
1084
1085 See also C<guestfs_vgs_full>.");
1086
1087   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1088    [InitBasicFSonLVM, Always, TestOutputList (
1089       [["lvs"]], ["/dev/VG/LV"]);
1090     InitEmpty, Always, TestOutputList (
1091       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1092        ["pvcreate"; "/dev/sda1"];
1093        ["pvcreate"; "/dev/sda2"];
1094        ["pvcreate"; "/dev/sda3"];
1095        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1096        ["vgcreate"; "VG2"; "/dev/sda3"];
1097        ["lvcreate"; "LV1"; "VG1"; "50"];
1098        ["lvcreate"; "LV2"; "VG1"; "50"];
1099        ["lvcreate"; "LV3"; "VG2"; "50"];
1100        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1101    "list the LVM logical volumes (LVs)",
1102    "\
1103 List all the logical volumes detected.  This is the equivalent
1104 of the L<lvs(8)> command.
1105
1106 This returns a list of the logical volume device names
1107 (eg. C</dev/VolGroup00/LogVol00>).
1108
1109 See also C<guestfs_lvs_full>.");
1110
1111   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1112    [], (* XXX how to test? *)
1113    "list the LVM physical volumes (PVs)",
1114    "\
1115 List all the physical volumes detected.  This is the equivalent
1116 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1117
1118   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1119    [], (* XXX how to test? *)
1120    "list the LVM volume groups (VGs)",
1121    "\
1122 List all the volumes groups detected.  This is the equivalent
1123 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1124
1125   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1126    [], (* XXX how to test? *)
1127    "list the LVM logical volumes (LVs)",
1128    "\
1129 List all the logical volumes detected.  This is the equivalent
1130 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1131
1132   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1133    [InitISOFS, Always, TestOutputList (
1134       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1135     InitISOFS, Always, TestOutputList (
1136       [["read_lines"; "/empty"]], [])],
1137    "read file as lines",
1138    "\
1139 Return the contents of the file named C<path>.
1140
1141 The file contents are returned as a list of lines.  Trailing
1142 C<LF> and C<CRLF> character sequences are I<not> returned.
1143
1144 Note that this function cannot correctly handle binary files
1145 (specifically, files containing C<\\0> character which is treated
1146 as end of line).  For those you need to use the C<guestfs_read_file>
1147 function which has a more complex interface.");
1148
1149   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1150    [], (* XXX Augeas code needs tests. *)
1151    "create a new Augeas handle",
1152    "\
1153 Create a new Augeas handle for editing configuration files.
1154 If there was any previous Augeas handle associated with this
1155 guestfs session, then it is closed.
1156
1157 You must call this before using any other C<guestfs_aug_*>
1158 commands.
1159
1160 C<root> is the filesystem root.  C<root> must not be NULL,
1161 use C</> instead.
1162
1163 The flags are the same as the flags defined in
1164 E<lt>augeas.hE<gt>, the logical I<or> of the following
1165 integers:
1166
1167 =over 4
1168
1169 =item C<AUG_SAVE_BACKUP> = 1
1170
1171 Keep the original file with a C<.augsave> extension.
1172
1173 =item C<AUG_SAVE_NEWFILE> = 2
1174
1175 Save changes into a file with extension C<.augnew>, and
1176 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1177
1178 =item C<AUG_TYPE_CHECK> = 4
1179
1180 Typecheck lenses (can be expensive).
1181
1182 =item C<AUG_NO_STDINC> = 8
1183
1184 Do not use standard load path for modules.
1185
1186 =item C<AUG_SAVE_NOOP> = 16
1187
1188 Make save a no-op, just record what would have been changed.
1189
1190 =item C<AUG_NO_LOAD> = 32
1191
1192 Do not load the tree in C<guestfs_aug_init>.
1193
1194 =back
1195
1196 To close the handle, you can call C<guestfs_aug_close>.
1197
1198 To find out more about Augeas, see L<http://augeas.net/>.");
1199
1200   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1201    [], (* XXX Augeas code needs tests. *)
1202    "close the current Augeas handle",
1203    "\
1204 Close the current Augeas handle and free up any resources
1205 used by it.  After calling this, you have to call
1206 C<guestfs_aug_init> again before you can use any other
1207 Augeas functions.");
1208
1209   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1210    [], (* XXX Augeas code needs tests. *)
1211    "define an Augeas variable",
1212    "\
1213 Defines an Augeas variable C<name> whose value is the result
1214 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1215 undefined.
1216
1217 On success this returns the number of nodes in C<expr>, or
1218 C<0> if C<expr> evaluates to something which is not a nodeset.");
1219
1220   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1221    [], (* XXX Augeas code needs tests. *)
1222    "define an Augeas node",
1223    "\
1224 Defines a variable C<name> whose value is the result of
1225 evaluating C<expr>.
1226
1227 If C<expr> evaluates to an empty nodeset, a node is created,
1228 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1229 C<name> will be the nodeset containing that single node.
1230
1231 On success this returns a pair containing the
1232 number of nodes in the nodeset, and a boolean flag
1233 if a node was created.");
1234
1235   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1236    [], (* XXX Augeas code needs tests. *)
1237    "look up the value of an Augeas path",
1238    "\
1239 Look up the value associated with C<path>.  If C<path>
1240 matches exactly one node, the C<value> is returned.");
1241
1242   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1243    [], (* XXX Augeas code needs tests. *)
1244    "set Augeas path to value",
1245    "\
1246 Set the value associated with C<path> to C<val>.
1247
1248 In the Augeas API, it is possible to clear a node by setting
1249 the value to NULL.  Due to an oversight in the libguestfs API
1250 you cannot do that with this call.  Instead you must use the
1251 C<guestfs_aug_clear> call.");
1252
1253   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1254    [], (* XXX Augeas code needs tests. *)
1255    "insert a sibling Augeas node",
1256    "\
1257 Create a new sibling C<label> for C<path>, inserting it into
1258 the tree before or after C<path> (depending on the boolean
1259 flag C<before>).
1260
1261 C<path> must match exactly one existing node in the tree, and
1262 C<label> must be a label, ie. not contain C</>, C<*> or end
1263 with a bracketed index C<[N]>.");
1264
1265   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1266    [], (* XXX Augeas code needs tests. *)
1267    "remove an Augeas path",
1268    "\
1269 Remove C<path> and all of its children.
1270
1271 On success this returns the number of entries which were removed.");
1272
1273   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1274    [], (* XXX Augeas code needs tests. *)
1275    "move Augeas node",
1276    "\
1277 Move the node C<src> to C<dest>.  C<src> must match exactly
1278 one node.  C<dest> is overwritten if it exists.");
1279
1280   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1281    [], (* XXX Augeas code needs tests. *)
1282    "return Augeas nodes which match augpath",
1283    "\
1284 Returns a list of paths which match the path expression C<path>.
1285 The returned paths are sufficiently qualified so that they match
1286 exactly one node in the current tree.");
1287
1288   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1289    [], (* XXX Augeas code needs tests. *)
1290    "write all pending Augeas changes to disk",
1291    "\
1292 This writes all pending changes to disk.
1293
1294 The flags which were passed to C<guestfs_aug_init> affect exactly
1295 how files are saved.");
1296
1297   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1298    [], (* XXX Augeas code needs tests. *)
1299    "load files into the tree",
1300    "\
1301 Load files into the tree.
1302
1303 See C<aug_load> in the Augeas documentation for the full gory
1304 details.");
1305
1306   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1307    [], (* XXX Augeas code needs tests. *)
1308    "list Augeas nodes under augpath",
1309    "\
1310 This is just a shortcut for listing C<guestfs_aug_match>
1311 C<path/*> and sorting the resulting nodes into alphabetical order.");
1312
1313   ("rm", (RErr, [Pathname "path"]), 29, [],
1314    [InitBasicFS, Always, TestRun
1315       [["touch"; "/new"];
1316        ["rm"; "/new"]];
1317     InitBasicFS, Always, TestLastFail
1318       [["rm"; "/new"]];
1319     InitBasicFS, Always, TestLastFail
1320       [["mkdir"; "/new"];
1321        ["rm"; "/new"]]],
1322    "remove a file",
1323    "\
1324 Remove the single file C<path>.");
1325
1326   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1327    [InitBasicFS, Always, TestRun
1328       [["mkdir"; "/new"];
1329        ["rmdir"; "/new"]];
1330     InitBasicFS, Always, TestLastFail
1331       [["rmdir"; "/new"]];
1332     InitBasicFS, Always, TestLastFail
1333       [["touch"; "/new"];
1334        ["rmdir"; "/new"]]],
1335    "remove a directory",
1336    "\
1337 Remove the single directory C<path>.");
1338
1339   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1340    [InitBasicFS, Always, TestOutputFalse
1341       [["mkdir"; "/new"];
1342        ["mkdir"; "/new/foo"];
1343        ["touch"; "/new/foo/bar"];
1344        ["rm_rf"; "/new"];
1345        ["exists"; "/new"]]],
1346    "remove a file or directory recursively",
1347    "\
1348 Remove the file or directory C<path>, recursively removing the
1349 contents if its a directory.  This is like the C<rm -rf> shell
1350 command.");
1351
1352   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1353    [InitBasicFS, Always, TestOutputTrue
1354       [["mkdir"; "/new"];
1355        ["is_dir"; "/new"]];
1356     InitBasicFS, Always, TestLastFail
1357       [["mkdir"; "/new/foo/bar"]]],
1358    "create a directory",
1359    "\
1360 Create a directory named C<path>.");
1361
1362   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1363    [InitBasicFS, Always, TestOutputTrue
1364       [["mkdir_p"; "/new/foo/bar"];
1365        ["is_dir"; "/new/foo/bar"]];
1366     InitBasicFS, Always, TestOutputTrue
1367       [["mkdir_p"; "/new/foo/bar"];
1368        ["is_dir"; "/new/foo"]];
1369     InitBasicFS, Always, TestOutputTrue
1370       [["mkdir_p"; "/new/foo/bar"];
1371        ["is_dir"; "/new"]];
1372     (* Regression tests for RHBZ#503133: *)
1373     InitBasicFS, Always, TestRun
1374       [["mkdir"; "/new"];
1375        ["mkdir_p"; "/new"]];
1376     InitBasicFS, Always, TestLastFail
1377       [["touch"; "/new"];
1378        ["mkdir_p"; "/new"]]],
1379    "create a directory and parents",
1380    "\
1381 Create a directory named C<path>, creating any parent directories
1382 as necessary.  This is like the C<mkdir -p> shell command.");
1383
1384   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1385    [], (* XXX Need stat command to test *)
1386    "change file mode",
1387    "\
1388 Change the mode (permissions) of C<path> to C<mode>.  Only
1389 numeric modes are supported.
1390
1391 I<Note>: When using this command from guestfish, C<mode>
1392 by default would be decimal, unless you prefix it with
1393 C<0> to get octal, ie. use C<0700> not C<700>.
1394
1395 The mode actually set is affected by the umask.");
1396
1397   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1398    [], (* XXX Need stat command to test *)
1399    "change file owner and group",
1400    "\
1401 Change the file owner to C<owner> and group to C<group>.
1402
1403 Only numeric uid and gid are supported.  If you want to use
1404 names, you will need to locate and parse the password file
1405 yourself (Augeas support makes this relatively easy).");
1406
1407   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1408    [InitISOFS, Always, TestOutputTrue (
1409       [["exists"; "/empty"]]);
1410     InitISOFS, Always, TestOutputTrue (
1411       [["exists"; "/directory"]])],
1412    "test if file or directory exists",
1413    "\
1414 This returns C<true> if and only if there is a file, directory
1415 (or anything) with the given C<path> name.
1416
1417 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1418
1419   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1420    [InitISOFS, Always, TestOutputTrue (
1421       [["is_file"; "/known-1"]]);
1422     InitISOFS, Always, TestOutputFalse (
1423       [["is_file"; "/directory"]])],
1424    "test if file exists",
1425    "\
1426 This returns C<true> if and only if there is a file
1427 with the given C<path> name.  Note that it returns false for
1428 other objects like directories.
1429
1430 See also C<guestfs_stat>.");
1431
1432   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1433    [InitISOFS, Always, TestOutputFalse (
1434       [["is_dir"; "/known-3"]]);
1435     InitISOFS, Always, TestOutputTrue (
1436       [["is_dir"; "/directory"]])],
1437    "test if file exists",
1438    "\
1439 This returns C<true> if and only if there is a directory
1440 with the given C<path> name.  Note that it returns false for
1441 other objects like files.
1442
1443 See also C<guestfs_stat>.");
1444
1445   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1446    [InitEmpty, Always, TestOutputListOfDevices (
1447       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1448        ["pvcreate"; "/dev/sda1"];
1449        ["pvcreate"; "/dev/sda2"];
1450        ["pvcreate"; "/dev/sda3"];
1451        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1452    "create an LVM physical volume",
1453    "\
1454 This creates an LVM physical volume on the named C<device>,
1455 where C<device> should usually be a partition name such
1456 as C</dev/sda1>.");
1457
1458   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1459    [InitEmpty, Always, TestOutputList (
1460       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1461        ["pvcreate"; "/dev/sda1"];
1462        ["pvcreate"; "/dev/sda2"];
1463        ["pvcreate"; "/dev/sda3"];
1464        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1465        ["vgcreate"; "VG2"; "/dev/sda3"];
1466        ["vgs"]], ["VG1"; "VG2"])],
1467    "create an LVM volume group",
1468    "\
1469 This creates an LVM volume group called C<volgroup>
1470 from the non-empty list of physical volumes C<physvols>.");
1471
1472   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1473    [InitEmpty, Always, TestOutputList (
1474       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1475        ["pvcreate"; "/dev/sda1"];
1476        ["pvcreate"; "/dev/sda2"];
1477        ["pvcreate"; "/dev/sda3"];
1478        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1479        ["vgcreate"; "VG2"; "/dev/sda3"];
1480        ["lvcreate"; "LV1"; "VG1"; "50"];
1481        ["lvcreate"; "LV2"; "VG1"; "50"];
1482        ["lvcreate"; "LV3"; "VG2"; "50"];
1483        ["lvcreate"; "LV4"; "VG2"; "50"];
1484        ["lvcreate"; "LV5"; "VG2"; "50"];
1485        ["lvs"]],
1486       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1487        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1488    "create an LVM logical volume",
1489    "\
1490 This creates an LVM logical volume called C<logvol>
1491 on the volume group C<volgroup>, with C<size> megabytes.");
1492
1493   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1494    [InitEmpty, Always, TestOutput (
1495       [["part_disk"; "/dev/sda"; "mbr"];
1496        ["mkfs"; "ext2"; "/dev/sda1"];
1497        ["mount_options"; ""; "/dev/sda1"; "/"];
1498        ["write_file"; "/new"; "new file contents"; "0"];
1499        ["cat"; "/new"]], "new file contents")],
1500    "make a filesystem",
1501    "\
1502 This creates a filesystem on C<device> (usually a partition
1503 or LVM logical volume).  The filesystem type is C<fstype>, for
1504 example C<ext3>.");
1505
1506   ("sfdisk", (RErr, [Device "device";
1507                      Int "cyls"; Int "heads"; Int "sectors";
1508                      StringList "lines"]), 43, [DangerWillRobinson],
1509    [],
1510    "create partitions on a block device",
1511    "\
1512 This is a direct interface to the L<sfdisk(8)> program for creating
1513 partitions on block devices.
1514
1515 C<device> should be a block device, for example C</dev/sda>.
1516
1517 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1518 and sectors on the device, which are passed directly to sfdisk as
1519 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1520 of these, then the corresponding parameter is omitted.  Usually for
1521 'large' disks, you can just pass C<0> for these, but for small
1522 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1523 out the right geometry and you will need to tell it.
1524
1525 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1526 information refer to the L<sfdisk(8)> manpage.
1527
1528 To create a single partition occupying the whole disk, you would
1529 pass C<lines> as a single element list, when the single element being
1530 the string C<,> (comma).
1531
1532 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1533 C<guestfs_part_init>");
1534
1535   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1536    [InitBasicFS, Always, TestOutput (
1537       [["write_file"; "/new"; "new file contents"; "0"];
1538        ["cat"; "/new"]], "new file contents");
1539     InitBasicFS, Always, TestOutput (
1540       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1541        ["cat"; "/new"]], "\nnew file contents\n");
1542     InitBasicFS, Always, TestOutput (
1543       [["write_file"; "/new"; "\n\n"; "0"];
1544        ["cat"; "/new"]], "\n\n");
1545     InitBasicFS, Always, TestOutput (
1546       [["write_file"; "/new"; ""; "0"];
1547        ["cat"; "/new"]], "");
1548     InitBasicFS, Always, TestOutput (
1549       [["write_file"; "/new"; "\n\n\n"; "0"];
1550        ["cat"; "/new"]], "\n\n\n");
1551     InitBasicFS, Always, TestOutput (
1552       [["write_file"; "/new"; "\n"; "0"];
1553        ["cat"; "/new"]], "\n")],
1554    "create a file",
1555    "\
1556 This call creates a file called C<path>.  The contents of the
1557 file is the string C<content> (which can contain any 8 bit data),
1558 with length C<size>.
1559
1560 As a special case, if C<size> is C<0>
1561 then the length is calculated using C<strlen> (so in this case
1562 the content cannot contain embedded ASCII NULs).
1563
1564 I<NB.> Owing to a bug, writing content containing ASCII NUL
1565 characters does I<not> work, even if the length is specified.
1566 We hope to resolve this bug in a future version.  In the meantime
1567 use C<guestfs_upload>.");
1568
1569   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1570    [InitEmpty, Always, TestOutputListOfDevices (
1571       [["part_disk"; "/dev/sda"; "mbr"];
1572        ["mkfs"; "ext2"; "/dev/sda1"];
1573        ["mount_options"; ""; "/dev/sda1"; "/"];
1574        ["mounts"]], ["/dev/sda1"]);
1575     InitEmpty, Always, TestOutputList (
1576       [["part_disk"; "/dev/sda"; "mbr"];
1577        ["mkfs"; "ext2"; "/dev/sda1"];
1578        ["mount_options"; ""; "/dev/sda1"; "/"];
1579        ["umount"; "/"];
1580        ["mounts"]], [])],
1581    "unmount a filesystem",
1582    "\
1583 This unmounts the given filesystem.  The filesystem may be
1584 specified either by its mountpoint (path) or the device which
1585 contains the filesystem.");
1586
1587   ("mounts", (RStringList "devices", []), 46, [],
1588    [InitBasicFS, Always, TestOutputListOfDevices (
1589       [["mounts"]], ["/dev/sda1"])],
1590    "show mounted filesystems",
1591    "\
1592 This returns the list of currently mounted filesystems.  It returns
1593 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1594
1595 Some internal mounts are not shown.
1596
1597 See also: C<guestfs_mountpoints>");
1598
1599   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1600    [InitBasicFS, Always, TestOutputList (
1601       [["umount_all"];
1602        ["mounts"]], []);
1603     (* check that umount_all can unmount nested mounts correctly: *)
1604     InitEmpty, Always, TestOutputList (
1605       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1606        ["mkfs"; "ext2"; "/dev/sda1"];
1607        ["mkfs"; "ext2"; "/dev/sda2"];
1608        ["mkfs"; "ext2"; "/dev/sda3"];
1609        ["mount_options"; ""; "/dev/sda1"; "/"];
1610        ["mkdir"; "/mp1"];
1611        ["mount_options"; ""; "/dev/sda2"; "/mp1"];
1612        ["mkdir"; "/mp1/mp2"];
1613        ["mount_options"; ""; "/dev/sda3"; "/mp1/mp2"];
1614        ["mkdir"; "/mp1/mp2/mp3"];
1615        ["umount_all"];
1616        ["mounts"]], [])],
1617    "unmount all filesystems",
1618    "\
1619 This unmounts all mounted filesystems.
1620
1621 Some internal mounts are not unmounted by this call.");
1622
1623   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1624    [],
1625    "remove all LVM LVs, VGs and PVs",
1626    "\
1627 This command removes all LVM logical volumes, volume groups
1628 and physical volumes.");
1629
1630   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1631    [InitISOFS, Always, TestOutput (
1632       [["file"; "/empty"]], "empty");
1633     InitISOFS, Always, TestOutput (
1634       [["file"; "/known-1"]], "ASCII text");
1635     InitISOFS, Always, TestLastFail (
1636       [["file"; "/notexists"]])],
1637    "determine file type",
1638    "\
1639 This call uses the standard L<file(1)> command to determine
1640 the type or contents of the file.  This also works on devices,
1641 for example to find out whether a partition contains a filesystem.
1642
1643 This call will also transparently look inside various types
1644 of compressed file.
1645
1646 The exact command which runs is C<file -zbsL path>.  Note in
1647 particular that the filename is not prepended to the output
1648 (the C<-b> option).");
1649
1650   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1651    [InitBasicFS, Always, TestOutput (
1652       [["upload"; "test-command"; "/test-command"];
1653        ["chmod"; "0o755"; "/test-command"];
1654        ["command"; "/test-command 1"]], "Result1");
1655     InitBasicFS, Always, TestOutput (
1656       [["upload"; "test-command"; "/test-command"];
1657        ["chmod"; "0o755"; "/test-command"];
1658        ["command"; "/test-command 2"]], "Result2\n");
1659     InitBasicFS, Always, TestOutput (
1660       [["upload"; "test-command"; "/test-command"];
1661        ["chmod"; "0o755"; "/test-command"];
1662        ["command"; "/test-command 3"]], "\nResult3");
1663     InitBasicFS, Always, TestOutput (
1664       [["upload"; "test-command"; "/test-command"];
1665        ["chmod"; "0o755"; "/test-command"];
1666        ["command"; "/test-command 4"]], "\nResult4\n");
1667     InitBasicFS, Always, TestOutput (
1668       [["upload"; "test-command"; "/test-command"];
1669        ["chmod"; "0o755"; "/test-command"];
1670        ["command"; "/test-command 5"]], "\nResult5\n\n");
1671     InitBasicFS, Always, TestOutput (
1672       [["upload"; "test-command"; "/test-command"];
1673        ["chmod"; "0o755"; "/test-command"];
1674        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1675     InitBasicFS, Always, TestOutput (
1676       [["upload"; "test-command"; "/test-command"];
1677        ["chmod"; "0o755"; "/test-command"];
1678        ["command"; "/test-command 7"]], "");
1679     InitBasicFS, Always, TestOutput (
1680       [["upload"; "test-command"; "/test-command"];
1681        ["chmod"; "0o755"; "/test-command"];
1682        ["command"; "/test-command 8"]], "\n");
1683     InitBasicFS, Always, TestOutput (
1684       [["upload"; "test-command"; "/test-command"];
1685        ["chmod"; "0o755"; "/test-command"];
1686        ["command"; "/test-command 9"]], "\n\n");
1687     InitBasicFS, Always, TestOutput (
1688       [["upload"; "test-command"; "/test-command"];
1689        ["chmod"; "0o755"; "/test-command"];
1690        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1691     InitBasicFS, Always, TestOutput (
1692       [["upload"; "test-command"; "/test-command"];
1693        ["chmod"; "0o755"; "/test-command"];
1694        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1695     InitBasicFS, Always, TestLastFail (
1696       [["upload"; "test-command"; "/test-command"];
1697        ["chmod"; "0o755"; "/test-command"];
1698        ["command"; "/test-command"]])],
1699    "run a command from the guest filesystem",
1700    "\
1701 This call runs a command from the guest filesystem.  The
1702 filesystem must be mounted, and must contain a compatible
1703 operating system (ie. something Linux, with the same
1704 or compatible processor architecture).
1705
1706 The single parameter is an argv-style list of arguments.
1707 The first element is the name of the program to run.
1708 Subsequent elements are parameters.  The list must be
1709 non-empty (ie. must contain a program name).  Note that
1710 the command runs directly, and is I<not> invoked via
1711 the shell (see C<guestfs_sh>).
1712
1713 The return value is anything printed to I<stdout> by
1714 the command.
1715
1716 If the command returns a non-zero exit status, then
1717 this function returns an error message.  The error message
1718 string is the content of I<stderr> from the command.
1719
1720 The C<$PATH> environment variable will contain at least
1721 C</usr/bin> and C</bin>.  If you require a program from
1722 another location, you should provide the full path in the
1723 first parameter.
1724
1725 Shared libraries and data files required by the program
1726 must be available on filesystems which are mounted in the
1727 correct places.  It is the caller's responsibility to ensure
1728 all filesystems that are needed are mounted at the right
1729 locations.");
1730
1731   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1732    [InitBasicFS, Always, TestOutputList (
1733       [["upload"; "test-command"; "/test-command"];
1734        ["chmod"; "0o755"; "/test-command"];
1735        ["command_lines"; "/test-command 1"]], ["Result1"]);
1736     InitBasicFS, Always, TestOutputList (
1737       [["upload"; "test-command"; "/test-command"];
1738        ["chmod"; "0o755"; "/test-command"];
1739        ["command_lines"; "/test-command 2"]], ["Result2"]);
1740     InitBasicFS, Always, TestOutputList (
1741       [["upload"; "test-command"; "/test-command"];
1742        ["chmod"; "0o755"; "/test-command"];
1743        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1744     InitBasicFS, Always, TestOutputList (
1745       [["upload"; "test-command"; "/test-command"];
1746        ["chmod"; "0o755"; "/test-command"];
1747        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1748     InitBasicFS, Always, TestOutputList (
1749       [["upload"; "test-command"; "/test-command"];
1750        ["chmod"; "0o755"; "/test-command"];
1751        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1752     InitBasicFS, Always, TestOutputList (
1753       [["upload"; "test-command"; "/test-command"];
1754        ["chmod"; "0o755"; "/test-command"];
1755        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1756     InitBasicFS, Always, TestOutputList (
1757       [["upload"; "test-command"; "/test-command"];
1758        ["chmod"; "0o755"; "/test-command"];
1759        ["command_lines"; "/test-command 7"]], []);
1760     InitBasicFS, Always, TestOutputList (
1761       [["upload"; "test-command"; "/test-command"];
1762        ["chmod"; "0o755"; "/test-command"];
1763        ["command_lines"; "/test-command 8"]], [""]);
1764     InitBasicFS, Always, TestOutputList (
1765       [["upload"; "test-command"; "/test-command"];
1766        ["chmod"; "0o755"; "/test-command"];
1767        ["command_lines"; "/test-command 9"]], ["";""]);
1768     InitBasicFS, Always, TestOutputList (
1769       [["upload"; "test-command"; "/test-command"];
1770        ["chmod"; "0o755"; "/test-command"];
1771        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1772     InitBasicFS, Always, TestOutputList (
1773       [["upload"; "test-command"; "/test-command"];
1774        ["chmod"; "0o755"; "/test-command"];
1775        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1776    "run a command, returning lines",
1777    "\
1778 This is the same as C<guestfs_command>, but splits the
1779 result into a list of lines.
1780
1781 See also: C<guestfs_sh_lines>");
1782
1783   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1784    [InitISOFS, Always, TestOutputStruct (
1785       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1786    "get file information",
1787    "\
1788 Returns file information for the given C<path>.
1789
1790 This is the same as the C<stat(2)> system call.");
1791
1792   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1793    [InitISOFS, Always, TestOutputStruct (
1794       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1795    "get file information for a symbolic link",
1796    "\
1797 Returns file information for the given C<path>.
1798
1799 This is the same as C<guestfs_stat> except that if C<path>
1800 is a symbolic link, then the link is stat-ed, not the file it
1801 refers to.
1802
1803 This is the same as the C<lstat(2)> system call.");
1804
1805   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1806    [InitISOFS, Always, TestOutputStruct (
1807       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1808    "get file system statistics",
1809    "\
1810 Returns file system statistics for any mounted file system.
1811 C<path> should be a file or directory in the mounted file system
1812 (typically it is the mount point itself, but it doesn't need to be).
1813
1814 This is the same as the C<statvfs(2)> system call.");
1815
1816   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1817    [], (* XXX test *)
1818    "get ext2/ext3/ext4 superblock details",
1819    "\
1820 This returns the contents of the ext2, ext3 or ext4 filesystem
1821 superblock on C<device>.
1822
1823 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1824 manpage for more details.  The list of fields returned isn't
1825 clearly defined, and depends on both the version of C<tune2fs>
1826 that libguestfs was built against, and the filesystem itself.");
1827
1828   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1829    [InitEmpty, Always, TestOutputTrue (
1830       [["blockdev_setro"; "/dev/sda"];
1831        ["blockdev_getro"; "/dev/sda"]])],
1832    "set block device to read-only",
1833    "\
1834 Sets the block device named C<device> to read-only.
1835
1836 This uses the L<blockdev(8)> command.");
1837
1838   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1839    [InitEmpty, Always, TestOutputFalse (
1840       [["blockdev_setrw"; "/dev/sda"];
1841        ["blockdev_getro"; "/dev/sda"]])],
1842    "set block device to read-write",
1843    "\
1844 Sets the block device named C<device> to read-write.
1845
1846 This uses the L<blockdev(8)> command.");
1847
1848   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1849    [InitEmpty, Always, TestOutputTrue (
1850       [["blockdev_setro"; "/dev/sda"];
1851        ["blockdev_getro"; "/dev/sda"]])],
1852    "is block device set to read-only",
1853    "\
1854 Returns a boolean indicating if the block device is read-only
1855 (true if read-only, false if not).
1856
1857 This uses the L<blockdev(8)> command.");
1858
1859   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1860    [InitEmpty, Always, TestOutputInt (
1861       [["blockdev_getss"; "/dev/sda"]], 512)],
1862    "get sectorsize of block device",
1863    "\
1864 This returns the size of sectors on a block device.
1865 Usually 512, but can be larger for modern devices.
1866
1867 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1868 for that).
1869
1870 This uses the L<blockdev(8)> command.");
1871
1872   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1873    [InitEmpty, Always, TestOutputInt (
1874       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1875    "get blocksize of block device",
1876    "\
1877 This returns the block size of a device.
1878
1879 (Note this is different from both I<size in blocks> and
1880 I<filesystem block size>).
1881
1882 This uses the L<blockdev(8)> command.");
1883
1884   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1885    [], (* XXX test *)
1886    "set blocksize of block device",
1887    "\
1888 This sets the block size of a device.
1889
1890 (Note this is different from both I<size in blocks> and
1891 I<filesystem block size>).
1892
1893 This uses the L<blockdev(8)> command.");
1894
1895   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1896    [InitEmpty, Always, TestOutputInt (
1897       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1898    "get total size of device in 512-byte sectors",
1899    "\
1900 This returns the size of the device in units of 512-byte sectors
1901 (even if the sectorsize isn't 512 bytes ... weird).
1902
1903 See also C<guestfs_blockdev_getss> for the real sector size of
1904 the device, and C<guestfs_blockdev_getsize64> for the more
1905 useful I<size in bytes>.
1906
1907 This uses the L<blockdev(8)> command.");
1908
1909   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1910    [InitEmpty, Always, TestOutputInt (
1911       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1912    "get total size of device in bytes",
1913    "\
1914 This returns the size of the device in bytes.
1915
1916 See also C<guestfs_blockdev_getsz>.
1917
1918 This uses the L<blockdev(8)> command.");
1919
1920   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1921    [InitEmpty, Always, TestRun
1922       [["blockdev_flushbufs"; "/dev/sda"]]],
1923    "flush device buffers",
1924    "\
1925 This tells the kernel to flush internal buffers associated
1926 with C<device>.
1927
1928 This uses the L<blockdev(8)> command.");
1929
1930   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1931    [InitEmpty, Always, TestRun
1932       [["blockdev_rereadpt"; "/dev/sda"]]],
1933    "reread partition table",
1934    "\
1935 Reread the partition table on C<device>.
1936
1937 This uses the L<blockdev(8)> command.");
1938
1939   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1940    [InitBasicFS, Always, TestOutput (
1941       (* Pick a file from cwd which isn't likely to change. *)
1942       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1943        ["checksum"; "md5"; "/COPYING.LIB"]],
1944       Digest.to_hex (Digest.file "COPYING.LIB"))],
1945    "upload a file from the local machine",
1946    "\
1947 Upload local file C<filename> to C<remotefilename> on the
1948 filesystem.
1949
1950 C<filename> can also be a named pipe.
1951
1952 See also C<guestfs_download>.");
1953
1954   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1955    [InitBasicFS, Always, TestOutput (
1956       (* Pick a file from cwd which isn't likely to change. *)
1957       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1958        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1959        ["upload"; "testdownload.tmp"; "/upload"];
1960        ["checksum"; "md5"; "/upload"]],
1961       Digest.to_hex (Digest.file "COPYING.LIB"))],
1962    "download a file to the local machine",
1963    "\
1964 Download file C<remotefilename> and save it as C<filename>
1965 on the local machine.
1966
1967 C<filename> can also be a named pipe.
1968
1969 See also C<guestfs_upload>, C<guestfs_cat>.");
1970
1971   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1972    [InitISOFS, Always, TestOutput (
1973       [["checksum"; "crc"; "/known-3"]], "2891671662");
1974     InitISOFS, Always, TestLastFail (
1975       [["checksum"; "crc"; "/notexists"]]);
1976     InitISOFS, Always, TestOutput (
1977       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1978     InitISOFS, Always, TestOutput (
1979       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1980     InitISOFS, Always, TestOutput (
1981       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1982     InitISOFS, Always, TestOutput (
1983       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1984     InitISOFS, Always, TestOutput (
1985       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1986     InitISOFS, Always, TestOutput (
1987       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1988    "compute MD5, SHAx or CRC checksum of file",
1989    "\
1990 This call computes the MD5, SHAx or CRC checksum of the
1991 file named C<path>.
1992
1993 The type of checksum to compute is given by the C<csumtype>
1994 parameter which must have one of the following values:
1995
1996 =over 4
1997
1998 =item C<crc>
1999
2000 Compute the cyclic redundancy check (CRC) specified by POSIX
2001 for the C<cksum> command.
2002
2003 =item C<md5>
2004
2005 Compute the MD5 hash (using the C<md5sum> program).
2006
2007 =item C<sha1>
2008
2009 Compute the SHA1 hash (using the C<sha1sum> program).
2010
2011 =item C<sha224>
2012
2013 Compute the SHA224 hash (using the C<sha224sum> program).
2014
2015 =item C<sha256>
2016
2017 Compute the SHA256 hash (using the C<sha256sum> program).
2018
2019 =item C<sha384>
2020
2021 Compute the SHA384 hash (using the C<sha384sum> program).
2022
2023 =item C<sha512>
2024
2025 Compute the SHA512 hash (using the C<sha512sum> program).
2026
2027 =back
2028
2029 The checksum is returned as a printable string.");
2030
2031   ("tar_in", (RErr, [FileIn "tarfile"; Pathname "directory"]), 69, [],
2032    [InitBasicFS, Always, TestOutput (
2033       [["tar_in"; "../images/helloworld.tar"; "/"];
2034        ["cat"; "/hello"]], "hello\n")],
2035    "unpack tarfile to directory",
2036    "\
2037 This command uploads and unpacks local file C<tarfile> (an
2038 I<uncompressed> tar file) into C<directory>.
2039
2040 To upload a compressed tarball, use C<guestfs_tgz_in>
2041 or C<guestfs_txz_in>.");
2042
2043   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
2044    [],
2045    "pack directory into tarfile",
2046    "\
2047 This command packs the contents of C<directory> and downloads
2048 it to local file C<tarfile>.
2049
2050 To download a compressed tarball, use C<guestfs_tgz_out>
2051 or C<guestfs_txz_out>.");
2052
2053   ("tgz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 71, [],
2054    [InitBasicFS, Always, TestOutput (
2055       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
2056        ["cat"; "/hello"]], "hello\n")],
2057    "unpack compressed tarball to directory",
2058    "\
2059 This command uploads and unpacks local file C<tarball> (a
2060 I<gzip compressed> tar file) into C<directory>.
2061
2062 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
2063
2064   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
2065    [],
2066    "pack directory into compressed tarball",
2067    "\
2068 This command packs the contents of C<directory> and downloads
2069 it to local file C<tarball>.
2070
2071 To download an uncompressed tarball, use C<guestfs_tar_out>.");
2072
2073   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
2074    [InitBasicFS, Always, TestLastFail (
2075       [["umount"; "/"];
2076        ["mount_ro"; "/dev/sda1"; "/"];
2077        ["touch"; "/new"]]);
2078     InitBasicFS, Always, TestOutput (
2079       [["write_file"; "/new"; "data"; "0"];
2080        ["umount"; "/"];
2081        ["mount_ro"; "/dev/sda1"; "/"];
2082        ["cat"; "/new"]], "data")],
2083    "mount a guest disk, read-only",
2084    "\
2085 This is the same as the C<guestfs_mount> command, but it
2086 mounts the filesystem with the read-only (I<-o ro>) flag.");
2087
2088   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
2089    [],
2090    "mount a guest disk with mount options",
2091    "\
2092 This is the same as the C<guestfs_mount> command, but it
2093 allows you to set the mount options as for the
2094 L<mount(8)> I<-o> flag.");
2095
2096   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2097    [],
2098    "mount a guest disk with mount options and vfstype",
2099    "\
2100 This is the same as the C<guestfs_mount> command, but it
2101 allows you to set both the mount options and the vfstype
2102 as for the L<mount(8)> I<-o> and I<-t> flags.");
2103
2104   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2105    [],
2106    "debugging and internals",
2107    "\
2108 The C<guestfs_debug> command exposes some internals of
2109 C<guestfsd> (the guestfs daemon) that runs inside the
2110 qemu subprocess.
2111
2112 There is no comprehensive help for this command.  You have
2113 to look at the file C<daemon/debug.c> in the libguestfs source
2114 to find out what you can do.");
2115
2116   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2117    [InitEmpty, Always, TestOutputList (
2118       [["part_disk"; "/dev/sda"; "mbr"];
2119        ["pvcreate"; "/dev/sda1"];
2120        ["vgcreate"; "VG"; "/dev/sda1"];
2121        ["lvcreate"; "LV1"; "VG"; "50"];
2122        ["lvcreate"; "LV2"; "VG"; "50"];
2123        ["lvremove"; "/dev/VG/LV1"];
2124        ["lvs"]], ["/dev/VG/LV2"]);
2125     InitEmpty, Always, TestOutputList (
2126       [["part_disk"; "/dev/sda"; "mbr"];
2127        ["pvcreate"; "/dev/sda1"];
2128        ["vgcreate"; "VG"; "/dev/sda1"];
2129        ["lvcreate"; "LV1"; "VG"; "50"];
2130        ["lvcreate"; "LV2"; "VG"; "50"];
2131        ["lvremove"; "/dev/VG"];
2132        ["lvs"]], []);
2133     InitEmpty, Always, TestOutputList (
2134       [["part_disk"; "/dev/sda"; "mbr"];
2135        ["pvcreate"; "/dev/sda1"];
2136        ["vgcreate"; "VG"; "/dev/sda1"];
2137        ["lvcreate"; "LV1"; "VG"; "50"];
2138        ["lvcreate"; "LV2"; "VG"; "50"];
2139        ["lvremove"; "/dev/VG"];
2140        ["vgs"]], ["VG"])],
2141    "remove an LVM logical volume",
2142    "\
2143 Remove an LVM logical volume C<device>, where C<device> is
2144 the path to the LV, such as C</dev/VG/LV>.
2145
2146 You can also remove all LVs in a volume group by specifying
2147 the VG name, C</dev/VG>.");
2148
2149   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2150    [InitEmpty, Always, TestOutputList (
2151       [["part_disk"; "/dev/sda"; "mbr"];
2152        ["pvcreate"; "/dev/sda1"];
2153        ["vgcreate"; "VG"; "/dev/sda1"];
2154        ["lvcreate"; "LV1"; "VG"; "50"];
2155        ["lvcreate"; "LV2"; "VG"; "50"];
2156        ["vgremove"; "VG"];
2157        ["lvs"]], []);
2158     InitEmpty, Always, TestOutputList (
2159       [["part_disk"; "/dev/sda"; "mbr"];
2160        ["pvcreate"; "/dev/sda1"];
2161        ["vgcreate"; "VG"; "/dev/sda1"];
2162        ["lvcreate"; "LV1"; "VG"; "50"];
2163        ["lvcreate"; "LV2"; "VG"; "50"];
2164        ["vgremove"; "VG"];
2165        ["vgs"]], [])],
2166    "remove an LVM volume group",
2167    "\
2168 Remove an LVM volume group C<vgname>, (for example C<VG>).
2169
2170 This also forcibly removes all logical volumes in the volume
2171 group (if any).");
2172
2173   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2174    [InitEmpty, Always, TestOutputListOfDevices (
2175       [["part_disk"; "/dev/sda"; "mbr"];
2176        ["pvcreate"; "/dev/sda1"];
2177        ["vgcreate"; "VG"; "/dev/sda1"];
2178        ["lvcreate"; "LV1"; "VG"; "50"];
2179        ["lvcreate"; "LV2"; "VG"; "50"];
2180        ["vgremove"; "VG"];
2181        ["pvremove"; "/dev/sda1"];
2182        ["lvs"]], []);
2183     InitEmpty, Always, TestOutputListOfDevices (
2184       [["part_disk"; "/dev/sda"; "mbr"];
2185        ["pvcreate"; "/dev/sda1"];
2186        ["vgcreate"; "VG"; "/dev/sda1"];
2187        ["lvcreate"; "LV1"; "VG"; "50"];
2188        ["lvcreate"; "LV2"; "VG"; "50"];
2189        ["vgremove"; "VG"];
2190        ["pvremove"; "/dev/sda1"];
2191        ["vgs"]], []);
2192     InitEmpty, Always, TestOutputListOfDevices (
2193       [["part_disk"; "/dev/sda"; "mbr"];
2194        ["pvcreate"; "/dev/sda1"];
2195        ["vgcreate"; "VG"; "/dev/sda1"];
2196        ["lvcreate"; "LV1"; "VG"; "50"];
2197        ["lvcreate"; "LV2"; "VG"; "50"];
2198        ["vgremove"; "VG"];
2199        ["pvremove"; "/dev/sda1"];
2200        ["pvs"]], [])],
2201    "remove an LVM physical volume",
2202    "\
2203 This wipes a physical volume C<device> so that LVM will no longer
2204 recognise it.
2205
2206 The implementation uses the C<pvremove> command which refuses to
2207 wipe physical volumes that contain any volume groups, so you have
2208 to remove those first.");
2209
2210   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2211    [InitBasicFS, Always, TestOutput (
2212       [["set_e2label"; "/dev/sda1"; "testlabel"];
2213        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2214    "set the ext2/3/4 filesystem label",
2215    "\
2216 This sets the ext2/3/4 filesystem label of the filesystem on
2217 C<device> to C<label>.  Filesystem labels are limited to
2218 16 characters.
2219
2220 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2221 to return the existing label on a filesystem.");
2222
2223   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2224    [],
2225    "get the ext2/3/4 filesystem label",
2226    "\
2227 This returns the ext2/3/4 filesystem label of the filesystem on
2228 C<device>.");
2229
2230   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2231    (let uuid = uuidgen () in
2232     [InitBasicFS, Always, TestOutput (
2233        [["set_e2uuid"; "/dev/sda1"; uuid];
2234         ["get_e2uuid"; "/dev/sda1"]], uuid);
2235      InitBasicFS, Always, TestOutput (
2236        [["set_e2uuid"; "/dev/sda1"; "clear"];
2237         ["get_e2uuid"; "/dev/sda1"]], "");
2238      (* We can't predict what UUIDs will be, so just check the commands run. *)
2239      InitBasicFS, Always, TestRun (
2240        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2241      InitBasicFS, Always, TestRun (
2242        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2243    "set the ext2/3/4 filesystem UUID",
2244    "\
2245 This sets the ext2/3/4 filesystem UUID of the filesystem on
2246 C<device> to C<uuid>.  The format of the UUID and alternatives
2247 such as C<clear>, C<random> and C<time> are described in the
2248 L<tune2fs(8)> manpage.
2249
2250 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2251 to return the existing UUID of a filesystem.");
2252
2253   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2254    [],
2255    "get the ext2/3/4 filesystem UUID",
2256    "\
2257 This returns the ext2/3/4 filesystem UUID of the filesystem on
2258 C<device>.");
2259
2260   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [FishOutput FishOutputHexadecimal],
2261    [InitBasicFS, Always, TestOutputInt (
2262       [["umount"; "/dev/sda1"];
2263        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2264     InitBasicFS, Always, TestOutputInt (
2265       [["umount"; "/dev/sda1"];
2266        ["zero"; "/dev/sda1"];
2267        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2268    "run the filesystem checker",
2269    "\
2270 This runs the filesystem checker (fsck) on C<device> which
2271 should have filesystem type C<fstype>.
2272
2273 The returned integer is the status.  See L<fsck(8)> for the
2274 list of status codes from C<fsck>.
2275
2276 Notes:
2277
2278 =over 4
2279
2280 =item *
2281
2282 Multiple status codes can be summed together.
2283
2284 =item *
2285
2286 A non-zero return code can mean \"success\", for example if
2287 errors have been corrected on the filesystem.
2288
2289 =item *
2290
2291 Checking or repairing NTFS volumes is not supported
2292 (by linux-ntfs).
2293
2294 =back
2295
2296 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2297
2298   ("zero", (RErr, [Device "device"]), 85, [],
2299    [InitBasicFS, Always, TestOutput (
2300       [["umount"; "/dev/sda1"];
2301        ["zero"; "/dev/sda1"];
2302        ["file"; "/dev/sda1"]], "data")],
2303    "write zeroes to the device",
2304    "\
2305 This command writes zeroes over the first few blocks of C<device>.
2306
2307 How many blocks are zeroed isn't specified (but it's I<not> enough
2308 to securely wipe the device).  It should be sufficient to remove
2309 any partition tables, filesystem superblocks and so on.
2310
2311 See also: C<guestfs_zero_device>, C<guestfs_scrub_device>.");
2312
2313   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2314    (* Test disabled because grub-install incompatible with virtio-blk driver.
2315     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2316     *)
2317    [InitBasicFS, Disabled, TestOutputTrue (
2318       [["grub_install"; "/"; "/dev/sda1"];
2319        ["is_dir"; "/boot"]])],
2320    "install GRUB",
2321    "\
2322 This command installs GRUB (the Grand Unified Bootloader) on
2323 C<device>, with the root directory being C<root>.");
2324
2325   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2326    [InitBasicFS, Always, TestOutput (
2327       [["write_file"; "/old"; "file content"; "0"];
2328        ["cp"; "/old"; "/new"];
2329        ["cat"; "/new"]], "file content");
2330     InitBasicFS, Always, TestOutputTrue (
2331       [["write_file"; "/old"; "file content"; "0"];
2332        ["cp"; "/old"; "/new"];
2333        ["is_file"; "/old"]]);
2334     InitBasicFS, Always, TestOutput (
2335       [["write_file"; "/old"; "file content"; "0"];
2336        ["mkdir"; "/dir"];
2337        ["cp"; "/old"; "/dir/new"];
2338        ["cat"; "/dir/new"]], "file content")],
2339    "copy a file",
2340    "\
2341 This copies a file from C<src> to C<dest> where C<dest> is
2342 either a destination filename or destination directory.");
2343
2344   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2345    [InitBasicFS, Always, TestOutput (
2346       [["mkdir"; "/olddir"];
2347        ["mkdir"; "/newdir"];
2348        ["write_file"; "/olddir/file"; "file content"; "0"];
2349        ["cp_a"; "/olddir"; "/newdir"];
2350        ["cat"; "/newdir/olddir/file"]], "file content")],
2351    "copy a file or directory recursively",
2352    "\
2353 This copies a file or directory from C<src> to C<dest>
2354 recursively using the C<cp -a> command.");
2355
2356   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2357    [InitBasicFS, Always, TestOutput (
2358       [["write_file"; "/old"; "file content"; "0"];
2359        ["mv"; "/old"; "/new"];
2360        ["cat"; "/new"]], "file content");
2361     InitBasicFS, Always, TestOutputFalse (
2362       [["write_file"; "/old"; "file content"; "0"];
2363        ["mv"; "/old"; "/new"];
2364        ["is_file"; "/old"]])],
2365    "move a file",
2366    "\
2367 This moves a file from C<src> to C<dest> where C<dest> is
2368 either a destination filename or destination directory.");
2369
2370   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2371    [InitEmpty, Always, TestRun (
2372       [["drop_caches"; "3"]])],
2373    "drop kernel page cache, dentries and inodes",
2374    "\
2375 This instructs the guest kernel to drop its page cache,
2376 and/or dentries and inode caches.  The parameter C<whattodrop>
2377 tells the kernel what precisely to drop, see
2378 L<http://linux-mm.org/Drop_Caches>
2379
2380 Setting C<whattodrop> to 3 should drop everything.
2381
2382 This automatically calls L<sync(2)> before the operation,
2383 so that the maximum guest memory is freed.");
2384
2385   ("dmesg", (RString "kmsgs", []), 91, [],
2386    [InitEmpty, Always, TestRun (
2387       [["dmesg"]])],
2388    "return kernel messages",
2389    "\
2390 This returns the kernel messages (C<dmesg> output) from
2391 the guest kernel.  This is sometimes useful for extended
2392 debugging of problems.
2393
2394 Another way to get the same information is to enable
2395 verbose messages with C<guestfs_set_verbose> or by setting
2396 the environment variable C<LIBGUESTFS_DEBUG=1> before
2397 running the program.");
2398
2399   ("ping_daemon", (RErr, []), 92, [],
2400    [InitEmpty, Always, TestRun (
2401       [["ping_daemon"]])],
2402    "ping the guest daemon",
2403    "\
2404 This is a test probe into the guestfs daemon running inside
2405 the qemu subprocess.  Calling this function checks that the
2406 daemon responds to the ping message, without affecting the daemon
2407 or attached block device(s) in any other way.");
2408
2409   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2410    [InitBasicFS, Always, TestOutputTrue (
2411       [["write_file"; "/file1"; "contents of a file"; "0"];
2412        ["cp"; "/file1"; "/file2"];
2413        ["equal"; "/file1"; "/file2"]]);
2414     InitBasicFS, Always, TestOutputFalse (
2415       [["write_file"; "/file1"; "contents of a file"; "0"];
2416        ["write_file"; "/file2"; "contents of another file"; "0"];
2417        ["equal"; "/file1"; "/file2"]]);
2418     InitBasicFS, Always, TestLastFail (
2419       [["equal"; "/file1"; "/file2"]])],
2420    "test if two files have equal contents",
2421    "\
2422 This compares the two files C<file1> and C<file2> and returns
2423 true if their content is exactly equal, or false otherwise.
2424
2425 The external L<cmp(1)> program is used for the comparison.");
2426
2427   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2428    [InitISOFS, Always, TestOutputList (
2429       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2430     InitISOFS, Always, TestOutputList (
2431       [["strings"; "/empty"]], [])],
2432    "print the printable strings in a file",
2433    "\
2434 This runs the L<strings(1)> command on a file and returns
2435 the list of printable strings found.");
2436
2437   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2438    [InitISOFS, Always, TestOutputList (
2439       [["strings_e"; "b"; "/known-5"]], []);
2440     InitBasicFS, Disabled, TestOutputList (
2441       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2442        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2443    "print the printable strings in a file",
2444    "\
2445 This is like the C<guestfs_strings> command, but allows you to
2446 specify the encoding.
2447
2448 See the L<strings(1)> manpage for the full list of encodings.
2449
2450 Commonly useful encodings are C<l> (lower case L) which will
2451 show strings inside Windows/x86 files.
2452
2453 The returned strings are transcoded to UTF-8.");
2454
2455   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2456    [InitISOFS, Always, TestOutput (
2457       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2458     (* Test for RHBZ#501888c2 regression which caused large hexdump
2459      * commands to segfault.
2460      *)
2461     InitISOFS, Always, TestRun (
2462       [["hexdump"; "/100krandom"]])],
2463    "dump a file in hexadecimal",
2464    "\
2465 This runs C<hexdump -C> on the given C<path>.  The result is
2466 the human-readable, canonical hex dump of the file.");
2467
2468   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2469    [InitNone, Always, TestOutput (
2470       [["part_disk"; "/dev/sda"; "mbr"];
2471        ["mkfs"; "ext3"; "/dev/sda1"];
2472        ["mount_options"; ""; "/dev/sda1"; "/"];
2473        ["write_file"; "/new"; "test file"; "0"];
2474        ["umount"; "/dev/sda1"];
2475        ["zerofree"; "/dev/sda1"];
2476        ["mount_options"; ""; "/dev/sda1"; "/"];
2477        ["cat"; "/new"]], "test file")],
2478    "zero unused inodes and disk blocks on ext2/3 filesystem",
2479    "\
2480 This runs the I<zerofree> program on C<device>.  This program
2481 claims to zero unused inodes and disk blocks on an ext2/3
2482 filesystem, thus making it possible to compress the filesystem
2483 more effectively.
2484
2485 You should B<not> run this program if the filesystem is
2486 mounted.
2487
2488 It is possible that using this program can damage the filesystem
2489 or data on the filesystem.");
2490
2491   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2492    [],
2493    "resize an LVM physical volume",
2494    "\
2495 This resizes (expands or shrinks) an existing LVM physical
2496 volume to match the new size of the underlying device.");
2497
2498   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2499                        Int "cyls"; Int "heads"; Int "sectors";
2500                        String "line"]), 99, [DangerWillRobinson],
2501    [],
2502    "modify a single partition on a block device",
2503    "\
2504 This runs L<sfdisk(8)> option to modify just the single
2505 partition C<n> (note: C<n> counts from 1).
2506
2507 For other parameters, see C<guestfs_sfdisk>.  You should usually
2508 pass C<0> for the cyls/heads/sectors parameters.
2509
2510 See also: C<guestfs_part_add>");
2511
2512   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2513    [],
2514    "display the partition table",
2515    "\
2516 This displays the partition table on C<device>, in the
2517 human-readable output of the L<sfdisk(8)> command.  It is
2518 not intended to be parsed.
2519
2520 See also: C<guestfs_part_list>");
2521
2522   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2523    [],
2524    "display the kernel geometry",
2525    "\
2526 This displays the kernel's idea of the geometry of C<device>.
2527
2528 The result is in human-readable format, and not designed to
2529 be parsed.");
2530
2531   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2532    [],
2533    "display the disk geometry from the partition table",
2534    "\
2535 This displays the disk geometry of C<device> read from the
2536 partition table.  Especially in the case where the underlying
2537 block device has been resized, this can be different from the
2538 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2539
2540 The result is in human-readable format, and not designed to
2541 be parsed.");
2542
2543   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2544    [],
2545    "activate or deactivate all volume groups",
2546    "\
2547 This command activates or (if C<activate> is false) deactivates
2548 all logical volumes in all volume groups.
2549 If activated, then they are made known to the
2550 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2551 then those devices disappear.
2552
2553 This command is the same as running C<vgchange -a y|n>");
2554
2555   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2556    [],
2557    "activate or deactivate some volume groups",
2558    "\
2559 This command activates or (if C<activate> is false) deactivates
2560 all logical volumes in the listed volume groups C<volgroups>.
2561 If activated, then they are made known to the
2562 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2563 then those devices disappear.
2564
2565 This command is the same as running C<vgchange -a y|n volgroups...>
2566
2567 Note that if C<volgroups> is an empty list then B<all> volume groups
2568 are activated or deactivated.");
2569
2570   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2571    [InitNone, Always, TestOutput (
2572       [["part_disk"; "/dev/sda"; "mbr"];
2573        ["pvcreate"; "/dev/sda1"];
2574        ["vgcreate"; "VG"; "/dev/sda1"];
2575        ["lvcreate"; "LV"; "VG"; "10"];
2576        ["mkfs"; "ext2"; "/dev/VG/LV"];
2577        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2578        ["write_file"; "/new"; "test content"; "0"];
2579        ["umount"; "/"];
2580        ["lvresize"; "/dev/VG/LV"; "20"];
2581        ["e2fsck_f"; "/dev/VG/LV"];
2582        ["resize2fs"; "/dev/VG/LV"];
2583        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2584        ["cat"; "/new"]], "test content")],
2585    "resize an LVM logical volume",
2586    "\
2587 This resizes (expands or shrinks) an existing LVM logical
2588 volume to C<mbytes>.  When reducing, data in the reduced part
2589 is lost.");
2590
2591   ("resize2fs", (RErr, [Device "device"]), 106, [],
2592    [], (* lvresize tests this *)
2593    "resize an ext2/ext3 filesystem",
2594    "\
2595 This resizes an ext2 or ext3 filesystem to match the size of
2596 the underlying device.
2597
2598 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2599 on the C<device> before calling this command.  For unknown reasons
2600 C<resize2fs> sometimes gives an error about this and sometimes not.
2601 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2602 calling this function.");
2603
2604   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2605    [InitBasicFS, Always, TestOutputList (
2606       [["find"; "/"]], ["lost+found"]);
2607     InitBasicFS, Always, TestOutputList (
2608       [["touch"; "/a"];
2609        ["mkdir"; "/b"];
2610        ["touch"; "/b/c"];
2611        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2612     InitBasicFS, Always, TestOutputList (
2613       [["mkdir_p"; "/a/b/c"];
2614        ["touch"; "/a/b/c/d"];
2615        ["find"; "/a/b/"]], ["c"; "c/d"])],
2616    "find all files and directories",
2617    "\
2618 This command lists out all files and directories, recursively,
2619 starting at C<directory>.  It is essentially equivalent to
2620 running the shell command C<find directory -print> but some
2621 post-processing happens on the output, described below.
2622
2623 This returns a list of strings I<without any prefix>.  Thus
2624 if the directory structure was:
2625
2626  /tmp/a
2627  /tmp/b
2628  /tmp/c/d
2629
2630 then the returned list from C<guestfs_find> C</tmp> would be
2631 4 elements:
2632
2633  a
2634  b
2635  c
2636  c/d
2637
2638 If C<directory> is not a directory, then this command returns
2639 an error.
2640
2641 The returned list is sorted.
2642
2643 See also C<guestfs_find0>.");
2644
2645   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2646    [], (* lvresize tests this *)
2647    "check an ext2/ext3 filesystem",
2648    "\
2649 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2650 filesystem checker on C<device>, noninteractively (C<-p>),
2651 even if the filesystem appears to be clean (C<-f>).
2652
2653 This command is only needed because of C<guestfs_resize2fs>
2654 (q.v.).  Normally you should use C<guestfs_fsck>.");
2655
2656   ("sleep", (RErr, [Int "secs"]), 109, [],
2657    [InitNone, Always, TestRun (
2658       [["sleep"; "1"]])],
2659    "sleep for some seconds",
2660    "\
2661 Sleep for C<secs> seconds.");
2662
2663   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2664    [InitNone, Always, TestOutputInt (
2665       [["part_disk"; "/dev/sda"; "mbr"];
2666        ["mkfs"; "ntfs"; "/dev/sda1"];
2667        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2668     InitNone, Always, TestOutputInt (
2669       [["part_disk"; "/dev/sda"; "mbr"];
2670        ["mkfs"; "ext2"; "/dev/sda1"];
2671        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2672    "probe NTFS volume",
2673    "\
2674 This command runs the L<ntfs-3g.probe(8)> command which probes
2675 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2676 be mounted read-write, and some cannot be mounted at all).
2677
2678 C<rw> is a boolean flag.  Set it to true if you want to test
2679 if the volume can be mounted read-write.  Set it to false if
2680 you want to test if the volume can be mounted read-only.
2681
2682 The return value is an integer which C<0> if the operation
2683 would succeed, or some non-zero value documented in the
2684 L<ntfs-3g.probe(8)> manual page.");
2685
2686   ("sh", (RString "output", [String "command"]), 111, [],
2687    [], (* XXX needs tests *)
2688    "run a command via the shell",
2689    "\
2690 This call runs a command from the guest filesystem via the
2691 guest's C</bin/sh>.
2692
2693 This is like C<guestfs_command>, but passes the command to:
2694
2695  /bin/sh -c \"command\"
2696
2697 Depending on the guest's shell, this usually results in
2698 wildcards being expanded, shell expressions being interpolated
2699 and so on.
2700
2701 All the provisos about C<guestfs_command> apply to this call.");
2702
2703   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2704    [], (* XXX needs tests *)
2705    "run a command via the shell returning lines",
2706    "\
2707 This is the same as C<guestfs_sh>, but splits the result
2708 into a list of lines.
2709
2710 See also: C<guestfs_command_lines>");
2711
2712   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2713    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2714     * code in stubs.c, since all valid glob patterns must start with "/".
2715     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2716     *)
2717    [InitBasicFS, Always, TestOutputList (
2718       [["mkdir_p"; "/a/b/c"];
2719        ["touch"; "/a/b/c/d"];
2720        ["touch"; "/a/b/c/e"];
2721        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2722     InitBasicFS, Always, TestOutputList (
2723       [["mkdir_p"; "/a/b/c"];
2724        ["touch"; "/a/b/c/d"];
2725        ["touch"; "/a/b/c/e"];
2726        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2727     InitBasicFS, Always, TestOutputList (
2728       [["mkdir_p"; "/a/b/c"];
2729        ["touch"; "/a/b/c/d"];
2730        ["touch"; "/a/b/c/e"];
2731        ["glob_expand"; "/a/*/x/*"]], [])],
2732    "expand a wildcard path",
2733    "\
2734 This command searches for all the pathnames matching
2735 C<pattern> according to the wildcard expansion rules
2736 used by the shell.
2737
2738 If no paths match, then this returns an empty list
2739 (note: not an error).
2740
2741 It is just a wrapper around the C L<glob(3)> function
2742 with flags C<GLOB_MARK|GLOB_BRACE>.
2743 See that manual page for more details.");
2744
2745   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2746    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2747       [["scrub_device"; "/dev/sdc"]])],
2748    "scrub (securely wipe) a device",
2749    "\
2750 This command writes patterns over C<device> to make data retrieval
2751 more difficult.
2752
2753 It is an interface to the L<scrub(1)> program.  See that
2754 manual page for more details.");
2755
2756   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2757    [InitBasicFS, Always, TestRun (
2758       [["write_file"; "/file"; "content"; "0"];
2759        ["scrub_file"; "/file"]])],
2760    "scrub (securely wipe) a file",
2761    "\
2762 This command writes patterns over a file to make data retrieval
2763 more difficult.
2764
2765 The file is I<removed> after scrubbing.
2766
2767 It is an interface to the L<scrub(1)> program.  See that
2768 manual page for more details.");
2769
2770   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2771    [], (* XXX needs testing *)
2772    "scrub (securely wipe) free space",
2773    "\
2774 This command creates the directory C<dir> and then fills it
2775 with files until the filesystem is full, and scrubs the files
2776 as for C<guestfs_scrub_file>, and deletes them.
2777 The intention is to scrub any free space on the partition
2778 containing C<dir>.
2779
2780 It is an interface to the L<scrub(1)> program.  See that
2781 manual page for more details.");
2782
2783   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2784    [InitBasicFS, Always, TestRun (
2785       [["mkdir"; "/tmp"];
2786        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2787    "create a temporary directory",
2788    "\
2789 This command creates a temporary directory.  The
2790 C<template> parameter should be a full pathname for the
2791 temporary directory name with the final six characters being
2792 \"XXXXXX\".
2793
2794 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2795 the second one being suitable for Windows filesystems.
2796
2797 The name of the temporary directory that was created
2798 is returned.
2799
2800 The temporary directory is created with mode 0700
2801 and is owned by root.
2802
2803 The caller is responsible for deleting the temporary
2804 directory and its contents after use.
2805
2806 See also: L<mkdtemp(3)>");
2807
2808   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2809    [InitISOFS, Always, TestOutputInt (
2810       [["wc_l"; "/10klines"]], 10000)],
2811    "count lines in a file",
2812    "\
2813 This command counts the lines in a file, using the
2814 C<wc -l> external command.");
2815
2816   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2817    [InitISOFS, Always, TestOutputInt (
2818       [["wc_w"; "/10klines"]], 10000)],
2819    "count words in a file",
2820    "\
2821 This command counts the words in a file, using the
2822 C<wc -w> external command.");
2823
2824   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2825    [InitISOFS, Always, TestOutputInt (
2826       [["wc_c"; "/100kallspaces"]], 102400)],
2827    "count characters in a file",
2828    "\
2829 This command counts the characters in a file, using the
2830 C<wc -c> external command.");
2831
2832   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2833    [InitISOFS, Always, TestOutputList (
2834       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2835    "return first 10 lines of a file",
2836    "\
2837 This command returns up to the first 10 lines of a file as
2838 a list of strings.");
2839
2840   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2841    [InitISOFS, Always, TestOutputList (
2842       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2843     InitISOFS, Always, TestOutputList (
2844       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2845     InitISOFS, Always, TestOutputList (
2846       [["head_n"; "0"; "/10klines"]], [])],
2847    "return first N lines of a file",
2848    "\
2849 If the parameter C<nrlines> is a positive number, this returns the first
2850 C<nrlines> lines of the file C<path>.
2851
2852 If the parameter C<nrlines> is a negative number, this returns lines
2853 from the file C<path>, excluding the last C<nrlines> lines.
2854
2855 If the parameter C<nrlines> is zero, this returns an empty list.");
2856
2857   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2858    [InitISOFS, Always, TestOutputList (
2859       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2860    "return last 10 lines of a file",
2861    "\
2862 This command returns up to the last 10 lines of a file as
2863 a list of strings.");
2864
2865   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2866    [InitISOFS, Always, TestOutputList (
2867       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2868     InitISOFS, Always, TestOutputList (
2869       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2870     InitISOFS, Always, TestOutputList (
2871       [["tail_n"; "0"; "/10klines"]], [])],
2872    "return last N lines of a file",
2873    "\
2874 If the parameter C<nrlines> is a positive number, this returns the last
2875 C<nrlines> lines of the file C<path>.
2876
2877 If the parameter C<nrlines> is a negative number, this returns lines
2878 from the file C<path>, starting with the C<-nrlines>th line.
2879
2880 If the parameter C<nrlines> is zero, this returns an empty list.");
2881
2882   ("df", (RString "output", []), 125, [],
2883    [], (* XXX Tricky to test because it depends on the exact format
2884         * of the 'df' command and other imponderables.
2885         *)
2886    "report file system disk space usage",
2887    "\
2888 This command runs the C<df> command to report disk space used.
2889
2890 This command is mostly useful for interactive sessions.  It
2891 is I<not> intended that you try to parse the output string.
2892 Use C<statvfs> from programs.");
2893
2894   ("df_h", (RString "output", []), 126, [],
2895    [], (* XXX Tricky to test because it depends on the exact format
2896         * of the 'df' command and other imponderables.
2897         *)
2898    "report file system disk space usage (human readable)",
2899    "\
2900 This command runs the C<df -h> command to report disk space used
2901 in human-readable format.
2902
2903 This command is mostly useful for interactive sessions.  It
2904 is I<not> intended that you try to parse the output string.
2905 Use C<statvfs> from programs.");
2906
2907   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2908    [InitISOFS, Always, TestOutputInt (
2909       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2910    "estimate file space usage",
2911    "\
2912 This command runs the C<du -s> command to estimate file space
2913 usage for C<path>.
2914
2915 C<path> can be a file or a directory.  If C<path> is a directory
2916 then the estimate includes the contents of the directory and all
2917 subdirectories (recursively).
2918
2919 The result is the estimated size in I<kilobytes>
2920 (ie. units of 1024 bytes).");
2921
2922   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2923    [InitISOFS, Always, TestOutputList (
2924       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2925    "list files in an initrd",
2926    "\
2927 This command lists out files contained in an initrd.
2928
2929 The files are listed without any initial C</> character.  The
2930 files are listed in the order they appear (not necessarily
2931 alphabetical).  Directory names are listed as separate items.
2932
2933 Old Linux kernels (2.4 and earlier) used a compressed ext2
2934 filesystem as initrd.  We I<only> support the newer initramfs
2935 format (compressed cpio files).");
2936
2937   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2938    [],
2939    "mount a file using the loop device",
2940    "\
2941 This command lets you mount C<file> (a filesystem image
2942 in a file) on a mount point.  It is entirely equivalent to
2943 the command C<mount -o loop file mountpoint>.");
2944
2945   ("mkswap", (RErr, [Device "device"]), 130, [],
2946    [InitEmpty, Always, TestRun (
2947       [["part_disk"; "/dev/sda"; "mbr"];
2948        ["mkswap"; "/dev/sda1"]])],
2949    "create a swap partition",
2950    "\
2951 Create a swap partition on C<device>.");
2952
2953   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2954    [InitEmpty, Always, TestRun (
2955       [["part_disk"; "/dev/sda"; "mbr"];
2956        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2957    "create a swap partition with a label",
2958    "\
2959 Create a swap partition on C<device> with label C<label>.
2960
2961 Note that you cannot attach a swap label to a block device
2962 (eg. C</dev/sda>), just to a partition.  This appears to be
2963 a limitation of the kernel or swap tools.");
2964
2965   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
2966    (let uuid = uuidgen () in
2967     [InitEmpty, Always, TestRun (
2968        [["part_disk"; "/dev/sda"; "mbr"];
2969         ["mkswap_U"; uuid; "/dev/sda1"]])]),
2970    "create a swap partition with an explicit UUID",
2971    "\
2972 Create a swap partition on C<device> with UUID C<uuid>.");
2973
2974   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
2975    [InitBasicFS, Always, TestOutputStruct (
2976       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2977        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2978        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2979     InitBasicFS, Always, TestOutputStruct (
2980       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2981        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2982    "make block, character or FIFO devices",
2983    "\
2984 This call creates block or character special devices, or
2985 named pipes (FIFOs).
2986
2987 The C<mode> parameter should be the mode, using the standard
2988 constants.  C<devmajor> and C<devminor> are the
2989 device major and minor numbers, only used when creating block
2990 and character special devices.
2991
2992 The mode actually set is affected by the umask.");
2993
2994   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
2995    [InitBasicFS, Always, TestOutputStruct (
2996       [["mkfifo"; "0o777"; "/node"];
2997        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2998    "make FIFO (named pipe)",
2999    "\
3000 This call creates a FIFO (named pipe) called C<path> with
3001 mode C<mode>.  It is just a convenient wrapper around
3002 C<guestfs_mknod>.
3003
3004 The mode actually set is affected by the umask.");
3005
3006   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
3007    [InitBasicFS, Always, TestOutputStruct (
3008       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
3009        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3010    "make block device node",
3011    "\
3012 This call creates a block device node called C<path> with
3013 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3014 It is just a convenient wrapper around C<guestfs_mknod>.
3015
3016 The mode actually set is affected by the umask.");
3017
3018   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
3019    [InitBasicFS, Always, TestOutputStruct (
3020       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
3021        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
3022    "make char device node",
3023    "\
3024 This call creates a char device node called C<path> with
3025 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3026 It is just a convenient wrapper around C<guestfs_mknod>.
3027
3028 The mode actually set is affected by the umask.");
3029
3030   ("umask", (RInt "oldmask", [Int "mask"]), 137, [FishOutput FishOutputOctal],
3031    [InitEmpty, Always, TestOutputInt (
3032       [["umask"; "0o22"]], 0o22)],
3033    "set file mode creation mask (umask)",
3034    "\
3035 This function sets the mask used for creating new files and
3036 device nodes to C<mask & 0777>.
3037
3038 Typical umask values would be C<022> which creates new files
3039 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
3040 C<002> which creates new files with permissions like
3041 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
3042
3043 The default umask is C<022>.  This is important because it
3044 means that directories and device nodes will be created with
3045 C<0644> or C<0755> mode even if you specify C<0777>.
3046
3047 See also C<guestfs_get_umask>,
3048 L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
3049
3050 This call returns the previous umask.");
3051
3052   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
3053    [],
3054    "read directories entries",
3055    "\
3056 This returns the list of directory entries in directory C<dir>.
3057
3058 All entries in the directory are returned, including C<.> and
3059 C<..>.  The entries are I<not> sorted, but returned in the same
3060 order as the underlying filesystem.
3061
3062 Also this call returns basic file type information about each
3063 file.  The C<ftyp> field will contain one of the following characters:
3064
3065 =over 4
3066
3067 =item 'b'
3068
3069 Block special
3070
3071 =item 'c'
3072
3073 Char special
3074
3075 =item 'd'
3076
3077 Directory
3078
3079 =item 'f'
3080
3081 FIFO (named pipe)
3082
3083 =item 'l'
3084
3085 Symbolic link
3086
3087 =item 'r'
3088
3089 Regular file
3090
3091 =item 's'
3092
3093 Socket
3094
3095 =item 'u'
3096
3097 Unknown file type
3098
3099 =item '?'
3100
3101 The L<readdir(3)> returned a C<d_type> field with an
3102 unexpected value
3103
3104 =back
3105
3106 This function is primarily intended for use by programs.  To
3107 get a simple list of names, use C<guestfs_ls>.  To get a printable
3108 directory for human consumption, use C<guestfs_ll>.");
3109
3110   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3111    [],
3112    "create partitions on a block device",
3113    "\
3114 This is a simplified interface to the C<guestfs_sfdisk>
3115 command, where partition sizes are specified in megabytes
3116 only (rounded to the nearest cylinder) and you don't need
3117 to specify the cyls, heads and sectors parameters which
3118 were rarely if ever used anyway.
3119
3120 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3121 and C<guestfs_part_disk>");
3122
3123   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3124    [],
3125    "determine file type inside a compressed file",
3126    "\
3127 This command runs C<file> after first decompressing C<path>
3128 using C<method>.
3129
3130 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3131
3132 Since 1.0.63, use C<guestfs_file> instead which can now
3133 process compressed files.");
3134
3135   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3136    [],
3137    "list extended attributes of a file or directory",
3138    "\
3139 This call lists the extended attributes of the file or directory
3140 C<path>.
3141
3142 At the system call level, this is a combination of the
3143 L<listxattr(2)> and L<getxattr(2)> calls.
3144
3145 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3146
3147   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3148    [],
3149    "list extended attributes of a file or directory",
3150    "\
3151 This is the same as C<guestfs_getxattrs>, but if C<path>
3152 is a symbolic link, then it returns the extended attributes
3153 of the link itself.");
3154
3155   ("setxattr", (RErr, [String "xattr";
3156                        String "val"; Int "vallen"; (* will be BufferIn *)
3157                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3158    [],
3159    "set extended attribute of a file or directory",
3160    "\
3161 This call sets the extended attribute named C<xattr>
3162 of the file C<path> to the value C<val> (of length C<vallen>).
3163 The value is arbitrary 8 bit data.
3164
3165 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3166
3167   ("lsetxattr", (RErr, [String "xattr";
3168                         String "val"; Int "vallen"; (* will be BufferIn *)
3169                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3170    [],
3171    "set extended attribute of a file or directory",
3172    "\
3173 This is the same as C<guestfs_setxattr>, but if C<path>
3174 is a symbolic link, then it sets an extended attribute
3175 of the link itself.");
3176
3177   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3178    [],
3179    "remove extended attribute of a file or directory",
3180    "\
3181 This call removes the extended attribute named C<xattr>
3182 of the file C<path>.
3183
3184 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3185
3186   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3187    [],
3188    "remove extended attribute of a file or directory",
3189    "\
3190 This is the same as C<guestfs_removexattr>, but if C<path>
3191 is a symbolic link, then it removes an extended attribute
3192 of the link itself.");
3193
3194   ("mountpoints", (RHashtable "mps", []), 147, [],
3195    [],
3196    "show mountpoints",
3197    "\
3198 This call is similar to C<guestfs_mounts>.  That call returns
3199 a list of devices.  This one returns a hash table (map) of
3200 device name to directory where the device is mounted.");
3201
3202   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3203    (* This is a special case: while you would expect a parameter
3204     * of type "Pathname", that doesn't work, because it implies
3205     * NEED_ROOT in the generated calling code in stubs.c, and
3206     * this function cannot use NEED_ROOT.
3207     *)
3208    [],
3209    "create a mountpoint",
3210    "\
3211 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3212 specialized calls that can be used to create extra mountpoints
3213 before mounting the first filesystem.
3214
3215 These calls are I<only> necessary in some very limited circumstances,
3216 mainly the case where you want to mount a mix of unrelated and/or
3217 read-only filesystems together.
3218
3219 For example, live CDs often contain a \"Russian doll\" nest of
3220 filesystems, an ISO outer layer, with a squashfs image inside, with
3221 an ext2/3 image inside that.  You can unpack this as follows
3222 in guestfish:
3223
3224  add-ro Fedora-11-i686-Live.iso
3225  run
3226  mkmountpoint /cd
3227  mkmountpoint /squash
3228  mkmountpoint /ext3
3229  mount /dev/sda /cd
3230  mount-loop /cd/LiveOS/squashfs.img /squash
3231  mount-loop /squash/LiveOS/ext3fs.img /ext3
3232
3233 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3234
3235   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3236    [],
3237    "remove a mountpoint",
3238    "\
3239 This calls removes a mountpoint that was previously created
3240 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3241 for full details.");
3242
3243   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3244    [InitISOFS, Always, TestOutputBuffer (
3245       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3246    "read a file",
3247    "\
3248 This calls returns the contents of the file C<path> as a
3249 buffer.
3250
3251 Unlike C<guestfs_cat>, this function can correctly
3252 handle files that contain embedded ASCII NUL characters.
3253 However unlike C<guestfs_download>, this function is limited
3254 in the total size of file that can be handled.");
3255
3256   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3257    [InitISOFS, Always, TestOutputList (
3258       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3259     InitISOFS, Always, TestOutputList (
3260       [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3261    "return lines matching a pattern",
3262    "\
3263 This calls the external C<grep> program and returns the
3264 matching lines.");
3265
3266   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3267    [InitISOFS, Always, TestOutputList (
3268       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3269    "return lines matching a pattern",
3270    "\
3271 This calls the external C<egrep> program and returns the
3272 matching lines.");
3273
3274   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3275    [InitISOFS, Always, TestOutputList (
3276       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3277    "return lines matching a pattern",
3278    "\
3279 This calls the external C<fgrep> program and returns the
3280 matching lines.");
3281
3282   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3283    [InitISOFS, Always, TestOutputList (
3284       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3285    "return lines matching a pattern",
3286    "\
3287 This calls the external C<grep -i> program and returns the
3288 matching lines.");
3289
3290   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3291    [InitISOFS, Always, TestOutputList (
3292       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3293    "return lines matching a pattern",
3294    "\
3295 This calls the external C<egrep -i> program and returns the
3296 matching lines.");
3297
3298   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3299    [InitISOFS, Always, TestOutputList (
3300       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3301    "return lines matching a pattern",
3302    "\
3303 This calls the external C<fgrep -i> program and returns the
3304 matching lines.");
3305
3306   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3307    [InitISOFS, Always, TestOutputList (
3308       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3309    "return lines matching a pattern",
3310    "\
3311 This calls the external C<zgrep> program and returns the
3312 matching lines.");
3313
3314   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3315    [InitISOFS, Always, TestOutputList (
3316       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3317    "return lines matching a pattern",
3318    "\
3319 This calls the external C<zegrep> program and returns the
3320 matching lines.");
3321
3322   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3323    [InitISOFS, Always, TestOutputList (
3324       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3325    "return lines matching a pattern",
3326    "\
3327 This calls the external C<zfgrep> program and returns the
3328 matching lines.");
3329
3330   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3331    [InitISOFS, Always, TestOutputList (
3332       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3333    "return lines matching a pattern",
3334    "\
3335 This calls the external C<zgrep -i> program and returns the
3336 matching lines.");
3337
3338   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3339    [InitISOFS, Always, TestOutputList (
3340       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3341    "return lines matching a pattern",
3342    "\
3343 This calls the external C<zegrep -i> program and returns the
3344 matching lines.");
3345
3346   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3347    [InitISOFS, Always, TestOutputList (
3348       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3349    "return lines matching a pattern",
3350    "\
3351 This calls the external C<zfgrep -i> program and returns the
3352 matching lines.");
3353
3354   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3355    [InitISOFS, Always, TestOutput (
3356       [["realpath"; "/../directory"]], "/directory")],
3357    "canonicalized absolute pathname",
3358    "\
3359 Return the canonicalized absolute pathname of C<path>.  The
3360 returned path has no C<.>, C<..> or symbolic link path elements.");
3361
3362   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3363    [InitBasicFS, Always, TestOutputStruct (
3364       [["touch"; "/a"];
3365        ["ln"; "/a"; "/b"];
3366        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3367    "create a hard link",
3368    "\
3369 This command creates a hard link using the C<ln> command.");
3370
3371   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3372    [InitBasicFS, Always, TestOutputStruct (
3373       [["touch"; "/a"];
3374        ["touch"; "/b"];
3375        ["ln_f"; "/a"; "/b"];
3376        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3377    "create a hard link",
3378    "\
3379 This command creates a hard link using the C<ln -f> command.
3380 The C<-f> option removes the link (C<linkname>) if it exists already.");
3381
3382   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3383    [InitBasicFS, Always, TestOutputStruct (
3384       [["touch"; "/a"];
3385        ["ln_s"; "a"; "/b"];
3386        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3387    "create a symbolic link",
3388    "\
3389 This command creates a symbolic link using the C<ln -s> command.");
3390
3391   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3392    [InitBasicFS, Always, TestOutput (
3393       [["mkdir_p"; "/a/b"];
3394        ["touch"; "/a/b/c"];
3395        ["ln_sf"; "../d"; "/a/b/c"];
3396        ["readlink"; "/a/b/c"]], "../d")],
3397    "create a symbolic link",
3398    "\
3399 This command creates a symbolic link using the C<ln -sf> command,
3400 The C<-f> option removes the link (C<linkname>) if it exists already.");
3401
3402   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3403    [] (* XXX tested above *),
3404    "read the target of a symbolic link",
3405    "\
3406 This command reads the target of a symbolic link.");
3407
3408   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3409    [InitBasicFS, Always, TestOutputStruct (
3410       [["fallocate"; "/a"; "1000000"];
3411        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3412    "preallocate a file in the guest filesystem",
3413    "\
3414 This command preallocates a file (containing zero bytes) named
3415 C<path> of size C<len> bytes.  If the file exists already, it
3416 is overwritten.
3417
3418 Do not confuse this with the guestfish-specific
3419 C<alloc> command which allocates a file in the host and
3420 attaches it as a device.");
3421
3422   ("swapon_device", (RErr, [Device "device"]), 170, [],
3423    [InitPartition, Always, TestRun (
3424       [["mkswap"; "/dev/sda1"];
3425        ["swapon_device"; "/dev/sda1"];
3426        ["swapoff_device"; "/dev/sda1"]])],
3427    "enable swap on device",
3428    "\
3429 This command enables the libguestfs appliance to use the
3430 swap device or partition named C<device>.  The increased
3431 memory is made available for all commands, for example
3432 those run using C<guestfs_command> or C<guestfs_sh>.
3433
3434 Note that you should not swap to existing guest swap
3435 partitions unless you know what you are doing.  They may
3436 contain hibernation information, or other information that
3437 the guest doesn't want you to trash.  You also risk leaking
3438 information about the host to the guest this way.  Instead,
3439 attach a new host device to the guest and swap on that.");
3440
3441   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3442    [], (* XXX tested by swapon_device *)
3443    "disable swap on device",
3444    "\
3445 This command disables the libguestfs appliance swap
3446 device or partition named C<device>.
3447 See C<guestfs_swapon_device>.");
3448
3449   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3450    [InitBasicFS, Always, TestRun (
3451       [["fallocate"; "/swap"; "8388608"];
3452        ["mkswap_file"; "/swap"];
3453        ["swapon_file"; "/swap"];
3454        ["swapoff_file"; "/swap"]])],
3455    "enable swap on file",
3456    "\
3457 This command enables swap to a file.
3458 See C<guestfs_swapon_device> for other notes.");
3459
3460   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3461    [], (* XXX tested by swapon_file *)
3462    "disable swap on file",
3463    "\
3464 This command disables the libguestfs appliance swap on file.");
3465
3466   ("swapon_label", (RErr, [String "label"]), 174, [],
3467    [InitEmpty, Always, TestRun (
3468       [["part_disk"; "/dev/sdb"; "mbr"];
3469        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3470        ["swapon_label"; "swapit"];
3471        ["swapoff_label"; "swapit"];
3472        ["zero"; "/dev/sdb"];
3473        ["blockdev_rereadpt"; "/dev/sdb"]])],
3474    "enable swap on labeled swap partition",
3475    "\
3476 This command enables swap to a labeled swap partition.
3477 See C<guestfs_swapon_device> for other notes.");
3478
3479   ("swapoff_label", (RErr, [String "label"]), 175, [],
3480    [], (* XXX tested by swapon_label *)
3481    "disable swap on labeled swap partition",
3482    "\
3483 This command disables the libguestfs appliance swap on
3484 labeled swap partition.");
3485
3486   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3487    (let uuid = uuidgen () in
3488     [InitEmpty, Always, TestRun (
3489        [["mkswap_U"; uuid; "/dev/sdb"];
3490         ["swapon_uuid"; uuid];
3491         ["swapoff_uuid"; uuid]])]),
3492    "enable swap on swap partition by UUID",
3493    "\
3494 This command enables swap to a swap partition with the given UUID.
3495 See C<guestfs_swapon_device> for other notes.");
3496
3497   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3498    [], (* XXX tested by swapon_uuid *)
3499    "disable swap on swap partition by UUID",
3500    "\
3501 This command disables the libguestfs appliance swap partition
3502 with the given UUID.");
3503
3504   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3505    [InitBasicFS, Always, TestRun (
3506       [["fallocate"; "/swap"; "8388608"];
3507        ["mkswap_file"; "/swap"]])],
3508    "create a swap file",
3509    "\
3510 Create a swap file.
3511
3512 This command just writes a swap file signature to an existing
3513 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3514
3515   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3516    [InitISOFS, Always, TestRun (
3517       [["inotify_init"; "0"]])],
3518    "create an inotify handle",
3519    "\
3520 This command creates a new inotify handle.
3521 The inotify subsystem can be used to notify events which happen to
3522 objects in the guest filesystem.
3523
3524 C<maxevents> is the maximum number of events which will be
3525 queued up between calls to C<guestfs_inotify_read> or
3526 C<guestfs_inotify_files>.
3527 If this is passed as C<0>, then the kernel (or previously set)
3528 default is used.  For Linux 2.6.29 the default was 16384 events.
3529 Beyond this limit, the kernel throws away events, but records
3530 the fact that it threw them away by setting a flag
3531 C<IN_Q_OVERFLOW> in the returned structure list (see
3532 C<guestfs_inotify_read>).
3533
3534 Before any events are generated, you have to add some
3535 watches to the internal watch list.  See:
3536 C<guestfs_inotify_add_watch>,
3537 C<guestfs_inotify_rm_watch> and
3538 C<guestfs_inotify_watch_all>.
3539
3540 Queued up events should be read periodically by calling
3541 C<guestfs_inotify_read>
3542 (or C<guestfs_inotify_files> which is just a helpful
3543 wrapper around C<guestfs_inotify_read>).  If you don't
3544 read the events out often enough then you risk the internal
3545 queue overflowing.
3546
3547 The handle should be closed after use by calling
3548 C<guestfs_inotify_close>.  This also removes any
3549 watches automatically.
3550
3551 See also L<inotify(7)> for an overview of the inotify interface
3552 as exposed by the Linux kernel, which is roughly what we expose
3553 via libguestfs.  Note that there is one global inotify handle
3554 per libguestfs instance.");
3555
3556   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3557    [InitBasicFS, Always, TestOutputList (
3558       [["inotify_init"; "0"];
3559        ["inotify_add_watch"; "/"; "1073741823"];
3560        ["touch"; "/a"];
3561        ["touch"; "/b"];
3562        ["inotify_files"]], ["a"; "b"])],
3563    "add an inotify watch",
3564    "\
3565 Watch C<path> for the events listed in C<mask>.
3566
3567 Note that if C<path> is a directory then events within that
3568 directory are watched, but this does I<not> happen recursively
3569 (in subdirectories).
3570
3571 Note for non-C or non-Linux callers: the inotify events are
3572 defined by the Linux kernel ABI and are listed in
3573 C</usr/include/sys/inotify.h>.");
3574
3575   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3576    [],
3577    "remove an inotify watch",
3578    "\
3579 Remove a previously defined inotify watch.
3580 See C<guestfs_inotify_add_watch>.");
3581
3582   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3583    [],
3584    "return list of inotify events",
3585    "\
3586 Return the complete queue of events that have happened
3587 since the previous read call.
3588
3589 If no events have happened, this returns an empty list.
3590
3591 I<Note>: In order to make sure that all events have been
3592 read, you must call this function repeatedly until it
3593 returns an empty list.  The reason is that the call will
3594 read events up to the maximum appliance-to-host message
3595 size and leave remaining events in the queue.");
3596
3597   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3598    [],
3599    "return list of watched files that had events",
3600    "\
3601 This function is a helpful wrapper around C<guestfs_inotify_read>
3602 which just returns a list of pathnames of objects that were
3603 touched.  The returned pathnames are sorted and deduplicated.");
3604
3605   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3606    [],
3607    "close the inotify handle",
3608    "\
3609 This closes the inotify handle which was previously
3610 opened by inotify_init.  It removes all watches, throws
3611 away any pending events, and deallocates all resources.");
3612
3613   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3614    [],
3615    "set SELinux security context",
3616    "\
3617 This sets the SELinux security context of the daemon
3618 to the string C<context>.
3619
3620 See the documentation about SELINUX in L<guestfs(3)>.");
3621
3622   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3623    [],
3624    "get SELinux security context",
3625    "\
3626 This gets the SELinux security context of the daemon.
3627
3628 See the documentation about SELINUX in L<guestfs(3)>,
3629 and C<guestfs_setcon>");
3630
3631   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3632    [InitEmpty, Always, TestOutput (
3633       [["part_disk"; "/dev/sda"; "mbr"];
3634        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3635        ["mount_options"; ""; "/dev/sda1"; "/"];
3636        ["write_file"; "/new"; "new file contents"; "0"];
3637        ["cat"; "/new"]], "new file contents")],
3638    "make a filesystem with block size",
3639    "\
3640 This call is similar to C<guestfs_mkfs>, but it allows you to
3641 control the block size of the resulting filesystem.  Supported
3642 block sizes depend on the filesystem type, but typically they
3643 are C<1024>, C<2048> or C<4096> only.");
3644
3645   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3646    [InitEmpty, Always, TestOutput (
3647       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3648        ["mke2journal"; "4096"; "/dev/sda1"];
3649        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3650        ["mount_options"; ""; "/dev/sda2"; "/"];
3651        ["write_file"; "/new"; "new file contents"; "0"];
3652        ["cat"; "/new"]], "new file contents")],
3653    "make ext2/3/4 external journal",
3654    "\
3655 This creates an ext2 external journal on C<device>.  It is equivalent
3656 to the command:
3657
3658  mke2fs -O journal_dev -b blocksize device");
3659
3660   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3661    [InitEmpty, Always, TestOutput (
3662       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3663        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3664        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3665        ["mount_options"; ""; "/dev/sda2"; "/"];
3666        ["write_file"; "/new"; "new file contents"; "0"];
3667        ["cat"; "/new"]], "new file contents")],
3668    "make ext2/3/4 external journal with label",
3669    "\
3670 This creates an ext2 external journal on C<device> with label C<label>.");
3671
3672   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3673    (let uuid = uuidgen () in
3674     [InitEmpty, Always, TestOutput (
3675        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3676         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3677         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3678         ["mount_options"; ""; "/dev/sda2"; "/"];
3679         ["write_file"; "/new"; "new file contents"; "0"];
3680         ["cat"; "/new"]], "new file contents")]),
3681    "make ext2/3/4 external journal with UUID",
3682    "\
3683 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3684
3685   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3686    [],
3687    "make ext2/3/4 filesystem with external journal",
3688    "\
3689 This creates an ext2/3/4 filesystem on C<device> with
3690 an external journal on C<journal>.  It is equivalent
3691 to the command:
3692
3693  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3694
3695 See also C<guestfs_mke2journal>.");
3696
3697   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3698    [],
3699    "make ext2/3/4 filesystem with external journal",
3700    "\
3701 This creates an ext2/3/4 filesystem on C<device> with
3702 an external journal on the journal labeled C<label>.
3703
3704 See also C<guestfs_mke2journal_L>.");
3705
3706   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3707    [],
3708    "make ext2/3/4 filesystem with external journal",
3709    "\
3710 This creates an ext2/3/4 filesystem on C<device> with
3711 an external journal on the journal with UUID C<uuid>.
3712
3713 See also C<guestfs_mke2journal_U>.");
3714
3715   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3716    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3717    "load a kernel module",
3718    "\
3719 This loads a kernel module in the appliance.
3720
3721 The kernel module must have been whitelisted when libguestfs
3722 was built (see C<appliance/kmod.whitelist.in> in the source).");
3723
3724   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3725    [InitNone, Always, TestOutput (
3726       [["echo_daemon"; "This is a test"]], "This is a test"
3727     )],
3728    "echo arguments back to the client",
3729    "\
3730 This command concatenate the list of C<words> passed with single spaces between
3731 them and returns the resulting string.
3732
3733 You can use this command to test the connection through to the daemon.
3734
3735 See also C<guestfs_ping_daemon>.");
3736
3737   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3738    [], (* There is a regression test for this. *)
3739    "find all files and directories, returning NUL-separated list",
3740    "\
3741 This command lists out all files and directories, recursively,
3742 starting at C<directory>, placing the resulting list in the
3743 external file called C<files>.
3744
3745 This command works the same way as C<guestfs_find> with the
3746 following exceptions:
3747
3748 =over 4
3749
3750 =item *
3751
3752 The resulting list is written to an external file.
3753
3754 =item *
3755
3756 Items (filenames) in the result are separated
3757 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3758
3759 =item *
3760
3761 This command is not limited in the number of names that it
3762 can return.
3763
3764 =item *
3765
3766 The result list is not sorted.
3767
3768 =back");
3769
3770   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3771    [InitISOFS, Always, TestOutput (
3772       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3773     InitISOFS, Always, TestOutput (
3774       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3775     InitISOFS, Always, TestOutput (
3776       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3777     InitISOFS, Always, TestLastFail (
3778       [["case_sensitive_path"; "/Known-1/"]]);
3779     InitBasicFS, Always, TestOutput (
3780       [["mkdir"; "/a"];
3781        ["mkdir"; "/a/bbb"];
3782        ["touch"; "/a/bbb/c"];
3783        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3784     InitBasicFS, Always, TestOutput (
3785       [["mkdir"; "/a"];
3786        ["mkdir"; "/a/bbb"];
3787        ["touch"; "/a/bbb/c"];
3788        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3789     InitBasicFS, Always, TestLastFail (
3790       [["mkdir"; "/a"];
3791        ["mkdir"; "/a/bbb"];
3792        ["touch"; "/a/bbb/c"];
3793        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3794    "return true path on case-insensitive filesystem",
3795    "\
3796 This can be used to resolve case insensitive paths on
3797 a filesystem which is case sensitive.  The use case is
3798 to resolve paths which you have read from Windows configuration
3799 files or the Windows Registry, to the true path.
3800
3801 The command handles a peculiarity of the Linux ntfs-3g
3802 filesystem driver (and probably others), which is that although
3803 the underlying filesystem is case-insensitive, the driver
3804 exports the filesystem to Linux as case-sensitive.
3805
3806 One consequence of this is that special directories such
3807 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3808 (or other things) depending on the precise details of how
3809 they were created.  In Windows itself this would not be
3810 a problem.
3811
3812 Bug or feature?  You decide:
3813 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3814
3815 This function resolves the true case of each element in the
3816 path and returns the case-sensitive path.
3817
3818 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3819 might return C<\"/WINDOWS/system32\"> (the exact return value
3820 would depend on details of how the directories were originally
3821 created under Windows).
3822
3823 I<Note>:
3824 This function does not handle drive names, backslashes etc.
3825
3826 See also C<guestfs_realpath>.");
3827
3828   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3829    [InitBasicFS, Always, TestOutput (
3830       [["vfs_type"; "/dev/sda1"]], "ext2")],
3831    "get the Linux VFS type corresponding to a mounted device",
3832    "\
3833 This command gets the block device type corresponding to
3834 a mounted device called C<device>.
3835
3836 Usually the result is the name of the Linux VFS module that
3837 is used to mount this device (probably determined automatically
3838 if you used the C<guestfs_mount> call).");
3839
3840   ("truncate", (RErr, [Pathname "path"]), 199, [],
3841    [InitBasicFS, Always, TestOutputStruct (
3842       [["write_file"; "/test"; "some stuff so size is not zero"; "0"];
3843        ["truncate"; "/test"];
3844        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3845    "truncate a file to zero size",
3846    "\
3847 This command truncates C<path> to a zero-length file.  The
3848 file must exist already.");
3849
3850   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3851    [InitBasicFS, Always, TestOutputStruct (
3852       [["touch"; "/test"];
3853        ["truncate_size"; "/test"; "1000"];
3854        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3855    "truncate a file to a particular size",
3856    "\
3857 This command truncates C<path> to size C<size> bytes.  The file
3858 must exist already.  If the file is smaller than C<size> then
3859 the file is extended to the required size with null bytes.");
3860
3861   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3862    [InitBasicFS, Always, TestOutputStruct (
3863       [["touch"; "/test"];
3864        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3865        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3866    "set timestamp of a file with nanosecond precision",
3867    "\
3868 This command sets the timestamps of a file with nanosecond
3869 precision.
3870
3871 C<atsecs, atnsecs> are the last access time (atime) in secs and
3872 nanoseconds from the epoch.
3873
3874 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3875 secs and nanoseconds from the epoch.
3876
3877 If the C<*nsecs> field contains the special value C<-1> then
3878 the corresponding timestamp is set to the current time.  (The
3879 C<*secs> field is ignored in this case).
3880
3881 If the C<*nsecs> field contains the special value C<-2> then
3882 the corresponding timestamp is left unchanged.  (The
3883 C<*secs> field is ignored in this case).");
3884
3885   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3886    [InitBasicFS, Always, TestOutputStruct (
3887       [["mkdir_mode"; "/test"; "0o111"];
3888        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3889    "create a directory with a particular mode",
3890    "\
3891 This command creates a directory, setting the initial permissions
3892 of the directory to C<mode>.
3893
3894 For common Linux filesystems, the actual mode which is set will
3895 be C<mode & ~umask & 01777>.  Non-native-Linux filesystems may
3896 interpret the mode in other ways.
3897
3898 See also C<guestfs_mkdir>, C<guestfs_umask>");
3899
3900   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
3901    [], (* XXX *)
3902    "change file owner and group",
3903    "\
3904 Change the file owner to C<owner> and group to C<group>.
3905 This is like C<guestfs_chown> but if C<path> is a symlink then
3906 the link itself is changed, not the target.
3907
3908 Only numeric uid and gid are supported.  If you want to use
3909 names, you will need to locate and parse the password file
3910 yourself (Augeas support makes this relatively easy).");
3911
3912   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
3913    [], (* XXX *)
3914    "lstat on multiple files",
3915    "\
3916 This call allows you to perform the C<guestfs_lstat> operation
3917 on multiple files, where all files are in the directory C<path>.
3918 C<names> is the list of files from this directory.
3919
3920 On return you get a list of stat structs, with a one-to-one
3921 correspondence to the C<names> list.  If any name did not exist
3922 or could not be lstat'd, then the C<ino> field of that structure
3923 is set to C<-1>.
3924
3925 This call is intended for programs that want to efficiently
3926 list a directory contents without making many round-trips.
3927 See also C<guestfs_lxattrlist> for a similarly efficient call
3928 for getting extended attributes.  Very long directory listings
3929 might cause the protocol message size to be exceeded, causing
3930 this call to fail.  The caller must split up such requests
3931 into smaller groups of names.");
3932
3933   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
3934    [], (* XXX *)
3935    "lgetxattr on multiple files",
3936    "\
3937 This call allows you to get the extended attributes
3938 of multiple files, where all files are in the directory C<path>.
3939 C<names> is the list of files from this directory.
3940
3941 On return you get a flat list of xattr structs which must be
3942 interpreted sequentially.  The first xattr struct always has a zero-length
3943 C<attrname>.  C<attrval> in this struct is zero-length
3944 to indicate there was an error doing C<lgetxattr> for this
3945 file, I<or> is a C string which is a decimal number
3946 (the number of following attributes for this file, which could
3947 be C<\"0\">).  Then after the first xattr struct are the
3948 zero or more attributes for the first named file.
3949 This repeats for the second and subsequent files.
3950
3951 This call is intended for programs that want to efficiently
3952 list a directory contents without making many round-trips.
3953 See also C<guestfs_lstatlist> for a similarly efficient call
3954 for getting standard stats.  Very long directory listings
3955 might cause the protocol message size to be exceeded, causing
3956 this call to fail.  The caller must split up such requests
3957 into smaller groups of names.");
3958
3959   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
3960    [], (* XXX *)
3961    "readlink on multiple files",
3962    "\
3963 This call allows you to do a C<readlink> operation
3964 on multiple files, where all files are in the directory C<path>.
3965 C<names> is the list of files from this directory.
3966
3967 On return you get a list of strings, with a one-to-one
3968 correspondence to the C<names> list.  Each string is the
3969 value of the symbol link.
3970
3971 If the C<readlink(2)> operation fails on any name, then
3972 the corresponding result string is the empty string C<\"\">.
3973 However the whole operation is completed even if there
3974 were C<readlink(2)> errors, and so you can call this
3975 function with names where you don't know if they are
3976 symbolic links already (albeit slightly less efficient).
3977
3978 This call is intended for programs that want to efficiently
3979 list a directory contents without making many round-trips.
3980 Very long directory listings might cause the protocol
3981 message size to be exceeded, causing
3982 this call to fail.  The caller must split up such requests
3983 into smaller groups of names.");
3984
3985   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
3986    [InitISOFS, Always, TestOutputBuffer (
3987       [["pread"; "/known-4"; "1"; "3"]], "\n");
3988     InitISOFS, Always, TestOutputBuffer (
3989       [["pread"; "/empty"; "0"; "100"]], "")],
3990    "read part of a file",
3991    "\
3992 This command lets you read part of a file.  It reads C<count>
3993 bytes of the file, starting at C<offset>, from file C<path>.
3994
3995 This may read fewer bytes than requested.  For further details
3996 see the L<pread(2)> system call.");
3997
3998   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
3999    [InitEmpty, Always, TestRun (
4000       [["part_init"; "/dev/sda"; "gpt"]])],
4001    "create an empty partition table",
4002    "\
4003 This creates an empty partition table on C<device> of one of the
4004 partition types listed below.  Usually C<parttype> should be
4005 either C<msdos> or C<gpt> (for large disks).
4006
4007 Initially there are no partitions.  Following this, you should
4008 call C<guestfs_part_add> for each partition required.
4009
4010 Possible values for C<parttype> are:
4011
4012 =over 4
4013
4014 =item B<efi> | B<gpt>
4015
4016 Intel EFI / GPT partition table.
4017
4018 This is recommended for >= 2 TB partitions that will be accessed
4019 from Linux and Intel-based Mac OS X.  It also has limited backwards
4020 compatibility with the C<mbr> format.
4021
4022 =item B<mbr> | B<msdos>
4023
4024 The standard PC \"Master Boot Record\" (MBR) format used
4025 by MS-DOS and Windows.  This partition type will B<only> work
4026 for device sizes up to 2 TB.  For large disks we recommend
4027 using C<gpt>.
4028
4029 =back
4030
4031 Other partition table types that may work but are not
4032 supported include:
4033
4034 =over 4
4035
4036 =item B<aix>
4037
4038 AIX disk labels.
4039
4040 =item B<amiga> | B<rdb>
4041
4042 Amiga \"Rigid Disk Block\" format.
4043
4044 =item B<bsd>
4045
4046 BSD disk labels.
4047
4048 =item B<dasd>
4049
4050 DASD, used on IBM mainframes.
4051
4052 =item B<dvh>
4053
4054 MIPS/SGI volumes.
4055
4056 =item B<mac>
4057
4058 Old Mac partition format.  Modern Macs use C<gpt>.
4059
4060 =item B<pc98>
4061
4062 NEC PC-98 format, common in Japan apparently.
4063
4064 =item B<sun>
4065
4066 Sun disk labels.
4067
4068 =back");
4069
4070   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
4071    [InitEmpty, Always, TestRun (
4072       [["part_init"; "/dev/sda"; "mbr"];
4073        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
4074     InitEmpty, Always, TestRun (
4075       [["part_init"; "/dev/sda"; "gpt"];
4076        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
4077        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
4078     InitEmpty, Always, TestRun (
4079       [["part_init"; "/dev/sda"; "mbr"];
4080        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
4081        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4082        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4083        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4084    "add a partition to the device",
4085    "\
4086 This command adds a partition to C<device>.  If there is no partition
4087 table on the device, call C<guestfs_part_init> first.
4088
4089 The C<prlogex> parameter is the type of partition.  Normally you
4090 should pass C<p> or C<primary> here, but MBR partition tables also
4091 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4092 types.
4093
4094 C<startsect> and C<endsect> are the start and end of the partition
4095 in I<sectors>.  C<endsect> may be negative, which means it counts
4096 backwards from the end of the disk (C<-1> is the last sector).
4097
4098 Creating a partition which covers the whole disk is not so easy.
4099 Use C<guestfs_part_disk> to do that.");
4100
4101   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4102    [InitEmpty, Always, TestRun (
4103       [["part_disk"; "/dev/sda"; "mbr"]]);
4104     InitEmpty, Always, TestRun (
4105       [["part_disk"; "/dev/sda"; "gpt"]])],
4106    "partition whole disk with a single primary partition",
4107    "\
4108 This command is simply a combination of C<guestfs_part_init>
4109 followed by C<guestfs_part_add> to create a single primary partition
4110 covering the whole disk.
4111
4112 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4113 but other possible values are described in C<guestfs_part_init>.");
4114
4115   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4116    [InitEmpty, Always, TestRun (
4117       [["part_disk"; "/dev/sda"; "mbr"];
4118        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4119    "make a partition bootable",
4120    "\
4121 This sets the bootable flag on partition numbered C<partnum> on
4122 device C<device>.  Note that partitions are numbered from 1.
4123
4124 The bootable flag is used by some operating systems (notably
4125 Windows) to determine which partition to boot from.  It is by
4126 no means universally recognized.");
4127
4128   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4129    [InitEmpty, Always, TestRun (
4130       [["part_disk"; "/dev/sda"; "gpt"];
4131        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4132    "set partition name",
4133    "\
4134 This sets the partition name on partition numbered C<partnum> on
4135 device C<device>.  Note that partitions are numbered from 1.
4136
4137 The partition name can only be set on certain types of partition
4138 table.  This works on C<gpt> but not on C<mbr> partitions.");
4139
4140   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4141    [], (* XXX Add a regression test for this. *)
4142    "list partitions on a device",
4143    "\
4144 This command parses the partition table on C<device> and
4145 returns the list of partitions found.
4146
4147 The fields in the returned structure are:
4148
4149 =over 4
4150
4151 =item B<part_num>
4152
4153 Partition number, counting from 1.
4154
4155 =item B<part_start>
4156
4157 Start of the partition I<in bytes>.  To get sectors you have to
4158 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4159
4160 =item B<part_end>
4161
4162 End of the partition in bytes.
4163
4164 =item B<part_size>
4165
4166 Size of the partition in bytes.
4167
4168 =back");
4169
4170   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4171    [InitEmpty, Always, TestOutput (
4172       [["part_disk"; "/dev/sda"; "gpt"];
4173        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4174    "get the partition table type",
4175    "\
4176 This command examines the partition table on C<device> and
4177 returns the partition table type (format) being used.
4178
4179 Common return values include: C<msdos> (a DOS/Windows style MBR
4180 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4181 values are possible, although unusual.  See C<guestfs_part_init>
4182 for a full list.");
4183
4184   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4185    [InitBasicFS, Always, TestOutputBuffer (
4186       [["fill"; "0x63"; "10"; "/test"];
4187        ["read_file"; "/test"]], "cccccccccc")],
4188    "fill a file with octets",
4189    "\
4190 This command creates a new file called C<path>.  The initial
4191 content of the file is C<len> octets of C<c>, where C<c>
4192 must be a number in the range C<[0..255]>.
4193
4194 To fill a file with zero bytes (sparsely), it is
4195 much more efficient to use C<guestfs_truncate_size>.");
4196
4197   ("available", (RErr, [StringList "groups"]), 216, [],
4198    [InitNone, Always, TestRun [["available"; ""]]],
4199    "test availability of some parts of the API",
4200    "\
4201 This command is used to check the availability of some
4202 groups of functionality in the appliance, which not all builds of
4203 the libguestfs appliance will be able to provide.
4204
4205 The libguestfs groups, and the functions that those
4206 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4207
4208 The argument C<groups> is a list of group names, eg:
4209 C<[\"inotify\", \"augeas\"]> would check for the availability of
4210 the Linux inotify functions and Augeas (configuration file
4211 editing) functions.
4212
4213 The command returns no error if I<all> requested groups are available.
4214
4215 It fails with an error if one or more of the requested
4216 groups is unavailable in the appliance.
4217
4218 If an unknown group name is included in the
4219 list of groups then an error is always returned.
4220
4221 I<Notes:>
4222
4223 =over 4
4224
4225 =item *
4226
4227 You must call C<guestfs_launch> before calling this function.
4228
4229 The reason is because we don't know what groups are
4230 supported by the appliance/daemon until it is running and can
4231 be queried.
4232
4233 =item *
4234
4235 If a group of functions is available, this does not necessarily
4236 mean that they will work.  You still have to check for errors
4237 when calling individual API functions even if they are
4238 available.
4239
4240 =item *
4241
4242 It is usually the job of distro packagers to build
4243 complete functionality into the libguestfs appliance.
4244 Upstream libguestfs, if built from source with all
4245 requirements satisfied, will support everything.
4246
4247 =item *
4248
4249 This call was added in version C<1.0.80>.  In previous
4250 versions of libguestfs all you could do would be to speculatively
4251 execute a command to find out if the daemon implemented it.
4252 See also C<guestfs_version>.
4253
4254 =back");
4255
4256   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4257    [InitBasicFS, Always, TestOutputBuffer (
4258       [["write_file"; "/src"; "hello, world"; "0"];
4259        ["dd"; "/src"; "/dest"];
4260        ["read_file"; "/dest"]], "hello, world")],
4261    "copy from source to destination using dd",
4262    "\
4263 This command copies from one source device or file C<src>
4264 to another destination device or file C<dest>.  Normally you
4265 would use this to copy to or from a device or partition, for
4266 example to duplicate a filesystem.
4267
4268 If the destination is a device, it must be as large or larger
4269 than the source file or device, otherwise the copy will fail.
4270 This command cannot do partial copies (see C<guestfs_copy_size>).");
4271
4272   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4273    [InitBasicFS, Always, TestOutputInt (
4274       [["write_file"; "/file"; "hello, world"; "0"];
4275        ["filesize"; "/file"]], 12)],
4276    "return the size of the file in bytes",
4277    "\
4278 This command returns the size of C<file> in bytes.
4279
4280 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4281 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4282 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4283
4284   ("lvrename", (RErr, [String "logvol"; String "newlogvol"]), 219, [],
4285    [InitBasicFSonLVM, Always, TestOutputList (
4286       [["lvrename"; "/dev/VG/LV"; "/dev/VG/LV2"];
4287        ["lvs"]], ["/dev/VG/LV2"])],
4288    "rename an LVM logical volume",
4289    "\
4290 Rename a logical volume C<logvol> with the new name C<newlogvol>.");
4291
4292   ("vgrename", (RErr, [String "volgroup"; String "newvolgroup"]), 220, [],
4293    [InitBasicFSonLVM, Always, TestOutputList (
4294       [["umount"; "/"];
4295        ["vg_activate"; "false"; "VG"];
4296        ["vgrename"; "VG"; "VG2"];
4297        ["vg_activate"; "true"; "VG2"];
4298        ["mount_options"; ""; "/dev/VG2/LV"; "/"];
4299        ["vgs"]], ["VG2"])],
4300    "rename an LVM volume group",
4301    "\
4302 Rename a volume group C<volgroup> with the new name C<newvolgroup>.");
4303
4304   ("initrd_cat", (RBufferOut "content", [Pathname "initrdpath"; String "filename"]), 221, [ProtocolLimitWarning],
4305    [InitISOFS, Always, TestOutputBuffer (
4306       [["initrd_cat"; "/initrd"; "known-4"]], "abc\ndef\nghi")],
4307    "list the contents of a single file in an initrd",
4308    "\
4309 This command unpacks the file C<filename> from the initrd file
4310 called C<initrdpath>.  The filename must be given I<without> the
4311 initial C</> character.
4312
4313 For example, in guestfish you could use the following command
4314 to examine the boot script (usually called C</init>)
4315 contained in a Linux initrd or initramfs image:
4316
4317  initrd-cat /boot/initrd-<version>.img init
4318
4319 See also C<guestfs_initrd_list>.");
4320
4321   ("pvuuid", (RString "uuid", [Device "device"]), 222, [],
4322    [],
4323    "get the UUID of a physical volume",
4324    "\
4325 This command returns the UUID of the LVM PV C<device>.");
4326
4327   ("vguuid", (RString "uuid", [String "vgname"]), 223, [],
4328    [],
4329    "get the UUID of a volume group",
4330    "\
4331 This command returns the UUID of the LVM VG named C<vgname>.");
4332
4333   ("lvuuid", (RString "uuid", [Device "device"]), 224, [],
4334    [],
4335    "get the UUID of a logical volume",
4336    "\
4337 This command returns the UUID of the LVM LV C<device>.");
4338
4339   ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [],
4340    [],
4341    "get the PV UUIDs containing the volume group",
4342    "\
4343 Given a VG called C<vgname>, this returns the UUIDs of all
4344 the physical volumes that this volume group resides on.
4345
4346 You can use this along with C<guestfs_pvs> and C<guestfs_pvuuid>
4347 calls to associate physical volumes and volume groups.
4348
4349 See also C<guestfs_vglvuuids>.");
4350
4351   ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [],
4352    [],
4353    "get the LV UUIDs of all LVs in the volume group",
4354    "\
4355 Given a VG called C<vgname>, this returns the UUIDs of all
4356 the logical volumes created in this volume group.
4357
4358 You can use this along with C<guestfs_lvs> and C<guestfs_lvuuid>
4359 calls to associate logical volumes and volume groups.
4360
4361 See also C<guestfs_vgpvuuids>.");
4362
4363   ("copy_size", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"; Int64 "size"]), 227, [],
4364    [InitBasicFS, Always, TestOutputBuffer (
4365       [["write_file"; "/src"; "hello, world"; "0"];
4366        ["copy_size"; "/src"; "/dest"; "5"];
4367        ["read_file"; "/dest"]], "hello")],
4368    "copy size bytes from source to destination using dd",
4369    "\
4370 This command copies exactly C<size> bytes from one source device
4371 or file C<src> to another destination device or file C<dest>.
4372
4373 Note this will fail if the source is too short or if the destination
4374 is not large enough.");
4375
4376   ("zero_device", (RErr, [Device "device"]), 228, [DangerWillRobinson],
4377    [InitBasicFSonLVM, Always, TestRun (
4378       [["zero_device"; "/dev/VG/LV"]])],
4379    "write zeroes to an entire device",
4380    "\
4381 This command writes zeroes over the entire C<device>.  Compare
4382 with C<guestfs_zero> which just zeroes the first few blocks of
4383 a device.");
4384
4385   ("txz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 229, [],
4386    [InitBasicFS, Always, TestOutput (
4387       [["txz_in"; "../images/helloworld.tar.xz"; "/"];
4388        ["cat"; "/hello"]], "hello\n")],
4389    "unpack compressed tarball to directory",
4390    "\
4391 This command uploads and unpacks local file C<tarball> (an
4392 I<xz compressed> tar file) into C<directory>.");
4393
4394   ("txz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 230, [],
4395    [],
4396    "pack directory into compressed tarball",
4397    "\
4398 This command packs the contents of C<directory> and downloads
4399 it to local file C<tarball> (as an xz compressed tar archive).");
4400
4401   ("ntfsresize", (RErr, [Device "device"]), 231, [Optional "ntfsprogs"],
4402    [],
4403    "resize an NTFS filesystem",
4404    "\
4405 This command resizes an NTFS filesystem, expanding or
4406 shrinking it to the size of the underlying device.
4407 See also L<ntfsresize(8)>.");
4408
4409   ("vgscan", (RErr, []), 232, [],
4410    [InitEmpty, Always, TestRun (
4411       [["vgscan"]])],
4412    "rescan for LVM physical volumes, volume groups and logical volumes",
4413    "\
4414 This rescans all block devices and rebuilds the list of LVM
4415 physical volumes, volume groups and logical volumes.");
4416
4417   ("part_del", (RErr, [Device "device"; Int "partnum"]), 233, [],
4418    [InitEmpty, Always, TestRun (
4419       [["part_init"; "/dev/sda"; "mbr"];
4420        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4421        ["part_del"; "/dev/sda"; "1"]])],
4422    "delete a partition",
4423    "\
4424 This command deletes the partition numbered C<partnum> on C<device>.
4425
4426 Note that in the case of MBR partitioning, deleting an
4427 extended partition also deletes any logical partitions
4428 it contains.");
4429
4430   ("part_get_bootable", (RBool "bootable", [Device "device"; Int "partnum"]), 234, [],
4431    [InitEmpty, Always, TestOutputTrue (
4432       [["part_init"; "/dev/sda"; "mbr"];
4433        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4434        ["part_set_bootable"; "/dev/sda"; "1"; "true"];
4435        ["part_get_bootable"; "/dev/sda"; "1"]])],
4436    "return true if a partition is bootable",
4437    "\
4438 This command returns true if the partition C<partnum> on
4439 C<device> has the bootable flag set.
4440
4441 See also C<guestfs_part_set_bootable>.");
4442
4443   ("part_get_mbr_id", (RInt "idbyte", [Device "device"; Int "partnum"]), 235, [FishOutput FishOutputHexadecimal],
4444    [InitEmpty, Always, TestOutputInt (
4445       [["part_init"; "/dev/sda"; "mbr"];
4446        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4447        ["part_set_mbr_id"; "/dev/sda"; "1"; "0x7f"];
4448        ["part_get_mbr_id"; "/dev/sda"; "1"]], 0x7f)],
4449    "get the MBR type byte (ID byte) from a partition",
4450    "\
4451 Returns the MBR type byte (also known as the ID byte) from
4452 the numbered partition C<partnum>.
4453
4454 Note that only MBR (old DOS-style) partitions have type bytes.
4455 You will get undefined results for other partition table
4456 types (see C<guestfs_part_get_parttype>).");
4457
4458   ("part_set_mbr_id", (RErr, [Device "device"; Int "partnum"; Int "idbyte"]), 236, [],
4459    [], (* tested by part_get_mbr_id *)
4460    "set the MBR type byte (ID byte) of a partition",
4461    "\
4462 Sets the MBR type byte (also known as the ID byte) of
4463 the numbered partition C<partnum> to C<idbyte>.  Note
4464 that the type bytes quoted in most documentation are
4465 in fact hexadecimal numbers, but usually documented
4466 without any leading \"0x\" which might be confusing.
4467
4468 Note that only MBR (old DOS-style) partitions have type bytes.
4469 You will get undefined results for other partition table
4470 types (see C<guestfs_part_get_parttype>).");
4471
4472   ("checksum_device", (RString "checksum", [String "csumtype"; Device "device"]), 237, [],
4473    [InitISOFS, Always, TestOutput (
4474       [["checksum_device"; "md5"; "/dev/sdd"]],
4475       (Digest.to_hex (Digest.file "images/test.iso")))],
4476    "compute MD5, SHAx or CRC checksum of the contents of a device",
4477    "\
4478 This call computes the MD5, SHAx or CRC checksum of the
4479 contents of the device named C<device>.  For the types of
4480 checksums supported see the C<guestfs_checksum> command.");
4481
4482   ("lvresize_free", (RErr, [Device "lv"; Int "percent"]), 238, [Optional "lvm2"],
4483    [InitNone, Always, TestRun (
4484       [["part_disk"; "/dev/sda"; "mbr"];
4485        ["pvcreate"; "/dev/sda1"];
4486        ["vgcreate"; "VG"; "/dev/sda1"];
4487        ["lvcreate"; "LV"; "VG"; "10"];
4488        ["lvresize_free"; "/dev/VG/LV"; "100"]])],
4489    "expand an LV to fill free space",
4490    "\
4491 This expands an existing logical volume C<lv> so that it fills
4492 C<pc>% of the remaining free space in the volume group.  Commonly
4493 you would call this with pc = 100 which expands the logical volume
4494 as much as possible, using all remaining free space in the volume
4495 group.");
4496
4497   ("aug_clear", (RErr, [String "augpath"]), 239, [Optional "augeas"],
4498    [], (* XXX Augeas code needs tests. *)
4499    "clear Augeas path",
4500    "\
4501 Set the value associated with C<path> to C<NULL>.  This
4502 is the same as the L<augtool(1)> C<clear> command.");
4503
4504   ("get_umask", (RInt "mask", []), 240, [FishOutput FishOutputOctal],
4505    [InitEmpty, Always, TestOutputInt (
4506       [["get_umask"]], 0o22)],
4507    "get the current umask",
4508    "\
4509 Return the current umask.  By default the umask is C<022>
4510 unless it has been set by calling C<guestfs_umask>.");
4511
4512   ("debug_upload", (RErr, [FileIn "filename"; String "tmpname"; Int "mode"]), 241, [],
4513    [],
4514    "upload a file to the appliance (internal use only)",
4515    "\
4516 The C<guestfs_debug_upload> command uploads a file to
4517 the libguestfs appliance.
4518
4519 There is no comprehensive help for this command.  You have
4520 to look at the file C<daemon/debug.c> in the libguestfs source
4521 to find out what it is for.");
4522
4523   ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [],
4524    [InitBasicFS, Always, TestOutput (
4525       [["base64_in"; "../images/hello.b64"; "/hello"];
4526        ["cat"; "/hello"]], "hello\n")],
4527    "upload base64-encoded data to file",
4528    "\
4529 This command uploads base64-encoded data from C<base64file>
4530 to C<filename>.");
4531
4532   ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [],
4533    [],
4534    "download file and encode as base64",
4535    "\
4536 This command downloads the contents of C<filename>, writing
4537 it out to local file C<base64file> encoded as base64.");
4538
4539 ]
4540
4541 let all_functions = non_daemon_functions @ daemon_functions
4542
4543 (* In some places we want the functions to be displayed sorted
4544  * alphabetically, so this is useful:
4545  *)
4546 let all_functions_sorted =
4547   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4548                compare n1 n2) all_functions
4549
4550 (* Field types for structures. *)
4551 type field =
4552   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4553   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4554   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4555   | FUInt32
4556   | FInt32
4557   | FUInt64
4558   | FInt64
4559   | FBytes                      (* Any int measure that counts bytes. *)
4560   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4561   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4562
4563 (* Because we generate extra parsing code for LVM command line tools,
4564  * we have to pull out the LVM columns separately here.
4565  *)
4566 let lvm_pv_cols = [
4567   "pv_name", FString;
4568   "pv_uuid", FUUID;
4569   "pv_fmt", FString;
4570   "pv_size", FBytes;
4571   "dev_size", FBytes;
4572   "pv_free", FBytes;
4573   "pv_used", FBytes;
4574   "pv_attr", FString (* XXX *);
4575   "pv_pe_count", FInt64;
4576   "pv_pe_alloc_count", FInt64;
4577   "pv_tags", FString;
4578   "pe_start", FBytes;
4579   "pv_mda_count", FInt64;
4580   "pv_mda_free", FBytes;
4581   (* Not in Fedora 10:
4582      "pv_mda_size", FBytes;
4583   *)
4584 ]
4585 let lvm_vg_cols = [
4586   "vg_name", FString;
4587   "vg_uuid", FUUID;
4588   "vg_fmt", FString;
4589   "vg_attr", FString (* XXX *);
4590   "vg_size", FBytes;
4591   "vg_free", FBytes;
4592   "vg_sysid", FString;
4593   "vg_extent_size", FBytes;
4594   "vg_extent_count", FInt64;
4595   "vg_free_count", FInt64;
4596   "max_lv", FInt64;
4597   "max_pv", FInt64;
4598   "pv_count", FInt64;
4599   "lv_count", FInt64;
4600   "snap_count", FInt64;
4601   "vg_seqno", FInt64;
4602   "vg_tags", FString;
4603   "vg_mda_count", FInt64;
4604   "vg_mda_free", FBytes;
4605   (* Not in Fedora 10:
4606      "vg_mda_size", FBytes;
4607   *)
4608 ]
4609 let lvm_lv_cols = [
4610   "lv_name", FString;
4611   "lv_uuid", FUUID;
4612   "lv_attr", FString (* XXX *);
4613   "lv_major", FInt64;
4614   "lv_minor", FInt64;
4615   "lv_kernel_major", FInt64;
4616   "lv_kernel_minor", FInt64;
4617   "lv_size", FBytes;
4618   "seg_count", FInt64;
4619   "origin", FString;
4620   "snap_percent", FOptPercent;
4621   "copy_percent", FOptPercent;
4622   "move_pv", FString;
4623   "lv_tags", FString;
4624   "mirror_log", FString;
4625   "modules", FString;
4626 ]
4627
4628 (* Names and fields in all structures (in RStruct and RStructList)
4629  * that we support.
4630  *)
4631 let structs = [
4632   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4633    * not use this struct in any new code.
4634    *)
4635   "int_bool", [
4636     "i", FInt32;                (* for historical compatibility *)
4637     "b", FInt32;                (* for historical compatibility *)
4638   ];
4639
4640   (* LVM PVs, VGs, LVs. *)
4641   "lvm_pv", lvm_pv_cols;
4642   "lvm_vg", lvm_vg_cols;
4643   "lvm_lv", lvm_lv_cols;
4644
4645   (* Column names and types from stat structures.
4646    * NB. Can't use things like 'st_atime' because glibc header files
4647    * define some of these as macros.  Ugh.
4648    *)
4649   "stat", [
4650     "dev", FInt64;
4651     "ino", FInt64;
4652     "mode", FInt64;
4653     "nlink", FInt64;
4654     "uid", FInt64;
4655     "gid", FInt64;
4656     "rdev", FInt64;
4657     "size", FInt64;
4658     "blksize", FInt64;
4659     "blocks", FInt64;
4660     "atime", FInt64;
4661     "mtime", FInt64;
4662     "ctime", FInt64;
4663   ];
4664   "statvfs", [
4665     "bsize", FInt64;
4666     "frsize", FInt64;
4667     "blocks", FInt64;
4668     "bfree", FInt64;
4669     "bavail", FInt64;
4670     "files", FInt64;
4671     "ffree", FInt64;
4672     "favail", FInt64;
4673     "fsid", FInt64;
4674     "flag", FInt64;
4675     "namemax", FInt64;
4676   ];
4677
4678   (* Column names in dirent structure. *)
4679   "dirent", [
4680     "ino", FInt64;
4681     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4682     "ftyp", FChar;
4683     "name", FString;
4684   ];
4685
4686   (* Version numbers. *)
4687   "version", [
4688     "major", FInt64;
4689     "minor", FInt64;
4690     "release", FInt64;
4691     "extra", FString;
4692   ];
4693
4694   (* Extended attribute. *)
4695   "xattr", [
4696     "attrname", FString;
4697     "attrval", FBuffer;
4698   ];
4699
4700   (* Inotify events. *)
4701   "inotify_event", [
4702     "in_wd", FInt64;
4703     "in_mask", FUInt32;
4704     "in_cookie", FUInt32;
4705     "in_name", FString;
4706   ];
4707
4708   (* Partition table entry. *)
4709   "partition", [
4710     "part_num", FInt32;
4711     "part_start", FBytes;
4712     "part_end", FBytes;
4713     "part_size", FBytes;
4714   ];
4715 ] (* end of structs *)
4716
4717 (* Ugh, Java has to be different ..
4718  * These names are also used by the Haskell bindings.
4719  *)
4720 let java_structs = [
4721   "int_bool", "IntBool";
4722   "lvm_pv", "PV";
4723   "lvm_vg", "VG";
4724   "lvm_lv", "LV";
4725   "stat", "Stat";
4726   "statvfs", "StatVFS";
4727   "dirent", "Dirent";
4728   "version", "Version";
4729   "xattr", "XAttr";
4730   "inotify_event", "INotifyEvent";
4731   "partition", "Partition";
4732 ]
4733
4734 (* What structs are actually returned. *)
4735 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4736
4737 (* Returns a list of RStruct/RStructList structs that are returned
4738  * by any function.  Each element of returned list is a pair:
4739  *
4740  * (structname, RStructOnly)
4741  *    == there exists function which returns RStruct (_, structname)
4742  * (structname, RStructListOnly)
4743  *    == there exists function which returns RStructList (_, structname)
4744  * (structname, RStructAndList)
4745  *    == there are functions returning both RStruct (_, structname)
4746  *                                      and RStructList (_, structname)
4747  *)
4748 let rstructs_used_by functions =
4749   (* ||| is a "logical OR" for rstructs_used_t *)
4750   let (|||) a b =
4751     match a, b with
4752     | RStructAndList, _
4753     | _, RStructAndList -> RStructAndList
4754     | RStructOnly, RStructListOnly
4755     | RStructListOnly, RStructOnly -> RStructAndList
4756     | RStructOnly, RStructOnly -> RStructOnly
4757     | RStructListOnly, RStructListOnly -> RStructListOnly
4758   in
4759
4760   let h = Hashtbl.create 13 in
4761
4762   (* if elem->oldv exists, update entry using ||| operator,
4763    * else just add elem->newv to the hash
4764    *)
4765   let update elem newv =
4766     try  let oldv = Hashtbl.find h elem in
4767          Hashtbl.replace h elem (newv ||| oldv)
4768     with Not_found -> Hashtbl.add h elem newv
4769   in
4770
4771   List.iter (
4772     fun (_, style, _, _, _, _, _) ->
4773       match fst style with
4774       | RStruct (_, structname) -> update structname RStructOnly
4775       | RStructList (_, structname) -> update structname RStructListOnly
4776       | _ -> ()
4777   ) functions;
4778
4779   (* return key->values as a list of (key,value) *)
4780   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4781
4782 (* Used for testing language bindings. *)
4783 type callt =
4784   | CallString of string
4785   | CallOptString of string option
4786   | CallStringList of string list
4787   | CallInt of int
4788   | CallInt64 of int64
4789   | CallBool of bool
4790
4791 (* Used to memoize the result of pod2text. *)
4792 let pod2text_memo_filename = "src/.pod2text.data"
4793 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4794   try
4795     let chan = open_in pod2text_memo_filename in
4796     let v = input_value chan in
4797     close_in chan;
4798     v
4799   with
4800     _ -> Hashtbl.create 13
4801 let pod2text_memo_updated () =
4802   let chan = open_out pod2text_memo_filename in
4803   output_value chan pod2text_memo;
4804   close_out chan
4805
4806 (* Useful functions.
4807  * Note we don't want to use any external OCaml libraries which
4808  * makes this a bit harder than it should be.
4809  *)
4810 module StringMap = Map.Make (String)
4811
4812 let failwithf fs = ksprintf failwith fs
4813
4814 let unique = let i = ref 0 in fun () -> incr i; !i
4815
4816 let replace_char s c1 c2 =
4817   let s2 = String.copy s in
4818   let r = ref false in
4819   for i = 0 to String.length s2 - 1 do
4820     if String.unsafe_get s2 i = c1 then (
4821       String.unsafe_set s2 i c2;
4822       r := true
4823     )
4824   done;
4825   if not !r then s else s2
4826
4827 let isspace c =
4828   c = ' '
4829   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4830
4831 let triml ?(test = isspace) str =
4832   let i = ref 0 in
4833   let n = ref (String.length str) in
4834   while !n > 0 && test str.[!i]; do
4835     decr n;
4836     incr i
4837   done;
4838   if !i = 0 then str
4839   else String.sub str !i !n
4840
4841 let trimr ?(test = isspace) str =
4842   let n = ref (String.length str) in
4843   while !n > 0 && test str.[!n-1]; do
4844     decr n
4845   done;
4846   if !n = String.length str then str
4847   else String.sub str 0 !n
4848
4849 let trim ?(test = isspace) str =
4850   trimr ~test (triml ~test str)
4851
4852 let rec find s sub =
4853   let len = String.length s in
4854   let sublen = String.length sub in
4855   let rec loop i =
4856     if i <= len-sublen then (
4857       let rec loop2 j =
4858         if j < sublen then (
4859           if s.[i+j] = sub.[j] then loop2 (j+1)
4860           else -1
4861         ) else
4862           i (* found *)
4863       in
4864       let r = loop2 0 in
4865       if r = -1 then loop (i+1) else r
4866     ) else
4867       -1 (* not found *)
4868   in
4869   loop 0
4870
4871 let rec replace_str s s1 s2 =
4872   let len = String.length s in
4873   let sublen = String.length s1 in
4874   let i = find s s1 in
4875   if i = -1 then s
4876   else (
4877     let s' = String.sub s 0 i in
4878     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4879     s' ^ s2 ^ replace_str s'' s1 s2
4880   )
4881
4882 let rec string_split sep str =
4883   let len = String.length str in
4884   let seplen = String.length sep in
4885   let i = find str sep in
4886   if i = -1 then [str]
4887   else (
4888     let s' = String.sub str 0 i in
4889     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4890     s' :: string_split sep s''
4891   )
4892
4893 let files_equal n1 n2 =
4894   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4895   match Sys.command cmd with
4896   | 0 -> true
4897   | 1 -> false
4898   | i -> failwithf "%s: failed with error code %d" cmd i
4899
4900 let rec filter_map f = function
4901   | [] -> []
4902   | x :: xs ->
4903       match f x with
4904       | Some y -> y :: filter_map f xs
4905       | None -> filter_map f xs
4906
4907 let rec find_map f = function
4908   | [] -> raise Not_found
4909   | x :: xs ->
4910       match f x with
4911       | Some y -> y
4912       | None -> find_map f xs
4913
4914 let iteri f xs =
4915   let rec loop i = function
4916     | [] -> ()
4917     | x :: xs -> f i x; loop (i+1) xs
4918   in
4919   loop 0 xs
4920
4921 let mapi f xs =
4922   let rec loop i = function
4923     | [] -> []
4924     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4925   in
4926   loop 0 xs
4927
4928 let count_chars c str =
4929   let count = ref 0 in
4930   for i = 0 to String.length str - 1 do
4931     if c = String.unsafe_get str i then incr count
4932   done;
4933   !count
4934
4935 let name_of_argt = function
4936   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4937   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4938   | FileIn n | FileOut n -> n
4939
4940 let java_name_of_struct typ =
4941   try List.assoc typ java_structs
4942   with Not_found ->
4943     failwithf
4944       "java_name_of_struct: no java_structs entry corresponding to %s" typ
4945
4946 let cols_of_struct typ =
4947   try List.assoc typ structs
4948   with Not_found ->
4949     failwithf "cols_of_struct: unknown struct %s" typ
4950
4951 let seq_of_test = function
4952   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
4953   | TestOutputListOfDevices (s, _)
4954   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
4955   | TestOutputTrue s | TestOutputFalse s
4956   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
4957   | TestOutputStruct (s, _)
4958   | TestLastFail s -> s
4959
4960 (* Handling for function flags. *)
4961 let protocol_limit_warning =
4962   "Because of the message protocol, there is a transfer limit
4963 of somewhere between 2MB and 4MB.  See L<guestfs(3)/PROTOCOL LIMITS>."
4964
4965 let danger_will_robinson =
4966   "B<This command is dangerous.  Without careful use you
4967 can easily destroy all your data>."
4968
4969 let deprecation_notice flags =
4970   try
4971     let alt =
4972       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
4973     let txt =
4974       sprintf "This function is deprecated.
4975 In new code, use the C<%s> call instead.
4976
4977 Deprecated functions will not be removed from the API, but the
4978 fact that they are deprecated indicates that there are problems
4979 with correct use of these functions." alt in
4980     Some txt
4981   with
4982     Not_found -> None
4983
4984 (* Create list of optional groups. *)
4985 let optgroups =
4986   let h = Hashtbl.create 13 in
4987   List.iter (
4988     fun (name, _, _, flags, _, _, _) ->
4989       List.iter (
4990         function
4991         | Optional group ->
4992             let names = try Hashtbl.find h group with Not_found -> [] in
4993             Hashtbl.replace h group (name :: names)
4994         | _ -> ()
4995       ) flags
4996   ) daemon_functions;
4997   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
4998   let groups =
4999     List.map (
5000       fun group -> group, List.sort compare (Hashtbl.find h group)
5001     ) groups in
5002   List.sort (fun x y -> compare (fst x) (fst y)) groups
5003
5004 (* Check function names etc. for consistency. *)
5005 let check_functions () =
5006   let contains_uppercase str =
5007     let len = String.length str in
5008     let rec loop i =
5009       if i >= len then false
5010       else (
5011         let c = str.[i] in
5012         if c >= 'A' && c <= 'Z' then true
5013         else loop (i+1)
5014       )
5015     in
5016     loop 0
5017   in
5018
5019   (* Check function names. *)
5020   List.iter (
5021     fun (name, _, _, _, _, _, _) ->
5022       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
5023         failwithf "function name %s does not need 'guestfs' prefix" name;
5024       if name = "" then
5025         failwithf "function name is empty";
5026       if name.[0] < 'a' || name.[0] > 'z' then
5027         failwithf "function name %s must start with lowercase a-z" name;
5028       if String.contains name '-' then
5029         failwithf "function name %s should not contain '-', use '_' instead."
5030           name
5031   ) all_functions;
5032
5033   (* Check function parameter/return names. *)
5034   List.iter (
5035     fun (name, style, _, _, _, _, _) ->
5036       let check_arg_ret_name n =
5037         if contains_uppercase n then
5038           failwithf "%s param/ret %s should not contain uppercase chars"
5039             name n;
5040         if String.contains n '-' || String.contains n '_' then
5041           failwithf "%s param/ret %s should not contain '-' or '_'"
5042             name n;
5043         if n = "value" then
5044           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;
5045         if n = "int" || n = "char" || n = "short" || n = "long" then
5046           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
5047         if n = "i" || n = "n" then
5048           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
5049         if n = "argv" || n = "args" then
5050           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
5051
5052         (* List Haskell, OCaml and C keywords here.
5053          * http://www.haskell.org/haskellwiki/Keywords
5054          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
5055          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
5056          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
5057          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
5058          * Omitting _-containing words, since they're handled above.
5059          * Omitting the OCaml reserved word, "val", is ok,
5060          * and saves us from renaming several parameters.
5061          *)
5062         let reserved = [
5063           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
5064           "char"; "class"; "const"; "constraint"; "continue"; "data";
5065           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
5066           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
5067           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
5068           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
5069           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
5070           "interface";
5071           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
5072           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
5073           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
5074           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
5075           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
5076           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
5077           "volatile"; "when"; "where"; "while";
5078           ] in
5079         if List.mem n reserved then
5080           failwithf "%s has param/ret using reserved word %s" name n;
5081       in
5082
5083       (match fst style with
5084        | RErr -> ()
5085        | RInt n | RInt64 n | RBool n
5086        | RConstString n | RConstOptString n | RString n
5087        | RStringList n | RStruct (n, _) | RStructList (n, _)
5088        | RHashtable n | RBufferOut n ->
5089            check_arg_ret_name n
5090       );
5091       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
5092   ) all_functions;
5093
5094   (* Check short descriptions. *)
5095   List.iter (
5096     fun (name, _, _, _, _, shortdesc, _) ->
5097       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
5098         failwithf "short description of %s should begin with lowercase." name;
5099       let c = shortdesc.[String.length shortdesc-1] in
5100       if c = '\n' || c = '.' then
5101         failwithf "short description of %s should not end with . or \\n." name
5102   ) all_functions;
5103
5104   (* Check long descriptions. *)
5105   List.iter (
5106     fun (name, _, _, _, _, _, longdesc) ->
5107       if longdesc.[String.length longdesc-1] = '\n' then
5108         failwithf "long description of %s should not end with \\n." name
5109   ) all_functions;
5110
5111   (* Check proc_nrs. *)
5112   List.iter (
5113     fun (name, _, proc_nr, _, _, _, _) ->
5114       if proc_nr <= 0 then
5115         failwithf "daemon function %s should have proc_nr > 0" name
5116   ) daemon_functions;
5117
5118   List.iter (
5119     fun (name, _, proc_nr, _, _, _, _) ->
5120       if proc_nr <> -1 then
5121         failwithf "non-daemon function %s should have proc_nr -1" name
5122   ) non_daemon_functions;
5123
5124   let proc_nrs =
5125     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
5126       daemon_functions in
5127   let proc_nrs =
5128     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
5129   let rec loop = function
5130     | [] -> ()
5131     | [_] -> ()
5132     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
5133         loop rest
5134     | (name1,nr1) :: (name2,nr2) :: _ ->
5135         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
5136           name1 name2 nr1 nr2
5137   in
5138   loop proc_nrs;
5139
5140   (* Check tests. *)
5141   List.iter (
5142     function
5143       (* Ignore functions that have no tests.  We generate a
5144        * warning when the user does 'make check' instead.
5145        *)
5146     | name, _, _, _, [], _, _ -> ()
5147     | name, _, _, _, tests, _, _ ->
5148         let funcs =
5149           List.map (
5150             fun (_, _, test) ->
5151               match seq_of_test test with
5152               | [] ->
5153                   failwithf "%s has a test containing an empty sequence" name
5154               | cmds -> List.map List.hd cmds
5155           ) tests in
5156         let funcs = List.flatten funcs in
5157
5158         let tested = List.mem name funcs in
5159
5160         if not tested then
5161           failwithf "function %s has tests but does not test itself" name
5162   ) all_functions
5163
5164 (* 'pr' prints to the current output file. *)
5165 let chan = ref Pervasives.stdout
5166 let lines = ref 0
5167 let pr fs =
5168   ksprintf
5169     (fun str ->
5170        let i = count_chars '\n' str in
5171        lines := !lines + i;
5172        output_string !chan str
5173     ) fs
5174
5175 let copyright_years =
5176   let this_year = 1900 + (localtime (time ())).tm_year in
5177   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
5178
5179 (* Generate a header block in a number of standard styles. *)
5180 type comment_style =
5181     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
5182 type license = GPLv2plus | LGPLv2plus
5183
5184 let generate_header ?(extra_inputs = []) comment license =
5185   let inputs = "src/generator.ml" :: extra_inputs in
5186   let c = match comment with
5187     | CStyle ->         pr "/* "; " *"
5188     | CPlusPlusStyle -> pr "// "; "//"
5189     | HashStyle ->      pr "# ";  "#"
5190     | OCamlStyle ->     pr "(* "; " *"
5191     | HaskellStyle ->   pr "{- "; "  " in
5192   pr "libguestfs generated file\n";
5193   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
5194   List.iter (pr "%s   %s\n" c) inputs;
5195   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
5196   pr "%s\n" c;
5197   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
5198   pr "%s\n" c;
5199   (match license with
5200    | GPLv2plus ->
5201        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
5202        pr "%s it under the terms of the GNU General Public License as published by\n" c;
5203        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
5204        pr "%s (at your option) any later version.\n" c;
5205        pr "%s\n" c;
5206        pr "%s This program is distributed in the hope that it will be useful,\n" c;
5207        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5208        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
5209        pr "%s GNU General Public License for more details.\n" c;
5210        pr "%s\n" c;
5211        pr "%s You should have received a copy of the GNU General Public License along\n" c;
5212        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
5213        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
5214
5215    | LGPLv2plus ->
5216        pr "%s This library is free software; you can redistribute it and/or\n" c;
5217        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
5218        pr "%s License as published by the Free Software Foundation; either\n" c;
5219        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
5220        pr "%s\n" c;
5221        pr "%s This library is distributed in the hope that it will be useful,\n" c;
5222        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5223        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
5224        pr "%s Lesser General Public License for more details.\n" c;
5225        pr "%s\n" c;
5226        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
5227        pr "%s License along with this library; if not, write to the Free Software\n" c;
5228        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
5229   );
5230   (match comment with
5231    | CStyle -> pr " */\n"
5232    | CPlusPlusStyle
5233    | HashStyle -> ()
5234    | OCamlStyle -> pr " *)\n"
5235    | HaskellStyle -> pr "-}\n"
5236   );
5237   pr "\n"
5238
5239 (* Start of main code generation functions below this line. *)
5240
5241 (* Generate the pod documentation for the C API. *)
5242 let rec generate_actions_pod () =
5243   List.iter (
5244     fun (shortname, style, _, flags, _, _, longdesc) ->
5245       if not (List.mem NotInDocs flags) then (
5246         let name = "guestfs_" ^ shortname in
5247         pr "=head2 %s\n\n" name;
5248         pr " ";
5249         generate_prototype ~extern:false ~handle:"g" name style;
5250         pr "\n\n";
5251         pr "%s\n\n" longdesc;
5252         (match fst style with
5253          | RErr ->
5254              pr "This function returns 0 on success or -1 on error.\n\n"
5255          | RInt _ ->
5256              pr "On error this function returns -1.\n\n"
5257          | RInt64 _ ->
5258              pr "On error this function returns -1.\n\n"
5259          | RBool _ ->
5260              pr "This function returns a C truth value on success or -1 on error.\n\n"
5261          | RConstString _ ->
5262              pr "This function returns a string, or NULL on error.
5263 The string is owned by the guest handle and must I<not> be freed.\n\n"
5264          | RConstOptString _ ->
5265              pr "This function returns a string which may be NULL.
5266 There is way to return an error from this function.
5267 The string is owned by the guest handle and must I<not> be freed.\n\n"
5268          | RString _ ->
5269              pr "This function returns a string, or NULL on error.
5270 I<The caller must free the returned string after use>.\n\n"
5271          | RStringList _ ->
5272              pr "This function returns a NULL-terminated array of strings
5273 (like L<environ(3)>), or NULL if there was an error.
5274 I<The caller must free the strings and the array after use>.\n\n"
5275          | RStruct (_, typ) ->
5276              pr "This function returns a C<struct guestfs_%s *>,
5277 or NULL if there was an error.
5278 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
5279          | RStructList (_, typ) ->
5280              pr "This function returns a C<struct guestfs_%s_list *>
5281 (see E<lt>guestfs-structs.hE<gt>),
5282 or NULL if there was an error.
5283 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
5284          | RHashtable _ ->
5285              pr "This function returns a NULL-terminated array of
5286 strings, or NULL if there was an error.
5287 The array of strings will always have length C<2n+1>, where
5288 C<n> keys and values alternate, followed by the trailing NULL entry.
5289 I<The caller must free the strings and the array after use>.\n\n"
5290          | RBufferOut _ ->
5291              pr "This function returns a buffer, or NULL on error.
5292 The size of the returned buffer is written to C<*size_r>.
5293 I<The caller must free the returned buffer after use>.\n\n"
5294         );
5295         if List.mem ProtocolLimitWarning flags then
5296           pr "%s\n\n" protocol_limit_warning;
5297         if List.mem DangerWillRobinson flags then
5298           pr "%s\n\n" danger_will_robinson;
5299         match deprecation_notice flags with
5300         | None -> ()
5301         | Some txt -> pr "%s\n\n" txt
5302       )
5303   ) all_functions_sorted
5304
5305 and generate_structs_pod () =
5306   (* Structs documentation. *)
5307   List.iter (
5308     fun (typ, cols) ->
5309       pr "=head2 guestfs_%s\n" typ;
5310       pr "\n";
5311       pr " struct guestfs_%s {\n" typ;
5312       List.iter (
5313         function
5314         | name, FChar -> pr "   char %s;\n" name
5315         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5316         | name, FInt32 -> pr "   int32_t %s;\n" name
5317         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5318         | name, FInt64 -> pr "   int64_t %s;\n" name
5319         | name, FString -> pr "   char *%s;\n" name
5320         | name, FBuffer ->
5321             pr "   /* The next two fields describe a byte array. */\n";
5322             pr "   uint32_t %s_len;\n" name;
5323             pr "   char *%s;\n" name
5324         | name, FUUID ->
5325             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5326             pr "   char %s[32];\n" name
5327         | name, FOptPercent ->
5328             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5329             pr "   float %s;\n" name
5330       ) cols;
5331       pr " };\n";
5332       pr " \n";
5333       pr " struct guestfs_%s_list {\n" typ;
5334       pr "   uint32_t len; /* Number of elements in list. */\n";
5335       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5336       pr " };\n";
5337       pr " \n";
5338       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5339       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5340         typ typ;
5341       pr "\n"
5342   ) structs
5343
5344 and generate_availability_pod () =
5345   (* Availability documentation. *)
5346   pr "=over 4\n";
5347   pr "\n";
5348   List.iter (
5349     fun (group, functions) ->
5350       pr "=item B<%s>\n" group;
5351       pr "\n";
5352       pr "The following functions:\n";
5353       List.iter (pr "L</guestfs_%s>\n") functions;
5354       pr "\n"
5355   ) optgroups;
5356   pr "=back\n";
5357   pr "\n"
5358
5359 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5360  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5361  *
5362  * We have to use an underscore instead of a dash because otherwise
5363  * rpcgen generates incorrect code.
5364  *
5365  * This header is NOT exported to clients, but see also generate_structs_h.
5366  *)
5367 and generate_xdr () =
5368   generate_header CStyle LGPLv2plus;
5369
5370   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5371   pr "typedef string str<>;\n";
5372   pr "\n";
5373
5374   (* Internal structures. *)
5375   List.iter (
5376     function
5377     | typ, cols ->
5378         pr "struct guestfs_int_%s {\n" typ;
5379         List.iter (function
5380                    | name, FChar -> pr "  char %s;\n" name
5381                    | name, FString -> pr "  string %s<>;\n" name
5382                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5383                    | name, FUUID -> pr "  opaque %s[32];\n" name
5384                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5385                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5386                    | name, FOptPercent -> pr "  float %s;\n" name
5387                   ) cols;
5388         pr "};\n";
5389         pr "\n";
5390         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5391         pr "\n";
5392   ) structs;
5393
5394   List.iter (
5395     fun (shortname, style, _, _, _, _, _) ->
5396       let name = "guestfs_" ^ shortname in
5397
5398       (match snd style with
5399        | [] -> ()
5400        | args ->
5401            pr "struct %s_args {\n" name;
5402            List.iter (
5403              function
5404              | Pathname n | Device n | Dev_or_Path n | String n ->
5405                  pr "  string %s<>;\n" n
5406              | OptString n -> pr "  str *%s;\n" n
5407              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5408              | Bool n -> pr "  bool %s;\n" n
5409              | Int n -> pr "  int %s;\n" n
5410              | Int64 n -> pr "  hyper %s;\n" n
5411              | FileIn _ | FileOut _ -> ()
5412            ) args;
5413            pr "};\n\n"
5414       );
5415       (match fst style with
5416        | RErr -> ()
5417        | RInt n ->
5418            pr "struct %s_ret {\n" name;
5419            pr "  int %s;\n" n;
5420            pr "};\n\n"
5421        | RInt64 n ->
5422            pr "struct %s_ret {\n" name;
5423            pr "  hyper %s;\n" n;
5424            pr "};\n\n"
5425        | RBool n ->
5426            pr "struct %s_ret {\n" name;
5427            pr "  bool %s;\n" n;
5428            pr "};\n\n"
5429        | RConstString _ | RConstOptString _ ->
5430            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5431        | RString n ->
5432            pr "struct %s_ret {\n" name;
5433            pr "  string %s<>;\n" n;
5434            pr "};\n\n"
5435        | RStringList n ->
5436            pr "struct %s_ret {\n" name;
5437            pr "  str %s<>;\n" n;
5438            pr "};\n\n"
5439        | RStruct (n, typ) ->
5440            pr "struct %s_ret {\n" name;
5441            pr "  guestfs_int_%s %s;\n" typ n;
5442            pr "};\n\n"
5443        | RStructList (n, typ) ->
5444            pr "struct %s_ret {\n" name;
5445            pr "  guestfs_int_%s_list %s;\n" typ n;
5446            pr "};\n\n"
5447        | RHashtable n ->
5448            pr "struct %s_ret {\n" name;
5449            pr "  str %s<>;\n" n;
5450            pr "};\n\n"
5451        | RBufferOut n ->
5452            pr "struct %s_ret {\n" name;
5453            pr "  opaque %s<>;\n" n;
5454            pr "};\n\n"
5455       );
5456   ) daemon_functions;
5457
5458   (* Table of procedure numbers. *)
5459   pr "enum guestfs_procedure {\n";
5460   List.iter (
5461     fun (shortname, _, proc_nr, _, _, _, _) ->
5462       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5463   ) daemon_functions;
5464   pr "  GUESTFS_PROC_NR_PROCS\n";
5465   pr "};\n";
5466   pr "\n";
5467
5468   (* Having to choose a maximum message size is annoying for several
5469    * reasons (it limits what we can do in the API), but it (a) makes
5470    * the protocol a lot simpler, and (b) provides a bound on the size
5471    * of the daemon which operates in limited memory space.
5472    *)
5473   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5474   pr "\n";
5475
5476   (* Message header, etc. *)
5477   pr "\
5478 /* The communication protocol is now documented in the guestfs(3)
5479  * manpage.
5480  */
5481
5482 const GUESTFS_PROGRAM = 0x2000F5F5;
5483 const GUESTFS_PROTOCOL_VERSION = 1;
5484
5485 /* These constants must be larger than any possible message length. */
5486 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5487 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5488
5489 enum guestfs_message_direction {
5490   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5491   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5492 };
5493
5494 enum guestfs_message_status {
5495   GUESTFS_STATUS_OK = 0,
5496   GUESTFS_STATUS_ERROR = 1
5497 };
5498
5499 const GUESTFS_ERROR_LEN = 256;
5500
5501 struct guestfs_message_error {
5502   string error_message<GUESTFS_ERROR_LEN>;
5503 };
5504
5505 struct guestfs_message_header {
5506   unsigned prog;                     /* GUESTFS_PROGRAM */
5507   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5508   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5509   guestfs_message_direction direction;
5510   unsigned serial;                   /* message serial number */
5511   guestfs_message_status status;
5512 };
5513
5514 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5515
5516 struct guestfs_chunk {
5517   int cancel;                        /* if non-zero, transfer is cancelled */
5518   /* data size is 0 bytes if the transfer has finished successfully */
5519   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5520 };
5521 "
5522
5523 (* Generate the guestfs-structs.h file. *)
5524 and generate_structs_h () =
5525   generate_header CStyle LGPLv2plus;
5526
5527   (* This is a public exported header file containing various
5528    * structures.  The structures are carefully written to have
5529    * exactly the same in-memory format as the XDR structures that
5530    * we use on the wire to the daemon.  The reason for creating
5531    * copies of these structures here is just so we don't have to
5532    * export the whole of guestfs_protocol.h (which includes much
5533    * unrelated and XDR-dependent stuff that we don't want to be
5534    * public, or required by clients).
5535    *
5536    * To reiterate, we will pass these structures to and from the
5537    * client with a simple assignment or memcpy, so the format
5538    * must be identical to what rpcgen / the RFC defines.
5539    *)
5540
5541   (* Public structures. *)
5542   List.iter (
5543     fun (typ, cols) ->
5544       pr "struct guestfs_%s {\n" typ;
5545       List.iter (
5546         function
5547         | name, FChar -> pr "  char %s;\n" name
5548         | name, FString -> pr "  char *%s;\n" name
5549         | name, FBuffer ->
5550             pr "  uint32_t %s_len;\n" name;
5551             pr "  char *%s;\n" name
5552         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5553         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5554         | name, FInt32 -> pr "  int32_t %s;\n" name
5555         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5556         | name, FInt64 -> pr "  int64_t %s;\n" name
5557         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5558       ) cols;
5559       pr "};\n";
5560       pr "\n";
5561       pr "struct guestfs_%s_list {\n" typ;
5562       pr "  uint32_t len;\n";
5563       pr "  struct guestfs_%s *val;\n" typ;
5564       pr "};\n";
5565       pr "\n";
5566       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5567       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5568       pr "\n"
5569   ) structs
5570
5571 (* Generate the guestfs-actions.h file. *)
5572 and generate_actions_h () =
5573   generate_header CStyle LGPLv2plus;
5574   List.iter (
5575     fun (shortname, style, _, _, _, _, _) ->
5576       let name = "guestfs_" ^ shortname in
5577       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5578         name style
5579   ) all_functions
5580
5581 (* Generate the guestfs-internal-actions.h file. *)
5582 and generate_internal_actions_h () =
5583   generate_header CStyle LGPLv2plus;
5584   List.iter (
5585     fun (shortname, style, _, _, _, _, _) ->
5586       let name = "guestfs__" ^ shortname in
5587       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5588         name style
5589   ) non_daemon_functions
5590
5591 (* Generate the client-side dispatch stubs. *)
5592 and generate_client_actions () =
5593   generate_header CStyle LGPLv2plus;
5594
5595   pr "\
5596 #include <stdio.h>
5597 #include <stdlib.h>
5598 #include <stdint.h>
5599 #include <string.h>
5600 #include <inttypes.h>
5601
5602 #include \"guestfs.h\"
5603 #include \"guestfs-internal.h\"
5604 #include \"guestfs-internal-actions.h\"
5605 #include \"guestfs_protocol.h\"
5606
5607 #define error guestfs_error
5608 //#define perrorf guestfs_perrorf
5609 #define safe_malloc guestfs_safe_malloc
5610 #define safe_realloc guestfs_safe_realloc
5611 //#define safe_strdup guestfs_safe_strdup
5612 #define safe_memdup guestfs_safe_memdup
5613
5614 /* Check the return message from a call for validity. */
5615 static int
5616 check_reply_header (guestfs_h *g,
5617                     const struct guestfs_message_header *hdr,
5618                     unsigned int proc_nr, unsigned int serial)
5619 {
5620   if (hdr->prog != GUESTFS_PROGRAM) {
5621     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5622     return -1;
5623   }
5624   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5625     error (g, \"wrong protocol version (%%d/%%d)\",
5626            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5627     return -1;
5628   }
5629   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5630     error (g, \"unexpected message direction (%%d/%%d)\",
5631            hdr->direction, GUESTFS_DIRECTION_REPLY);
5632     return -1;
5633   }
5634   if (hdr->proc != proc_nr) {
5635     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5636     return -1;
5637   }
5638   if (hdr->serial != serial) {
5639     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5640     return -1;
5641   }
5642
5643   return 0;
5644 }
5645
5646 /* Check we are in the right state to run a high-level action. */
5647 static int
5648 check_state (guestfs_h *g, const char *caller)
5649 {
5650   if (!guestfs__is_ready (g)) {
5651     if (guestfs__is_config (g) || guestfs__is_launching (g))
5652       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5653         caller);
5654     else
5655       error (g, \"%%s called from the wrong state, %%d != READY\",
5656         caller, guestfs__get_state (g));
5657     return -1;
5658   }
5659   return 0;
5660 }
5661
5662 ";
5663
5664   (* Generate code to generate guestfish call traces. *)
5665   let trace_call shortname style =
5666     pr "  if (guestfs__get_trace (g)) {\n";
5667
5668     let needs_i =
5669       List.exists (function
5670                    | StringList _ | DeviceList _ -> true
5671                    | _ -> false) (snd style) in
5672     if needs_i then (
5673       pr "    int i;\n";
5674       pr "\n"
5675     );
5676
5677     pr "    printf (\"%s\");\n" shortname;
5678     List.iter (
5679       function
5680       | String n                        (* strings *)
5681       | Device n
5682       | Pathname n
5683       | Dev_or_Path n
5684       | FileIn n
5685       | FileOut n ->
5686           (* guestfish doesn't support string escaping, so neither do we *)
5687           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5688       | OptString n ->                  (* string option *)
5689           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5690           pr "    else printf (\" null\");\n"
5691       | StringList n
5692       | DeviceList n ->                 (* string list *)
5693           pr "    putchar (' ');\n";
5694           pr "    putchar ('\"');\n";
5695           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5696           pr "      if (i > 0) putchar (' ');\n";
5697           pr "      fputs (%s[i], stdout);\n" n;
5698           pr "    }\n";
5699           pr "    putchar ('\"');\n";
5700       | Bool n ->                       (* boolean *)
5701           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5702       | Int n ->                        (* int *)
5703           pr "    printf (\" %%d\", %s);\n" n
5704       | Int64 n ->
5705           pr "    printf (\" %%\" PRIi64, %s);\n" n
5706     ) (snd style);
5707     pr "    putchar ('\\n');\n";
5708     pr "  }\n";
5709     pr "\n";
5710   in
5711
5712   (* For non-daemon functions, generate a wrapper around each function. *)
5713   List.iter (
5714     fun (shortname, style, _, _, _, _, _) ->
5715       let name = "guestfs_" ^ shortname in
5716
5717       generate_prototype ~extern:false ~semicolon:false ~newline:true
5718         ~handle:"g" name style;
5719       pr "{\n";
5720       trace_call shortname style;
5721       pr "  return guestfs__%s " shortname;
5722       generate_c_call_args ~handle:"g" style;
5723       pr ";\n";
5724       pr "}\n";
5725       pr "\n"
5726   ) non_daemon_functions;
5727
5728   (* Client-side stubs for each function. *)
5729   List.iter (
5730     fun (shortname, style, _, _, _, _, _) ->
5731       let name = "guestfs_" ^ shortname in
5732
5733       (* Generate the action stub. *)
5734       generate_prototype ~extern:false ~semicolon:false ~newline:true
5735         ~handle:"g" name style;
5736
5737       let error_code =
5738         match fst style with
5739         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5740         | RConstString _ | RConstOptString _ ->
5741             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5742         | RString _ | RStringList _
5743         | RStruct _ | RStructList _
5744         | RHashtable _ | RBufferOut _ ->
5745             "NULL" in
5746
5747       pr "{\n";
5748
5749       (match snd style with
5750        | [] -> ()
5751        | _ -> pr "  struct %s_args args;\n" name
5752       );
5753
5754       pr "  guestfs_message_header hdr;\n";
5755       pr "  guestfs_message_error err;\n";
5756       let has_ret =
5757         match fst style with
5758         | RErr -> false
5759         | RConstString _ | RConstOptString _ ->
5760             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5761         | RInt _ | RInt64 _
5762         | RBool _ | RString _ | RStringList _
5763         | RStruct _ | RStructList _
5764         | RHashtable _ | RBufferOut _ ->
5765             pr "  struct %s_ret ret;\n" name;
5766             true in
5767
5768       pr "  int serial;\n";
5769       pr "  int r;\n";
5770       pr "\n";
5771       trace_call shortname style;
5772       pr "  if (check_state (g, \"%s\") == -1) return %s;\n"
5773         shortname error_code;
5774       pr "  guestfs___set_busy (g);\n";
5775       pr "\n";
5776
5777       (* Send the main header and arguments. *)
5778       (match snd style with
5779        | [] ->
5780            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5781              (String.uppercase shortname)
5782        | args ->
5783            List.iter (
5784              function
5785              | Pathname n | Device n | Dev_or_Path n | String n ->
5786                  pr "  args.%s = (char *) %s;\n" n n
5787              | OptString n ->
5788                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5789              | StringList n | DeviceList n ->
5790                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5791                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5792              | Bool n ->
5793                  pr "  args.%s = %s;\n" n n
5794              | Int n ->
5795                  pr "  args.%s = %s;\n" n n
5796              | Int64 n ->
5797                  pr "  args.%s = %s;\n" n n
5798              | FileIn _ | FileOut _ -> ()
5799            ) args;
5800            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5801              (String.uppercase shortname);
5802            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5803              name;
5804       );
5805       pr "  if (serial == -1) {\n";
5806       pr "    guestfs___end_busy (g);\n";
5807       pr "    return %s;\n" error_code;
5808       pr "  }\n";
5809       pr "\n";
5810
5811       (* Send any additional files (FileIn) requested. *)
5812       let need_read_reply_label = ref false in
5813       List.iter (
5814         function
5815         | FileIn n ->
5816             pr "  r = guestfs___send_file (g, %s);\n" n;
5817             pr "  if (r == -1) {\n";
5818             pr "    guestfs___end_busy (g);\n";
5819             pr "    return %s;\n" error_code;
5820             pr "  }\n";
5821             pr "  if (r == -2) /* daemon cancelled */\n";
5822             pr "    goto read_reply;\n";
5823             need_read_reply_label := true;
5824             pr "\n";
5825         | _ -> ()
5826       ) (snd style);
5827
5828       (* Wait for the reply from the remote end. *)
5829       if !need_read_reply_label then pr " read_reply:\n";
5830       pr "  memset (&hdr, 0, sizeof hdr);\n";
5831       pr "  memset (&err, 0, sizeof err);\n";
5832       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5833       pr "\n";
5834       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5835       if not has_ret then
5836         pr "NULL, NULL"
5837       else
5838         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5839       pr ");\n";
5840
5841       pr "  if (r == -1) {\n";
5842       pr "    guestfs___end_busy (g);\n";
5843       pr "    return %s;\n" error_code;
5844       pr "  }\n";
5845       pr "\n";
5846
5847       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5848         (String.uppercase shortname);
5849       pr "    guestfs___end_busy (g);\n";
5850       pr "    return %s;\n" error_code;
5851       pr "  }\n";
5852       pr "\n";
5853
5854       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5855       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5856       pr "    free (err.error_message);\n";
5857       pr "    guestfs___end_busy (g);\n";
5858       pr "    return %s;\n" error_code;
5859       pr "  }\n";
5860       pr "\n";
5861
5862       (* Expecting to receive further files (FileOut)? *)
5863       List.iter (
5864         function
5865         | FileOut n ->
5866             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5867             pr "    guestfs___end_busy (g);\n";
5868             pr "    return %s;\n" error_code;
5869             pr "  }\n";
5870             pr "\n";
5871         | _ -> ()
5872       ) (snd style);
5873
5874       pr "  guestfs___end_busy (g);\n";
5875
5876       (match fst style with
5877        | RErr -> pr "  return 0;\n"
5878        | RInt n | RInt64 n | RBool n ->
5879            pr "  return ret.%s;\n" n
5880        | RConstString _ | RConstOptString _ ->
5881            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5882        | RString n ->
5883            pr "  return ret.%s; /* caller will free */\n" n
5884        | RStringList n | RHashtable n ->
5885            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5886            pr "  ret.%s.%s_val =\n" n n;
5887            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5888            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5889              n n;
5890            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5891            pr "  return ret.%s.%s_val;\n" n n
5892        | RStruct (n, _) ->
5893            pr "  /* caller will free this */\n";
5894            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5895        | RStructList (n, _) ->
5896            pr "  /* caller will free this */\n";
5897            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5898        | RBufferOut n ->
5899            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5900            pr "   * _val might be NULL here.  To make the API saner for\n";
5901            pr "   * callers, we turn this case into a unique pointer (using\n";
5902            pr "   * malloc(1)).\n";
5903            pr "   */\n";
5904            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5905            pr "    *size_r = ret.%s.%s_len;\n" n n;
5906            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5907            pr "  } else {\n";
5908            pr "    free (ret.%s.%s_val);\n" n n;
5909            pr "    char *p = safe_malloc (g, 1);\n";
5910            pr "    *size_r = ret.%s.%s_len;\n" n n;
5911            pr "    return p;\n";
5912            pr "  }\n";
5913       );
5914
5915       pr "}\n\n"
5916   ) daemon_functions;
5917
5918   (* Functions to free structures. *)
5919   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5920   pr " * structure format is identical to the XDR format.  See note in\n";
5921   pr " * generator.ml.\n";
5922   pr " */\n";
5923   pr "\n";
5924
5925   List.iter (
5926     fun (typ, _) ->
5927       pr "void\n";
5928       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5929       pr "{\n";
5930       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5931       pr "  free (x);\n";
5932       pr "}\n";
5933       pr "\n";
5934
5935       pr "void\n";
5936       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5937       pr "{\n";
5938       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
5939       pr "  free (x);\n";
5940       pr "}\n";
5941       pr "\n";
5942
5943   ) structs;
5944
5945 (* Generate daemon/actions.h. *)
5946 and generate_daemon_actions_h () =
5947   generate_header CStyle GPLv2plus;
5948
5949   pr "#include \"../src/guestfs_protocol.h\"\n";
5950   pr "\n";
5951
5952   List.iter (
5953     fun (name, style, _, _, _, _, _) ->
5954       generate_prototype
5955         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
5956         name style;
5957   ) daemon_functions
5958
5959 (* Generate the linker script which controls the visibility of
5960  * symbols in the public ABI and ensures no other symbols get
5961  * exported accidentally.
5962  *)
5963 and generate_linker_script () =
5964   generate_header HashStyle GPLv2plus;
5965
5966   let globals = [
5967     "guestfs_create";
5968     "guestfs_close";
5969     "guestfs_get_error_handler";
5970     "guestfs_get_out_of_memory_handler";
5971     "guestfs_last_error";
5972     "guestfs_set_error_handler";
5973     "guestfs_set_launch_done_callback";
5974     "guestfs_set_log_message_callback";
5975     "guestfs_set_out_of_memory_handler";
5976     "guestfs_set_subprocess_quit_callback";
5977
5978     (* Unofficial parts of the API: the bindings code use these
5979      * functions, so it is useful to export them.
5980      *)
5981     "guestfs_safe_calloc";
5982     "guestfs_safe_malloc";
5983   ] in
5984   let functions =
5985     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
5986       all_functions in
5987   let structs =
5988     List.concat (
5989       List.map (fun (typ, _) ->
5990                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
5991         structs
5992     ) in
5993   let globals = List.sort compare (globals @ functions @ structs) in
5994
5995   pr "{\n";
5996   pr "    global:\n";
5997   List.iter (pr "        %s;\n") globals;
5998   pr "\n";
5999
6000   pr "    local:\n";
6001   pr "        *;\n";
6002   pr "};\n"
6003
6004 (* Generate the server-side stubs. *)
6005 and generate_daemon_actions () =
6006   generate_header CStyle GPLv2plus;
6007
6008   pr "#include <config.h>\n";
6009   pr "\n";
6010   pr "#include <stdio.h>\n";
6011   pr "#include <stdlib.h>\n";
6012   pr "#include <string.h>\n";
6013   pr "#include <inttypes.h>\n";
6014   pr "#include <rpc/types.h>\n";
6015   pr "#include <rpc/xdr.h>\n";
6016   pr "\n";
6017   pr "#include \"daemon.h\"\n";
6018   pr "#include \"c-ctype.h\"\n";
6019   pr "#include \"../src/guestfs_protocol.h\"\n";
6020   pr "#include \"actions.h\"\n";
6021   pr "\n";
6022
6023   List.iter (
6024     fun (name, style, _, _, _, _, _) ->
6025       (* Generate server-side stubs. *)
6026       pr "static void %s_stub (XDR *xdr_in)\n" name;
6027       pr "{\n";
6028       let error_code =
6029         match fst style with
6030         | RErr | RInt _ -> pr "  int r;\n"; "-1"
6031         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6032         | RBool _ -> pr "  int r;\n"; "-1"
6033         | RConstString _ | RConstOptString _ ->
6034             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6035         | RString _ -> pr "  char *r;\n"; "NULL"
6036         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6037         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
6038         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
6039         | RBufferOut _ ->
6040             pr "  size_t size = 1;\n";
6041             pr "  char *r;\n";
6042             "NULL" in
6043
6044       (match snd style with
6045        | [] -> ()
6046        | args ->
6047            pr "  struct guestfs_%s_args args;\n" name;
6048            List.iter (
6049              function
6050              | Device n | Dev_or_Path n
6051              | Pathname n
6052              | String n -> ()
6053              | OptString n -> pr "  char *%s;\n" n
6054              | StringList n | DeviceList n -> pr "  char **%s;\n" n
6055              | Bool n -> pr "  int %s;\n" n
6056              | Int n -> pr "  int %s;\n" n
6057              | Int64 n -> pr "  int64_t %s;\n" n
6058              | FileIn _ | FileOut _ -> ()
6059            ) args
6060       );
6061       pr "\n";
6062
6063       let is_filein =
6064         List.exists (function FileIn _ -> true | _ -> false) (snd style) in
6065
6066       (match snd style with
6067        | [] -> ()
6068        | args ->
6069            pr "  memset (&args, 0, sizeof args);\n";
6070            pr "\n";
6071            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
6072            if is_filein then
6073              pr "    cancel_receive ();\n";
6074            pr "    reply_with_error (\"daemon failed to decode procedure arguments\");\n";
6075            pr "    goto done;\n";
6076            pr "  }\n";
6077            let pr_args n =
6078              pr "  char *%s = args.%s;\n" n n
6079            in
6080            let pr_list_handling_code n =
6081              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
6082              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
6083              pr "  if (%s == NULL) {\n" n;
6084              if is_filein then
6085                pr "    cancel_receive ();\n";
6086              pr "    reply_with_perror (\"realloc\");\n";
6087              pr "    goto done;\n";
6088              pr "  }\n";
6089              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
6090              pr "  args.%s.%s_val = %s;\n" n n n;
6091            in
6092            List.iter (
6093              function
6094              | Pathname n ->
6095                  pr_args n;
6096                  pr "  ABS_PATH (%s, %s, goto done);\n"
6097                    n (if is_filein then "cancel_receive ()" else "");
6098              | Device n ->
6099                  pr_args n;
6100                  pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
6101                    n (if is_filein then "cancel_receive ()" else "");
6102              | Dev_or_Path n ->
6103                  pr_args n;
6104                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
6105                    n (if is_filein then "cancel_receive ()" else "");
6106              | String n -> pr_args n
6107              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
6108              | StringList n ->
6109                  pr_list_handling_code n;
6110              | DeviceList n ->
6111                  pr_list_handling_code n;
6112                  pr "  /* Ensure that each is a device,\n";
6113                  pr "   * and perform device name translation. */\n";
6114                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
6115                  pr "    RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n"
6116                    (if is_filein then "cancel_receive ()" else "");
6117                  pr "  }\n";
6118              | Bool n -> pr "  %s = args.%s;\n" n n
6119              | Int n -> pr "  %s = args.%s;\n" n n
6120              | Int64 n -> pr "  %s = args.%s;\n" n n
6121              | FileIn _ | FileOut _ -> ()
6122            ) args;
6123            pr "\n"
6124       );
6125
6126
6127       (* this is used at least for do_equal *)
6128       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
6129         (* Emit NEED_ROOT just once, even when there are two or
6130            more Pathname args *)
6131         pr "  NEED_ROOT (%s, goto done);\n"
6132           (if is_filein then "cancel_receive ()" else "");
6133       );
6134
6135       (* Don't want to call the impl with any FileIn or FileOut
6136        * parameters, since these go "outside" the RPC protocol.
6137        *)
6138       let args' =
6139         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
6140           (snd style) in
6141       pr "  r = do_%s " name;
6142       generate_c_call_args (fst style, args');
6143       pr ";\n";
6144
6145       (match fst style with
6146        | RErr | RInt _ | RInt64 _ | RBool _
6147        | RConstString _ | RConstOptString _
6148        | RString _ | RStringList _ | RHashtable _
6149        | RStruct (_, _) | RStructList (_, _) ->
6150            pr "  if (r == %s)\n" error_code;
6151            pr "    /* do_%s has already called reply_with_error */\n" name;
6152            pr "    goto done;\n";
6153            pr "\n"
6154        | RBufferOut _ ->
6155            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
6156            pr "   * an ordinary zero-length buffer), so be careful ...\n";
6157            pr "   */\n";
6158            pr "  if (size == 1 && r == %s)\n" error_code;
6159            pr "    /* do_%s has already called reply_with_error */\n" name;
6160            pr "    goto done;\n";
6161            pr "\n"
6162       );
6163
6164       (* If there are any FileOut parameters, then the impl must
6165        * send its own reply.
6166        *)
6167       let no_reply =
6168         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
6169       if no_reply then
6170         pr "  /* do_%s has already sent a reply */\n" name
6171       else (
6172         match fst style with
6173         | RErr -> pr "  reply (NULL, NULL);\n"
6174         | RInt n | RInt64 n | RBool n ->
6175             pr "  struct guestfs_%s_ret ret;\n" name;
6176             pr "  ret.%s = r;\n" n;
6177             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6178               name
6179         | RConstString _ | RConstOptString _ ->
6180             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6181         | RString n ->
6182             pr "  struct guestfs_%s_ret ret;\n" name;
6183             pr "  ret.%s = r;\n" n;
6184             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6185               name;
6186             pr "  free (r);\n"
6187         | RStringList n | RHashtable n ->
6188             pr "  struct guestfs_%s_ret ret;\n" name;
6189             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
6190             pr "  ret.%s.%s_val = r;\n" n n;
6191             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6192               name;
6193             pr "  free_strings (r);\n"
6194         | RStruct (n, _) ->
6195             pr "  struct guestfs_%s_ret ret;\n" name;
6196             pr "  ret.%s = *r;\n" n;
6197             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6198               name;
6199             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6200               name
6201         | RStructList (n, _) ->
6202             pr "  struct guestfs_%s_ret ret;\n" name;
6203             pr "  ret.%s = *r;\n" n;
6204             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6205               name;
6206             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6207               name
6208         | RBufferOut n ->
6209             pr "  struct guestfs_%s_ret ret;\n" name;
6210             pr "  ret.%s.%s_val = r;\n" n n;
6211             pr "  ret.%s.%s_len = size;\n" n n;
6212             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6213               name;
6214             pr "  free (r);\n"
6215       );
6216
6217       (* Free the args. *)
6218       pr "done:\n";
6219       (match snd style with
6220        | [] -> ()
6221        | _ ->
6222            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
6223              name
6224       );
6225       pr "  return;\n";
6226       pr "}\n\n";
6227   ) daemon_functions;
6228
6229   (* Dispatch function. *)
6230   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
6231   pr "{\n";
6232   pr "  switch (proc_nr) {\n";
6233
6234   List.iter (
6235     fun (name, style, _, _, _, _, _) ->
6236       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
6237       pr "      %s_stub (xdr_in);\n" name;
6238       pr "      break;\n"
6239   ) daemon_functions;
6240
6241   pr "    default:\n";
6242   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";
6243   pr "  }\n";
6244   pr "}\n";
6245   pr "\n";
6246
6247   (* LVM columns and tokenization functions. *)
6248   (* XXX This generates crap code.  We should rethink how we
6249    * do this parsing.
6250    *)
6251   List.iter (
6252     function
6253     | typ, cols ->
6254         pr "static const char *lvm_%s_cols = \"%s\";\n"
6255           typ (String.concat "," (List.map fst cols));
6256         pr "\n";
6257
6258         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
6259         pr "{\n";
6260         pr "  char *tok, *p, *next;\n";
6261         pr "  int i, j;\n";
6262         pr "\n";
6263         (*
6264           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
6265           pr "\n";
6266         *)
6267         pr "  if (!str) {\n";
6268         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
6269         pr "    return -1;\n";
6270         pr "  }\n";
6271         pr "  if (!*str || c_isspace (*str)) {\n";
6272         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
6273         pr "    return -1;\n";
6274         pr "  }\n";
6275         pr "  tok = str;\n";
6276         List.iter (
6277           fun (name, coltype) ->
6278             pr "  if (!tok) {\n";
6279             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
6280             pr "    return -1;\n";
6281             pr "  }\n";
6282             pr "  p = strchrnul (tok, ',');\n";
6283             pr "  if (*p) next = p+1; else next = NULL;\n";
6284             pr "  *p = '\\0';\n";
6285             (match coltype with
6286              | FString ->
6287                  pr "  r->%s = strdup (tok);\n" name;
6288                  pr "  if (r->%s == NULL) {\n" name;
6289                  pr "    perror (\"strdup\");\n";
6290                  pr "    return -1;\n";
6291                  pr "  }\n"
6292              | FUUID ->
6293                  pr "  for (i = j = 0; i < 32; ++j) {\n";
6294                  pr "    if (tok[j] == '\\0') {\n";
6295                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
6296                  pr "      return -1;\n";
6297                  pr "    } else if (tok[j] != '-')\n";
6298                  pr "      r->%s[i++] = tok[j];\n" name;
6299                  pr "  }\n";
6300              | FBytes ->
6301                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
6302                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6303                  pr "    return -1;\n";
6304                  pr "  }\n";
6305              | FInt64 ->
6306                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
6307                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6308                  pr "    return -1;\n";
6309                  pr "  }\n";
6310              | FOptPercent ->
6311                  pr "  if (tok[0] == '\\0')\n";
6312                  pr "    r->%s = -1;\n" name;
6313                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
6314                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6315                  pr "    return -1;\n";
6316                  pr "  }\n";
6317              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
6318                  assert false (* can never be an LVM column *)
6319             );
6320             pr "  tok = next;\n";
6321         ) cols;
6322
6323         pr "  if (tok != NULL) {\n";
6324         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6325         pr "    return -1;\n";
6326         pr "  }\n";
6327         pr "  return 0;\n";
6328         pr "}\n";
6329         pr "\n";
6330
6331         pr "guestfs_int_lvm_%s_list *\n" typ;
6332         pr "parse_command_line_%ss (void)\n" typ;
6333         pr "{\n";
6334         pr "  char *out, *err;\n";
6335         pr "  char *p, *pend;\n";
6336         pr "  int r, i;\n";
6337         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6338         pr "  void *newp;\n";
6339         pr "\n";
6340         pr "  ret = malloc (sizeof *ret);\n";
6341         pr "  if (!ret) {\n";
6342         pr "    reply_with_perror (\"malloc\");\n";
6343         pr "    return NULL;\n";
6344         pr "  }\n";
6345         pr "\n";
6346         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6347         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6348         pr "\n";
6349         pr "  r = command (&out, &err,\n";
6350         pr "           \"lvm\", \"%ss\",\n" typ;
6351         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6352         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6353         pr "  if (r == -1) {\n";
6354         pr "    reply_with_error (\"%%s\", err);\n";
6355         pr "    free (out);\n";
6356         pr "    free (err);\n";
6357         pr "    free (ret);\n";
6358         pr "    return NULL;\n";
6359         pr "  }\n";
6360         pr "\n";
6361         pr "  free (err);\n";
6362         pr "\n";
6363         pr "  /* Tokenize each line of the output. */\n";
6364         pr "  p = out;\n";
6365         pr "  i = 0;\n";
6366         pr "  while (p) {\n";
6367         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6368         pr "    if (pend) {\n";
6369         pr "      *pend = '\\0';\n";
6370         pr "      pend++;\n";
6371         pr "    }\n";
6372         pr "\n";
6373         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6374         pr "      p++;\n";
6375         pr "\n";
6376         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6377         pr "      p = pend;\n";
6378         pr "      continue;\n";
6379         pr "    }\n";
6380         pr "\n";
6381         pr "    /* Allocate some space to store this next entry. */\n";
6382         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6383         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6384         pr "    if (newp == NULL) {\n";
6385         pr "      reply_with_perror (\"realloc\");\n";
6386         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6387         pr "      free (ret);\n";
6388         pr "      free (out);\n";
6389         pr "      return NULL;\n";
6390         pr "    }\n";
6391         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6392         pr "\n";
6393         pr "    /* Tokenize the next entry. */\n";
6394         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6395         pr "    if (r == -1) {\n";
6396         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6397         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6398         pr "      free (ret);\n";
6399         pr "      free (out);\n";
6400         pr "      return NULL;\n";
6401         pr "    }\n";
6402         pr "\n";
6403         pr "    ++i;\n";
6404         pr "    p = pend;\n";
6405         pr "  }\n";
6406         pr "\n";
6407         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6408         pr "\n";
6409         pr "  free (out);\n";
6410         pr "  return ret;\n";
6411         pr "}\n"
6412
6413   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6414
6415 (* Generate a list of function names, for debugging in the daemon.. *)
6416 and generate_daemon_names () =
6417   generate_header CStyle GPLv2plus;
6418
6419   pr "#include <config.h>\n";
6420   pr "\n";
6421   pr "#include \"daemon.h\"\n";
6422   pr "\n";
6423
6424   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6425   pr "const char *function_names[] = {\n";
6426   List.iter (
6427     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6428   ) daemon_functions;
6429   pr "};\n";
6430
6431 (* Generate the optional groups for the daemon to implement
6432  * guestfs_available.
6433  *)
6434 and generate_daemon_optgroups_c () =
6435   generate_header CStyle GPLv2plus;
6436
6437   pr "#include <config.h>\n";
6438   pr "\n";
6439   pr "#include \"daemon.h\"\n";
6440   pr "#include \"optgroups.h\"\n";
6441   pr "\n";
6442
6443   pr "struct optgroup optgroups[] = {\n";
6444   List.iter (
6445     fun (group, _) ->
6446       pr "  { \"%s\", optgroup_%s_available },\n" group group
6447   ) optgroups;
6448   pr "  { NULL, NULL }\n";
6449   pr "};\n"
6450
6451 and generate_daemon_optgroups_h () =
6452   generate_header CStyle GPLv2plus;
6453
6454   List.iter (
6455     fun (group, _) ->
6456       pr "extern int optgroup_%s_available (void);\n" group
6457   ) optgroups
6458
6459 (* Generate the tests. *)
6460 and generate_tests () =
6461   generate_header CStyle GPLv2plus;
6462
6463   pr "\
6464 #include <stdio.h>
6465 #include <stdlib.h>
6466 #include <string.h>
6467 #include <unistd.h>
6468 #include <sys/types.h>
6469 #include <fcntl.h>
6470
6471 #include \"guestfs.h\"
6472 #include \"guestfs-internal.h\"
6473
6474 static guestfs_h *g;
6475 static int suppress_error = 0;
6476
6477 static void print_error (guestfs_h *g, void *data, const char *msg)
6478 {
6479   if (!suppress_error)
6480     fprintf (stderr, \"%%s\\n\", msg);
6481 }
6482
6483 /* FIXME: nearly identical code appears in fish.c */
6484 static void print_strings (char *const *argv)
6485 {
6486   int argc;
6487
6488   for (argc = 0; argv[argc] != NULL; ++argc)
6489     printf (\"\\t%%s\\n\", argv[argc]);
6490 }
6491
6492 /*
6493 static void print_table (char const *const *argv)
6494 {
6495   int i;
6496
6497   for (i = 0; argv[i] != NULL; i += 2)
6498     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6499 }
6500 */
6501
6502 ";
6503
6504   (* Generate a list of commands which are not tested anywhere. *)
6505   pr "static void no_test_warnings (void)\n";
6506   pr "{\n";
6507
6508   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6509   List.iter (
6510     fun (_, _, _, _, tests, _, _) ->
6511       let tests = filter_map (
6512         function
6513         | (_, (Always|If _|Unless _), test) -> Some test
6514         | (_, Disabled, _) -> None
6515       ) tests in
6516       let seq = List.concat (List.map seq_of_test tests) in
6517       let cmds_tested = List.map List.hd seq in
6518       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6519   ) all_functions;
6520
6521   List.iter (
6522     fun (name, _, _, _, _, _, _) ->
6523       if not (Hashtbl.mem hash name) then
6524         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6525   ) all_functions;
6526
6527   pr "}\n";
6528   pr "\n";
6529
6530   (* Generate the actual tests.  Note that we generate the tests
6531    * in reverse order, deliberately, so that (in general) the
6532    * newest tests run first.  This makes it quicker and easier to
6533    * debug them.
6534    *)
6535   let test_names =
6536     List.map (
6537       fun (name, _, _, flags, tests, _, _) ->
6538         mapi (generate_one_test name flags) tests
6539     ) (List.rev all_functions) in
6540   let test_names = List.concat test_names in
6541   let nr_tests = List.length test_names in
6542
6543   pr "\
6544 int main (int argc, char *argv[])
6545 {
6546   char c = 0;
6547   unsigned long int n_failed = 0;
6548   const char *filename;
6549   int fd;
6550   int nr_tests, test_num = 0;
6551
6552   setbuf (stdout, NULL);
6553
6554   no_test_warnings ();
6555
6556   g = guestfs_create ();
6557   if (g == NULL) {
6558     printf (\"guestfs_create FAILED\\n\");
6559     exit (EXIT_FAILURE);
6560   }
6561
6562   guestfs_set_error_handler (g, print_error, NULL);
6563
6564   guestfs_set_path (g, \"../appliance\");
6565
6566   filename = \"test1.img\";
6567   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6568   if (fd == -1) {
6569     perror (filename);
6570     exit (EXIT_FAILURE);
6571   }
6572   if (lseek (fd, %d, SEEK_SET) == -1) {
6573     perror (\"lseek\");
6574     close (fd);
6575     unlink (filename);
6576     exit (EXIT_FAILURE);
6577   }
6578   if (write (fd, &c, 1) == -1) {
6579     perror (\"write\");
6580     close (fd);
6581     unlink (filename);
6582     exit (EXIT_FAILURE);
6583   }
6584   if (close (fd) == -1) {
6585     perror (filename);
6586     unlink (filename);
6587     exit (EXIT_FAILURE);
6588   }
6589   if (guestfs_add_drive (g, filename) == -1) {
6590     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6591     exit (EXIT_FAILURE);
6592   }
6593
6594   filename = \"test2.img\";
6595   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6596   if (fd == -1) {
6597     perror (filename);
6598     exit (EXIT_FAILURE);
6599   }
6600   if (lseek (fd, %d, SEEK_SET) == -1) {
6601     perror (\"lseek\");
6602     close (fd);
6603     unlink (filename);
6604     exit (EXIT_FAILURE);
6605   }
6606   if (write (fd, &c, 1) == -1) {
6607     perror (\"write\");
6608     close (fd);
6609     unlink (filename);
6610     exit (EXIT_FAILURE);
6611   }
6612   if (close (fd) == -1) {
6613     perror (filename);
6614     unlink (filename);
6615     exit (EXIT_FAILURE);
6616   }
6617   if (guestfs_add_drive (g, filename) == -1) {
6618     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6619     exit (EXIT_FAILURE);
6620   }
6621
6622   filename = \"test3.img\";
6623   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6624   if (fd == -1) {
6625     perror (filename);
6626     exit (EXIT_FAILURE);
6627   }
6628   if (lseek (fd, %d, SEEK_SET) == -1) {
6629     perror (\"lseek\");
6630     close (fd);
6631     unlink (filename);
6632     exit (EXIT_FAILURE);
6633   }
6634   if (write (fd, &c, 1) == -1) {
6635     perror (\"write\");
6636     close (fd);
6637     unlink (filename);
6638     exit (EXIT_FAILURE);
6639   }
6640   if (close (fd) == -1) {
6641     perror (filename);
6642     unlink (filename);
6643     exit (EXIT_FAILURE);
6644   }
6645   if (guestfs_add_drive (g, filename) == -1) {
6646     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6647     exit (EXIT_FAILURE);
6648   }
6649
6650   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6651     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6652     exit (EXIT_FAILURE);
6653   }
6654
6655   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6656   alarm (600);
6657
6658   if (guestfs_launch (g) == -1) {
6659     printf (\"guestfs_launch FAILED\\n\");
6660     exit (EXIT_FAILURE);
6661   }
6662
6663   /* Cancel previous alarm. */
6664   alarm (0);
6665
6666   nr_tests = %d;
6667
6668 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6669
6670   iteri (
6671     fun i test_name ->
6672       pr "  test_num++;\n";
6673       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6674       pr "  if (%s () == -1) {\n" test_name;
6675       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6676       pr "    n_failed++;\n";
6677       pr "  }\n";
6678   ) test_names;
6679   pr "\n";
6680
6681   pr "  guestfs_close (g);\n";
6682   pr "  unlink (\"test1.img\");\n";
6683   pr "  unlink (\"test2.img\");\n";
6684   pr "  unlink (\"test3.img\");\n";
6685   pr "\n";
6686
6687   pr "  if (n_failed > 0) {\n";
6688   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6689   pr "    exit (EXIT_FAILURE);\n";
6690   pr "  }\n";
6691   pr "\n";
6692
6693   pr "  exit (EXIT_SUCCESS);\n";
6694   pr "}\n"
6695
6696 and generate_one_test name flags i (init, prereq, test) =
6697   let test_name = sprintf "test_%s_%d" name i in
6698
6699   pr "\
6700 static int %s_skip (void)
6701 {
6702   const char *str;
6703
6704   str = getenv (\"TEST_ONLY\");
6705   if (str)
6706     return strstr (str, \"%s\") == NULL;
6707   str = getenv (\"SKIP_%s\");
6708   if (str && STREQ (str, \"1\")) return 1;
6709   str = getenv (\"SKIP_TEST_%s\");
6710   if (str && STREQ (str, \"1\")) return 1;
6711   return 0;
6712 }
6713
6714 " test_name name (String.uppercase test_name) (String.uppercase name);
6715
6716   (match prereq with
6717    | Disabled | Always -> ()
6718    | If code | Unless code ->
6719        pr "static int %s_prereq (void)\n" test_name;
6720        pr "{\n";
6721        pr "  %s\n" code;
6722        pr "}\n";
6723        pr "\n";
6724   );
6725
6726   pr "\
6727 static int %s (void)
6728 {
6729   if (%s_skip ()) {
6730     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6731     return 0;
6732   }
6733
6734 " test_name test_name test_name;
6735
6736   (* Optional functions should only be tested if the relevant
6737    * support is available in the daemon.
6738    *)
6739   List.iter (
6740     function
6741     | Optional group ->
6742         pr "  {\n";
6743         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6744         pr "    int r;\n";
6745         pr "    suppress_error = 1;\n";
6746         pr "    r = guestfs_available (g, (char **) groups);\n";
6747         pr "    suppress_error = 0;\n";
6748         pr "    if (r == -1) {\n";
6749         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6750         pr "      return 0;\n";
6751         pr "    }\n";
6752         pr "  }\n";
6753     | _ -> ()
6754   ) flags;
6755
6756   (match prereq with
6757    | Disabled ->
6758        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6759    | If _ ->
6760        pr "  if (! %s_prereq ()) {\n" test_name;
6761        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6762        pr "    return 0;\n";
6763        pr "  }\n";
6764        pr "\n";
6765        generate_one_test_body name i test_name init test;
6766    | Unless _ ->
6767        pr "  if (%s_prereq ()) {\n" test_name;
6768        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6769        pr "    return 0;\n";
6770        pr "  }\n";
6771        pr "\n";
6772        generate_one_test_body name i test_name init test;
6773    | Always ->
6774        generate_one_test_body name i test_name init test
6775   );
6776
6777   pr "  return 0;\n";
6778   pr "}\n";
6779   pr "\n";
6780   test_name
6781
6782 and generate_one_test_body name i test_name init test =
6783   (match init with
6784    | InitNone (* XXX at some point, InitNone and InitEmpty became
6785                * folded together as the same thing.  Really we should
6786                * make InitNone do nothing at all, but the tests may
6787                * need to be checked to make sure this is OK.
6788                *)
6789    | InitEmpty ->
6790        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6791        List.iter (generate_test_command_call test_name)
6792          [["blockdev_setrw"; "/dev/sda"];
6793           ["umount_all"];
6794           ["lvm_remove_all"]]
6795    | InitPartition ->
6796        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6797        List.iter (generate_test_command_call test_name)
6798          [["blockdev_setrw"; "/dev/sda"];
6799           ["umount_all"];
6800           ["lvm_remove_all"];
6801           ["part_disk"; "/dev/sda"; "mbr"]]
6802    | InitBasicFS ->
6803        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6804        List.iter (generate_test_command_call test_name)
6805          [["blockdev_setrw"; "/dev/sda"];
6806           ["umount_all"];
6807           ["lvm_remove_all"];
6808           ["part_disk"; "/dev/sda"; "mbr"];
6809           ["mkfs"; "ext2"; "/dev/sda1"];
6810           ["mount_options"; ""; "/dev/sda1"; "/"]]
6811    | InitBasicFSonLVM ->
6812        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6813          test_name;
6814        List.iter (generate_test_command_call test_name)
6815          [["blockdev_setrw"; "/dev/sda"];
6816           ["umount_all"];
6817           ["lvm_remove_all"];
6818           ["part_disk"; "/dev/sda"; "mbr"];
6819           ["pvcreate"; "/dev/sda1"];
6820           ["vgcreate"; "VG"; "/dev/sda1"];
6821           ["lvcreate"; "LV"; "VG"; "8"];
6822           ["mkfs"; "ext2"; "/dev/VG/LV"];
6823           ["mount_options"; ""; "/dev/VG/LV"; "/"]]
6824    | InitISOFS ->
6825        pr "  /* InitISOFS for %s */\n" test_name;
6826        List.iter (generate_test_command_call test_name)
6827          [["blockdev_setrw"; "/dev/sda"];
6828           ["umount_all"];
6829           ["lvm_remove_all"];
6830           ["mount_ro"; "/dev/sdd"; "/"]]
6831   );
6832
6833   let get_seq_last = function
6834     | [] ->
6835         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6836           test_name
6837     | seq ->
6838         let seq = List.rev seq in
6839         List.rev (List.tl seq), List.hd seq
6840   in
6841
6842   match test with
6843   | TestRun seq ->
6844       pr "  /* TestRun for %s (%d) */\n" name i;
6845       List.iter (generate_test_command_call test_name) seq
6846   | TestOutput (seq, expected) ->
6847       pr "  /* TestOutput for %s (%d) */\n" name i;
6848       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6849       let seq, last = get_seq_last seq in
6850       let test () =
6851         pr "    if (STRNEQ (r, expected)) {\n";
6852         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6853         pr "      return -1;\n";
6854         pr "    }\n"
6855       in
6856       List.iter (generate_test_command_call test_name) seq;
6857       generate_test_command_call ~test test_name last
6858   | TestOutputList (seq, expected) ->
6859       pr "  /* TestOutputList for %s (%d) */\n" name i;
6860       let seq, last = get_seq_last seq in
6861       let test () =
6862         iteri (
6863           fun i str ->
6864             pr "    if (!r[%d]) {\n" i;
6865             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6866             pr "      print_strings (r);\n";
6867             pr "      return -1;\n";
6868             pr "    }\n";
6869             pr "    {\n";
6870             pr "      const char *expected = \"%s\";\n" (c_quote str);
6871             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6872             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6873             pr "        return -1;\n";
6874             pr "      }\n";
6875             pr "    }\n"
6876         ) expected;
6877         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6878         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6879           test_name;
6880         pr "      print_strings (r);\n";
6881         pr "      return -1;\n";
6882         pr "    }\n"
6883       in
6884       List.iter (generate_test_command_call test_name) seq;
6885       generate_test_command_call ~test test_name last
6886   | TestOutputListOfDevices (seq, expected) ->
6887       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6888       let seq, last = get_seq_last seq in
6889       let test () =
6890         iteri (
6891           fun i str ->
6892             pr "    if (!r[%d]) {\n" i;
6893             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6894             pr "      print_strings (r);\n";
6895             pr "      return -1;\n";
6896             pr "    }\n";
6897             pr "    {\n";
6898             pr "      const char *expected = \"%s\";\n" (c_quote str);
6899             pr "      r[%d][5] = 's';\n" i;
6900             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6901             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6902             pr "        return -1;\n";
6903             pr "      }\n";
6904             pr "    }\n"
6905         ) expected;
6906         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6907         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6908           test_name;
6909         pr "      print_strings (r);\n";
6910         pr "      return -1;\n";
6911         pr "    }\n"
6912       in
6913       List.iter (generate_test_command_call test_name) seq;
6914       generate_test_command_call ~test test_name last
6915   | TestOutputInt (seq, expected) ->
6916       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6917       let seq, last = get_seq_last seq in
6918       let test () =
6919         pr "    if (r != %d) {\n" expected;
6920         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6921           test_name expected;
6922         pr "               (int) r);\n";
6923         pr "      return -1;\n";
6924         pr "    }\n"
6925       in
6926       List.iter (generate_test_command_call test_name) seq;
6927       generate_test_command_call ~test test_name last
6928   | TestOutputIntOp (seq, op, expected) ->
6929       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6930       let seq, last = get_seq_last seq in
6931       let test () =
6932         pr "    if (! (r %s %d)) {\n" op expected;
6933         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6934           test_name op expected;
6935         pr "               (int) r);\n";
6936         pr "      return -1;\n";
6937         pr "    }\n"
6938       in
6939       List.iter (generate_test_command_call test_name) seq;
6940       generate_test_command_call ~test test_name last
6941   | TestOutputTrue seq ->
6942       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
6943       let seq, last = get_seq_last seq in
6944       let test () =
6945         pr "    if (!r) {\n";
6946         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
6947           test_name;
6948         pr "      return -1;\n";
6949         pr "    }\n"
6950       in
6951       List.iter (generate_test_command_call test_name) seq;
6952       generate_test_command_call ~test test_name last
6953   | TestOutputFalse seq ->
6954       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
6955       let seq, last = get_seq_last seq in
6956       let test () =
6957         pr "    if (r) {\n";
6958         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
6959           test_name;
6960         pr "      return -1;\n";
6961         pr "    }\n"
6962       in
6963       List.iter (generate_test_command_call test_name) seq;
6964       generate_test_command_call ~test test_name last
6965   | TestOutputLength (seq, expected) ->
6966       pr "  /* TestOutputLength for %s (%d) */\n" name i;
6967       let seq, last = get_seq_last seq in
6968       let test () =
6969         pr "    int j;\n";
6970         pr "    for (j = 0; j < %d; ++j)\n" expected;
6971         pr "      if (r[j] == NULL) {\n";
6972         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
6973           test_name;
6974         pr "        print_strings (r);\n";
6975         pr "        return -1;\n";
6976         pr "      }\n";
6977         pr "    if (r[j] != NULL) {\n";
6978         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
6979           test_name;
6980         pr "      print_strings (r);\n";
6981         pr "      return -1;\n";
6982         pr "    }\n"
6983       in
6984       List.iter (generate_test_command_call test_name) seq;
6985       generate_test_command_call ~test test_name last
6986   | TestOutputBuffer (seq, expected) ->
6987       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
6988       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6989       let seq, last = get_seq_last seq in
6990       let len = String.length expected in
6991       let test () =
6992         pr "    if (size != %d) {\n" len;
6993         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
6994         pr "      return -1;\n";
6995         pr "    }\n";
6996         pr "    if (STRNEQLEN (r, expected, size)) {\n";
6997         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6998         pr "      return -1;\n";
6999         pr "    }\n"
7000       in
7001       List.iter (generate_test_command_call test_name) seq;
7002       generate_test_command_call ~test test_name last
7003   | TestOutputStruct (seq, checks) ->
7004       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
7005       let seq, last = get_seq_last seq in
7006       let test () =
7007         List.iter (
7008           function
7009           | CompareWithInt (field, expected) ->
7010               pr "    if (r->%s != %d) {\n" field expected;
7011               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
7012                 test_name field expected;
7013               pr "               (int) r->%s);\n" field;
7014               pr "      return -1;\n";
7015               pr "    }\n"
7016           | CompareWithIntOp (field, op, expected) ->
7017               pr "    if (!(r->%s %s %d)) {\n" field op expected;
7018               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
7019                 test_name field op expected;
7020               pr "               (int) r->%s);\n" field;
7021               pr "      return -1;\n";
7022               pr "    }\n"
7023           | CompareWithString (field, expected) ->
7024               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
7025               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
7026                 test_name field expected;
7027               pr "               r->%s);\n" field;
7028               pr "      return -1;\n";
7029               pr "    }\n"
7030           | CompareFieldsIntEq (field1, field2) ->
7031               pr "    if (r->%s != r->%s) {\n" field1 field2;
7032               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
7033                 test_name field1 field2;
7034               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
7035               pr "      return -1;\n";
7036               pr "    }\n"
7037           | CompareFieldsStrEq (field1, field2) ->
7038               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
7039               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
7040                 test_name field1 field2;
7041               pr "               r->%s, r->%s);\n" field1 field2;
7042               pr "      return -1;\n";
7043               pr "    }\n"
7044         ) checks
7045       in
7046       List.iter (generate_test_command_call test_name) seq;
7047       generate_test_command_call ~test test_name last
7048   | TestLastFail seq ->
7049       pr "  /* TestLastFail for %s (%d) */\n" name i;
7050       let seq, last = get_seq_last seq in
7051       List.iter (generate_test_command_call test_name) seq;
7052       generate_test_command_call test_name ~expect_error:true last
7053
7054 (* Generate the code to run a command, leaving the result in 'r'.
7055  * If you expect to get an error then you should set expect_error:true.
7056  *)
7057 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
7058   match cmd with
7059   | [] -> assert false
7060   | name :: args ->
7061       (* Look up the command to find out what args/ret it has. *)
7062       let style =
7063         try
7064           let _, style, _, _, _, _, _ =
7065             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
7066           style
7067         with Not_found ->
7068           failwithf "%s: in test, command %s was not found" test_name name in
7069
7070       if List.length (snd style) <> List.length args then
7071         failwithf "%s: in test, wrong number of args given to %s"
7072           test_name name;
7073
7074       pr "  {\n";
7075
7076       List.iter (
7077         function
7078         | OptString n, "NULL" -> ()
7079         | Pathname n, arg
7080         | Device n, arg
7081         | Dev_or_Path n, arg
7082         | String n, arg
7083         | OptString n, arg ->
7084             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
7085         | Int _, _
7086         | Int64 _, _
7087         | Bool _, _
7088         | FileIn _, _ | FileOut _, _ -> ()
7089         | StringList n, "" | DeviceList n, "" ->
7090             pr "    const char *const %s[1] = { NULL };\n" n
7091         | StringList n, arg | DeviceList n, arg ->
7092             let strs = string_split " " arg in
7093             iteri (
7094               fun i str ->
7095                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
7096             ) strs;
7097             pr "    const char *const %s[] = {\n" n;
7098             iteri (
7099               fun i _ -> pr "      %s_%d,\n" n i
7100             ) strs;
7101             pr "      NULL\n";
7102             pr "    };\n";
7103       ) (List.combine (snd style) args);
7104
7105       let error_code =
7106         match fst style with
7107         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
7108         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
7109         | RConstString _ | RConstOptString _ ->
7110             pr "    const char *r;\n"; "NULL"
7111         | RString _ -> pr "    char *r;\n"; "NULL"
7112         | RStringList _ | RHashtable _ ->
7113             pr "    char **r;\n";
7114             pr "    int i;\n";
7115             "NULL"
7116         | RStruct (_, typ) ->
7117             pr "    struct guestfs_%s *r;\n" typ; "NULL"
7118         | RStructList (_, typ) ->
7119             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
7120         | RBufferOut _ ->
7121             pr "    char *r;\n";
7122             pr "    size_t size;\n";
7123             "NULL" in
7124
7125       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
7126       pr "    r = guestfs_%s (g" name;
7127
7128       (* Generate the parameters. *)
7129       List.iter (
7130         function
7131         | OptString _, "NULL" -> pr ", NULL"
7132         | Pathname n, _
7133         | Device n, _ | Dev_or_Path n, _
7134         | String n, _
7135         | OptString n, _ ->
7136             pr ", %s" n
7137         | FileIn _, arg | FileOut _, arg ->
7138             pr ", \"%s\"" (c_quote arg)
7139         | StringList n, _ | DeviceList n, _ ->
7140             pr ", (char **) %s" n
7141         | Int _, arg ->
7142             let i =
7143               try int_of_string arg
7144               with Failure "int_of_string" ->
7145                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
7146             pr ", %d" i
7147         | Int64 _, arg ->
7148             let i =
7149               try Int64.of_string arg
7150               with Failure "int_of_string" ->
7151                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
7152             pr ", %Ld" i
7153         | Bool _, arg ->
7154             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
7155       ) (List.combine (snd style) args);
7156
7157       (match fst style with
7158        | RBufferOut _ -> pr ", &size"
7159        | _ -> ()
7160       );
7161
7162       pr ");\n";
7163
7164       if not expect_error then
7165         pr "    if (r == %s)\n" error_code
7166       else
7167         pr "    if (r != %s)\n" error_code;
7168       pr "      return -1;\n";
7169
7170       (* Insert the test code. *)
7171       (match test with
7172        | None -> ()
7173        | Some f -> f ()
7174       );
7175
7176       (match fst style with
7177        | RErr | RInt _ | RInt64 _ | RBool _
7178        | RConstString _ | RConstOptString _ -> ()
7179        | RString _ | RBufferOut _ -> pr "    free (r);\n"
7180        | RStringList _ | RHashtable _ ->
7181            pr "    for (i = 0; r[i] != NULL; ++i)\n";
7182            pr "      free (r[i]);\n";
7183            pr "    free (r);\n"
7184        | RStruct (_, typ) ->
7185            pr "    guestfs_free_%s (r);\n" typ
7186        | RStructList (_, typ) ->
7187            pr "    guestfs_free_%s_list (r);\n" typ
7188       );
7189
7190       pr "  }\n"
7191
7192 and c_quote str =
7193   let str = replace_str str "\r" "\\r" in
7194   let str = replace_str str "\n" "\\n" in
7195   let str = replace_str str "\t" "\\t" in
7196   let str = replace_str str "\000" "\\0" in
7197   str
7198
7199 (* Generate a lot of different functions for guestfish. *)
7200 and generate_fish_cmds () =
7201   generate_header CStyle GPLv2plus;
7202
7203   let all_functions =
7204     List.filter (
7205       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7206     ) all_functions in
7207   let all_functions_sorted =
7208     List.filter (
7209       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7210     ) all_functions_sorted in
7211
7212   pr "#include <config.h>\n";
7213   pr "\n";
7214   pr "#include <stdio.h>\n";
7215   pr "#include <stdlib.h>\n";
7216   pr "#include <string.h>\n";
7217   pr "#include <inttypes.h>\n";
7218   pr "\n";
7219   pr "#include <guestfs.h>\n";
7220   pr "#include \"c-ctype.h\"\n";
7221   pr "#include \"full-write.h\"\n";
7222   pr "#include \"xstrtol.h\"\n";
7223   pr "#include \"fish.h\"\n";
7224   pr "\n";
7225
7226   (* list_commands function, which implements guestfish -h *)
7227   pr "void list_commands (void)\n";
7228   pr "{\n";
7229   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
7230   pr "  list_builtin_commands ();\n";
7231   List.iter (
7232     fun (name, _, _, flags, _, shortdesc, _) ->
7233       let name = replace_char name '_' '-' in
7234       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
7235         name shortdesc
7236   ) all_functions_sorted;
7237   pr "  printf (\"    %%s\\n\",";
7238   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
7239   pr "}\n";
7240   pr "\n";
7241
7242   (* display_command function, which implements guestfish -h cmd *)
7243   pr "void display_command (const char *cmd)\n";
7244   pr "{\n";
7245   List.iter (
7246     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7247       let name2 = replace_char name '_' '-' in
7248       let alias =
7249         try find_map (function FishAlias n -> Some n | _ -> None) flags
7250         with Not_found -> name in
7251       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
7252       let synopsis =
7253         match snd style with
7254         | [] -> name2
7255         | args ->
7256             sprintf "%s %s"
7257               name2 (String.concat " " (List.map name_of_argt args)) in
7258
7259       let warnings =
7260         if List.mem ProtocolLimitWarning flags then
7261           ("\n\n" ^ protocol_limit_warning)
7262         else "" in
7263
7264       (* For DangerWillRobinson commands, we should probably have
7265        * guestfish prompt before allowing you to use them (especially
7266        * in interactive mode). XXX
7267        *)
7268       let warnings =
7269         warnings ^
7270           if List.mem DangerWillRobinson flags then
7271             ("\n\n" ^ danger_will_robinson)
7272           else "" in
7273
7274       let warnings =
7275         warnings ^
7276           match deprecation_notice flags with
7277           | None -> ""
7278           | Some txt -> "\n\n" ^ txt in
7279
7280       let describe_alias =
7281         if name <> alias then
7282           sprintf "\n\nYou can use '%s' as an alias for this command." alias
7283         else "" in
7284
7285       pr "  if (";
7286       pr "STRCASEEQ (cmd, \"%s\")" name;
7287       if name <> name2 then
7288         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7289       if name <> alias then
7290         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7291       pr ")\n";
7292       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
7293         name2 shortdesc
7294         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
7295          "=head1 DESCRIPTION\n\n" ^
7296          longdesc ^ warnings ^ describe_alias);
7297       pr "  else\n"
7298   ) all_functions;
7299   pr "    display_builtin_command (cmd);\n";
7300   pr "}\n";
7301   pr "\n";
7302
7303   let emit_print_list_function typ =
7304     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
7305       typ typ typ;
7306     pr "{\n";
7307     pr "  unsigned int i;\n";
7308     pr "\n";
7309     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
7310     pr "    printf (\"[%%d] = {\\n\", i);\n";
7311     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
7312     pr "    printf (\"}\\n\");\n";
7313     pr "  }\n";
7314     pr "}\n";
7315     pr "\n";
7316   in
7317
7318   (* print_* functions *)
7319   List.iter (
7320     fun (typ, cols) ->
7321       let needs_i =
7322         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
7323
7324       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7325       pr "{\n";
7326       if needs_i then (
7327         pr "  unsigned int i;\n";
7328         pr "\n"
7329       );
7330       List.iter (
7331         function
7332         | name, FString ->
7333             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7334         | name, FUUID ->
7335             pr "  printf (\"%%s%s: \", indent);\n" name;
7336             pr "  for (i = 0; i < 32; ++i)\n";
7337             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7338             pr "  printf (\"\\n\");\n"
7339         | name, FBuffer ->
7340             pr "  printf (\"%%s%s: \", indent);\n" name;
7341             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7342             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7343             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7344             pr "    else\n";
7345             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7346             pr "  printf (\"\\n\");\n"
7347         | name, (FUInt64|FBytes) ->
7348             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7349               name typ name
7350         | name, FInt64 ->
7351             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7352               name typ name
7353         | name, FUInt32 ->
7354             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7355               name typ name
7356         | name, FInt32 ->
7357             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7358               name typ name
7359         | name, FChar ->
7360             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7361               name typ name
7362         | name, FOptPercent ->
7363             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7364               typ name name typ name;
7365             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7366       ) cols;
7367       pr "}\n";
7368       pr "\n";
7369   ) structs;
7370
7371   (* Emit a print_TYPE_list function definition only if that function is used. *)
7372   List.iter (
7373     function
7374     | typ, (RStructListOnly | RStructAndList) ->
7375         (* generate the function for typ *)
7376         emit_print_list_function typ
7377     | typ, _ -> () (* empty *)
7378   ) (rstructs_used_by all_functions);
7379
7380   (* Emit a print_TYPE function definition only if that function is used. *)
7381   List.iter (
7382     function
7383     | typ, (RStructOnly | RStructAndList) ->
7384         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7385         pr "{\n";
7386         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7387         pr "}\n";
7388         pr "\n";
7389     | typ, _ -> () (* empty *)
7390   ) (rstructs_used_by all_functions);
7391
7392   (* run_<action> actions *)
7393   List.iter (
7394     fun (name, style, _, flags, _, _, _) ->
7395       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7396       pr "{\n";
7397       (match fst style with
7398        | RErr
7399        | RInt _
7400        | RBool _ -> pr "  int r;\n"
7401        | RInt64 _ -> pr "  int64_t r;\n"
7402        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7403        | RString _ -> pr "  char *r;\n"
7404        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7405        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7406        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7407        | RBufferOut _ ->
7408            pr "  char *r;\n";
7409            pr "  size_t size;\n";
7410       );
7411       List.iter (
7412         function
7413         | Device n
7414         | String n
7415         | OptString n -> pr "  const char *%s;\n" n
7416         | Pathname n
7417         | Dev_or_Path n
7418         | FileIn n
7419         | FileOut n -> pr "  char *%s;\n" n
7420         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7421         | Bool n -> pr "  int %s;\n" n
7422         | Int n -> pr "  int %s;\n" n
7423         | Int64 n -> pr "  int64_t %s;\n" n
7424       ) (snd style);
7425
7426       (* Check and convert parameters. *)
7427       let argc_expected = List.length (snd style) in
7428       pr "  if (argc != %d) {\n" argc_expected;
7429       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7430         argc_expected;
7431       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7432       pr "    return -1;\n";
7433       pr "  }\n";
7434
7435       let parse_integer fn fntyp rtyp range name i =
7436         pr "  {\n";
7437         pr "    strtol_error xerr;\n";
7438         pr "    %s r;\n" fntyp;
7439         pr "\n";
7440         pr "    xerr = %s (argv[%d], NULL, 0, &r, \"\");\n" fn i;
7441         pr "    if (xerr != LONGINT_OK) {\n";
7442         pr "      fprintf (stderr,\n";
7443         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7444         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7445         pr "      return -1;\n";
7446         pr "    }\n";
7447         (match range with
7448          | None -> ()
7449          | Some (min, max, comment) ->
7450              pr "    /* %s */\n" comment;
7451              pr "    if (r < %s || r > %s) {\n" min max;
7452              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7453                name;
7454              pr "      return -1;\n";
7455              pr "    }\n";
7456              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7457         );
7458         pr "    %s = r;\n" name;
7459         pr "  }\n";
7460       in
7461
7462       iteri (
7463         fun i ->
7464           function
7465           | Device name
7466           | String name ->
7467               pr "  %s = argv[%d];\n" name i
7468           | Pathname name
7469           | Dev_or_Path name ->
7470               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7471               pr "  if (%s == NULL) return -1;\n" name
7472           | OptString name ->
7473               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7474                 name i i
7475           | FileIn name ->
7476               pr "  %s = file_in (argv[%d]);\n" name i;
7477               pr "  if (%s == NULL) return -1;\n" name
7478           | FileOut name ->
7479               pr "  %s = file_out (argv[%d]);\n" name i;
7480               pr "  if (%s == NULL) return -1;\n" name
7481           | StringList name | DeviceList name ->
7482               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7483               pr "  if (%s == NULL) return -1;\n" name;
7484           | Bool name ->
7485               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7486           | Int name ->
7487               let range =
7488                 let min = "(-(2LL<<30))"
7489                 and max = "((2LL<<30)-1)"
7490                 and comment =
7491                   "The Int type in the generator is a signed 31 bit int." in
7492                 Some (min, max, comment) in
7493               parse_integer "xstrtoll" "long long" "int" range name i
7494           | Int64 name ->
7495               parse_integer "xstrtoll" "long long" "int64_t" None name i
7496       ) (snd style);
7497
7498       (* Call C API function. *)
7499       let fn =
7500         try find_map (function FishAction n -> Some n | _ -> None) flags
7501         with Not_found -> sprintf "guestfs_%s" name in
7502       pr "  r = %s " fn;
7503       generate_c_call_args ~handle:"g" style;
7504       pr ";\n";
7505
7506       List.iter (
7507         function
7508         | Device name | String name
7509         | OptString name | Bool name
7510         | Int name | Int64 name -> ()
7511         | Pathname name | Dev_or_Path name | FileOut name ->
7512             pr "  free (%s);\n" name
7513         | FileIn name ->
7514             pr "  free_file_in (%s);\n" name
7515         | StringList name | DeviceList name ->
7516             pr "  free_strings (%s);\n" name
7517       ) (snd style);
7518
7519       (* Any output flags? *)
7520       let fish_output =
7521         let flags = filter_map (
7522           function FishOutput flag -> Some flag | _ -> None
7523         ) flags in
7524         match flags with
7525         | [] -> None
7526         | [f] -> Some f
7527         | _ ->
7528             failwithf "%s: more than one FishOutput flag is not allowed" name in
7529
7530       (* Check return value for errors and display command results. *)
7531       (match fst style with
7532        | RErr -> pr "  return r;\n"
7533        | RInt _ ->
7534            pr "  if (r == -1) return -1;\n";
7535            (match fish_output with
7536             | None ->
7537                 pr "  printf (\"%%d\\n\", r);\n";
7538             | Some FishOutputOctal ->
7539                 pr "  printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n";
7540             | Some FishOutputHexadecimal ->
7541                 pr "  printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7542            pr "  return 0;\n"
7543        | RInt64 _ ->
7544            pr "  if (r == -1) return -1;\n";
7545            (match fish_output with
7546             | None ->
7547                 pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7548             | Some FishOutputOctal ->
7549                 pr "  printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n";
7550             | Some FishOutputHexadecimal ->
7551                 pr "  printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7552            pr "  return 0;\n"
7553        | RBool _ ->
7554            pr "  if (r == -1) return -1;\n";
7555            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7556            pr "  return 0;\n"
7557        | RConstString _ ->
7558            pr "  if (r == NULL) return -1;\n";
7559            pr "  printf (\"%%s\\n\", r);\n";
7560            pr "  return 0;\n"
7561        | RConstOptString _ ->
7562            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7563            pr "  return 0;\n"
7564        | RString _ ->
7565            pr "  if (r == NULL) return -1;\n";
7566            pr "  printf (\"%%s\\n\", r);\n";
7567            pr "  free (r);\n";
7568            pr "  return 0;\n"
7569        | RStringList _ ->
7570            pr "  if (r == NULL) return -1;\n";
7571            pr "  print_strings (r);\n";
7572            pr "  free_strings (r);\n";
7573            pr "  return 0;\n"
7574        | RStruct (_, typ) ->
7575            pr "  if (r == NULL) return -1;\n";
7576            pr "  print_%s (r);\n" typ;
7577            pr "  guestfs_free_%s (r);\n" typ;
7578            pr "  return 0;\n"
7579        | RStructList (_, typ) ->
7580            pr "  if (r == NULL) return -1;\n";
7581            pr "  print_%s_list (r);\n" typ;
7582            pr "  guestfs_free_%s_list (r);\n" typ;
7583            pr "  return 0;\n"
7584        | RHashtable _ ->
7585            pr "  if (r == NULL) return -1;\n";
7586            pr "  print_table (r);\n";
7587            pr "  free_strings (r);\n";
7588            pr "  return 0;\n"
7589        | RBufferOut _ ->
7590            pr "  if (r == NULL) return -1;\n";
7591            pr "  if (full_write (1, r, size) != size) {\n";
7592            pr "    perror (\"write\");\n";
7593            pr "    free (r);\n";
7594            pr "    return -1;\n";
7595            pr "  }\n";
7596            pr "  free (r);\n";
7597            pr "  return 0;\n"
7598       );
7599       pr "}\n";
7600       pr "\n"
7601   ) all_functions;
7602
7603   (* run_action function *)
7604   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7605   pr "{\n";
7606   List.iter (
7607     fun (name, _, _, flags, _, _, _) ->
7608       let name2 = replace_char name '_' '-' in
7609       let alias =
7610         try find_map (function FishAlias n -> Some n | _ -> None) flags
7611         with Not_found -> name in
7612       pr "  if (";
7613       pr "STRCASEEQ (cmd, \"%s\")" name;
7614       if name <> name2 then
7615         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7616       if name <> alias then
7617         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7618       pr ")\n";
7619       pr "    return run_%s (cmd, argc, argv);\n" name;
7620       pr "  else\n";
7621   ) all_functions;
7622   pr "    {\n";
7623   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7624   pr "      if (command_num == 1)\n";
7625   pr "        extended_help_message ();\n";
7626   pr "      return -1;\n";
7627   pr "    }\n";
7628   pr "  return 0;\n";
7629   pr "}\n";
7630   pr "\n"
7631
7632 (* Readline completion for guestfish. *)
7633 and generate_fish_completion () =
7634   generate_header CStyle GPLv2plus;
7635
7636   let all_functions =
7637     List.filter (
7638       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7639     ) all_functions in
7640
7641   pr "\
7642 #include <config.h>
7643
7644 #include <stdio.h>
7645 #include <stdlib.h>
7646 #include <string.h>
7647
7648 #ifdef HAVE_LIBREADLINE
7649 #include <readline/readline.h>
7650 #endif
7651
7652 #include \"fish.h\"
7653
7654 #ifdef HAVE_LIBREADLINE
7655
7656 static const char *const commands[] = {
7657   BUILTIN_COMMANDS_FOR_COMPLETION,
7658 ";
7659
7660   (* Get the commands, including the aliases.  They don't need to be
7661    * sorted - the generator() function just does a dumb linear search.
7662    *)
7663   let commands =
7664     List.map (
7665       fun (name, _, _, flags, _, _, _) ->
7666         let name2 = replace_char name '_' '-' in
7667         let alias =
7668           try find_map (function FishAlias n -> Some n | _ -> None) flags
7669           with Not_found -> name in
7670
7671         if name <> alias then [name2; alias] else [name2]
7672     ) all_functions in
7673   let commands = List.flatten commands in
7674
7675   List.iter (pr "  \"%s\",\n") commands;
7676
7677   pr "  NULL
7678 };
7679
7680 static char *
7681 generator (const char *text, int state)
7682 {
7683   static int index, len;
7684   const char *name;
7685
7686   if (!state) {
7687     index = 0;
7688     len = strlen (text);
7689   }
7690
7691   rl_attempted_completion_over = 1;
7692
7693   while ((name = commands[index]) != NULL) {
7694     index++;
7695     if (STRCASEEQLEN (name, text, len))
7696       return strdup (name);
7697   }
7698
7699   return NULL;
7700 }
7701
7702 #endif /* HAVE_LIBREADLINE */
7703
7704 #ifdef HAVE_RL_COMPLETION_MATCHES
7705 #define RL_COMPLETION_MATCHES rl_completion_matches
7706 #else
7707 #ifdef HAVE_COMPLETION_MATCHES
7708 #define RL_COMPLETION_MATCHES completion_matches
7709 #endif
7710 #endif /* else just fail if we don't have either symbol */
7711
7712 char **
7713 do_completion (const char *text, int start, int end)
7714 {
7715   char **matches = NULL;
7716
7717 #ifdef HAVE_LIBREADLINE
7718   rl_completion_append_character = ' ';
7719
7720   if (start == 0)
7721     matches = RL_COMPLETION_MATCHES (text, generator);
7722   else if (complete_dest_paths)
7723     matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
7724 #endif
7725
7726   return matches;
7727 }
7728 ";
7729
7730 (* Generate the POD documentation for guestfish. *)
7731 and generate_fish_actions_pod () =
7732   let all_functions_sorted =
7733     List.filter (
7734       fun (_, _, _, flags, _, _, _) ->
7735         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7736     ) all_functions_sorted in
7737
7738   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7739
7740   List.iter (
7741     fun (name, style, _, flags, _, _, longdesc) ->
7742       let longdesc =
7743         Str.global_substitute rex (
7744           fun s ->
7745             let sub =
7746               try Str.matched_group 1 s
7747               with Not_found ->
7748                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7749             "C<" ^ replace_char sub '_' '-' ^ ">"
7750         ) longdesc in
7751       let name = replace_char name '_' '-' in
7752       let alias =
7753         try find_map (function FishAlias n -> Some n | _ -> None) flags
7754         with Not_found -> name in
7755
7756       pr "=head2 %s" name;
7757       if name <> alias then
7758         pr " | %s" alias;
7759       pr "\n";
7760       pr "\n";
7761       pr " %s" name;
7762       List.iter (
7763         function
7764         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7765         | OptString n -> pr " %s" n
7766         | StringList n | DeviceList n -> pr " '%s ...'" n
7767         | Bool _ -> pr " true|false"
7768         | Int n -> pr " %s" n
7769         | Int64 n -> pr " %s" n
7770         | FileIn n | FileOut n -> pr " (%s|-)" n
7771       ) (snd style);
7772       pr "\n";
7773       pr "\n";
7774       pr "%s\n\n" longdesc;
7775
7776       if List.exists (function FileIn _ | FileOut _ -> true
7777                       | _ -> false) (snd style) then
7778         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7779
7780       if List.mem ProtocolLimitWarning flags then
7781         pr "%s\n\n" protocol_limit_warning;
7782
7783       if List.mem DangerWillRobinson flags then
7784         pr "%s\n\n" danger_will_robinson;
7785
7786       match deprecation_notice flags with
7787       | None -> ()
7788       | Some txt -> pr "%s\n\n" txt
7789   ) all_functions_sorted
7790
7791 (* Generate a C function prototype. *)
7792 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7793     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7794     ?(prefix = "")
7795     ?handle name style =
7796   if extern then pr "extern ";
7797   if static then pr "static ";
7798   (match fst style with
7799    | RErr -> pr "int "
7800    | RInt _ -> pr "int "
7801    | RInt64 _ -> pr "int64_t "
7802    | RBool _ -> pr "int "
7803    | RConstString _ | RConstOptString _ -> pr "const char *"
7804    | RString _ | RBufferOut _ -> pr "char *"
7805    | RStringList _ | RHashtable _ -> pr "char **"
7806    | RStruct (_, typ) ->
7807        if not in_daemon then pr "struct guestfs_%s *" typ
7808        else pr "guestfs_int_%s *" typ
7809    | RStructList (_, typ) ->
7810        if not in_daemon then pr "struct guestfs_%s_list *" typ
7811        else pr "guestfs_int_%s_list *" typ
7812   );
7813   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7814   pr "%s%s (" prefix name;
7815   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7816     pr "void"
7817   else (
7818     let comma = ref false in
7819     (match handle with
7820      | None -> ()
7821      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7822     );
7823     let next () =
7824       if !comma then (
7825         if single_line then pr ", " else pr ",\n\t\t"
7826       );
7827       comma := true
7828     in
7829     List.iter (
7830       function
7831       | Pathname n
7832       | Device n | Dev_or_Path n
7833       | String n
7834       | OptString n ->
7835           next ();
7836           pr "const char *%s" n
7837       | StringList n | DeviceList n ->
7838           next ();
7839           pr "char *const *%s" n
7840       | Bool n -> next (); pr "int %s" n
7841       | Int n -> next (); pr "int %s" n
7842       | Int64 n -> next (); pr "int64_t %s" n
7843       | FileIn n
7844       | FileOut n ->
7845           if not in_daemon then (next (); pr "const char *%s" n)
7846     ) (snd style);
7847     if is_RBufferOut then (next (); pr "size_t *size_r");
7848   );
7849   pr ")";
7850   if semicolon then pr ";";
7851   if newline then pr "\n"
7852
7853 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7854 and generate_c_call_args ?handle ?(decl = false) style =
7855   pr "(";
7856   let comma = ref false in
7857   let next () =
7858     if !comma then pr ", ";
7859     comma := true
7860   in
7861   (match handle with
7862    | None -> ()
7863    | Some handle -> pr "%s" handle; comma := true
7864   );
7865   List.iter (
7866     fun arg ->
7867       next ();
7868       pr "%s" (name_of_argt arg)
7869   ) (snd style);
7870   (* For RBufferOut calls, add implicit &size parameter. *)
7871   if not decl then (
7872     match fst style with
7873     | RBufferOut _ ->
7874         next ();
7875         pr "&size"
7876     | _ -> ()
7877   );
7878   pr ")"
7879
7880 (* Generate the OCaml bindings interface. *)
7881 and generate_ocaml_mli () =
7882   generate_header OCamlStyle LGPLv2plus;
7883
7884   pr "\
7885 (** For API documentation you should refer to the C API
7886     in the guestfs(3) manual page.  The OCaml API uses almost
7887     exactly the same calls. *)
7888
7889 type t
7890 (** A [guestfs_h] handle. *)
7891
7892 exception Error of string
7893 (** This exception is raised when there is an error. *)
7894
7895 exception Handle_closed of string
7896 (** This exception is raised if you use a {!Guestfs.t} handle
7897     after calling {!close} on it.  The string is the name of
7898     the function. *)
7899
7900 val create : unit -> t
7901 (** Create a {!Guestfs.t} handle. *)
7902
7903 val close : t -> unit
7904 (** Close the {!Guestfs.t} handle and free up all resources used
7905     by it immediately.
7906
7907     Handles are closed by the garbage collector when they become
7908     unreferenced, but callers can call this in order to provide
7909     predictable cleanup. *)
7910
7911 ";
7912   generate_ocaml_structure_decls ();
7913
7914   (* The actions. *)
7915   List.iter (
7916     fun (name, style, _, _, _, shortdesc, _) ->
7917       generate_ocaml_prototype name style;
7918       pr "(** %s *)\n" shortdesc;
7919       pr "\n"
7920   ) all_functions_sorted
7921
7922 (* Generate the OCaml bindings implementation. *)
7923 and generate_ocaml_ml () =
7924   generate_header OCamlStyle LGPLv2plus;
7925
7926   pr "\
7927 type t
7928
7929 exception Error of string
7930 exception Handle_closed of string
7931
7932 external create : unit -> t = \"ocaml_guestfs_create\"
7933 external close : t -> unit = \"ocaml_guestfs_close\"
7934
7935 (* Give the exceptions names, so they can be raised from the C code. *)
7936 let () =
7937   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
7938   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
7939
7940 ";
7941
7942   generate_ocaml_structure_decls ();
7943
7944   (* The actions. *)
7945   List.iter (
7946     fun (name, style, _, _, _, shortdesc, _) ->
7947       generate_ocaml_prototype ~is_external:true name style;
7948   ) all_functions_sorted
7949
7950 (* Generate the OCaml bindings C implementation. *)
7951 and generate_ocaml_c () =
7952   generate_header CStyle LGPLv2plus;
7953
7954   pr "\
7955 #include <stdio.h>
7956 #include <stdlib.h>
7957 #include <string.h>
7958
7959 #include <caml/config.h>
7960 #include <caml/alloc.h>
7961 #include <caml/callback.h>
7962 #include <caml/fail.h>
7963 #include <caml/memory.h>
7964 #include <caml/mlvalues.h>
7965 #include <caml/signals.h>
7966
7967 #include <guestfs.h>
7968
7969 #include \"guestfs_c.h\"
7970
7971 /* Copy a hashtable of string pairs into an assoc-list.  We return
7972  * the list in reverse order, but hashtables aren't supposed to be
7973  * ordered anyway.
7974  */
7975 static CAMLprim value
7976 copy_table (char * const * argv)
7977 {
7978   CAMLparam0 ();
7979   CAMLlocal5 (rv, pairv, kv, vv, cons);
7980   int i;
7981
7982   rv = Val_int (0);
7983   for (i = 0; argv[i] != NULL; i += 2) {
7984     kv = caml_copy_string (argv[i]);
7985     vv = caml_copy_string (argv[i+1]);
7986     pairv = caml_alloc (2, 0);
7987     Store_field (pairv, 0, kv);
7988     Store_field (pairv, 1, vv);
7989     cons = caml_alloc (2, 0);
7990     Store_field (cons, 1, rv);
7991     rv = cons;
7992     Store_field (cons, 0, pairv);
7993   }
7994
7995   CAMLreturn (rv);
7996 }
7997
7998 ";
7999
8000   (* Struct copy functions. *)
8001
8002   let emit_ocaml_copy_list_function typ =
8003     pr "static CAMLprim value\n";
8004     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
8005     pr "{\n";
8006     pr "  CAMLparam0 ();\n";
8007     pr "  CAMLlocal2 (rv, v);\n";
8008     pr "  unsigned int i;\n";
8009     pr "\n";
8010     pr "  if (%ss->len == 0)\n" typ;
8011     pr "    CAMLreturn (Atom (0));\n";
8012     pr "  else {\n";
8013     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
8014     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
8015     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
8016     pr "      caml_modify (&Field (rv, i), v);\n";
8017     pr "    }\n";
8018     pr "    CAMLreturn (rv);\n";
8019     pr "  }\n";
8020     pr "}\n";
8021     pr "\n";
8022   in
8023
8024   List.iter (
8025     fun (typ, cols) ->
8026       let has_optpercent_col =
8027         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
8028
8029       pr "static CAMLprim value\n";
8030       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
8031       pr "{\n";
8032       pr "  CAMLparam0 ();\n";
8033       if has_optpercent_col then
8034         pr "  CAMLlocal3 (rv, v, v2);\n"
8035       else
8036         pr "  CAMLlocal2 (rv, v);\n";
8037       pr "\n";
8038       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
8039       iteri (
8040         fun i col ->
8041           (match col with
8042            | name, FString ->
8043                pr "  v = caml_copy_string (%s->%s);\n" typ name
8044            | name, FBuffer ->
8045                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
8046                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
8047                  typ name typ name
8048            | name, FUUID ->
8049                pr "  v = caml_alloc_string (32);\n";
8050                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
8051            | name, (FBytes|FInt64|FUInt64) ->
8052                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
8053            | name, (FInt32|FUInt32) ->
8054                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
8055            | name, FOptPercent ->
8056                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
8057                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
8058                pr "    v = caml_alloc (1, 0);\n";
8059                pr "    Store_field (v, 0, v2);\n";
8060                pr "  } else /* None */\n";
8061                pr "    v = Val_int (0);\n";
8062            | name, FChar ->
8063                pr "  v = Val_int (%s->%s);\n" typ name
8064           );
8065           pr "  Store_field (rv, %d, v);\n" i
8066       ) cols;
8067       pr "  CAMLreturn (rv);\n";
8068       pr "}\n";
8069       pr "\n";
8070   ) structs;
8071
8072   (* Emit a copy_TYPE_list function definition only if that function is used. *)
8073   List.iter (
8074     function
8075     | typ, (RStructListOnly | RStructAndList) ->
8076         (* generate the function for typ *)
8077         emit_ocaml_copy_list_function typ
8078     | typ, _ -> () (* empty *)
8079   ) (rstructs_used_by all_functions);
8080
8081   (* The wrappers. *)
8082   List.iter (
8083     fun (name, style, _, _, _, _, _) ->
8084       pr "/* Automatically generated wrapper for function\n";
8085       pr " * ";
8086       generate_ocaml_prototype name style;
8087       pr " */\n";
8088       pr "\n";
8089
8090       let params =
8091         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
8092
8093       let needs_extra_vs =
8094         match fst style with RConstOptString _ -> true | _ -> false in
8095
8096       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8097       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
8098       List.iter (pr ", value %s") (List.tl params); pr ");\n";
8099       pr "\n";
8100
8101       pr "CAMLprim value\n";
8102       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
8103       List.iter (pr ", value %s") (List.tl params);
8104       pr ")\n";
8105       pr "{\n";
8106
8107       (match params with
8108        | [p1; p2; p3; p4; p5] ->
8109            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
8110        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
8111            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
8112            pr "  CAMLxparam%d (%s);\n"
8113              (List.length rest) (String.concat ", " rest)
8114        | ps ->
8115            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
8116       );
8117       if not needs_extra_vs then
8118         pr "  CAMLlocal1 (rv);\n"
8119       else
8120         pr "  CAMLlocal3 (rv, v, v2);\n";
8121       pr "\n";
8122
8123       pr "  guestfs_h *g = Guestfs_val (gv);\n";
8124       pr "  if (g == NULL)\n";
8125       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
8126       pr "\n";
8127
8128       List.iter (
8129         function
8130         | Pathname n
8131         | Device n | Dev_or_Path n
8132         | String n
8133         | FileIn n
8134         | FileOut n ->
8135             pr "  const char *%s = String_val (%sv);\n" n n
8136         | OptString n ->
8137             pr "  const char *%s =\n" n;
8138             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
8139               n n
8140         | StringList n | DeviceList n ->
8141             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
8142         | Bool n ->
8143             pr "  int %s = Bool_val (%sv);\n" n n
8144         | Int n ->
8145             pr "  int %s = Int_val (%sv);\n" n n
8146         | Int64 n ->
8147             pr "  int64_t %s = Int64_val (%sv);\n" n n
8148       ) (snd style);
8149       let error_code =
8150         match fst style with
8151         | RErr -> pr "  int r;\n"; "-1"
8152         | RInt _ -> pr "  int r;\n"; "-1"
8153         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8154         | RBool _ -> pr "  int r;\n"; "-1"
8155         | RConstString _ | RConstOptString _ ->
8156             pr "  const char *r;\n"; "NULL"
8157         | RString _ -> pr "  char *r;\n"; "NULL"
8158         | RStringList _ ->
8159             pr "  int i;\n";
8160             pr "  char **r;\n";
8161             "NULL"
8162         | RStruct (_, typ) ->
8163             pr "  struct guestfs_%s *r;\n" typ; "NULL"
8164         | RStructList (_, typ) ->
8165             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8166         | RHashtable _ ->
8167             pr "  int i;\n";
8168             pr "  char **r;\n";
8169             "NULL"
8170         | RBufferOut _ ->
8171             pr "  char *r;\n";
8172             pr "  size_t size;\n";
8173             "NULL" in
8174       pr "\n";
8175
8176       pr "  caml_enter_blocking_section ();\n";
8177       pr "  r = guestfs_%s " name;
8178       generate_c_call_args ~handle:"g" style;
8179       pr ";\n";
8180       pr "  caml_leave_blocking_section ();\n";
8181
8182       List.iter (
8183         function
8184         | StringList n | DeviceList n ->
8185             pr "  ocaml_guestfs_free_strings (%s);\n" n;
8186         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8187         | Bool _ | Int _ | Int64 _
8188         | FileIn _ | FileOut _ -> ()
8189       ) (snd style);
8190
8191       pr "  if (r == %s)\n" error_code;
8192       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
8193       pr "\n";
8194
8195       (match fst style with
8196        | RErr -> pr "  rv = Val_unit;\n"
8197        | RInt _ -> pr "  rv = Val_int (r);\n"
8198        | RInt64 _ ->
8199            pr "  rv = caml_copy_int64 (r);\n"
8200        | RBool _ -> pr "  rv = Val_bool (r);\n"
8201        | RConstString _ ->
8202            pr "  rv = caml_copy_string (r);\n"
8203        | RConstOptString _ ->
8204            pr "  if (r) { /* Some string */\n";
8205            pr "    v = caml_alloc (1, 0);\n";
8206            pr "    v2 = caml_copy_string (r);\n";
8207            pr "    Store_field (v, 0, v2);\n";
8208            pr "  } else /* None */\n";
8209            pr "    v = Val_int (0);\n";
8210        | RString _ ->
8211            pr "  rv = caml_copy_string (r);\n";
8212            pr "  free (r);\n"
8213        | RStringList _ ->
8214            pr "  rv = caml_copy_string_array ((const char **) r);\n";
8215            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8216            pr "  free (r);\n"
8217        | RStruct (_, typ) ->
8218            pr "  rv = copy_%s (r);\n" typ;
8219            pr "  guestfs_free_%s (r);\n" typ;
8220        | RStructList (_, typ) ->
8221            pr "  rv = copy_%s_list (r);\n" typ;
8222            pr "  guestfs_free_%s_list (r);\n" typ;
8223        | RHashtable _ ->
8224            pr "  rv = copy_table (r);\n";
8225            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8226            pr "  free (r);\n";
8227        | RBufferOut _ ->
8228            pr "  rv = caml_alloc_string (size);\n";
8229            pr "  memcpy (String_val (rv), r, size);\n";
8230       );
8231
8232       pr "  CAMLreturn (rv);\n";
8233       pr "}\n";
8234       pr "\n";
8235
8236       if List.length params > 5 then (
8237         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8238         pr "CAMLprim value ";
8239         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
8240         pr "CAMLprim value\n";
8241         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
8242         pr "{\n";
8243         pr "  return ocaml_guestfs_%s (argv[0]" name;
8244         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
8245         pr ");\n";
8246         pr "}\n";
8247         pr "\n"
8248       )
8249   ) all_functions_sorted
8250
8251 and generate_ocaml_structure_decls () =
8252   List.iter (
8253     fun (typ, cols) ->
8254       pr "type %s = {\n" typ;
8255       List.iter (
8256         function
8257         | name, FString -> pr "  %s : string;\n" name
8258         | name, FBuffer -> pr "  %s : string;\n" name
8259         | name, FUUID -> pr "  %s : string;\n" name
8260         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
8261         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
8262         | name, FChar -> pr "  %s : char;\n" name
8263         | name, FOptPercent -> pr "  %s : float option;\n" name
8264       ) cols;
8265       pr "}\n";
8266       pr "\n"
8267   ) structs
8268
8269 and generate_ocaml_prototype ?(is_external = false) name style =
8270   if is_external then pr "external " else pr "val ";
8271   pr "%s : t -> " name;
8272   List.iter (
8273     function
8274     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
8275     | OptString _ -> pr "string option -> "
8276     | StringList _ | DeviceList _ -> pr "string array -> "
8277     | Bool _ -> pr "bool -> "
8278     | Int _ -> pr "int -> "
8279     | Int64 _ -> pr "int64 -> "
8280   ) (snd style);
8281   (match fst style with
8282    | RErr -> pr "unit" (* all errors are turned into exceptions *)
8283    | RInt _ -> pr "int"
8284    | RInt64 _ -> pr "int64"
8285    | RBool _ -> pr "bool"
8286    | RConstString _ -> pr "string"
8287    | RConstOptString _ -> pr "string option"
8288    | RString _ | RBufferOut _ -> pr "string"
8289    | RStringList _ -> pr "string array"
8290    | RStruct (_, typ) -> pr "%s" typ
8291    | RStructList (_, typ) -> pr "%s array" typ
8292    | RHashtable _ -> pr "(string * string) list"
8293   );
8294   if is_external then (
8295     pr " = ";
8296     if List.length (snd style) + 1 > 5 then
8297       pr "\"ocaml_guestfs_%s_byte\" " name;
8298     pr "\"ocaml_guestfs_%s\"" name
8299   );
8300   pr "\n"
8301
8302 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
8303 and generate_perl_xs () =
8304   generate_header CStyle LGPLv2plus;
8305
8306   pr "\
8307 #include \"EXTERN.h\"
8308 #include \"perl.h\"
8309 #include \"XSUB.h\"
8310
8311 #include <guestfs.h>
8312
8313 #ifndef PRId64
8314 #define PRId64 \"lld\"
8315 #endif
8316
8317 static SV *
8318 my_newSVll(long long val) {
8319 #ifdef USE_64_BIT_ALL
8320   return newSViv(val);
8321 #else
8322   char buf[100];
8323   int len;
8324   len = snprintf(buf, 100, \"%%\" PRId64, val);
8325   return newSVpv(buf, len);
8326 #endif
8327 }
8328
8329 #ifndef PRIu64
8330 #define PRIu64 \"llu\"
8331 #endif
8332
8333 static SV *
8334 my_newSVull(unsigned long long val) {
8335 #ifdef USE_64_BIT_ALL
8336   return newSVuv(val);
8337 #else
8338   char buf[100];
8339   int len;
8340   len = snprintf(buf, 100, \"%%\" PRIu64, val);
8341   return newSVpv(buf, len);
8342 #endif
8343 }
8344
8345 /* http://www.perlmonks.org/?node_id=680842 */
8346 static char **
8347 XS_unpack_charPtrPtr (SV *arg) {
8348   char **ret;
8349   AV *av;
8350   I32 i;
8351
8352   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
8353     croak (\"array reference expected\");
8354
8355   av = (AV *)SvRV (arg);
8356   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
8357   if (!ret)
8358     croak (\"malloc failed\");
8359
8360   for (i = 0; i <= av_len (av); i++) {
8361     SV **elem = av_fetch (av, i, 0);
8362
8363     if (!elem || !*elem)
8364       croak (\"missing element in list\");
8365
8366     ret[i] = SvPV_nolen (*elem);
8367   }
8368
8369   ret[i] = NULL;
8370
8371   return ret;
8372 }
8373
8374 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8375
8376 PROTOTYPES: ENABLE
8377
8378 guestfs_h *
8379 _create ()
8380    CODE:
8381       RETVAL = guestfs_create ();
8382       if (!RETVAL)
8383         croak (\"could not create guestfs handle\");
8384       guestfs_set_error_handler (RETVAL, NULL, NULL);
8385  OUTPUT:
8386       RETVAL
8387
8388 void
8389 DESTROY (g)
8390       guestfs_h *g;
8391  PPCODE:
8392       guestfs_close (g);
8393
8394 ";
8395
8396   List.iter (
8397     fun (name, style, _, _, _, _, _) ->
8398       (match fst style with
8399        | RErr -> pr "void\n"
8400        | RInt _ -> pr "SV *\n"
8401        | RInt64 _ -> pr "SV *\n"
8402        | RBool _ -> pr "SV *\n"
8403        | RConstString _ -> pr "SV *\n"
8404        | RConstOptString _ -> pr "SV *\n"
8405        | RString _ -> pr "SV *\n"
8406        | RBufferOut _ -> pr "SV *\n"
8407        | RStringList _
8408        | RStruct _ | RStructList _
8409        | RHashtable _ ->
8410            pr "void\n" (* all lists returned implictly on the stack *)
8411       );
8412       (* Call and arguments. *)
8413       pr "%s " name;
8414       generate_c_call_args ~handle:"g" ~decl:true style;
8415       pr "\n";
8416       pr "      guestfs_h *g;\n";
8417       iteri (
8418         fun i ->
8419           function
8420           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8421               pr "      char *%s;\n" n
8422           | OptString n ->
8423               (* http://www.perlmonks.org/?node_id=554277
8424                * Note that the implicit handle argument means we have
8425                * to add 1 to the ST(x) operator.
8426                *)
8427               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8428           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8429           | Bool n -> pr "      int %s;\n" n
8430           | Int n -> pr "      int %s;\n" n
8431           | Int64 n -> pr "      int64_t %s;\n" n
8432       ) (snd style);
8433
8434       let do_cleanups () =
8435         List.iter (
8436           function
8437           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8438           | Bool _ | Int _ | Int64 _
8439           | FileIn _ | FileOut _ -> ()
8440           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8441         ) (snd style)
8442       in
8443
8444       (* Code. *)
8445       (match fst style with
8446        | RErr ->
8447            pr "PREINIT:\n";
8448            pr "      int r;\n";
8449            pr " PPCODE:\n";
8450            pr "      r = guestfs_%s " name;
8451            generate_c_call_args ~handle:"g" style;
8452            pr ";\n";
8453            do_cleanups ();
8454            pr "      if (r == -1)\n";
8455            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8456        | RInt n
8457        | RBool n ->
8458            pr "PREINIT:\n";
8459            pr "      int %s;\n" n;
8460            pr "   CODE:\n";
8461            pr "      %s = guestfs_%s " n name;
8462            generate_c_call_args ~handle:"g" style;
8463            pr ";\n";
8464            do_cleanups ();
8465            pr "      if (%s == -1)\n" n;
8466            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8467            pr "      RETVAL = newSViv (%s);\n" n;
8468            pr " OUTPUT:\n";
8469            pr "      RETVAL\n"
8470        | RInt64 n ->
8471            pr "PREINIT:\n";
8472            pr "      int64_t %s;\n" n;
8473            pr "   CODE:\n";
8474            pr "      %s = guestfs_%s " n name;
8475            generate_c_call_args ~handle:"g" style;
8476            pr ";\n";
8477            do_cleanups ();
8478            pr "      if (%s == -1)\n" n;
8479            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8480            pr "      RETVAL = my_newSVll (%s);\n" n;
8481            pr " OUTPUT:\n";
8482            pr "      RETVAL\n"
8483        | RConstString n ->
8484            pr "PREINIT:\n";
8485            pr "      const char *%s;\n" n;
8486            pr "   CODE:\n";
8487            pr "      %s = guestfs_%s " n name;
8488            generate_c_call_args ~handle:"g" style;
8489            pr ";\n";
8490            do_cleanups ();
8491            pr "      if (%s == NULL)\n" n;
8492            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8493            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8494            pr " OUTPUT:\n";
8495            pr "      RETVAL\n"
8496        | RConstOptString n ->
8497            pr "PREINIT:\n";
8498            pr "      const char *%s;\n" n;
8499            pr "   CODE:\n";
8500            pr "      %s = guestfs_%s " n name;
8501            generate_c_call_args ~handle:"g" style;
8502            pr ";\n";
8503            do_cleanups ();
8504            pr "      if (%s == NULL)\n" n;
8505            pr "        RETVAL = &PL_sv_undef;\n";
8506            pr "      else\n";
8507            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8508            pr " OUTPUT:\n";
8509            pr "      RETVAL\n"
8510        | RString n ->
8511            pr "PREINIT:\n";
8512            pr "      char *%s;\n" n;
8513            pr "   CODE:\n";
8514            pr "      %s = guestfs_%s " n name;
8515            generate_c_call_args ~handle:"g" style;
8516            pr ";\n";
8517            do_cleanups ();
8518            pr "      if (%s == NULL)\n" n;
8519            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8520            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8521            pr "      free (%s);\n" n;
8522            pr " OUTPUT:\n";
8523            pr "      RETVAL\n"
8524        | RStringList n | RHashtable n ->
8525            pr "PREINIT:\n";
8526            pr "      char **%s;\n" n;
8527            pr "      int i, n;\n";
8528            pr " PPCODE:\n";
8529            pr "      %s = guestfs_%s " n name;
8530            generate_c_call_args ~handle:"g" style;
8531            pr ";\n";
8532            do_cleanups ();
8533            pr "      if (%s == NULL)\n" n;
8534            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8535            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8536            pr "      EXTEND (SP, n);\n";
8537            pr "      for (i = 0; i < n; ++i) {\n";
8538            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8539            pr "        free (%s[i]);\n" n;
8540            pr "      }\n";
8541            pr "      free (%s);\n" n;
8542        | RStruct (n, typ) ->
8543            let cols = cols_of_struct typ in
8544            generate_perl_struct_code typ cols name style n do_cleanups
8545        | RStructList (n, typ) ->
8546            let cols = cols_of_struct typ in
8547            generate_perl_struct_list_code typ cols name style n do_cleanups
8548        | RBufferOut n ->
8549            pr "PREINIT:\n";
8550            pr "      char *%s;\n" n;
8551            pr "      size_t size;\n";
8552            pr "   CODE:\n";
8553            pr "      %s = guestfs_%s " n name;
8554            generate_c_call_args ~handle:"g" style;
8555            pr ";\n";
8556            do_cleanups ();
8557            pr "      if (%s == NULL)\n" n;
8558            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8559            pr "      RETVAL = newSVpvn (%s, size);\n" n;
8560            pr "      free (%s);\n" n;
8561            pr " OUTPUT:\n";
8562            pr "      RETVAL\n"
8563       );
8564
8565       pr "\n"
8566   ) all_functions
8567
8568 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8569   pr "PREINIT:\n";
8570   pr "      struct guestfs_%s_list *%s;\n" typ n;
8571   pr "      int i;\n";
8572   pr "      HV *hv;\n";
8573   pr " PPCODE:\n";
8574   pr "      %s = guestfs_%s " n name;
8575   generate_c_call_args ~handle:"g" style;
8576   pr ";\n";
8577   do_cleanups ();
8578   pr "      if (%s == NULL)\n" n;
8579   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8580   pr "      EXTEND (SP, %s->len);\n" n;
8581   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8582   pr "        hv = newHV ();\n";
8583   List.iter (
8584     function
8585     | name, FString ->
8586         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8587           name (String.length name) n name
8588     | name, FUUID ->
8589         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8590           name (String.length name) n name
8591     | name, FBuffer ->
8592         pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8593           name (String.length name) n name n name
8594     | name, (FBytes|FUInt64) ->
8595         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8596           name (String.length name) n name
8597     | name, FInt64 ->
8598         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8599           name (String.length name) n name
8600     | name, (FInt32|FUInt32) ->
8601         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8602           name (String.length name) n name
8603     | name, FChar ->
8604         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8605           name (String.length name) n name
8606     | name, FOptPercent ->
8607         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8608           name (String.length name) n name
8609   ) cols;
8610   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8611   pr "      }\n";
8612   pr "      guestfs_free_%s_list (%s);\n" typ n
8613
8614 and generate_perl_struct_code typ cols name style n do_cleanups =
8615   pr "PREINIT:\n";
8616   pr "      struct guestfs_%s *%s;\n" typ n;
8617   pr " PPCODE:\n";
8618   pr "      %s = guestfs_%s " n name;
8619   generate_c_call_args ~handle:"g" style;
8620   pr ";\n";
8621   do_cleanups ();
8622   pr "      if (%s == NULL)\n" n;
8623   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8624   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8625   List.iter (
8626     fun ((name, _) as col) ->
8627       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8628
8629       match col with
8630       | name, FString ->
8631           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8632             n name
8633       | name, FBuffer ->
8634           pr "      PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
8635             n name n name
8636       | name, FUUID ->
8637           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8638             n name
8639       | name, (FBytes|FUInt64) ->
8640           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8641             n name
8642       | name, FInt64 ->
8643           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8644             n name
8645       | name, (FInt32|FUInt32) ->
8646           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8647             n name
8648       | name, FChar ->
8649           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8650             n name
8651       | name, FOptPercent ->
8652           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8653             n name
8654   ) cols;
8655   pr "      free (%s);\n" n
8656
8657 (* Generate Sys/Guestfs.pm. *)
8658 and generate_perl_pm () =
8659   generate_header HashStyle LGPLv2plus;
8660
8661   pr "\
8662 =pod
8663
8664 =head1 NAME
8665
8666 Sys::Guestfs - Perl bindings for libguestfs
8667
8668 =head1 SYNOPSIS
8669
8670  use Sys::Guestfs;
8671
8672  my $h = Sys::Guestfs->new ();
8673  $h->add_drive ('guest.img');
8674  $h->launch ();
8675  $h->mount ('/dev/sda1', '/');
8676  $h->touch ('/hello');
8677  $h->sync ();
8678
8679 =head1 DESCRIPTION
8680
8681 The C<Sys::Guestfs> module provides a Perl XS binding to the
8682 libguestfs API for examining and modifying virtual machine
8683 disk images.
8684
8685 Amongst the things this is good for: making batch configuration
8686 changes to guests, getting disk used/free statistics (see also:
8687 virt-df), migrating between virtualization systems (see also:
8688 virt-p2v), performing partial backups, performing partial guest
8689 clones, cloning guests and changing registry/UUID/hostname info, and
8690 much else besides.
8691
8692 Libguestfs uses Linux kernel and qemu code, and can access any type of
8693 guest filesystem that Linux and qemu can, including but not limited
8694 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8695 schemes, qcow, qcow2, vmdk.
8696
8697 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8698 LVs, what filesystem is in each LV, etc.).  It can also run commands
8699 in the context of the guest.  Also you can access filesystems over
8700 FUSE.
8701
8702 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8703 functions for using libguestfs from Perl, including integration
8704 with libvirt.
8705
8706 =head1 ERRORS
8707
8708 All errors turn into calls to C<croak> (see L<Carp(3)>).
8709
8710 =head1 METHODS
8711
8712 =over 4
8713
8714 =cut
8715
8716 package Sys::Guestfs;
8717
8718 use strict;
8719 use warnings;
8720
8721 require XSLoader;
8722 XSLoader::load ('Sys::Guestfs');
8723
8724 =item $h = Sys::Guestfs->new ();
8725
8726 Create a new guestfs handle.
8727
8728 =cut
8729
8730 sub new {
8731   my $proto = shift;
8732   my $class = ref ($proto) || $proto;
8733
8734   my $self = Sys::Guestfs::_create ();
8735   bless $self, $class;
8736   return $self;
8737 }
8738
8739 ";
8740
8741   (* Actions.  We only need to print documentation for these as
8742    * they are pulled in from the XS code automatically.
8743    *)
8744   List.iter (
8745     fun (name, style, _, flags, _, _, longdesc) ->
8746       if not (List.mem NotInDocs flags) then (
8747         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8748         pr "=item ";
8749         generate_perl_prototype name style;
8750         pr "\n\n";
8751         pr "%s\n\n" longdesc;
8752         if List.mem ProtocolLimitWarning flags then
8753           pr "%s\n\n" protocol_limit_warning;
8754         if List.mem DangerWillRobinson flags then
8755           pr "%s\n\n" danger_will_robinson;
8756         match deprecation_notice flags with
8757         | None -> ()
8758         | Some txt -> pr "%s\n\n" txt
8759       )
8760   ) all_functions_sorted;
8761
8762   (* End of file. *)
8763   pr "\
8764 =cut
8765
8766 1;
8767
8768 =back
8769
8770 =head1 COPYRIGHT
8771
8772 Copyright (C) %s Red Hat Inc.
8773
8774 =head1 LICENSE
8775
8776 Please see the file COPYING.LIB for the full license.
8777
8778 =head1 SEE ALSO
8779
8780 L<guestfs(3)>,
8781 L<guestfish(1)>,
8782 L<http://libguestfs.org>,
8783 L<Sys::Guestfs::Lib(3)>.
8784
8785 =cut
8786 " copyright_years
8787
8788 and generate_perl_prototype name style =
8789   (match fst style with
8790    | RErr -> ()
8791    | RBool n
8792    | RInt n
8793    | RInt64 n
8794    | RConstString n
8795    | RConstOptString n
8796    | RString n
8797    | RBufferOut n -> pr "$%s = " n
8798    | RStruct (n,_)
8799    | RHashtable n -> pr "%%%s = " n
8800    | RStringList n
8801    | RStructList (n,_) -> pr "@%s = " n
8802   );
8803   pr "$h->%s (" name;
8804   let comma = ref false in
8805   List.iter (
8806     fun arg ->
8807       if !comma then pr ", ";
8808       comma := true;
8809       match arg with
8810       | Pathname n | Device n | Dev_or_Path n | String n
8811       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8812           pr "$%s" n
8813       | StringList n | DeviceList n ->
8814           pr "\\@%s" n
8815   ) (snd style);
8816   pr ");"
8817
8818 (* Generate Python C module. *)
8819 and generate_python_c () =
8820   generate_header CStyle LGPLv2plus;
8821
8822   pr "\
8823 #include <Python.h>
8824
8825 #include <stdio.h>
8826 #include <stdlib.h>
8827 #include <assert.h>
8828
8829 #include \"guestfs.h\"
8830
8831 typedef struct {
8832   PyObject_HEAD
8833   guestfs_h *g;
8834 } Pyguestfs_Object;
8835
8836 static guestfs_h *
8837 get_handle (PyObject *obj)
8838 {
8839   assert (obj);
8840   assert (obj != Py_None);
8841   return ((Pyguestfs_Object *) obj)->g;
8842 }
8843
8844 static PyObject *
8845 put_handle (guestfs_h *g)
8846 {
8847   assert (g);
8848   return
8849     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8850 }
8851
8852 /* This list should be freed (but not the strings) after use. */
8853 static char **
8854 get_string_list (PyObject *obj)
8855 {
8856   int i, len;
8857   char **r;
8858
8859   assert (obj);
8860
8861   if (!PyList_Check (obj)) {
8862     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8863     return NULL;
8864   }
8865
8866   len = PyList_Size (obj);
8867   r = malloc (sizeof (char *) * (len+1));
8868   if (r == NULL) {
8869     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8870     return NULL;
8871   }
8872
8873   for (i = 0; i < len; ++i)
8874     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8875   r[len] = NULL;
8876
8877   return r;
8878 }
8879
8880 static PyObject *
8881 put_string_list (char * const * const argv)
8882 {
8883   PyObject *list;
8884   int argc, i;
8885
8886   for (argc = 0; argv[argc] != NULL; ++argc)
8887     ;
8888
8889   list = PyList_New (argc);
8890   for (i = 0; i < argc; ++i)
8891     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8892
8893   return list;
8894 }
8895
8896 static PyObject *
8897 put_table (char * const * const argv)
8898 {
8899   PyObject *list, *item;
8900   int argc, i;
8901
8902   for (argc = 0; argv[argc] != NULL; ++argc)
8903     ;
8904
8905   list = PyList_New (argc >> 1);
8906   for (i = 0; i < argc; i += 2) {
8907     item = PyTuple_New (2);
8908     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8909     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8910     PyList_SetItem (list, i >> 1, item);
8911   }
8912
8913   return list;
8914 }
8915
8916 static void
8917 free_strings (char **argv)
8918 {
8919   int argc;
8920
8921   for (argc = 0; argv[argc] != NULL; ++argc)
8922     free (argv[argc]);
8923   free (argv);
8924 }
8925
8926 static PyObject *
8927 py_guestfs_create (PyObject *self, PyObject *args)
8928 {
8929   guestfs_h *g;
8930
8931   g = guestfs_create ();
8932   if (g == NULL) {
8933     PyErr_SetString (PyExc_RuntimeError,
8934                      \"guestfs.create: failed to allocate handle\");
8935     return NULL;
8936   }
8937   guestfs_set_error_handler (g, NULL, NULL);
8938   return put_handle (g);
8939 }
8940
8941 static PyObject *
8942 py_guestfs_close (PyObject *self, PyObject *args)
8943 {
8944   PyObject *py_g;
8945   guestfs_h *g;
8946
8947   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
8948     return NULL;
8949   g = get_handle (py_g);
8950
8951   guestfs_close (g);
8952
8953   Py_INCREF (Py_None);
8954   return Py_None;
8955 }
8956
8957 ";
8958
8959   let emit_put_list_function typ =
8960     pr "static PyObject *\n";
8961     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
8962     pr "{\n";
8963     pr "  PyObject *list;\n";
8964     pr "  int i;\n";
8965     pr "\n";
8966     pr "  list = PyList_New (%ss->len);\n" typ;
8967     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
8968     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
8969     pr "  return list;\n";
8970     pr "};\n";
8971     pr "\n"
8972   in
8973
8974   (* Structures, turned into Python dictionaries. *)
8975   List.iter (
8976     fun (typ, cols) ->
8977       pr "static PyObject *\n";
8978       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
8979       pr "{\n";
8980       pr "  PyObject *dict;\n";
8981       pr "\n";
8982       pr "  dict = PyDict_New ();\n";
8983       List.iter (
8984         function
8985         | name, FString ->
8986             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8987             pr "                        PyString_FromString (%s->%s));\n"
8988               typ name
8989         | name, FBuffer ->
8990             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8991             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
8992               typ name typ name
8993         | name, FUUID ->
8994             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8995             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
8996               typ name
8997         | name, (FBytes|FUInt64) ->
8998             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8999             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
9000               typ name
9001         | name, FInt64 ->
9002             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9003             pr "                        PyLong_FromLongLong (%s->%s));\n"
9004               typ name
9005         | name, FUInt32 ->
9006             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9007             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
9008               typ name
9009         | name, FInt32 ->
9010             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9011             pr "                        PyLong_FromLong (%s->%s));\n"
9012               typ name
9013         | name, FOptPercent ->
9014             pr "  if (%s->%s >= 0)\n" typ name;
9015             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
9016             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
9017               typ name;
9018             pr "  else {\n";
9019             pr "    Py_INCREF (Py_None);\n";
9020             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
9021             pr "  }\n"
9022         | name, FChar ->
9023             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9024             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
9025       ) cols;
9026       pr "  return dict;\n";
9027       pr "};\n";
9028       pr "\n";
9029
9030   ) structs;
9031
9032   (* Emit a put_TYPE_list function definition only if that function is used. *)
9033   List.iter (
9034     function
9035     | typ, (RStructListOnly | RStructAndList) ->
9036         (* generate the function for typ *)
9037         emit_put_list_function typ
9038     | typ, _ -> () (* empty *)
9039   ) (rstructs_used_by all_functions);
9040
9041   (* Python wrapper functions. *)
9042   List.iter (
9043     fun (name, style, _, _, _, _, _) ->
9044       pr "static PyObject *\n";
9045       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
9046       pr "{\n";
9047
9048       pr "  PyObject *py_g;\n";
9049       pr "  guestfs_h *g;\n";
9050       pr "  PyObject *py_r;\n";
9051
9052       let error_code =
9053         match fst style with
9054         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9055         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9056         | RConstString _ | RConstOptString _ ->
9057             pr "  const char *r;\n"; "NULL"
9058         | RString _ -> pr "  char *r;\n"; "NULL"
9059         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9060         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9061         | RStructList (_, typ) ->
9062             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9063         | RBufferOut _ ->
9064             pr "  char *r;\n";
9065             pr "  size_t size;\n";
9066             "NULL" in
9067
9068       List.iter (
9069         function
9070         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9071             pr "  const char *%s;\n" n
9072         | OptString n -> pr "  const char *%s;\n" n
9073         | StringList n | DeviceList n ->
9074             pr "  PyObject *py_%s;\n" n;
9075             pr "  char **%s;\n" n
9076         | Bool n -> pr "  int %s;\n" n
9077         | Int n -> pr "  int %s;\n" n
9078         | Int64 n -> pr "  long long %s;\n" n
9079       ) (snd style);
9080
9081       pr "\n";
9082
9083       (* Convert the parameters. *)
9084       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
9085       List.iter (
9086         function
9087         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
9088         | OptString _ -> pr "z"
9089         | StringList _ | DeviceList _ -> pr "O"
9090         | Bool _ -> pr "i" (* XXX Python has booleans? *)
9091         | Int _ -> pr "i"
9092         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
9093                              * emulate C's int/long/long long in Python?
9094                              *)
9095       ) (snd style);
9096       pr ":guestfs_%s\",\n" name;
9097       pr "                         &py_g";
9098       List.iter (
9099         function
9100         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
9101         | OptString n -> pr ", &%s" n
9102         | StringList n | DeviceList n -> pr ", &py_%s" n
9103         | Bool n -> pr ", &%s" n
9104         | Int n -> pr ", &%s" n
9105         | Int64 n -> pr ", &%s" n
9106       ) (snd style);
9107
9108       pr "))\n";
9109       pr "    return NULL;\n";
9110
9111       pr "  g = get_handle (py_g);\n";
9112       List.iter (
9113         function
9114         | Pathname _ | Device _ | Dev_or_Path _ | String _
9115         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9116         | StringList n | DeviceList n ->
9117             pr "  %s = get_string_list (py_%s);\n" n n;
9118             pr "  if (!%s) return NULL;\n" n
9119       ) (snd style);
9120
9121       pr "\n";
9122
9123       pr "  r = guestfs_%s " name;
9124       generate_c_call_args ~handle:"g" style;
9125       pr ";\n";
9126
9127       List.iter (
9128         function
9129         | Pathname _ | Device _ | Dev_or_Path _ | String _
9130         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9131         | StringList n | DeviceList n ->
9132             pr "  free (%s);\n" n
9133       ) (snd style);
9134
9135       pr "  if (r == %s) {\n" error_code;
9136       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
9137       pr "    return NULL;\n";
9138       pr "  }\n";
9139       pr "\n";
9140
9141       (match fst style with
9142        | RErr ->
9143            pr "  Py_INCREF (Py_None);\n";
9144            pr "  py_r = Py_None;\n"
9145        | RInt _
9146        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
9147        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
9148        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
9149        | RConstOptString _ ->
9150            pr "  if (r)\n";
9151            pr "    py_r = PyString_FromString (r);\n";
9152            pr "  else {\n";
9153            pr "    Py_INCREF (Py_None);\n";
9154            pr "    py_r = Py_None;\n";
9155            pr "  }\n"
9156        | RString _ ->
9157            pr "  py_r = PyString_FromString (r);\n";
9158            pr "  free (r);\n"
9159        | RStringList _ ->
9160            pr "  py_r = put_string_list (r);\n";
9161            pr "  free_strings (r);\n"
9162        | RStruct (_, typ) ->
9163            pr "  py_r = put_%s (r);\n" typ;
9164            pr "  guestfs_free_%s (r);\n" typ
9165        | RStructList (_, typ) ->
9166            pr "  py_r = put_%s_list (r);\n" typ;
9167            pr "  guestfs_free_%s_list (r);\n" typ
9168        | RHashtable n ->
9169            pr "  py_r = put_table (r);\n";
9170            pr "  free_strings (r);\n"
9171        | RBufferOut _ ->
9172            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
9173            pr "  free (r);\n"
9174       );
9175
9176       pr "  return py_r;\n";
9177       pr "}\n";
9178       pr "\n"
9179   ) all_functions;
9180
9181   (* Table of functions. *)
9182   pr "static PyMethodDef methods[] = {\n";
9183   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
9184   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
9185   List.iter (
9186     fun (name, _, _, _, _, _, _) ->
9187       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
9188         name name
9189   ) all_functions;
9190   pr "  { NULL, NULL, 0, NULL }\n";
9191   pr "};\n";
9192   pr "\n";
9193
9194   (* Init function. *)
9195   pr "\
9196 void
9197 initlibguestfsmod (void)
9198 {
9199   static int initialized = 0;
9200
9201   if (initialized) return;
9202   Py_InitModule ((char *) \"libguestfsmod\", methods);
9203   initialized = 1;
9204 }
9205 "
9206
9207 (* Generate Python module. *)
9208 and generate_python_py () =
9209   generate_header HashStyle LGPLv2plus;
9210
9211   pr "\
9212 u\"\"\"Python bindings for libguestfs
9213
9214 import guestfs
9215 g = guestfs.GuestFS ()
9216 g.add_drive (\"guest.img\")
9217 g.launch ()
9218 parts = g.list_partitions ()
9219
9220 The guestfs module provides a Python binding to the libguestfs API
9221 for examining and modifying virtual machine disk images.
9222
9223 Amongst the things this is good for: making batch configuration
9224 changes to guests, getting disk used/free statistics (see also:
9225 virt-df), migrating between virtualization systems (see also:
9226 virt-p2v), performing partial backups, performing partial guest
9227 clones, cloning guests and changing registry/UUID/hostname info, and
9228 much else besides.
9229
9230 Libguestfs uses Linux kernel and qemu code, and can access any type of
9231 guest filesystem that Linux and qemu can, including but not limited
9232 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
9233 schemes, qcow, qcow2, vmdk.
9234
9235 Libguestfs provides ways to enumerate guest storage (eg. partitions,
9236 LVs, what filesystem is in each LV, etc.).  It can also run commands
9237 in the context of the guest.  Also you can access filesystems over
9238 FUSE.
9239
9240 Errors which happen while using the API are turned into Python
9241 RuntimeError exceptions.
9242
9243 To create a guestfs handle you usually have to perform the following
9244 sequence of calls:
9245
9246 # Create the handle, call add_drive at least once, and possibly
9247 # several times if the guest has multiple block devices:
9248 g = guestfs.GuestFS ()
9249 g.add_drive (\"guest.img\")
9250
9251 # Launch the qemu subprocess and wait for it to become ready:
9252 g.launch ()
9253
9254 # Now you can issue commands, for example:
9255 logvols = g.lvs ()
9256
9257 \"\"\"
9258
9259 import libguestfsmod
9260
9261 class GuestFS:
9262     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
9263
9264     def __init__ (self):
9265         \"\"\"Create a new libguestfs handle.\"\"\"
9266         self._o = libguestfsmod.create ()
9267
9268     def __del__ (self):
9269         libguestfsmod.close (self._o)
9270
9271 ";
9272
9273   List.iter (
9274     fun (name, style, _, flags, _, _, longdesc) ->
9275       pr "    def %s " name;
9276       generate_py_call_args ~handle:"self" (snd style);
9277       pr ":\n";
9278
9279       if not (List.mem NotInDocs flags) then (
9280         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9281         let doc =
9282           match fst style with
9283           | RErr | RInt _ | RInt64 _ | RBool _
9284           | RConstOptString _ | RConstString _
9285           | RString _ | RBufferOut _ -> doc
9286           | RStringList _ ->
9287               doc ^ "\n\nThis function returns a list of strings."
9288           | RStruct (_, typ) ->
9289               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
9290           | RStructList (_, typ) ->
9291               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
9292           | RHashtable _ ->
9293               doc ^ "\n\nThis function returns a dictionary." in
9294         let doc =
9295           if List.mem ProtocolLimitWarning flags then
9296             doc ^ "\n\n" ^ protocol_limit_warning
9297           else doc in
9298         let doc =
9299           if List.mem DangerWillRobinson flags then
9300             doc ^ "\n\n" ^ danger_will_robinson
9301           else doc in
9302         let doc =
9303           match deprecation_notice flags with
9304           | None -> doc
9305           | Some txt -> doc ^ "\n\n" ^ txt in
9306         let doc = pod2text ~width:60 name doc in
9307         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
9308         let doc = String.concat "\n        " doc in
9309         pr "        u\"\"\"%s\"\"\"\n" doc;
9310       );
9311       pr "        return libguestfsmod.%s " name;
9312       generate_py_call_args ~handle:"self._o" (snd style);
9313       pr "\n";
9314       pr "\n";
9315   ) all_functions
9316
9317 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
9318 and generate_py_call_args ~handle args =
9319   pr "(%s" handle;
9320   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9321   pr ")"
9322
9323 (* Useful if you need the longdesc POD text as plain text.  Returns a
9324  * list of lines.
9325  *
9326  * Because this is very slow (the slowest part of autogeneration),
9327  * we memoize the results.
9328  *)
9329 and pod2text ~width name longdesc =
9330   let key = width, name, longdesc in
9331   try Hashtbl.find pod2text_memo key
9332   with Not_found ->
9333     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
9334     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
9335     close_out chan;
9336     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
9337     let chan = open_process_in cmd in
9338     let lines = ref [] in
9339     let rec loop i =
9340       let line = input_line chan in
9341       if i = 1 then             (* discard the first line of output *)
9342         loop (i+1)
9343       else (
9344         let line = triml line in
9345         lines := line :: !lines;
9346         loop (i+1)
9347       ) in
9348     let lines = try loop 1 with End_of_file -> List.rev !lines in
9349     unlink filename;
9350     (match close_process_in chan with
9351      | WEXITED 0 -> ()
9352      | WEXITED i ->
9353          failwithf "pod2text: process exited with non-zero status (%d)" i
9354      | WSIGNALED i | WSTOPPED i ->
9355          failwithf "pod2text: process signalled or stopped by signal %d" i
9356     );
9357     Hashtbl.add pod2text_memo key lines;
9358     pod2text_memo_updated ();
9359     lines
9360
9361 (* Generate ruby bindings. *)
9362 and generate_ruby_c () =
9363   generate_header CStyle LGPLv2plus;
9364
9365   pr "\
9366 #include <stdio.h>
9367 #include <stdlib.h>
9368
9369 #include <ruby.h>
9370
9371 #include \"guestfs.h\"
9372
9373 #include \"extconf.h\"
9374
9375 /* For Ruby < 1.9 */
9376 #ifndef RARRAY_LEN
9377 #define RARRAY_LEN(r) (RARRAY((r))->len)
9378 #endif
9379
9380 static VALUE m_guestfs;                 /* guestfs module */
9381 static VALUE c_guestfs;                 /* guestfs_h handle */
9382 static VALUE e_Error;                   /* used for all errors */
9383
9384 static void ruby_guestfs_free (void *p)
9385 {
9386   if (!p) return;
9387   guestfs_close ((guestfs_h *) p);
9388 }
9389
9390 static VALUE ruby_guestfs_create (VALUE m)
9391 {
9392   guestfs_h *g;
9393
9394   g = guestfs_create ();
9395   if (!g)
9396     rb_raise (e_Error, \"failed to create guestfs handle\");
9397
9398   /* Don't print error messages to stderr by default. */
9399   guestfs_set_error_handler (g, NULL, NULL);
9400
9401   /* Wrap it, and make sure the close function is called when the
9402    * handle goes away.
9403    */
9404   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9405 }
9406
9407 static VALUE ruby_guestfs_close (VALUE gv)
9408 {
9409   guestfs_h *g;
9410   Data_Get_Struct (gv, guestfs_h, g);
9411
9412   ruby_guestfs_free (g);
9413   DATA_PTR (gv) = NULL;
9414
9415   return Qnil;
9416 }
9417
9418 ";
9419
9420   List.iter (
9421     fun (name, style, _, _, _, _, _) ->
9422       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9423       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9424       pr ")\n";
9425       pr "{\n";
9426       pr "  guestfs_h *g;\n";
9427       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9428       pr "  if (!g)\n";
9429       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9430         name;
9431       pr "\n";
9432
9433       List.iter (
9434         function
9435         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9436             pr "  Check_Type (%sv, T_STRING);\n" n;
9437             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9438             pr "  if (!%s)\n" n;
9439             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9440             pr "              \"%s\", \"%s\");\n" n name
9441         | OptString n ->
9442             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9443         | StringList n | DeviceList n ->
9444             pr "  char **%s;\n" n;
9445             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9446             pr "  {\n";
9447             pr "    int i, len;\n";
9448             pr "    len = RARRAY_LEN (%sv);\n" n;
9449             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9450               n;
9451             pr "    for (i = 0; i < len; ++i) {\n";
9452             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9453             pr "      %s[i] = StringValueCStr (v);\n" n;
9454             pr "    }\n";
9455             pr "    %s[len] = NULL;\n" n;
9456             pr "  }\n";
9457         | Bool n ->
9458             pr "  int %s = RTEST (%sv);\n" n n
9459         | Int n ->
9460             pr "  int %s = NUM2INT (%sv);\n" n n
9461         | Int64 n ->
9462             pr "  long long %s = NUM2LL (%sv);\n" n n
9463       ) (snd style);
9464       pr "\n";
9465
9466       let error_code =
9467         match fst style with
9468         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9469         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9470         | RConstString _ | RConstOptString _ ->
9471             pr "  const char *r;\n"; "NULL"
9472         | RString _ -> pr "  char *r;\n"; "NULL"
9473         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9474         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9475         | RStructList (_, typ) ->
9476             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9477         | RBufferOut _ ->
9478             pr "  char *r;\n";
9479             pr "  size_t size;\n";
9480             "NULL" in
9481       pr "\n";
9482
9483       pr "  r = guestfs_%s " name;
9484       generate_c_call_args ~handle:"g" style;
9485       pr ";\n";
9486
9487       List.iter (
9488         function
9489         | Pathname _ | Device _ | Dev_or_Path _ | String _
9490         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9491         | StringList n | DeviceList n ->
9492             pr "  free (%s);\n" n
9493       ) (snd style);
9494
9495       pr "  if (r == %s)\n" error_code;
9496       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9497       pr "\n";
9498
9499       (match fst style with
9500        | RErr ->
9501            pr "  return Qnil;\n"
9502        | RInt _ | RBool _ ->
9503            pr "  return INT2NUM (r);\n"
9504        | RInt64 _ ->
9505            pr "  return ULL2NUM (r);\n"
9506        | RConstString _ ->
9507            pr "  return rb_str_new2 (r);\n";
9508        | RConstOptString _ ->
9509            pr "  if (r)\n";
9510            pr "    return rb_str_new2 (r);\n";
9511            pr "  else\n";
9512            pr "    return Qnil;\n";
9513        | RString _ ->
9514            pr "  VALUE rv = rb_str_new2 (r);\n";
9515            pr "  free (r);\n";
9516            pr "  return rv;\n";
9517        | RStringList _ ->
9518            pr "  int i, len = 0;\n";
9519            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9520            pr "  VALUE rv = rb_ary_new2 (len);\n";
9521            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9522            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9523            pr "    free (r[i]);\n";
9524            pr "  }\n";
9525            pr "  free (r);\n";
9526            pr "  return rv;\n"
9527        | RStruct (_, typ) ->
9528            let cols = cols_of_struct typ in
9529            generate_ruby_struct_code typ cols
9530        | RStructList (_, typ) ->
9531            let cols = cols_of_struct typ in
9532            generate_ruby_struct_list_code typ cols
9533        | RHashtable _ ->
9534            pr "  VALUE rv = rb_hash_new ();\n";
9535            pr "  int i;\n";
9536            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9537            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9538            pr "    free (r[i]);\n";
9539            pr "    free (r[i+1]);\n";
9540            pr "  }\n";
9541            pr "  free (r);\n";
9542            pr "  return rv;\n"
9543        | RBufferOut _ ->
9544            pr "  VALUE rv = rb_str_new (r, size);\n";
9545            pr "  free (r);\n";
9546            pr "  return rv;\n";
9547       );
9548
9549       pr "}\n";
9550       pr "\n"
9551   ) all_functions;
9552
9553   pr "\
9554 /* Initialize the module. */
9555 void Init__guestfs ()
9556 {
9557   m_guestfs = rb_define_module (\"Guestfs\");
9558   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9559   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9560
9561   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9562   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9563
9564 ";
9565   (* Define the rest of the methods. *)
9566   List.iter (
9567     fun (name, style, _, _, _, _, _) ->
9568       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9569       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9570   ) all_functions;
9571
9572   pr "}\n"
9573
9574 (* Ruby code to return a struct. *)
9575 and generate_ruby_struct_code typ cols =
9576   pr "  VALUE rv = rb_hash_new ();\n";
9577   List.iter (
9578     function
9579     | name, FString ->
9580         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9581     | name, FBuffer ->
9582         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9583     | name, FUUID ->
9584         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9585     | name, (FBytes|FUInt64) ->
9586         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9587     | name, FInt64 ->
9588         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9589     | name, FUInt32 ->
9590         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9591     | name, FInt32 ->
9592         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9593     | name, FOptPercent ->
9594         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9595     | name, FChar -> (* XXX wrong? *)
9596         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9597   ) cols;
9598   pr "  guestfs_free_%s (r);\n" typ;
9599   pr "  return rv;\n"
9600
9601 (* Ruby code to return a struct list. *)
9602 and generate_ruby_struct_list_code typ cols =
9603   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9604   pr "  int i;\n";
9605   pr "  for (i = 0; i < r->len; ++i) {\n";
9606   pr "    VALUE hv = rb_hash_new ();\n";
9607   List.iter (
9608     function
9609     | name, FString ->
9610         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9611     | name, FBuffer ->
9612         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
9613     | name, FUUID ->
9614         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9615     | name, (FBytes|FUInt64) ->
9616         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9617     | name, FInt64 ->
9618         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9619     | name, FUInt32 ->
9620         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9621     | name, FInt32 ->
9622         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9623     | name, FOptPercent ->
9624         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9625     | name, FChar -> (* XXX wrong? *)
9626         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9627   ) cols;
9628   pr "    rb_ary_push (rv, hv);\n";
9629   pr "  }\n";
9630   pr "  guestfs_free_%s_list (r);\n" typ;
9631   pr "  return rv;\n"
9632
9633 (* Generate Java bindings GuestFS.java file. *)
9634 and generate_java_java () =
9635   generate_header CStyle LGPLv2plus;
9636
9637   pr "\
9638 package com.redhat.et.libguestfs;
9639
9640 import java.util.HashMap;
9641 import com.redhat.et.libguestfs.LibGuestFSException;
9642 import com.redhat.et.libguestfs.PV;
9643 import com.redhat.et.libguestfs.VG;
9644 import com.redhat.et.libguestfs.LV;
9645 import com.redhat.et.libguestfs.Stat;
9646 import com.redhat.et.libguestfs.StatVFS;
9647 import com.redhat.et.libguestfs.IntBool;
9648 import com.redhat.et.libguestfs.Dirent;
9649
9650 /**
9651  * The GuestFS object is a libguestfs handle.
9652  *
9653  * @author rjones
9654  */
9655 public class GuestFS {
9656   // Load the native code.
9657   static {
9658     System.loadLibrary (\"guestfs_jni\");
9659   }
9660
9661   /**
9662    * The native guestfs_h pointer.
9663    */
9664   long g;
9665
9666   /**
9667    * Create a libguestfs handle.
9668    *
9669    * @throws LibGuestFSException
9670    */
9671   public GuestFS () throws LibGuestFSException
9672   {
9673     g = _create ();
9674   }
9675   private native long _create () throws LibGuestFSException;
9676
9677   /**
9678    * Close a libguestfs handle.
9679    *
9680    * You can also leave handles to be collected by the garbage
9681    * collector, but this method ensures that the resources used
9682    * by the handle are freed up immediately.  If you call any
9683    * other methods after closing the handle, you will get an
9684    * exception.
9685    *
9686    * @throws LibGuestFSException
9687    */
9688   public void close () throws LibGuestFSException
9689   {
9690     if (g != 0)
9691       _close (g);
9692     g = 0;
9693   }
9694   private native void _close (long g) throws LibGuestFSException;
9695
9696   public void finalize () throws LibGuestFSException
9697   {
9698     close ();
9699   }
9700
9701 ";
9702
9703   List.iter (
9704     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9705       if not (List.mem NotInDocs flags); then (
9706         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9707         let doc =
9708           if List.mem ProtocolLimitWarning flags then
9709             doc ^ "\n\n" ^ protocol_limit_warning
9710           else doc in
9711         let doc =
9712           if List.mem DangerWillRobinson flags then
9713             doc ^ "\n\n" ^ danger_will_robinson
9714           else doc in
9715         let doc =
9716           match deprecation_notice flags with
9717           | None -> doc
9718           | Some txt -> doc ^ "\n\n" ^ txt in
9719         let doc = pod2text ~width:60 name doc in
9720         let doc = List.map (            (* RHBZ#501883 *)
9721           function
9722           | "" -> "<p>"
9723           | nonempty -> nonempty
9724         ) doc in
9725         let doc = String.concat "\n   * " doc in
9726
9727         pr "  /**\n";
9728         pr "   * %s\n" shortdesc;
9729         pr "   * <p>\n";
9730         pr "   * %s\n" doc;
9731         pr "   * @throws LibGuestFSException\n";
9732         pr "   */\n";
9733         pr "  ";
9734       );
9735       generate_java_prototype ~public:true ~semicolon:false name style;
9736       pr "\n";
9737       pr "  {\n";
9738       pr "    if (g == 0)\n";
9739       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9740         name;
9741       pr "    ";
9742       if fst style <> RErr then pr "return ";
9743       pr "_%s " name;
9744       generate_java_call_args ~handle:"g" (snd style);
9745       pr ";\n";
9746       pr "  }\n";
9747       pr "  ";
9748       generate_java_prototype ~privat:true ~native:true name style;
9749       pr "\n";
9750       pr "\n";
9751   ) all_functions;
9752
9753   pr "}\n"
9754
9755 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9756 and generate_java_call_args ~handle args =
9757   pr "(%s" handle;
9758   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9759   pr ")"
9760
9761 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9762     ?(semicolon=true) name style =
9763   if privat then pr "private ";
9764   if public then pr "public ";
9765   if native then pr "native ";
9766
9767   (* return type *)
9768   (match fst style with
9769    | RErr -> pr "void ";
9770    | RInt _ -> pr "int ";
9771    | RInt64 _ -> pr "long ";
9772    | RBool _ -> pr "boolean ";
9773    | RConstString _ | RConstOptString _ | RString _
9774    | RBufferOut _ -> pr "String ";
9775    | RStringList _ -> pr "String[] ";
9776    | RStruct (_, typ) ->
9777        let name = java_name_of_struct typ in
9778        pr "%s " name;
9779    | RStructList (_, typ) ->
9780        let name = java_name_of_struct typ in
9781        pr "%s[] " name;
9782    | RHashtable _ -> pr "HashMap<String,String> ";
9783   );
9784
9785   if native then pr "_%s " name else pr "%s " name;
9786   pr "(";
9787   let needs_comma = ref false in
9788   if native then (
9789     pr "long g";
9790     needs_comma := true
9791   );
9792
9793   (* args *)
9794   List.iter (
9795     fun arg ->
9796       if !needs_comma then pr ", ";
9797       needs_comma := true;
9798
9799       match arg with
9800       | Pathname n
9801       | Device n | Dev_or_Path n
9802       | String n
9803       | OptString n
9804       | FileIn n
9805       | FileOut n ->
9806           pr "String %s" n
9807       | StringList n | DeviceList n ->
9808           pr "String[] %s" n
9809       | Bool n ->
9810           pr "boolean %s" n
9811       | Int n ->
9812           pr "int %s" n
9813       | Int64 n ->
9814           pr "long %s" n
9815   ) (snd style);
9816
9817   pr ")\n";
9818   pr "    throws LibGuestFSException";
9819   if semicolon then pr ";"
9820
9821 and generate_java_struct jtyp cols () =
9822   generate_header CStyle LGPLv2plus;
9823
9824   pr "\
9825 package com.redhat.et.libguestfs;
9826
9827 /**
9828  * Libguestfs %s structure.
9829  *
9830  * @author rjones
9831  * @see GuestFS
9832  */
9833 public class %s {
9834 " jtyp jtyp;
9835
9836   List.iter (
9837     function
9838     | name, FString
9839     | name, FUUID
9840     | name, FBuffer -> pr "  public String %s;\n" name
9841     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9842     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9843     | name, FChar -> pr "  public char %s;\n" name
9844     | name, FOptPercent ->
9845         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9846         pr "  public float %s;\n" name
9847   ) cols;
9848
9849   pr "}\n"
9850
9851 and generate_java_c () =
9852   generate_header CStyle LGPLv2plus;
9853
9854   pr "\
9855 #include <stdio.h>
9856 #include <stdlib.h>
9857 #include <string.h>
9858
9859 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9860 #include \"guestfs.h\"
9861
9862 /* Note that this function returns.  The exception is not thrown
9863  * until after the wrapper function returns.
9864  */
9865 static void
9866 throw_exception (JNIEnv *env, const char *msg)
9867 {
9868   jclass cl;
9869   cl = (*env)->FindClass (env,
9870                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9871   (*env)->ThrowNew (env, cl, msg);
9872 }
9873
9874 JNIEXPORT jlong JNICALL
9875 Java_com_redhat_et_libguestfs_GuestFS__1create
9876   (JNIEnv *env, jobject obj)
9877 {
9878   guestfs_h *g;
9879
9880   g = guestfs_create ();
9881   if (g == NULL) {
9882     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9883     return 0;
9884   }
9885   guestfs_set_error_handler (g, NULL, NULL);
9886   return (jlong) (long) g;
9887 }
9888
9889 JNIEXPORT void JNICALL
9890 Java_com_redhat_et_libguestfs_GuestFS__1close
9891   (JNIEnv *env, jobject obj, jlong jg)
9892 {
9893   guestfs_h *g = (guestfs_h *) (long) jg;
9894   guestfs_close (g);
9895 }
9896
9897 ";
9898
9899   List.iter (
9900     fun (name, style, _, _, _, _, _) ->
9901       pr "JNIEXPORT ";
9902       (match fst style with
9903        | RErr -> pr "void ";
9904        | RInt _ -> pr "jint ";
9905        | RInt64 _ -> pr "jlong ";
9906        | RBool _ -> pr "jboolean ";
9907        | RConstString _ | RConstOptString _ | RString _
9908        | RBufferOut _ -> pr "jstring ";
9909        | RStruct _ | RHashtable _ ->
9910            pr "jobject ";
9911        | RStringList _ | RStructList _ ->
9912            pr "jobjectArray ";
9913       );
9914       pr "JNICALL\n";
9915       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9916       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9917       pr "\n";
9918       pr "  (JNIEnv *env, jobject obj, jlong jg";
9919       List.iter (
9920         function
9921         | Pathname n
9922         | Device n | Dev_or_Path n
9923         | String n
9924         | OptString n
9925         | FileIn n
9926         | FileOut n ->
9927             pr ", jstring j%s" n
9928         | StringList n | DeviceList n ->
9929             pr ", jobjectArray j%s" n
9930         | Bool n ->
9931             pr ", jboolean j%s" n
9932         | Int n ->
9933             pr ", jint j%s" n
9934         | Int64 n ->
9935             pr ", jlong j%s" n
9936       ) (snd style);
9937       pr ")\n";
9938       pr "{\n";
9939       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
9940       let error_code, no_ret =
9941         match fst style with
9942         | RErr -> pr "  int r;\n"; "-1", ""
9943         | RBool _
9944         | RInt _ -> pr "  int r;\n"; "-1", "0"
9945         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
9946         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9947         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9948         | RString _ ->
9949             pr "  jstring jr;\n";
9950             pr "  char *r;\n"; "NULL", "NULL"
9951         | RStringList _ ->
9952             pr "  jobjectArray jr;\n";
9953             pr "  int r_len;\n";
9954             pr "  jclass cl;\n";
9955             pr "  jstring jstr;\n";
9956             pr "  char **r;\n"; "NULL", "NULL"
9957         | RStruct (_, typ) ->
9958             pr "  jobject jr;\n";
9959             pr "  jclass cl;\n";
9960             pr "  jfieldID fl;\n";
9961             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
9962         | RStructList (_, typ) ->
9963             pr "  jobjectArray jr;\n";
9964             pr "  jclass cl;\n";
9965             pr "  jfieldID fl;\n";
9966             pr "  jobject jfl;\n";
9967             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
9968         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
9969         | RBufferOut _ ->
9970             pr "  jstring jr;\n";
9971             pr "  char *r;\n";
9972             pr "  size_t size;\n";
9973             "NULL", "NULL" in
9974       List.iter (
9975         function
9976         | Pathname n
9977         | Device n | Dev_or_Path n
9978         | String n
9979         | OptString n
9980         | FileIn n
9981         | FileOut n ->
9982             pr "  const char *%s;\n" n
9983         | StringList n | DeviceList n ->
9984             pr "  int %s_len;\n" n;
9985             pr "  const char **%s;\n" n
9986         | Bool n
9987         | Int n ->
9988             pr "  int %s;\n" n
9989         | Int64 n ->
9990             pr "  int64_t %s;\n" n
9991       ) (snd style);
9992
9993       let needs_i =
9994         (match fst style with
9995          | RStringList _ | RStructList _ -> true
9996          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
9997          | RConstOptString _
9998          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
9999           List.exists (function
10000                        | StringList _ -> true
10001                        | DeviceList _ -> true
10002                        | _ -> false) (snd style) in
10003       if needs_i then
10004         pr "  int i;\n";
10005
10006       pr "\n";
10007
10008       (* Get the parameters. *)
10009       List.iter (
10010         function
10011         | Pathname n
10012         | Device n | Dev_or_Path n
10013         | String n
10014         | FileIn n
10015         | FileOut n ->
10016             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
10017         | OptString n ->
10018             (* This is completely undocumented, but Java null becomes
10019              * a NULL parameter.
10020              *)
10021             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
10022         | StringList n | DeviceList n ->
10023             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
10024             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
10025             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10026             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10027               n;
10028             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
10029             pr "  }\n";
10030             pr "  %s[%s_len] = NULL;\n" n n;
10031         | Bool n
10032         | Int n
10033         | Int64 n ->
10034             pr "  %s = j%s;\n" n n
10035       ) (snd style);
10036
10037       (* Make the call. *)
10038       pr "  r = guestfs_%s " name;
10039       generate_c_call_args ~handle:"g" style;
10040       pr ";\n";
10041
10042       (* Release the parameters. *)
10043       List.iter (
10044         function
10045         | Pathname n
10046         | Device n | Dev_or_Path n
10047         | String n
10048         | FileIn n
10049         | FileOut n ->
10050             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10051         | OptString n ->
10052             pr "  if (j%s)\n" n;
10053             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10054         | StringList n | DeviceList n ->
10055             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10056             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10057               n;
10058             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
10059             pr "  }\n";
10060             pr "  free (%s);\n" n
10061         | Bool n
10062         | Int n
10063         | Int64 n -> ()
10064       ) (snd style);
10065
10066       (* Check for errors. *)
10067       pr "  if (r == %s) {\n" error_code;
10068       pr "    throw_exception (env, guestfs_last_error (g));\n";
10069       pr "    return %s;\n" no_ret;
10070       pr "  }\n";
10071
10072       (* Return value. *)
10073       (match fst style with
10074        | RErr -> ()
10075        | RInt _ -> pr "  return (jint) r;\n"
10076        | RBool _ -> pr "  return (jboolean) r;\n"
10077        | RInt64 _ -> pr "  return (jlong) r;\n"
10078        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
10079        | RConstOptString _ ->
10080            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
10081        | RString _ ->
10082            pr "  jr = (*env)->NewStringUTF (env, r);\n";
10083            pr "  free (r);\n";
10084            pr "  return jr;\n"
10085        | RStringList _ ->
10086            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
10087            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
10088            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
10089            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
10090            pr "  for (i = 0; i < r_len; ++i) {\n";
10091            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
10092            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
10093            pr "    free (r[i]);\n";
10094            pr "  }\n";
10095            pr "  free (r);\n";
10096            pr "  return jr;\n"
10097        | RStruct (_, typ) ->
10098            let jtyp = java_name_of_struct typ in
10099            let cols = cols_of_struct typ in
10100            generate_java_struct_return typ jtyp cols
10101        | RStructList (_, typ) ->
10102            let jtyp = java_name_of_struct typ in
10103            let cols = cols_of_struct typ in
10104            generate_java_struct_list_return typ jtyp cols
10105        | RHashtable _ ->
10106            (* XXX *)
10107            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
10108            pr "  return NULL;\n"
10109        | RBufferOut _ ->
10110            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
10111            pr "  free (r);\n";
10112            pr "  return jr;\n"
10113       );
10114
10115       pr "}\n";
10116       pr "\n"
10117   ) all_functions
10118
10119 and generate_java_struct_return typ jtyp cols =
10120   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10121   pr "  jr = (*env)->AllocObject (env, cl);\n";
10122   List.iter (
10123     function
10124     | name, FString ->
10125         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10126         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
10127     | name, FUUID ->
10128         pr "  {\n";
10129         pr "    char s[33];\n";
10130         pr "    memcpy (s, r->%s, 32);\n" name;
10131         pr "    s[32] = 0;\n";
10132         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10133         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10134         pr "  }\n";
10135     | name, FBuffer ->
10136         pr "  {\n";
10137         pr "    int len = r->%s_len;\n" name;
10138         pr "    char s[len+1];\n";
10139         pr "    memcpy (s, r->%s, len);\n" name;
10140         pr "    s[len] = 0;\n";
10141         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10142         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10143         pr "  }\n";
10144     | name, (FBytes|FUInt64|FInt64) ->
10145         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10146         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10147     | name, (FUInt32|FInt32) ->
10148         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10149         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10150     | name, FOptPercent ->
10151         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10152         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
10153     | name, FChar ->
10154         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10155         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10156   ) cols;
10157   pr "  free (r);\n";
10158   pr "  return jr;\n"
10159
10160 and generate_java_struct_list_return typ jtyp cols =
10161   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10162   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
10163   pr "  for (i = 0; i < r->len; ++i) {\n";
10164   pr "    jfl = (*env)->AllocObject (env, cl);\n";
10165   List.iter (
10166     function
10167     | name, FString ->
10168         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10169         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
10170     | name, FUUID ->
10171         pr "    {\n";
10172         pr "      char s[33];\n";
10173         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
10174         pr "      s[32] = 0;\n";
10175         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10176         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10177         pr "    }\n";
10178     | name, FBuffer ->
10179         pr "    {\n";
10180         pr "      int len = r->val[i].%s_len;\n" name;
10181         pr "      char s[len+1];\n";
10182         pr "      memcpy (s, r->val[i].%s, len);\n" name;
10183         pr "      s[len] = 0;\n";
10184         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10185         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10186         pr "    }\n";
10187     | name, (FBytes|FUInt64|FInt64) ->
10188         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10189         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10190     | name, (FUInt32|FInt32) ->
10191         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10192         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10193     | name, FOptPercent ->
10194         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10195         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
10196     | name, FChar ->
10197         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10198         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10199   ) cols;
10200   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
10201   pr "  }\n";
10202   pr "  guestfs_free_%s_list (r);\n" typ;
10203   pr "  return jr;\n"
10204
10205 and generate_java_makefile_inc () =
10206   generate_header HashStyle GPLv2plus;
10207
10208   pr "java_built_sources = \\\n";
10209   List.iter (
10210     fun (typ, jtyp) ->
10211         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
10212   ) java_structs;
10213   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
10214
10215 and generate_haskell_hs () =
10216   generate_header HaskellStyle LGPLv2plus;
10217
10218   (* XXX We only know how to generate partial FFI for Haskell
10219    * at the moment.  Please help out!
10220    *)
10221   let can_generate style =
10222     match style with
10223     | RErr, _
10224     | RInt _, _
10225     | RInt64 _, _ -> true
10226     | RBool _, _
10227     | RConstString _, _
10228     | RConstOptString _, _
10229     | RString _, _
10230     | RStringList _, _
10231     | RStruct _, _
10232     | RStructList _, _
10233     | RHashtable _, _
10234     | RBufferOut _, _ -> false in
10235
10236   pr "\
10237 {-# INCLUDE <guestfs.h> #-}
10238 {-# LANGUAGE ForeignFunctionInterface #-}
10239
10240 module Guestfs (
10241   create";
10242
10243   (* List out the names of the actions we want to export. *)
10244   List.iter (
10245     fun (name, style, _, _, _, _, _) ->
10246       if can_generate style then pr ",\n  %s" name
10247   ) all_functions;
10248
10249   pr "
10250   ) where
10251
10252 -- Unfortunately some symbols duplicate ones already present
10253 -- in Prelude.  We don't know which, so we hard-code a list
10254 -- here.
10255 import Prelude hiding (truncate)
10256
10257 import Foreign
10258 import Foreign.C
10259 import Foreign.C.Types
10260 import IO
10261 import Control.Exception
10262 import Data.Typeable
10263
10264 data GuestfsS = GuestfsS            -- represents the opaque C struct
10265 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
10266 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
10267
10268 -- XXX define properly later XXX
10269 data PV = PV
10270 data VG = VG
10271 data LV = LV
10272 data IntBool = IntBool
10273 data Stat = Stat
10274 data StatVFS = StatVFS
10275 data Hashtable = Hashtable
10276
10277 foreign import ccall unsafe \"guestfs_create\" c_create
10278   :: IO GuestfsP
10279 foreign import ccall unsafe \"&guestfs_close\" c_close
10280   :: FunPtr (GuestfsP -> IO ())
10281 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
10282   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
10283
10284 create :: IO GuestfsH
10285 create = do
10286   p <- c_create
10287   c_set_error_handler p nullPtr nullPtr
10288   h <- newForeignPtr c_close p
10289   return h
10290
10291 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
10292   :: GuestfsP -> IO CString
10293
10294 -- last_error :: GuestfsH -> IO (Maybe String)
10295 -- last_error h = do
10296 --   str <- withForeignPtr h (\\p -> c_last_error p)
10297 --   maybePeek peekCString str
10298
10299 last_error :: GuestfsH -> IO (String)
10300 last_error h = do
10301   str <- withForeignPtr h (\\p -> c_last_error p)
10302   if (str == nullPtr)
10303     then return \"no error\"
10304     else peekCString str
10305
10306 ";
10307
10308   (* Generate wrappers for each foreign function. *)
10309   List.iter (
10310     fun (name, style, _, _, _, _, _) ->
10311       if can_generate style then (
10312         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
10313         pr "  :: ";
10314         generate_haskell_prototype ~handle:"GuestfsP" style;
10315         pr "\n";
10316         pr "\n";
10317         pr "%s :: " name;
10318         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
10319         pr "\n";
10320         pr "%s %s = do\n" name
10321           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
10322         pr "  r <- ";
10323         (* Convert pointer arguments using with* functions. *)
10324         List.iter (
10325           function
10326           | FileIn n
10327           | FileOut n
10328           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
10329           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
10330           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
10331           | Bool _ | Int _ | Int64 _ -> ()
10332         ) (snd style);
10333         (* Convert integer arguments. *)
10334         let args =
10335           List.map (
10336             function
10337             | Bool n -> sprintf "(fromBool %s)" n
10338             | Int n -> sprintf "(fromIntegral %s)" n
10339             | Int64 n -> sprintf "(fromIntegral %s)" n
10340             | FileIn n | FileOut n
10341             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
10342           ) (snd style) in
10343         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
10344           (String.concat " " ("p" :: args));
10345         (match fst style with
10346          | RErr | RInt _ | RInt64 _ | RBool _ ->
10347              pr "  if (r == -1)\n";
10348              pr "    then do\n";
10349              pr "      err <- last_error h\n";
10350              pr "      fail err\n";
10351          | RConstString _ | RConstOptString _ | RString _
10352          | RStringList _ | RStruct _
10353          | RStructList _ | RHashtable _ | RBufferOut _ ->
10354              pr "  if (r == nullPtr)\n";
10355              pr "    then do\n";
10356              pr "      err <- last_error h\n";
10357              pr "      fail err\n";
10358         );
10359         (match fst style with
10360          | RErr ->
10361              pr "    else return ()\n"
10362          | RInt _ ->
10363              pr "    else return (fromIntegral r)\n"
10364          | RInt64 _ ->
10365              pr "    else return (fromIntegral r)\n"
10366          | RBool _ ->
10367              pr "    else return (toBool r)\n"
10368          | RConstString _
10369          | RConstOptString _
10370          | RString _
10371          | RStringList _
10372          | RStruct _
10373          | RStructList _
10374          | RHashtable _
10375          | RBufferOut _ ->
10376              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10377         );
10378         pr "\n";
10379       )
10380   ) all_functions
10381
10382 and generate_haskell_prototype ~handle ?(hs = false) style =
10383   pr "%s -> " handle;
10384   let string = if hs then "String" else "CString" in
10385   let int = if hs then "Int" else "CInt" in
10386   let bool = if hs then "Bool" else "CInt" in
10387   let int64 = if hs then "Integer" else "Int64" in
10388   List.iter (
10389     fun arg ->
10390       (match arg with
10391        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10392        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10393        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10394        | Bool _ -> pr "%s" bool
10395        | Int _ -> pr "%s" int
10396        | Int64 _ -> pr "%s" int
10397        | FileIn _ -> pr "%s" string
10398        | FileOut _ -> pr "%s" string
10399       );
10400       pr " -> ";
10401   ) (snd style);
10402   pr "IO (";
10403   (match fst style with
10404    | RErr -> if not hs then pr "CInt"
10405    | RInt _ -> pr "%s" int
10406    | RInt64 _ -> pr "%s" int64
10407    | RBool _ -> pr "%s" bool
10408    | RConstString _ -> pr "%s" string
10409    | RConstOptString _ -> pr "Maybe %s" string
10410    | RString _ -> pr "%s" string
10411    | RStringList _ -> pr "[%s]" string
10412    | RStruct (_, typ) ->
10413        let name = java_name_of_struct typ in
10414        pr "%s" name
10415    | RStructList (_, typ) ->
10416        let name = java_name_of_struct typ in
10417        pr "[%s]" name
10418    | RHashtable _ -> pr "Hashtable"
10419    | RBufferOut _ -> pr "%s" string
10420   );
10421   pr ")"
10422
10423 and generate_csharp () =
10424   generate_header CPlusPlusStyle LGPLv2plus;
10425
10426   (* XXX Make this configurable by the C# assembly users. *)
10427   let library = "libguestfs.so.0" in
10428
10429   pr "\
10430 // These C# bindings are highly experimental at present.
10431 //
10432 // Firstly they only work on Linux (ie. Mono).  In order to get them
10433 // to work on Windows (ie. .Net) you would need to port the library
10434 // itself to Windows first.
10435 //
10436 // The second issue is that some calls are known to be incorrect and
10437 // can cause Mono to segfault.  Particularly: calls which pass or
10438 // return string[], or return any structure value.  This is because
10439 // we haven't worked out the correct way to do this from C#.
10440 //
10441 // The third issue is that when compiling you get a lot of warnings.
10442 // We are not sure whether the warnings are important or not.
10443 //
10444 // Fourthly we do not routinely build or test these bindings as part
10445 // of the make && make check cycle, which means that regressions might
10446 // go unnoticed.
10447 //
10448 // Suggestions and patches are welcome.
10449
10450 // To compile:
10451 //
10452 // gmcs Libguestfs.cs
10453 // mono Libguestfs.exe
10454 //
10455 // (You'll probably want to add a Test class / static main function
10456 // otherwise this won't do anything useful).
10457
10458 using System;
10459 using System.IO;
10460 using System.Runtime.InteropServices;
10461 using System.Runtime.Serialization;
10462 using System.Collections;
10463
10464 namespace Guestfs
10465 {
10466   class Error : System.ApplicationException
10467   {
10468     public Error (string message) : base (message) {}
10469     protected Error (SerializationInfo info, StreamingContext context) {}
10470   }
10471
10472   class Guestfs
10473   {
10474     IntPtr _handle;
10475
10476     [DllImport (\"%s\")]
10477     static extern IntPtr guestfs_create ();
10478
10479     public Guestfs ()
10480     {
10481       _handle = guestfs_create ();
10482       if (_handle == IntPtr.Zero)
10483         throw new Error (\"could not create guestfs handle\");
10484     }
10485
10486     [DllImport (\"%s\")]
10487     static extern void guestfs_close (IntPtr h);
10488
10489     ~Guestfs ()
10490     {
10491       guestfs_close (_handle);
10492     }
10493
10494     [DllImport (\"%s\")]
10495     static extern string guestfs_last_error (IntPtr h);
10496
10497 " library library library;
10498
10499   (* Generate C# structure bindings.  We prefix struct names with
10500    * underscore because C# cannot have conflicting struct names and
10501    * method names (eg. "class stat" and "stat").
10502    *)
10503   List.iter (
10504     fun (typ, cols) ->
10505       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10506       pr "    public class _%s {\n" typ;
10507       List.iter (
10508         function
10509         | name, FChar -> pr "      char %s;\n" name
10510         | name, FString -> pr "      string %s;\n" name
10511         | name, FBuffer ->
10512             pr "      uint %s_len;\n" name;
10513             pr "      string %s;\n" name
10514         | name, FUUID ->
10515             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10516             pr "      string %s;\n" name
10517         | name, FUInt32 -> pr "      uint %s;\n" name
10518         | name, FInt32 -> pr "      int %s;\n" name
10519         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10520         | name, FInt64 -> pr "      long %s;\n" name
10521         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10522       ) cols;
10523       pr "    }\n";
10524       pr "\n"
10525   ) structs;
10526
10527   (* Generate C# function bindings. *)
10528   List.iter (
10529     fun (name, style, _, _, _, shortdesc, _) ->
10530       let rec csharp_return_type () =
10531         match fst style with
10532         | RErr -> "void"
10533         | RBool n -> "bool"
10534         | RInt n -> "int"
10535         | RInt64 n -> "long"
10536         | RConstString n
10537         | RConstOptString n
10538         | RString n
10539         | RBufferOut n -> "string"
10540         | RStruct (_,n) -> "_" ^ n
10541         | RHashtable n -> "Hashtable"
10542         | RStringList n -> "string[]"
10543         | RStructList (_,n) -> sprintf "_%s[]" n
10544
10545       and c_return_type () =
10546         match fst style with
10547         | RErr
10548         | RBool _
10549         | RInt _ -> "int"
10550         | RInt64 _ -> "long"
10551         | RConstString _
10552         | RConstOptString _
10553         | RString _
10554         | RBufferOut _ -> "string"
10555         | RStruct (_,n) -> "_" ^ n
10556         | RHashtable _
10557         | RStringList _ -> "string[]"
10558         | RStructList (_,n) -> sprintf "_%s[]" n
10559
10560       and c_error_comparison () =
10561         match fst style with
10562         | RErr
10563         | RBool _
10564         | RInt _
10565         | RInt64 _ -> "== -1"
10566         | RConstString _
10567         | RConstOptString _
10568         | RString _
10569         | RBufferOut _
10570         | RStruct (_,_)
10571         | RHashtable _
10572         | RStringList _
10573         | RStructList (_,_) -> "== null"
10574
10575       and generate_extern_prototype () =
10576         pr "    static extern %s guestfs_%s (IntPtr h"
10577           (c_return_type ()) name;
10578         List.iter (
10579           function
10580           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10581           | FileIn n | FileOut n ->
10582               pr ", [In] string %s" n
10583           | StringList n | DeviceList n ->
10584               pr ", [In] string[] %s" n
10585           | Bool n ->
10586               pr ", bool %s" n
10587           | Int n ->
10588               pr ", int %s" n
10589           | Int64 n ->
10590               pr ", long %s" n
10591         ) (snd style);
10592         pr ");\n"
10593
10594       and generate_public_prototype () =
10595         pr "    public %s %s (" (csharp_return_type ()) name;
10596         let comma = ref false in
10597         let next () =
10598           if !comma then pr ", ";
10599           comma := true
10600         in
10601         List.iter (
10602           function
10603           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10604           | FileIn n | FileOut n ->
10605               next (); pr "string %s" n
10606           | StringList n | DeviceList n ->
10607               next (); pr "string[] %s" n
10608           | Bool n ->
10609               next (); pr "bool %s" n
10610           | Int n ->
10611               next (); pr "int %s" n
10612           | Int64 n ->
10613               next (); pr "long %s" n
10614         ) (snd style);
10615         pr ")\n"
10616
10617       and generate_call () =
10618         pr "guestfs_%s (_handle" name;
10619         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10620         pr ");\n";
10621       in
10622
10623       pr "    [DllImport (\"%s\")]\n" library;
10624       generate_extern_prototype ();
10625       pr "\n";
10626       pr "    /// <summary>\n";
10627       pr "    /// %s\n" shortdesc;
10628       pr "    /// </summary>\n";
10629       generate_public_prototype ();
10630       pr "    {\n";
10631       pr "      %s r;\n" (c_return_type ());
10632       pr "      r = ";
10633       generate_call ();
10634       pr "      if (r %s)\n" (c_error_comparison ());
10635       pr "        throw new Error (guestfs_last_error (_handle));\n";
10636       (match fst style with
10637        | RErr -> ()
10638        | RBool _ ->
10639            pr "      return r != 0 ? true : false;\n"
10640        | RHashtable _ ->
10641            pr "      Hashtable rr = new Hashtable ();\n";
10642            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10643            pr "        rr.Add (r[i], r[i+1]);\n";
10644            pr "      return rr;\n"
10645        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10646        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10647        | RStructList _ ->
10648            pr "      return r;\n"
10649       );
10650       pr "    }\n";
10651       pr "\n";
10652   ) all_functions_sorted;
10653
10654   pr "  }
10655 }
10656 "
10657
10658 and generate_bindtests () =
10659   generate_header CStyle LGPLv2plus;
10660
10661   pr "\
10662 #include <stdio.h>
10663 #include <stdlib.h>
10664 #include <inttypes.h>
10665 #include <string.h>
10666
10667 #include \"guestfs.h\"
10668 #include \"guestfs-internal.h\"
10669 #include \"guestfs-internal-actions.h\"
10670 #include \"guestfs_protocol.h\"
10671
10672 #define error guestfs_error
10673 #define safe_calloc guestfs_safe_calloc
10674 #define safe_malloc guestfs_safe_malloc
10675
10676 static void
10677 print_strings (char *const *argv)
10678 {
10679   int argc;
10680
10681   printf (\"[\");
10682   for (argc = 0; argv[argc] != NULL; ++argc) {
10683     if (argc > 0) printf (\", \");
10684     printf (\"\\\"%%s\\\"\", argv[argc]);
10685   }
10686   printf (\"]\\n\");
10687 }
10688
10689 /* The test0 function prints its parameters to stdout. */
10690 ";
10691
10692   let test0, tests =
10693     match test_functions with
10694     | [] -> assert false
10695     | test0 :: tests -> test0, tests in
10696
10697   let () =
10698     let (name, style, _, _, _, _, _) = test0 in
10699     generate_prototype ~extern:false ~semicolon:false ~newline:true
10700       ~handle:"g" ~prefix:"guestfs__" name style;
10701     pr "{\n";
10702     List.iter (
10703       function
10704       | Pathname n
10705       | Device n | Dev_or_Path n
10706       | String n
10707       | FileIn n
10708       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10709       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10710       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10711       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10712       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10713       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10714     ) (snd style);
10715     pr "  /* Java changes stdout line buffering so we need this: */\n";
10716     pr "  fflush (stdout);\n";
10717     pr "  return 0;\n";
10718     pr "}\n";
10719     pr "\n" in
10720
10721   List.iter (
10722     fun (name, style, _, _, _, _, _) ->
10723       if String.sub name (String.length name - 3) 3 <> "err" then (
10724         pr "/* Test normal return. */\n";
10725         generate_prototype ~extern:false ~semicolon:false ~newline:true
10726           ~handle:"g" ~prefix:"guestfs__" name style;
10727         pr "{\n";
10728         (match fst style with
10729          | RErr ->
10730              pr "  return 0;\n"
10731          | RInt _ ->
10732              pr "  int r;\n";
10733              pr "  sscanf (val, \"%%d\", &r);\n";
10734              pr "  return r;\n"
10735          | RInt64 _ ->
10736              pr "  int64_t r;\n";
10737              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10738              pr "  return r;\n"
10739          | RBool _ ->
10740              pr "  return STREQ (val, \"true\");\n"
10741          | RConstString _
10742          | RConstOptString _ ->
10743              (* Can't return the input string here.  Return a static
10744               * string so we ensure we get a segfault if the caller
10745               * tries to free it.
10746               *)
10747              pr "  return \"static string\";\n"
10748          | RString _ ->
10749              pr "  return strdup (val);\n"
10750          | RStringList _ ->
10751              pr "  char **strs;\n";
10752              pr "  int n, i;\n";
10753              pr "  sscanf (val, \"%%d\", &n);\n";
10754              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10755              pr "  for (i = 0; i < n; ++i) {\n";
10756              pr "    strs[i] = safe_malloc (g, 16);\n";
10757              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10758              pr "  }\n";
10759              pr "  strs[n] = NULL;\n";
10760              pr "  return strs;\n"
10761          | RStruct (_, typ) ->
10762              pr "  struct guestfs_%s *r;\n" typ;
10763              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10764              pr "  return r;\n"
10765          | RStructList (_, typ) ->
10766              pr "  struct guestfs_%s_list *r;\n" typ;
10767              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10768              pr "  sscanf (val, \"%%d\", &r->len);\n";
10769              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10770              pr "  return r;\n"
10771          | RHashtable _ ->
10772              pr "  char **strs;\n";
10773              pr "  int n, i;\n";
10774              pr "  sscanf (val, \"%%d\", &n);\n";
10775              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10776              pr "  for (i = 0; i < n; ++i) {\n";
10777              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10778              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10779              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10780              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10781              pr "  }\n";
10782              pr "  strs[n*2] = NULL;\n";
10783              pr "  return strs;\n"
10784          | RBufferOut _ ->
10785              pr "  return strdup (val);\n"
10786         );
10787         pr "}\n";
10788         pr "\n"
10789       ) else (
10790         pr "/* Test error return. */\n";
10791         generate_prototype ~extern:false ~semicolon:false ~newline:true
10792           ~handle:"g" ~prefix:"guestfs__" name style;
10793         pr "{\n";
10794         pr "  error (g, \"error\");\n";
10795         (match fst style with
10796          | RErr | RInt _ | RInt64 _ | RBool _ ->
10797              pr "  return -1;\n"
10798          | RConstString _ | RConstOptString _
10799          | RString _ | RStringList _ | RStruct _
10800          | RStructList _
10801          | RHashtable _
10802          | RBufferOut _ ->
10803              pr "  return NULL;\n"
10804         );
10805         pr "}\n";
10806         pr "\n"
10807       )
10808   ) tests
10809
10810 and generate_ocaml_bindtests () =
10811   generate_header OCamlStyle GPLv2plus;
10812
10813   pr "\
10814 let () =
10815   let g = Guestfs.create () in
10816 ";
10817
10818   let mkargs args =
10819     String.concat " " (
10820       List.map (
10821         function
10822         | CallString s -> "\"" ^ s ^ "\""
10823         | CallOptString None -> "None"
10824         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10825         | CallStringList xs ->
10826             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10827         | CallInt i when i >= 0 -> string_of_int i
10828         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10829         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10830         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10831         | CallBool b -> string_of_bool b
10832       ) args
10833     )
10834   in
10835
10836   generate_lang_bindtests (
10837     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10838   );
10839
10840   pr "print_endline \"EOF\"\n"
10841
10842 and generate_perl_bindtests () =
10843   pr "#!/usr/bin/perl -w\n";
10844   generate_header HashStyle GPLv2plus;
10845
10846   pr "\
10847 use strict;
10848
10849 use Sys::Guestfs;
10850
10851 my $g = Sys::Guestfs->new ();
10852 ";
10853
10854   let mkargs args =
10855     String.concat ", " (
10856       List.map (
10857         function
10858         | CallString s -> "\"" ^ s ^ "\""
10859         | CallOptString None -> "undef"
10860         | CallOptString (Some s) -> sprintf "\"%s\"" s
10861         | CallStringList xs ->
10862             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10863         | CallInt i -> string_of_int i
10864         | CallInt64 i -> Int64.to_string i
10865         | CallBool b -> if b then "1" else "0"
10866       ) args
10867     )
10868   in
10869
10870   generate_lang_bindtests (
10871     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10872   );
10873
10874   pr "print \"EOF\\n\"\n"
10875
10876 and generate_python_bindtests () =
10877   generate_header HashStyle GPLv2plus;
10878
10879   pr "\
10880 import guestfs
10881
10882 g = guestfs.GuestFS ()
10883 ";
10884
10885   let mkargs args =
10886     String.concat ", " (
10887       List.map (
10888         function
10889         | CallString s -> "\"" ^ s ^ "\""
10890         | CallOptString None -> "None"
10891         | CallOptString (Some s) -> sprintf "\"%s\"" s
10892         | CallStringList xs ->
10893             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10894         | CallInt i -> string_of_int i
10895         | CallInt64 i -> Int64.to_string i
10896         | CallBool b -> if b then "1" else "0"
10897       ) args
10898     )
10899   in
10900
10901   generate_lang_bindtests (
10902     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10903   );
10904
10905   pr "print \"EOF\"\n"
10906
10907 and generate_ruby_bindtests () =
10908   generate_header HashStyle GPLv2plus;
10909
10910   pr "\
10911 require 'guestfs'
10912
10913 g = Guestfs::create()
10914 ";
10915
10916   let mkargs args =
10917     String.concat ", " (
10918       List.map (
10919         function
10920         | CallString s -> "\"" ^ s ^ "\""
10921         | CallOptString None -> "nil"
10922         | CallOptString (Some s) -> sprintf "\"%s\"" s
10923         | CallStringList xs ->
10924             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10925         | CallInt i -> string_of_int i
10926         | CallInt64 i -> Int64.to_string i
10927         | CallBool b -> string_of_bool b
10928       ) args
10929     )
10930   in
10931
10932   generate_lang_bindtests (
10933     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10934   );
10935
10936   pr "print \"EOF\\n\"\n"
10937
10938 and generate_java_bindtests () =
10939   generate_header CStyle GPLv2plus;
10940
10941   pr "\
10942 import com.redhat.et.libguestfs.*;
10943
10944 public class Bindtests {
10945     public static void main (String[] argv)
10946     {
10947         try {
10948             GuestFS g = new GuestFS ();
10949 ";
10950
10951   let mkargs args =
10952     String.concat ", " (
10953       List.map (
10954         function
10955         | CallString s -> "\"" ^ s ^ "\""
10956         | CallOptString None -> "null"
10957         | CallOptString (Some s) -> sprintf "\"%s\"" s
10958         | CallStringList xs ->
10959             "new String[]{" ^
10960               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
10961         | CallInt i -> string_of_int i
10962         | CallInt64 i -> Int64.to_string i
10963         | CallBool b -> string_of_bool b
10964       ) args
10965     )
10966   in
10967
10968   generate_lang_bindtests (
10969     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
10970   );
10971
10972   pr "
10973             System.out.println (\"EOF\");
10974         }
10975         catch (Exception exn) {
10976             System.err.println (exn);
10977             System.exit (1);
10978         }
10979     }
10980 }
10981 "
10982
10983 and generate_haskell_bindtests () =
10984   generate_header HaskellStyle GPLv2plus;
10985
10986   pr "\
10987 module Bindtests where
10988 import qualified Guestfs
10989
10990 main = do
10991   g <- Guestfs.create
10992 ";
10993
10994   let mkargs args =
10995     String.concat " " (
10996       List.map (
10997         function
10998         | CallString s -> "\"" ^ s ^ "\""
10999         | CallOptString None -> "Nothing"
11000         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
11001         | CallStringList xs ->
11002             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11003         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
11004         | CallInt i -> string_of_int i
11005         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
11006         | CallInt64 i -> Int64.to_string i
11007         | CallBool true -> "True"
11008         | CallBool false -> "False"
11009       ) args
11010     )
11011   in
11012
11013   generate_lang_bindtests (
11014     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
11015   );
11016
11017   pr "  putStrLn \"EOF\"\n"
11018
11019 (* Language-independent bindings tests - we do it this way to
11020  * ensure there is parity in testing bindings across all languages.
11021  *)
11022 and generate_lang_bindtests call =
11023   call "test0" [CallString "abc"; CallOptString (Some "def");
11024                 CallStringList []; CallBool false;
11025                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11026   call "test0" [CallString "abc"; CallOptString None;
11027                 CallStringList []; CallBool false;
11028                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11029   call "test0" [CallString ""; CallOptString (Some "def");
11030                 CallStringList []; CallBool false;
11031                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11032   call "test0" [CallString ""; CallOptString (Some "");
11033                 CallStringList []; CallBool false;
11034                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11035   call "test0" [CallString "abc"; CallOptString (Some "def");
11036                 CallStringList ["1"]; CallBool false;
11037                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11038   call "test0" [CallString "abc"; CallOptString (Some "def");
11039                 CallStringList ["1"; "2"]; CallBool false;
11040                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11041   call "test0" [CallString "abc"; CallOptString (Some "def");
11042                 CallStringList ["1"]; CallBool true;
11043                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11044   call "test0" [CallString "abc"; CallOptString (Some "def");
11045                 CallStringList ["1"]; CallBool false;
11046                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
11047   call "test0" [CallString "abc"; CallOptString (Some "def");
11048                 CallStringList ["1"]; CallBool false;
11049                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
11050   call "test0" [CallString "abc"; CallOptString (Some "def");
11051                 CallStringList ["1"]; CallBool false;
11052                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
11053   call "test0" [CallString "abc"; CallOptString (Some "def");
11054                 CallStringList ["1"]; CallBool false;
11055                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
11056   call "test0" [CallString "abc"; CallOptString (Some "def");
11057                 CallStringList ["1"]; CallBool false;
11058                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
11059   call "test0" [CallString "abc"; CallOptString (Some "def");
11060                 CallStringList ["1"]; CallBool false;
11061                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
11062
11063 (* XXX Add here tests of the return and error functions. *)
11064
11065 (* Code to generator bindings for virt-inspector.  Currently only
11066  * implemented for OCaml code (for virt-p2v 2.0).
11067  *)
11068 let rng_input = "inspector/virt-inspector.rng"
11069
11070 (* Read the input file and parse it into internal structures.  This is
11071  * by no means a complete RELAX NG parser, but is just enough to be
11072  * able to parse the specific input file.
11073  *)
11074 type rng =
11075   | Element of string * rng list        (* <element name=name/> *)
11076   | Attribute of string * rng list        (* <attribute name=name/> *)
11077   | Interleave of rng list                (* <interleave/> *)
11078   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
11079   | OneOrMore of rng                        (* <oneOrMore/> *)
11080   | Optional of rng                        (* <optional/> *)
11081   | Choice of string list                (* <choice><value/>*</choice> *)
11082   | Value of string                        (* <value>str</value> *)
11083   | Text                                (* <text/> *)
11084
11085 let rec string_of_rng = function
11086   | Element (name, xs) ->
11087       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11088   | Attribute (name, xs) ->
11089       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11090   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
11091   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
11092   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
11093   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
11094   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
11095   | Value value -> "Value \"" ^ value ^ "\""
11096   | Text -> "Text"
11097
11098 and string_of_rng_list xs =
11099   String.concat ", " (List.map string_of_rng xs)
11100
11101 let rec parse_rng ?defines context = function
11102   | [] -> []
11103   | Xml.Element ("element", ["name", name], children) :: rest ->
11104       Element (name, parse_rng ?defines context children)
11105       :: parse_rng ?defines context rest
11106   | Xml.Element ("attribute", ["name", name], children) :: rest ->
11107       Attribute (name, parse_rng ?defines context children)
11108       :: parse_rng ?defines context rest
11109   | Xml.Element ("interleave", [], children) :: rest ->
11110       Interleave (parse_rng ?defines context children)
11111       :: parse_rng ?defines context rest
11112   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
11113       let rng = parse_rng ?defines context [child] in
11114       (match rng with
11115        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
11116        | _ ->
11117            failwithf "%s: <zeroOrMore> contains more than one child element"
11118              context
11119       )
11120   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
11121       let rng = parse_rng ?defines context [child] in
11122       (match rng with
11123        | [child] -> OneOrMore child :: parse_rng ?defines context rest
11124        | _ ->
11125            failwithf "%s: <oneOrMore> contains more than one child element"
11126              context
11127       )
11128   | Xml.Element ("optional", [], [child]) :: rest ->
11129       let rng = parse_rng ?defines context [child] in
11130       (match rng with
11131        | [child] -> Optional child :: parse_rng ?defines context rest
11132        | _ ->
11133            failwithf "%s: <optional> contains more than one child element"
11134              context
11135       )
11136   | Xml.Element ("choice", [], children) :: rest ->
11137       let values = List.map (
11138         function Xml.Element ("value", [], [Xml.PCData value]) -> value
11139         | _ ->
11140             failwithf "%s: can't handle anything except <value> in <choice>"
11141               context
11142       ) children in
11143       Choice values
11144       :: parse_rng ?defines context rest
11145   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
11146       Value value :: parse_rng ?defines context rest
11147   | Xml.Element ("text", [], []) :: rest ->
11148       Text :: parse_rng ?defines context rest
11149   | Xml.Element ("ref", ["name", name], []) :: rest ->
11150       (* Look up the reference.  Because of limitations in this parser,
11151        * we can't handle arbitrarily nested <ref> yet.  You can only
11152        * use <ref> from inside <start>.
11153        *)
11154       (match defines with
11155        | None ->
11156            failwithf "%s: contains <ref>, but no refs are defined yet" context
11157        | Some map ->
11158            let rng = StringMap.find name map in
11159            rng @ parse_rng ?defines context rest
11160       )
11161   | x :: _ ->
11162       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
11163
11164 let grammar =
11165   let xml = Xml.parse_file rng_input in
11166   match xml with
11167   | Xml.Element ("grammar", _,
11168                  Xml.Element ("start", _, gram) :: defines) ->
11169       (* The <define/> elements are referenced in the <start> section,
11170        * so build a map of those first.
11171        *)
11172       let defines = List.fold_left (
11173         fun map ->
11174           function Xml.Element ("define", ["name", name], defn) ->
11175             StringMap.add name defn map
11176           | _ ->
11177               failwithf "%s: expected <define name=name/>" rng_input
11178       ) StringMap.empty defines in
11179       let defines = StringMap.mapi parse_rng defines in
11180
11181       (* Parse the <start> clause, passing the defines. *)
11182       parse_rng ~defines "<start>" gram
11183   | _ ->
11184       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
11185         rng_input
11186
11187 let name_of_field = function
11188   | Element (name, _) | Attribute (name, _)
11189   | ZeroOrMore (Element (name, _))
11190   | OneOrMore (Element (name, _))
11191   | Optional (Element (name, _)) -> name
11192   | Optional (Attribute (name, _)) -> name
11193   | Text -> (* an unnamed field in an element *)
11194       "data"
11195   | rng ->
11196       failwithf "name_of_field failed at: %s" (string_of_rng rng)
11197
11198 (* At the moment this function only generates OCaml types.  However we
11199  * should parameterize it later so it can generate types/structs in a
11200  * variety of languages.
11201  *)
11202 let generate_types xs =
11203   (* A simple type is one that can be printed out directly, eg.
11204    * "string option".  A complex type is one which has a name and has
11205    * to be defined via another toplevel definition, eg. a struct.
11206    *
11207    * generate_type generates code for either simple or complex types.
11208    * In the simple case, it returns the string ("string option").  In
11209    * the complex case, it returns the name ("mountpoint").  In the
11210    * complex case it has to print out the definition before returning,
11211    * so it should only be called when we are at the beginning of a
11212    * new line (BOL context).
11213    *)
11214   let rec generate_type = function
11215     | Text ->                                (* string *)
11216         "string", true
11217     | Choice values ->                        (* [`val1|`val2|...] *)
11218         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
11219     | ZeroOrMore rng ->                        (* <rng> list *)
11220         let t, is_simple = generate_type rng in
11221         t ^ " list (* 0 or more *)", is_simple
11222     | OneOrMore rng ->                        (* <rng> list *)
11223         let t, is_simple = generate_type rng in
11224         t ^ " list (* 1 or more *)", is_simple
11225                                         (* virt-inspector hack: bool *)
11226     | Optional (Attribute (name, [Value "1"])) ->
11227         "bool", true
11228     | Optional rng ->                        (* <rng> list *)
11229         let t, is_simple = generate_type rng in
11230         t ^ " option", is_simple
11231                                         (* type name = { fields ... } *)
11232     | Element (name, fields) when is_attrs_interleave fields ->
11233         generate_type_struct name (get_attrs_interleave fields)
11234     | Element (name, [field])                (* type name = field *)
11235     | Attribute (name, [field]) ->
11236         let t, is_simple = generate_type field in
11237         if is_simple then (t, true)
11238         else (
11239           pr "type %s = %s\n" name t;
11240           name, false
11241         )
11242     | Element (name, fields) ->              (* type name = { fields ... } *)
11243         generate_type_struct name fields
11244     | rng ->
11245         failwithf "generate_type failed at: %s" (string_of_rng rng)
11246
11247   and is_attrs_interleave = function
11248     | [Interleave _] -> true
11249     | Attribute _ :: fields -> is_attrs_interleave fields
11250     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11251     | _ -> false
11252
11253   and get_attrs_interleave = function
11254     | [Interleave fields] -> fields
11255     | ((Attribute _) as field) :: fields
11256     | ((Optional (Attribute _)) as field) :: fields ->
11257         field :: get_attrs_interleave fields
11258     | _ -> assert false
11259
11260   and generate_types xs =
11261     List.iter (fun x -> ignore (generate_type x)) xs
11262
11263   and generate_type_struct name fields =
11264     (* Calculate the types of the fields first.  We have to do this
11265      * before printing anything so we are still in BOL context.
11266      *)
11267     let types = List.map fst (List.map generate_type fields) in
11268
11269     (* Special case of a struct containing just a string and another
11270      * field.  Turn it into an assoc list.
11271      *)
11272     match types with
11273     | ["string"; other] ->
11274         let fname1, fname2 =
11275           match fields with
11276           | [f1; f2] -> name_of_field f1, name_of_field f2
11277           | _ -> assert false in
11278         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
11279         name, false
11280
11281     | types ->
11282         pr "type %s = {\n" name;
11283         List.iter (
11284           fun (field, ftype) ->
11285             let fname = name_of_field field in
11286             pr "  %s_%s : %s;\n" name fname ftype
11287         ) (List.combine fields types);
11288         pr "}\n";
11289         (* Return the name of this type, and
11290          * false because it's not a simple type.
11291          *)
11292         name, false
11293   in
11294
11295   generate_types xs
11296
11297 let generate_parsers xs =
11298   (* As for generate_type above, generate_parser makes a parser for
11299    * some type, and returns the name of the parser it has generated.
11300    * Because it (may) need to print something, it should always be
11301    * called in BOL context.
11302    *)
11303   let rec generate_parser = function
11304     | Text ->                                (* string *)
11305         "string_child_or_empty"
11306     | Choice values ->                        (* [`val1|`val2|...] *)
11307         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
11308           (String.concat "|"
11309              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
11310     | ZeroOrMore rng ->                        (* <rng> list *)
11311         let pa = generate_parser rng in
11312         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11313     | OneOrMore rng ->                        (* <rng> list *)
11314         let pa = generate_parser rng in
11315         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11316                                         (* virt-inspector hack: bool *)
11317     | Optional (Attribute (name, [Value "1"])) ->
11318         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
11319     | Optional rng ->                        (* <rng> list *)
11320         let pa = generate_parser rng in
11321         sprintf "(function None -> None | Some x -> Some (%s x))" pa
11322                                         (* type name = { fields ... } *)
11323     | Element (name, fields) when is_attrs_interleave fields ->
11324         generate_parser_struct name (get_attrs_interleave fields)
11325     | Element (name, [field]) ->        (* type name = field *)
11326         let pa = generate_parser field in
11327         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11328         pr "let %s =\n" parser_name;
11329         pr "  %s\n" pa;
11330         pr "let parse_%s = %s\n" name parser_name;
11331         parser_name
11332     | Attribute (name, [field]) ->
11333         let pa = generate_parser field in
11334         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11335         pr "let %s =\n" parser_name;
11336         pr "  %s\n" pa;
11337         pr "let parse_%s = %s\n" name parser_name;
11338         parser_name
11339     | Element (name, fields) ->              (* type name = { fields ... } *)
11340         generate_parser_struct name ([], fields)
11341     | rng ->
11342         failwithf "generate_parser failed at: %s" (string_of_rng rng)
11343
11344   and is_attrs_interleave = function
11345     | [Interleave _] -> true
11346     | Attribute _ :: fields -> is_attrs_interleave fields
11347     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11348     | _ -> false
11349
11350   and get_attrs_interleave = function
11351     | [Interleave fields] -> [], fields
11352     | ((Attribute _) as field) :: fields
11353     | ((Optional (Attribute _)) as field) :: fields ->
11354         let attrs, interleaves = get_attrs_interleave fields in
11355         (field :: attrs), interleaves
11356     | _ -> assert false
11357
11358   and generate_parsers xs =
11359     List.iter (fun x -> ignore (generate_parser x)) xs
11360
11361   and generate_parser_struct name (attrs, interleaves) =
11362     (* Generate parsers for the fields first.  We have to do this
11363      * before printing anything so we are still in BOL context.
11364      *)
11365     let fields = attrs @ interleaves in
11366     let pas = List.map generate_parser fields in
11367
11368     (* Generate an intermediate tuple from all the fields first.
11369      * If the type is just a string + another field, then we will
11370      * return this directly, otherwise it is turned into a record.
11371      *
11372      * RELAX NG note: This code treats <interleave> and plain lists of
11373      * fields the same.  In other words, it doesn't bother enforcing
11374      * any ordering of fields in the XML.
11375      *)
11376     pr "let parse_%s x =\n" name;
11377     pr "  let t = (\n    ";
11378     let comma = ref false in
11379     List.iter (
11380       fun x ->
11381         if !comma then pr ",\n    ";
11382         comma := true;
11383         match x with
11384         | Optional (Attribute (fname, [field])), pa ->
11385             pr "%s x" pa
11386         | Optional (Element (fname, [field])), pa ->
11387             pr "%s (optional_child %S x)" pa fname
11388         | Attribute (fname, [Text]), _ ->
11389             pr "attribute %S x" fname
11390         | (ZeroOrMore _ | OneOrMore _), pa ->
11391             pr "%s x" pa
11392         | Text, pa ->
11393             pr "%s x" pa
11394         | (field, pa) ->
11395             let fname = name_of_field field in
11396             pr "%s (child %S x)" pa fname
11397     ) (List.combine fields pas);
11398     pr "\n  ) in\n";
11399
11400     (match fields with
11401      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11402          pr "  t\n"
11403
11404      | _ ->
11405          pr "  (Obj.magic t : %s)\n" name
11406 (*
11407          List.iter (
11408            function
11409            | (Optional (Attribute (fname, [field])), pa) ->
11410                pr "  %s_%s =\n" name fname;
11411                pr "    %s x;\n" pa
11412            | (Optional (Element (fname, [field])), pa) ->
11413                pr "  %s_%s =\n" name fname;
11414                pr "    (let x = optional_child %S x in\n" fname;
11415                pr "     %s x);\n" pa
11416            | (field, pa) ->
11417                let fname = name_of_field field in
11418                pr "  %s_%s =\n" name fname;
11419                pr "    (let x = child %S x in\n" fname;
11420                pr "     %s x);\n" pa
11421          ) (List.combine fields pas);
11422          pr "}\n"
11423 *)
11424     );
11425     sprintf "parse_%s" name
11426   in
11427
11428   generate_parsers xs
11429
11430 (* Generate ocaml/guestfs_inspector.mli. *)
11431 let generate_ocaml_inspector_mli () =
11432   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11433
11434   pr "\
11435 (** This is an OCaml language binding to the external [virt-inspector]
11436     program.
11437
11438     For more information, please read the man page [virt-inspector(1)].
11439 *)
11440
11441 ";
11442
11443   generate_types grammar;
11444   pr "(** The nested information returned from the {!inspect} function. *)\n";
11445   pr "\n";
11446
11447   pr "\
11448 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11449 (** To inspect a libvirt domain called [name], pass a singleton
11450     list: [inspect [name]].  When using libvirt only, you may
11451     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11452
11453     To inspect a disk image or images, pass a list of the filenames
11454     of the disk images: [inspect filenames]
11455
11456     This function inspects the given guest or disk images and
11457     returns a list of operating system(s) found and a large amount
11458     of information about them.  In the vast majority of cases,
11459     a virtual machine only contains a single operating system.
11460
11461     If the optional [~xml] parameter is given, then this function
11462     skips running the external virt-inspector program and just
11463     parses the given XML directly (which is expected to be XML
11464     produced from a previous run of virt-inspector).  The list of
11465     names and connect URI are ignored in this case.
11466
11467     This function can throw a wide variety of exceptions, for example
11468     if the external virt-inspector program cannot be found, or if
11469     it doesn't generate valid XML.
11470 *)
11471 "
11472
11473 (* Generate ocaml/guestfs_inspector.ml. *)
11474 let generate_ocaml_inspector_ml () =
11475   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11476
11477   pr "open Unix\n";
11478   pr "\n";
11479
11480   generate_types grammar;
11481   pr "\n";
11482
11483   pr "\
11484 (* Misc functions which are used by the parser code below. *)
11485 let first_child = function
11486   | Xml.Element (_, _, c::_) -> c
11487   | Xml.Element (name, _, []) ->
11488       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11489   | Xml.PCData str ->
11490       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11491
11492 let string_child_or_empty = function
11493   | Xml.Element (_, _, [Xml.PCData s]) -> s
11494   | Xml.Element (_, _, []) -> \"\"
11495   | Xml.Element (x, _, _) ->
11496       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11497                 x ^ \" instead\")
11498   | Xml.PCData str ->
11499       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11500
11501 let optional_child name xml =
11502   let children = Xml.children xml in
11503   try
11504     Some (List.find (function
11505                      | Xml.Element (n, _, _) when n = name -> true
11506                      | _ -> false) children)
11507   with
11508     Not_found -> None
11509
11510 let child name xml =
11511   match optional_child name xml with
11512   | Some c -> c
11513   | None ->
11514       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11515
11516 let attribute name xml =
11517   try Xml.attrib xml name
11518   with Xml.No_attribute _ ->
11519     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11520
11521 ";
11522
11523   generate_parsers grammar;
11524   pr "\n";
11525
11526   pr "\
11527 (* Run external virt-inspector, then use parser to parse the XML. *)
11528 let inspect ?connect ?xml names =
11529   let xml =
11530     match xml with
11531     | None ->
11532         if names = [] then invalid_arg \"inspect: no names given\";
11533         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11534           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11535           names in
11536         let cmd = List.map Filename.quote cmd in
11537         let cmd = String.concat \" \" cmd in
11538         let chan = open_process_in cmd in
11539         let xml = Xml.parse_in chan in
11540         (match close_process_in chan with
11541          | WEXITED 0 -> ()
11542          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11543          | WSIGNALED i | WSTOPPED i ->
11544              failwith (\"external virt-inspector command died or stopped on sig \" ^
11545                        string_of_int i)
11546         );
11547         xml
11548     | Some doc ->
11549         Xml.parse_string doc in
11550   parse_operatingsystems xml
11551 "
11552
11553 (* This is used to generate the src/MAX_PROC_NR file which
11554  * contains the maximum procedure number, a surrogate for the
11555  * ABI version number.  See src/Makefile.am for the details.
11556  *)
11557 and generate_max_proc_nr () =
11558   let proc_nrs = List.map (
11559     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11560   ) daemon_functions in
11561
11562   let max_proc_nr = List.fold_left max 0 proc_nrs in
11563
11564   pr "%d\n" max_proc_nr
11565
11566 let output_to filename k =
11567   let filename_new = filename ^ ".new" in
11568   chan := open_out filename_new;
11569   k ();
11570   close_out !chan;
11571   chan := Pervasives.stdout;
11572
11573   (* Is the new file different from the current file? *)
11574   if Sys.file_exists filename && files_equal filename filename_new then
11575     unlink filename_new                 (* same, so skip it *)
11576   else (
11577     (* different, overwrite old one *)
11578     (try chmod filename 0o644 with Unix_error _ -> ());
11579     rename filename_new filename;
11580     chmod filename 0o444;
11581     printf "written %s\n%!" filename;
11582   )
11583
11584 let perror msg = function
11585   | Unix_error (err, _, _) ->
11586       eprintf "%s: %s\n" msg (error_message err)
11587   | exn ->
11588       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11589
11590 (* Main program. *)
11591 let () =
11592   let lock_fd =
11593     try openfile "HACKING" [O_RDWR] 0
11594     with
11595     | Unix_error (ENOENT, _, _) ->
11596         eprintf "\
11597 You are probably running this from the wrong directory.
11598 Run it from the top source directory using the command
11599   src/generator.ml
11600 ";
11601         exit 1
11602     | exn ->
11603         perror "open: HACKING" exn;
11604         exit 1 in
11605
11606   (* Acquire a lock so parallel builds won't try to run the generator
11607    * twice at the same time.  Subsequent builds will wait for the first
11608    * one to finish.  Note the lock is released implicitly when the
11609    * program exits.
11610    *)
11611   (try lockf lock_fd F_LOCK 1
11612    with exn ->
11613      perror "lock: HACKING" exn;
11614      exit 1);
11615
11616   check_functions ();
11617
11618   output_to "src/guestfs_protocol.x" generate_xdr;
11619   output_to "src/guestfs-structs.h" generate_structs_h;
11620   output_to "src/guestfs-actions.h" generate_actions_h;
11621   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11622   output_to "src/guestfs-actions.c" generate_client_actions;
11623   output_to "src/guestfs-bindtests.c" generate_bindtests;
11624   output_to "src/guestfs-structs.pod" generate_structs_pod;
11625   output_to "src/guestfs-actions.pod" generate_actions_pod;
11626   output_to "src/guestfs-availability.pod" generate_availability_pod;
11627   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11628   output_to "src/libguestfs.syms" generate_linker_script;
11629   output_to "daemon/actions.h" generate_daemon_actions_h;
11630   output_to "daemon/stubs.c" generate_daemon_actions;
11631   output_to "daemon/names.c" generate_daemon_names;
11632   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11633   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11634   output_to "capitests/tests.c" generate_tests;
11635   output_to "fish/cmds.c" generate_fish_cmds;
11636   output_to "fish/completion.c" generate_fish_completion;
11637   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11638   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11639   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11640   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11641   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11642   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11643   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11644   output_to "perl/Guestfs.xs" generate_perl_xs;
11645   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11646   output_to "perl/bindtests.pl" generate_perl_bindtests;
11647   output_to "python/guestfs-py.c" generate_python_c;
11648   output_to "python/guestfs.py" generate_python_py;
11649   output_to "python/bindtests.py" generate_python_bindtests;
11650   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11651   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11652   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11653
11654   List.iter (
11655     fun (typ, jtyp) ->
11656       let cols = cols_of_struct typ in
11657       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11658       output_to filename (generate_java_struct jtyp cols);
11659   ) java_structs;
11660
11661   output_to "java/Makefile.inc" generate_java_makefile_inc;
11662   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11663   output_to "java/Bindtests.java" generate_java_bindtests;
11664   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11665   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11666   output_to "csharp/Libguestfs.cs" generate_csharp;
11667
11668   (* Always generate this file last, and unconditionally.  It's used
11669    * by the Makefile to know when we must re-run the generator.
11670    *)
11671   let chan = open_out "src/stamp-generator" in
11672   fprintf chan "1\n";
11673   close_out chan;
11674
11675   printf "generated %d lines of code\n" !lines