77fa0530a01a4cc730a7ac9a3422b518a6c90b7f
[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 ]
4524
4525 let all_functions = non_daemon_functions @ daemon_functions
4526
4527 (* In some places we want the functions to be displayed sorted
4528  * alphabetically, so this is useful:
4529  *)
4530 let all_functions_sorted =
4531   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4532                compare n1 n2) all_functions
4533
4534 (* Field types for structures. *)
4535 type field =
4536   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4537   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4538   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4539   | FUInt32
4540   | FInt32
4541   | FUInt64
4542   | FInt64
4543   | FBytes                      (* Any int measure that counts bytes. *)
4544   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4545   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4546
4547 (* Because we generate extra parsing code for LVM command line tools,
4548  * we have to pull out the LVM columns separately here.
4549  *)
4550 let lvm_pv_cols = [
4551   "pv_name", FString;
4552   "pv_uuid", FUUID;
4553   "pv_fmt", FString;
4554   "pv_size", FBytes;
4555   "dev_size", FBytes;
4556   "pv_free", FBytes;
4557   "pv_used", FBytes;
4558   "pv_attr", FString (* XXX *);
4559   "pv_pe_count", FInt64;
4560   "pv_pe_alloc_count", FInt64;
4561   "pv_tags", FString;
4562   "pe_start", FBytes;
4563   "pv_mda_count", FInt64;
4564   "pv_mda_free", FBytes;
4565   (* Not in Fedora 10:
4566      "pv_mda_size", FBytes;
4567   *)
4568 ]
4569 let lvm_vg_cols = [
4570   "vg_name", FString;
4571   "vg_uuid", FUUID;
4572   "vg_fmt", FString;
4573   "vg_attr", FString (* XXX *);
4574   "vg_size", FBytes;
4575   "vg_free", FBytes;
4576   "vg_sysid", FString;
4577   "vg_extent_size", FBytes;
4578   "vg_extent_count", FInt64;
4579   "vg_free_count", FInt64;
4580   "max_lv", FInt64;
4581   "max_pv", FInt64;
4582   "pv_count", FInt64;
4583   "lv_count", FInt64;
4584   "snap_count", FInt64;
4585   "vg_seqno", FInt64;
4586   "vg_tags", FString;
4587   "vg_mda_count", FInt64;
4588   "vg_mda_free", FBytes;
4589   (* Not in Fedora 10:
4590      "vg_mda_size", FBytes;
4591   *)
4592 ]
4593 let lvm_lv_cols = [
4594   "lv_name", FString;
4595   "lv_uuid", FUUID;
4596   "lv_attr", FString (* XXX *);
4597   "lv_major", FInt64;
4598   "lv_minor", FInt64;
4599   "lv_kernel_major", FInt64;
4600   "lv_kernel_minor", FInt64;
4601   "lv_size", FBytes;
4602   "seg_count", FInt64;
4603   "origin", FString;
4604   "snap_percent", FOptPercent;
4605   "copy_percent", FOptPercent;
4606   "move_pv", FString;
4607   "lv_tags", FString;
4608   "mirror_log", FString;
4609   "modules", FString;
4610 ]
4611
4612 (* Names and fields in all structures (in RStruct and RStructList)
4613  * that we support.
4614  *)
4615 let structs = [
4616   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4617    * not use this struct in any new code.
4618    *)
4619   "int_bool", [
4620     "i", FInt32;                (* for historical compatibility *)
4621     "b", FInt32;                (* for historical compatibility *)
4622   ];
4623
4624   (* LVM PVs, VGs, LVs. *)
4625   "lvm_pv", lvm_pv_cols;
4626   "lvm_vg", lvm_vg_cols;
4627   "lvm_lv", lvm_lv_cols;
4628
4629   (* Column names and types from stat structures.
4630    * NB. Can't use things like 'st_atime' because glibc header files
4631    * define some of these as macros.  Ugh.
4632    *)
4633   "stat", [
4634     "dev", FInt64;
4635     "ino", FInt64;
4636     "mode", FInt64;
4637     "nlink", FInt64;
4638     "uid", FInt64;
4639     "gid", FInt64;
4640     "rdev", FInt64;
4641     "size", FInt64;
4642     "blksize", FInt64;
4643     "blocks", FInt64;
4644     "atime", FInt64;
4645     "mtime", FInt64;
4646     "ctime", FInt64;
4647   ];
4648   "statvfs", [
4649     "bsize", FInt64;
4650     "frsize", FInt64;
4651     "blocks", FInt64;
4652     "bfree", FInt64;
4653     "bavail", FInt64;
4654     "files", FInt64;
4655     "ffree", FInt64;
4656     "favail", FInt64;
4657     "fsid", FInt64;
4658     "flag", FInt64;
4659     "namemax", FInt64;
4660   ];
4661
4662   (* Column names in dirent structure. *)
4663   "dirent", [
4664     "ino", FInt64;
4665     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4666     "ftyp", FChar;
4667     "name", FString;
4668   ];
4669
4670   (* Version numbers. *)
4671   "version", [
4672     "major", FInt64;
4673     "minor", FInt64;
4674     "release", FInt64;
4675     "extra", FString;
4676   ];
4677
4678   (* Extended attribute. *)
4679   "xattr", [
4680     "attrname", FString;
4681     "attrval", FBuffer;
4682   ];
4683
4684   (* Inotify events. *)
4685   "inotify_event", [
4686     "in_wd", FInt64;
4687     "in_mask", FUInt32;
4688     "in_cookie", FUInt32;
4689     "in_name", FString;
4690   ];
4691
4692   (* Partition table entry. *)
4693   "partition", [
4694     "part_num", FInt32;
4695     "part_start", FBytes;
4696     "part_end", FBytes;
4697     "part_size", FBytes;
4698   ];
4699 ] (* end of structs *)
4700
4701 (* Ugh, Java has to be different ..
4702  * These names are also used by the Haskell bindings.
4703  *)
4704 let java_structs = [
4705   "int_bool", "IntBool";
4706   "lvm_pv", "PV";
4707   "lvm_vg", "VG";
4708   "lvm_lv", "LV";
4709   "stat", "Stat";
4710   "statvfs", "StatVFS";
4711   "dirent", "Dirent";
4712   "version", "Version";
4713   "xattr", "XAttr";
4714   "inotify_event", "INotifyEvent";
4715   "partition", "Partition";
4716 ]
4717
4718 (* What structs are actually returned. *)
4719 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
4720
4721 (* Returns a list of RStruct/RStructList structs that are returned
4722  * by any function.  Each element of returned list is a pair:
4723  *
4724  * (structname, RStructOnly)
4725  *    == there exists function which returns RStruct (_, structname)
4726  * (structname, RStructListOnly)
4727  *    == there exists function which returns RStructList (_, structname)
4728  * (structname, RStructAndList)
4729  *    == there are functions returning both RStruct (_, structname)
4730  *                                      and RStructList (_, structname)
4731  *)
4732 let rstructs_used_by functions =
4733   (* ||| is a "logical OR" for rstructs_used_t *)
4734   let (|||) a b =
4735     match a, b with
4736     | RStructAndList, _
4737     | _, RStructAndList -> RStructAndList
4738     | RStructOnly, RStructListOnly
4739     | RStructListOnly, RStructOnly -> RStructAndList
4740     | RStructOnly, RStructOnly -> RStructOnly
4741     | RStructListOnly, RStructListOnly -> RStructListOnly
4742   in
4743
4744   let h = Hashtbl.create 13 in
4745
4746   (* if elem->oldv exists, update entry using ||| operator,
4747    * else just add elem->newv to the hash
4748    *)
4749   let update elem newv =
4750     try  let oldv = Hashtbl.find h elem in
4751          Hashtbl.replace h elem (newv ||| oldv)
4752     with Not_found -> Hashtbl.add h elem newv
4753   in
4754
4755   List.iter (
4756     fun (_, style, _, _, _, _, _) ->
4757       match fst style with
4758       | RStruct (_, structname) -> update structname RStructOnly
4759       | RStructList (_, structname) -> update structname RStructListOnly
4760       | _ -> ()
4761   ) functions;
4762
4763   (* return key->values as a list of (key,value) *)
4764   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
4765
4766 (* Used for testing language bindings. *)
4767 type callt =
4768   | CallString of string
4769   | CallOptString of string option
4770   | CallStringList of string list
4771   | CallInt of int
4772   | CallInt64 of int64
4773   | CallBool of bool
4774
4775 (* Used to memoize the result of pod2text. *)
4776 let pod2text_memo_filename = "src/.pod2text.data"
4777 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
4778   try
4779     let chan = open_in pod2text_memo_filename in
4780     let v = input_value chan in
4781     close_in chan;
4782     v
4783   with
4784     _ -> Hashtbl.create 13
4785 let pod2text_memo_updated () =
4786   let chan = open_out pod2text_memo_filename in
4787   output_value chan pod2text_memo;
4788   close_out chan
4789
4790 (* Useful functions.
4791  * Note we don't want to use any external OCaml libraries which
4792  * makes this a bit harder than it should be.
4793  *)
4794 module StringMap = Map.Make (String)
4795
4796 let failwithf fs = ksprintf failwith fs
4797
4798 let unique = let i = ref 0 in fun () -> incr i; !i
4799
4800 let replace_char s c1 c2 =
4801   let s2 = String.copy s in
4802   let r = ref false in
4803   for i = 0 to String.length s2 - 1 do
4804     if String.unsafe_get s2 i = c1 then (
4805       String.unsafe_set s2 i c2;
4806       r := true
4807     )
4808   done;
4809   if not !r then s else s2
4810
4811 let isspace c =
4812   c = ' '
4813   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
4814
4815 let triml ?(test = isspace) str =
4816   let i = ref 0 in
4817   let n = ref (String.length str) in
4818   while !n > 0 && test str.[!i]; do
4819     decr n;
4820     incr i
4821   done;
4822   if !i = 0 then str
4823   else String.sub str !i !n
4824
4825 let trimr ?(test = isspace) str =
4826   let n = ref (String.length str) in
4827   while !n > 0 && test str.[!n-1]; do
4828     decr n
4829   done;
4830   if !n = String.length str then str
4831   else String.sub str 0 !n
4832
4833 let trim ?(test = isspace) str =
4834   trimr ~test (triml ~test str)
4835
4836 let rec find s sub =
4837   let len = String.length s in
4838   let sublen = String.length sub in
4839   let rec loop i =
4840     if i <= len-sublen then (
4841       let rec loop2 j =
4842         if j < sublen then (
4843           if s.[i+j] = sub.[j] then loop2 (j+1)
4844           else -1
4845         ) else
4846           i (* found *)
4847       in
4848       let r = loop2 0 in
4849       if r = -1 then loop (i+1) else r
4850     ) else
4851       -1 (* not found *)
4852   in
4853   loop 0
4854
4855 let rec replace_str s s1 s2 =
4856   let len = String.length s in
4857   let sublen = String.length s1 in
4858   let i = find s s1 in
4859   if i = -1 then s
4860   else (
4861     let s' = String.sub s 0 i in
4862     let s'' = String.sub s (i+sublen) (len-i-sublen) in
4863     s' ^ s2 ^ replace_str s'' s1 s2
4864   )
4865
4866 let rec string_split sep str =
4867   let len = String.length str in
4868   let seplen = String.length sep in
4869   let i = find str sep in
4870   if i = -1 then [str]
4871   else (
4872     let s' = String.sub str 0 i in
4873     let s'' = String.sub str (i+seplen) (len-i-seplen) in
4874     s' :: string_split sep s''
4875   )
4876
4877 let files_equal n1 n2 =
4878   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
4879   match Sys.command cmd with
4880   | 0 -> true
4881   | 1 -> false
4882   | i -> failwithf "%s: failed with error code %d" cmd i
4883
4884 let rec filter_map f = function
4885   | [] -> []
4886   | x :: xs ->
4887       match f x with
4888       | Some y -> y :: filter_map f xs
4889       | None -> filter_map f xs
4890
4891 let rec find_map f = function
4892   | [] -> raise Not_found
4893   | x :: xs ->
4894       match f x with
4895       | Some y -> y
4896       | None -> find_map f xs
4897
4898 let iteri f xs =
4899   let rec loop i = function
4900     | [] -> ()
4901     | x :: xs -> f i x; loop (i+1) xs
4902   in
4903   loop 0 xs
4904
4905 let mapi f xs =
4906   let rec loop i = function
4907     | [] -> []
4908     | x :: xs -> let r = f i x in r :: loop (i+1) xs
4909   in
4910   loop 0 xs
4911
4912 let count_chars c str =
4913   let count = ref 0 in
4914   for i = 0 to String.length str - 1 do
4915     if c = String.unsafe_get str i then incr count
4916   done;
4917   !count
4918
4919 let name_of_argt = function
4920   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
4921   | StringList n | DeviceList n | Bool n | Int n | Int64 n
4922   | FileIn n | FileOut n -> n
4923
4924 let java_name_of_struct typ =
4925   try List.assoc typ java_structs
4926   with Not_found ->
4927     failwithf
4928       "java_name_of_struct: no java_structs entry corresponding to %s" typ
4929
4930 let cols_of_struct typ =
4931   try List.assoc typ structs
4932   with Not_found ->
4933     failwithf "cols_of_struct: unknown struct %s" typ
4934
4935 let seq_of_test = function
4936   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
4937   | TestOutputListOfDevices (s, _)
4938   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
4939   | TestOutputTrue s | TestOutputFalse s
4940   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
4941   | TestOutputStruct (s, _)
4942   | TestLastFail s -> s
4943
4944 (* Handling for function flags. *)
4945 let protocol_limit_warning =
4946   "Because of the message protocol, there is a transfer limit
4947 of somewhere between 2MB and 4MB.  See L<guestfs(3)/PROTOCOL LIMITS>."
4948
4949 let danger_will_robinson =
4950   "B<This command is dangerous.  Without careful use you
4951 can easily destroy all your data>."
4952
4953 let deprecation_notice flags =
4954   try
4955     let alt =
4956       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
4957     let txt =
4958       sprintf "This function is deprecated.
4959 In new code, use the C<%s> call instead.
4960
4961 Deprecated functions will not be removed from the API, but the
4962 fact that they are deprecated indicates that there are problems
4963 with correct use of these functions." alt in
4964     Some txt
4965   with
4966     Not_found -> None
4967
4968 (* Create list of optional groups. *)
4969 let optgroups =
4970   let h = Hashtbl.create 13 in
4971   List.iter (
4972     fun (name, _, _, flags, _, _, _) ->
4973       List.iter (
4974         function
4975         | Optional group ->
4976             let names = try Hashtbl.find h group with Not_found -> [] in
4977             Hashtbl.replace h group (name :: names)
4978         | _ -> ()
4979       ) flags
4980   ) daemon_functions;
4981   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
4982   let groups =
4983     List.map (
4984       fun group -> group, List.sort compare (Hashtbl.find h group)
4985     ) groups in
4986   List.sort (fun x y -> compare (fst x) (fst y)) groups
4987
4988 (* Check function names etc. for consistency. *)
4989 let check_functions () =
4990   let contains_uppercase str =
4991     let len = String.length str in
4992     let rec loop i =
4993       if i >= len then false
4994       else (
4995         let c = str.[i] in
4996         if c >= 'A' && c <= 'Z' then true
4997         else loop (i+1)
4998       )
4999     in
5000     loop 0
5001   in
5002
5003   (* Check function names. *)
5004   List.iter (
5005     fun (name, _, _, _, _, _, _) ->
5006       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
5007         failwithf "function name %s does not need 'guestfs' prefix" name;
5008       if name = "" then
5009         failwithf "function name is empty";
5010       if name.[0] < 'a' || name.[0] > 'z' then
5011         failwithf "function name %s must start with lowercase a-z" name;
5012       if String.contains name '-' then
5013         failwithf "function name %s should not contain '-', use '_' instead."
5014           name
5015   ) all_functions;
5016
5017   (* Check function parameter/return names. *)
5018   List.iter (
5019     fun (name, style, _, _, _, _, _) ->
5020       let check_arg_ret_name n =
5021         if contains_uppercase n then
5022           failwithf "%s param/ret %s should not contain uppercase chars"
5023             name n;
5024         if String.contains n '-' || String.contains n '_' then
5025           failwithf "%s param/ret %s should not contain '-' or '_'"
5026             name n;
5027         if n = "value" then
5028           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;
5029         if n = "int" || n = "char" || n = "short" || n = "long" then
5030           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
5031         if n = "i" || n = "n" then
5032           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
5033         if n = "argv" || n = "args" then
5034           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
5035
5036         (* List Haskell, OCaml and C keywords here.
5037          * http://www.haskell.org/haskellwiki/Keywords
5038          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
5039          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
5040          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
5041          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
5042          * Omitting _-containing words, since they're handled above.
5043          * Omitting the OCaml reserved word, "val", is ok,
5044          * and saves us from renaming several parameters.
5045          *)
5046         let reserved = [
5047           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
5048           "char"; "class"; "const"; "constraint"; "continue"; "data";
5049           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
5050           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
5051           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
5052           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
5053           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
5054           "interface";
5055           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
5056           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
5057           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
5058           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
5059           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
5060           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
5061           "volatile"; "when"; "where"; "while";
5062           ] in
5063         if List.mem n reserved then
5064           failwithf "%s has param/ret using reserved word %s" name n;
5065       in
5066
5067       (match fst style with
5068        | RErr -> ()
5069        | RInt n | RInt64 n | RBool n
5070        | RConstString n | RConstOptString n | RString n
5071        | RStringList n | RStruct (n, _) | RStructList (n, _)
5072        | RHashtable n | RBufferOut n ->
5073            check_arg_ret_name n
5074       );
5075       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
5076   ) all_functions;
5077
5078   (* Check short descriptions. *)
5079   List.iter (
5080     fun (name, _, _, _, _, shortdesc, _) ->
5081       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
5082         failwithf "short description of %s should begin with lowercase." name;
5083       let c = shortdesc.[String.length shortdesc-1] in
5084       if c = '\n' || c = '.' then
5085         failwithf "short description of %s should not end with . or \\n." name
5086   ) all_functions;
5087
5088   (* Check long descriptions. *)
5089   List.iter (
5090     fun (name, _, _, _, _, _, longdesc) ->
5091       if longdesc.[String.length longdesc-1] = '\n' then
5092         failwithf "long description of %s should not end with \\n." name
5093   ) all_functions;
5094
5095   (* Check proc_nrs. *)
5096   List.iter (
5097     fun (name, _, proc_nr, _, _, _, _) ->
5098       if proc_nr <= 0 then
5099         failwithf "daemon function %s should have proc_nr > 0" name
5100   ) daemon_functions;
5101
5102   List.iter (
5103     fun (name, _, proc_nr, _, _, _, _) ->
5104       if proc_nr <> -1 then
5105         failwithf "non-daemon function %s should have proc_nr -1" name
5106   ) non_daemon_functions;
5107
5108   let proc_nrs =
5109     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
5110       daemon_functions in
5111   let proc_nrs =
5112     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
5113   let rec loop = function
5114     | [] -> ()
5115     | [_] -> ()
5116     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
5117         loop rest
5118     | (name1,nr1) :: (name2,nr2) :: _ ->
5119         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
5120           name1 name2 nr1 nr2
5121   in
5122   loop proc_nrs;
5123
5124   (* Check tests. *)
5125   List.iter (
5126     function
5127       (* Ignore functions that have no tests.  We generate a
5128        * warning when the user does 'make check' instead.
5129        *)
5130     | name, _, _, _, [], _, _ -> ()
5131     | name, _, _, _, tests, _, _ ->
5132         let funcs =
5133           List.map (
5134             fun (_, _, test) ->
5135               match seq_of_test test with
5136               | [] ->
5137                   failwithf "%s has a test containing an empty sequence" name
5138               | cmds -> List.map List.hd cmds
5139           ) tests in
5140         let funcs = List.flatten funcs in
5141
5142         let tested = List.mem name funcs in
5143
5144         if not tested then
5145           failwithf "function %s has tests but does not test itself" name
5146   ) all_functions
5147
5148 (* 'pr' prints to the current output file. *)
5149 let chan = ref Pervasives.stdout
5150 let lines = ref 0
5151 let pr fs =
5152   ksprintf
5153     (fun str ->
5154        let i = count_chars '\n' str in
5155        lines := !lines + i;
5156        output_string !chan str
5157     ) fs
5158
5159 let copyright_years =
5160   let this_year = 1900 + (localtime (time ())).tm_year in
5161   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
5162
5163 (* Generate a header block in a number of standard styles. *)
5164 type comment_style =
5165     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
5166 type license = GPLv2plus | LGPLv2plus
5167
5168 let generate_header ?(extra_inputs = []) comment license =
5169   let inputs = "src/generator.ml" :: extra_inputs in
5170   let c = match comment with
5171     | CStyle ->         pr "/* "; " *"
5172     | CPlusPlusStyle -> pr "// "; "//"
5173     | HashStyle ->      pr "# ";  "#"
5174     | OCamlStyle ->     pr "(* "; " *"
5175     | HaskellStyle ->   pr "{- "; "  " in
5176   pr "libguestfs generated file\n";
5177   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
5178   List.iter (pr "%s   %s\n" c) inputs;
5179   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
5180   pr "%s\n" c;
5181   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
5182   pr "%s\n" c;
5183   (match license with
5184    | GPLv2plus ->
5185        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
5186        pr "%s it under the terms of the GNU General Public License as published by\n" c;
5187        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
5188        pr "%s (at your option) any later version.\n" c;
5189        pr "%s\n" c;
5190        pr "%s This program is distributed in the hope that it will be useful,\n" c;
5191        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5192        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
5193        pr "%s GNU General Public License for more details.\n" c;
5194        pr "%s\n" c;
5195        pr "%s You should have received a copy of the GNU General Public License along\n" c;
5196        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
5197        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
5198
5199    | LGPLv2plus ->
5200        pr "%s This library is free software; you can redistribute it and/or\n" c;
5201        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
5202        pr "%s License as published by the Free Software Foundation; either\n" c;
5203        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
5204        pr "%s\n" c;
5205        pr "%s This library is distributed in the hope that it will be useful,\n" c;
5206        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5207        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
5208        pr "%s Lesser General Public License for more details.\n" c;
5209        pr "%s\n" c;
5210        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
5211        pr "%s License along with this library; if not, write to the Free Software\n" c;
5212        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
5213   );
5214   (match comment with
5215    | CStyle -> pr " */\n"
5216    | CPlusPlusStyle
5217    | HashStyle -> ()
5218    | OCamlStyle -> pr " *)\n"
5219    | HaskellStyle -> pr "-}\n"
5220   );
5221   pr "\n"
5222
5223 (* Start of main code generation functions below this line. *)
5224
5225 (* Generate the pod documentation for the C API. *)
5226 let rec generate_actions_pod () =
5227   List.iter (
5228     fun (shortname, style, _, flags, _, _, longdesc) ->
5229       if not (List.mem NotInDocs flags) then (
5230         let name = "guestfs_" ^ shortname in
5231         pr "=head2 %s\n\n" name;
5232         pr " ";
5233         generate_prototype ~extern:false ~handle:"g" name style;
5234         pr "\n\n";
5235         pr "%s\n\n" longdesc;
5236         (match fst style with
5237          | RErr ->
5238              pr "This function returns 0 on success or -1 on error.\n\n"
5239          | RInt _ ->
5240              pr "On error this function returns -1.\n\n"
5241          | RInt64 _ ->
5242              pr "On error this function returns -1.\n\n"
5243          | RBool _ ->
5244              pr "This function returns a C truth value on success or -1 on error.\n\n"
5245          | RConstString _ ->
5246              pr "This function returns a string, or NULL on error.
5247 The string is owned by the guest handle and must I<not> be freed.\n\n"
5248          | RConstOptString _ ->
5249              pr "This function returns a string which may be NULL.
5250 There is way to return an error from this function.
5251 The string is owned by the guest handle and must I<not> be freed.\n\n"
5252          | RString _ ->
5253              pr "This function returns a string, or NULL on error.
5254 I<The caller must free the returned string after use>.\n\n"
5255          | RStringList _ ->
5256              pr "This function returns a NULL-terminated array of strings
5257 (like L<environ(3)>), or NULL if there was an error.
5258 I<The caller must free the strings and the array after use>.\n\n"
5259          | RStruct (_, typ) ->
5260              pr "This function returns a C<struct guestfs_%s *>,
5261 or NULL if there was an error.
5262 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
5263          | RStructList (_, typ) ->
5264              pr "This function returns a C<struct guestfs_%s_list *>
5265 (see E<lt>guestfs-structs.hE<gt>),
5266 or NULL if there was an error.
5267 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
5268          | RHashtable _ ->
5269              pr "This function returns a NULL-terminated array of
5270 strings, or NULL if there was an error.
5271 The array of strings will always have length C<2n+1>, where
5272 C<n> keys and values alternate, followed by the trailing NULL entry.
5273 I<The caller must free the strings and the array after use>.\n\n"
5274          | RBufferOut _ ->
5275              pr "This function returns a buffer, or NULL on error.
5276 The size of the returned buffer is written to C<*size_r>.
5277 I<The caller must free the returned buffer after use>.\n\n"
5278         );
5279         if List.mem ProtocolLimitWarning flags then
5280           pr "%s\n\n" protocol_limit_warning;
5281         if List.mem DangerWillRobinson flags then
5282           pr "%s\n\n" danger_will_robinson;
5283         match deprecation_notice flags with
5284         | None -> ()
5285         | Some txt -> pr "%s\n\n" txt
5286       )
5287   ) all_functions_sorted
5288
5289 and generate_structs_pod () =
5290   (* Structs documentation. *)
5291   List.iter (
5292     fun (typ, cols) ->
5293       pr "=head2 guestfs_%s\n" typ;
5294       pr "\n";
5295       pr " struct guestfs_%s {\n" typ;
5296       List.iter (
5297         function
5298         | name, FChar -> pr "   char %s;\n" name
5299         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5300         | name, FInt32 -> pr "   int32_t %s;\n" name
5301         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5302         | name, FInt64 -> pr "   int64_t %s;\n" name
5303         | name, FString -> pr "   char *%s;\n" name
5304         | name, FBuffer ->
5305             pr "   /* The next two fields describe a byte array. */\n";
5306             pr "   uint32_t %s_len;\n" name;
5307             pr "   char *%s;\n" name
5308         | name, FUUID ->
5309             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5310             pr "   char %s[32];\n" name
5311         | name, FOptPercent ->
5312             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5313             pr "   float %s;\n" name
5314       ) cols;
5315       pr " };\n";
5316       pr " \n";
5317       pr " struct guestfs_%s_list {\n" typ;
5318       pr "   uint32_t len; /* Number of elements in list. */\n";
5319       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5320       pr " };\n";
5321       pr " \n";
5322       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5323       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5324         typ typ;
5325       pr "\n"
5326   ) structs
5327
5328 and generate_availability_pod () =
5329   (* Availability documentation. *)
5330   pr "=over 4\n";
5331   pr "\n";
5332   List.iter (
5333     fun (group, functions) ->
5334       pr "=item B<%s>\n" group;
5335       pr "\n";
5336       pr "The following functions:\n";
5337       List.iter (pr "L</guestfs_%s>\n") functions;
5338       pr "\n"
5339   ) optgroups;
5340   pr "=back\n";
5341   pr "\n"
5342
5343 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5344  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5345  *
5346  * We have to use an underscore instead of a dash because otherwise
5347  * rpcgen generates incorrect code.
5348  *
5349  * This header is NOT exported to clients, but see also generate_structs_h.
5350  *)
5351 and generate_xdr () =
5352   generate_header CStyle LGPLv2plus;
5353
5354   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5355   pr "typedef string str<>;\n";
5356   pr "\n";
5357
5358   (* Internal structures. *)
5359   List.iter (
5360     function
5361     | typ, cols ->
5362         pr "struct guestfs_int_%s {\n" typ;
5363         List.iter (function
5364                    | name, FChar -> pr "  char %s;\n" name
5365                    | name, FString -> pr "  string %s<>;\n" name
5366                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5367                    | name, FUUID -> pr "  opaque %s[32];\n" name
5368                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5369                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5370                    | name, FOptPercent -> pr "  float %s;\n" name
5371                   ) cols;
5372         pr "};\n";
5373         pr "\n";
5374         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5375         pr "\n";
5376   ) structs;
5377
5378   List.iter (
5379     fun (shortname, style, _, _, _, _, _) ->
5380       let name = "guestfs_" ^ shortname in
5381
5382       (match snd style with
5383        | [] -> ()
5384        | args ->
5385            pr "struct %s_args {\n" name;
5386            List.iter (
5387              function
5388              | Pathname n | Device n | Dev_or_Path n | String n ->
5389                  pr "  string %s<>;\n" n
5390              | OptString n -> pr "  str *%s;\n" n
5391              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5392              | Bool n -> pr "  bool %s;\n" n
5393              | Int n -> pr "  int %s;\n" n
5394              | Int64 n -> pr "  hyper %s;\n" n
5395              | FileIn _ | FileOut _ -> ()
5396            ) args;
5397            pr "};\n\n"
5398       );
5399       (match fst style with
5400        | RErr -> ()
5401        | RInt n ->
5402            pr "struct %s_ret {\n" name;
5403            pr "  int %s;\n" n;
5404            pr "};\n\n"
5405        | RInt64 n ->
5406            pr "struct %s_ret {\n" name;
5407            pr "  hyper %s;\n" n;
5408            pr "};\n\n"
5409        | RBool n ->
5410            pr "struct %s_ret {\n" name;
5411            pr "  bool %s;\n" n;
5412            pr "};\n\n"
5413        | RConstString _ | RConstOptString _ ->
5414            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5415        | RString n ->
5416            pr "struct %s_ret {\n" name;
5417            pr "  string %s<>;\n" n;
5418            pr "};\n\n"
5419        | RStringList n ->
5420            pr "struct %s_ret {\n" name;
5421            pr "  str %s<>;\n" n;
5422            pr "};\n\n"
5423        | RStruct (n, typ) ->
5424            pr "struct %s_ret {\n" name;
5425            pr "  guestfs_int_%s %s;\n" typ n;
5426            pr "};\n\n"
5427        | RStructList (n, typ) ->
5428            pr "struct %s_ret {\n" name;
5429            pr "  guestfs_int_%s_list %s;\n" typ n;
5430            pr "};\n\n"
5431        | RHashtable n ->
5432            pr "struct %s_ret {\n" name;
5433            pr "  str %s<>;\n" n;
5434            pr "};\n\n"
5435        | RBufferOut n ->
5436            pr "struct %s_ret {\n" name;
5437            pr "  opaque %s<>;\n" n;
5438            pr "};\n\n"
5439       );
5440   ) daemon_functions;
5441
5442   (* Table of procedure numbers. *)
5443   pr "enum guestfs_procedure {\n";
5444   List.iter (
5445     fun (shortname, _, proc_nr, _, _, _, _) ->
5446       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5447   ) daemon_functions;
5448   pr "  GUESTFS_PROC_NR_PROCS\n";
5449   pr "};\n";
5450   pr "\n";
5451
5452   (* Having to choose a maximum message size is annoying for several
5453    * reasons (it limits what we can do in the API), but it (a) makes
5454    * the protocol a lot simpler, and (b) provides a bound on the size
5455    * of the daemon which operates in limited memory space.
5456    *)
5457   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5458   pr "\n";
5459
5460   (* Message header, etc. *)
5461   pr "\
5462 /* The communication protocol is now documented in the guestfs(3)
5463  * manpage.
5464  */
5465
5466 const GUESTFS_PROGRAM = 0x2000F5F5;
5467 const GUESTFS_PROTOCOL_VERSION = 1;
5468
5469 /* These constants must be larger than any possible message length. */
5470 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5471 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5472
5473 enum guestfs_message_direction {
5474   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5475   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5476 };
5477
5478 enum guestfs_message_status {
5479   GUESTFS_STATUS_OK = 0,
5480   GUESTFS_STATUS_ERROR = 1
5481 };
5482
5483 const GUESTFS_ERROR_LEN = 256;
5484
5485 struct guestfs_message_error {
5486   string error_message<GUESTFS_ERROR_LEN>;
5487 };
5488
5489 struct guestfs_message_header {
5490   unsigned prog;                     /* GUESTFS_PROGRAM */
5491   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5492   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5493   guestfs_message_direction direction;
5494   unsigned serial;                   /* message serial number */
5495   guestfs_message_status status;
5496 };
5497
5498 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5499
5500 struct guestfs_chunk {
5501   int cancel;                        /* if non-zero, transfer is cancelled */
5502   /* data size is 0 bytes if the transfer has finished successfully */
5503   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5504 };
5505 "
5506
5507 (* Generate the guestfs-structs.h file. *)
5508 and generate_structs_h () =
5509   generate_header CStyle LGPLv2plus;
5510
5511   (* This is a public exported header file containing various
5512    * structures.  The structures are carefully written to have
5513    * exactly the same in-memory format as the XDR structures that
5514    * we use on the wire to the daemon.  The reason for creating
5515    * copies of these structures here is just so we don't have to
5516    * export the whole of guestfs_protocol.h (which includes much
5517    * unrelated and XDR-dependent stuff that we don't want to be
5518    * public, or required by clients).
5519    *
5520    * To reiterate, we will pass these structures to and from the
5521    * client with a simple assignment or memcpy, so the format
5522    * must be identical to what rpcgen / the RFC defines.
5523    *)
5524
5525   (* Public structures. *)
5526   List.iter (
5527     fun (typ, cols) ->
5528       pr "struct guestfs_%s {\n" typ;
5529       List.iter (
5530         function
5531         | name, FChar -> pr "  char %s;\n" name
5532         | name, FString -> pr "  char *%s;\n" name
5533         | name, FBuffer ->
5534             pr "  uint32_t %s_len;\n" name;
5535             pr "  char *%s;\n" name
5536         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5537         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5538         | name, FInt32 -> pr "  int32_t %s;\n" name
5539         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5540         | name, FInt64 -> pr "  int64_t %s;\n" name
5541         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5542       ) cols;
5543       pr "};\n";
5544       pr "\n";
5545       pr "struct guestfs_%s_list {\n" typ;
5546       pr "  uint32_t len;\n";
5547       pr "  struct guestfs_%s *val;\n" typ;
5548       pr "};\n";
5549       pr "\n";
5550       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5551       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5552       pr "\n"
5553   ) structs
5554
5555 (* Generate the guestfs-actions.h file. *)
5556 and generate_actions_h () =
5557   generate_header CStyle LGPLv2plus;
5558   List.iter (
5559     fun (shortname, style, _, _, _, _, _) ->
5560       let name = "guestfs_" ^ shortname in
5561       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5562         name style
5563   ) all_functions
5564
5565 (* Generate the guestfs-internal-actions.h file. *)
5566 and generate_internal_actions_h () =
5567   generate_header CStyle LGPLv2plus;
5568   List.iter (
5569     fun (shortname, style, _, _, _, _, _) ->
5570       let name = "guestfs__" ^ shortname in
5571       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5572         name style
5573   ) non_daemon_functions
5574
5575 (* Generate the client-side dispatch stubs. *)
5576 and generate_client_actions () =
5577   generate_header CStyle LGPLv2plus;
5578
5579   pr "\
5580 #include <stdio.h>
5581 #include <stdlib.h>
5582 #include <stdint.h>
5583 #include <string.h>
5584 #include <inttypes.h>
5585
5586 #include \"guestfs.h\"
5587 #include \"guestfs-internal.h\"
5588 #include \"guestfs-internal-actions.h\"
5589 #include \"guestfs_protocol.h\"
5590
5591 #define error guestfs_error
5592 //#define perrorf guestfs_perrorf
5593 #define safe_malloc guestfs_safe_malloc
5594 #define safe_realloc guestfs_safe_realloc
5595 //#define safe_strdup guestfs_safe_strdup
5596 #define safe_memdup guestfs_safe_memdup
5597
5598 /* Check the return message from a call for validity. */
5599 static int
5600 check_reply_header (guestfs_h *g,
5601                     const struct guestfs_message_header *hdr,
5602                     unsigned int proc_nr, unsigned int serial)
5603 {
5604   if (hdr->prog != GUESTFS_PROGRAM) {
5605     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5606     return -1;
5607   }
5608   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5609     error (g, \"wrong protocol version (%%d/%%d)\",
5610            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5611     return -1;
5612   }
5613   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5614     error (g, \"unexpected message direction (%%d/%%d)\",
5615            hdr->direction, GUESTFS_DIRECTION_REPLY);
5616     return -1;
5617   }
5618   if (hdr->proc != proc_nr) {
5619     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5620     return -1;
5621   }
5622   if (hdr->serial != serial) {
5623     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5624     return -1;
5625   }
5626
5627   return 0;
5628 }
5629
5630 /* Check we are in the right state to run a high-level action. */
5631 static int
5632 check_state (guestfs_h *g, const char *caller)
5633 {
5634   if (!guestfs__is_ready (g)) {
5635     if (guestfs__is_config (g) || guestfs__is_launching (g))
5636       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5637         caller);
5638     else
5639       error (g, \"%%s called from the wrong state, %%d != READY\",
5640         caller, guestfs__get_state (g));
5641     return -1;
5642   }
5643   return 0;
5644 }
5645
5646 ";
5647
5648   (* Generate code to generate guestfish call traces. *)
5649   let trace_call shortname style =
5650     pr "  if (guestfs__get_trace (g)) {\n";
5651
5652     let needs_i =
5653       List.exists (function
5654                    | StringList _ | DeviceList _ -> true
5655                    | _ -> false) (snd style) in
5656     if needs_i then (
5657       pr "    int i;\n";
5658       pr "\n"
5659     );
5660
5661     pr "    printf (\"%s\");\n" shortname;
5662     List.iter (
5663       function
5664       | String n                        (* strings *)
5665       | Device n
5666       | Pathname n
5667       | Dev_or_Path n
5668       | FileIn n
5669       | FileOut n ->
5670           (* guestfish doesn't support string escaping, so neither do we *)
5671           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
5672       | OptString n ->                  (* string option *)
5673           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
5674           pr "    else printf (\" null\");\n"
5675       | StringList n
5676       | DeviceList n ->                 (* string list *)
5677           pr "    putchar (' ');\n";
5678           pr "    putchar ('\"');\n";
5679           pr "    for (i = 0; %s[i]; ++i) {\n" n;
5680           pr "      if (i > 0) putchar (' ');\n";
5681           pr "      fputs (%s[i], stdout);\n" n;
5682           pr "    }\n";
5683           pr "    putchar ('\"');\n";
5684       | Bool n ->                       (* boolean *)
5685           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
5686       | Int n ->                        (* int *)
5687           pr "    printf (\" %%d\", %s);\n" n
5688       | Int64 n ->
5689           pr "    printf (\" %%\" PRIi64, %s);\n" n
5690     ) (snd style);
5691     pr "    putchar ('\\n');\n";
5692     pr "  }\n";
5693     pr "\n";
5694   in
5695
5696   (* For non-daemon functions, generate a wrapper around each function. *)
5697   List.iter (
5698     fun (shortname, style, _, _, _, _, _) ->
5699       let name = "guestfs_" ^ shortname in
5700
5701       generate_prototype ~extern:false ~semicolon:false ~newline:true
5702         ~handle:"g" name style;
5703       pr "{\n";
5704       trace_call shortname style;
5705       pr "  return guestfs__%s " shortname;
5706       generate_c_call_args ~handle:"g" style;
5707       pr ";\n";
5708       pr "}\n";
5709       pr "\n"
5710   ) non_daemon_functions;
5711
5712   (* Client-side stubs for each function. *)
5713   List.iter (
5714     fun (shortname, style, _, _, _, _, _) ->
5715       let name = "guestfs_" ^ shortname in
5716
5717       (* Generate the action stub. *)
5718       generate_prototype ~extern:false ~semicolon:false ~newline:true
5719         ~handle:"g" name style;
5720
5721       let error_code =
5722         match fst style with
5723         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5724         | RConstString _ | RConstOptString _ ->
5725             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5726         | RString _ | RStringList _
5727         | RStruct _ | RStructList _
5728         | RHashtable _ | RBufferOut _ ->
5729             "NULL" in
5730
5731       pr "{\n";
5732
5733       (match snd style with
5734        | [] -> ()
5735        | _ -> pr "  struct %s_args args;\n" name
5736       );
5737
5738       pr "  guestfs_message_header hdr;\n";
5739       pr "  guestfs_message_error err;\n";
5740       let has_ret =
5741         match fst style with
5742         | RErr -> false
5743         | RConstString _ | RConstOptString _ ->
5744             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5745         | RInt _ | RInt64 _
5746         | RBool _ | RString _ | RStringList _
5747         | RStruct _ | RStructList _
5748         | RHashtable _ | RBufferOut _ ->
5749             pr "  struct %s_ret ret;\n" name;
5750             true in
5751
5752       pr "  int serial;\n";
5753       pr "  int r;\n";
5754       pr "\n";
5755       trace_call shortname style;
5756       pr "  if (check_state (g, \"%s\") == -1) return %s;\n"
5757         shortname error_code;
5758       pr "  guestfs___set_busy (g);\n";
5759       pr "\n";
5760
5761       (* Send the main header and arguments. *)
5762       (match snd style with
5763        | [] ->
5764            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
5765              (String.uppercase shortname)
5766        | args ->
5767            List.iter (
5768              function
5769              | Pathname n | Device n | Dev_or_Path n | String n ->
5770                  pr "  args.%s = (char *) %s;\n" n n
5771              | OptString n ->
5772                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
5773              | StringList n | DeviceList n ->
5774                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
5775                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
5776              | Bool n ->
5777                  pr "  args.%s = %s;\n" n n
5778              | Int n ->
5779                  pr "  args.%s = %s;\n" n n
5780              | Int64 n ->
5781                  pr "  args.%s = %s;\n" n n
5782              | FileIn _ | FileOut _ -> ()
5783            ) args;
5784            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
5785              (String.uppercase shortname);
5786            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
5787              name;
5788       );
5789       pr "  if (serial == -1) {\n";
5790       pr "    guestfs___end_busy (g);\n";
5791       pr "    return %s;\n" error_code;
5792       pr "  }\n";
5793       pr "\n";
5794
5795       (* Send any additional files (FileIn) requested. *)
5796       let need_read_reply_label = ref false in
5797       List.iter (
5798         function
5799         | FileIn n ->
5800             pr "  r = guestfs___send_file (g, %s);\n" n;
5801             pr "  if (r == -1) {\n";
5802             pr "    guestfs___end_busy (g);\n";
5803             pr "    return %s;\n" error_code;
5804             pr "  }\n";
5805             pr "  if (r == -2) /* daemon cancelled */\n";
5806             pr "    goto read_reply;\n";
5807             need_read_reply_label := true;
5808             pr "\n";
5809         | _ -> ()
5810       ) (snd style);
5811
5812       (* Wait for the reply from the remote end. *)
5813       if !need_read_reply_label then pr " read_reply:\n";
5814       pr "  memset (&hdr, 0, sizeof hdr);\n";
5815       pr "  memset (&err, 0, sizeof err);\n";
5816       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
5817       pr "\n";
5818       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
5819       if not has_ret then
5820         pr "NULL, NULL"
5821       else
5822         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
5823       pr ");\n";
5824
5825       pr "  if (r == -1) {\n";
5826       pr "    guestfs___end_busy (g);\n";
5827       pr "    return %s;\n" error_code;
5828       pr "  }\n";
5829       pr "\n";
5830
5831       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
5832         (String.uppercase shortname);
5833       pr "    guestfs___end_busy (g);\n";
5834       pr "    return %s;\n" error_code;
5835       pr "  }\n";
5836       pr "\n";
5837
5838       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
5839       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
5840       pr "    free (err.error_message);\n";
5841       pr "    guestfs___end_busy (g);\n";
5842       pr "    return %s;\n" error_code;
5843       pr "  }\n";
5844       pr "\n";
5845
5846       (* Expecting to receive further files (FileOut)? *)
5847       List.iter (
5848         function
5849         | FileOut n ->
5850             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
5851             pr "    guestfs___end_busy (g);\n";
5852             pr "    return %s;\n" error_code;
5853             pr "  }\n";
5854             pr "\n";
5855         | _ -> ()
5856       ) (snd style);
5857
5858       pr "  guestfs___end_busy (g);\n";
5859
5860       (match fst style with
5861        | RErr -> pr "  return 0;\n"
5862        | RInt n | RInt64 n | RBool n ->
5863            pr "  return ret.%s;\n" n
5864        | RConstString _ | RConstOptString _ ->
5865            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5866        | RString n ->
5867            pr "  return ret.%s; /* caller will free */\n" n
5868        | RStringList n | RHashtable n ->
5869            pr "  /* caller will free this, but we need to add a NULL entry */\n";
5870            pr "  ret.%s.%s_val =\n" n n;
5871            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
5872            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
5873              n n;
5874            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
5875            pr "  return ret.%s.%s_val;\n" n n
5876        | RStruct (n, _) ->
5877            pr "  /* caller will free this */\n";
5878            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5879        | RStructList (n, _) ->
5880            pr "  /* caller will free this */\n";
5881            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
5882        | RBufferOut n ->
5883            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
5884            pr "   * _val might be NULL here.  To make the API saner for\n";
5885            pr "   * callers, we turn this case into a unique pointer (using\n";
5886            pr "   * malloc(1)).\n";
5887            pr "   */\n";
5888            pr "  if (ret.%s.%s_len > 0) {\n" n n;
5889            pr "    *size_r = ret.%s.%s_len;\n" n n;
5890            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
5891            pr "  } else {\n";
5892            pr "    free (ret.%s.%s_val);\n" n n;
5893            pr "    char *p = safe_malloc (g, 1);\n";
5894            pr "    *size_r = ret.%s.%s_len;\n" n n;
5895            pr "    return p;\n";
5896            pr "  }\n";
5897       );
5898
5899       pr "}\n\n"
5900   ) daemon_functions;
5901
5902   (* Functions to free structures. *)
5903   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
5904   pr " * structure format is identical to the XDR format.  See note in\n";
5905   pr " * generator.ml.\n";
5906   pr " */\n";
5907   pr "\n";
5908
5909   List.iter (
5910     fun (typ, _) ->
5911       pr "void\n";
5912       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
5913       pr "{\n";
5914       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
5915       pr "  free (x);\n";
5916       pr "}\n";
5917       pr "\n";
5918
5919       pr "void\n";
5920       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
5921       pr "{\n";
5922       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
5923       pr "  free (x);\n";
5924       pr "}\n";
5925       pr "\n";
5926
5927   ) structs;
5928
5929 (* Generate daemon/actions.h. *)
5930 and generate_daemon_actions_h () =
5931   generate_header CStyle GPLv2plus;
5932
5933   pr "#include \"../src/guestfs_protocol.h\"\n";
5934   pr "\n";
5935
5936   List.iter (
5937     fun (name, style, _, _, _, _, _) ->
5938       generate_prototype
5939         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
5940         name style;
5941   ) daemon_functions
5942
5943 (* Generate the linker script which controls the visibility of
5944  * symbols in the public ABI and ensures no other symbols get
5945  * exported accidentally.
5946  *)
5947 and generate_linker_script () =
5948   generate_header HashStyle GPLv2plus;
5949
5950   let globals = [
5951     "guestfs_create";
5952     "guestfs_close";
5953     "guestfs_get_error_handler";
5954     "guestfs_get_out_of_memory_handler";
5955     "guestfs_last_error";
5956     "guestfs_set_error_handler";
5957     "guestfs_set_launch_done_callback";
5958     "guestfs_set_log_message_callback";
5959     "guestfs_set_out_of_memory_handler";
5960     "guestfs_set_subprocess_quit_callback";
5961
5962     (* Unofficial parts of the API: the bindings code use these
5963      * functions, so it is useful to export them.
5964      *)
5965     "guestfs_safe_calloc";
5966     "guestfs_safe_malloc";
5967   ] in
5968   let functions =
5969     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
5970       all_functions in
5971   let structs =
5972     List.concat (
5973       List.map (fun (typ, _) ->
5974                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
5975         structs
5976     ) in
5977   let globals = List.sort compare (globals @ functions @ structs) in
5978
5979   pr "{\n";
5980   pr "    global:\n";
5981   List.iter (pr "        %s;\n") globals;
5982   pr "\n";
5983
5984   pr "    local:\n";
5985   pr "        *;\n";
5986   pr "};\n"
5987
5988 (* Generate the server-side stubs. *)
5989 and generate_daemon_actions () =
5990   generate_header CStyle GPLv2plus;
5991
5992   pr "#include <config.h>\n";
5993   pr "\n";
5994   pr "#include <stdio.h>\n";
5995   pr "#include <stdlib.h>\n";
5996   pr "#include <string.h>\n";
5997   pr "#include <inttypes.h>\n";
5998   pr "#include <rpc/types.h>\n";
5999   pr "#include <rpc/xdr.h>\n";
6000   pr "\n";
6001   pr "#include \"daemon.h\"\n";
6002   pr "#include \"c-ctype.h\"\n";
6003   pr "#include \"../src/guestfs_protocol.h\"\n";
6004   pr "#include \"actions.h\"\n";
6005   pr "\n";
6006
6007   List.iter (
6008     fun (name, style, _, _, _, _, _) ->
6009       (* Generate server-side stubs. *)
6010       pr "static void %s_stub (XDR *xdr_in)\n" name;
6011       pr "{\n";
6012       let error_code =
6013         match fst style with
6014         | RErr | RInt _ -> pr "  int r;\n"; "-1"
6015         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6016         | RBool _ -> pr "  int r;\n"; "-1"
6017         | RConstString _ | RConstOptString _ ->
6018             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6019         | RString _ -> pr "  char *r;\n"; "NULL"
6020         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6021         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
6022         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
6023         | RBufferOut _ ->
6024             pr "  size_t size = 1;\n";
6025             pr "  char *r;\n";
6026             "NULL" in
6027
6028       (match snd style with
6029        | [] -> ()
6030        | args ->
6031            pr "  struct guestfs_%s_args args;\n" name;
6032            List.iter (
6033              function
6034              | Device n | Dev_or_Path n
6035              | Pathname n
6036              | String n -> ()
6037              | OptString n -> pr "  char *%s;\n" n
6038              | StringList n | DeviceList n -> pr "  char **%s;\n" n
6039              | Bool n -> pr "  int %s;\n" n
6040              | Int n -> pr "  int %s;\n" n
6041              | Int64 n -> pr "  int64_t %s;\n" n
6042              | FileIn _ | FileOut _ -> ()
6043            ) args
6044       );
6045       pr "\n";
6046
6047       let is_filein =
6048         List.exists (function FileIn _ -> true | _ -> false) (snd style) in
6049
6050       (match snd style with
6051        | [] -> ()
6052        | args ->
6053            pr "  memset (&args, 0, sizeof args);\n";
6054            pr "\n";
6055            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
6056            if is_filein then
6057              pr "    cancel_receive ();\n";
6058            pr "    reply_with_error (\"daemon failed to decode procedure arguments\");\n";
6059            pr "    goto done;\n";
6060            pr "  }\n";
6061            let pr_args n =
6062              pr "  char *%s = args.%s;\n" n n
6063            in
6064            let pr_list_handling_code n =
6065              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
6066              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
6067              pr "  if (%s == NULL) {\n" n;
6068              if is_filein then
6069                pr "    cancel_receive ();\n";
6070              pr "    reply_with_perror (\"realloc\");\n";
6071              pr "    goto done;\n";
6072              pr "  }\n";
6073              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
6074              pr "  args.%s.%s_val = %s;\n" n n n;
6075            in
6076            List.iter (
6077              function
6078              | Pathname n ->
6079                  pr_args n;
6080                  pr "  ABS_PATH (%s, %s, goto done);\n"
6081                    n (if is_filein then "cancel_receive ()" else "");
6082              | Device n ->
6083                  pr_args n;
6084                  pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
6085                    n (if is_filein then "cancel_receive ()" else "");
6086              | Dev_or_Path n ->
6087                  pr_args n;
6088                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
6089                    n (if is_filein then "cancel_receive ()" else "");
6090              | String n -> pr_args n
6091              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
6092              | StringList n ->
6093                  pr_list_handling_code n;
6094              | DeviceList n ->
6095                  pr_list_handling_code n;
6096                  pr "  /* Ensure that each is a device,\n";
6097                  pr "   * and perform device name translation. */\n";
6098                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
6099                  pr "    RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n"
6100                    (if is_filein then "cancel_receive ()" else "");
6101                  pr "  }\n";
6102              | Bool n -> pr "  %s = args.%s;\n" n n
6103              | Int n -> pr "  %s = args.%s;\n" n n
6104              | Int64 n -> pr "  %s = args.%s;\n" n n
6105              | FileIn _ | FileOut _ -> ()
6106            ) args;
6107            pr "\n"
6108       );
6109
6110
6111       (* this is used at least for do_equal *)
6112       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
6113         (* Emit NEED_ROOT just once, even when there are two or
6114            more Pathname args *)
6115         pr "  NEED_ROOT (%s, goto done);\n"
6116           (if is_filein then "cancel_receive ()" else "");
6117       );
6118
6119       (* Don't want to call the impl with any FileIn or FileOut
6120        * parameters, since these go "outside" the RPC protocol.
6121        *)
6122       let args' =
6123         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
6124           (snd style) in
6125       pr "  r = do_%s " name;
6126       generate_c_call_args (fst style, args');
6127       pr ";\n";
6128
6129       (match fst style with
6130        | RErr | RInt _ | RInt64 _ | RBool _
6131        | RConstString _ | RConstOptString _
6132        | RString _ | RStringList _ | RHashtable _
6133        | RStruct (_, _) | RStructList (_, _) ->
6134            pr "  if (r == %s)\n" error_code;
6135            pr "    /* do_%s has already called reply_with_error */\n" name;
6136            pr "    goto done;\n";
6137            pr "\n"
6138        | RBufferOut _ ->
6139            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
6140            pr "   * an ordinary zero-length buffer), so be careful ...\n";
6141            pr "   */\n";
6142            pr "  if (size == 1 && r == %s)\n" error_code;
6143            pr "    /* do_%s has already called reply_with_error */\n" name;
6144            pr "    goto done;\n";
6145            pr "\n"
6146       );
6147
6148       (* If there are any FileOut parameters, then the impl must
6149        * send its own reply.
6150        *)
6151       let no_reply =
6152         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
6153       if no_reply then
6154         pr "  /* do_%s has already sent a reply */\n" name
6155       else (
6156         match fst style with
6157         | RErr -> pr "  reply (NULL, NULL);\n"
6158         | RInt n | RInt64 n | RBool n ->
6159             pr "  struct guestfs_%s_ret ret;\n" name;
6160             pr "  ret.%s = r;\n" n;
6161             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6162               name
6163         | RConstString _ | RConstOptString _ ->
6164             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6165         | RString n ->
6166             pr "  struct guestfs_%s_ret ret;\n" name;
6167             pr "  ret.%s = r;\n" n;
6168             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6169               name;
6170             pr "  free (r);\n"
6171         | RStringList n | RHashtable n ->
6172             pr "  struct guestfs_%s_ret ret;\n" name;
6173             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
6174             pr "  ret.%s.%s_val = r;\n" n n;
6175             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6176               name;
6177             pr "  free_strings (r);\n"
6178         | RStruct (n, _) ->
6179             pr "  struct guestfs_%s_ret ret;\n" name;
6180             pr "  ret.%s = *r;\n" n;
6181             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6182               name;
6183             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6184               name
6185         | RStructList (n, _) ->
6186             pr "  struct guestfs_%s_ret ret;\n" name;
6187             pr "  ret.%s = *r;\n" n;
6188             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6189               name;
6190             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6191               name
6192         | RBufferOut n ->
6193             pr "  struct guestfs_%s_ret ret;\n" name;
6194             pr "  ret.%s.%s_val = r;\n" n n;
6195             pr "  ret.%s.%s_len = size;\n" n n;
6196             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6197               name;
6198             pr "  free (r);\n"
6199       );
6200
6201       (* Free the args. *)
6202       pr "done:\n";
6203       (match snd style with
6204        | [] -> ()
6205        | _ ->
6206            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
6207              name
6208       );
6209       pr "  return;\n";
6210       pr "}\n\n";
6211   ) daemon_functions;
6212
6213   (* Dispatch function. *)
6214   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
6215   pr "{\n";
6216   pr "  switch (proc_nr) {\n";
6217
6218   List.iter (
6219     fun (name, style, _, _, _, _, _) ->
6220       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
6221       pr "      %s_stub (xdr_in);\n" name;
6222       pr "      break;\n"
6223   ) daemon_functions;
6224
6225   pr "    default:\n";
6226   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";
6227   pr "  }\n";
6228   pr "}\n";
6229   pr "\n";
6230
6231   (* LVM columns and tokenization functions. *)
6232   (* XXX This generates crap code.  We should rethink how we
6233    * do this parsing.
6234    *)
6235   List.iter (
6236     function
6237     | typ, cols ->
6238         pr "static const char *lvm_%s_cols = \"%s\";\n"
6239           typ (String.concat "," (List.map fst cols));
6240         pr "\n";
6241
6242         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
6243         pr "{\n";
6244         pr "  char *tok, *p, *next;\n";
6245         pr "  int i, j;\n";
6246         pr "\n";
6247         (*
6248           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
6249           pr "\n";
6250         *)
6251         pr "  if (!str) {\n";
6252         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
6253         pr "    return -1;\n";
6254         pr "  }\n";
6255         pr "  if (!*str || c_isspace (*str)) {\n";
6256         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
6257         pr "    return -1;\n";
6258         pr "  }\n";
6259         pr "  tok = str;\n";
6260         List.iter (
6261           fun (name, coltype) ->
6262             pr "  if (!tok) {\n";
6263             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
6264             pr "    return -1;\n";
6265             pr "  }\n";
6266             pr "  p = strchrnul (tok, ',');\n";
6267             pr "  if (*p) next = p+1; else next = NULL;\n";
6268             pr "  *p = '\\0';\n";
6269             (match coltype with
6270              | FString ->
6271                  pr "  r->%s = strdup (tok);\n" name;
6272                  pr "  if (r->%s == NULL) {\n" name;
6273                  pr "    perror (\"strdup\");\n";
6274                  pr "    return -1;\n";
6275                  pr "  }\n"
6276              | FUUID ->
6277                  pr "  for (i = j = 0; i < 32; ++j) {\n";
6278                  pr "    if (tok[j] == '\\0') {\n";
6279                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
6280                  pr "      return -1;\n";
6281                  pr "    } else if (tok[j] != '-')\n";
6282                  pr "      r->%s[i++] = tok[j];\n" name;
6283                  pr "  }\n";
6284              | FBytes ->
6285                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
6286                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6287                  pr "    return -1;\n";
6288                  pr "  }\n";
6289              | FInt64 ->
6290                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
6291                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6292                  pr "    return -1;\n";
6293                  pr "  }\n";
6294              | FOptPercent ->
6295                  pr "  if (tok[0] == '\\0')\n";
6296                  pr "    r->%s = -1;\n" name;
6297                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
6298                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6299                  pr "    return -1;\n";
6300                  pr "  }\n";
6301              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
6302                  assert false (* can never be an LVM column *)
6303             );
6304             pr "  tok = next;\n";
6305         ) cols;
6306
6307         pr "  if (tok != NULL) {\n";
6308         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6309         pr "    return -1;\n";
6310         pr "  }\n";
6311         pr "  return 0;\n";
6312         pr "}\n";
6313         pr "\n";
6314
6315         pr "guestfs_int_lvm_%s_list *\n" typ;
6316         pr "parse_command_line_%ss (void)\n" typ;
6317         pr "{\n";
6318         pr "  char *out, *err;\n";
6319         pr "  char *p, *pend;\n";
6320         pr "  int r, i;\n";
6321         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6322         pr "  void *newp;\n";
6323         pr "\n";
6324         pr "  ret = malloc (sizeof *ret);\n";
6325         pr "  if (!ret) {\n";
6326         pr "    reply_with_perror (\"malloc\");\n";
6327         pr "    return NULL;\n";
6328         pr "  }\n";
6329         pr "\n";
6330         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6331         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6332         pr "\n";
6333         pr "  r = command (&out, &err,\n";
6334         pr "           \"lvm\", \"%ss\",\n" typ;
6335         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6336         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6337         pr "  if (r == -1) {\n";
6338         pr "    reply_with_error (\"%%s\", err);\n";
6339         pr "    free (out);\n";
6340         pr "    free (err);\n";
6341         pr "    free (ret);\n";
6342         pr "    return NULL;\n";
6343         pr "  }\n";
6344         pr "\n";
6345         pr "  free (err);\n";
6346         pr "\n";
6347         pr "  /* Tokenize each line of the output. */\n";
6348         pr "  p = out;\n";
6349         pr "  i = 0;\n";
6350         pr "  while (p) {\n";
6351         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6352         pr "    if (pend) {\n";
6353         pr "      *pend = '\\0';\n";
6354         pr "      pend++;\n";
6355         pr "    }\n";
6356         pr "\n";
6357         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6358         pr "      p++;\n";
6359         pr "\n";
6360         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6361         pr "      p = pend;\n";
6362         pr "      continue;\n";
6363         pr "    }\n";
6364         pr "\n";
6365         pr "    /* Allocate some space to store this next entry. */\n";
6366         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6367         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6368         pr "    if (newp == NULL) {\n";
6369         pr "      reply_with_perror (\"realloc\");\n";
6370         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6371         pr "      free (ret);\n";
6372         pr "      free (out);\n";
6373         pr "      return NULL;\n";
6374         pr "    }\n";
6375         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6376         pr "\n";
6377         pr "    /* Tokenize the next entry. */\n";
6378         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6379         pr "    if (r == -1) {\n";
6380         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6381         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6382         pr "      free (ret);\n";
6383         pr "      free (out);\n";
6384         pr "      return NULL;\n";
6385         pr "    }\n";
6386         pr "\n";
6387         pr "    ++i;\n";
6388         pr "    p = pend;\n";
6389         pr "  }\n";
6390         pr "\n";
6391         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6392         pr "\n";
6393         pr "  free (out);\n";
6394         pr "  return ret;\n";
6395         pr "}\n"
6396
6397   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6398
6399 (* Generate a list of function names, for debugging in the daemon.. *)
6400 and generate_daemon_names () =
6401   generate_header CStyle GPLv2plus;
6402
6403   pr "#include <config.h>\n";
6404   pr "\n";
6405   pr "#include \"daemon.h\"\n";
6406   pr "\n";
6407
6408   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6409   pr "const char *function_names[] = {\n";
6410   List.iter (
6411     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6412   ) daemon_functions;
6413   pr "};\n";
6414
6415 (* Generate the optional groups for the daemon to implement
6416  * guestfs_available.
6417  *)
6418 and generate_daemon_optgroups_c () =
6419   generate_header CStyle GPLv2plus;
6420
6421   pr "#include <config.h>\n";
6422   pr "\n";
6423   pr "#include \"daemon.h\"\n";
6424   pr "#include \"optgroups.h\"\n";
6425   pr "\n";
6426
6427   pr "struct optgroup optgroups[] = {\n";
6428   List.iter (
6429     fun (group, _) ->
6430       pr "  { \"%s\", optgroup_%s_available },\n" group group
6431   ) optgroups;
6432   pr "  { NULL, NULL }\n";
6433   pr "};\n"
6434
6435 and generate_daemon_optgroups_h () =
6436   generate_header CStyle GPLv2plus;
6437
6438   List.iter (
6439     fun (group, _) ->
6440       pr "extern int optgroup_%s_available (void);\n" group
6441   ) optgroups
6442
6443 (* Generate the tests. *)
6444 and generate_tests () =
6445   generate_header CStyle GPLv2plus;
6446
6447   pr "\
6448 #include <stdio.h>
6449 #include <stdlib.h>
6450 #include <string.h>
6451 #include <unistd.h>
6452 #include <sys/types.h>
6453 #include <fcntl.h>
6454
6455 #include \"guestfs.h\"
6456 #include \"guestfs-internal.h\"
6457
6458 static guestfs_h *g;
6459 static int suppress_error = 0;
6460
6461 static void print_error (guestfs_h *g, void *data, const char *msg)
6462 {
6463   if (!suppress_error)
6464     fprintf (stderr, \"%%s\\n\", msg);
6465 }
6466
6467 /* FIXME: nearly identical code appears in fish.c */
6468 static void print_strings (char *const *argv)
6469 {
6470   int argc;
6471
6472   for (argc = 0; argv[argc] != NULL; ++argc)
6473     printf (\"\\t%%s\\n\", argv[argc]);
6474 }
6475
6476 /*
6477 static void print_table (char const *const *argv)
6478 {
6479   int i;
6480
6481   for (i = 0; argv[i] != NULL; i += 2)
6482     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6483 }
6484 */
6485
6486 ";
6487
6488   (* Generate a list of commands which are not tested anywhere. *)
6489   pr "static void no_test_warnings (void)\n";
6490   pr "{\n";
6491
6492   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6493   List.iter (
6494     fun (_, _, _, _, tests, _, _) ->
6495       let tests = filter_map (
6496         function
6497         | (_, (Always|If _|Unless _), test) -> Some test
6498         | (_, Disabled, _) -> None
6499       ) tests in
6500       let seq = List.concat (List.map seq_of_test tests) in
6501       let cmds_tested = List.map List.hd seq in
6502       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6503   ) all_functions;
6504
6505   List.iter (
6506     fun (name, _, _, _, _, _, _) ->
6507       if not (Hashtbl.mem hash name) then
6508         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6509   ) all_functions;
6510
6511   pr "}\n";
6512   pr "\n";
6513
6514   (* Generate the actual tests.  Note that we generate the tests
6515    * in reverse order, deliberately, so that (in general) the
6516    * newest tests run first.  This makes it quicker and easier to
6517    * debug them.
6518    *)
6519   let test_names =
6520     List.map (
6521       fun (name, _, _, flags, tests, _, _) ->
6522         mapi (generate_one_test name flags) tests
6523     ) (List.rev all_functions) in
6524   let test_names = List.concat test_names in
6525   let nr_tests = List.length test_names in
6526
6527   pr "\
6528 int main (int argc, char *argv[])
6529 {
6530   char c = 0;
6531   unsigned long int n_failed = 0;
6532   const char *filename;
6533   int fd;
6534   int nr_tests, test_num = 0;
6535
6536   setbuf (stdout, NULL);
6537
6538   no_test_warnings ();
6539
6540   g = guestfs_create ();
6541   if (g == NULL) {
6542     printf (\"guestfs_create FAILED\\n\");
6543     exit (EXIT_FAILURE);
6544   }
6545
6546   guestfs_set_error_handler (g, print_error, NULL);
6547
6548   guestfs_set_path (g, \"../appliance\");
6549
6550   filename = \"test1.img\";
6551   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6552   if (fd == -1) {
6553     perror (filename);
6554     exit (EXIT_FAILURE);
6555   }
6556   if (lseek (fd, %d, SEEK_SET) == -1) {
6557     perror (\"lseek\");
6558     close (fd);
6559     unlink (filename);
6560     exit (EXIT_FAILURE);
6561   }
6562   if (write (fd, &c, 1) == -1) {
6563     perror (\"write\");
6564     close (fd);
6565     unlink (filename);
6566     exit (EXIT_FAILURE);
6567   }
6568   if (close (fd) == -1) {
6569     perror (filename);
6570     unlink (filename);
6571     exit (EXIT_FAILURE);
6572   }
6573   if (guestfs_add_drive (g, filename) == -1) {
6574     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6575     exit (EXIT_FAILURE);
6576   }
6577
6578   filename = \"test2.img\";
6579   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6580   if (fd == -1) {
6581     perror (filename);
6582     exit (EXIT_FAILURE);
6583   }
6584   if (lseek (fd, %d, SEEK_SET) == -1) {
6585     perror (\"lseek\");
6586     close (fd);
6587     unlink (filename);
6588     exit (EXIT_FAILURE);
6589   }
6590   if (write (fd, &c, 1) == -1) {
6591     perror (\"write\");
6592     close (fd);
6593     unlink (filename);
6594     exit (EXIT_FAILURE);
6595   }
6596   if (close (fd) == -1) {
6597     perror (filename);
6598     unlink (filename);
6599     exit (EXIT_FAILURE);
6600   }
6601   if (guestfs_add_drive (g, filename) == -1) {
6602     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6603     exit (EXIT_FAILURE);
6604   }
6605
6606   filename = \"test3.img\";
6607   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6608   if (fd == -1) {
6609     perror (filename);
6610     exit (EXIT_FAILURE);
6611   }
6612   if (lseek (fd, %d, SEEK_SET) == -1) {
6613     perror (\"lseek\");
6614     close (fd);
6615     unlink (filename);
6616     exit (EXIT_FAILURE);
6617   }
6618   if (write (fd, &c, 1) == -1) {
6619     perror (\"write\");
6620     close (fd);
6621     unlink (filename);
6622     exit (EXIT_FAILURE);
6623   }
6624   if (close (fd) == -1) {
6625     perror (filename);
6626     unlink (filename);
6627     exit (EXIT_FAILURE);
6628   }
6629   if (guestfs_add_drive (g, filename) == -1) {
6630     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6631     exit (EXIT_FAILURE);
6632   }
6633
6634   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
6635     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
6636     exit (EXIT_FAILURE);
6637   }
6638
6639   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
6640   alarm (600);
6641
6642   if (guestfs_launch (g) == -1) {
6643     printf (\"guestfs_launch FAILED\\n\");
6644     exit (EXIT_FAILURE);
6645   }
6646
6647   /* Cancel previous alarm. */
6648   alarm (0);
6649
6650   nr_tests = %d;
6651
6652 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
6653
6654   iteri (
6655     fun i test_name ->
6656       pr "  test_num++;\n";
6657       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
6658       pr "  if (%s () == -1) {\n" test_name;
6659       pr "    printf (\"%s FAILED\\n\");\n" test_name;
6660       pr "    n_failed++;\n";
6661       pr "  }\n";
6662   ) test_names;
6663   pr "\n";
6664
6665   pr "  guestfs_close (g);\n";
6666   pr "  unlink (\"test1.img\");\n";
6667   pr "  unlink (\"test2.img\");\n";
6668   pr "  unlink (\"test3.img\");\n";
6669   pr "\n";
6670
6671   pr "  if (n_failed > 0) {\n";
6672   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
6673   pr "    exit (EXIT_FAILURE);\n";
6674   pr "  }\n";
6675   pr "\n";
6676
6677   pr "  exit (EXIT_SUCCESS);\n";
6678   pr "}\n"
6679
6680 and generate_one_test name flags i (init, prereq, test) =
6681   let test_name = sprintf "test_%s_%d" name i in
6682
6683   pr "\
6684 static int %s_skip (void)
6685 {
6686   const char *str;
6687
6688   str = getenv (\"TEST_ONLY\");
6689   if (str)
6690     return strstr (str, \"%s\") == NULL;
6691   str = getenv (\"SKIP_%s\");
6692   if (str && STREQ (str, \"1\")) return 1;
6693   str = getenv (\"SKIP_TEST_%s\");
6694   if (str && STREQ (str, \"1\")) return 1;
6695   return 0;
6696 }
6697
6698 " test_name name (String.uppercase test_name) (String.uppercase name);
6699
6700   (match prereq with
6701    | Disabled | Always -> ()
6702    | If code | Unless code ->
6703        pr "static int %s_prereq (void)\n" test_name;
6704        pr "{\n";
6705        pr "  %s\n" code;
6706        pr "}\n";
6707        pr "\n";
6708   );
6709
6710   pr "\
6711 static int %s (void)
6712 {
6713   if (%s_skip ()) {
6714     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
6715     return 0;
6716   }
6717
6718 " test_name test_name test_name;
6719
6720   (* Optional functions should only be tested if the relevant
6721    * support is available in the daemon.
6722    *)
6723   List.iter (
6724     function
6725     | Optional group ->
6726         pr "  {\n";
6727         pr "    const char *groups[] = { \"%s\", NULL };\n" group;
6728         pr "    int r;\n";
6729         pr "    suppress_error = 1;\n";
6730         pr "    r = guestfs_available (g, (char **) groups);\n";
6731         pr "    suppress_error = 0;\n";
6732         pr "    if (r == -1) {\n";
6733         pr "      printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
6734         pr "      return 0;\n";
6735         pr "    }\n";
6736         pr "  }\n";
6737     | _ -> ()
6738   ) flags;
6739
6740   (match prereq with
6741    | Disabled ->
6742        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
6743    | If _ ->
6744        pr "  if (! %s_prereq ()) {\n" test_name;
6745        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6746        pr "    return 0;\n";
6747        pr "  }\n";
6748        pr "\n";
6749        generate_one_test_body name i test_name init test;
6750    | Unless _ ->
6751        pr "  if (%s_prereq ()) {\n" test_name;
6752        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
6753        pr "    return 0;\n";
6754        pr "  }\n";
6755        pr "\n";
6756        generate_one_test_body name i test_name init test;
6757    | Always ->
6758        generate_one_test_body name i test_name init test
6759   );
6760
6761   pr "  return 0;\n";
6762   pr "}\n";
6763   pr "\n";
6764   test_name
6765
6766 and generate_one_test_body name i test_name init test =
6767   (match init with
6768    | InitNone (* XXX at some point, InitNone and InitEmpty became
6769                * folded together as the same thing.  Really we should
6770                * make InitNone do nothing at all, but the tests may
6771                * need to be checked to make sure this is OK.
6772                *)
6773    | InitEmpty ->
6774        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
6775        List.iter (generate_test_command_call test_name)
6776          [["blockdev_setrw"; "/dev/sda"];
6777           ["umount_all"];
6778           ["lvm_remove_all"]]
6779    | InitPartition ->
6780        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
6781        List.iter (generate_test_command_call test_name)
6782          [["blockdev_setrw"; "/dev/sda"];
6783           ["umount_all"];
6784           ["lvm_remove_all"];
6785           ["part_disk"; "/dev/sda"; "mbr"]]
6786    | InitBasicFS ->
6787        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
6788        List.iter (generate_test_command_call test_name)
6789          [["blockdev_setrw"; "/dev/sda"];
6790           ["umount_all"];
6791           ["lvm_remove_all"];
6792           ["part_disk"; "/dev/sda"; "mbr"];
6793           ["mkfs"; "ext2"; "/dev/sda1"];
6794           ["mount_options"; ""; "/dev/sda1"; "/"]]
6795    | InitBasicFSonLVM ->
6796        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
6797          test_name;
6798        List.iter (generate_test_command_call test_name)
6799          [["blockdev_setrw"; "/dev/sda"];
6800           ["umount_all"];
6801           ["lvm_remove_all"];
6802           ["part_disk"; "/dev/sda"; "mbr"];
6803           ["pvcreate"; "/dev/sda1"];
6804           ["vgcreate"; "VG"; "/dev/sda1"];
6805           ["lvcreate"; "LV"; "VG"; "8"];
6806           ["mkfs"; "ext2"; "/dev/VG/LV"];
6807           ["mount_options"; ""; "/dev/VG/LV"; "/"]]
6808    | InitISOFS ->
6809        pr "  /* InitISOFS for %s */\n" test_name;
6810        List.iter (generate_test_command_call test_name)
6811          [["blockdev_setrw"; "/dev/sda"];
6812           ["umount_all"];
6813           ["lvm_remove_all"];
6814           ["mount_ro"; "/dev/sdd"; "/"]]
6815   );
6816
6817   let get_seq_last = function
6818     | [] ->
6819         failwithf "%s: you cannot use [] (empty list) when expecting a command"
6820           test_name
6821     | seq ->
6822         let seq = List.rev seq in
6823         List.rev (List.tl seq), List.hd seq
6824   in
6825
6826   match test with
6827   | TestRun seq ->
6828       pr "  /* TestRun for %s (%d) */\n" name i;
6829       List.iter (generate_test_command_call test_name) seq
6830   | TestOutput (seq, expected) ->
6831       pr "  /* TestOutput for %s (%d) */\n" name i;
6832       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6833       let seq, last = get_seq_last seq in
6834       let test () =
6835         pr "    if (STRNEQ (r, expected)) {\n";
6836         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6837         pr "      return -1;\n";
6838         pr "    }\n"
6839       in
6840       List.iter (generate_test_command_call test_name) seq;
6841       generate_test_command_call ~test test_name last
6842   | TestOutputList (seq, expected) ->
6843       pr "  /* TestOutputList for %s (%d) */\n" name i;
6844       let seq, last = get_seq_last seq in
6845       let test () =
6846         iteri (
6847           fun i str ->
6848             pr "    if (!r[%d]) {\n" i;
6849             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6850             pr "      print_strings (r);\n";
6851             pr "      return -1;\n";
6852             pr "    }\n";
6853             pr "    {\n";
6854             pr "      const char *expected = \"%s\";\n" (c_quote str);
6855             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6856             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6857             pr "        return -1;\n";
6858             pr "      }\n";
6859             pr "    }\n"
6860         ) expected;
6861         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6862         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6863           test_name;
6864         pr "      print_strings (r);\n";
6865         pr "      return -1;\n";
6866         pr "    }\n"
6867       in
6868       List.iter (generate_test_command_call test_name) seq;
6869       generate_test_command_call ~test test_name last
6870   | TestOutputListOfDevices (seq, expected) ->
6871       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
6872       let seq, last = get_seq_last seq in
6873       let test () =
6874         iteri (
6875           fun i str ->
6876             pr "    if (!r[%d]) {\n" i;
6877             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
6878             pr "      print_strings (r);\n";
6879             pr "      return -1;\n";
6880             pr "    }\n";
6881             pr "    {\n";
6882             pr "      const char *expected = \"%s\";\n" (c_quote str);
6883             pr "      r[%d][5] = 's';\n" i;
6884             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
6885             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
6886             pr "        return -1;\n";
6887             pr "      }\n";
6888             pr "    }\n"
6889         ) expected;
6890         pr "    if (r[%d] != NULL) {\n" (List.length expected);
6891         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
6892           test_name;
6893         pr "      print_strings (r);\n";
6894         pr "      return -1;\n";
6895         pr "    }\n"
6896       in
6897       List.iter (generate_test_command_call test_name) seq;
6898       generate_test_command_call ~test test_name last
6899   | TestOutputInt (seq, expected) ->
6900       pr "  /* TestOutputInt for %s (%d) */\n" name i;
6901       let seq, last = get_seq_last seq in
6902       let test () =
6903         pr "    if (r != %d) {\n" expected;
6904         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
6905           test_name expected;
6906         pr "               (int) r);\n";
6907         pr "      return -1;\n";
6908         pr "    }\n"
6909       in
6910       List.iter (generate_test_command_call test_name) seq;
6911       generate_test_command_call ~test test_name last
6912   | TestOutputIntOp (seq, op, expected) ->
6913       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
6914       let seq, last = get_seq_last seq in
6915       let test () =
6916         pr "    if (! (r %s %d)) {\n" op expected;
6917         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
6918           test_name op expected;
6919         pr "               (int) r);\n";
6920         pr "      return -1;\n";
6921         pr "    }\n"
6922       in
6923       List.iter (generate_test_command_call test_name) seq;
6924       generate_test_command_call ~test test_name last
6925   | TestOutputTrue seq ->
6926       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
6927       let seq, last = get_seq_last seq in
6928       let test () =
6929         pr "    if (!r) {\n";
6930         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
6931           test_name;
6932         pr "      return -1;\n";
6933         pr "    }\n"
6934       in
6935       List.iter (generate_test_command_call test_name) seq;
6936       generate_test_command_call ~test test_name last
6937   | TestOutputFalse seq ->
6938       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
6939       let seq, last = get_seq_last seq in
6940       let test () =
6941         pr "    if (r) {\n";
6942         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
6943           test_name;
6944         pr "      return -1;\n";
6945         pr "    }\n"
6946       in
6947       List.iter (generate_test_command_call test_name) seq;
6948       generate_test_command_call ~test test_name last
6949   | TestOutputLength (seq, expected) ->
6950       pr "  /* TestOutputLength for %s (%d) */\n" name i;
6951       let seq, last = get_seq_last seq in
6952       let test () =
6953         pr "    int j;\n";
6954         pr "    for (j = 0; j < %d; ++j)\n" expected;
6955         pr "      if (r[j] == NULL) {\n";
6956         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
6957           test_name;
6958         pr "        print_strings (r);\n";
6959         pr "        return -1;\n";
6960         pr "      }\n";
6961         pr "    if (r[j] != NULL) {\n";
6962         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
6963           test_name;
6964         pr "      print_strings (r);\n";
6965         pr "      return -1;\n";
6966         pr "    }\n"
6967       in
6968       List.iter (generate_test_command_call test_name) seq;
6969       generate_test_command_call ~test test_name last
6970   | TestOutputBuffer (seq, expected) ->
6971       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
6972       pr "  const char *expected = \"%s\";\n" (c_quote expected);
6973       let seq, last = get_seq_last seq in
6974       let len = String.length expected in
6975       let test () =
6976         pr "    if (size != %d) {\n" len;
6977         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
6978         pr "      return -1;\n";
6979         pr "    }\n";
6980         pr "    if (STRNEQLEN (r, expected, size)) {\n";
6981         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
6982         pr "      return -1;\n";
6983         pr "    }\n"
6984       in
6985       List.iter (generate_test_command_call test_name) seq;
6986       generate_test_command_call ~test test_name last
6987   | TestOutputStruct (seq, checks) ->
6988       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
6989       let seq, last = get_seq_last seq in
6990       let test () =
6991         List.iter (
6992           function
6993           | CompareWithInt (field, expected) ->
6994               pr "    if (r->%s != %d) {\n" field expected;
6995               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
6996                 test_name field expected;
6997               pr "               (int) r->%s);\n" field;
6998               pr "      return -1;\n";
6999               pr "    }\n"
7000           | CompareWithIntOp (field, op, expected) ->
7001               pr "    if (!(r->%s %s %d)) {\n" field op expected;
7002               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
7003                 test_name field op expected;
7004               pr "               (int) r->%s);\n" field;
7005               pr "      return -1;\n";
7006               pr "    }\n"
7007           | CompareWithString (field, expected) ->
7008               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
7009               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
7010                 test_name field expected;
7011               pr "               r->%s);\n" field;
7012               pr "      return -1;\n";
7013               pr "    }\n"
7014           | CompareFieldsIntEq (field1, field2) ->
7015               pr "    if (r->%s != r->%s) {\n" field1 field2;
7016               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
7017                 test_name field1 field2;
7018               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
7019               pr "      return -1;\n";
7020               pr "    }\n"
7021           | CompareFieldsStrEq (field1, field2) ->
7022               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
7023               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
7024                 test_name field1 field2;
7025               pr "               r->%s, r->%s);\n" field1 field2;
7026               pr "      return -1;\n";
7027               pr "    }\n"
7028         ) checks
7029       in
7030       List.iter (generate_test_command_call test_name) seq;
7031       generate_test_command_call ~test test_name last
7032   | TestLastFail seq ->
7033       pr "  /* TestLastFail for %s (%d) */\n" name i;
7034       let seq, last = get_seq_last seq in
7035       List.iter (generate_test_command_call test_name) seq;
7036       generate_test_command_call test_name ~expect_error:true last
7037
7038 (* Generate the code to run a command, leaving the result in 'r'.
7039  * If you expect to get an error then you should set expect_error:true.
7040  *)
7041 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
7042   match cmd with
7043   | [] -> assert false
7044   | name :: args ->
7045       (* Look up the command to find out what args/ret it has. *)
7046       let style =
7047         try
7048           let _, style, _, _, _, _, _ =
7049             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
7050           style
7051         with Not_found ->
7052           failwithf "%s: in test, command %s was not found" test_name name in
7053
7054       if List.length (snd style) <> List.length args then
7055         failwithf "%s: in test, wrong number of args given to %s"
7056           test_name name;
7057
7058       pr "  {\n";
7059
7060       List.iter (
7061         function
7062         | OptString n, "NULL" -> ()
7063         | Pathname n, arg
7064         | Device n, arg
7065         | Dev_or_Path n, arg
7066         | String n, arg
7067         | OptString n, arg ->
7068             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
7069         | Int _, _
7070         | Int64 _, _
7071         | Bool _, _
7072         | FileIn _, _ | FileOut _, _ -> ()
7073         | StringList n, "" | DeviceList n, "" ->
7074             pr "    const char *const %s[1] = { NULL };\n" n
7075         | StringList n, arg | DeviceList n, arg ->
7076             let strs = string_split " " arg in
7077             iteri (
7078               fun i str ->
7079                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
7080             ) strs;
7081             pr "    const char *const %s[] = {\n" n;
7082             iteri (
7083               fun i _ -> pr "      %s_%d,\n" n i
7084             ) strs;
7085             pr "      NULL\n";
7086             pr "    };\n";
7087       ) (List.combine (snd style) args);
7088
7089       let error_code =
7090         match fst style with
7091         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
7092         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
7093         | RConstString _ | RConstOptString _ ->
7094             pr "    const char *r;\n"; "NULL"
7095         | RString _ -> pr "    char *r;\n"; "NULL"
7096         | RStringList _ | RHashtable _ ->
7097             pr "    char **r;\n";
7098             pr "    int i;\n";
7099             "NULL"
7100         | RStruct (_, typ) ->
7101             pr "    struct guestfs_%s *r;\n" typ; "NULL"
7102         | RStructList (_, typ) ->
7103             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
7104         | RBufferOut _ ->
7105             pr "    char *r;\n";
7106             pr "    size_t size;\n";
7107             "NULL" in
7108
7109       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
7110       pr "    r = guestfs_%s (g" name;
7111
7112       (* Generate the parameters. *)
7113       List.iter (
7114         function
7115         | OptString _, "NULL" -> pr ", NULL"
7116         | Pathname n, _
7117         | Device n, _ | Dev_or_Path n, _
7118         | String n, _
7119         | OptString n, _ ->
7120             pr ", %s" n
7121         | FileIn _, arg | FileOut _, arg ->
7122             pr ", \"%s\"" (c_quote arg)
7123         | StringList n, _ | DeviceList n, _ ->
7124             pr ", (char **) %s" n
7125         | Int _, arg ->
7126             let i =
7127               try int_of_string arg
7128               with Failure "int_of_string" ->
7129                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
7130             pr ", %d" i
7131         | Int64 _, arg ->
7132             let i =
7133               try Int64.of_string arg
7134               with Failure "int_of_string" ->
7135                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
7136             pr ", %Ld" i
7137         | Bool _, arg ->
7138             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
7139       ) (List.combine (snd style) args);
7140
7141       (match fst style with
7142        | RBufferOut _ -> pr ", &size"
7143        | _ -> ()
7144       );
7145
7146       pr ");\n";
7147
7148       if not expect_error then
7149         pr "    if (r == %s)\n" error_code
7150       else
7151         pr "    if (r != %s)\n" error_code;
7152       pr "      return -1;\n";
7153
7154       (* Insert the test code. *)
7155       (match test with
7156        | None -> ()
7157        | Some f -> f ()
7158       );
7159
7160       (match fst style with
7161        | RErr | RInt _ | RInt64 _ | RBool _
7162        | RConstString _ | RConstOptString _ -> ()
7163        | RString _ | RBufferOut _ -> pr "    free (r);\n"
7164        | RStringList _ | RHashtable _ ->
7165            pr "    for (i = 0; r[i] != NULL; ++i)\n";
7166            pr "      free (r[i]);\n";
7167            pr "    free (r);\n"
7168        | RStruct (_, typ) ->
7169            pr "    guestfs_free_%s (r);\n" typ
7170        | RStructList (_, typ) ->
7171            pr "    guestfs_free_%s_list (r);\n" typ
7172       );
7173
7174       pr "  }\n"
7175
7176 and c_quote str =
7177   let str = replace_str str "\r" "\\r" in
7178   let str = replace_str str "\n" "\\n" in
7179   let str = replace_str str "\t" "\\t" in
7180   let str = replace_str str "\000" "\\0" in
7181   str
7182
7183 (* Generate a lot of different functions for guestfish. *)
7184 and generate_fish_cmds () =
7185   generate_header CStyle GPLv2plus;
7186
7187   let all_functions =
7188     List.filter (
7189       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7190     ) all_functions in
7191   let all_functions_sorted =
7192     List.filter (
7193       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7194     ) all_functions_sorted in
7195
7196   pr "#include <config.h>\n";
7197   pr "\n";
7198   pr "#include <stdio.h>\n";
7199   pr "#include <stdlib.h>\n";
7200   pr "#include <string.h>\n";
7201   pr "#include <inttypes.h>\n";
7202   pr "\n";
7203   pr "#include <guestfs.h>\n";
7204   pr "#include \"c-ctype.h\"\n";
7205   pr "#include \"full-write.h\"\n";
7206   pr "#include \"xstrtol.h\"\n";
7207   pr "#include \"fish.h\"\n";
7208   pr "\n";
7209
7210   (* list_commands function, which implements guestfish -h *)
7211   pr "void list_commands (void)\n";
7212   pr "{\n";
7213   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
7214   pr "  list_builtin_commands ();\n";
7215   List.iter (
7216     fun (name, _, _, flags, _, shortdesc, _) ->
7217       let name = replace_char name '_' '-' in
7218       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
7219         name shortdesc
7220   ) all_functions_sorted;
7221   pr "  printf (\"    %%s\\n\",";
7222   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
7223   pr "}\n";
7224   pr "\n";
7225
7226   (* display_command function, which implements guestfish -h cmd *)
7227   pr "void display_command (const char *cmd)\n";
7228   pr "{\n";
7229   List.iter (
7230     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7231       let name2 = replace_char name '_' '-' in
7232       let alias =
7233         try find_map (function FishAlias n -> Some n | _ -> None) flags
7234         with Not_found -> name in
7235       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
7236       let synopsis =
7237         match snd style with
7238         | [] -> name2
7239         | args ->
7240             sprintf "%s %s"
7241               name2 (String.concat " " (List.map name_of_argt args)) in
7242
7243       let warnings =
7244         if List.mem ProtocolLimitWarning flags then
7245           ("\n\n" ^ protocol_limit_warning)
7246         else "" in
7247
7248       (* For DangerWillRobinson commands, we should probably have
7249        * guestfish prompt before allowing you to use them (especially
7250        * in interactive mode). XXX
7251        *)
7252       let warnings =
7253         warnings ^
7254           if List.mem DangerWillRobinson flags then
7255             ("\n\n" ^ danger_will_robinson)
7256           else "" in
7257
7258       let warnings =
7259         warnings ^
7260           match deprecation_notice flags with
7261           | None -> ""
7262           | Some txt -> "\n\n" ^ txt in
7263
7264       let describe_alias =
7265         if name <> alias then
7266           sprintf "\n\nYou can use '%s' as an alias for this command." alias
7267         else "" in
7268
7269       pr "  if (";
7270       pr "STRCASEEQ (cmd, \"%s\")" name;
7271       if name <> name2 then
7272         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7273       if name <> alias then
7274         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7275       pr ")\n";
7276       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
7277         name2 shortdesc
7278         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
7279          "=head1 DESCRIPTION\n\n" ^
7280          longdesc ^ warnings ^ describe_alias);
7281       pr "  else\n"
7282   ) all_functions;
7283   pr "    display_builtin_command (cmd);\n";
7284   pr "}\n";
7285   pr "\n";
7286
7287   let emit_print_list_function typ =
7288     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
7289       typ typ typ;
7290     pr "{\n";
7291     pr "  unsigned int i;\n";
7292     pr "\n";
7293     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
7294     pr "    printf (\"[%%d] = {\\n\", i);\n";
7295     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
7296     pr "    printf (\"}\\n\");\n";
7297     pr "  }\n";
7298     pr "}\n";
7299     pr "\n";
7300   in
7301
7302   (* print_* functions *)
7303   List.iter (
7304     fun (typ, cols) ->
7305       let needs_i =
7306         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
7307
7308       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7309       pr "{\n";
7310       if needs_i then (
7311         pr "  unsigned int i;\n";
7312         pr "\n"
7313       );
7314       List.iter (
7315         function
7316         | name, FString ->
7317             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7318         | name, FUUID ->
7319             pr "  printf (\"%%s%s: \", indent);\n" name;
7320             pr "  for (i = 0; i < 32; ++i)\n";
7321             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7322             pr "  printf (\"\\n\");\n"
7323         | name, FBuffer ->
7324             pr "  printf (\"%%s%s: \", indent);\n" name;
7325             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7326             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7327             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7328             pr "    else\n";
7329             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7330             pr "  printf (\"\\n\");\n"
7331         | name, (FUInt64|FBytes) ->
7332             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7333               name typ name
7334         | name, FInt64 ->
7335             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7336               name typ name
7337         | name, FUInt32 ->
7338             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7339               name typ name
7340         | name, FInt32 ->
7341             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7342               name typ name
7343         | name, FChar ->
7344             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7345               name typ name
7346         | name, FOptPercent ->
7347             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7348               typ name name typ name;
7349             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7350       ) cols;
7351       pr "}\n";
7352       pr "\n";
7353   ) structs;
7354
7355   (* Emit a print_TYPE_list function definition only if that function is used. *)
7356   List.iter (
7357     function
7358     | typ, (RStructListOnly | RStructAndList) ->
7359         (* generate the function for typ *)
7360         emit_print_list_function typ
7361     | typ, _ -> () (* empty *)
7362   ) (rstructs_used_by all_functions);
7363
7364   (* Emit a print_TYPE function definition only if that function is used. *)
7365   List.iter (
7366     function
7367     | typ, (RStructOnly | RStructAndList) ->
7368         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7369         pr "{\n";
7370         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7371         pr "}\n";
7372         pr "\n";
7373     | typ, _ -> () (* empty *)
7374   ) (rstructs_used_by all_functions);
7375
7376   (* run_<action> actions *)
7377   List.iter (
7378     fun (name, style, _, flags, _, _, _) ->
7379       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7380       pr "{\n";
7381       (match fst style with
7382        | RErr
7383        | RInt _
7384        | RBool _ -> pr "  int r;\n"
7385        | RInt64 _ -> pr "  int64_t r;\n"
7386        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7387        | RString _ -> pr "  char *r;\n"
7388        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7389        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7390        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7391        | RBufferOut _ ->
7392            pr "  char *r;\n";
7393            pr "  size_t size;\n";
7394       );
7395       List.iter (
7396         function
7397         | Device n
7398         | String n
7399         | OptString n -> pr "  const char *%s;\n" n
7400         | Pathname n
7401         | Dev_or_Path n
7402         | FileIn n
7403         | FileOut n -> pr "  char *%s;\n" n
7404         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7405         | Bool n -> pr "  int %s;\n" n
7406         | Int n -> pr "  int %s;\n" n
7407         | Int64 n -> pr "  int64_t %s;\n" n
7408       ) (snd style);
7409
7410       (* Check and convert parameters. *)
7411       let argc_expected = List.length (snd style) in
7412       pr "  if (argc != %d) {\n" argc_expected;
7413       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7414         argc_expected;
7415       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7416       pr "    return -1;\n";
7417       pr "  }\n";
7418
7419       let parse_integer fn fntyp rtyp range name i =
7420         pr "  {\n";
7421         pr "    strtol_error xerr;\n";
7422         pr "    %s r;\n" fntyp;
7423         pr "\n";
7424         pr "    xerr = %s (argv[%d], NULL, 0, &r, \"\");\n" fn i;
7425         pr "    if (xerr != LONGINT_OK) {\n";
7426         pr "      fprintf (stderr,\n";
7427         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7428         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7429         pr "      return -1;\n";
7430         pr "    }\n";
7431         (match range with
7432          | None -> ()
7433          | Some (min, max, comment) ->
7434              pr "    /* %s */\n" comment;
7435              pr "    if (r < %s || r > %s) {\n" min max;
7436              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7437                name;
7438              pr "      return -1;\n";
7439              pr "    }\n";
7440              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7441         );
7442         pr "    %s = r;\n" name;
7443         pr "  }\n";
7444       in
7445
7446       iteri (
7447         fun i ->
7448           function
7449           | Device name
7450           | String name ->
7451               pr "  %s = argv[%d];\n" name i
7452           | Pathname name
7453           | Dev_or_Path name ->
7454               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7455               pr "  if (%s == NULL) return -1;\n" name
7456           | OptString name ->
7457               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7458                 name i i
7459           | FileIn name ->
7460               pr "  %s = file_in (argv[%d]);\n" name i;
7461               pr "  if (%s == NULL) return -1;\n" name
7462           | FileOut name ->
7463               pr "  %s = file_out (argv[%d]);\n" name i;
7464               pr "  if (%s == NULL) return -1;\n" name
7465           | StringList name | DeviceList name ->
7466               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7467               pr "  if (%s == NULL) return -1;\n" name;
7468           | Bool name ->
7469               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7470           | Int name ->
7471               let range =
7472                 let min = "(-(2LL<<30))"
7473                 and max = "((2LL<<30)-1)"
7474                 and comment =
7475                   "The Int type in the generator is a signed 31 bit int." in
7476                 Some (min, max, comment) in
7477               parse_integer "xstrtoll" "long long" "int" range name i
7478           | Int64 name ->
7479               parse_integer "xstrtoll" "long long" "int64_t" None name i
7480       ) (snd style);
7481
7482       (* Call C API function. *)
7483       let fn =
7484         try find_map (function FishAction n -> Some n | _ -> None) flags
7485         with Not_found -> sprintf "guestfs_%s" name in
7486       pr "  r = %s " fn;
7487       generate_c_call_args ~handle:"g" style;
7488       pr ";\n";
7489
7490       List.iter (
7491         function
7492         | Device name | String name
7493         | OptString name | Bool name
7494         | Int name | Int64 name -> ()
7495         | Pathname name | Dev_or_Path name | FileOut name ->
7496             pr "  free (%s);\n" name
7497         | FileIn name ->
7498             pr "  free_file_in (%s);\n" name
7499         | StringList name | DeviceList name ->
7500             pr "  free_strings (%s);\n" name
7501       ) (snd style);
7502
7503       (* Any output flags? *)
7504       let fish_output =
7505         let flags = filter_map (
7506           function FishOutput flag -> Some flag | _ -> None
7507         ) flags in
7508         match flags with
7509         | [] -> None
7510         | [f] -> Some f
7511         | _ ->
7512             failwithf "%s: more than one FishOutput flag is not allowed" name in
7513
7514       (* Check return value for errors and display command results. *)
7515       (match fst style with
7516        | RErr -> pr "  return r;\n"
7517        | RInt _ ->
7518            pr "  if (r == -1) return -1;\n";
7519            (match fish_output with
7520             | None ->
7521                 pr "  printf (\"%%d\\n\", r);\n";
7522             | Some FishOutputOctal ->
7523                 pr "  printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n";
7524             | Some FishOutputHexadecimal ->
7525                 pr "  printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7526            pr "  return 0;\n"
7527        | RInt64 _ ->
7528            pr "  if (r == -1) return -1;\n";
7529            (match fish_output with
7530             | None ->
7531                 pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7532             | Some FishOutputOctal ->
7533                 pr "  printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n";
7534             | Some FishOutputHexadecimal ->
7535                 pr "  printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7536            pr "  return 0;\n"
7537        | RBool _ ->
7538            pr "  if (r == -1) return -1;\n";
7539            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7540            pr "  return 0;\n"
7541        | RConstString _ ->
7542            pr "  if (r == NULL) return -1;\n";
7543            pr "  printf (\"%%s\\n\", r);\n";
7544            pr "  return 0;\n"
7545        | RConstOptString _ ->
7546            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7547            pr "  return 0;\n"
7548        | RString _ ->
7549            pr "  if (r == NULL) return -1;\n";
7550            pr "  printf (\"%%s\\n\", r);\n";
7551            pr "  free (r);\n";
7552            pr "  return 0;\n"
7553        | RStringList _ ->
7554            pr "  if (r == NULL) return -1;\n";
7555            pr "  print_strings (r);\n";
7556            pr "  free_strings (r);\n";
7557            pr "  return 0;\n"
7558        | RStruct (_, typ) ->
7559            pr "  if (r == NULL) return -1;\n";
7560            pr "  print_%s (r);\n" typ;
7561            pr "  guestfs_free_%s (r);\n" typ;
7562            pr "  return 0;\n"
7563        | RStructList (_, typ) ->
7564            pr "  if (r == NULL) return -1;\n";
7565            pr "  print_%s_list (r);\n" typ;
7566            pr "  guestfs_free_%s_list (r);\n" typ;
7567            pr "  return 0;\n"
7568        | RHashtable _ ->
7569            pr "  if (r == NULL) return -1;\n";
7570            pr "  print_table (r);\n";
7571            pr "  free_strings (r);\n";
7572            pr "  return 0;\n"
7573        | RBufferOut _ ->
7574            pr "  if (r == NULL) return -1;\n";
7575            pr "  if (full_write (1, r, size) != size) {\n";
7576            pr "    perror (\"write\");\n";
7577            pr "    free (r);\n";
7578            pr "    return -1;\n";
7579            pr "  }\n";
7580            pr "  free (r);\n";
7581            pr "  return 0;\n"
7582       );
7583       pr "}\n";
7584       pr "\n"
7585   ) all_functions;
7586
7587   (* run_action function *)
7588   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7589   pr "{\n";
7590   List.iter (
7591     fun (name, _, _, flags, _, _, _) ->
7592       let name2 = replace_char name '_' '-' in
7593       let alias =
7594         try find_map (function FishAlias n -> Some n | _ -> None) flags
7595         with Not_found -> name in
7596       pr "  if (";
7597       pr "STRCASEEQ (cmd, \"%s\")" name;
7598       if name <> name2 then
7599         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7600       if name <> alias then
7601         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7602       pr ")\n";
7603       pr "    return run_%s (cmd, argc, argv);\n" name;
7604       pr "  else\n";
7605   ) all_functions;
7606   pr "    {\n";
7607   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7608   pr "      if (command_num == 1)\n";
7609   pr "        extended_help_message ();\n";
7610   pr "      return -1;\n";
7611   pr "    }\n";
7612   pr "  return 0;\n";
7613   pr "}\n";
7614   pr "\n"
7615
7616 (* Readline completion for guestfish. *)
7617 and generate_fish_completion () =
7618   generate_header CStyle GPLv2plus;
7619
7620   let all_functions =
7621     List.filter (
7622       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7623     ) all_functions in
7624
7625   pr "\
7626 #include <config.h>
7627
7628 #include <stdio.h>
7629 #include <stdlib.h>
7630 #include <string.h>
7631
7632 #ifdef HAVE_LIBREADLINE
7633 #include <readline/readline.h>
7634 #endif
7635
7636 #include \"fish.h\"
7637
7638 #ifdef HAVE_LIBREADLINE
7639
7640 static const char *const commands[] = {
7641   BUILTIN_COMMANDS_FOR_COMPLETION,
7642 ";
7643
7644   (* Get the commands, including the aliases.  They don't need to be
7645    * sorted - the generator() function just does a dumb linear search.
7646    *)
7647   let commands =
7648     List.map (
7649       fun (name, _, _, flags, _, _, _) ->
7650         let name2 = replace_char name '_' '-' in
7651         let alias =
7652           try find_map (function FishAlias n -> Some n | _ -> None) flags
7653           with Not_found -> name in
7654
7655         if name <> alias then [name2; alias] else [name2]
7656     ) all_functions in
7657   let commands = List.flatten commands in
7658
7659   List.iter (pr "  \"%s\",\n") commands;
7660
7661   pr "  NULL
7662 };
7663
7664 static char *
7665 generator (const char *text, int state)
7666 {
7667   static int index, len;
7668   const char *name;
7669
7670   if (!state) {
7671     index = 0;
7672     len = strlen (text);
7673   }
7674
7675   rl_attempted_completion_over = 1;
7676
7677   while ((name = commands[index]) != NULL) {
7678     index++;
7679     if (STRCASEEQLEN (name, text, len))
7680       return strdup (name);
7681   }
7682
7683   return NULL;
7684 }
7685
7686 #endif /* HAVE_LIBREADLINE */
7687
7688 #ifdef HAVE_RL_COMPLETION_MATCHES
7689 #define RL_COMPLETION_MATCHES rl_completion_matches
7690 #else
7691 #ifdef HAVE_COMPLETION_MATCHES
7692 #define RL_COMPLETION_MATCHES completion_matches
7693 #endif
7694 #endif /* else just fail if we don't have either symbol */
7695
7696 char **
7697 do_completion (const char *text, int start, int end)
7698 {
7699   char **matches = NULL;
7700
7701 #ifdef HAVE_LIBREADLINE
7702   rl_completion_append_character = ' ';
7703
7704   if (start == 0)
7705     matches = RL_COMPLETION_MATCHES (text, generator);
7706   else if (complete_dest_paths)
7707     matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
7708 #endif
7709
7710   return matches;
7711 }
7712 ";
7713
7714 (* Generate the POD documentation for guestfish. *)
7715 and generate_fish_actions_pod () =
7716   let all_functions_sorted =
7717     List.filter (
7718       fun (_, _, _, flags, _, _, _) ->
7719         not (List.mem NotInFish flags || List.mem NotInDocs flags)
7720     ) all_functions_sorted in
7721
7722   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
7723
7724   List.iter (
7725     fun (name, style, _, flags, _, _, longdesc) ->
7726       let longdesc =
7727         Str.global_substitute rex (
7728           fun s ->
7729             let sub =
7730               try Str.matched_group 1 s
7731               with Not_found ->
7732                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
7733             "C<" ^ replace_char sub '_' '-' ^ ">"
7734         ) longdesc in
7735       let name = replace_char name '_' '-' in
7736       let alias =
7737         try find_map (function FishAlias n -> Some n | _ -> None) flags
7738         with Not_found -> name in
7739
7740       pr "=head2 %s" name;
7741       if name <> alias then
7742         pr " | %s" alias;
7743       pr "\n";
7744       pr "\n";
7745       pr " %s" name;
7746       List.iter (
7747         function
7748         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
7749         | OptString n -> pr " %s" n
7750         | StringList n | DeviceList n -> pr " '%s ...'" n
7751         | Bool _ -> pr " true|false"
7752         | Int n -> pr " %s" n
7753         | Int64 n -> pr " %s" n
7754         | FileIn n | FileOut n -> pr " (%s|-)" n
7755       ) (snd style);
7756       pr "\n";
7757       pr "\n";
7758       pr "%s\n\n" longdesc;
7759
7760       if List.exists (function FileIn _ | FileOut _ -> true
7761                       | _ -> false) (snd style) then
7762         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
7763
7764       if List.mem ProtocolLimitWarning flags then
7765         pr "%s\n\n" protocol_limit_warning;
7766
7767       if List.mem DangerWillRobinson flags then
7768         pr "%s\n\n" danger_will_robinson;
7769
7770       match deprecation_notice flags with
7771       | None -> ()
7772       | Some txt -> pr "%s\n\n" txt
7773   ) all_functions_sorted
7774
7775 (* Generate a C function prototype. *)
7776 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
7777     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
7778     ?(prefix = "")
7779     ?handle name style =
7780   if extern then pr "extern ";
7781   if static then pr "static ";
7782   (match fst style with
7783    | RErr -> pr "int "
7784    | RInt _ -> pr "int "
7785    | RInt64 _ -> pr "int64_t "
7786    | RBool _ -> pr "int "
7787    | RConstString _ | RConstOptString _ -> pr "const char *"
7788    | RString _ | RBufferOut _ -> pr "char *"
7789    | RStringList _ | RHashtable _ -> pr "char **"
7790    | RStruct (_, typ) ->
7791        if not in_daemon then pr "struct guestfs_%s *" typ
7792        else pr "guestfs_int_%s *" typ
7793    | RStructList (_, typ) ->
7794        if not in_daemon then pr "struct guestfs_%s_list *" typ
7795        else pr "guestfs_int_%s_list *" typ
7796   );
7797   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
7798   pr "%s%s (" prefix name;
7799   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
7800     pr "void"
7801   else (
7802     let comma = ref false in
7803     (match handle with
7804      | None -> ()
7805      | Some handle -> pr "guestfs_h *%s" handle; comma := true
7806     );
7807     let next () =
7808       if !comma then (
7809         if single_line then pr ", " else pr ",\n\t\t"
7810       );
7811       comma := true
7812     in
7813     List.iter (
7814       function
7815       | Pathname n
7816       | Device n | Dev_or_Path n
7817       | String n
7818       | OptString n ->
7819           next ();
7820           pr "const char *%s" n
7821       | StringList n | DeviceList n ->
7822           next ();
7823           pr "char *const *%s" n
7824       | Bool n -> next (); pr "int %s" n
7825       | Int n -> next (); pr "int %s" n
7826       | Int64 n -> next (); pr "int64_t %s" n
7827       | FileIn n
7828       | FileOut n ->
7829           if not in_daemon then (next (); pr "const char *%s" n)
7830     ) (snd style);
7831     if is_RBufferOut then (next (); pr "size_t *size_r");
7832   );
7833   pr ")";
7834   if semicolon then pr ";";
7835   if newline then pr "\n"
7836
7837 (* Generate C call arguments, eg "(handle, foo, bar)" *)
7838 and generate_c_call_args ?handle ?(decl = false) style =
7839   pr "(";
7840   let comma = ref false in
7841   let next () =
7842     if !comma then pr ", ";
7843     comma := true
7844   in
7845   (match handle with
7846    | None -> ()
7847    | Some handle -> pr "%s" handle; comma := true
7848   );
7849   List.iter (
7850     fun arg ->
7851       next ();
7852       pr "%s" (name_of_argt arg)
7853   ) (snd style);
7854   (* For RBufferOut calls, add implicit &size parameter. *)
7855   if not decl then (
7856     match fst style with
7857     | RBufferOut _ ->
7858         next ();
7859         pr "&size"
7860     | _ -> ()
7861   );
7862   pr ")"
7863
7864 (* Generate the OCaml bindings interface. *)
7865 and generate_ocaml_mli () =
7866   generate_header OCamlStyle LGPLv2plus;
7867
7868   pr "\
7869 (** For API documentation you should refer to the C API
7870     in the guestfs(3) manual page.  The OCaml API uses almost
7871     exactly the same calls. *)
7872
7873 type t
7874 (** A [guestfs_h] handle. *)
7875
7876 exception Error of string
7877 (** This exception is raised when there is an error. *)
7878
7879 exception Handle_closed of string
7880 (** This exception is raised if you use a {!Guestfs.t} handle
7881     after calling {!close} on it.  The string is the name of
7882     the function. *)
7883
7884 val create : unit -> t
7885 (** Create a {!Guestfs.t} handle. *)
7886
7887 val close : t -> unit
7888 (** Close the {!Guestfs.t} handle and free up all resources used
7889     by it immediately.
7890
7891     Handles are closed by the garbage collector when they become
7892     unreferenced, but callers can call this in order to provide
7893     predictable cleanup. *)
7894
7895 ";
7896   generate_ocaml_structure_decls ();
7897
7898   (* The actions. *)
7899   List.iter (
7900     fun (name, style, _, _, _, shortdesc, _) ->
7901       generate_ocaml_prototype name style;
7902       pr "(** %s *)\n" shortdesc;
7903       pr "\n"
7904   ) all_functions_sorted
7905
7906 (* Generate the OCaml bindings implementation. *)
7907 and generate_ocaml_ml () =
7908   generate_header OCamlStyle LGPLv2plus;
7909
7910   pr "\
7911 type t
7912
7913 exception Error of string
7914 exception Handle_closed of string
7915
7916 external create : unit -> t = \"ocaml_guestfs_create\"
7917 external close : t -> unit = \"ocaml_guestfs_close\"
7918
7919 (* Give the exceptions names, so they can be raised from the C code. *)
7920 let () =
7921   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
7922   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
7923
7924 ";
7925
7926   generate_ocaml_structure_decls ();
7927
7928   (* The actions. *)
7929   List.iter (
7930     fun (name, style, _, _, _, shortdesc, _) ->
7931       generate_ocaml_prototype ~is_external:true name style;
7932   ) all_functions_sorted
7933
7934 (* Generate the OCaml bindings C implementation. *)
7935 and generate_ocaml_c () =
7936   generate_header CStyle LGPLv2plus;
7937
7938   pr "\
7939 #include <stdio.h>
7940 #include <stdlib.h>
7941 #include <string.h>
7942
7943 #include <caml/config.h>
7944 #include <caml/alloc.h>
7945 #include <caml/callback.h>
7946 #include <caml/fail.h>
7947 #include <caml/memory.h>
7948 #include <caml/mlvalues.h>
7949 #include <caml/signals.h>
7950
7951 #include <guestfs.h>
7952
7953 #include \"guestfs_c.h\"
7954
7955 /* Copy a hashtable of string pairs into an assoc-list.  We return
7956  * the list in reverse order, but hashtables aren't supposed to be
7957  * ordered anyway.
7958  */
7959 static CAMLprim value
7960 copy_table (char * const * argv)
7961 {
7962   CAMLparam0 ();
7963   CAMLlocal5 (rv, pairv, kv, vv, cons);
7964   int i;
7965
7966   rv = Val_int (0);
7967   for (i = 0; argv[i] != NULL; i += 2) {
7968     kv = caml_copy_string (argv[i]);
7969     vv = caml_copy_string (argv[i+1]);
7970     pairv = caml_alloc (2, 0);
7971     Store_field (pairv, 0, kv);
7972     Store_field (pairv, 1, vv);
7973     cons = caml_alloc (2, 0);
7974     Store_field (cons, 1, rv);
7975     rv = cons;
7976     Store_field (cons, 0, pairv);
7977   }
7978
7979   CAMLreturn (rv);
7980 }
7981
7982 ";
7983
7984   (* Struct copy functions. *)
7985
7986   let emit_ocaml_copy_list_function typ =
7987     pr "static CAMLprim value\n";
7988     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
7989     pr "{\n";
7990     pr "  CAMLparam0 ();\n";
7991     pr "  CAMLlocal2 (rv, v);\n";
7992     pr "  unsigned int i;\n";
7993     pr "\n";
7994     pr "  if (%ss->len == 0)\n" typ;
7995     pr "    CAMLreturn (Atom (0));\n";
7996     pr "  else {\n";
7997     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
7998     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
7999     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
8000     pr "      caml_modify (&Field (rv, i), v);\n";
8001     pr "    }\n";
8002     pr "    CAMLreturn (rv);\n";
8003     pr "  }\n";
8004     pr "}\n";
8005     pr "\n";
8006   in
8007
8008   List.iter (
8009     fun (typ, cols) ->
8010       let has_optpercent_col =
8011         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
8012
8013       pr "static CAMLprim value\n";
8014       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
8015       pr "{\n";
8016       pr "  CAMLparam0 ();\n";
8017       if has_optpercent_col then
8018         pr "  CAMLlocal3 (rv, v, v2);\n"
8019       else
8020         pr "  CAMLlocal2 (rv, v);\n";
8021       pr "\n";
8022       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
8023       iteri (
8024         fun i col ->
8025           (match col with
8026            | name, FString ->
8027                pr "  v = caml_copy_string (%s->%s);\n" typ name
8028            | name, FBuffer ->
8029                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
8030                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
8031                  typ name typ name
8032            | name, FUUID ->
8033                pr "  v = caml_alloc_string (32);\n";
8034                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
8035            | name, (FBytes|FInt64|FUInt64) ->
8036                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
8037            | name, (FInt32|FUInt32) ->
8038                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
8039            | name, FOptPercent ->
8040                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
8041                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
8042                pr "    v = caml_alloc (1, 0);\n";
8043                pr "    Store_field (v, 0, v2);\n";
8044                pr "  } else /* None */\n";
8045                pr "    v = Val_int (0);\n";
8046            | name, FChar ->
8047                pr "  v = Val_int (%s->%s);\n" typ name
8048           );
8049           pr "  Store_field (rv, %d, v);\n" i
8050       ) cols;
8051       pr "  CAMLreturn (rv);\n";
8052       pr "}\n";
8053       pr "\n";
8054   ) structs;
8055
8056   (* Emit a copy_TYPE_list function definition only if that function is used. *)
8057   List.iter (
8058     function
8059     | typ, (RStructListOnly | RStructAndList) ->
8060         (* generate the function for typ *)
8061         emit_ocaml_copy_list_function typ
8062     | typ, _ -> () (* empty *)
8063   ) (rstructs_used_by all_functions);
8064
8065   (* The wrappers. *)
8066   List.iter (
8067     fun (name, style, _, _, _, _, _) ->
8068       pr "/* Automatically generated wrapper for function\n";
8069       pr " * ";
8070       generate_ocaml_prototype name style;
8071       pr " */\n";
8072       pr "\n";
8073
8074       let params =
8075         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
8076
8077       let needs_extra_vs =
8078         match fst style with RConstOptString _ -> true | _ -> false in
8079
8080       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8081       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
8082       List.iter (pr ", value %s") (List.tl params); pr ");\n";
8083       pr "\n";
8084
8085       pr "CAMLprim value\n";
8086       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
8087       List.iter (pr ", value %s") (List.tl params);
8088       pr ")\n";
8089       pr "{\n";
8090
8091       (match params with
8092        | [p1; p2; p3; p4; p5] ->
8093            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
8094        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
8095            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
8096            pr "  CAMLxparam%d (%s);\n"
8097              (List.length rest) (String.concat ", " rest)
8098        | ps ->
8099            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
8100       );
8101       if not needs_extra_vs then
8102         pr "  CAMLlocal1 (rv);\n"
8103       else
8104         pr "  CAMLlocal3 (rv, v, v2);\n";
8105       pr "\n";
8106
8107       pr "  guestfs_h *g = Guestfs_val (gv);\n";
8108       pr "  if (g == NULL)\n";
8109       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
8110       pr "\n";
8111
8112       List.iter (
8113         function
8114         | Pathname n
8115         | Device n | Dev_or_Path n
8116         | String n
8117         | FileIn n
8118         | FileOut n ->
8119             pr "  const char *%s = String_val (%sv);\n" n n
8120         | OptString n ->
8121             pr "  const char *%s =\n" n;
8122             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
8123               n n
8124         | StringList n | DeviceList n ->
8125             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
8126         | Bool n ->
8127             pr "  int %s = Bool_val (%sv);\n" n n
8128         | Int n ->
8129             pr "  int %s = Int_val (%sv);\n" n n
8130         | Int64 n ->
8131             pr "  int64_t %s = Int64_val (%sv);\n" n n
8132       ) (snd style);
8133       let error_code =
8134         match fst style with
8135         | RErr -> pr "  int r;\n"; "-1"
8136         | RInt _ -> pr "  int r;\n"; "-1"
8137         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8138         | RBool _ -> pr "  int r;\n"; "-1"
8139         | RConstString _ | RConstOptString _ ->
8140             pr "  const char *r;\n"; "NULL"
8141         | RString _ -> pr "  char *r;\n"; "NULL"
8142         | RStringList _ ->
8143             pr "  int i;\n";
8144             pr "  char **r;\n";
8145             "NULL"
8146         | RStruct (_, typ) ->
8147             pr "  struct guestfs_%s *r;\n" typ; "NULL"
8148         | RStructList (_, typ) ->
8149             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8150         | RHashtable _ ->
8151             pr "  int i;\n";
8152             pr "  char **r;\n";
8153             "NULL"
8154         | RBufferOut _ ->
8155             pr "  char *r;\n";
8156             pr "  size_t size;\n";
8157             "NULL" in
8158       pr "\n";
8159
8160       pr "  caml_enter_blocking_section ();\n";
8161       pr "  r = guestfs_%s " name;
8162       generate_c_call_args ~handle:"g" style;
8163       pr ";\n";
8164       pr "  caml_leave_blocking_section ();\n";
8165
8166       List.iter (
8167         function
8168         | StringList n | DeviceList n ->
8169             pr "  ocaml_guestfs_free_strings (%s);\n" n;
8170         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8171         | Bool _ | Int _ | Int64 _
8172         | FileIn _ | FileOut _ -> ()
8173       ) (snd style);
8174
8175       pr "  if (r == %s)\n" error_code;
8176       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
8177       pr "\n";
8178
8179       (match fst style with
8180        | RErr -> pr "  rv = Val_unit;\n"
8181        | RInt _ -> pr "  rv = Val_int (r);\n"
8182        | RInt64 _ ->
8183            pr "  rv = caml_copy_int64 (r);\n"
8184        | RBool _ -> pr "  rv = Val_bool (r);\n"
8185        | RConstString _ ->
8186            pr "  rv = caml_copy_string (r);\n"
8187        | RConstOptString _ ->
8188            pr "  if (r) { /* Some string */\n";
8189            pr "    v = caml_alloc (1, 0);\n";
8190            pr "    v2 = caml_copy_string (r);\n";
8191            pr "    Store_field (v, 0, v2);\n";
8192            pr "  } else /* None */\n";
8193            pr "    v = Val_int (0);\n";
8194        | RString _ ->
8195            pr "  rv = caml_copy_string (r);\n";
8196            pr "  free (r);\n"
8197        | RStringList _ ->
8198            pr "  rv = caml_copy_string_array ((const char **) r);\n";
8199            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8200            pr "  free (r);\n"
8201        | RStruct (_, typ) ->
8202            pr "  rv = copy_%s (r);\n" typ;
8203            pr "  guestfs_free_%s (r);\n" typ;
8204        | RStructList (_, typ) ->
8205            pr "  rv = copy_%s_list (r);\n" typ;
8206            pr "  guestfs_free_%s_list (r);\n" typ;
8207        | RHashtable _ ->
8208            pr "  rv = copy_table (r);\n";
8209            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8210            pr "  free (r);\n";
8211        | RBufferOut _ ->
8212            pr "  rv = caml_alloc_string (size);\n";
8213            pr "  memcpy (String_val (rv), r, size);\n";
8214       );
8215
8216       pr "  CAMLreturn (rv);\n";
8217       pr "}\n";
8218       pr "\n";
8219
8220       if List.length params > 5 then (
8221         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8222         pr "CAMLprim value ";
8223         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
8224         pr "CAMLprim value\n";
8225         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
8226         pr "{\n";
8227         pr "  return ocaml_guestfs_%s (argv[0]" name;
8228         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
8229         pr ");\n";
8230         pr "}\n";
8231         pr "\n"
8232       )
8233   ) all_functions_sorted
8234
8235 and generate_ocaml_structure_decls () =
8236   List.iter (
8237     fun (typ, cols) ->
8238       pr "type %s = {\n" typ;
8239       List.iter (
8240         function
8241         | name, FString -> pr "  %s : string;\n" name
8242         | name, FBuffer -> pr "  %s : string;\n" name
8243         | name, FUUID -> pr "  %s : string;\n" name
8244         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
8245         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
8246         | name, FChar -> pr "  %s : char;\n" name
8247         | name, FOptPercent -> pr "  %s : float option;\n" name
8248       ) cols;
8249       pr "}\n";
8250       pr "\n"
8251   ) structs
8252
8253 and generate_ocaml_prototype ?(is_external = false) name style =
8254   if is_external then pr "external " else pr "val ";
8255   pr "%s : t -> " name;
8256   List.iter (
8257     function
8258     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
8259     | OptString _ -> pr "string option -> "
8260     | StringList _ | DeviceList _ -> pr "string array -> "
8261     | Bool _ -> pr "bool -> "
8262     | Int _ -> pr "int -> "
8263     | Int64 _ -> pr "int64 -> "
8264   ) (snd style);
8265   (match fst style with
8266    | RErr -> pr "unit" (* all errors are turned into exceptions *)
8267    | RInt _ -> pr "int"
8268    | RInt64 _ -> pr "int64"
8269    | RBool _ -> pr "bool"
8270    | RConstString _ -> pr "string"
8271    | RConstOptString _ -> pr "string option"
8272    | RString _ | RBufferOut _ -> pr "string"
8273    | RStringList _ -> pr "string array"
8274    | RStruct (_, typ) -> pr "%s" typ
8275    | RStructList (_, typ) -> pr "%s array" typ
8276    | RHashtable _ -> pr "(string * string) list"
8277   );
8278   if is_external then (
8279     pr " = ";
8280     if List.length (snd style) + 1 > 5 then
8281       pr "\"ocaml_guestfs_%s_byte\" " name;
8282     pr "\"ocaml_guestfs_%s\"" name
8283   );
8284   pr "\n"
8285
8286 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
8287 and generate_perl_xs () =
8288   generate_header CStyle LGPLv2plus;
8289
8290   pr "\
8291 #include \"EXTERN.h\"
8292 #include \"perl.h\"
8293 #include \"XSUB.h\"
8294
8295 #include <guestfs.h>
8296
8297 #ifndef PRId64
8298 #define PRId64 \"lld\"
8299 #endif
8300
8301 static SV *
8302 my_newSVll(long long val) {
8303 #ifdef USE_64_BIT_ALL
8304   return newSViv(val);
8305 #else
8306   char buf[100];
8307   int len;
8308   len = snprintf(buf, 100, \"%%\" PRId64, val);
8309   return newSVpv(buf, len);
8310 #endif
8311 }
8312
8313 #ifndef PRIu64
8314 #define PRIu64 \"llu\"
8315 #endif
8316
8317 static SV *
8318 my_newSVull(unsigned long long val) {
8319 #ifdef USE_64_BIT_ALL
8320   return newSVuv(val);
8321 #else
8322   char buf[100];
8323   int len;
8324   len = snprintf(buf, 100, \"%%\" PRIu64, val);
8325   return newSVpv(buf, len);
8326 #endif
8327 }
8328
8329 /* http://www.perlmonks.org/?node_id=680842 */
8330 static char **
8331 XS_unpack_charPtrPtr (SV *arg) {
8332   char **ret;
8333   AV *av;
8334   I32 i;
8335
8336   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
8337     croak (\"array reference expected\");
8338
8339   av = (AV *)SvRV (arg);
8340   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
8341   if (!ret)
8342     croak (\"malloc failed\");
8343
8344   for (i = 0; i <= av_len (av); i++) {
8345     SV **elem = av_fetch (av, i, 0);
8346
8347     if (!elem || !*elem)
8348       croak (\"missing element in list\");
8349
8350     ret[i] = SvPV_nolen (*elem);
8351   }
8352
8353   ret[i] = NULL;
8354
8355   return ret;
8356 }
8357
8358 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8359
8360 PROTOTYPES: ENABLE
8361
8362 guestfs_h *
8363 _create ()
8364    CODE:
8365       RETVAL = guestfs_create ();
8366       if (!RETVAL)
8367         croak (\"could not create guestfs handle\");
8368       guestfs_set_error_handler (RETVAL, NULL, NULL);
8369  OUTPUT:
8370       RETVAL
8371
8372 void
8373 DESTROY (g)
8374       guestfs_h *g;
8375  PPCODE:
8376       guestfs_close (g);
8377
8378 ";
8379
8380   List.iter (
8381     fun (name, style, _, _, _, _, _) ->
8382       (match fst style with
8383        | RErr -> pr "void\n"
8384        | RInt _ -> pr "SV *\n"
8385        | RInt64 _ -> pr "SV *\n"
8386        | RBool _ -> pr "SV *\n"
8387        | RConstString _ -> pr "SV *\n"
8388        | RConstOptString _ -> pr "SV *\n"
8389        | RString _ -> pr "SV *\n"
8390        | RBufferOut _ -> pr "SV *\n"
8391        | RStringList _
8392        | RStruct _ | RStructList _
8393        | RHashtable _ ->
8394            pr "void\n" (* all lists returned implictly on the stack *)
8395       );
8396       (* Call and arguments. *)
8397       pr "%s " name;
8398       generate_c_call_args ~handle:"g" ~decl:true style;
8399       pr "\n";
8400       pr "      guestfs_h *g;\n";
8401       iteri (
8402         fun i ->
8403           function
8404           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8405               pr "      char *%s;\n" n
8406           | OptString n ->
8407               (* http://www.perlmonks.org/?node_id=554277
8408                * Note that the implicit handle argument means we have
8409                * to add 1 to the ST(x) operator.
8410                *)
8411               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8412           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8413           | Bool n -> pr "      int %s;\n" n
8414           | Int n -> pr "      int %s;\n" n
8415           | Int64 n -> pr "      int64_t %s;\n" n
8416       ) (snd style);
8417
8418       let do_cleanups () =
8419         List.iter (
8420           function
8421           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8422           | Bool _ | Int _ | Int64 _
8423           | FileIn _ | FileOut _ -> ()
8424           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8425         ) (snd style)
8426       in
8427
8428       (* Code. *)
8429       (match fst style with
8430        | RErr ->
8431            pr "PREINIT:\n";
8432            pr "      int r;\n";
8433            pr " PPCODE:\n";
8434            pr "      r = guestfs_%s " name;
8435            generate_c_call_args ~handle:"g" style;
8436            pr ";\n";
8437            do_cleanups ();
8438            pr "      if (r == -1)\n";
8439            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8440        | RInt n
8441        | RBool n ->
8442            pr "PREINIT:\n";
8443            pr "      int %s;\n" n;
8444            pr "   CODE:\n";
8445            pr "      %s = guestfs_%s " n name;
8446            generate_c_call_args ~handle:"g" style;
8447            pr ";\n";
8448            do_cleanups ();
8449            pr "      if (%s == -1)\n" n;
8450            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8451            pr "      RETVAL = newSViv (%s);\n" n;
8452            pr " OUTPUT:\n";
8453            pr "      RETVAL\n"
8454        | RInt64 n ->
8455            pr "PREINIT:\n";
8456            pr "      int64_t %s;\n" n;
8457            pr "   CODE:\n";
8458            pr "      %s = guestfs_%s " n name;
8459            generate_c_call_args ~handle:"g" style;
8460            pr ";\n";
8461            do_cleanups ();
8462            pr "      if (%s == -1)\n" n;
8463            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8464            pr "      RETVAL = my_newSVll (%s);\n" n;
8465            pr " OUTPUT:\n";
8466            pr "      RETVAL\n"
8467        | RConstString n ->
8468            pr "PREINIT:\n";
8469            pr "      const char *%s;\n" n;
8470            pr "   CODE:\n";
8471            pr "      %s = guestfs_%s " n name;
8472            generate_c_call_args ~handle:"g" style;
8473            pr ";\n";
8474            do_cleanups ();
8475            pr "      if (%s == NULL)\n" n;
8476            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8477            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8478            pr " OUTPUT:\n";
8479            pr "      RETVAL\n"
8480        | RConstOptString n ->
8481            pr "PREINIT:\n";
8482            pr "      const char *%s;\n" n;
8483            pr "   CODE:\n";
8484            pr "      %s = guestfs_%s " n name;
8485            generate_c_call_args ~handle:"g" style;
8486            pr ";\n";
8487            do_cleanups ();
8488            pr "      if (%s == NULL)\n" n;
8489            pr "        RETVAL = &PL_sv_undef;\n";
8490            pr "      else\n";
8491            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8492            pr " OUTPUT:\n";
8493            pr "      RETVAL\n"
8494        | RString n ->
8495            pr "PREINIT:\n";
8496            pr "      char *%s;\n" n;
8497            pr "   CODE:\n";
8498            pr "      %s = guestfs_%s " n name;
8499            generate_c_call_args ~handle:"g" style;
8500            pr ";\n";
8501            do_cleanups ();
8502            pr "      if (%s == NULL)\n" n;
8503            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8504            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8505            pr "      free (%s);\n" n;
8506            pr " OUTPUT:\n";
8507            pr "      RETVAL\n"
8508        | RStringList n | RHashtable n ->
8509            pr "PREINIT:\n";
8510            pr "      char **%s;\n" n;
8511            pr "      int i, n;\n";
8512            pr " PPCODE:\n";
8513            pr "      %s = guestfs_%s " n name;
8514            generate_c_call_args ~handle:"g" style;
8515            pr ";\n";
8516            do_cleanups ();
8517            pr "      if (%s == NULL)\n" n;
8518            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8519            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8520            pr "      EXTEND (SP, n);\n";
8521            pr "      for (i = 0; i < n; ++i) {\n";
8522            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8523            pr "        free (%s[i]);\n" n;
8524            pr "      }\n";
8525            pr "      free (%s);\n" n;
8526        | RStruct (n, typ) ->
8527            let cols = cols_of_struct typ in
8528            generate_perl_struct_code typ cols name style n do_cleanups
8529        | RStructList (n, typ) ->
8530            let cols = cols_of_struct typ in
8531            generate_perl_struct_list_code typ cols name style n do_cleanups
8532        | RBufferOut n ->
8533            pr "PREINIT:\n";
8534            pr "      char *%s;\n" n;
8535            pr "      size_t size;\n";
8536            pr "   CODE:\n";
8537            pr "      %s = guestfs_%s " n name;
8538            generate_c_call_args ~handle:"g" style;
8539            pr ";\n";
8540            do_cleanups ();
8541            pr "      if (%s == NULL)\n" n;
8542            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8543            pr "      RETVAL = newSVpvn (%s, size);\n" n;
8544            pr "      free (%s);\n" n;
8545            pr " OUTPUT:\n";
8546            pr "      RETVAL\n"
8547       );
8548
8549       pr "\n"
8550   ) all_functions
8551
8552 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8553   pr "PREINIT:\n";
8554   pr "      struct guestfs_%s_list *%s;\n" typ n;
8555   pr "      int i;\n";
8556   pr "      HV *hv;\n";
8557   pr " PPCODE:\n";
8558   pr "      %s = guestfs_%s " n name;
8559   generate_c_call_args ~handle:"g" style;
8560   pr ";\n";
8561   do_cleanups ();
8562   pr "      if (%s == NULL)\n" n;
8563   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8564   pr "      EXTEND (SP, %s->len);\n" n;
8565   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8566   pr "        hv = newHV ();\n";
8567   List.iter (
8568     function
8569     | name, FString ->
8570         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8571           name (String.length name) n name
8572     | name, FUUID ->
8573         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8574           name (String.length name) n name
8575     | name, FBuffer ->
8576         pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8577           name (String.length name) n name n name
8578     | name, (FBytes|FUInt64) ->
8579         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8580           name (String.length name) n name
8581     | name, FInt64 ->
8582         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8583           name (String.length name) n name
8584     | name, (FInt32|FUInt32) ->
8585         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8586           name (String.length name) n name
8587     | name, FChar ->
8588         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8589           name (String.length name) n name
8590     | name, FOptPercent ->
8591         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8592           name (String.length name) n name
8593   ) cols;
8594   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8595   pr "      }\n";
8596   pr "      guestfs_free_%s_list (%s);\n" typ n
8597
8598 and generate_perl_struct_code typ cols name style n do_cleanups =
8599   pr "PREINIT:\n";
8600   pr "      struct guestfs_%s *%s;\n" typ n;
8601   pr " PPCODE:\n";
8602   pr "      %s = guestfs_%s " n name;
8603   generate_c_call_args ~handle:"g" style;
8604   pr ";\n";
8605   do_cleanups ();
8606   pr "      if (%s == NULL)\n" n;
8607   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8608   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
8609   List.iter (
8610     fun ((name, _) as col) ->
8611       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
8612
8613       match col with
8614       | name, FString ->
8615           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
8616             n name
8617       | name, FBuffer ->
8618           pr "      PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
8619             n name n name
8620       | name, FUUID ->
8621           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
8622             n name
8623       | name, (FBytes|FUInt64) ->
8624           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
8625             n name
8626       | name, FInt64 ->
8627           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
8628             n name
8629       | name, (FInt32|FUInt32) ->
8630           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8631             n name
8632       | name, FChar ->
8633           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
8634             n name
8635       | name, FOptPercent ->
8636           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
8637             n name
8638   ) cols;
8639   pr "      free (%s);\n" n
8640
8641 (* Generate Sys/Guestfs.pm. *)
8642 and generate_perl_pm () =
8643   generate_header HashStyle LGPLv2plus;
8644
8645   pr "\
8646 =pod
8647
8648 =head1 NAME
8649
8650 Sys::Guestfs - Perl bindings for libguestfs
8651
8652 =head1 SYNOPSIS
8653
8654  use Sys::Guestfs;
8655
8656  my $h = Sys::Guestfs->new ();
8657  $h->add_drive ('guest.img');
8658  $h->launch ();
8659  $h->mount ('/dev/sda1', '/');
8660  $h->touch ('/hello');
8661  $h->sync ();
8662
8663 =head1 DESCRIPTION
8664
8665 The C<Sys::Guestfs> module provides a Perl XS binding to the
8666 libguestfs API for examining and modifying virtual machine
8667 disk images.
8668
8669 Amongst the things this is good for: making batch configuration
8670 changes to guests, getting disk used/free statistics (see also:
8671 virt-df), migrating between virtualization systems (see also:
8672 virt-p2v), performing partial backups, performing partial guest
8673 clones, cloning guests and changing registry/UUID/hostname info, and
8674 much else besides.
8675
8676 Libguestfs uses Linux kernel and qemu code, and can access any type of
8677 guest filesystem that Linux and qemu can, including but not limited
8678 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
8679 schemes, qcow, qcow2, vmdk.
8680
8681 Libguestfs provides ways to enumerate guest storage (eg. partitions,
8682 LVs, what filesystem is in each LV, etc.).  It can also run commands
8683 in the context of the guest.  Also you can access filesystems over
8684 FUSE.
8685
8686 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
8687 functions for using libguestfs from Perl, including integration
8688 with libvirt.
8689
8690 =head1 ERRORS
8691
8692 All errors turn into calls to C<croak> (see L<Carp(3)>).
8693
8694 =head1 METHODS
8695
8696 =over 4
8697
8698 =cut
8699
8700 package Sys::Guestfs;
8701
8702 use strict;
8703 use warnings;
8704
8705 require XSLoader;
8706 XSLoader::load ('Sys::Guestfs');
8707
8708 =item $h = Sys::Guestfs->new ();
8709
8710 Create a new guestfs handle.
8711
8712 =cut
8713
8714 sub new {
8715   my $proto = shift;
8716   my $class = ref ($proto) || $proto;
8717
8718   my $self = Sys::Guestfs::_create ();
8719   bless $self, $class;
8720   return $self;
8721 }
8722
8723 ";
8724
8725   (* Actions.  We only need to print documentation for these as
8726    * they are pulled in from the XS code automatically.
8727    *)
8728   List.iter (
8729     fun (name, style, _, flags, _, _, longdesc) ->
8730       if not (List.mem NotInDocs flags) then (
8731         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
8732         pr "=item ";
8733         generate_perl_prototype name style;
8734         pr "\n\n";
8735         pr "%s\n\n" longdesc;
8736         if List.mem ProtocolLimitWarning flags then
8737           pr "%s\n\n" protocol_limit_warning;
8738         if List.mem DangerWillRobinson flags then
8739           pr "%s\n\n" danger_will_robinson;
8740         match deprecation_notice flags with
8741         | None -> ()
8742         | Some txt -> pr "%s\n\n" txt
8743       )
8744   ) all_functions_sorted;
8745
8746   (* End of file. *)
8747   pr "\
8748 =cut
8749
8750 1;
8751
8752 =back
8753
8754 =head1 COPYRIGHT
8755
8756 Copyright (C) %s Red Hat Inc.
8757
8758 =head1 LICENSE
8759
8760 Please see the file COPYING.LIB for the full license.
8761
8762 =head1 SEE ALSO
8763
8764 L<guestfs(3)>,
8765 L<guestfish(1)>,
8766 L<http://libguestfs.org>,
8767 L<Sys::Guestfs::Lib(3)>.
8768
8769 =cut
8770 " copyright_years
8771
8772 and generate_perl_prototype name style =
8773   (match fst style with
8774    | RErr -> ()
8775    | RBool n
8776    | RInt n
8777    | RInt64 n
8778    | RConstString n
8779    | RConstOptString n
8780    | RString n
8781    | RBufferOut n -> pr "$%s = " n
8782    | RStruct (n,_)
8783    | RHashtable n -> pr "%%%s = " n
8784    | RStringList n
8785    | RStructList (n,_) -> pr "@%s = " n
8786   );
8787   pr "$h->%s (" name;
8788   let comma = ref false in
8789   List.iter (
8790     fun arg ->
8791       if !comma then pr ", ";
8792       comma := true;
8793       match arg with
8794       | Pathname n | Device n | Dev_or_Path n | String n
8795       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n ->
8796           pr "$%s" n
8797       | StringList n | DeviceList n ->
8798           pr "\\@%s" n
8799   ) (snd style);
8800   pr ");"
8801
8802 (* Generate Python C module. *)
8803 and generate_python_c () =
8804   generate_header CStyle LGPLv2plus;
8805
8806   pr "\
8807 #include <Python.h>
8808
8809 #include <stdio.h>
8810 #include <stdlib.h>
8811 #include <assert.h>
8812
8813 #include \"guestfs.h\"
8814
8815 typedef struct {
8816   PyObject_HEAD
8817   guestfs_h *g;
8818 } Pyguestfs_Object;
8819
8820 static guestfs_h *
8821 get_handle (PyObject *obj)
8822 {
8823   assert (obj);
8824   assert (obj != Py_None);
8825   return ((Pyguestfs_Object *) obj)->g;
8826 }
8827
8828 static PyObject *
8829 put_handle (guestfs_h *g)
8830 {
8831   assert (g);
8832   return
8833     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
8834 }
8835
8836 /* This list should be freed (but not the strings) after use. */
8837 static char **
8838 get_string_list (PyObject *obj)
8839 {
8840   int i, len;
8841   char **r;
8842
8843   assert (obj);
8844
8845   if (!PyList_Check (obj)) {
8846     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
8847     return NULL;
8848   }
8849
8850   len = PyList_Size (obj);
8851   r = malloc (sizeof (char *) * (len+1));
8852   if (r == NULL) {
8853     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
8854     return NULL;
8855   }
8856
8857   for (i = 0; i < len; ++i)
8858     r[i] = PyString_AsString (PyList_GetItem (obj, i));
8859   r[len] = NULL;
8860
8861   return r;
8862 }
8863
8864 static PyObject *
8865 put_string_list (char * const * const argv)
8866 {
8867   PyObject *list;
8868   int argc, i;
8869
8870   for (argc = 0; argv[argc] != NULL; ++argc)
8871     ;
8872
8873   list = PyList_New (argc);
8874   for (i = 0; i < argc; ++i)
8875     PyList_SetItem (list, i, PyString_FromString (argv[i]));
8876
8877   return list;
8878 }
8879
8880 static PyObject *
8881 put_table (char * const * const argv)
8882 {
8883   PyObject *list, *item;
8884   int argc, i;
8885
8886   for (argc = 0; argv[argc] != NULL; ++argc)
8887     ;
8888
8889   list = PyList_New (argc >> 1);
8890   for (i = 0; i < argc; i += 2) {
8891     item = PyTuple_New (2);
8892     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
8893     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
8894     PyList_SetItem (list, i >> 1, item);
8895   }
8896
8897   return list;
8898 }
8899
8900 static void
8901 free_strings (char **argv)
8902 {
8903   int argc;
8904
8905   for (argc = 0; argv[argc] != NULL; ++argc)
8906     free (argv[argc]);
8907   free (argv);
8908 }
8909
8910 static PyObject *
8911 py_guestfs_create (PyObject *self, PyObject *args)
8912 {
8913   guestfs_h *g;
8914
8915   g = guestfs_create ();
8916   if (g == NULL) {
8917     PyErr_SetString (PyExc_RuntimeError,
8918                      \"guestfs.create: failed to allocate handle\");
8919     return NULL;
8920   }
8921   guestfs_set_error_handler (g, NULL, NULL);
8922   return put_handle (g);
8923 }
8924
8925 static PyObject *
8926 py_guestfs_close (PyObject *self, PyObject *args)
8927 {
8928   PyObject *py_g;
8929   guestfs_h *g;
8930
8931   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
8932     return NULL;
8933   g = get_handle (py_g);
8934
8935   guestfs_close (g);
8936
8937   Py_INCREF (Py_None);
8938   return Py_None;
8939 }
8940
8941 ";
8942
8943   let emit_put_list_function typ =
8944     pr "static PyObject *\n";
8945     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
8946     pr "{\n";
8947     pr "  PyObject *list;\n";
8948     pr "  int i;\n";
8949     pr "\n";
8950     pr "  list = PyList_New (%ss->len);\n" typ;
8951     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
8952     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
8953     pr "  return list;\n";
8954     pr "};\n";
8955     pr "\n"
8956   in
8957
8958   (* Structures, turned into Python dictionaries. *)
8959   List.iter (
8960     fun (typ, cols) ->
8961       pr "static PyObject *\n";
8962       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
8963       pr "{\n";
8964       pr "  PyObject *dict;\n";
8965       pr "\n";
8966       pr "  dict = PyDict_New ();\n";
8967       List.iter (
8968         function
8969         | name, FString ->
8970             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8971             pr "                        PyString_FromString (%s->%s));\n"
8972               typ name
8973         | name, FBuffer ->
8974             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8975             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
8976               typ name typ name
8977         | name, FUUID ->
8978             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8979             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
8980               typ name
8981         | name, (FBytes|FUInt64) ->
8982             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8983             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
8984               typ name
8985         | name, FInt64 ->
8986             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8987             pr "                        PyLong_FromLongLong (%s->%s));\n"
8988               typ name
8989         | name, FUInt32 ->
8990             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8991             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
8992               typ name
8993         | name, FInt32 ->
8994             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
8995             pr "                        PyLong_FromLong (%s->%s));\n"
8996               typ name
8997         | name, FOptPercent ->
8998             pr "  if (%s->%s >= 0)\n" typ name;
8999             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
9000             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
9001               typ name;
9002             pr "  else {\n";
9003             pr "    Py_INCREF (Py_None);\n";
9004             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
9005             pr "  }\n"
9006         | name, FChar ->
9007             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9008             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
9009       ) cols;
9010       pr "  return dict;\n";
9011       pr "};\n";
9012       pr "\n";
9013
9014   ) structs;
9015
9016   (* Emit a put_TYPE_list function definition only if that function is used. *)
9017   List.iter (
9018     function
9019     | typ, (RStructListOnly | RStructAndList) ->
9020         (* generate the function for typ *)
9021         emit_put_list_function typ
9022     | typ, _ -> () (* empty *)
9023   ) (rstructs_used_by all_functions);
9024
9025   (* Python wrapper functions. *)
9026   List.iter (
9027     fun (name, style, _, _, _, _, _) ->
9028       pr "static PyObject *\n";
9029       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
9030       pr "{\n";
9031
9032       pr "  PyObject *py_g;\n";
9033       pr "  guestfs_h *g;\n";
9034       pr "  PyObject *py_r;\n";
9035
9036       let error_code =
9037         match fst style with
9038         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9039         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9040         | RConstString _ | RConstOptString _ ->
9041             pr "  const char *r;\n"; "NULL"
9042         | RString _ -> pr "  char *r;\n"; "NULL"
9043         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9044         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9045         | RStructList (_, typ) ->
9046             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9047         | RBufferOut _ ->
9048             pr "  char *r;\n";
9049             pr "  size_t size;\n";
9050             "NULL" in
9051
9052       List.iter (
9053         function
9054         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9055             pr "  const char *%s;\n" n
9056         | OptString n -> pr "  const char *%s;\n" n
9057         | StringList n | DeviceList n ->
9058             pr "  PyObject *py_%s;\n" n;
9059             pr "  char **%s;\n" n
9060         | Bool n -> pr "  int %s;\n" n
9061         | Int n -> pr "  int %s;\n" n
9062         | Int64 n -> pr "  long long %s;\n" n
9063       ) (snd style);
9064
9065       pr "\n";
9066
9067       (* Convert the parameters. *)
9068       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
9069       List.iter (
9070         function
9071         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
9072         | OptString _ -> pr "z"
9073         | StringList _ | DeviceList _ -> pr "O"
9074         | Bool _ -> pr "i" (* XXX Python has booleans? *)
9075         | Int _ -> pr "i"
9076         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
9077                              * emulate C's int/long/long long in Python?
9078                              *)
9079       ) (snd style);
9080       pr ":guestfs_%s\",\n" name;
9081       pr "                         &py_g";
9082       List.iter (
9083         function
9084         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
9085         | OptString n -> pr ", &%s" n
9086         | StringList n | DeviceList n -> pr ", &py_%s" n
9087         | Bool n -> pr ", &%s" n
9088         | Int n -> pr ", &%s" n
9089         | Int64 n -> pr ", &%s" n
9090       ) (snd style);
9091
9092       pr "))\n";
9093       pr "    return NULL;\n";
9094
9095       pr "  g = get_handle (py_g);\n";
9096       List.iter (
9097         function
9098         | Pathname _ | Device _ | Dev_or_Path _ | String _
9099         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9100         | StringList n | DeviceList n ->
9101             pr "  %s = get_string_list (py_%s);\n" n n;
9102             pr "  if (!%s) return NULL;\n" n
9103       ) (snd style);
9104
9105       pr "\n";
9106
9107       pr "  r = guestfs_%s " name;
9108       generate_c_call_args ~handle:"g" style;
9109       pr ";\n";
9110
9111       List.iter (
9112         function
9113         | Pathname _ | Device _ | Dev_or_Path _ | String _
9114         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9115         | StringList n | DeviceList n ->
9116             pr "  free (%s);\n" n
9117       ) (snd style);
9118
9119       pr "  if (r == %s) {\n" error_code;
9120       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
9121       pr "    return NULL;\n";
9122       pr "  }\n";
9123       pr "\n";
9124
9125       (match fst style with
9126        | RErr ->
9127            pr "  Py_INCREF (Py_None);\n";
9128            pr "  py_r = Py_None;\n"
9129        | RInt _
9130        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
9131        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
9132        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
9133        | RConstOptString _ ->
9134            pr "  if (r)\n";
9135            pr "    py_r = PyString_FromString (r);\n";
9136            pr "  else {\n";
9137            pr "    Py_INCREF (Py_None);\n";
9138            pr "    py_r = Py_None;\n";
9139            pr "  }\n"
9140        | RString _ ->
9141            pr "  py_r = PyString_FromString (r);\n";
9142            pr "  free (r);\n"
9143        | RStringList _ ->
9144            pr "  py_r = put_string_list (r);\n";
9145            pr "  free_strings (r);\n"
9146        | RStruct (_, typ) ->
9147            pr "  py_r = put_%s (r);\n" typ;
9148            pr "  guestfs_free_%s (r);\n" typ
9149        | RStructList (_, typ) ->
9150            pr "  py_r = put_%s_list (r);\n" typ;
9151            pr "  guestfs_free_%s_list (r);\n" typ
9152        | RHashtable n ->
9153            pr "  py_r = put_table (r);\n";
9154            pr "  free_strings (r);\n"
9155        | RBufferOut _ ->
9156            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
9157            pr "  free (r);\n"
9158       );
9159
9160       pr "  return py_r;\n";
9161       pr "}\n";
9162       pr "\n"
9163   ) all_functions;
9164
9165   (* Table of functions. *)
9166   pr "static PyMethodDef methods[] = {\n";
9167   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
9168   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
9169   List.iter (
9170     fun (name, _, _, _, _, _, _) ->
9171       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
9172         name name
9173   ) all_functions;
9174   pr "  { NULL, NULL, 0, NULL }\n";
9175   pr "};\n";
9176   pr "\n";
9177
9178   (* Init function. *)
9179   pr "\
9180 void
9181 initlibguestfsmod (void)
9182 {
9183   static int initialized = 0;
9184
9185   if (initialized) return;
9186   Py_InitModule ((char *) \"libguestfsmod\", methods);
9187   initialized = 1;
9188 }
9189 "
9190
9191 (* Generate Python module. *)
9192 and generate_python_py () =
9193   generate_header HashStyle LGPLv2plus;
9194
9195   pr "\
9196 u\"\"\"Python bindings for libguestfs
9197
9198 import guestfs
9199 g = guestfs.GuestFS ()
9200 g.add_drive (\"guest.img\")
9201 g.launch ()
9202 parts = g.list_partitions ()
9203
9204 The guestfs module provides a Python binding to the libguestfs API
9205 for examining and modifying virtual machine disk images.
9206
9207 Amongst the things this is good for: making batch configuration
9208 changes to guests, getting disk used/free statistics (see also:
9209 virt-df), migrating between virtualization systems (see also:
9210 virt-p2v), performing partial backups, performing partial guest
9211 clones, cloning guests and changing registry/UUID/hostname info, and
9212 much else besides.
9213
9214 Libguestfs uses Linux kernel and qemu code, and can access any type of
9215 guest filesystem that Linux and qemu can, including but not limited
9216 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
9217 schemes, qcow, qcow2, vmdk.
9218
9219 Libguestfs provides ways to enumerate guest storage (eg. partitions,
9220 LVs, what filesystem is in each LV, etc.).  It can also run commands
9221 in the context of the guest.  Also you can access filesystems over
9222 FUSE.
9223
9224 Errors which happen while using the API are turned into Python
9225 RuntimeError exceptions.
9226
9227 To create a guestfs handle you usually have to perform the following
9228 sequence of calls:
9229
9230 # Create the handle, call add_drive at least once, and possibly
9231 # several times if the guest has multiple block devices:
9232 g = guestfs.GuestFS ()
9233 g.add_drive (\"guest.img\")
9234
9235 # Launch the qemu subprocess and wait for it to become ready:
9236 g.launch ()
9237
9238 # Now you can issue commands, for example:
9239 logvols = g.lvs ()
9240
9241 \"\"\"
9242
9243 import libguestfsmod
9244
9245 class GuestFS:
9246     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
9247
9248     def __init__ (self):
9249         \"\"\"Create a new libguestfs handle.\"\"\"
9250         self._o = libguestfsmod.create ()
9251
9252     def __del__ (self):
9253         libguestfsmod.close (self._o)
9254
9255 ";
9256
9257   List.iter (
9258     fun (name, style, _, flags, _, _, longdesc) ->
9259       pr "    def %s " name;
9260       generate_py_call_args ~handle:"self" (snd style);
9261       pr ":\n";
9262
9263       if not (List.mem NotInDocs flags) then (
9264         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9265         let doc =
9266           match fst style with
9267           | RErr | RInt _ | RInt64 _ | RBool _
9268           | RConstOptString _ | RConstString _
9269           | RString _ | RBufferOut _ -> doc
9270           | RStringList _ ->
9271               doc ^ "\n\nThis function returns a list of strings."
9272           | RStruct (_, typ) ->
9273               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
9274           | RStructList (_, typ) ->
9275               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
9276           | RHashtable _ ->
9277               doc ^ "\n\nThis function returns a dictionary." in
9278         let doc =
9279           if List.mem ProtocolLimitWarning flags then
9280             doc ^ "\n\n" ^ protocol_limit_warning
9281           else doc in
9282         let doc =
9283           if List.mem DangerWillRobinson flags then
9284             doc ^ "\n\n" ^ danger_will_robinson
9285           else doc in
9286         let doc =
9287           match deprecation_notice flags with
9288           | None -> doc
9289           | Some txt -> doc ^ "\n\n" ^ txt in
9290         let doc = pod2text ~width:60 name doc in
9291         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
9292         let doc = String.concat "\n        " doc in
9293         pr "        u\"\"\"%s\"\"\"\n" doc;
9294       );
9295       pr "        return libguestfsmod.%s " name;
9296       generate_py_call_args ~handle:"self._o" (snd style);
9297       pr "\n";
9298       pr "\n";
9299   ) all_functions
9300
9301 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
9302 and generate_py_call_args ~handle args =
9303   pr "(%s" handle;
9304   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9305   pr ")"
9306
9307 (* Useful if you need the longdesc POD text as plain text.  Returns a
9308  * list of lines.
9309  *
9310  * Because this is very slow (the slowest part of autogeneration),
9311  * we memoize the results.
9312  *)
9313 and pod2text ~width name longdesc =
9314   let key = width, name, longdesc in
9315   try Hashtbl.find pod2text_memo key
9316   with Not_found ->
9317     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
9318     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
9319     close_out chan;
9320     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
9321     let chan = open_process_in cmd in
9322     let lines = ref [] in
9323     let rec loop i =
9324       let line = input_line chan in
9325       if i = 1 then             (* discard the first line of output *)
9326         loop (i+1)
9327       else (
9328         let line = triml line in
9329         lines := line :: !lines;
9330         loop (i+1)
9331       ) in
9332     let lines = try loop 1 with End_of_file -> List.rev !lines in
9333     unlink filename;
9334     (match close_process_in chan with
9335      | WEXITED 0 -> ()
9336      | WEXITED i ->
9337          failwithf "pod2text: process exited with non-zero status (%d)" i
9338      | WSIGNALED i | WSTOPPED i ->
9339          failwithf "pod2text: process signalled or stopped by signal %d" i
9340     );
9341     Hashtbl.add pod2text_memo key lines;
9342     pod2text_memo_updated ();
9343     lines
9344
9345 (* Generate ruby bindings. *)
9346 and generate_ruby_c () =
9347   generate_header CStyle LGPLv2plus;
9348
9349   pr "\
9350 #include <stdio.h>
9351 #include <stdlib.h>
9352
9353 #include <ruby.h>
9354
9355 #include \"guestfs.h\"
9356
9357 #include \"extconf.h\"
9358
9359 /* For Ruby < 1.9 */
9360 #ifndef RARRAY_LEN
9361 #define RARRAY_LEN(r) (RARRAY((r))->len)
9362 #endif
9363
9364 static VALUE m_guestfs;                 /* guestfs module */
9365 static VALUE c_guestfs;                 /* guestfs_h handle */
9366 static VALUE e_Error;                   /* used for all errors */
9367
9368 static void ruby_guestfs_free (void *p)
9369 {
9370   if (!p) return;
9371   guestfs_close ((guestfs_h *) p);
9372 }
9373
9374 static VALUE ruby_guestfs_create (VALUE m)
9375 {
9376   guestfs_h *g;
9377
9378   g = guestfs_create ();
9379   if (!g)
9380     rb_raise (e_Error, \"failed to create guestfs handle\");
9381
9382   /* Don't print error messages to stderr by default. */
9383   guestfs_set_error_handler (g, NULL, NULL);
9384
9385   /* Wrap it, and make sure the close function is called when the
9386    * handle goes away.
9387    */
9388   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9389 }
9390
9391 static VALUE ruby_guestfs_close (VALUE gv)
9392 {
9393   guestfs_h *g;
9394   Data_Get_Struct (gv, guestfs_h, g);
9395
9396   ruby_guestfs_free (g);
9397   DATA_PTR (gv) = NULL;
9398
9399   return Qnil;
9400 }
9401
9402 ";
9403
9404   List.iter (
9405     fun (name, style, _, _, _, _, _) ->
9406       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9407       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9408       pr ")\n";
9409       pr "{\n";
9410       pr "  guestfs_h *g;\n";
9411       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9412       pr "  if (!g)\n";
9413       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9414         name;
9415       pr "\n";
9416
9417       List.iter (
9418         function
9419         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9420             pr "  Check_Type (%sv, T_STRING);\n" n;
9421             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9422             pr "  if (!%s)\n" n;
9423             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9424             pr "              \"%s\", \"%s\");\n" n name
9425         | OptString n ->
9426             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9427         | StringList n | DeviceList n ->
9428             pr "  char **%s;\n" n;
9429             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9430             pr "  {\n";
9431             pr "    int i, len;\n";
9432             pr "    len = RARRAY_LEN (%sv);\n" n;
9433             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9434               n;
9435             pr "    for (i = 0; i < len; ++i) {\n";
9436             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9437             pr "      %s[i] = StringValueCStr (v);\n" n;
9438             pr "    }\n";
9439             pr "    %s[len] = NULL;\n" n;
9440             pr "  }\n";
9441         | Bool n ->
9442             pr "  int %s = RTEST (%sv);\n" n n
9443         | Int n ->
9444             pr "  int %s = NUM2INT (%sv);\n" n n
9445         | Int64 n ->
9446             pr "  long long %s = NUM2LL (%sv);\n" n n
9447       ) (snd style);
9448       pr "\n";
9449
9450       let error_code =
9451         match fst style with
9452         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9453         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9454         | RConstString _ | RConstOptString _ ->
9455             pr "  const char *r;\n"; "NULL"
9456         | RString _ -> pr "  char *r;\n"; "NULL"
9457         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9458         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9459         | RStructList (_, typ) ->
9460             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9461         | RBufferOut _ ->
9462             pr "  char *r;\n";
9463             pr "  size_t size;\n";
9464             "NULL" in
9465       pr "\n";
9466
9467       pr "  r = guestfs_%s " name;
9468       generate_c_call_args ~handle:"g" style;
9469       pr ";\n";
9470
9471       List.iter (
9472         function
9473         | Pathname _ | Device _ | Dev_or_Path _ | String _
9474         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _ -> ()
9475         | StringList n | DeviceList n ->
9476             pr "  free (%s);\n" n
9477       ) (snd style);
9478
9479       pr "  if (r == %s)\n" error_code;
9480       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9481       pr "\n";
9482
9483       (match fst style with
9484        | RErr ->
9485            pr "  return Qnil;\n"
9486        | RInt _ | RBool _ ->
9487            pr "  return INT2NUM (r);\n"
9488        | RInt64 _ ->
9489            pr "  return ULL2NUM (r);\n"
9490        | RConstString _ ->
9491            pr "  return rb_str_new2 (r);\n";
9492        | RConstOptString _ ->
9493            pr "  if (r)\n";
9494            pr "    return rb_str_new2 (r);\n";
9495            pr "  else\n";
9496            pr "    return Qnil;\n";
9497        | RString _ ->
9498            pr "  VALUE rv = rb_str_new2 (r);\n";
9499            pr "  free (r);\n";
9500            pr "  return rv;\n";
9501        | RStringList _ ->
9502            pr "  int i, len = 0;\n";
9503            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9504            pr "  VALUE rv = rb_ary_new2 (len);\n";
9505            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9506            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9507            pr "    free (r[i]);\n";
9508            pr "  }\n";
9509            pr "  free (r);\n";
9510            pr "  return rv;\n"
9511        | RStruct (_, typ) ->
9512            let cols = cols_of_struct typ in
9513            generate_ruby_struct_code typ cols
9514        | RStructList (_, typ) ->
9515            let cols = cols_of_struct typ in
9516            generate_ruby_struct_list_code typ cols
9517        | RHashtable _ ->
9518            pr "  VALUE rv = rb_hash_new ();\n";
9519            pr "  int i;\n";
9520            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9521            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9522            pr "    free (r[i]);\n";
9523            pr "    free (r[i+1]);\n";
9524            pr "  }\n";
9525            pr "  free (r);\n";
9526            pr "  return rv;\n"
9527        | RBufferOut _ ->
9528            pr "  VALUE rv = rb_str_new (r, size);\n";
9529            pr "  free (r);\n";
9530            pr "  return rv;\n";
9531       );
9532
9533       pr "}\n";
9534       pr "\n"
9535   ) all_functions;
9536
9537   pr "\
9538 /* Initialize the module. */
9539 void Init__guestfs ()
9540 {
9541   m_guestfs = rb_define_module (\"Guestfs\");
9542   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9543   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9544
9545   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9546   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9547
9548 ";
9549   (* Define the rest of the methods. *)
9550   List.iter (
9551     fun (name, style, _, _, _, _, _) ->
9552       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9553       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9554   ) all_functions;
9555
9556   pr "}\n"
9557
9558 (* Ruby code to return a struct. *)
9559 and generate_ruby_struct_code typ cols =
9560   pr "  VALUE rv = rb_hash_new ();\n";
9561   List.iter (
9562     function
9563     | name, FString ->
9564         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9565     | name, FBuffer ->
9566         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9567     | name, FUUID ->
9568         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9569     | name, (FBytes|FUInt64) ->
9570         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9571     | name, FInt64 ->
9572         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
9573     | name, FUInt32 ->
9574         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
9575     | name, FInt32 ->
9576         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
9577     | name, FOptPercent ->
9578         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
9579     | name, FChar -> (* XXX wrong? *)
9580         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9581   ) cols;
9582   pr "  guestfs_free_%s (r);\n" typ;
9583   pr "  return rv;\n"
9584
9585 (* Ruby code to return a struct list. *)
9586 and generate_ruby_struct_list_code typ cols =
9587   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
9588   pr "  int i;\n";
9589   pr "  for (i = 0; i < r->len; ++i) {\n";
9590   pr "    VALUE hv = rb_hash_new ();\n";
9591   List.iter (
9592     function
9593     | name, FString ->
9594         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
9595     | name, FBuffer ->
9596         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
9597     | name, FUUID ->
9598         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
9599     | name, (FBytes|FUInt64) ->
9600         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9601     | name, FInt64 ->
9602         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
9603     | name, FUInt32 ->
9604         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
9605     | name, FInt32 ->
9606         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
9607     | name, FOptPercent ->
9608         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
9609     | name, FChar -> (* XXX wrong? *)
9610         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
9611   ) cols;
9612   pr "    rb_ary_push (rv, hv);\n";
9613   pr "  }\n";
9614   pr "  guestfs_free_%s_list (r);\n" typ;
9615   pr "  return rv;\n"
9616
9617 (* Generate Java bindings GuestFS.java file. *)
9618 and generate_java_java () =
9619   generate_header CStyle LGPLv2plus;
9620
9621   pr "\
9622 package com.redhat.et.libguestfs;
9623
9624 import java.util.HashMap;
9625 import com.redhat.et.libguestfs.LibGuestFSException;
9626 import com.redhat.et.libguestfs.PV;
9627 import com.redhat.et.libguestfs.VG;
9628 import com.redhat.et.libguestfs.LV;
9629 import com.redhat.et.libguestfs.Stat;
9630 import com.redhat.et.libguestfs.StatVFS;
9631 import com.redhat.et.libguestfs.IntBool;
9632 import com.redhat.et.libguestfs.Dirent;
9633
9634 /**
9635  * The GuestFS object is a libguestfs handle.
9636  *
9637  * @author rjones
9638  */
9639 public class GuestFS {
9640   // Load the native code.
9641   static {
9642     System.loadLibrary (\"guestfs_jni\");
9643   }
9644
9645   /**
9646    * The native guestfs_h pointer.
9647    */
9648   long g;
9649
9650   /**
9651    * Create a libguestfs handle.
9652    *
9653    * @throws LibGuestFSException
9654    */
9655   public GuestFS () throws LibGuestFSException
9656   {
9657     g = _create ();
9658   }
9659   private native long _create () throws LibGuestFSException;
9660
9661   /**
9662    * Close a libguestfs handle.
9663    *
9664    * You can also leave handles to be collected by the garbage
9665    * collector, but this method ensures that the resources used
9666    * by the handle are freed up immediately.  If you call any
9667    * other methods after closing the handle, you will get an
9668    * exception.
9669    *
9670    * @throws LibGuestFSException
9671    */
9672   public void close () throws LibGuestFSException
9673   {
9674     if (g != 0)
9675       _close (g);
9676     g = 0;
9677   }
9678   private native void _close (long g) throws LibGuestFSException;
9679
9680   public void finalize () throws LibGuestFSException
9681   {
9682     close ();
9683   }
9684
9685 ";
9686
9687   List.iter (
9688     fun (name, style, _, flags, _, shortdesc, longdesc) ->
9689       if not (List.mem NotInDocs flags); then (
9690         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9691         let doc =
9692           if List.mem ProtocolLimitWarning flags then
9693             doc ^ "\n\n" ^ protocol_limit_warning
9694           else doc in
9695         let doc =
9696           if List.mem DangerWillRobinson flags then
9697             doc ^ "\n\n" ^ danger_will_robinson
9698           else doc in
9699         let doc =
9700           match deprecation_notice flags with
9701           | None -> doc
9702           | Some txt -> doc ^ "\n\n" ^ txt in
9703         let doc = pod2text ~width:60 name doc in
9704         let doc = List.map (            (* RHBZ#501883 *)
9705           function
9706           | "" -> "<p>"
9707           | nonempty -> nonempty
9708         ) doc in
9709         let doc = String.concat "\n   * " doc in
9710
9711         pr "  /**\n";
9712         pr "   * %s\n" shortdesc;
9713         pr "   * <p>\n";
9714         pr "   * %s\n" doc;
9715         pr "   * @throws LibGuestFSException\n";
9716         pr "   */\n";
9717         pr "  ";
9718       );
9719       generate_java_prototype ~public:true ~semicolon:false name style;
9720       pr "\n";
9721       pr "  {\n";
9722       pr "    if (g == 0)\n";
9723       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
9724         name;
9725       pr "    ";
9726       if fst style <> RErr then pr "return ";
9727       pr "_%s " name;
9728       generate_java_call_args ~handle:"g" (snd style);
9729       pr ";\n";
9730       pr "  }\n";
9731       pr "  ";
9732       generate_java_prototype ~privat:true ~native:true name style;
9733       pr "\n";
9734       pr "\n";
9735   ) all_functions;
9736
9737   pr "}\n"
9738
9739 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
9740 and generate_java_call_args ~handle args =
9741   pr "(%s" handle;
9742   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9743   pr ")"
9744
9745 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
9746     ?(semicolon=true) name style =
9747   if privat then pr "private ";
9748   if public then pr "public ";
9749   if native then pr "native ";
9750
9751   (* return type *)
9752   (match fst style with
9753    | RErr -> pr "void ";
9754    | RInt _ -> pr "int ";
9755    | RInt64 _ -> pr "long ";
9756    | RBool _ -> pr "boolean ";
9757    | RConstString _ | RConstOptString _ | RString _
9758    | RBufferOut _ -> pr "String ";
9759    | RStringList _ -> pr "String[] ";
9760    | RStruct (_, typ) ->
9761        let name = java_name_of_struct typ in
9762        pr "%s " name;
9763    | RStructList (_, typ) ->
9764        let name = java_name_of_struct typ in
9765        pr "%s[] " name;
9766    | RHashtable _ -> pr "HashMap<String,String> ";
9767   );
9768
9769   if native then pr "_%s " name else pr "%s " name;
9770   pr "(";
9771   let needs_comma = ref false in
9772   if native then (
9773     pr "long g";
9774     needs_comma := true
9775   );
9776
9777   (* args *)
9778   List.iter (
9779     fun arg ->
9780       if !needs_comma then pr ", ";
9781       needs_comma := true;
9782
9783       match arg with
9784       | Pathname n
9785       | Device n | Dev_or_Path n
9786       | String n
9787       | OptString n
9788       | FileIn n
9789       | FileOut n ->
9790           pr "String %s" n
9791       | StringList n | DeviceList n ->
9792           pr "String[] %s" n
9793       | Bool n ->
9794           pr "boolean %s" n
9795       | Int n ->
9796           pr "int %s" n
9797       | Int64 n ->
9798           pr "long %s" n
9799   ) (snd style);
9800
9801   pr ")\n";
9802   pr "    throws LibGuestFSException";
9803   if semicolon then pr ";"
9804
9805 and generate_java_struct jtyp cols () =
9806   generate_header CStyle LGPLv2plus;
9807
9808   pr "\
9809 package com.redhat.et.libguestfs;
9810
9811 /**
9812  * Libguestfs %s structure.
9813  *
9814  * @author rjones
9815  * @see GuestFS
9816  */
9817 public class %s {
9818 " jtyp jtyp;
9819
9820   List.iter (
9821     function
9822     | name, FString
9823     | name, FUUID
9824     | name, FBuffer -> pr "  public String %s;\n" name
9825     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
9826     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
9827     | name, FChar -> pr "  public char %s;\n" name
9828     | name, FOptPercent ->
9829         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
9830         pr "  public float %s;\n" name
9831   ) cols;
9832
9833   pr "}\n"
9834
9835 and generate_java_c () =
9836   generate_header CStyle LGPLv2plus;
9837
9838   pr "\
9839 #include <stdio.h>
9840 #include <stdlib.h>
9841 #include <string.h>
9842
9843 #include \"com_redhat_et_libguestfs_GuestFS.h\"
9844 #include \"guestfs.h\"
9845
9846 /* Note that this function returns.  The exception is not thrown
9847  * until after the wrapper function returns.
9848  */
9849 static void
9850 throw_exception (JNIEnv *env, const char *msg)
9851 {
9852   jclass cl;
9853   cl = (*env)->FindClass (env,
9854                           \"com/redhat/et/libguestfs/LibGuestFSException\");
9855   (*env)->ThrowNew (env, cl, msg);
9856 }
9857
9858 JNIEXPORT jlong JNICALL
9859 Java_com_redhat_et_libguestfs_GuestFS__1create
9860   (JNIEnv *env, jobject obj)
9861 {
9862   guestfs_h *g;
9863
9864   g = guestfs_create ();
9865   if (g == NULL) {
9866     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
9867     return 0;
9868   }
9869   guestfs_set_error_handler (g, NULL, NULL);
9870   return (jlong) (long) g;
9871 }
9872
9873 JNIEXPORT void JNICALL
9874 Java_com_redhat_et_libguestfs_GuestFS__1close
9875   (JNIEnv *env, jobject obj, jlong jg)
9876 {
9877   guestfs_h *g = (guestfs_h *) (long) jg;
9878   guestfs_close (g);
9879 }
9880
9881 ";
9882
9883   List.iter (
9884     fun (name, style, _, _, _, _, _) ->
9885       pr "JNIEXPORT ";
9886       (match fst style with
9887        | RErr -> pr "void ";
9888        | RInt _ -> pr "jint ";
9889        | RInt64 _ -> pr "jlong ";
9890        | RBool _ -> pr "jboolean ";
9891        | RConstString _ | RConstOptString _ | RString _
9892        | RBufferOut _ -> pr "jstring ";
9893        | RStruct _ | RHashtable _ ->
9894            pr "jobject ";
9895        | RStringList _ | RStructList _ ->
9896            pr "jobjectArray ";
9897       );
9898       pr "JNICALL\n";
9899       pr "Java_com_redhat_et_libguestfs_GuestFS_";
9900       pr "%s" (replace_str ("_" ^ name) "_" "_1");
9901       pr "\n";
9902       pr "  (JNIEnv *env, jobject obj, jlong jg";
9903       List.iter (
9904         function
9905         | Pathname n
9906         | Device n | Dev_or_Path n
9907         | String n
9908         | OptString n
9909         | FileIn n
9910         | FileOut n ->
9911             pr ", jstring j%s" n
9912         | StringList n | DeviceList n ->
9913             pr ", jobjectArray j%s" n
9914         | Bool n ->
9915             pr ", jboolean j%s" n
9916         | Int n ->
9917             pr ", jint j%s" n
9918         | Int64 n ->
9919             pr ", jlong j%s" n
9920       ) (snd style);
9921       pr ")\n";
9922       pr "{\n";
9923       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
9924       let error_code, no_ret =
9925         match fst style with
9926         | RErr -> pr "  int r;\n"; "-1", ""
9927         | RBool _
9928         | RInt _ -> pr "  int r;\n"; "-1", "0"
9929         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
9930         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9931         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
9932         | RString _ ->
9933             pr "  jstring jr;\n";
9934             pr "  char *r;\n"; "NULL", "NULL"
9935         | RStringList _ ->
9936             pr "  jobjectArray jr;\n";
9937             pr "  int r_len;\n";
9938             pr "  jclass cl;\n";
9939             pr "  jstring jstr;\n";
9940             pr "  char **r;\n"; "NULL", "NULL"
9941         | RStruct (_, typ) ->
9942             pr "  jobject jr;\n";
9943             pr "  jclass cl;\n";
9944             pr "  jfieldID fl;\n";
9945             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
9946         | RStructList (_, typ) ->
9947             pr "  jobjectArray jr;\n";
9948             pr "  jclass cl;\n";
9949             pr "  jfieldID fl;\n";
9950             pr "  jobject jfl;\n";
9951             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
9952         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
9953         | RBufferOut _ ->
9954             pr "  jstring jr;\n";
9955             pr "  char *r;\n";
9956             pr "  size_t size;\n";
9957             "NULL", "NULL" in
9958       List.iter (
9959         function
9960         | Pathname n
9961         | Device n | Dev_or_Path n
9962         | String n
9963         | OptString n
9964         | FileIn n
9965         | FileOut n ->
9966             pr "  const char *%s;\n" n
9967         | StringList n | DeviceList n ->
9968             pr "  int %s_len;\n" n;
9969             pr "  const char **%s;\n" n
9970         | Bool n
9971         | Int n ->
9972             pr "  int %s;\n" n
9973         | Int64 n ->
9974             pr "  int64_t %s;\n" n
9975       ) (snd style);
9976
9977       let needs_i =
9978         (match fst style with
9979          | RStringList _ | RStructList _ -> true
9980          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
9981          | RConstOptString _
9982          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
9983           List.exists (function
9984                        | StringList _ -> true
9985                        | DeviceList _ -> true
9986                        | _ -> false) (snd style) in
9987       if needs_i then
9988         pr "  int i;\n";
9989
9990       pr "\n";
9991
9992       (* Get the parameters. *)
9993       List.iter (
9994         function
9995         | Pathname n
9996         | Device n | Dev_or_Path n
9997         | String n
9998         | FileIn n
9999         | FileOut n ->
10000             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
10001         | OptString n ->
10002             (* This is completely undocumented, but Java null becomes
10003              * a NULL parameter.
10004              *)
10005             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
10006         | StringList n | DeviceList n ->
10007             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
10008             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
10009             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10010             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10011               n;
10012             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
10013             pr "  }\n";
10014             pr "  %s[%s_len] = NULL;\n" n n;
10015         | Bool n
10016         | Int n
10017         | Int64 n ->
10018             pr "  %s = j%s;\n" n n
10019       ) (snd style);
10020
10021       (* Make the call. *)
10022       pr "  r = guestfs_%s " name;
10023       generate_c_call_args ~handle:"g" style;
10024       pr ";\n";
10025
10026       (* Release the parameters. *)
10027       List.iter (
10028         function
10029         | Pathname n
10030         | Device n | Dev_or_Path n
10031         | String n
10032         | FileIn n
10033         | FileOut n ->
10034             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10035         | OptString n ->
10036             pr "  if (j%s)\n" n;
10037             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10038         | StringList n | DeviceList n ->
10039             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10040             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10041               n;
10042             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
10043             pr "  }\n";
10044             pr "  free (%s);\n" n
10045         | Bool n
10046         | Int n
10047         | Int64 n -> ()
10048       ) (snd style);
10049
10050       (* Check for errors. *)
10051       pr "  if (r == %s) {\n" error_code;
10052       pr "    throw_exception (env, guestfs_last_error (g));\n";
10053       pr "    return %s;\n" no_ret;
10054       pr "  }\n";
10055
10056       (* Return value. *)
10057       (match fst style with
10058        | RErr -> ()
10059        | RInt _ -> pr "  return (jint) r;\n"
10060        | RBool _ -> pr "  return (jboolean) r;\n"
10061        | RInt64 _ -> pr "  return (jlong) r;\n"
10062        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
10063        | RConstOptString _ ->
10064            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
10065        | RString _ ->
10066            pr "  jr = (*env)->NewStringUTF (env, r);\n";
10067            pr "  free (r);\n";
10068            pr "  return jr;\n"
10069        | RStringList _ ->
10070            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
10071            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
10072            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
10073            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
10074            pr "  for (i = 0; i < r_len; ++i) {\n";
10075            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
10076            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
10077            pr "    free (r[i]);\n";
10078            pr "  }\n";
10079            pr "  free (r);\n";
10080            pr "  return jr;\n"
10081        | RStruct (_, typ) ->
10082            let jtyp = java_name_of_struct typ in
10083            let cols = cols_of_struct typ in
10084            generate_java_struct_return typ jtyp cols
10085        | RStructList (_, typ) ->
10086            let jtyp = java_name_of_struct typ in
10087            let cols = cols_of_struct typ in
10088            generate_java_struct_list_return typ jtyp cols
10089        | RHashtable _ ->
10090            (* XXX *)
10091            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
10092            pr "  return NULL;\n"
10093        | RBufferOut _ ->
10094            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
10095            pr "  free (r);\n";
10096            pr "  return jr;\n"
10097       );
10098
10099       pr "}\n";
10100       pr "\n"
10101   ) all_functions
10102
10103 and generate_java_struct_return typ jtyp cols =
10104   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10105   pr "  jr = (*env)->AllocObject (env, cl);\n";
10106   List.iter (
10107     function
10108     | name, FString ->
10109         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10110         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
10111     | name, FUUID ->
10112         pr "  {\n";
10113         pr "    char s[33];\n";
10114         pr "    memcpy (s, r->%s, 32);\n" name;
10115         pr "    s[32] = 0;\n";
10116         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10117         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10118         pr "  }\n";
10119     | name, FBuffer ->
10120         pr "  {\n";
10121         pr "    int len = r->%s_len;\n" name;
10122         pr "    char s[len+1];\n";
10123         pr "    memcpy (s, r->%s, len);\n" name;
10124         pr "    s[len] = 0;\n";
10125         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10126         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10127         pr "  }\n";
10128     | name, (FBytes|FUInt64|FInt64) ->
10129         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10130         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10131     | name, (FUInt32|FInt32) ->
10132         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10133         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10134     | name, FOptPercent ->
10135         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10136         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
10137     | name, FChar ->
10138         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10139         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10140   ) cols;
10141   pr "  free (r);\n";
10142   pr "  return jr;\n"
10143
10144 and generate_java_struct_list_return typ jtyp cols =
10145   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10146   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
10147   pr "  for (i = 0; i < r->len; ++i) {\n";
10148   pr "    jfl = (*env)->AllocObject (env, cl);\n";
10149   List.iter (
10150     function
10151     | name, FString ->
10152         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10153         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
10154     | name, FUUID ->
10155         pr "    {\n";
10156         pr "      char s[33];\n";
10157         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
10158         pr "      s[32] = 0;\n";
10159         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10160         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10161         pr "    }\n";
10162     | name, FBuffer ->
10163         pr "    {\n";
10164         pr "      int len = r->val[i].%s_len;\n" name;
10165         pr "      char s[len+1];\n";
10166         pr "      memcpy (s, r->val[i].%s, len);\n" name;
10167         pr "      s[len] = 0;\n";
10168         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10169         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10170         pr "    }\n";
10171     | name, (FBytes|FUInt64|FInt64) ->
10172         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10173         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10174     | name, (FUInt32|FInt32) ->
10175         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10176         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10177     | name, FOptPercent ->
10178         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10179         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
10180     | name, FChar ->
10181         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10182         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10183   ) cols;
10184   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
10185   pr "  }\n";
10186   pr "  guestfs_free_%s_list (r);\n" typ;
10187   pr "  return jr;\n"
10188
10189 and generate_java_makefile_inc () =
10190   generate_header HashStyle GPLv2plus;
10191
10192   pr "java_built_sources = \\\n";
10193   List.iter (
10194     fun (typ, jtyp) ->
10195         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
10196   ) java_structs;
10197   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
10198
10199 and generate_haskell_hs () =
10200   generate_header HaskellStyle LGPLv2plus;
10201
10202   (* XXX We only know how to generate partial FFI for Haskell
10203    * at the moment.  Please help out!
10204    *)
10205   let can_generate style =
10206     match style with
10207     | RErr, _
10208     | RInt _, _
10209     | RInt64 _, _ -> true
10210     | RBool _, _
10211     | RConstString _, _
10212     | RConstOptString _, _
10213     | RString _, _
10214     | RStringList _, _
10215     | RStruct _, _
10216     | RStructList _, _
10217     | RHashtable _, _
10218     | RBufferOut _, _ -> false in
10219
10220   pr "\
10221 {-# INCLUDE <guestfs.h> #-}
10222 {-# LANGUAGE ForeignFunctionInterface #-}
10223
10224 module Guestfs (
10225   create";
10226
10227   (* List out the names of the actions we want to export. *)
10228   List.iter (
10229     fun (name, style, _, _, _, _, _) ->
10230       if can_generate style then pr ",\n  %s" name
10231   ) all_functions;
10232
10233   pr "
10234   ) where
10235
10236 -- Unfortunately some symbols duplicate ones already present
10237 -- in Prelude.  We don't know which, so we hard-code a list
10238 -- here.
10239 import Prelude hiding (truncate)
10240
10241 import Foreign
10242 import Foreign.C
10243 import Foreign.C.Types
10244 import IO
10245 import Control.Exception
10246 import Data.Typeable
10247
10248 data GuestfsS = GuestfsS            -- represents the opaque C struct
10249 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
10250 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
10251
10252 -- XXX define properly later XXX
10253 data PV = PV
10254 data VG = VG
10255 data LV = LV
10256 data IntBool = IntBool
10257 data Stat = Stat
10258 data StatVFS = StatVFS
10259 data Hashtable = Hashtable
10260
10261 foreign import ccall unsafe \"guestfs_create\" c_create
10262   :: IO GuestfsP
10263 foreign import ccall unsafe \"&guestfs_close\" c_close
10264   :: FunPtr (GuestfsP -> IO ())
10265 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
10266   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
10267
10268 create :: IO GuestfsH
10269 create = do
10270   p <- c_create
10271   c_set_error_handler p nullPtr nullPtr
10272   h <- newForeignPtr c_close p
10273   return h
10274
10275 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
10276   :: GuestfsP -> IO CString
10277
10278 -- last_error :: GuestfsH -> IO (Maybe String)
10279 -- last_error h = do
10280 --   str <- withForeignPtr h (\\p -> c_last_error p)
10281 --   maybePeek peekCString str
10282
10283 last_error :: GuestfsH -> IO (String)
10284 last_error h = do
10285   str <- withForeignPtr h (\\p -> c_last_error p)
10286   if (str == nullPtr)
10287     then return \"no error\"
10288     else peekCString str
10289
10290 ";
10291
10292   (* Generate wrappers for each foreign function. *)
10293   List.iter (
10294     fun (name, style, _, _, _, _, _) ->
10295       if can_generate style then (
10296         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
10297         pr "  :: ";
10298         generate_haskell_prototype ~handle:"GuestfsP" style;
10299         pr "\n";
10300         pr "\n";
10301         pr "%s :: " name;
10302         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
10303         pr "\n";
10304         pr "%s %s = do\n" name
10305           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
10306         pr "  r <- ";
10307         (* Convert pointer arguments using with* functions. *)
10308         List.iter (
10309           function
10310           | FileIn n
10311           | FileOut n
10312           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
10313           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
10314           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
10315           | Bool _ | Int _ | Int64 _ -> ()
10316         ) (snd style);
10317         (* Convert integer arguments. *)
10318         let args =
10319           List.map (
10320             function
10321             | Bool n -> sprintf "(fromBool %s)" n
10322             | Int n -> sprintf "(fromIntegral %s)" n
10323             | Int64 n -> sprintf "(fromIntegral %s)" n
10324             | FileIn n | FileOut n
10325             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
10326           ) (snd style) in
10327         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
10328           (String.concat " " ("p" :: args));
10329         (match fst style with
10330          | RErr | RInt _ | RInt64 _ | RBool _ ->
10331              pr "  if (r == -1)\n";
10332              pr "    then do\n";
10333              pr "      err <- last_error h\n";
10334              pr "      fail err\n";
10335          | RConstString _ | RConstOptString _ | RString _
10336          | RStringList _ | RStruct _
10337          | RStructList _ | RHashtable _ | RBufferOut _ ->
10338              pr "  if (r == nullPtr)\n";
10339              pr "    then do\n";
10340              pr "      err <- last_error h\n";
10341              pr "      fail err\n";
10342         );
10343         (match fst style with
10344          | RErr ->
10345              pr "    else return ()\n"
10346          | RInt _ ->
10347              pr "    else return (fromIntegral r)\n"
10348          | RInt64 _ ->
10349              pr "    else return (fromIntegral r)\n"
10350          | RBool _ ->
10351              pr "    else return (toBool r)\n"
10352          | RConstString _
10353          | RConstOptString _
10354          | RString _
10355          | RStringList _
10356          | RStruct _
10357          | RStructList _
10358          | RHashtable _
10359          | RBufferOut _ ->
10360              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10361         );
10362         pr "\n";
10363       )
10364   ) all_functions
10365
10366 and generate_haskell_prototype ~handle ?(hs = false) style =
10367   pr "%s -> " handle;
10368   let string = if hs then "String" else "CString" in
10369   let int = if hs then "Int" else "CInt" in
10370   let bool = if hs then "Bool" else "CInt" in
10371   let int64 = if hs then "Integer" else "Int64" in
10372   List.iter (
10373     fun arg ->
10374       (match arg with
10375        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10376        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10377        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10378        | Bool _ -> pr "%s" bool
10379        | Int _ -> pr "%s" int
10380        | Int64 _ -> pr "%s" int
10381        | FileIn _ -> pr "%s" string
10382        | FileOut _ -> pr "%s" string
10383       );
10384       pr " -> ";
10385   ) (snd style);
10386   pr "IO (";
10387   (match fst style with
10388    | RErr -> if not hs then pr "CInt"
10389    | RInt _ -> pr "%s" int
10390    | RInt64 _ -> pr "%s" int64
10391    | RBool _ -> pr "%s" bool
10392    | RConstString _ -> pr "%s" string
10393    | RConstOptString _ -> pr "Maybe %s" string
10394    | RString _ -> pr "%s" string
10395    | RStringList _ -> pr "[%s]" string
10396    | RStruct (_, typ) ->
10397        let name = java_name_of_struct typ in
10398        pr "%s" name
10399    | RStructList (_, typ) ->
10400        let name = java_name_of_struct typ in
10401        pr "[%s]" name
10402    | RHashtable _ -> pr "Hashtable"
10403    | RBufferOut _ -> pr "%s" string
10404   );
10405   pr ")"
10406
10407 and generate_csharp () =
10408   generate_header CPlusPlusStyle LGPLv2plus;
10409
10410   (* XXX Make this configurable by the C# assembly users. *)
10411   let library = "libguestfs.so.0" in
10412
10413   pr "\
10414 // These C# bindings are highly experimental at present.
10415 //
10416 // Firstly they only work on Linux (ie. Mono).  In order to get them
10417 // to work on Windows (ie. .Net) you would need to port the library
10418 // itself to Windows first.
10419 //
10420 // The second issue is that some calls are known to be incorrect and
10421 // can cause Mono to segfault.  Particularly: calls which pass or
10422 // return string[], or return any structure value.  This is because
10423 // we haven't worked out the correct way to do this from C#.
10424 //
10425 // The third issue is that when compiling you get a lot of warnings.
10426 // We are not sure whether the warnings are important or not.
10427 //
10428 // Fourthly we do not routinely build or test these bindings as part
10429 // of the make && make check cycle, which means that regressions might
10430 // go unnoticed.
10431 //
10432 // Suggestions and patches are welcome.
10433
10434 // To compile:
10435 //
10436 // gmcs Libguestfs.cs
10437 // mono Libguestfs.exe
10438 //
10439 // (You'll probably want to add a Test class / static main function
10440 // otherwise this won't do anything useful).
10441
10442 using System;
10443 using System.IO;
10444 using System.Runtime.InteropServices;
10445 using System.Runtime.Serialization;
10446 using System.Collections;
10447
10448 namespace Guestfs
10449 {
10450   class Error : System.ApplicationException
10451   {
10452     public Error (string message) : base (message) {}
10453     protected Error (SerializationInfo info, StreamingContext context) {}
10454   }
10455
10456   class Guestfs
10457   {
10458     IntPtr _handle;
10459
10460     [DllImport (\"%s\")]
10461     static extern IntPtr guestfs_create ();
10462
10463     public Guestfs ()
10464     {
10465       _handle = guestfs_create ();
10466       if (_handle == IntPtr.Zero)
10467         throw new Error (\"could not create guestfs handle\");
10468     }
10469
10470     [DllImport (\"%s\")]
10471     static extern void guestfs_close (IntPtr h);
10472
10473     ~Guestfs ()
10474     {
10475       guestfs_close (_handle);
10476     }
10477
10478     [DllImport (\"%s\")]
10479     static extern string guestfs_last_error (IntPtr h);
10480
10481 " library library library;
10482
10483   (* Generate C# structure bindings.  We prefix struct names with
10484    * underscore because C# cannot have conflicting struct names and
10485    * method names (eg. "class stat" and "stat").
10486    *)
10487   List.iter (
10488     fun (typ, cols) ->
10489       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10490       pr "    public class _%s {\n" typ;
10491       List.iter (
10492         function
10493         | name, FChar -> pr "      char %s;\n" name
10494         | name, FString -> pr "      string %s;\n" name
10495         | name, FBuffer ->
10496             pr "      uint %s_len;\n" name;
10497             pr "      string %s;\n" name
10498         | name, FUUID ->
10499             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10500             pr "      string %s;\n" name
10501         | name, FUInt32 -> pr "      uint %s;\n" name
10502         | name, FInt32 -> pr "      int %s;\n" name
10503         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10504         | name, FInt64 -> pr "      long %s;\n" name
10505         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10506       ) cols;
10507       pr "    }\n";
10508       pr "\n"
10509   ) structs;
10510
10511   (* Generate C# function bindings. *)
10512   List.iter (
10513     fun (name, style, _, _, _, shortdesc, _) ->
10514       let rec csharp_return_type () =
10515         match fst style with
10516         | RErr -> "void"
10517         | RBool n -> "bool"
10518         | RInt n -> "int"
10519         | RInt64 n -> "long"
10520         | RConstString n
10521         | RConstOptString n
10522         | RString n
10523         | RBufferOut n -> "string"
10524         | RStruct (_,n) -> "_" ^ n
10525         | RHashtable n -> "Hashtable"
10526         | RStringList n -> "string[]"
10527         | RStructList (_,n) -> sprintf "_%s[]" n
10528
10529       and c_return_type () =
10530         match fst style with
10531         | RErr
10532         | RBool _
10533         | RInt _ -> "int"
10534         | RInt64 _ -> "long"
10535         | RConstString _
10536         | RConstOptString _
10537         | RString _
10538         | RBufferOut _ -> "string"
10539         | RStruct (_,n) -> "_" ^ n
10540         | RHashtable _
10541         | RStringList _ -> "string[]"
10542         | RStructList (_,n) -> sprintf "_%s[]" n
10543
10544       and c_error_comparison () =
10545         match fst style with
10546         | RErr
10547         | RBool _
10548         | RInt _
10549         | RInt64 _ -> "== -1"
10550         | RConstString _
10551         | RConstOptString _
10552         | RString _
10553         | RBufferOut _
10554         | RStruct (_,_)
10555         | RHashtable _
10556         | RStringList _
10557         | RStructList (_,_) -> "== null"
10558
10559       and generate_extern_prototype () =
10560         pr "    static extern %s guestfs_%s (IntPtr h"
10561           (c_return_type ()) name;
10562         List.iter (
10563           function
10564           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10565           | FileIn n | FileOut n ->
10566               pr ", [In] string %s" n
10567           | StringList n | DeviceList n ->
10568               pr ", [In] string[] %s" n
10569           | Bool n ->
10570               pr ", bool %s" n
10571           | Int n ->
10572               pr ", int %s" n
10573           | Int64 n ->
10574               pr ", long %s" n
10575         ) (snd style);
10576         pr ");\n"
10577
10578       and generate_public_prototype () =
10579         pr "    public %s %s (" (csharp_return_type ()) name;
10580         let comma = ref false in
10581         let next () =
10582           if !comma then pr ", ";
10583           comma := true
10584         in
10585         List.iter (
10586           function
10587           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
10588           | FileIn n | FileOut n ->
10589               next (); pr "string %s" n
10590           | StringList n | DeviceList n ->
10591               next (); pr "string[] %s" n
10592           | Bool n ->
10593               next (); pr "bool %s" n
10594           | Int n ->
10595               next (); pr "int %s" n
10596           | Int64 n ->
10597               next (); pr "long %s" n
10598         ) (snd style);
10599         pr ")\n"
10600
10601       and generate_call () =
10602         pr "guestfs_%s (_handle" name;
10603         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
10604         pr ");\n";
10605       in
10606
10607       pr "    [DllImport (\"%s\")]\n" library;
10608       generate_extern_prototype ();
10609       pr "\n";
10610       pr "    /// <summary>\n";
10611       pr "    /// %s\n" shortdesc;
10612       pr "    /// </summary>\n";
10613       generate_public_prototype ();
10614       pr "    {\n";
10615       pr "      %s r;\n" (c_return_type ());
10616       pr "      r = ";
10617       generate_call ();
10618       pr "      if (r %s)\n" (c_error_comparison ());
10619       pr "        throw new Error (guestfs_last_error (_handle));\n";
10620       (match fst style with
10621        | RErr -> ()
10622        | RBool _ ->
10623            pr "      return r != 0 ? true : false;\n"
10624        | RHashtable _ ->
10625            pr "      Hashtable rr = new Hashtable ();\n";
10626            pr "      for (int i = 0; i < r.Length; i += 2)\n";
10627            pr "        rr.Add (r[i], r[i+1]);\n";
10628            pr "      return rr;\n"
10629        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
10630        | RString _ | RBufferOut _ | RStruct _ | RStringList _
10631        | RStructList _ ->
10632            pr "      return r;\n"
10633       );
10634       pr "    }\n";
10635       pr "\n";
10636   ) all_functions_sorted;
10637
10638   pr "  }
10639 }
10640 "
10641
10642 and generate_bindtests () =
10643   generate_header CStyle LGPLv2plus;
10644
10645   pr "\
10646 #include <stdio.h>
10647 #include <stdlib.h>
10648 #include <inttypes.h>
10649 #include <string.h>
10650
10651 #include \"guestfs.h\"
10652 #include \"guestfs-internal.h\"
10653 #include \"guestfs-internal-actions.h\"
10654 #include \"guestfs_protocol.h\"
10655
10656 #define error guestfs_error
10657 #define safe_calloc guestfs_safe_calloc
10658 #define safe_malloc guestfs_safe_malloc
10659
10660 static void
10661 print_strings (char *const *argv)
10662 {
10663   int argc;
10664
10665   printf (\"[\");
10666   for (argc = 0; argv[argc] != NULL; ++argc) {
10667     if (argc > 0) printf (\", \");
10668     printf (\"\\\"%%s\\\"\", argv[argc]);
10669   }
10670   printf (\"]\\n\");
10671 }
10672
10673 /* The test0 function prints its parameters to stdout. */
10674 ";
10675
10676   let test0, tests =
10677     match test_functions with
10678     | [] -> assert false
10679     | test0 :: tests -> test0, tests in
10680
10681   let () =
10682     let (name, style, _, _, _, _, _) = test0 in
10683     generate_prototype ~extern:false ~semicolon:false ~newline:true
10684       ~handle:"g" ~prefix:"guestfs__" name style;
10685     pr "{\n";
10686     List.iter (
10687       function
10688       | Pathname n
10689       | Device n | Dev_or_Path n
10690       | String n
10691       | FileIn n
10692       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
10693       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
10694       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
10695       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
10696       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
10697       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
10698     ) (snd style);
10699     pr "  /* Java changes stdout line buffering so we need this: */\n";
10700     pr "  fflush (stdout);\n";
10701     pr "  return 0;\n";
10702     pr "}\n";
10703     pr "\n" in
10704
10705   List.iter (
10706     fun (name, style, _, _, _, _, _) ->
10707       if String.sub name (String.length name - 3) 3 <> "err" then (
10708         pr "/* Test normal return. */\n";
10709         generate_prototype ~extern:false ~semicolon:false ~newline:true
10710           ~handle:"g" ~prefix:"guestfs__" name style;
10711         pr "{\n";
10712         (match fst style with
10713          | RErr ->
10714              pr "  return 0;\n"
10715          | RInt _ ->
10716              pr "  int r;\n";
10717              pr "  sscanf (val, \"%%d\", &r);\n";
10718              pr "  return r;\n"
10719          | RInt64 _ ->
10720              pr "  int64_t r;\n";
10721              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
10722              pr "  return r;\n"
10723          | RBool _ ->
10724              pr "  return STREQ (val, \"true\");\n"
10725          | RConstString _
10726          | RConstOptString _ ->
10727              (* Can't return the input string here.  Return a static
10728               * string so we ensure we get a segfault if the caller
10729               * tries to free it.
10730               *)
10731              pr "  return \"static string\";\n"
10732          | RString _ ->
10733              pr "  return strdup (val);\n"
10734          | RStringList _ ->
10735              pr "  char **strs;\n";
10736              pr "  int n, i;\n";
10737              pr "  sscanf (val, \"%%d\", &n);\n";
10738              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
10739              pr "  for (i = 0; i < n; ++i) {\n";
10740              pr "    strs[i] = safe_malloc (g, 16);\n";
10741              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
10742              pr "  }\n";
10743              pr "  strs[n] = NULL;\n";
10744              pr "  return strs;\n"
10745          | RStruct (_, typ) ->
10746              pr "  struct guestfs_%s *r;\n" typ;
10747              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10748              pr "  return r;\n"
10749          | RStructList (_, typ) ->
10750              pr "  struct guestfs_%s_list *r;\n" typ;
10751              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
10752              pr "  sscanf (val, \"%%d\", &r->len);\n";
10753              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
10754              pr "  return r;\n"
10755          | RHashtable _ ->
10756              pr "  char **strs;\n";
10757              pr "  int n, i;\n";
10758              pr "  sscanf (val, \"%%d\", &n);\n";
10759              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
10760              pr "  for (i = 0; i < n; ++i) {\n";
10761              pr "    strs[i*2] = safe_malloc (g, 16);\n";
10762              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
10763              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
10764              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
10765              pr "  }\n";
10766              pr "  strs[n*2] = NULL;\n";
10767              pr "  return strs;\n"
10768          | RBufferOut _ ->
10769              pr "  return strdup (val);\n"
10770         );
10771         pr "}\n";
10772         pr "\n"
10773       ) else (
10774         pr "/* Test error return. */\n";
10775         generate_prototype ~extern:false ~semicolon:false ~newline:true
10776           ~handle:"g" ~prefix:"guestfs__" name style;
10777         pr "{\n";
10778         pr "  error (g, \"error\");\n";
10779         (match fst style with
10780          | RErr | RInt _ | RInt64 _ | RBool _ ->
10781              pr "  return -1;\n"
10782          | RConstString _ | RConstOptString _
10783          | RString _ | RStringList _ | RStruct _
10784          | RStructList _
10785          | RHashtable _
10786          | RBufferOut _ ->
10787              pr "  return NULL;\n"
10788         );
10789         pr "}\n";
10790         pr "\n"
10791       )
10792   ) tests
10793
10794 and generate_ocaml_bindtests () =
10795   generate_header OCamlStyle GPLv2plus;
10796
10797   pr "\
10798 let () =
10799   let g = Guestfs.create () in
10800 ";
10801
10802   let mkargs args =
10803     String.concat " " (
10804       List.map (
10805         function
10806         | CallString s -> "\"" ^ s ^ "\""
10807         | CallOptString None -> "None"
10808         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
10809         | CallStringList xs ->
10810             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
10811         | CallInt i when i >= 0 -> string_of_int i
10812         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
10813         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
10814         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
10815         | CallBool b -> string_of_bool b
10816       ) args
10817     )
10818   in
10819
10820   generate_lang_bindtests (
10821     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
10822   );
10823
10824   pr "print_endline \"EOF\"\n"
10825
10826 and generate_perl_bindtests () =
10827   pr "#!/usr/bin/perl -w\n";
10828   generate_header HashStyle GPLv2plus;
10829
10830   pr "\
10831 use strict;
10832
10833 use Sys::Guestfs;
10834
10835 my $g = Sys::Guestfs->new ();
10836 ";
10837
10838   let mkargs args =
10839     String.concat ", " (
10840       List.map (
10841         function
10842         | CallString s -> "\"" ^ s ^ "\""
10843         | CallOptString None -> "undef"
10844         | CallOptString (Some s) -> sprintf "\"%s\"" s
10845         | CallStringList xs ->
10846             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10847         | CallInt i -> string_of_int i
10848         | CallInt64 i -> Int64.to_string i
10849         | CallBool b -> if b then "1" else "0"
10850       ) args
10851     )
10852   in
10853
10854   generate_lang_bindtests (
10855     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
10856   );
10857
10858   pr "print \"EOF\\n\"\n"
10859
10860 and generate_python_bindtests () =
10861   generate_header HashStyle GPLv2plus;
10862
10863   pr "\
10864 import guestfs
10865
10866 g = guestfs.GuestFS ()
10867 ";
10868
10869   let mkargs args =
10870     String.concat ", " (
10871       List.map (
10872         function
10873         | CallString s -> "\"" ^ s ^ "\""
10874         | CallOptString None -> "None"
10875         | CallOptString (Some s) -> sprintf "\"%s\"" s
10876         | CallStringList xs ->
10877             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10878         | CallInt i -> string_of_int i
10879         | CallInt64 i -> Int64.to_string i
10880         | CallBool b -> if b then "1" else "0"
10881       ) args
10882     )
10883   in
10884
10885   generate_lang_bindtests (
10886     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
10887   );
10888
10889   pr "print \"EOF\"\n"
10890
10891 and generate_ruby_bindtests () =
10892   generate_header HashStyle GPLv2plus;
10893
10894   pr "\
10895 require 'guestfs'
10896
10897 g = Guestfs::create()
10898 ";
10899
10900   let mkargs args =
10901     String.concat ", " (
10902       List.map (
10903         function
10904         | CallString s -> "\"" ^ s ^ "\""
10905         | CallOptString None -> "nil"
10906         | CallOptString (Some s) -> sprintf "\"%s\"" s
10907         | CallStringList xs ->
10908             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10909         | CallInt i -> string_of_int i
10910         | CallInt64 i -> Int64.to_string i
10911         | CallBool b -> string_of_bool b
10912       ) args
10913     )
10914   in
10915
10916   generate_lang_bindtests (
10917     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
10918   );
10919
10920   pr "print \"EOF\\n\"\n"
10921
10922 and generate_java_bindtests () =
10923   generate_header CStyle GPLv2plus;
10924
10925   pr "\
10926 import com.redhat.et.libguestfs.*;
10927
10928 public class Bindtests {
10929     public static void main (String[] argv)
10930     {
10931         try {
10932             GuestFS g = new GuestFS ();
10933 ";
10934
10935   let mkargs args =
10936     String.concat ", " (
10937       List.map (
10938         function
10939         | CallString s -> "\"" ^ s ^ "\""
10940         | CallOptString None -> "null"
10941         | CallOptString (Some s) -> sprintf "\"%s\"" s
10942         | CallStringList xs ->
10943             "new String[]{" ^
10944               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
10945         | CallInt i -> string_of_int i
10946         | CallInt64 i -> Int64.to_string i
10947         | CallBool b -> string_of_bool b
10948       ) args
10949     )
10950   in
10951
10952   generate_lang_bindtests (
10953     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
10954   );
10955
10956   pr "
10957             System.out.println (\"EOF\");
10958         }
10959         catch (Exception exn) {
10960             System.err.println (exn);
10961             System.exit (1);
10962         }
10963     }
10964 }
10965 "
10966
10967 and generate_haskell_bindtests () =
10968   generate_header HaskellStyle GPLv2plus;
10969
10970   pr "\
10971 module Bindtests where
10972 import qualified Guestfs
10973
10974 main = do
10975   g <- Guestfs.create
10976 ";
10977
10978   let mkargs args =
10979     String.concat " " (
10980       List.map (
10981         function
10982         | CallString s -> "\"" ^ s ^ "\""
10983         | CallOptString None -> "Nothing"
10984         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
10985         | CallStringList xs ->
10986             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
10987         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
10988         | CallInt i -> string_of_int i
10989         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
10990         | CallInt64 i -> Int64.to_string i
10991         | CallBool true -> "True"
10992         | CallBool false -> "False"
10993       ) args
10994     )
10995   in
10996
10997   generate_lang_bindtests (
10998     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
10999   );
11000
11001   pr "  putStrLn \"EOF\"\n"
11002
11003 (* Language-independent bindings tests - we do it this way to
11004  * ensure there is parity in testing bindings across all languages.
11005  *)
11006 and generate_lang_bindtests call =
11007   call "test0" [CallString "abc"; CallOptString (Some "def");
11008                 CallStringList []; CallBool false;
11009                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11010   call "test0" [CallString "abc"; CallOptString None;
11011                 CallStringList []; CallBool false;
11012                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11013   call "test0" [CallString ""; CallOptString (Some "def");
11014                 CallStringList []; CallBool false;
11015                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11016   call "test0" [CallString ""; CallOptString (Some "");
11017                 CallStringList []; CallBool false;
11018                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11019   call "test0" [CallString "abc"; CallOptString (Some "def");
11020                 CallStringList ["1"]; CallBool false;
11021                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11022   call "test0" [CallString "abc"; CallOptString (Some "def");
11023                 CallStringList ["1"; "2"]; CallBool false;
11024                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11025   call "test0" [CallString "abc"; CallOptString (Some "def");
11026                 CallStringList ["1"]; CallBool true;
11027                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456"];
11028   call "test0" [CallString "abc"; CallOptString (Some "def");
11029                 CallStringList ["1"]; CallBool false;
11030                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456"];
11031   call "test0" [CallString "abc"; CallOptString (Some "def");
11032                 CallStringList ["1"]; CallBool false;
11033                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456"];
11034   call "test0" [CallString "abc"; CallOptString (Some "def");
11035                 CallStringList ["1"]; CallBool false;
11036                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456"];
11037   call "test0" [CallString "abc"; CallOptString (Some "def");
11038                 CallStringList ["1"]; CallBool false;
11039                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456"];
11040   call "test0" [CallString "abc"; CallOptString (Some "def");
11041                 CallStringList ["1"]; CallBool false;
11042                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456"];
11043   call "test0" [CallString "abc"; CallOptString (Some "def");
11044                 CallStringList ["1"]; CallBool false;
11045                 CallInt 0; CallInt64 0L; CallString ""; CallString ""]
11046
11047 (* XXX Add here tests of the return and error functions. *)
11048
11049 (* Code to generator bindings for virt-inspector.  Currently only
11050  * implemented for OCaml code (for virt-p2v 2.0).
11051  *)
11052 let rng_input = "inspector/virt-inspector.rng"
11053
11054 (* Read the input file and parse it into internal structures.  This is
11055  * by no means a complete RELAX NG parser, but is just enough to be
11056  * able to parse the specific input file.
11057  *)
11058 type rng =
11059   | Element of string * rng list        (* <element name=name/> *)
11060   | Attribute of string * rng list        (* <attribute name=name/> *)
11061   | Interleave of rng list                (* <interleave/> *)
11062   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
11063   | OneOrMore of rng                        (* <oneOrMore/> *)
11064   | Optional of rng                        (* <optional/> *)
11065   | Choice of string list                (* <choice><value/>*</choice> *)
11066   | Value of string                        (* <value>str</value> *)
11067   | Text                                (* <text/> *)
11068
11069 let rec string_of_rng = function
11070   | Element (name, xs) ->
11071       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11072   | Attribute (name, xs) ->
11073       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11074   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
11075   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
11076   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
11077   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
11078   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
11079   | Value value -> "Value \"" ^ value ^ "\""
11080   | Text -> "Text"
11081
11082 and string_of_rng_list xs =
11083   String.concat ", " (List.map string_of_rng xs)
11084
11085 let rec parse_rng ?defines context = function
11086   | [] -> []
11087   | Xml.Element ("element", ["name", name], children) :: rest ->
11088       Element (name, parse_rng ?defines context children)
11089       :: parse_rng ?defines context rest
11090   | Xml.Element ("attribute", ["name", name], children) :: rest ->
11091       Attribute (name, parse_rng ?defines context children)
11092       :: parse_rng ?defines context rest
11093   | Xml.Element ("interleave", [], children) :: rest ->
11094       Interleave (parse_rng ?defines context children)
11095       :: parse_rng ?defines context rest
11096   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
11097       let rng = parse_rng ?defines context [child] in
11098       (match rng with
11099        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
11100        | _ ->
11101            failwithf "%s: <zeroOrMore> contains more than one child element"
11102              context
11103       )
11104   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
11105       let rng = parse_rng ?defines context [child] in
11106       (match rng with
11107        | [child] -> OneOrMore child :: parse_rng ?defines context rest
11108        | _ ->
11109            failwithf "%s: <oneOrMore> contains more than one child element"
11110              context
11111       )
11112   | Xml.Element ("optional", [], [child]) :: rest ->
11113       let rng = parse_rng ?defines context [child] in
11114       (match rng with
11115        | [child] -> Optional child :: parse_rng ?defines context rest
11116        | _ ->
11117            failwithf "%s: <optional> contains more than one child element"
11118              context
11119       )
11120   | Xml.Element ("choice", [], children) :: rest ->
11121       let values = List.map (
11122         function Xml.Element ("value", [], [Xml.PCData value]) -> value
11123         | _ ->
11124             failwithf "%s: can't handle anything except <value> in <choice>"
11125               context
11126       ) children in
11127       Choice values
11128       :: parse_rng ?defines context rest
11129   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
11130       Value value :: parse_rng ?defines context rest
11131   | Xml.Element ("text", [], []) :: rest ->
11132       Text :: parse_rng ?defines context rest
11133   | Xml.Element ("ref", ["name", name], []) :: rest ->
11134       (* Look up the reference.  Because of limitations in this parser,
11135        * we can't handle arbitrarily nested <ref> yet.  You can only
11136        * use <ref> from inside <start>.
11137        *)
11138       (match defines with
11139        | None ->
11140            failwithf "%s: contains <ref>, but no refs are defined yet" context
11141        | Some map ->
11142            let rng = StringMap.find name map in
11143            rng @ parse_rng ?defines context rest
11144       )
11145   | x :: _ ->
11146       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
11147
11148 let grammar =
11149   let xml = Xml.parse_file rng_input in
11150   match xml with
11151   | Xml.Element ("grammar", _,
11152                  Xml.Element ("start", _, gram) :: defines) ->
11153       (* The <define/> elements are referenced in the <start> section,
11154        * so build a map of those first.
11155        *)
11156       let defines = List.fold_left (
11157         fun map ->
11158           function Xml.Element ("define", ["name", name], defn) ->
11159             StringMap.add name defn map
11160           | _ ->
11161               failwithf "%s: expected <define name=name/>" rng_input
11162       ) StringMap.empty defines in
11163       let defines = StringMap.mapi parse_rng defines in
11164
11165       (* Parse the <start> clause, passing the defines. *)
11166       parse_rng ~defines "<start>" gram
11167   | _ ->
11168       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
11169         rng_input
11170
11171 let name_of_field = function
11172   | Element (name, _) | Attribute (name, _)
11173   | ZeroOrMore (Element (name, _))
11174   | OneOrMore (Element (name, _))
11175   | Optional (Element (name, _)) -> name
11176   | Optional (Attribute (name, _)) -> name
11177   | Text -> (* an unnamed field in an element *)
11178       "data"
11179   | rng ->
11180       failwithf "name_of_field failed at: %s" (string_of_rng rng)
11181
11182 (* At the moment this function only generates OCaml types.  However we
11183  * should parameterize it later so it can generate types/structs in a
11184  * variety of languages.
11185  *)
11186 let generate_types xs =
11187   (* A simple type is one that can be printed out directly, eg.
11188    * "string option".  A complex type is one which has a name and has
11189    * to be defined via another toplevel definition, eg. a struct.
11190    *
11191    * generate_type generates code for either simple or complex types.
11192    * In the simple case, it returns the string ("string option").  In
11193    * the complex case, it returns the name ("mountpoint").  In the
11194    * complex case it has to print out the definition before returning,
11195    * so it should only be called when we are at the beginning of a
11196    * new line (BOL context).
11197    *)
11198   let rec generate_type = function
11199     | Text ->                                (* string *)
11200         "string", true
11201     | Choice values ->                        (* [`val1|`val2|...] *)
11202         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
11203     | ZeroOrMore rng ->                        (* <rng> list *)
11204         let t, is_simple = generate_type rng in
11205         t ^ " list (* 0 or more *)", is_simple
11206     | OneOrMore rng ->                        (* <rng> list *)
11207         let t, is_simple = generate_type rng in
11208         t ^ " list (* 1 or more *)", is_simple
11209                                         (* virt-inspector hack: bool *)
11210     | Optional (Attribute (name, [Value "1"])) ->
11211         "bool", true
11212     | Optional rng ->                        (* <rng> list *)
11213         let t, is_simple = generate_type rng in
11214         t ^ " option", is_simple
11215                                         (* type name = { fields ... } *)
11216     | Element (name, fields) when is_attrs_interleave fields ->
11217         generate_type_struct name (get_attrs_interleave fields)
11218     | Element (name, [field])                (* type name = field *)
11219     | Attribute (name, [field]) ->
11220         let t, is_simple = generate_type field in
11221         if is_simple then (t, true)
11222         else (
11223           pr "type %s = %s\n" name t;
11224           name, false
11225         )
11226     | Element (name, fields) ->              (* type name = { fields ... } *)
11227         generate_type_struct name fields
11228     | rng ->
11229         failwithf "generate_type failed at: %s" (string_of_rng rng)
11230
11231   and is_attrs_interleave = function
11232     | [Interleave _] -> true
11233     | Attribute _ :: fields -> is_attrs_interleave fields
11234     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11235     | _ -> false
11236
11237   and get_attrs_interleave = function
11238     | [Interleave fields] -> fields
11239     | ((Attribute _) as field) :: fields
11240     | ((Optional (Attribute _)) as field) :: fields ->
11241         field :: get_attrs_interleave fields
11242     | _ -> assert false
11243
11244   and generate_types xs =
11245     List.iter (fun x -> ignore (generate_type x)) xs
11246
11247   and generate_type_struct name fields =
11248     (* Calculate the types of the fields first.  We have to do this
11249      * before printing anything so we are still in BOL context.
11250      *)
11251     let types = List.map fst (List.map generate_type fields) in
11252
11253     (* Special case of a struct containing just a string and another
11254      * field.  Turn it into an assoc list.
11255      *)
11256     match types with
11257     | ["string"; other] ->
11258         let fname1, fname2 =
11259           match fields with
11260           | [f1; f2] -> name_of_field f1, name_of_field f2
11261           | _ -> assert false in
11262         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
11263         name, false
11264
11265     | types ->
11266         pr "type %s = {\n" name;
11267         List.iter (
11268           fun (field, ftype) ->
11269             let fname = name_of_field field in
11270             pr "  %s_%s : %s;\n" name fname ftype
11271         ) (List.combine fields types);
11272         pr "}\n";
11273         (* Return the name of this type, and
11274          * false because it's not a simple type.
11275          *)
11276         name, false
11277   in
11278
11279   generate_types xs
11280
11281 let generate_parsers xs =
11282   (* As for generate_type above, generate_parser makes a parser for
11283    * some type, and returns the name of the parser it has generated.
11284    * Because it (may) need to print something, it should always be
11285    * called in BOL context.
11286    *)
11287   let rec generate_parser = function
11288     | Text ->                                (* string *)
11289         "string_child_or_empty"
11290     | Choice values ->                        (* [`val1|`val2|...] *)
11291         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
11292           (String.concat "|"
11293              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
11294     | ZeroOrMore rng ->                        (* <rng> list *)
11295         let pa = generate_parser rng in
11296         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11297     | OneOrMore rng ->                        (* <rng> list *)
11298         let pa = generate_parser rng in
11299         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11300                                         (* virt-inspector hack: bool *)
11301     | Optional (Attribute (name, [Value "1"])) ->
11302         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
11303     | Optional rng ->                        (* <rng> list *)
11304         let pa = generate_parser rng in
11305         sprintf "(function None -> None | Some x -> Some (%s x))" pa
11306                                         (* type name = { fields ... } *)
11307     | Element (name, fields) when is_attrs_interleave fields ->
11308         generate_parser_struct name (get_attrs_interleave fields)
11309     | Element (name, [field]) ->        (* type name = field *)
11310         let pa = generate_parser field in
11311         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11312         pr "let %s =\n" parser_name;
11313         pr "  %s\n" pa;
11314         pr "let parse_%s = %s\n" name parser_name;
11315         parser_name
11316     | Attribute (name, [field]) ->
11317         let pa = generate_parser field in
11318         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11319         pr "let %s =\n" parser_name;
11320         pr "  %s\n" pa;
11321         pr "let parse_%s = %s\n" name parser_name;
11322         parser_name
11323     | Element (name, fields) ->              (* type name = { fields ... } *)
11324         generate_parser_struct name ([], fields)
11325     | rng ->
11326         failwithf "generate_parser failed at: %s" (string_of_rng rng)
11327
11328   and is_attrs_interleave = function
11329     | [Interleave _] -> true
11330     | Attribute _ :: fields -> is_attrs_interleave fields
11331     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11332     | _ -> false
11333
11334   and get_attrs_interleave = function
11335     | [Interleave fields] -> [], fields
11336     | ((Attribute _) as field) :: fields
11337     | ((Optional (Attribute _)) as field) :: fields ->
11338         let attrs, interleaves = get_attrs_interleave fields in
11339         (field :: attrs), interleaves
11340     | _ -> assert false
11341
11342   and generate_parsers xs =
11343     List.iter (fun x -> ignore (generate_parser x)) xs
11344
11345   and generate_parser_struct name (attrs, interleaves) =
11346     (* Generate parsers for the fields first.  We have to do this
11347      * before printing anything so we are still in BOL context.
11348      *)
11349     let fields = attrs @ interleaves in
11350     let pas = List.map generate_parser fields in
11351
11352     (* Generate an intermediate tuple from all the fields first.
11353      * If the type is just a string + another field, then we will
11354      * return this directly, otherwise it is turned into a record.
11355      *
11356      * RELAX NG note: This code treats <interleave> and plain lists of
11357      * fields the same.  In other words, it doesn't bother enforcing
11358      * any ordering of fields in the XML.
11359      *)
11360     pr "let parse_%s x =\n" name;
11361     pr "  let t = (\n    ";
11362     let comma = ref false in
11363     List.iter (
11364       fun x ->
11365         if !comma then pr ",\n    ";
11366         comma := true;
11367         match x with
11368         | Optional (Attribute (fname, [field])), pa ->
11369             pr "%s x" pa
11370         | Optional (Element (fname, [field])), pa ->
11371             pr "%s (optional_child %S x)" pa fname
11372         | Attribute (fname, [Text]), _ ->
11373             pr "attribute %S x" fname
11374         | (ZeroOrMore _ | OneOrMore _), pa ->
11375             pr "%s x" pa
11376         | Text, pa ->
11377             pr "%s x" pa
11378         | (field, pa) ->
11379             let fname = name_of_field field in
11380             pr "%s (child %S x)" pa fname
11381     ) (List.combine fields pas);
11382     pr "\n  ) in\n";
11383
11384     (match fields with
11385      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11386          pr "  t\n"
11387
11388      | _ ->
11389          pr "  (Obj.magic t : %s)\n" name
11390 (*
11391          List.iter (
11392            function
11393            | (Optional (Attribute (fname, [field])), pa) ->
11394                pr "  %s_%s =\n" name fname;
11395                pr "    %s x;\n" pa
11396            | (Optional (Element (fname, [field])), pa) ->
11397                pr "  %s_%s =\n" name fname;
11398                pr "    (let x = optional_child %S x in\n" fname;
11399                pr "     %s x);\n" pa
11400            | (field, pa) ->
11401                let fname = name_of_field field in
11402                pr "  %s_%s =\n" name fname;
11403                pr "    (let x = child %S x in\n" fname;
11404                pr "     %s x);\n" pa
11405          ) (List.combine fields pas);
11406          pr "}\n"
11407 *)
11408     );
11409     sprintf "parse_%s" name
11410   in
11411
11412   generate_parsers xs
11413
11414 (* Generate ocaml/guestfs_inspector.mli. *)
11415 let generate_ocaml_inspector_mli () =
11416   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11417
11418   pr "\
11419 (** This is an OCaml language binding to the external [virt-inspector]
11420     program.
11421
11422     For more information, please read the man page [virt-inspector(1)].
11423 *)
11424
11425 ";
11426
11427   generate_types grammar;
11428   pr "(** The nested information returned from the {!inspect} function. *)\n";
11429   pr "\n";
11430
11431   pr "\
11432 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11433 (** To inspect a libvirt domain called [name], pass a singleton
11434     list: [inspect [name]].  When using libvirt only, you may
11435     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11436
11437     To inspect a disk image or images, pass a list of the filenames
11438     of the disk images: [inspect filenames]
11439
11440     This function inspects the given guest or disk images and
11441     returns a list of operating system(s) found and a large amount
11442     of information about them.  In the vast majority of cases,
11443     a virtual machine only contains a single operating system.
11444
11445     If the optional [~xml] parameter is given, then this function
11446     skips running the external virt-inspector program and just
11447     parses the given XML directly (which is expected to be XML
11448     produced from a previous run of virt-inspector).  The list of
11449     names and connect URI are ignored in this case.
11450
11451     This function can throw a wide variety of exceptions, for example
11452     if the external virt-inspector program cannot be found, or if
11453     it doesn't generate valid XML.
11454 *)
11455 "
11456
11457 (* Generate ocaml/guestfs_inspector.ml. *)
11458 let generate_ocaml_inspector_ml () =
11459   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11460
11461   pr "open Unix\n";
11462   pr "\n";
11463
11464   generate_types grammar;
11465   pr "\n";
11466
11467   pr "\
11468 (* Misc functions which are used by the parser code below. *)
11469 let first_child = function
11470   | Xml.Element (_, _, c::_) -> c
11471   | Xml.Element (name, _, []) ->
11472       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11473   | Xml.PCData str ->
11474       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11475
11476 let string_child_or_empty = function
11477   | Xml.Element (_, _, [Xml.PCData s]) -> s
11478   | Xml.Element (_, _, []) -> \"\"
11479   | Xml.Element (x, _, _) ->
11480       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11481                 x ^ \" instead\")
11482   | Xml.PCData str ->
11483       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11484
11485 let optional_child name xml =
11486   let children = Xml.children xml in
11487   try
11488     Some (List.find (function
11489                      | Xml.Element (n, _, _) when n = name -> true
11490                      | _ -> false) children)
11491   with
11492     Not_found -> None
11493
11494 let child name xml =
11495   match optional_child name xml with
11496   | Some c -> c
11497   | None ->
11498       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11499
11500 let attribute name xml =
11501   try Xml.attrib xml name
11502   with Xml.No_attribute _ ->
11503     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11504
11505 ";
11506
11507   generate_parsers grammar;
11508   pr "\n";
11509
11510   pr "\
11511 (* Run external virt-inspector, then use parser to parse the XML. *)
11512 let inspect ?connect ?xml names =
11513   let xml =
11514     match xml with
11515     | None ->
11516         if names = [] then invalid_arg \"inspect: no names given\";
11517         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11518           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11519           names in
11520         let cmd = List.map Filename.quote cmd in
11521         let cmd = String.concat \" \" cmd in
11522         let chan = open_process_in cmd in
11523         let xml = Xml.parse_in chan in
11524         (match close_process_in chan with
11525          | WEXITED 0 -> ()
11526          | WEXITED _ -> failwith \"external virt-inspector command failed\"
11527          | WSIGNALED i | WSTOPPED i ->
11528              failwith (\"external virt-inspector command died or stopped on sig \" ^
11529                        string_of_int i)
11530         );
11531         xml
11532     | Some doc ->
11533         Xml.parse_string doc in
11534   parse_operatingsystems xml
11535 "
11536
11537 (* This is used to generate the src/MAX_PROC_NR file which
11538  * contains the maximum procedure number, a surrogate for the
11539  * ABI version number.  See src/Makefile.am for the details.
11540  *)
11541 and generate_max_proc_nr () =
11542   let proc_nrs = List.map (
11543     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
11544   ) daemon_functions in
11545
11546   let max_proc_nr = List.fold_left max 0 proc_nrs in
11547
11548   pr "%d\n" max_proc_nr
11549
11550 let output_to filename k =
11551   let filename_new = filename ^ ".new" in
11552   chan := open_out filename_new;
11553   k ();
11554   close_out !chan;
11555   chan := Pervasives.stdout;
11556
11557   (* Is the new file different from the current file? *)
11558   if Sys.file_exists filename && files_equal filename filename_new then
11559     unlink filename_new                 (* same, so skip it *)
11560   else (
11561     (* different, overwrite old one *)
11562     (try chmod filename 0o644 with Unix_error _ -> ());
11563     rename filename_new filename;
11564     chmod filename 0o444;
11565     printf "written %s\n%!" filename;
11566   )
11567
11568 let perror msg = function
11569   | Unix_error (err, _, _) ->
11570       eprintf "%s: %s\n" msg (error_message err)
11571   | exn ->
11572       eprintf "%s: %s\n" msg (Printexc.to_string exn)
11573
11574 (* Main program. *)
11575 let () =
11576   let lock_fd =
11577     try openfile "HACKING" [O_RDWR] 0
11578     with
11579     | Unix_error (ENOENT, _, _) ->
11580         eprintf "\
11581 You are probably running this from the wrong directory.
11582 Run it from the top source directory using the command
11583   src/generator.ml
11584 ";
11585         exit 1
11586     | exn ->
11587         perror "open: HACKING" exn;
11588         exit 1 in
11589
11590   (* Acquire a lock so parallel builds won't try to run the generator
11591    * twice at the same time.  Subsequent builds will wait for the first
11592    * one to finish.  Note the lock is released implicitly when the
11593    * program exits.
11594    *)
11595   (try lockf lock_fd F_LOCK 1
11596    with exn ->
11597      perror "lock: HACKING" exn;
11598      exit 1);
11599
11600   check_functions ();
11601
11602   output_to "src/guestfs_protocol.x" generate_xdr;
11603   output_to "src/guestfs-structs.h" generate_structs_h;
11604   output_to "src/guestfs-actions.h" generate_actions_h;
11605   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
11606   output_to "src/guestfs-actions.c" generate_client_actions;
11607   output_to "src/guestfs-bindtests.c" generate_bindtests;
11608   output_to "src/guestfs-structs.pod" generate_structs_pod;
11609   output_to "src/guestfs-actions.pod" generate_actions_pod;
11610   output_to "src/guestfs-availability.pod" generate_availability_pod;
11611   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
11612   output_to "src/libguestfs.syms" generate_linker_script;
11613   output_to "daemon/actions.h" generate_daemon_actions_h;
11614   output_to "daemon/stubs.c" generate_daemon_actions;
11615   output_to "daemon/names.c" generate_daemon_names;
11616   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
11617   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
11618   output_to "capitests/tests.c" generate_tests;
11619   output_to "fish/cmds.c" generate_fish_cmds;
11620   output_to "fish/completion.c" generate_fish_completion;
11621   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
11622   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
11623   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
11624   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
11625   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
11626   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
11627   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
11628   output_to "perl/Guestfs.xs" generate_perl_xs;
11629   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
11630   output_to "perl/bindtests.pl" generate_perl_bindtests;
11631   output_to "python/guestfs-py.c" generate_python_c;
11632   output_to "python/guestfs.py" generate_python_py;
11633   output_to "python/bindtests.py" generate_python_bindtests;
11634   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
11635   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
11636   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
11637
11638   List.iter (
11639     fun (typ, jtyp) ->
11640       let cols = cols_of_struct typ in
11641       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
11642       output_to filename (generate_java_struct jtyp cols);
11643   ) java_structs;
11644
11645   output_to "java/Makefile.inc" generate_java_makefile_inc;
11646   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
11647   output_to "java/Bindtests.java" generate_java_bindtests;
11648   output_to "haskell/Guestfs.hs" generate_haskell_hs;
11649   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
11650   output_to "csharp/Libguestfs.cs" generate_csharp;
11651
11652   (* Always generate this file last, and unconditionally.  It's used
11653    * by the Makefile to know when we must re-run the generator.
11654    *)
11655   let chan = open_out "src/stamp-generator" in
11656   fprintf chan "1\n";
11657   close_out chan;
11658
11659   printf "generated %d lines of code\n" !lines